【问题标题】:Marshalling C++ struct to C#将 C++ 结构编组为 C#
【发布时间】:2014-06-27 01:00:02
【问题描述】:

我在非托管 C++ 中有这么简单的结构:

struct Cam
{
    char ip[16];
    char login[16];
    char pass[16];
    char name[16];
};

和 C# 编组结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct Cam
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string ip;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string login;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string pass;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string name;
}

当我通过函数将 C# struct 传递给 C++ lib 时

[DllImport("NVRLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void AddCameraStruct(Cam cam);
...
Cam cam = new Cam();
cam.ip = "192.168.0.232";
cam.login = "admin";
cam.pass = "admin";
cam.name = "kekekeke";
AddCameraStruct(cam);

并在 C++ 中打印传递的值:

__declspec(dllexport) void AddCameraStruct(Camera cam)
{
    printf(cam.ip);
    printf("\n");
    printf(cam.login);
    printf("\n");
    printf(cam.name);
    printf("\n");
    printf(cam.pass);
    strcpy(camera[CAM_NUM].ip, cam.ip);
    strcpy(camera[CAM_NUM].login, cam.login);
    strcpy(camera[CAM_NUM].pass, cam.pass);
    strcpy(camera[CAM_NUM].name, cam.name);
    CAM_NUM++;
}

打印出来:

232
<EMPTY LINE>
192.168.0.232
n

我做错了什么?

【问题讨论】:

  • 请添加 c++ 'Camera' 类
  • __declspec(dllexport) __cdecl void AddCameraStruct(Camera cam)
  • @SaniHuttunen 如果您认为这可以解决问题,您应该将其发布为答案,而不是评论。 (我认为不会,但我可能会弄错。)
  • @SaniHuttunen 输入您所写的内容后出现错误“缺少显式类型”
  • @Lukas 我认为 Jossef Harush 的观点是您的 AddCameraStruct 的参数类型为 Camera,而不是 Cam,并且您的问题中缺少 Camera 的定义。 @SaniHuttunen 够公平的。

标签: c# c++


【解决方案1】:

在我从你们的 cmets 那里学到了更多之后,

改变

__declspec(dllexport) void AddCameraStruct(Camera cam)

__declspec(dllexport) void AddCameraStruct(Cam cam)

【讨论】:

    【解决方案2】:

    更新:你写道:

    你是对的,我错过了,IDE 没有给我任何建议,因为我确实也有 C++ 中的 Camera 类。谢谢:)

    我认为这是一个复制和粘贴错误。在下面的示例中,它已经像这样进行了更正,并且可以正常工作。如果您的代码包含Cam,不确定为什么/如果您收到错误,因为它不是一个可识别的结构(至少在我的环境中)。

    底线:您展示的代码部分可以正常工作。您使用UnmanagedType.ByValTStr,这取决于所选的字符集,您将其定义为CharSet = CharSet.Ansi,然后映射到DLL 库中的char *。这就是它应该被编组的方式,它是正确的。

    我创建了一个测试应用PInvokeTestDll,如下:

    DLL 部分,在 Win32 本机 DLL 项目中:

    #include <atlbase.h>
    
    WIN32_DLL_UNMANGLED_API void AddCameraStruct(Camera cam)
    {
        USES_CONVERSION;
        OutputDebugString(A2W(cam.ip));
        OutputDebugString(A2W(cam.login));
        OutputDebugString(A2W(cam.name));
        OutputDebugString(A2W(cam.pass));
    }
    

    在头文件中:

    #define WIN32_DLL_UNMANGLED_API extern "C" _declspec(dllexport)
    
    struct Camera
    {
        char ip[16];
        char login[16];
        char pass[16];
        char name[16];
    };
    
    WIN32_DLL_UNMANGLED_API void AddCameraStruct(Camera cam);
    

    在 C# 项目中:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct Cam
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
        public string ip;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
        public string login;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
        public string pass;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
        public string name;
    }
    
    class Program
    {
        [DllImport(@"PInvokeTestDll.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void AddCameraStruct(Cam cam);
    
        static void Main(string[] args)
        {
            Cam cam = new Cam
            {
                ip = "192.168.0.232", 
                login = "admin", 
                pass = "admin", 
                name = "kekekeke"
            };
            AddCameraStruct(cam);
        }
    }
    

    运行此项目会在 Visual Studio 的“输出”>“调试”窗口中显示以下内容:

    192.168.0.232adminkekekekeadmin
    

    如您所见,我将 Cam 结构重命名为 Camera 结构,假设这是您这边的剪切和粘贴错误。我还删除了printf 语句,因为您在调试期间看不到输出(并且OutputDebugString 需要LPCWSTR,因此需要ATL 宏A2W)。

    我的猜测是您没有展示实际导致您的结构失败的部分。我假设它在 C++ 端,因为如果结构是您键入的,它“简单地工作”(这也通过在调试期间单步进入 DLL 函数期间悬停在结构的字段上“证明”)。我建议您按照我的做法隔离问题:创建一个仅处理编组和 DLL 导出函数原型的测试项目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-17
      • 2022-11-22
      • 1970-01-01
      相关资源
      最近更新 更多