且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-12 15:14:29

对于从C#传递到C ++的输入参数的字符串,您可以在以下位置使用LPCWSTR(即const wchar_t*) C ++一侧的界面,然后使用C#一侧的 UnmanagedType.LPWstr 选项进行封送.

For strings that are input parameters passed from C# to C++, you could just use LPCWSTR (i.e. const wchar_t*) at the interface on the C++ side, and marshal using the UnmanagedType.LPWstr option on the C# side.

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

But you must pay attention when you want to return strings from C++ to C#.
In fact, the string must somehow be allocated in C++, then the string pointer must be passed to C#. C# and the CLR must be able to properly release this string when it's no needed anymore, and this point can present issues. For example: C#/CLR should be able to release the string memory using the same allocator used by the C++ code to allocate the string.

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

This problem of using the same memory allocator for strings created in C++ and consumed in C# can be solved using BSTRs.
A BSTR is a COM string, that is allocated using the COM allocator, and can be freed using the same COM allocator. So, both the C++ and the C# side can share the same memory allocator for the string.

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

To return a BSTR, you can use the MarshalAs.UnmanagedTypeBStr option.

有关C#中的字符串封送处理的更多详细信息,请参见

More details on string marshaling in C# can be found in this MSDN page.

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作为返回字符串,则对于C ++函数接口代码的一致性,您可能还希望使用BSTR s作为输入字符串(即使并非绝对必要).

If you choose to have BSTRs as the returned string, for coherence of the C++ function interface code, you may also want to use BSTRs as the input strings (even if that is not strictly necessary).

您还有一个选择,就是请求调用者提供适当大小的缓冲区,本机C ++函数将用返回的字符串填充该缓冲区.这有点类似于几种Win32 API(例如 GetWindowText() ).
例如,在此处,您可以找到GetWindwoText()的相应P/Invoke :

Another option you have is to request the caller to provide a properly sized buffer that the native C++ function will fill with the returned string. This is somewhat similar to what several Win32 APIs (like e.g. GetWindowText()) do.
As an example, here you can find the corresponding 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等).

However, I think that returning a BSTR is nicer from a C# calling perspective (in fact, e.g. on the C# side you are not required to use a StringBuilder for the output string, etc.).

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

Last but not least, another option that you might be interested in is to build a tiny C++/CLI bridging layer to expose your native C++ code to C#, and marshal strings between native and managed using C++/CLI (and e.g. the System::String class).