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

时间:2015-01-16 21:01:09

标签: c# string dll pinvoke

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

我一直收到错误“尝试读取或写入受保护的内存。这通常表明其他内存已损坏。”尝试从dll中检索字符串时。我承认这是一个假设,但是我在运行AIM_GetVersion之前可以运行的两个dll命令(两者都返回整数)都运行良好(不仅没有返回任何错误,而是从设备检索响应)。到目前为止我所读到的内容表明,使用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

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

1 个答案:

答案 0 :(得分:2)

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

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