olidev
olidev

Reputation: 20684

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());

Upvotes: 3

Views: 4179

Answers (2)

Paul Michalik
Paul Michalik

Reputation: 4381

What are you trying to do? The UConfig^ you receive in the constructor of ConfigHandler is a perfectly valid handle to a UConfig .NET instance. There is no need to marshal, cast or do anything special about it.

So, basically I want to convert the System::Object^ uConfig to the native UConfig. Could you please tell me how can I do it?

There is no native UConfig in the code snippet you've posted. You create an instance in C# and pass it to the ConfigHandler which stores a reference to it:

public ref class ConfigHandler {
    Config^ mConfig;
public:
    ConfigHandler(Config^ pConfig) : mConfig(pConfig) {}
};

You could even define the ConfigHandler in a completely different assembly using C#, there would be no difference. Well almost none, your ConfigHandler defined in C++/CLI will implement IDisposable, but since it does not store any unmanaged resources it does not matter. Hm, are you aware of the fact that you are not writing C++ but C++/CLI which is a huge difference?

Upvotes: 2

Kiril
Kiril

Reputation: 40395

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);

Upvotes: 3

Related Questions