非托管c++代码向托管代码发送字符串的错误

Bug with Unmanaged C++ code sending a string to Managed code

本文关键字:字符串 错误 托管代码 c++ 代码      更新时间:2023-10-16

我有一个c#项目,它使用了一个非托管的c++静态库。当c#从非托管代码中返回字符串时,我得到了一个奇怪的错误。程序崩溃,VS告诉我可能的堆损坏。字符串是非托管代码中对象中的一个字段,因此它不是局部变量问题。奇怪的是,崩溃总是在调试模式下发生,而只有在实际运行程序的一些非常特殊的情况下才会发生。此外,尽管调试崩溃在所有计算机上都是可重现的,但运行时崩溃只发生在某些计算机上。

我应该注意到我有许多函数从非托管代码导出,除了这个函数和另一个做几乎相同的事情(GetBlockInfo)之外,它们都不会引起问题。

下面是导致崩溃的代码行:

string info = CppToCsharpAdapter.GetFileInfo(myHashFilePointer);

CppToCsharpAdapter是我的托管/非托管代码适配器。CppToCsharpAdapter。GetFileInfo调用执行对非托管代码中的GetFileInfo函数的调用。

下面是.cpp中的导出函数:

__declspec(dllexport)   const   char* __stdcall  GetFileInfo(HashFile* THIS)
{
      return THIS->GetFileInfo().c_str();   
}

非托管代码中的GetFileInfo函数:

string& GetFileInfo()
{
    try
    {
        LogicalHeaderBlock *infoBlock = LogicalFHBuffer;
        stringstream infoString;
        infoString<<infoBlock->getHashFuncID()<<endl;
             // many more lines//
        fileInfo = infoString.str();
        return fileInfo;
    }
    catch(exception &e)
    { throw e; }
}

这是导致崩溃的调用堆栈:

ntdll.dll!770a04e4()    
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
ntdll.dll!77062a2a()    
ntdll.dll!770a1b71()    
oleaut32.dll!75c43e59()     
[Managed to Native Transition]  
mscorlib.dll!System.StubHelpers.AnsiBSTRMarshaler.ClearNative(System.IntPtr pNative) + 0x45 bytes   
FMS_adapter.dll!FMS_adapter.HashFile.GetFileInfo() Line 249 + 0xb bytes C#

编辑:更新了调用堆栈,现在我得到[Managed to Native Transition]行,这显然表明问题在那里。

任何帮助都将非常感激。提前谢谢。

编辑:我最终通过c# CppToCsharpAdapter.GetFileInfo()函数返回一个IntPtr,然后将其转换为c#中的字符串来解决问题。

问题在于您的CppToCsharpAdapter.GetFileInfo的p/Invoke定义,您的问题中没有包括该定义。至少,它需要添加以下属性:

[return: MarshalAs(UnmanagedType.LPStr)]

如果省略此属性,p/Invoke层将假设返回的字符串在代码中由BSTR表示,但实际上您使用的是以空结尾的ANSI字符串。这个链接有更多的信息:

字符串的默认封送处理:平台调用中使用的字符串

您的dll导出的GetFileInfo()函数返回原始 const char*,但我不确定这是托管代码的正确类型(除非您使用适当的p/Invoke签名…)。

您是否考虑过返回 BSTR ?BSTR是一个典型的COM字符串,我认为。net非常理解COM,所以它也可以自动释放由本地代码返回的COM分配字符串。

__declspec(dllexport) BSTR __stdcall GetFileInfo(....)
{
    ....
    // Assume that "nativeString" is "const char*".
    // We first convert from ANSI/MBCS to Unicode:
    // (CA2W is a conversion helper defined in <atlconv.h>)
    CA2W unicodeNativeString( nativeString );
    // ...and then we return a BSTR built from it:
    return ::SysAllocString( unicodeNativeString );
}

编辑:

作为旁注,另一个(不是dll导出的)GetFileInfo()函数,返回string&,但我建议您只返回string (即只返回string而不是 string&)。