Search code examples
c#c++c++-cli

Pass an object from C# to C++ using C++/CLI or convert Object^ to Object


In C++, I create this class:

public ref class UConfig
{
    public:
       UConfig(short nr);
       ~UConfig();
       bool checkNr();

    private:
      short _nr;
}

and a public class in C++ that will be called in C#:

public ref class UConfigHandler
{
    public:
        UConfigHandler(UConfig^ uConfig);        
}

Then in C#, I can do it like this:

UConfig uConfig = new UConfig(1);
UConfigHandler uConfigHandler = UConfigHandler(uConfig);

in C++, I debug it and I inside the constructor:

UConfigHandler::UConfigHandler(UConfig^ uConfig)
{
    // while debugging I see that uConfig is: System::Object^
    // how to do the conversion from the uConfig to UConfig inside C++
    // I would like to do something like this but I got an exception
    UConfig myConfig = uConfig; // the program is stopped here but I dont know what is the error
}

So, basically I want to convert the System::Object^ uConfig to the native UConfig. How can I do that?

Something I have done similar with String^ to string:

input is String^

IntPtr stringPointer = (IntPtr)Marshal::StringToHGlobalAnsi(input);

string retrievedString = string((char*)stringPointer.ToPointer());

Solution

  • You're trying to assign a handle of a UConfig instance to a UConfig object. You've declared UConfig^ uConfig as a reference, therefore you can only assign it to a reference.

    It would be the equivalent in C++ if you did this:

    MyClass* mcp = new MyClass();
    MyClass mcv = mcp;
    

    In other words, your UConfigHandler constructor should look like this:

    UConfigHandler::UConfigHandler(UConfig^ uConfig)
    {
        UConfig^ myConfig = uConfig;
    }
    

    Update

    You might be able to do it... you can marshal a struct so you should be able to marshal a class too. I haven't done that, but the documentation of Marshal.StructureToPtr gives a similar example:

    // Initialize unmanged memory to hold the struct.
    IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(uConfig));
    
    // Copy the struct to unmanaged memory.
    Marshal.StructureToPtr(uConfig, pnt, false);
    
    // Create another UConfig.
    UConfig myConfig ;
    
    // Set this UConfig to the value of the 
    // UConfig in unmanaged memory. 
    myConfig = (UConfig)Marshal.PtrToStructure(pnt, typeof(UConfig));
    

    However, you can no longer take advantage of the garbage collection: you've allocated unmanaged memory so you'll also have to free it! If you don't free the allocated memory you will get a memory leak, so don't roget to do this:

    // Free the unmanaged memory.
    Marshal.FreeHGlobal(pnt);