¿Cómo pasar parámetros de cadena entre C ++ y C #?

He importado una biblioteca de C ++ en mi proyecto de C #. Puedo obtener la respuesta de un método C ++ que no tiene parámetros. Lo que quiero hacer es enviar algunos parámetros de cadena a C ++ y obtener el resultado.

En C ++:

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

Cía#:

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

¿Cómo puedo hacer esto?

Para las cadenas que son parámetros de entrada pasados ​​de C # a C ++, solo puede usar LPCWSTR (es decir, const wchar_t* ) en la interfaz en el lado C ++, y mariscal usando la opción UnmanagedType.LPWstr en el lado C #.

Pero debe prestar atención cuando desee devolver cadenas de C ++ a C # .
De hecho, la cadena debe asignarse de alguna manera en C ++, luego el puntero de la cadena debe pasarse a C #. C # y el CLR deben poder lanzar correctamente esta cadena cuando ya no se necesita, y este punto puede presentar problemas. Por ejemplo: C # / CLR debería poder liberar la memoria de cadena utilizando el mismo asignador utilizado por el código C ++ para asignar la cadena.

Este problema de usar el mismo asignador de memoria para las cadenas creadas en C ++ y consumidas en C # se puede resolver utilizando BSTR s .
Un BSTR es una cadena COM, que se asigna utilizando el asignador COM, y se puede liberar utilizando el mismo asignador COM. Por lo tanto, tanto el lado C ++ como el lado C # pueden compartir el mismo asignador de memoria para la cadena.

Para devolver un BSTR , puede usar la opción MarshalAs.UnmanagedTypeBStr .

Se pueden encontrar más detalles sobre el cálculo de cadenas en C # en esta página de MSDN .

En 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 (eg 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++!"); } 

En C # :

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

Si elige tener BSTR s como la cadena devuelta, para la coherencia del código de interfaz de la función C ++, también puede usar BSTR s como las cadenas de entrada (incluso si eso no es estrictamente necesario).


Otra opción que tiene es solicitarle a la persona que llama que proporcione un búfer de tamaño adecuado que la función nativa de C ++ llenará con la cadena devuelta. Esto es algo similar a lo que hacen varias API de Win32 (como, por ejemplo, GetWindowText() ).
Como ejemplo, aquí puede encontrar el P / Invoke correspondiente para GetWindwoText() :

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

Sin embargo, creo que devolver un BSTR es mejor desde una perspectiva de llamada de C # (de hecho, por ejemplo, en el lado de C # no es necesario usar un StringBuilder para la cadena de salida, etc.).


Por último, pero no menos importante, otra opción en la que podría estar interesado es crear una pequeña capa de puente C ++ / CLI para exponer su código C ++ nativo a C #, e intercambiar cadenas entre nativo y administrado usando C ++ / CLI (y, por ejemplo, System::String Clase de System::String ).