As Hans Passant wishes here is the scenario of mine. I have a mixed mode application in which the native code does all the hard work while respecting the performance and managed code is responsible for only GUI. Also users will be participating by writing their proprietary C# code. I have C++ for native classes, C# for GUI and user code and C++/Cli for wrapper classes in between. Among all of my C++ classes there is one that does %90 of the calculations and is created a different parameter each time. Let's call it NativeClass. There are apprx. 2000 instances of this NativeClass and I have to find the right instance related to some parameter before it does calculation. So I devised a hash_map, with parameters being the hash code, for this purpose. When I get a parameter, I seek for the right instance in hash_map, I find it and call someof its methods.
When users contrubute to calculations by writing C# code and this class execute these codes by callbacks. This is trivial but sometimes I need some information about the .Net classes that users built. So I need to attach that specific ManagedClass to NativeClass somehow. My first solution is using GChandle.Alloc() and transfering the handles address. But there are some concerns about GC that it will not be doing its job properly. Hans recommended the Marshal.AllocCoTaskMem() and Marshal.StructureToPtr() to allocate managed objects in unmanaged memory, however I believe this is valid for value type classes or structs. How about ref classes? How can I pass a reference to NativeClass while preventing them to be GC collected and make GC work properly at the sametime ?
Here is some sample code:
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);
}
};
I am sorry that it is toooooo long and still not clear.
I spent quite a while battling with a similar problem and this is the outline of the solution that worked for me ....
void *
new
and delete
rather than anything such as AllocHGlobal
GCHandle
between the void * and managed object referenceMarshalByRefObject
- you don't need it as you are doing your own marshallingI took your above code and hacked at it to get:
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);
}
};
This should put you on the right track.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With