我有一个 DLL,我需要从中 P/调用以下 C 方法:
int DAStart(
HANDLE hOpen,
char* IPAddress,
int IPPort,
int threadPriority,
char* name,
char* password,
char* userName)
使用 P/Invoke Assistant 和我自己的研究,我得出了以下 C# 签名:
[DllImportAttribute("<libName>", EntryPoint="DAStart")]
static extern int DAStart(
IntPtr hOpen,
[MarshalAs(Unmanaged.LPStr)] StringBuilder IPAddress,
int IPPort,
int threadPriority,
[MarshalAs(Unmanaged.LPStr)] StringBuilder name,
[MarshalAs(Unmanaged.LPStr)] StringBuilder password,
[MarshalAs(Unmanaged.LPStr)] StringBuilder userName);
现在,我按以下方式进行调用:
int port = 3000;
int threadPriority = 20;
DAStart(
this.nativeDllHandle, // an IntPtr class field
new StringBuilder("10.0.10.1"),
int port,
int threadPriority,
new StringBuilder("admin"),
new StringBuilder("admin"),
new StringBuilder("admin"));
现在,有时这工作得很好,但我遇到了 Win32 错误 1008 - 试图引用一个不存在的 token
在随后调用此库时。
会不会是我的 StringBuilder 对象被垃圾回收,因此如果 native 代码尝试使用它,引用将不再存在?我应该为他们每个人保留一份引用吗?
在这种情况下,IntPtr 是否是传递我的字符串的更好解决方案?
** 更新 **
这是我拥有的 DAStart 的所有 API 文档:
输入
HANDLE hInfo DAOpen返回的句柄
char *IPAdress_in TMEE服务器的IP地址
int IPPort TMEE Server 控制台端口(默认为 3000 端口)
int threadPriority 发送文件线程的线程优先级。
char *name 未在硬件 DLL 中使用
char *password 不用于硬件 DLL
char *username 不在硬件 DLL 中使用
返回
错误_成功 0
ERROR_BAD_HANDLE -1
ERROR_BIND_FAILED -10
评论
DAStart API 将客户端 dll 连接到事件的 TMEE 服务器服务。客户端线程以设置为 threadPriority 参数的优先级启动。 IP 地址参数必须设置为 TMEE 服务器的地址。端口参数必须设置为 TMEE 服务器监听控制台连接的端口(控制台使用的默认端口为 3010)。控制台线程以设置为 threadPriority 参数的优先级启动。
最佳答案
在注释中,您指出 DLL 获取 char*
指针的副本(而不是字符串的内容),然后在 之后修改字符串的内容> DAStart
返回。
面对这种非常规的界面设计,您唯一的选择就是负责字符串参数的编码。您不能使用 StringBuilder
,因为传递给 native 代码的 char*
仅在 pinvoke 调用期间有效。不能相信它在 pinvoke 调用返回后有效。
所以您唯一的解决方案是将字符串参数作为 IntPtr
传递。使用 Marshal.StringToHGlobalAnsi
分配内存。将生成的 IntPtr
传递给 DAStart
。当您确定 DLL 已使用指针完成时,使用 Marshal.FreeHGlobal
解除分配。
关于c# - P/Invoke 有时会导致 Win32 1008 Error with StringBuilder parameters,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9604779/