简体   繁体   中英

Passing a pointer to class into unmanaged c++ code from C#

I have a c++ exported function in dll:

int MyMethod(ulong pid, MyStruct* struct);

MyStruct is described as class:

class MyStruct
{
public:
uchar   nVersion;
uchar   nModuleType;
uchar   nMachine64;
uchar   nReserved;
ulong  data1;
ulong  data2;
ulong  data3;
};

I'm trying to import this function to my C# code like this:

[DllImport("mydll.dll", EntryPoint = "#24")]
private static extern int _MyMethod(long pid, ref MyStruct struct);

Class in C#:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
stuct MyStruct
{
    public byte nVersion;
    public byte nModuleType;
    public byte nMachine64;
    public byte nReserved;
    public ulong data1;
    public ulong data2;
    public ulong data3;
}

And i'm getting System.AccessViolationException :

MyStruct struct = new MyStruct();
_MyMethod(4728, ref struct);

What's wrong?

UPDATE: System.Runtime.InteropServices.Marshal.SizeOf(struct) returns 32. Why? I thought it should be 4 * 1 + 8 * 3 = 28

In C# we have class es and struct s. All class types are reference but struct types are value types. This means when you have something like class MyStruct and you write MyStruct s it is actually something like a pointer to base class, and when you pass it by reference you actually pass address of that pointer, so it has nothing to do with C++ that expect a pointer to main struct . According to this solution to your problem is to convert class to struct .

long and ulong in C# are 64 bit types while they are 32 bit in C++(MSVC at least), so when you declare your function such that its first parameter is long you send extra 32 bit value that may override next parameter and cause it to be invalid:

Stack:
    32 bit: [first 32 bit of the first parameter]
    32 bit: [second 32 bit of the first parameter]
    32 bit: [address of your structure]

So when function called it will take an invalid parameter as address of struct. so just change your function definition to:

[DllImport("mydll.dll", EntryPoint = "#24")]
private static extern int _MyMethod(int pid, ref MyStruct struct);

An your struct to:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
stuct MyStruct
{
    public byte nVersion;
    public byte nModuleType;
    public byte nMachine64;
    public byte nReserved;
    public uint data1;
    public uint data2;
    public uint data3;
}

may be source of your error is in first parameter of the function, because function expect a 32 bit value and you provide a 64 bit one and actually you provide 2, 32 bit value to the function that cause the function

SizeOf() returns 32 because of the alignment requirements for ulong, an 8 byte value type. The default value for StructLayoutAttribute.Pack is 8, same as the default packing used in native code. So data1 gets aligned to offset 8 and there's a 4 byte gap between nReserved and data1. So 4 x 1 + 4 + 3 x 8 = 32.

You probably got that gap because in native C++ code compiled with the MSVC compiler, an ulong is 4 bytes. Same as uint in C#. So fix the structure declaration, replace ulong with uint.

Next problem, the cause of the AV, is that you declared the structure as a class in C#. Which is a reference type which always gets passed by reference. Your current declaration is equivalent to MyStruct** in C++ code. Either remove the ref in the declaration or declare it as a struct instead of a class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM