【发布时间】:2016-08-12 18:10:05
【问题描述】:
我需要将一些现有的 .NET 逻辑(即程序集 MyManaged.dll)暴露给本机代码,因此我决定创建 C++/CLIbridge。我创建了 C++/CLI 项目并添加了对 MyManaged.dll 的引用。长话短说——它有效——我已经成功地访问了所有应该可以从本机代码访问的东西。
但是大问题是我的实现泄漏了内存。经过几天的测试和研究,我将问题缩小到System::String const wchar_t 转换。最后,我创建了一个简单的 C++/CLI 项目来演示(重现)该问题:
#define EXPORTED __declspec(dllexport)
System::String^ ToManaged(const wchar_t* unmanagedString)
{
return gcnew System::String(unmanagedString);
}
const wchar_t* ToUnmanaged(System::String^ managedString)
{
return (wchar_t*) System::Runtime::InteropServices::Marshal::StringToHGlobalUni(managedString).ToPointer();
}
EXPORTED const wchar_t* __stdcall GetString(const wchar_t* dummy)
{
return ToUnmanaged(ToManaged(dummy));
}
(如果从前面的代码中看不出来的话——我是 C++/CLI 的新手)
正如我所提到的,代码有效但会累积内存消耗,因此System::String const wchar_t 转换肯定存在泄漏。
我的问题很明显:如何实现字符串转换没有泄漏。
谢谢!
【问题讨论】:
-
我会使用 COM 并且 COM 启用您需要访问的方法。使用 tlb.exe 生成 COM 互操作。少了很多头痛。我沿着 cli/c++ 路径走下去,发现了 dll 加载顺序问题和病毒软件创建问题等问题。
-
@CKIsLearning - 感谢您提供帮助。老实说,出于某种原因,我非常反对 COM。如果我没有找到任何其他解决方案,我会去那里,但同时我已经解决了这个问题,没有理由这样做。还是谢谢!
-
对 Marshal::StringToHGlobalUni() 的每次调用必须与对 Marshal::FreeCoTaskMem() 的调用配对。这会使您的 ToUnmanaged() 函数损坏而没有希望进行简单的修复,该调用不会发生。您将不得不重新考虑这一点,考虑使用更智能的字符串类型,例如 std::wstring
-
@HansPassant - 谢谢,但正如您在下面看到的,我已经使用
<msclr\marshal.h>解决了这个问题。