[英]Passing C# struct to C++ unmanaged DLL returning incorrect result
I have a simple C++ win32 DLL developed in visual studio 2017 and compiled in 64 bit environment having the following code: 我有一个在Visual Studio 2017中开发并在64位环境中编译的简单C ++ win32 DLL,具有以下代码:
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;
}
}
The above code contains a method which returns the sum of two integers by taking a typedef struct as an argument. 上面的代码包含一个方法,该方法通过将typedef结构作为参数返回两个整数的和。
I have a C# client application which consumes this Win32 C++ DLL using PInvoke. 我有一个使用PInvoke消耗此Win32 C ++ DLL的C#客户端应用程序。 Following is the code of my C# client application: 以下是我的C#客户端应用程序的代码:
[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);
}
}
With the above code, I am expecting '12' as output, but instead I am getting '-1504178328' as output. 使用上面的代码,我期望输出为'12',但是我将输出为'-1504178328'。
I am a C# developer with no experience in C++ at all. 我是一位完全没有C ++经验的C#开发人员。 Please help me to solve this problem. 请帮我解决这个问题。
Use a simpler P/Invoke wrapper: 使用更简单的P / Invoke包装器:
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;
}
}
and use it like this: 并像这样使用它:
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
is a struct, thus local variable nums
in CSharpExample()
is allocated completely on stack. LibWrap.Nums
是一个结构,因此CSharpExample()
局部变量nums
完全分配在堆栈上。 LibWrap.Nums
by ref
to LibWrap.Initialize
will pass the pointer to local variable nums
on stack. 通过ref
将托管结构LibWrap.Nums
传递给LibWrap.Initialize
将指针传递给堆栈上的局部变量nums
。 LibWrap.Initialize
is called synchronously, so that the pointer you pass to it isn't used anywhere after LibWrap.Initialize
function exits. LibWrap.Initialize
是同步调用的,因此,传递给它的指针在LibWrap.Initialize
函数退出后不会在任何地方使用。 This is important because the pointer becomes invalid as soon as CSharpExample()
exits. 这很重要,因为一旦CSharpExample()
退出,指针就会变得无效。 On the C# side, you are not handling the nested struct correctly. 在C#端,您没有正确处理嵌套结构。 Try this instead: 尝试以下方法:
[StructLayout(LayoutKind.Sequential)]
public struct mynums {
public int num1;
public int num2;
}
[StructLayout(LayoutKind.Sequential)]
public struct sum1 {
public mynums nums;
}
public class LibWrap {
[DllImport("C++.dll", EntryPoint = "initialize")]
public static extern int Initialize(ref sum1 summing);
}
class Program {
static void Main(string[] args) {
sum1 mysum;
mysum.nums.num1 = 6;
mysum.nums.num2 = 6;
int res = LibWrap.Initialize(ref mysum);
Console.WriteLine(res);
}
}
That being said, having a struct whose sole data member is another struct is redundant and unnecessary. 话虽这么说,拥有唯一的数据成员是另一个结构的结构是多余的和不必要的。 You should remove the outer struct altogether, eg: 您应该完全删除外部结构,例如:
struct nums {
int num1;
int num2;
};
extern "C" {
__declspec(dllexport) int initialize(nums *summing) {
return summing->num1 + summing->num2;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct nums {
public int num1;
public int num2;
}
public class LibWrap {
[DllImport("C++.dll", EntryPoint = "initialize")]
public static extern int Initialize(ref nums summing);
}
class Program {
static void Main(string[] args) {
nums mynums;
mynums.num1 = 6;
mynums.num2 = 6;
int res = LibWrap.Initialize(ref mynums);
Console.WriteLine(res);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.