c++ lib dll 的 C# 包装类

Posted

技术标签:

【中文标题】c++ lib dll 的 C# 包装类【英文标题】:C# wrapper class for c++ lib dll 【发布时间】:2012-04-28 09:02:13 【问题描述】:

我正在尝试在 c# 中创建一个类来访问 c++ 库中的函数。 c++ dll中的函数:bool WriteReply(const unsigned char *reply, const unsigned long reply_length).

它在 c++ 中的使用示例:-

unsigned short msg_id = 0x0000;                      
byte msg_body[] = (byte)(GetTickCount()/0x100);    // a random value for loopback data

    // combine the message id and message body into an big msg
    unsigned long msg_length = sizeof(msg_id)+sizeof(msg_body);
    byte* big_msg = new byte[msg_length];
    big_msg[0] = LOBYTE(msg_id);
    big_msg[1] = HIBYTE(msg_id);
    memcpy((void*)&big_msg[2], (void*)msg_body, sizeof(msg_body));

    // send the big message
    if (!big_dev.WriteReply(big_msg, msg_length))
    
        //do something here
    

我似乎无法将函数从 c# 传递给 dll (AccessViolationException)。这是我尝试过的命令:-

byte[] bytearray = new byte[3]  0x01, 0x02, 0x03 ;
IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytearray.Length);
Marshal.Copy(bytearray, 0, unmanagedPointer, bytearray.Length);

bool writestatus = (bool)NativeMethods.WriteReply(unmanagedPointer, (uint)bytearray.Length);

在进口方面:-

[DllImport("dllname.dll", EntryPoint = "WriteReply")]
[return: MarshalAs(UnmanagedType.U1)]
internal static extern bool WriteReply(IntPtr msg, uint reply_length);

请告诉我哪里出错了?谢谢!

【问题讨论】:

你很接近。减去 reply_length 参数,这是一个 uint,而不是 ulong。 感谢Hans Passant 的回复,但它不起作用。我仍然收到 AccessViolationException。还有其他建议吗?你为什么说reply_length是一个uint,而不是ulong?谢谢! 因为 long 在 C++ 中是 32 位的。使用调试器找出问题所在。 同一个问题不要问两次:***.com/questions/10370895/… @Johann - AccessViolationException 和“.dll”应该是平台的好选择器。并且无法使其正常工作:) 【参考方案1】:

假设你的 C++ 方法使用了字符串并且没有修改它...

试试这个

__declspec(dllexport) bool __cdecl WriteReply(const unsigned char *reply, const unsigned long reply_length);


[DllImport("libfile.dll", EntryPoint = "WriteReply")]
private static extern bool WriteReplyExternal(
    [MarshalAs(UnmanagedType.LPStr)] [Out] string replyString,
    [Out] UInt32 replyLength);

或者更好(因为C字符串是空终止的并且缓冲区是只读的,所以你不必担心缓冲区溢出,长度参数是多余的):

__declspec(dllexport) bool __cdecl WriteReply(const unsigned char *reply);


[DllImport("libfile.dll", EntryPoint = "WriteReply")]
private static extern bool WriteReplyExternal(
    [MarshalAs(UnmanagedType.LPStr)] [Out] string replyString);

如果方法不在类中,这些将起作用,否则您需要use the C++ mangled name as the entry point。

如果您的字符串包含 1...127 ASCII 范围之外的字符(例如非英文字母),您应该在 C++ 中使用 wchar_t 而不是 char,在编组中使用 LPWStr 而不是 LPStr。

编辑:

您需要用另一个方法包装私有方法,该方法具有更适合 .NET 的签名,例如

public void WriteReply(string message)

    var result = WriteReplyExternal(message, message.Length);
    if (result == false)
        throw new ApplicationException("WriteReplay failed ...");

【讨论】:

嗨,丹尼,感谢您的回复。实际上,该函数是 c# lib 将包含 msg 及其长度的字符串传递给 c++ lib dll 的地方。然而,c++ lib dll 只接受这些参数:“const unsigned char *reply”以及“const unsigned long reply_length”。我的问题是我不知道如何将字符串和长度从 c# 传递给 c++ dll 并接受来自 c++ dll 的布尔回复。有什么建议吗?谢谢! 嗨,试过了..也没有用..我想我没有将它作为指向字节数组的指针传递,就像它在 c++ 示例代码中的处理方式一样(参见上文)。你怎么看?谢谢! 首先,char 数组不是字节数组,其次我用字符串做过很多次。使用depends (dependencywalker.com) 打开你的C++ DLL 并检查暴露的签名。【参考方案2】:

我认为最新添加的代码为真正的问题提供了线索:

if (!big_dev.WriteReply(big_msg, msg_length))

这不起作用,因为WriteReply 是一个成员函数。您需要调用 C 样式函数而不是 C++ 成员函数。后者需要一个实例(代码示例中的big_dev)。

【讨论】:

我已经清理了这里的代码/问题,ReplyMsg/WriteReply 在这里实际上是错字;我已经根据代码中的内容对其进行了更正。我现在正要尝试 Danny Varod 的建议:) 我回答的重点是。如果这是一个成员函数,那么 Danny 的回答将无济于事。即使不是成员函数,丹尼的回答也无济于事。正如您已经说过的,这不是一个以 null 结尾的字符串,因此 Danny 的答案中的所有内容都不适用。反复试验不是您在这里需要的。你需要考虑问题。 我不明白你的回复。 c++ 示例文件工作正常。当我尝试从 c# 访问 .dll 时,它只是不起作用。 C++ 代码似乎正在调用成员函数。是这样吗?

以上是关于c++ lib dll 的 C# 包装类的主要内容,如果未能解决你的问题,请参考以下文章

C# 包装类和来自 c++ 的 dllimport

从 C# 调用 C++ dll 方法/类

用于 C++ 的 C# 包装器,但仅编译为静态库

在 Visual Studio 2010 Express 中从 dll 自动生成 C# 包装类?

用多个 C# .dll 包装多个 C++ .dll

Swig C++ to C#:如何从 C++ 包装类以使模板类中的方法在 C# 的派生类中可用?