将C#结构传递给C ++非托管DLL返回错误的结果
我有一个在Visual Studio 2017中开发并在64位环境中编译的简单C ++ win32 DLL,具有以下代码:
I have a simple C++ win32 DLL developed in visual studio 2017 and compiled in 64 bit environment having the following code:
typedef struct sum {
struct {
int num1;
int num2;
} nums;
} sum1;
extern "C" {
__declspec(dllexport) int initialize(sum1 *summing)
{
int res;
res = summing->nums.num1 + summing->nums.num2;
return res;
}
}
上面的代码包含一个方法,该方法通过将typedef结构作为参数来返回两个整数的和.
The above code contains a method which returns the sum of two integers by taking a typedef struct as an argument.
我有一个C#客户端应用程序,该应用程序使用PInvoke使用此Win32 C ++ DLL.以下是我的C#客户端应用程序的代码:
I have a C# client application which consumes this Win32 C++ DLL using PInvoke. Following is the code of my C# client application:
[StructLayout(LayoutKind.Sequential)]
public struct nums
{
public int a;
public int b;
}
[StructLayout(LayoutKind.Sequential)]
public struct mydef
{
public IntPtr sum;
}
public class LibWrap
{
[DllImport("C++.dll", EntryPoint = "initialize")]
public static extern int Initialize(ref mydef mydef);
}
class Program
{
static void Main(string[] args)
{
mydef mydef = new mydef();
nums nums;
nums.a = 6;
nums.b = 6;
IntPtr buffer1 = Marshal.AllocCoTaskMem(Marshal.SizeOf(nums));
Marshal.StructureToPtr(nums, buffer1, false);
mydef.sum = buffer1;
int res = LibWrap.Initialize(ref mydef);
Console.WriteLine(res);
}
}
使用上面的代码,我期望输出为'12',但是我将输出为'-1504178328'.
With the above code, I am expecting '12' as output, but instead I am getting '-1504178328' as output.
我是一位C#开发人员,完全没有C ++经验.请帮我解决这个问题.
I am a C# developer with no experience in C++ at all. Please help me to solve this problem.
使用更简单的P/Invoke包装器:
Use a simpler P/Invoke wrapper:
public static class LibWrap
{
[DllImport("C++.dll", EntryPoint = "initialize")]
public static extern int Initialize(ref Nums nums);
[StructLayout(LayoutKind.Sequential)]
public struct Nums
{
public int a;
public int b;
}
}
并像这样使用它:
void CSharpExample()
{
LibWrap.Nums nums;
nums.a = 6;
nums.b = 7;
int res = LibWrap.Initialize(ref nums);
Console.WriteLine(res);
}
在您的示例中,您不需要任何内存分配和封送处理,因为:
In your example, you don't need any memory allocation and marshaling, because:
-
LibWrap.Nums
是一个结构,因此CSharpExample()
中的局部变量nums
完全在堆栈上分配. - 将托管结构
LibWrap.Nums
由ref
传递给LibWrap.Initialize
会将指针传递给堆栈上的局部变量nums
. -
LibWrap.Initialize
被同步调用,因此传递给它的指针在LibWrap.Initialize
函数退出后不会在任何地方使用.这很重要,因为CSharpExample()
退出后指针立即变为无效.
-
LibWrap.Nums
is a struct, thus local variablenums
inCSharpExample()
is allocated completely on stack. - passing managed struct
LibWrap.Nums
byref
toLibWrap.Initialize
will pass the pointer to local variablenums
on stack. -
LibWrap.Initialize
is called synchronously, so that the pointer you pass to it isn't used anywhere afterLibWrap.Initialize
function exits. This is important because the pointer becomes invalid as soon asCSharpExample()
exits.