2013-03-08 3 views
5

C++/CLI에서 관리되지 않는 API를 사용해야합니다. 이 API는 임의의 사용자 데이터와 몇 콜백에 대한 void 포인터를 저장합니다. 그런 다음 결국 콜백을 호출하여 사용자 데이터를 void *로 전달합니다. 내가하려고 해요이 gcroot 사용은 안전한가요?

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

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

을 :

지금까지 나는 즉, 사용자 데이터로서의 "이"포인터를 전달하고,이 클래스에 다시 API 호출을 가지고 그 포인터를 사용하여 기본 클래스를했다 관리되는 클래스를 사용하여이를 번역하십시오. 내가 지금 여기에 내가 지금하고 있어요 방법, 유형 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에 의해 이동됨에 따라 어떻게 든 관리되는 참조를 추적합니다. 비 관리 코드에 의해 void *로 저장되는 동안이 작업을 관리합니까? 이 코드는 안전한가요?

감사합니다.

+1

마샬링 :: GetFunctionPointerForDelegate(), 예를 들어 [여기 있습니다] (http://stackoverflow.com/questions/2972452/c-cli-pass-managed-delegate-to-unmanaged-code/2973278#2973278)) –

답변

2

에서 개최되는 관리되는 방법의 메서드를 호출합니다.이 작업이 끝나고 완벽하게 작동합니다. gcroot의 목적은 네이티브 힙에 관리되는 참조를 저장하는 것입니다.

0

아니요! 그것은 정확히 다른 방향입니다. gcroot는 기본 클래스 템플릿입니다. clr 지원으로 컴파일 된 네이티브 형식의 관리되는 메모리 핸들을 저장하는 데 사용합니다. 일반적으로 네이티브 객체의 멤버 함수에 대한 호출을 gcroot 유형의 멤버에 저장된 관리 객체로 전환하는 데이 객체를 사용합니다.

편집 : 내가 코드 예제를 입력하는 것은 조금 어색 모바일 어제에 있었다 ... gcroot<T^>의 의도 일반적인 사용은 이러한 라인을 따라 어딘가에 :

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

무엇 네이티브 응용 프로그램 또는 라이브러리 참조하고 포함하십시오.

귀하의 네이티브 애플리케이션이 CreateCallback 전화
// 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)); 
} 

ICallback의 인스턴스를받을 때 Invoke -d : 그런 다음 ICallback를 구현하고 gcroot<ManagedType^> A의 일부 관리되는 개체에 대한 핸들을 저장 CLR을 지원하도록 컴파일 혼합 구성 요소를 가지고 gcroot<System::Action^> ...

+1

그래서 네이티브 API가 clr 지원으로 컴파일되지 않는다는 것이 문제입니까? 왜냐하면 당신이 묘사하는 것은 정확하게 내가하는 일이기 때문입니다. – Asik

+0

gcroot를 사용하는 원시 클래스는 clr 지원으로 컴파일해야합니다. 내가 설명한 것은 여러분이 질문 한 것과 정확히 반대입니다 : 관리 된 객체에 네이티브 gcroot 포인터를 저장합니다. –

+0

글쎄, gcroot가 사용되는 함수 ("콜백") *는 * CLR 지원으로 컴파일됩니다. gcroot는 허용되지 않는 관리되지 않는 힙에 저장됩니다. 어떤 차이가있어 관리되는 클래스가 그것에 대한 포인터를 유지할 수 있습니까? – Asik