如何正确地将字符串从非托管第三方 dll 返回到 C#



所以,背景信息:我正在尝试向外部设备(即阻抗分析仪,AIM 4170D)发出命令,并已获得一个dll来提供C#代码和设备本身之间的命令接口。我没有 dll 的代码。诚然,我什至不知道dll是用什么语言写的。命令本身的名称以及参数由 dll 附带的文档给出。文档还指出,字符串的长度永远不会超过 255 字节。

我一直收到错误"试图读取或写入受保护的内存。这通常表示其他内存已损坏。 尝试从 DLL 检索字符串时。我承认这是一个假设,但是我可以在运行AIM_GetVersion之前运行的两个 dll 命令(这两个命令都返回 ints)工作正常(不仅不返回错误,而且从设备检索响应)。到目前为止,我所读到的内容表明,使用 dll 中的字符串可能会有问题,但也假设我可以访问 dll 原始代码来解决此问题。

第一次尝试:

[DllImport(@"AIM_863_DLL.dll", CallingConvention = CallingConvention.StdCall)]
public static extern string AIM_GetVersion(int flag);
string ver = AIM_GetVersion(1);

第二次尝试:

[DllImport(@"AIM_863_DLL.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr AIM_GetVersion(int flag);
IntPtr ver = Marshal.AllocHGlobal(255);
ver = AIM_GetVersion(1);
Marshal.FreeHGlobal(ver);

两次尝试在调用AIM_GetVersion时都遇到了相同的错误(如上所述)。如果我尝试在设备关闭时运行第二组,则在FreeHGlobal上出现错误"对内存位置的无效访问"。(好吧,我确实尝试了两件事,但"第二次"尝试是我发现的唯一导致程序行为改变的尝试。我在这里提供了它,以防它可以缩小问题的范围。

另外,我正在使用x86使用VS2010编译它。

感谢您提供的任何帮助。另外,我对此有点陌生,所以如果我遗漏了任何可能有用的东西,我会尽可能提供它。

编辑:好的,我正在将所有相关代码添加到我从第三方获得的这个函数中。在代码的顶部只是简单地列出:

EXPORT  AIM_GetVersion

再往前走,实际函数(它只是在 dll 中更深地调用另一个函数,我没有给出):

' External command for DLL:
SUB AIM_GetVersion(flag:int),string
extcmnd=1
runmode=1
Get_Version(0)
extcmnd=0
if error : s1="34506" : endif
RETURN s1
EndSub

如果我需要更多信息,我可以再次询问公司,但我不确定还能问什么。

你的 Marshal.AllocHGlobal() 调用只会泄漏内存,删除它。 你不能调用Marshal.FreeHGlobal(),字符串在进程堆上分配的几率很小。 像这样的 C 代码通常返回一个文字字符串,它不应该也不能被释放。

只需调用 Marshal.PtrToStringAnsi() 即可将 IntPtr 转换为字符串,仅此而已。 写一个小的测试程序,做十亿次,当它不爆炸时,你会感觉好多了。

最新更新