Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass char* in struct from c# to c++

It feels like my problem is similar to this.

So far, I have a struct defined in C++ like this:

typedef struct struct_type1
{
    uint64  nameLen;
    char *  name;  
} STATUSSTRUCT;

and a function defined as:

extern int _stdcall getStatus(STATUSSTRUCT * status);

and presumably the function like this:

int _stdcall getStatus(STATUSSTRUCT * status)
{
    status->nameLen = someLength;
    status->name = someName;
    return 1;
}

Note that I can't actually change the C++ code (for various reasons) nor the header file.

My C# code looks like this:

public struct STATUSSTRUCT
{
    public UInt64 nameLen;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4128)]
    public byte[] name;
}
STATUSSTRUCT status;

[DllImport("test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int getStatus(ref STATUSSTRUCT status);

public void refreshStatus() {
    status = new STATUSSTRUCT();
    status.nameLen = 4128;
    status.name = new byte[4128];
    getStatus(ref status);
}

However, calling refreshStatus is giving me System.AccessViolationException.

Can someone help me figure out how I can call this function in C++ from C#?

like image 686
user3736336 Avatar asked Aug 25 '16 20:08

user3736336


2 Answers

Your structure expects a pointer to an array; you are marshalling the array. One side of the transaction is expecting to get the address "123 Sesame Street" and you are providing an exact replica of the apartment building at that address. That's not going to work.

To get marshalling code correct you need to have a thorough and deep understanding of memory management in C#. My advice is that you obtain the services of an expert.

like image 69
Eric Lippert Avatar answered Oct 05 '22 01:10

Eric Lippert


You may try to use StringBuilder instead of byte[] and LPStr instead of ByValArray:

public struct STATUSSTRUCT
{
    public UInt64 nameLen;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 4128)]
    public StringBuilder name;
}

status = new STATUSSTRUCT();
status.nameLen = 4128;
status.name = new StringBuilder(4128);
getStatus(ref status);

https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype(v=vs.110).aspx

like image 44
Nazar Avatar answered Oct 05 '22 03:10

Nazar