2013-03-08 22 views
5

Potrzebuję użyć niezarządzanego API z C++/CLI. Ten interfejs API przechowuje nieważny wskaźnik dla dowolnych danych użytkownika i kilku wywołań zwrotnych. Następnie w końcu wywołuje te wywołania zwrotne, przekazując dane użytkownika jako nieważne *.Czy korzystanie z gcroot jest bezpieczne?

Dotychczas miałem natywną klasę przekazując swoją „ten” wskaźnik jako danych użytkownika, a za pomocą tego wskaźnika, aby mieć wywołania API z powrotem do tej klasy, tj:

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

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

próbuję przetłumacz to za pomocą klasy zarządzanej. Okazało się, że typ gcroot mogą być wykorzystane do bezpiecznego przechowywania zarządzanego odniesienie w natywnym kodzie, więc oto jak robię to teraz:

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

Choć wydaje się dobrze do kompilatora C++/CLI, nie jestem doskonale upewniony. Z tego co rozumiem, gcroot w jakiś sposób śledzi zarządzany odnośnik, gdy jest przenoszony przez GC. Czy uda się to zrobić, gdy będzie przechowywany jako pustka * przez niezarządzany kod? Czy ten kod jest bezpieczny?

Dzięki.

+1

Wykonaj frazę Marshal :: GetFunctionPointerForDelegate(), przykład [jest tutaj] (http://stackoverflow.com/questions/2972452/c-cli-pass-managed-delegate-to -unmanaged -code/2973278#2973278) –

Odpowiedz

2

Tak właśnie skończyłem i działa idealnie. Celem gcroot jest przechowywanie referencji zarządzanej na rodzimym stercie, co właśnie tutaj robię.

0

Nie! Jest dokładnie odwrotnie. gcroot to szablon klasy natywnej. Używa się go do przechowywania uchwytu do zarządzanej pamięci w natywnym typie, który jest skompilowany z obsługą Clr. Zwykle używa się go do przekierowywania wywołań do funkcji składowych natywnego obiektu do zarządzanego obiektu przechowywanego w elemencie gcroot typu.

EDIT: Byłem na telefon wczoraj gdzie wpisując przykłady kod jest nieco niewygodne ... Zamierzone i typowe użycie gcroot<T^> jest gdzieś wzdłuż tych linii:

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

To jest to, co rodzime aplikacje lub biblioteki zobacz i dołącz. Następnie masz mieszaną składnik skompilowany ze wsparciem CLR, który realizuje ICallback i przechowuje uchwyt do pewnego zarządzanego obiektu w 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)); 
} 

ojczystym aplikacje nazywają CreateCallback, odbieranie instancją ICallback który po Invoke -d nazywa metodę zarządzanego typu, która odbyła się w gcroot<System::Action^> ...

+1

Więc problem polega na tym, że natywny interfejs API nie jest skompilowany z obsługą Clr? Ponieważ w przeciwnym razie to, co opisujesz, jest dokładnie tym, co robię. – Asik

+0

Natywna klasa korzystająca z gcroot musi być skompilowana z obsługą Clr. To, co opisałem, jest dokładnie przeciwieństwem tego, co pokazałeś w swoim pytaniu: przechowujesz natywny wskaźnik gcroot w zarządzanym obiekcie. –

+0

Cóż, funkcja, w której używany jest gcroot ("Callback") * jest * skompilowany z obsługą CLR. Gcroot jest przechowywany na niezarządzanym stosie, który najwyraźniej jest dozwolony. Jaką różnicę spowodowałoby, że klasa zarządzana zachowała dla niej wskaźnik? – Asik

Powiązane problemy