C# 和 C++ dll - 编组字符串

C# and C++ dll - marshalling strings

我制作了一个测试应用程序,将 C# 字符串传递给 C++ DLL 以 return 其更改后的值。

取自 MSDN 的示例:

Marshaling Data with Platform Invoke

Strings Sample

用于定义 DllImport 的 class 的一部分:

public class LibWrap
{
    [DllImport(
        "PInvokeLib.dll",
        EntryPoint = "TestStringAsResult",
        ExactSpelling = true,
        CharSet = CharSet.Ansi,
        SetLastError = true)]
    public static extern string TestStringAsResult(string value);
}   

DLL函数调用:

const string s = "My string !!!";
var str = LibWrap.TestStringAsResult(s);
Console.WriteLine(Environment.NewLine + "String returned: {0}", str);
// String returned: My string !!!AAA or String returned: My string !!!+counter value

在 DLL 代码中,我将使用字符串和 return 其更改后的值:

// int counter = 0;
PINVOKELIB_API char* TestStringAsResult(char* value)
{
    const size_t alloc_size = 64;
    const auto result = static_cast<char*>(CoTaskMemAlloc(alloc_size));
    // counter++;
    std::string work_str = value;
    work_str += "AAA";
    //work_str += std::to_string(counter);
    StringCchCopyA(result, alloc_size, const_cast<char*>(work_str.c_str()));
    return result;
}

然后我循环了10次,例如在C#代码中:

const string s = "My string !!!";
var str = LibWrap.TestStringAsResult(s);
Console.WriteLine(Environment.NewLine + "String returned: {0}", str);

并得到了从"My string !!! 1""My string !!! 10"

的结果

这表明 DLL 已静态加载到 C# 应用程序进程中 - 我的理解是否正确?

原来在DLL中为结果分配了10次内存?

我是否需要使用 CoTaskMemFree()?如果需要——我如何在 C# 端调用它?

在 Adam Nathan 的书中找到了答案
.NET and COM: The Complete Interoperability Guide
第 18 章第 791 页

朋友给了我this link

Another case that requires the use of IntPtr occurs when a function allocates memory and expects the caller to free the memory. This is fairly rare in Win32 APIs, because most operate on a caller-allocated buffer (as in the examples that use StringBuilder). When a PInvoke signature returns a string (either via a return type or a by-reference parameter), the Interop Marshaler internally copies the contents of the unmanaged string to a .NET string, then calls CoTaskMemFree (the unmanaged equivalent of Marshal.FreeCoTaskMem) to free the unmanaged string. This is a problem, however, if the unmanaged string was not allocated with CoTaskMemAlloc!