2013-03-08 9 views
5

Ich brauche eine nicht verwaltete API von C++/CLI. Diese API speichert einen Void-Zeiger auf beliebige Benutzerdaten und einige Callbacks. Es ruft dann schließlich diese Rückrufe auf und übergibt die Benutzerdaten als void *.Ist diese Verwendung von gcroot sicher?

Bisher hatte ich eine native Klasse sein „dieses“ Zeiger als die Benutzerdaten übergeben, und die Verwendung dieser Zeiger den API-Aufruf zu haben, wieder in dieser Klasse, das heißt:

static void __stdcall Callback(void* userData) { 
    ((MyType*)userData)->Method(); 
} 

class MyType { 
public: 
    MyType() { RegisterWithApi((void*)this, Callback); } 
    void Method(); 
}; 

Ich versuche, übersetze dies mit einer verwalteten Klasse. Ich fand, dass der Typ gcroot sicher verwendet werden kann, um eine verwaltete Referenz zu speichern in nativen Code, also hier ist, wie ich es jetzt tue:

// This is called by the native API 
static void __stdcall Callback(void* userData) { 
    // Cast back to gcroot and call into managed code 
    (*(gcroot<MyType^>*)userData)->Method(); 
} 

ref class MyType { 
    gcroot<MyType^>* m_self; 
public: 
    MyType() { 
     m_self = new gcroot<MyType^>; 
     RegisterWithApi((void*)m_self, Callback); 
    } 
    ~MyType() { delete m_self; } 
    // Method we want called by the native API 
    void Method(); 
} 

Während dies dem C Fein scheint ++/CLI-Compiler, bin ich nicht vollkommen versichert. Von dem, was ich verstehe, behält Gcroot irgendwie seine gemanagte Referenz bei, da sie vom GC bewegt wird. Wird es dies schaffen, während es als void * durch nicht verwalteten Code gespeichert wird? Ist dieser Code sicher?

Danke.

+1

Do favor Marshal :: GetFunctionPointerForDelegate(), ein Beispiel [ist hier] (http://stackoverflow.com/questions/2972452/c-cli-pass-managed-delegate-to-unmanaged-code/2973278#2973278) –

Antwort

2

Dies ist, was ich getan habe und es funktioniert perfekt. Der Zweck von gcroot ist es, eine verwaltete Referenz auf dem nativen Heap zu speichern, und genau das mache ich hier.

0

Nein! Es ist genau umgekehrt. gcroot ist eine native Klassenvorlage. Sie verwenden es, um einen Handle für verwalteten Speicher in einem systemeigenen Typ zu speichern, der mit clr-Unterstützung kompiliert wurde. In der Regel werden Sie Aufrufe von Memberfunktionen eines systemeigenen Objekts an ein verwaltetes Objekt umleiten, das in einem Member vom Typ gcroot gespeichert ist.

EDIT: Ich auf mobilen gestern war, wo Beispiele Code eingeben ein wenig umständlich ist ... Die beabsichtigte und typische Verwendung von gcroot<T^> ist irgendwo in dieser Richtung:

// ICallback.h 
struct ICallback { 
    virtual void Invoke() = 0; 
    virtual void Release() = 0; 
    protected: 
     ~ICallback() {} 
}; 

Das ist, was Ihre native Anwendungen oder Bibliotheken sehen und einschließen. Dann haben Sie eine gemischte Komponente mit CLR-Unterstützung kompiliert, die ICallback implementiert und speichert dann ein Handle zu einem gewissen verwaltete Objekt in ein gcroot<ManagedType^>:

// Callback.cpp (this translation unit must be compiled with /clr) 
// I did not compile and test, but you get the point... 
template<class T^> class Callback : public ICallback { 
    gcroot<T^> m_Managed; 

    virtual void Invoke() 
    { 
     m_Managed->Invoke(); 
    } 

    virtual void Release() 
    { 
     delete this; 
    } 
public: 
    Callback(T^ p_Managed) : m_Managed(p_Managed) {} 
}; 

__declspec(dllexport) ICallback* CreateCallback() 
{ 
    auto t_Managed = gcnew SomeManagedType(); 
    return new Callback<System::Action^>(
     gcnew System::Action(t_Managed, &SomeManagedType::Method)); 
} 

Ihre native Anwendungen CreateCallback nennen, eine Instanz von ICallback empfangen die, wenn Invoke -d ruft eine Methode des verwalteten Typs auf, gehalten in gcroot<System::Action^> ...

+1

Also ist das Problem, dass die native API nicht mit CLR-Unterstützung kompiliert wird? Weil sonst, was du beschreibst, genau das ist, was ich mache. – Asik

+0

Die native Klasse, die gcroot verwendet, muss mit clr-Unterstützung kompiliert werden. Was ich beschrieben habe, ist genau das Gegenteil von dem, was Sie in Ihrer Frage gezeigt haben: Sie speichern einen nativen GCROOT-Zeiger in einem verwalteten Objekt. –

+0

Nun, die Funktion, wo der gcroot verwendet wird ("Callback") * ist mit CLR-Unterstützung kompiliert. Der GCROOT wird auf dem nicht verwalteten Speicher gespeichert, der anscheinend erlaubt ist. Welchen Unterschied würde es machen, dass eine verwaltete Klasse einen Zeiger darauf behält? – Asik

Verwandte Themen