views:

62

answers:

1

Hi,

I have written a structure in VC++. I have made a dll of the VC++ code and calling this dll in C# using PInvoke.

The VC++ dll looks like this

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#if defined(_MSC_VER)
#include <windows.h>
#define DLL extern "C" __declspec(dllexport)
#else
#define DLL
#endif


struct SYSTEM_OUTPUT
{
    int status;
};


DLL SYSTEM_OUTPUT* getStatus()
{
    SYSTEM_OUTPUT* output;
    output->status = 7;

    return output;
}

I am calling the getStatus() function from the dll in my C# code, which looks as follows;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace UsingReturnStructDLL
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SYSTEM_OUTPUT
    {
        [MarshalAs(UnmanagedType.I4)]
        int Status;
    }



public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

        public SYSTEM_OUTPUT output;

        [DllImport("ReturnStructDLL", EntryPoint = "getStatus")]
        [return: MarshalAs(UnmanagedType.Struct)]
        public extern static SYSTEM_OUTPUT getStatus();



        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                SYSTEM_OUTPUT output = getStatus();
            }
            catch (AccessViolationException e)
            {
                label1.Text = e.Message;
            }

        }
    }
}

I want to retrieve the values in the struct in my C# code. With the above setup of my code, I am getting the following error;

Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int32/UInt32
must be paired with I4, U4, or Error).

Can someone please help me with the issue?

Thanks.

+2  A: 

Make your C++ code work first. It is junk as posted, you don't initialize the pointer. It will crash with an AccessViolation.

Returning pointers to structures is very hard to get right in C/C++ as well, the client of your code won't know how the memory needs to be released. Which plays havoc on the P/Invoke marshaller as well, it is going to try to release the pointer with CoTaskMemFree(). That's a kaboom on Vista and up, a memory leak on XP.

All of these problems disappear if you let the client pass a pointer to the structure as an argument:

void getStatus(SYSTEM_OUTPUT* buffer)

Which then in C# becomes:

[DllImport("mumble.dll")]
private static extern void getStatus(out SYSTEM_OUTPUT buffer);
Hans Passant
Hi, if I make my C# client to pass the structure as an argument, how would I be able to set the value for the member of the structure in cpp. As-In going by your way, in c++, buffer.status = 7; gives me an error.I'm sorry, if this question is very kiddish, I am newbie!Thanks for help
James
Time to consult a C++ language book. It is buffer->status = 7.
Hans Passant
Thanks a lot Hans! You helped a lot!
James