2011-06-27 18 views
6

que tienen algún código C++:¿Cómo envuelvo una interfaz C++ (clase abstracta) en C++/CLI?

namespace Compute { 
    class __declspec(dllexport) IProgressCB { 
    public:  
    virtual void progress(int percentCompleted) = 0; 
    };  
    double __declspec(dllexport) compute(IProgressCB *progressCB, ...); 
} 

que necesito para llamar desde C#.
Por lo tanto, quiero ajustar este código C++ en C++/CLI.

Entiendo cómo ajustar la función de cálculo(), , pero ¿cómo envuelvo la interfaz IProgress?

(parece que no es posible para una clase .Net para heredar una clase de C++?)

Respuesta

2

Este marco debe conseguir usted comenzó:

interface class IProgressEventSink 
{ ... }; 

class ProgressEventForwarder : IProgressEventCB 
{ 
    gcroot<IProgressEventSink^> m_sink; 
public: 
    ProgressEventForwarder(IProgressEventSink^ sink) : m_sink(sink) {} 

// IProgressEventCB implementation 
    virtual void OnProgress(ProgressInfo info) { m_sink->OnProgress(info.a, info.b); } 
}; 

ref class ComputeCLI 
{ 
    Compute* m_pimpl; 
// ... 

public: 
    RegisterHandler(IProgressEventSink^ sink) 
    { 
     // assumes Compute deletes the handler when done 
     // if not, keep this pointer and delete later to avoid memory leak 
     m_pimpl->RegisterHandler(new ProgressEventForwarder(sink)); 
    } 
}; 
+0

BTW. ¿Sabes cómo puedo "automatizar" la construcción del código Sink y Forwarder? – Andy

+0

@Andreas: "construcción de código" no es muy clara. ¿Quiere decir "generación de código" u "construcción de objeto"? –

+0

Lo siento. Me refiero a la generación de código. Entiendo que SWIG genera código PInvoke en lugar de C++/CLI, pero algo así, tal vez más ligero sería ideal. – Andy

4

Utilice un ref class que mantiene un puntero a la instancia envuelto:

namespace ComputeCLI { 
    public ref class IProgressCB{ 
    public: 
     void progress(int percentCompleted) 
     { 
      // call corresponding function of the wrapped object 
      m_wrappedObject->progress(percentCompleted); 
     } 

    internal: 
     // Create the wrapper and assign the wrapped object 
     IProgressCB(Compute::IProgressCB* wrappedObject) 
      : m_wrappedObject(wrappedObject){} 

     // The wrapped object 
     Compute::IProgressCB* m_wrappedObject; 
    }; 

    public ref class StaticFunctions{ 
    public: 
     static double compute(IProgressCB^ progressCB, ...){ 
      Compute::compute(progressCB->m_wrappedObject, ...); 
     } 
    }; 
} 
+0

Ya tengo una clase de C++ llamada IProgressCB que se incluirá desde C++/CLI; por lo que esta clase debe llamarse de otra manera (por ejemplo, IProgressCLI)? Además, el método compute() espera un puntero a un IProgress de C++, por lo que IProgressCLI heredará IProgressCB, pero esto no parece estar permitido. – Andy

+1

Debería considerar poner su código contenedor en otro espacio de nombres. (tal vez ComputeCli) Por lo tanto, puede usar la misma función y nombres de clase. La función de cálculo debe funcionar con la interfaz administrada. Editaré el código para demostrar esto. – Stephan

+0

¿Pero cómo le digo a mi código C++ que invoque la interfaz C++/CLI? El "flujo" aquí: C++ -> C++/CLI-> C# es lo opuesto a lo que suele ocurrir: C# -> C++/CLI-> C++. – Andy

Cuestiones relacionadas