如何在 C++ 和 C# 之间传递字符串参数

How to pass string parameters between C++ and C#?

本文关键字:字符串 参数 之间 C++      更新时间:2023-10-16

我已经在我的 C# 项目中导入了一个C++库。我可以得到一个没有参数的C++方法的答案。我想做的是将一些字符串参数发送到C++并获得它的结果。

在C++:

public String SomeMethod(String param1, String param2)
{
     //Some code
}

在 C# 中:

[DllImport("Library Path")]
public static extern string SomeMethod(string param1, string param2);

我该怎么做?

对于从 C# 传递到 C++ 的输入参数字符串,您可以只使用 LPCWSTR(即 const wchar_t* C++),并使用 C# 端的 UnmanagedType.LPWstr 选项封送。

但是,当您要将字符串从C++返回到 C# 时,必须注意。
实际上,字符串必须以某种方式在C++中分配,然后字符串指针必须传递给 C#。C# 和 CLR 必须能够在不再需要此字符串时正确释放此字符串,这一点可能会出现问题。例如:C#/CLR 应该能够使用C++代码用于分配字符串的相同分配器释放字符串内存。

对于在 C++ 中创建并在 C# 中使用的字符串使用相同的内存分配器的问题可以使用 BSTR s 来解决。
BSTR是使用 COM 分配器分配的 COM 字符串,可以使用相同的 COM 分配器释放。因此,C++端和 C# 端可以共享字符串的同一内存分配器。

要返回BSTR,您可以使用MarshalAs.UnmanagedTypeBStr选项。

有关 C# 中的字符串封送处理的更多详细信息,请参阅此 MSDN 页面。

C++

//
// Note: Export using a pure C interface from C++ DLL.
// (You can use C++ *inside* the DLL boundaries.)
// __stdcall is a widely used calling convention for 
// C DLL functions (e.g. lots of Win32 APIs use it).
//
extern "C" BSTR __stdcall GetSomeString(void)
{
    //
    // Note: BSTRs are allocated using SysAllocString()
    // (...and freed using SysFreeString()).
    //
    // You could also use a convenient ATL RAII wrapper
    // (instead of using raw BSTRs inside C++ code), 
    // like CComBSTR.
    //
    return ::SysAllocString(L"Hello from C++!");
}

C# 中:

[DllImport(@"YourDll.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string GetSomeString();

如果选择将 BSTR s 作为返回的字符串,则为了C++函数接口代码的一致性,您可能还希望使用 BSTR s 作为输入字符串(即使这不是绝对必要的)。


另一个选项是请求调用方提供一个大小合适的缓冲区,本机C++函数将使用返回的字符串填充该缓冲区。这有点类似于几个 Win32 API(例如 GetWindowText() ) 做。
例如,在这里您可以找到相应的 P/Invoke for GetWindwoText()

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

但是,我认为从 C# 调用的角度来看,返回BSTR更好(实际上,例如,在 C# 端,您不需要对输出字符串使用 StringBuilder 等)。


最后但并非最不重要的一点是,您可能感兴趣的另一个选项是构建一个微小的 C++/CLI 桥接层,以将您的本机C++代码公开给 C#,并使用 C++/CLI(例如 System::String 类)在本机和托管之间封送字符串。