2011-06-27 13 views
6

Mam C++ kod:Jak zawinąć interfejs C++ (klasa abstrakcyjna) w C++/CLI?

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

że muszę zadzwonić z C#.
Dlatego chcę zawinąć ten kod C++ w C++/CLI.

Rozumiem, jak zawinąć funkcję compute(), , ale jak zawinąć interfejs IProgress?

(Wydaje się, że nie jest możliwe dla klasy .NET dziedziczą klasy C++?)

Odpowiedz

2

Ramy te powinny uzyskać zacząłeś:

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. Czy wiesz, w jaki sposób mogę "zautomatyzować" konstrukcję kodu Sink and the Forwarder? – Andy

+0

@Andreas: "Konstrukcja kodu" nie jest zbyt jasna. Masz na myśli "generowanie kodu" lub "konstruowanie obiektów"? –

+0

Przepraszamy. Mam na myśli generowanie kodu. Rozumiem, że SWIG generuje kod PInvoke zamiast C++/CLI, ale coś takiego, być może bardziej lekkiego, byłoby idealne. – Andy

4

Użyj ref class który posiada wskaźnik do zawiniętego przykład:

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

Mam już klasę C++ o nazwie IProgressCB, która będzie dołączona do C++/CLI; więc tę klasę należy nazwać czymś innym (np. IProgressCLI)? Również metoda compute() oczekuje wskaźnika na C++ IProgress, więc IProgressCLI musi odziedziczyć IProgressCB, ale wydaje się, że nie jest to dozwolone? – Andy

+1

Należy rozważyć umieszczenie kodu opakowania w innym obszarze nazw. (może ComputeCli) W ten sposób możesz używać tych samych nazw funkcji i klas. Funkcja obliczeniowa musi działać z zarządzanym interfejsem. Zmienię kod, aby to pokazać. – Stephan

+0

Ale jak mogę powiedzieć mój kod C++, aby wywołać interfejs C++/CLI? "Przepływ" tutaj: C++ -> C++/CLI-> C# jest przeciwieństwem tego, co zwykle się dzieje: C# -> C++/CLI-> C++. – Andy