我认为问题出在我的C++函数中,但我试过了
C++中的C++函数:
bool __declspec( dllexport ) OpenA(std::string file)
{
return true;
}
Run Code Online (Sandbox Code Playgroud)
C#代码:
[DllImport("pk2.dll")]
public static extern bool OpenA(string path);
if (OpenA(@"E:\asdasd\"))
Run Code Online (Sandbox Code Playgroud)
我得到一个例外,内存已损坏,为什么?
如果我删除了std :: string参数,它的效果很好,但是使用std :: string它不起作用.
我有一个非托管的C++ DLL,我用一个简单的C接口包装,所以我可以从C#上调用PInvoke.这是C包装器中的示例方法:
const wchar_t* getMyString()
{
// Assume that someWideString is a std::wstring that will remain
// in memory for the life of the incoming calls.
return someWideString.c_str();
}
Run Code Online (Sandbox Code Playgroud)
这是我的C#DLLImport设置.
[DllImport( "my.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl )]
private static extern string GetMyString();
Run Code Online (Sandbox Code Playgroud)
然而,字符串没有被正确编组,通常搞砸了第一个字符,或者有时会显示出一堆中文字符.我已经记录了C端实现的输出,以确认std :: wstring是否正确形成.
我还尝试更改DLLImport以返回IntPtr并使用Marshal.PtrToStringUni使用包装方法进行转换,它具有相同的结果.
[DllImport( "my.dll", CallingConvention = CallingConvention.Cdecl )]
private static extern IntPtr GetMyString();
public string GetMyStringMarshal()
{
return Marshal.PtrToStringUni( GetMyString() );
}
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
因此,如下所述,这不是我的绑定的问题,而是我的wchar_t*的生命周期.我的书面假设是错误的,someWideString实际上是在我调用应用程序的其余部分时被复制的.因此它只存在于堆栈中,并且在我的C#代码完成编组之前就被释放了.
正确的解决方案是将指针传递给我的方法,如shf301所述,或者确保在我的C#接口有时间复制之前,我的wchar_t*引用不会被移动/重新分配/销毁.
将std :: wstring作为"const&std :: wstring"返回到我的C层意味着我对c_str()的调用将返回一个不会在我的C方法范围之外立即释放的引用.
然后调用C#代码需要使用Marshal.PtrToStringUni()将数据从引用复制到托管字符串.