c# - 了解 C++ DLL 使用 union 映射到 C#

标签 c# c++ pointers dll unions

我有以下场景。我在用 C++ 编写的 DLL 中有一个带有 union 的结构,我需要将此结构映射到 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();
}

现在,如果您通过传递 type = 2 来运行此代码,并尝试打印 bizarre.name,它将出现垃圾字符,如果您传递 type = 3,显然 DLL 无法获取指向的内容by bizarre.name,我相信这两种行为有相同的原因,但我不知道是什么原因。

最佳答案

char 数组并不是 C 中真正的 char 数组,实际上 C# 将使用 wchar_t 类型(16 位 char)。

使用 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# 代码(如@Hans Passant 所述):

[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++ DLL 使用 union 映射到 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36745938/

相关文章:

c - 龟兔赛跑指南

c# - 在 Visual Studio 中有没有办法自动将所有 resx 语言文件添加到项目中?

c# - .net 字典和查找添加/更新

c++ - 指向基于虚拟接口(interface)的可变参数模板类的指针

C++如何在堆栈上动态分配内存?

c - 为什么不能使用指向 char 指针的指针而不是 char 指针数组?

C++ 访问不属于对象本身的内存

c# - 从单个 LINQ 查询中选择多个值

c# - 使用C#连接MYSQL数据库

c++ - 在 C++ 中将电话号码中的字母转换为数字