2013-03-08 42 views
5

Tôi cần sử dụng API không được quản lý từ C++/CLI. API này lưu trữ một con trỏ void đến dữ liệu người dùng tùy ý và một vài callback. Sau đó nó cuối cùng gọi những callbacks đó, chuyển dữ liệu người dùng vào như void *.Việc sử dụng gcroot có an toàn không?

Cho đến nay tôi đã có một lớp bản địa đi qua nó "này" con trỏ như dữ liệu người dùng, và sử dụng con trỏ đó để có cuộc gọi API trở lại vào lớp này, ví dụ:

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

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

Tôi đang cố gắng để dịch điều này bằng cách sử dụng một lớp được quản lý. Tôi phát hiện ra rằng loại gcroot thể được sử dụng để lưu trữ một cách an toàn một tài liệu tham khảo được quản lý trong mã nguồn gốc, vì vậy đây là cách tôi đang làm bây giờ:

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

Trong khi điều này có vẻ tốt với trình biên dịch C++/CLI, tôi không hoàn toàn yên tâm. Từ những gì tôi hiểu, gcroot bằng cách nào đó theo dõi tham chiếu được quản lý của nó khi nó được chuyển bởi GC. Nó sẽ quản lý để làm điều này trong khi được lưu trữ như là một void * bởi mã không được quản lý? Mã này có an toàn không?

Cảm ơn.

+1

Làm lợi cho Nguyên soái :: GetFunctionPointerForDelegate(), ví dụ [ở đây] (http://stackoverflow.com/questions/2972452/c-cli-pass-managed-delegate-to-unmanaged-code/2973278#2973278) –

Trả lời

2

Đây là những gì tôi đã kết thúc và hoạt động hoàn hảo. Mục đích của gcroot là lưu trữ một tài liệu tham khảo được quản lý trên heap gốc, đó chính xác là những gì tôi đang làm ở đây.

0

Không! Đó là chính xác theo cách khác xung quanh. gcroot là một mẫu lớp gốc. Bạn sử dụng nó để lưu trữ một xử lý để quản lý bộ nhớ trong một loại bản địa được biên dịch với hỗ trợ clr. Bạn thường sẽ sử dụng nó để chuyển hướng các cuộc gọi đến các hàm thành viên của một đối tượng gốc thành một đối tượng được quản lý được lưu trữ trong một thành viên của kiểu gcroot.

EDIT: Tôi đã về ngày hôm qua di động, nơi gõ ví dụ mã là một chút vụng về ... Những dự định và điển hình sử dụng gcroot<T^> là ở đâu đó dọc theo những dòng:

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

Đó là những gì các ứng dụng hoặc thư viện mẹ đẻ của bạn xem và bao gồm. Sau đó, bạn có một thành phần hỗn hợp biên soạn với sự hỗ trợ CLR, mà thực hiện ICallback và lưu trữ một xử lý cho một số đối tượng được quản lý trong một 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)); 
} 

ứng dụng bản địa của bạn gọi CreateCallback, nhận được một thể hiện của ICallback mà khi Invoke -d gọi phương thức thuộc loại được quản lý, được giữ trong gcroot<System::Action^> ...

+1

Vậy vấn đề là API gốc không được biên dịch với hỗ trợ clr? Bởi vì nếu không những gì bạn mô tả là chính xác những gì tôi đang làm. – Asik

+0

Lớp gốc sử dụng gcroot phải được biên dịch với hỗ trợ clr. Những gì tôi mô tả là hoàn toàn trái ngược với những gì bạn đã thể hiện trong câu hỏi của bạn: bạn lưu trữ một con trỏ gcroot bản địa trong một đối tượng được quản lý. –

+0

Vâng, chức năng mà gcroot được sử dụng ("Callback") * được biên dịch với hỗ trợ CLR. Các gcroot được lưu trữ trên heap unmanaged mà dường như được cho phép. Điều gì khác biệt sẽ làm cho một lớp được quản lý giữ một con trỏ đến nó? – Asik

Các vấn đề liên quan