2011-04-26 9 views
6

Tengo un C++ - CLR envoltorio alrededor de una biblioteca estándar de C++ llamada desde C#. Para recibir mensajes de estado de la biblioteca, utilizo un delegado asignado a una devolución de llamada en el código C++ a través de Marshal :: GetFunctionPointerForDelegate.Cómo pasar una cadena de C++ - CLI a C# a través de C++ - devoluciones de llamada de la CLI y delegados

Esto me ha llevado bastante tiempo para ponerme a trabajar y estoy muy, muy cerca (creo). Se llama al delegado C# pero la cadena no se pasa correctamente a través del límite.

Cuando llamo a TakesCallback ("Cadena de prueba") desde el código C++ me sale basura en la función C#.

--- La clase y la devolución de llamada función original de C++ ---

class Solver 
{ 
    private: 

    std::string TakesCallback(const std::string message) 
    { 
     return cb(message); 
    } 

    public: 

    // Declare an unmanaged function type that takes a string 
    typedef std::string (__stdcall* ANSWERCB)(const std::string); 
    ANSWERCB cb; 
}; 

--- función para establecer la devolución de llamada desde el contenedor administrado ----

// Set the delegate callback 
void ManagedSolver::SetMessageCallback(SendMessageDelegate^ sendMessageDelegate) 
{ 
    _sendMessage = sendMessageDelegate; 

    // Use GetFunctionPointerForDelegate to get the pointer for delegate callback 
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(sendMessageDelegate); 
    _solver->cb = static_cast<Solver::ANSWERCB>(ip.ToPointer()); 
} 

--- C# de función se pasa al SetMessageCallBack C++ \ CLR envoltorio ----

private void Message(string message) 
{ 
    XtraMessageBox.Show(message, "Done", MessageBoxButtons.OK); 
} 
+2

¿Seguro que quieres decir de C++? Las Extensiones administradas para C++ dejaron de ser compatibles con (creo) Visual Studio 2003. C++/CLI es su reemplazo, y es un lenguaje completamente diferente ... –

+0

Hola Billy, lo siento, tienes razón, por supuesto. Mi contenedor es C++/CLR alrededor de una biblioteca estándar de C++. He actualizado el título y el cuerpo. –

+0

OK Lo he resuelto std :: string no funcionará con interoperabilidad debido a la variedad de implementaciones que se indican aquí http://stackoverflow.com/questions/874551/stdstring-in-c Volveré y responderé esto tan pronto como StackOverflow me lo permita. –

Respuesta

1

C++ std::string y .NET System::String no son intercambiables. C# no puede usar el primero, y el código nativo de C++ no puede usar el segundo. Lo que necesita es una función C++/CLI que acepte std::string y la convierta a System::String^ antes de llamar al delegado.

1

En general, std clases de C++ no pueden ser pantano aled desde/hacia C#. Si usted está construyendo su código C++ como Unicode, lo recomendaría para cambiar el código en el siguiente:

C++

// Declare an unmanaged function type that takes a string 
typedef int (__stdcall* ANSWERCB)(LPCTSTR); 

C#

private void Message([MarshalAs(UnmanagedType.LPWStr)]string message) 
{ 
    XtraMessageBox.Show(message, "Done", MessageBoxButtons.OK); 
} 

Tome un vistazo a la siguiente example from MSDN

3

He estado usando the code from this page durante algunos meses y lo encuentro muy bueno. Es solo un archivo de encabezado que puede copiar a través de sus proyectos y hace el trabajo de forma rápida y limpia.

Se utilizan, por ejemplo,

std::wstring s = clix::marshalString<E_UNICODE>(myCliString); 

o

System::String^ s = clix::marshalString<E_ANSI>(mystdstring); 

funciona en ambos sentidos y le permiten especificar qué codificación que desea (ANSI, UTF-8 o Unicode de Ventanas - en realidad UTF16).

1

C++ (no administrado)

class DllContext 
{ 
public: 
typedef void (__stdcall *LOG_CALLBECK)(const wchar_t* LogString); 
DllContext(LOG_CALLBECK WriteLog) // Constructor 
{ 
    this->WriteLog = WriteLog; 
    this->WriteLog(L"Creating сontext..."); // UNICODE string! 
} 

private: 
LOG_CALLBECK WriteLog; 
} 

// Export function 
SENDAUDIOCLIENT_API DllContext *CreateContext(DllContext::LOG_CALLBECK WriteLog) 
{ 
    return new DllContext(WriteLog); 
} 

C#

class MyClass 
{ 
private delegate void WriteLog_Delegate([MarshalAs(UnmanagedType.LPWStr)]string Mess); 
private WriteLog_Delegate WriteLog; 

[DllImport("My.dll", EntryPoint = "[email protected]@[email protected]@[email protected]@Z", CallingConvention = CallingConvention.Cdecl)] 
private static extern IntPtr CreateContext(WriteLog_Delegate WriteLogProc); 

private IntPtr Context = IntPtr.Zero; 

public MyClass() 
{ 
    this.WriteLog = new WriteLog_Delegate(this.WriteLogToConsole); 
     this.Context = CreateContext(this.WriteLog); 
} 

private void WriteLogToConsole(string Mess) 
{ 
    Console.WriteLine("Message from unmanaged code: {0}", Mess); 
} 
}