【发布时间】:2018-02-07 08:29:56
【问题描述】:
我有一个 ASP.NET Web 应用程序,它需要访问本机 C++ DLL 中的函数。为此,我使用托管 C++ DLL 包装了本机 C++ 代码。但是,从托管代码调用本机函数会导致 System.AccessViolationException。我不必使用本机代码,但它会写入文件系统(日志),这是我的第一个猜测,但根据其他 SO 答案,AccessViolationException 是由内存问题引起的。
代码很简单,这是精简版:
#include <msclr\marshal_cppstd.h>
#define AS_NATIVE_STRING(managed_string) msclr::interop::marshal_as<std::string>(managed_string)
#define AS_MANAGED_STRING(native_string) msclr::interop::marshal_as<String^>(native_string)
ReturnStruct ManagedClass::execute_managed(String ^param1, String ^param2)
{
auto param1_native = AS_NATIVE_STRING(param1);
auto param2_native = AS_NATIVE_STRING(param2);
// here I get the exception:
auto result = _wrapped_api->execute_native(param1_native, param2_native);
if (is_error_string(result.first))
throw gcnew System::Exception(AS_MANAGED_STRING(result.second));
auto result1 = AS_MANAGED_STRING(result.first);
auto result2 = AS_MANAGED_STRING(result.second);
return ReturnStruct(result1, result2);
}
关于可能导致它的任何提示?我确实看过类似的问题,但似乎没有一个答案真正适合我的问题。
编辑:
使用HandleProcessCorruptedStateExceptionsAttribute,我能够确定AccessViolationException 的错误消息:“尝试读取或写入受保护的内存。这通常表明其他内存已损坏。”
【问题讨论】:
-
尝试使用 std::wstring 代替 std::string。
-
这不是一个真正的选择,因为包装的代码只接受
std::string,我无法改变它。除此之外,根据docs.microsoft.com/cpp/dotnet/overview-of-marshaling-in-cpp,std::string和System::String^之间的转换是有效的。是的,我可能会从System::String^转换为std::wstring,然后再转换为std::string,但我不想碰std::wstring,所以你能告诉我你的建议背后的原因吗?这只是一个疯狂的猜测还是一个有根据的建议? -
只是字符串由 16 位字符组成。好的,如果您保留 std ASCII 集,但除此之外的任何内容,并且您使用 utf-8/wchars 等。此代码是在其自己的文件中还是大型托管 C++ 代码的一部分?托管/非托管的东西通常需要在一个单独的源文件中。我从来没有找到原因,但通常有效。
-
这可能是真的,但我刚刚验证,编组到多字节字符串也适用于非 ASCII 字符,或者基本上:这可以正常工作。整个 DLL 仅包含 6 个混合托管代码和本机代码的函数,所以是的,您可以说它们位于单独的文件中。
标签: c++ managed-c++