我有一个DLL,我需要P / Invoke以下C方法:
int DAStart(
HANDLE hOpen,
char* IPAddress,
int IPPort,
int threadPriority,
char* name,
char* password,
char* userName)
使用P / Invoke助手和我自己的研究,我想出了以下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 - An attempt was made to reference a token that does not exist
。
可能是我的StringBuilder对象被垃圾收集,以便在本机代码尝试使用它时引用不再存在?我应该为每一个提供参考吗?
在这种情况下,IntPtr会更好地传递我的字符串吗?
** 更新 **
这是我为DAStart提供的所有API文档:
输入
HANDLE hInfo DAOpen返回的句柄
char * IPAdress_in TMEE服务器的IP地址
int IPPort控制台TMEE服务器端口(默认为端口3000)
int threadPriority发送文件线程的线程优先级
char * name未在硬件DLL中使用
char *密码未在硬件DLL中使用
char * username未在硬件DLL中使用
返回
ERROR_SUCCESS 0
ERROR_BAD_HANDLE -1
ERROR_BIND_FAILED -10
评论
DAStart API将客户端DLL连接到活动的TMEE Server服务。启动客户端线程时,优先级设置为threadPriority参数。 IP地址参数必须设置为TMEE服务器的地址。必须将port参数设置为TMEE Server侦听Console连接的端口(控制台使用的默认端口为3010)。启动Console线程时,优先级设置为threadPriority参数。
答案 0 :(得分:2)
在评论中,您指出DLL会获取char*
指针的副本(而不是字符串的内容),然后在 {{1>之后修改字符串的内容返回。
面对这种非常规的界面设计,您唯一的选择是掌控字符串参数的编组。您无法使用DAStart
,因为传递给本机代码的StringBuilder
仅在pinvoke调用期间有效。在pinvoke调用返回后,不能依赖它是有效的。
因此,您唯一的解决方案是将字符串参数传递为char*
。使用IntPtr
分配内存。将生成的Marshal.StringToHGlobalAnsi
传递给IntPtr
。当您确定DLL已完成指针时,请使用DAStart
解除分配。
答案 1 :(得分:-2)
垃圾收集器不知道托管环境之外的引用。
因此,只要您需要对象,就需要在某处保留一个额外的引用 - 最简单的方法是通过调用类中的静态属性。
IntPtr没有什么区别 - 它也会被收集。