了解C++ DLL 映射到具有联合的 C#
本文关键字:C++ DLL 映射 了解 | 更新日期: 2024-10-30 07:09:41
我有以下情况。我有一个在用 C++ 编写的 DLL 中带有联合的结构,我需要将此结构映射到 C# 代码。请记住,我无法更改 DLL 中的代码。下面是一个示例代码来说明正在发生的事情:
typedef struct {
int type;
union {
int val;
double val2;
char *name;
};
} BIZARRE;
__declspec(dllexport) void changeBizarre(BIZARRE *bizarre, int type, const char *v)
{
bizarre->type = type;
if(type == 0) {
bizarre->val = 5;
} else if(type == 1) {
bizarre->val2 = 2.0;
} else if(type == 2) {
strncpy(bizarre->name, "test", strlen("test"));
} else if(type == 3 && strcmp(v, "test") == 0) {
bizarre->val = 10;
}
}
在 C# 代码中,我完成了以下操作:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct BIZARRE
{
[FieldOffset(0)]
public int type;
[FieldOffset(8)]
public int val;
[FieldOffset(8)]
public double val2;
[FieldOffset(8)]
public char *name;
}
[DllImport("proj.dll", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void changeBizarre(ref BIZARRE bizarre, int type, char *name);
unsafe static void Main()
{
char[] v = "test".ToCharArray();
bizarre.type = 0;
bizarre.val = 0;
bizarre.val2 = 0.0;
fixed (char* address = v)
{
bizarre.name = address;
changeBizarre(ref bizarre, 3, &bizarre.name);
Console.WriteLine("{0}", bizarre.val);
}
Console.ReadKey();
}
现在,如果您通过传递类型 = 2 来运行此代码,并尝试打印 bizarre.name,它将显示垃圾字符,如果您传递类型 = 3,显然 DLL 无法获取 bizarre.name 指向的内容,我相信这两种行为具有相同的原因,但我不知道它是什么。
char
数组在 C 中不是真正的char
数组,实际上 C# 将使用wchar_t
类型(16 位字符)。
使用wchar_t
的东西更改您的 C 代码:
typedef struct {
int type;
union {
int val;
double val2;
wchar_t *name;
};
} BIZARRE;
__declspec(dllexport) void changeBizarre(BIZARRE *bizarre, int type, const wchar_t *v)
{
bizarre->type = type;
if (type == 0) {
bizarre->val = 5;
}
else if (type == 1) {
bizarre->val2 = 2.0;
}
else if (type == 2) {
wcsncpy(bizarre->name, L"test", wcslen("test"));
}
else if (type == 3 && wcscmp(v, L"test") == 0) {
bizarre->val = 10;
}
}
或
使用 byte
类型而不是 char
更改 C# 代码(如 Passant @Hans所述):
[StructLayout(LayoutKind.Explicit)]
public unsafe struct BIZARRE
{
[FieldOffset(0)]
public int type;
[FieldOffset(8)]
public int val;
[FieldOffset(8)]
public double val2;
[FieldOffset(8)]
public byte* name;
}
class Program
{
[DllImport("UnionMapping_dll.dll", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void changeBizarre(ref BIZARRE bizarre, int type, byte* name);
static unsafe void Main(string[] args)
{
BIZARRE bizarre;
byte[] v = Encoding.ASCII.GetBytes("test");
bizarre.type = 0;
bizarre.val = 0;
bizarre.val2 = 0.0;
fixed (byte* address = v)
{
bizarre.name = address;
changeBizarre(ref bizarre, 3, bizarre.name);
Console.WriteLine("{0}", bizarre.val);
}
Console.ReadKey();
}
}
C++代码在结构中具有联合 - 用于互操作目的的 C# 等效项应反映:
using System.Runtime.InteropServices;
public struct BIZARRE
{
public int type;
[StructLayout(LayoutKind.Explicit)]
public struct AnonymousStruct
{
[FieldOffset(0)]
public int val;
[FieldOffset(0)]
public double val2;
[FieldOffset(0)]
public string name;
}
}