用char*参数用P/Invoke调用一个C DLL函数
本文关键字:一个 函数 DLL 调用 char 参数 Invoke | 更新日期: 2023-09-27 17:58:01
我读过其他类似的问题,但它们并不能解决这个特定的问题。我有一个带有touppercase函数的旧C库(作为示例)。这将获取一个char*并返回一个char*。然而,返回的指针是指向同一字符串的指针(不要问我没有写)。
功能如下:
__declspec(dllexport)
char * __cdecl touppercase(char *ps_source)
{
char *ps_buffer = NULL;
assert (ps_source != NULL);
ps_buffer = ps_source;
while (*ps_buffer != ''0')
{
*ps_buffer = toupper(*ps_buffer);
ps_buffer++;
}
*ps_buffer = ''0';
return (ps_source);
}
声明这一点的C#代码看起来像:
[DllImport("mydll.dll", EntryPoint = "touppercase",
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern System.IntPtr touppercase(string postData);
我的应用程序中对此的调用看起来像
string sTest2 = Marshal.PtrToStringAnsi(to_uppercase(sTest));
然而,sTest2最终只是一个随机字符串。
我用相同的参数向同一个dll添加了一个测试函数,但这会在本地分配内存并复制字符串。这很好用。为什么原始版本现在有效?
注意:更新dll库本身不是一个选项。
函数正在修改引用,因此您应该使用字符串生成器:
[DllImport("dll.dll", EntryPoint="touppercase",
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern System.IntPtr touppercase(StringBuilder postData);
可以这样称呼它:
StringBuilder sTest = new StringBuilder("abs");
touppercase(sTest);
string result = sTest.ToString();
关于返回指针的解释->Ben Voigt
正如您正确观察到的,返回类型是指向同一字符串的指针。提供给函数的字符串是.NET用于Unicode->ANSI转换的临时缓冲区,在P/Invoke返回之前解除分配。所以它是一个必须忽略的野生指针(最好只使用C#void返回类型)。
我还建议使用StringBuilder
而不是String
作为参数,这让.NET知道该函数将更改传递的参数。StringBuilder
的内容将被函数修改,这就是在没有返回值的情况下获得结果的方式。