从PInvoke返回一个字符串?我使用PInvoke实现本机代码(C++)和托管代码(C#)之间的互操作性。我刚刚写了一个简单的函数,它从C++代码中获取一个字符串。我的代码看起来像C#代码:[DllImport("MyDll.dll")]privatestaticexternstringGetSomeText();公共静态字符串GetAllValidProjects(){字符串s=GetSomeText();返回s;}C++代码char*GetSomeText(){std::stringstri="SomeTextHere";char*pchr=(char*)stri.c_str();返回PCHR;在c++的末尾一切正常,即pchr在“C#Here”中包含“SomeTextHere”,但在C#中,字符串s包含注释。我不知道我做错了什么。任何帮助将不胜感激首先,正如其他人所指出的那样,您的C++甚至在您尝试互操作之前就已损坏。您正在返回指向stri缓冲区的指针。但是因为stri在函数返回后立即被销毁,所以返回值是无效的。更何况,即使你解决了问题,你仍然需要做更多的事情。它将无法在C++代码中分配内存,这需要C#代码才能解除分配。有几种选择可以正确完成它。您的C#代码可以向C++代码询问字符串的长度。然后创建一个C#StringBuilder并为其分配适当的大小。接下来,将StringBuilder对象传递给C++代码,其默认封送处理将作为LPWSTR。在这种方法中,C#代码分配字符串,而您的C++代码接收必须复制缓冲区的C字符串。或者,您可以从C++返回BSTR,这允许在本机C++代码中进行分配并在C#代码中取消分配。BSTR方法可能只是我的方式。它看起来像这样:C++#includeBSTRGetSomeText(){return::SysAllocString(L"Greetingsfromthenativeworld!");}C#[DllImport(@"test.dll",CallingConvention=CallingConvention.Cdecl)][返回:MarshalAs(UnmanagedType.BStr)]privatestaticexternstringGetSomeText();更新HansPassant在评论中添加了几个有用的观察结果。首先,大多数P/Invoke互操作是针对无法更改的现有接口完成的,您无法选择首选的互操作接口方法。好像不是这样的,应该选择哪种方法呢?选项1是在首先询问本机代码需要多少空间后,在托管代码中分配缓冲区。也许使用双方同意的固定大小缓冲区就足够了。选项1失败的地方是组装字符串很昂贵并且你不想做两次(例如一次返回它的长度,然后再次返回内容)。这是选项2,BSTR发挥作用的地方。Hans指出了BSTR的一个缺点,那就是它带有一个UTF-16负载,但你的源数据可能没问题,这是一个“麻烦”。为了解决这个问题,您可以按如下方式包装从char*到BSTR的转换:BSTRANSItoBSTR(char*input){BSTRresult=NULL;intlenA=lstrlenA(输入);intlenW=::MultiByteToWideChar(CP_ACP,0,输入,lenA,NULL,0);如果(lenW>0){结果=::SysAllocStringLen(0,lenW);::MultiByteToWideChar(CP_ACP,0,输入,lenA,结果,lenW);}返回结果;这是最难的,现在很容易添加其他包装器以从LPWSTR、std::string、std::wrstring等转换为BSTR。这是因为std::stringstri="SomeTextHere";是一个堆栈对象,在调用GetSomeText()后被销毁。调用后返回一个无效的pchr指针。您可能需要为文本动态分配空间才能访问它。将C++函数定义更改为:char*GetSomeText(){std::stringstri="SomeTextHere";返回strcpy(newchar[stri.size()],stri.c_str());像上面的东西。你明白了……另一种从C++获取字符串的方法。如果您不能修改您的C++DLL。您可以使用IntPtr而不是String来声明DllImport。调用该函数时,可以将Ptr编组回String。[DllImport("MyDll.dll")]privatestaticexternIntPtrGetSomeText();公共静态字符串GetAllValidProjects(){字符串s=Marshal.PtrToStringAnsi(GetSomeText());返回s;}注意:在上一篇文章中提到过。“SomeHereHere”分配在堆栈上,因此无论何时函数返回,堆栈都是无线连接的。因此,数据可能会被覆盖。因此,您应该在调用Marshal.PtrToStringAnsi后立即使用它。不要坚持使用IntPtr。char*GetSomeText(){std::stringstri="这里有一些文本";char*pchr=(char*)stri.c_str();返回PCHR;}如果声明一个字符串变量来存储它,GetSomeText()返回的Char指针是不可接受的。试试[DllImport("MyDll.dll")]privatestaticexternstringGetSomeText();publicstaticstringGetAllValidProjects(){strings=newstring(GetSomeText());返回s;C#学习教程:从PInvoke返回一个字符串?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
