ali*_*hoo 5 .net c# c++-cli marshalling pinning
正如Hans Passant所 希望的那样这是我的情景.我有一个混合模式应用程序,其中本机代码执行所有艰苦的工作,同时尊重性能和托管代码只负责GUI.用户也将通过编写他们的专有C#代码参与.我有本地类的C++,GUI和用户代码的C#以及介于两者之间的包装类的C++/Cli.在我的所有C++类中,有一个执行%90的计算,每次都创建一个不同的参数.我们称之为NativeClass.有apprx.这个NativeClass的2000个实例,我必须在计算之前找到与某个参数相关的正确实例.所以我设计了一个hash_map,其参数是哈希码,用于此目的.当我得到一个参数时,我在hash_map中寻找正确的实例,我找到它并调用它的一些方法.
当用户通过编写C#代码来控制计算时,该类通过回调执行这些代码.这是微不足道的,但有时我需要一些关于用户构建的.Net类的信息.所以我需要以某种方式将特定的ManagedClass附加到NativeClass.我的第一个解决方案是使用GChandle.Alloc()并传输句柄地址.但有一些担心 GC不会正常工作.Hans建议Marshal.AllocCoTaskMem()和Marshal.StructureToPtr()在非托管内存中分配托管对象,但我相信这对值类型类或结构有效.ref类怎么样?如何在防止GC收集并使GC同时正常工作的同时传递对NativeClass的引用?
以下是一些示例代码:
class NativeClass
{
private:
int AddressOfManagedHandle;
public:
static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
{
// return NativeClass associated with SomeParameter from NativeClassHashMap;
}
NativeClass(int addr, int SomeParameter) : AddressOfManagedHandle(addr)
{
}
int GetAddress(){return AddressOfManagedHandle;}
void DoCalculation(){
// CALCULATIONS
}
};
public ref class ManagedClass : MarshalByRefObject
{
private:
NativeClass* _nc;
//GCHandle handle;
void FreeManagedClass()
{
Marshal::FreeHGlobal(IntPtr(_nc->GetAddress()));
//if(handle.IsAllocated)
//handle.Free();
delete _nc;
}
public:
ManagedClass()
{
IntPtr addr = (Marshal::AllocHGlobal(Marshal::Sizeof(this))); // Error
Marshal::StructureToPtr(this,addr,true);
//handle = GCHandle.Alloc(this);
//IntPtr addr = handle.ToIntPtr();
_nc = new NativeClass(addr.ToInt32());
}
~ManagedClass() {FreeManagedClass();}
!ManagedClass() {FreeManagedClass();}
int GetAddress() {return _nc->GetAddress();};
static ManagedClass^ GetManagedClass(int SomeParameter)
{
int addr = NativeClass::GetNativeClassFromHashMap(SomeParameter)->GetAddress();
//Object^obj = GCHandle::FromIntPtr(IntPtr(addr)).Target;
Object^ obj = Marshal::PtrToStructure(IntPtr(addr), ManagedClass::typeid );
return dynamic_cast<ManagedClass^>(obj);
}
};
Run Code Online (Sandbox Code Playgroud)
我很抱歉,它太长了,仍然不清楚.
我花了很长时间与类似的问题作斗争,这是对我有用的解决方案的概要......
void *new而delete不是诸如此类的东西AllocHGlobalGCHandle在 void * 和托管对象引用之间转换MarshalByRefObject- 你不需要它,因为你正在做你自己的编组我拿了你上面的代码并对其进行了修改以获得:
class NativeClass
{
private:
void * managedHandle;
public:
static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
{
// return NativeClass associated with SomeParameter from NativeClassHashMap;
}
NativeClass(void *handle, int SomeParameter)
: managedHandle(handle)
{
}
void * ManagedHandle()
{
return managedHandle;
}
void DoCalculation()
{
// CALCULATIONS
}
};
public ref class ManagedClass
{
private:
NativeClass* _nc;
void FreeManagedClass()
{
if (_nc)
{
// Free the handle to the managed object
static_cast<GCHandle>(IntPtr(_nc->ManagedHandle)).Free();
// Delete the native object
delete _nc;
_nc = 0;
}
}
public:
ManagedClass()
{
// Allocate GCHandle of type 'Normal' (see doco for Normal, Weak, Pinned)
GCHandle gch = GCHandle::Alloc(this, GCHandleType::Normal);
// Convert to void*
void *handle = static_cast<IntPtr>(gch).ToPointer();
// Initialise native object, storing handle to native object as void*
_nc = new NativeClass(handle);
}
~ManagedClass() {FreeManagedClass();}
!ManagedClass() {FreeManagedClass();}
static ManagedClass^ GetManagedClass(int SomeParameter)
{
// Native class is retrieved from hash map
NativeClass *nc = NativeClass::GetNativeClassFromHashMap(SomeParameter);
// Extract GCHandle from handle stored in native class
// This is the reverse of the process used in the ManagedClass constructor
GCHandle gch = static_cast<GCHandle>(IntPtr(nc->ManagedHandle()));
// Cast the target of the GCHandle to the managed object
return dynamic_cast<ManagedClass^>(gch.Target);
}
};
Run Code Online (Sandbox Code Playgroud)
这应该会让你走上正轨。
| 归档时间: |
|
| 查看次数: |
7086 次 |
| 最近记录: |