2013-03-08 2 views
5

Мне нужно использовать неуправляемый API из C++/CLI. Этот API хранит указатель void на произвольные пользовательские данные и несколько обратных вызовов. Затем он вызывает эти обратные вызовы, передавая данные пользователя как void *.Является ли это использование gcroot безопасным?

До сих пор я был родной класс, передавая ее «это» указатель в качестве пользовательских данных, и с помощью этого указателя есть вызов API обратно в этот класс, то есть:

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

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

Я пытаюсь переведите это, используя управляемый класс. Я обнаружил, что тип gcroot может использоваться для безопасного хранения управляемых ссылок в машинном коде, так вот, как я делаю это сейчас:

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

Хотя это кажется штраф в C++/CLI компилятор, я не отлично зарекомендовал себя. Из того, что я понимаю, gcroot каким-то образом отслеживает свою управляемую ссылку, поскольку она перемещается GC. Удастся ли это сделать, сохраняя как пустоту * неуправляемым кодом? Безопасен ли этот код?

Спасибо.

+1

Do favor Marshal :: GetFunctionPointerForDelegate(), пример [здесь] (http://stackoverflow.com/questions/2972452/c-cli-pass-managed-delegate-to-unmanaged-code/2973278#2973278) –

ответ

2

Это то, что я закончил, и он отлично работает. Цель gcroot - хранить управляемую ссылку на нативной куче, что я и делаю здесь.

0

Нет! Совсем наоборот. gcroot - это шаблон родного класса. Вы используете его для хранения дескриптора управляемой памяти в собственном типе, который скомпилирован с поддержкой clr. Обычно вы будете использовать его для переадресации вызовов на функции-члены собственного объекта на управляемый объект, хранящийся в элементе типа gcroot.

EDIT: Я был на мобильный вчера, где печатая примеры кода немного неудобно ... Желаемое и типичное использование gcroot<T^> где-то вдоль этих линий:

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

То есть то, что ваши родные приложения или библиотеки см. и включать. Тогда у вас есть смешанный компонент, собранный с поддержкой CLR, которая реализует ICallback и хранит дескриптор некоторого управляемого объекта в 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)); 
} 

Ваши родные приложения называют CreateCallback, Получать экземпляр из ICallback который при Invoke -d вызывает метод управляемого типа, который находится в gcroot<System::Action^> ...

+1

Итак, проблема в том, что собственный API не скомпилирован с поддержкой clr? Потому что иначе вы описываете именно то, что я делаю. – Asik

+0

Нативный класс, который использует gcroot, должен быть скомпилирован с поддержкой clr. То, что я описал, прямо противоположно тому, что вы показали в своем вопросе: вы сохраняете собственный указатель gcroot в управляемом объекте. –

+0

Ну, функция, в которой используется gcroot («Обратный звонок») *, скомпилирована с поддержкой CLR. Gcroot хранится на неуправляемой куче, которая, по-видимому, разрешена. Какая разница в том, что управляемый класс сохранит указатель на него? – Asik

Смежные вопросы