如何正确地将结构指针从 C# 传递到 C DLL
How to properly pass struct pointer from C# to C DLL
我需要从 C DLL 导出函数。这是我写的例子
typedef struct tag_struct {
unsigned char first;
unsigned char second;
} st_struct;
__declspec(dllexport) unsigned char Func( st_struct *ptr )
{
return ptr->first + ptr->second;
}
这是我用来导入上述函数的 C# 代码。
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ImportTest
{
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public class st_struct
{
public byte first;
public byte second;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
st_struct x = new st_struct();
x.first = 1;
x.second = 2;
byte result = Func(ref x);
}
[DllImport("MarshalTest.dll")]
protected static extern byte Func(ref st_struct inputs);
}
}
我的问题是 Func 的 return 值不是 3,它应该是 (1 + 2)。
我正在使用调试器查看 DLL 中的值 - 它们不同(不是我提供的 1 和 2)。
当我像这样更改 C# 代码时,函数 return 的正确值:
public Form1()
{
InitializeComponent();
st_struct x = new st_struct();
x.first = 1;
x.second = 2;
byte result = Func(x);
}
[DllImport("MarshalTest.dll")]
protected static extern byte Func(st_struct inputs);
删除 ref 后问题消失。但是我不明白为什么。
你能解释一下吗?
您可能认为 ref
关键字是 passing parameter by reference
所必需的。但是由于st_struct
定义为引用类型(class是引用类型),所以参数是按引用传递的,不是按值传递的。您不需要 ref
关键字。
如果 st_struct
被定义为 struct
,当您使用 ref
关键字时,您可能会发现它有效。
正如@kennyzx 所提到的,由于您的 st_struct
是一个 class,它已经是一个引用类型并将作为指针传递。我怀疑将 ref
放在上面会给你一个双指针,这在混合托管和非托管代码时没有多大意义。如果指针发生变化,编组器可能会处理它并为您创建一个新对象,但这似乎是一件粗略的事情。
因此,当在没有 ref
的情况下传递 class 时,它会按预期工作(C 代码获得一个指针)。如果将其更改为 struct
,则在不使用 ref
的情况下传递它应该将其传递到堆栈上,而使用 ref
传递它会将其作为指针传递。
使用 struct
在你的情况下似乎是显而易见的选择,因为它可以直接传递(CLR 只需要固定它并传递一个指针)。使用 class
我怀疑会涉及更多编组。
我需要从 C DLL 导出函数。这是我写的例子
typedef struct tag_struct {
unsigned char first;
unsigned char second;
} st_struct;
__declspec(dllexport) unsigned char Func( st_struct *ptr )
{
return ptr->first + ptr->second;
}
这是我用来导入上述函数的 C# 代码。
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ImportTest
{
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public class st_struct
{
public byte first;
public byte second;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
st_struct x = new st_struct();
x.first = 1;
x.second = 2;
byte result = Func(ref x);
}
[DllImport("MarshalTest.dll")]
protected static extern byte Func(ref st_struct inputs);
}
}
我的问题是 Func 的 return 值不是 3,它应该是 (1 + 2)。
我正在使用调试器查看 DLL 中的值 - 它们不同(不是我提供的 1 和 2)。
当我像这样更改 C# 代码时,函数 return 的正确值:
public Form1()
{
InitializeComponent();
st_struct x = new st_struct();
x.first = 1;
x.second = 2;
byte result = Func(x);
}
[DllImport("MarshalTest.dll")]
protected static extern byte Func(st_struct inputs);
删除 ref 后问题消失。但是我不明白为什么。
你能解释一下吗?
您可能认为 ref
关键字是 passing parameter by reference
所必需的。但是由于st_struct
定义为引用类型(class是引用类型),所以参数是按引用传递的,不是按值传递的。您不需要 ref
关键字。
如果 st_struct
被定义为 struct
,当您使用 ref
关键字时,您可能会发现它有效。
正如@kennyzx 所提到的,由于您的 st_struct
是一个 class,它已经是一个引用类型并将作为指针传递。我怀疑将 ref
放在上面会给你一个双指针,这在混合托管和非托管代码时没有多大意义。如果指针发生变化,编组器可能会处理它并为您创建一个新对象,但这似乎是一件粗略的事情。
因此,当在没有 ref
的情况下传递 class 时,它会按预期工作(C 代码获得一个指针)。如果将其更改为 struct
,则在不使用 ref
的情况下传递它应该将其传递到堆栈上,而使用 ref
传递它会将其作为指针传递。
使用 struct
在你的情况下似乎是显而易见的选择,因为它可以直接传递(CLR 只需要固定它并传递一个指针)。使用 class
我怀疑会涉及更多编组。