为啥这个显式 P/Invoke 不起作用?
Posted
技术标签:
【中文标题】为啥这个显式 P/Invoke 不起作用?【英文标题】:Why this Explicit P/Invoke does not work?为什么这个显式 P/Invoke 不起作用? 【发布时间】:2010-06-10 14:25:25 【问题描述】:以下 .net 到本机 C 代码不起作用,任何想法
extern "C"
TRADITIONALDLL_API int TestStrRef( __inout char* c)
int rc = strlen(c);
std::cout << "the input to TestStrRef is: >>" << c << "<<" ;
c = "This is from the C code ";
return rc;
[DllImport("MyDll.dll", SetLastError = true)]
static extern int TestStrRef([MarshalAs(UnmanagedType.LPStr)] ref string s);
String abc = "InOut string";
TestStrRef(ref abc);
此时,Console.WriteLine(abc) 应该打印“This is from the C code”,但没有,有什么想法吗?
仅供参考 - 我有另一个不使用 ref 类型字符串的测试函数,它工作得很好
【问题讨论】:
首先让它在 C 中工作。 Native C - 它是 C .net - 不知道 :( 【参考方案1】:您的代码在 C 端也有错误。 __inout 注释只是告诉编译器您可以更改“c”参数指向的缓冲区。但是指针本身位于堆栈中,如果您修改了“c”参数,则不会返回给调用者。 您的声明可能如下所示:
extern "C"
TRADITIONALDLL_API int TestStrRef( __inout char** c)
int rc = strlen(*c);
std::cout << "the input to TestStrRef is: >>" << *c << "<<" ;
*c = "This is from the C code ";
return rc;
还有 C# 方面:
[DllImport("MyDll.dll", SetLastError = true)]
static extern int TestStrRef(ref IntPtr c);
String abc = "InOut string";
IntPtr ptrOrig = Marshal.StringToHGlobalAnsi(abc)
IntPtr ptr = ptrOrig; // Because IntPtr is structure, ptr contains copy of ptrOrig
int len = TestStrRef(ref ptr);
Marshal.FreeHGlobal(ptrOrig); // You need to free memory located to abc' native copy
string newAbc = Marshal.PtrToStringAnsi(ptr);
// You cannot free memory pointed by ptr, because it pointed to literal string located in dll code.
【讨论】:
【参考方案2】:这对你有用吗?基本上只需在 DllImport 语句中添加 CallingConvention = CallingConvention.Cdecl 即可。您可能还想指定CharSet(例如:CharSet:=CharSet.Unicode)
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
static extern int TestStrRef([MarshalAs(UnmanagedType.LPStr)] ref string s);
【讨论】:
为什么调用约定很重要?调用方法已经为 OP 工作了。以上是关于为啥这个显式 P/Invoke 不起作用?的主要内容,如果未能解决你的问题,请参考以下文章