.net 4.0 -如何防止在64位Windows上从c++到c#返回字符串时出现AccessViolationExce
.net 4.0 - How do I prevent AccessViolationException when returning a string from C++ to C# on 64-bit Windows?
我正在使用第三方专有DLL,我无法获得其源代码。不过,我可以使用SWIG 1.3.39自动生成的包装器代码。包装器代码由编译成DLL的c++文件(使用一些描述DLL的头文件)和对c++包装器DLL进行PInvoke调用的c#项目组成。
根据我对供应商文档的解释,我已经根据目标平台将解决方案中的所有内容编译为x86或x64。供应商提供了32位和64位版本的专有DLL,我已经确保在给定的构建中使用了正确的DLL。我的机器是32位的。在我的机器上测试我的应用程序的x86版本,无论是发布版本还是调试版本,似乎都工作得很好。然而,在64位上,应用程序在Debug模式下工作,但在System模式下失败。
我读了一篇很好的博客文章,它似乎很好地描述了调试与发布的问题,以及引起这篇博客文章的这个问题和答案。但是,我不确定如何排除这种情况下的问题。
AccessViolationException似乎在第一次从c++包装器返回(或试图返回)任何实际长度的字符串时发生。下面是有问题的c#代码:
// In one file of the C# wrapper:
public string GetKey()
{
// swigCPtr is a HandleRef to an object already created
string ret = csWrapperPINVOKE.mdMUHybrid_GetKey(swigCPtr);
return ret;
}
// In the csWrapperPINVOKE class in another file in the C# wrapper:
[DllImport("csWrapper.dll", EntryPoint="CSharp_mdMUHybrid_GetKey")]
public static extern StringBuilder mdMUHybrid_GetKey(HandleRef jarg1);
和c++包装器中麻烦的c++代码:
SWIGEXPORT char * SWIGSTDCALL CSharp_mdMUHybrid_GetKey(void * jarg1) {
char * jresult ;
mdMUHybrid *arg1 = (mdMUHybrid *) 0 ;
char *result = 0 ;
arg1 = (mdMUHybrid *)jarg1;
result = (char *)(arg1)->GetKey();
jresult = SWIG_csharp_string_callback((const char *)result);
return jresult;
}
SWIGEXPORT
已经定义为__declspec(dllexport)
。在调试中,我发现SWIG_csharp_string_callback
,定义为:
/* Callback for returning strings to C# without leaking memory */
typedef char * (SWIGSTDCALL* SWIG_CSharpStringHelperCallback)(const char *);
static SWIG_CSharpStringHelperCallback SWIG_csharp_string_callback = NULL;
被设置为委托(在c#包装器中):
static string CreateString(string cString) {
return cString;
}
我试过用这段代码来使用Marshal.PtrToStringAut
这样的结构,但无济于事。如何排除故障和/或解决此问题?
正确的方法是让托管代码分配非托管代码将写入的缓冲区(字符串数据)。假设由于某种原因这是不切实际的,您需要做的是以一种可以从托管代码中释放的方式分配字符串数据。
通常的方法是使用LocalAlloc
分配内存,然后可以使用Marshal.FreeHGlobal
从托管代码中释放内存。这样你就不再需要SWIG_csharp_string_callback
和CreateString
了。
c++代码:
SWIGEXPORT HLOCAL SWIGSTDCALL CSharp_mdMUHybrid_GetKey(mdMUHybrid* jarg1)
{
char const* const str = jarg1->GetKey();
std::size_t const len = std::strlen(str);
HLOCAL const result = ::LocalAlloc(LPTR, len + 1u);
if (result)
std::strncpy(static_cast<char*>(result), str, len);
return result;
}
c#代码:
// In one file of the C# wrapper:
public string GetKey()
{
return csWrapperPINVOKE.mdMUHybrid_GetKey(swigCPtr);
}
// ...
public static class csWrapperPINVOKE
{
// ...
[DllImport("csWrapper.dll")]
private static extern IntPtr CSharp_mdMUHybrid_GetKey(HandleRef jarg1);
public static string mdMUHybrid_GetKey(HandleRef jarg1)
{
var ptr = CSharp_mdMUHybrid_GetKey(jarg1);
try
{
return Marshal.PtrToStringAnsi(ptr);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}
作为题外话,你展示的那一小段c++代码是一个丑陋的带有类的C语言遗迹;如果这是其余代码库的代表,那么,哇……: -/ - 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- C 字符串返回字符串的整数/双精度/长整型值
- 如何从COM模块中的函数返回字符串数组?
- React Native (Android):无法通过 JNI 在 jobject 中返回字符串
- 我如何在函数 cpp 中返回字符串
- 我有一个返回字符串向量的函数.它需要两个字符串,并且返回一个字符串中缺少的字符串
- 格式化返回字符串C++
- 返回字符串vs通过引用传递字符串以更新值
- 如何在不使用 STL 的情况下从函数反转字符串后返回字符串C++?
- 使用 ctypes 从函数返回字符串C++会给出大的 int,而不是 char 指针
- 从 C++ 中的模板函数返回字符串和整数
- 返回字符串的散点回文计数
- C++重载字符串 [] 运算符以返回字符串和
- 返回字符串和不同向量数据类型的映射C++
- 字符串函数不返回字符串? C++
- 从函数返回字符串C++错误
- 如何在返回字符串的函数中不忽略void值
- 我想将字符串转换为 Json 格式并返回字符串向量作为答案
- C - 返回字符串时的分割故障
- 使用向量和字符串函数返回字符串