2011-12-19 46 views
1

我正在使用C++/CLI創建一個圍繞C++庫的.NET包裝(我無法訪問源代碼)。 C++庫需要回調用C++/CLI編寫的.NET委託。我使用Marshal :: GetFunctionPointerForDelegate將一個回調函數分配給C++庫類。然而,當這個函數從非託管端被回調時,我需要確保.NET代理函數仍然在同一個內存位置。如何創建一個固定內存的C++/CLI類?

最簡單的方法當然是要求.NET庫用戶固定.NET對象,但這不是一個真正的乾淨設計,並且還允許用戶在腳下自己拍攝。更好的方法是設計.NET類,以便在創建時或者由函數/事件觸發時引腳。

我該怎麼設計呢?根據這個鏈接,http://msdn.microsoft.com/en-us/library/18xa23yk%28v=VS.100%29.aspx,你不能有內部〜=固定指針作爲對象成員。這意味着可以創建一個固定的指針引用作爲靜態或全局變量。

所以我想做一些像這兩者中的任何一個,但不能讓它編譯/工作。

public ref class UserClass{ 
void createDotNetCPPWrapperClass() 
{ 
    m_class = gcnew DotNetCPPWrapperClass; 
} 

DotNetCPPWrapperClass^ m_class 

}; 


public ref class DotNetCPPWrapperClass{ 

static pin_ptr<DotNetCPPWrapperClass^> pinnedSelf; 

DotNetCPPWrapperClass() 
{ 
    pinnedSelf = this; 
} 
}; 

OR

public ref class UserClass{ 

void createDotNetCPPWrapperClass() 
{ 
    m_class = gcnew DotNetCPPWrapperClass; 
    m_class->setupImportantStuff(); 
} 

DotNetCPPWrapperClass^ m_class 

}; 


public ref class DotNetCPPWrapperClass{ 

static pin_ptr<DotNetCPPWrapperClass^> pinnedSelf; 

DotNetCPPWrapperClass(){} 

void setupImportantStuff() 
{ 
    pinnedSelf = this; 
} 

}; 
+0

您是否使用框架提供的'GCHandle'或'HandleRef'結構進行調查? – 2011-12-19 16:27:28

+0

不,但現在使用Google搜索。謝謝。 – 2011-12-19 16:32:56

+0

使用Marshal :: GetFunctionPointerForDelegate()的要點是你*不必*必須這樣做。不要幫忙。 – 2011-12-19 16:55:31

回答

0

GCHandle將解決你的問題。

public ref class Wrapper 
{ 

GChandle thisHandle; 
public: 
    Wrapper() 
    { 
    thisHandle = GCHandle.Alloc(this, GCHandleType::Normal); 
    } 

    ~Wrapper() // Dispose 
    { 
    if(thisHandle.IsAllocated) 
     thisHandle.Free; 
    } 

    !Wrapper() // Finalize 
    { 
    //Native resource releasing 
    } 
} 

現在有幾點你需要小心。

  1. 你不想GCHandle.Alloc()東西固定了很長時間。固定對象後,GC無法收集在內存中的固定對象之前對齊的對象,因爲固定對象的地址無法更改。所以garbace收藏變得毫無意義。請注意,我將GCHandleType::Normal的句柄分配給它不僅使其無法收回,而且也是可移動的。
  2. 我不知道GC是否試圖收集具有分配句柄的對象,並調用該對象的終結器。國際海事組織這沒有任何意義,因爲句柄阻止GC收集對象。因此,在C++中調用delete運算符並在C#中調用Dispose()非常非常重要,並釋放句柄。如果你忘記調用它們,整個對象就會變成內存泄漏。
0
public class MyClass { 

    private GCHandle gch; 

    public MyClass() { 
    gch=GCHandle.Alloc(this, GCHandleType.Pinned); 
    } 
}