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# 包装类的主要内容,如果未能解决你的问题,请参考以下文章