GCHandle, Marshal, managed and unmanaged memory: for connection or not for output

How Hans Passant Wisheshere is my script. I have a mixed-mode application in which native code does all the hard work, while complying with performance and managed code is only responsible for the graphical interface. Also, users will participate by writing their own C # code. I have C ++ for native classes, C # for GUI and user code, and C ++ / Cli for wrapper classes between them. Among all my C ++ classes, there is one that does% 90 calculations and a different parameter is created each time. Let me call it NativeClass. There is apprx. 2000 instances of this NativeClass, and I have to find the correct instance associated with some parameter before it starts to calculate. Therefore, I developed hash_map, with parameters being a hash code, for this purpose. When I get the parameter, I look for the correct instance in hash_map,I find it and call some of its methods.
When users compete with computing by writing C # code, and this class executes these codes through callbacks. This is trivial, but sometimes I need information about the .Net classes that were created by users. So I need to somehow bind this particular ManagedClass to a NativeClass. My first solution is to use GChandle.Alloc () and move the handle address. But there are some problemsregarding GC, that he will not do his job properly. Hans recommended that Marshal.AllocCoTaskMem () and Marshal.StructureToPtr () allocate managed objects in unmanaged memory, however, I believe this is true for value type classes or structures. What about ref classes? How can I pass a link to a NativeClass without allowing them to be compiled by the GC and for the GC to work correctly over time?

Here is a 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'm sorry this toooooo is long and still not clear.

+5
source share
3 answers

I spent a lot of time fighting a similar problem, and this is the outline of the solution that worked for me ....

  • Save the managed class handle as void *
  • ( )
  • new delete, , AllocHGlobal
  • GCHandle 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);
    }
};

.

+3

.

GCHandle - .

GCHandle ref , .

0

All Articles