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

时间:2015-01-21 07:23:17

标签: c# c++ string interop pinvoke

我在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);

我该怎么做?

1 个答案:

答案 0 :(得分:2)

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

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

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

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

有关C#中字符串编组的更多详细信息,请参阅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 s作为返回的字符串,对于C ++函数接口代码的 coherence ,您可能还希望使用BSTR作为< em>输入字符串(即使这不是绝对必要的)。


另一个选择是请求调用者提供正确大小的缓冲区,本机C ++函数将填充返回的字符串。这有点类似于几个Win32 API(例如GetWindowText())所做的 例如,here您可以找到GetWindwoText()的相应P / Invoke:

[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类)。