2013-03-08 4 views
5

Ho bisogno di utilizzare un'API non gestita da C++/CLI. Questa API memorizza un puntatore vuoto su dati utente arbitrari e alcuni callback. Alla fine chiama quei callback, passando i dati dell'utente nel nulla *.L'uso di gcroot è sicuro?

Finora ho avuto una classe nativa passando il suo puntatore "this" come i dati degli utenti, e l'utilizzo di tale puntatore per avere la chiamata API di nuovo in questa classe, vale a dire:

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

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

sto cercando di traduci questo utilizzando una classe gestita. Ho trovato che il tipo gcroot può essere utilizzata per memorizzare in modo sicuro un riferimento gestito in codice nativo, quindi ecco come lo sto facendo ora:

// 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(); 
} 

Anche se questo sembra che vada bene per il compilatore C++/CLI, io non sono perfettamente rassicurante. Da quanto ho capito, gcroot in qualche modo tiene traccia del suo riferimento gestito mentre viene spostato dal GC. Riuscirà a farlo mentre memorizzato come vuoto * dal codice non gestito? Questo codice è sicuro?

Grazie.

+1

Preferire Marshal :: GetFunctionPointerForDelegate(), un esempio [è qui] (http://stackoverflow.com/questions/2972452/c-cli-pass-managed-delegate-to-unmanaged-code/2973278#2973278) –

risposta

2

Questo è quello che ho finito e funziona perfettamente. Lo scopo di gcroot è di memorizzare un riferimento gestito sull'heap nativo, che è esattamente quello che sto facendo qui.

0

No! È esattamente il contrario. gcroot è un modello di classe nativa. Lo si utilizza per memorizzare un handle nella memoria gestita in un tipo nativo che è compilato con il supporto clr. In genere lo utilizzi per deviare le chiamate alle funzioni membro di un oggetto nativo a un oggetto gestito memorizzato in un membro di tipo gcroot.

EDIT: Sono stato ieri cellulare dove digitando esempi di codice è un po 'imbarazzante ... L'utilizzo previsto e tipico di gcroot<T^> è da qualche parte in questo senso:

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

Questo è ciò che le applicazioni native o le librerie vedere e includere. Poi, si dispone di un componente mista compilato con il supporto CLR, che implementa ICallback e memorizza un handle per un oggetto gestito in un 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)); 
} 

Le tue applicazioni native chiamano CreateCallback, ricevilo un'istanza di ICallback che quando Invoke -d chiama un metodo di tipo gestito, tenuto in gcroot<System::Action^> ...

+1

Quindi il problema è che l'API nativa non è compilata con il supporto clr? Perché altrimenti ciò che descrivi è esattamente quello che sto facendo. – Asik

+0

La classe nativa che utilizza gcroot deve essere compilata con il supporto clr. Quello che ho descritto è esattamente l'opposto di ciò che hai mostrato nella tua domanda: memorizzi un puntatore gcroot nativo in un oggetto gestito. –

+0

Bene, la funzione in cui viene utilizzato il gcroot ("Callback") * è * compilata con supporto CLR. Il gcroot è memorizzato nell'heap non gestito, apparentemente consentito. Che differenza farebbe che una classe gestita continuasse a puntare su di essa? – Asik