2011-12-19 44 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); 
    } 
}