[.net] Managed wrapper for unmanaged class (C++)

Started by
6 comments, last by Subotron 16 years, 2 months ago
I've written an unmanaged (OO) C++ library that I now want to access from inside C#. I've started building a wrapper in managed C++ for all classes in my library, and so far everything works fine, but I now have an issue I can't resolve nor find anything on (probably I'm searching wrong, but I tried a lot of things). I'm wrapping a class that has some public data members which are pointers (actually boost::shared_ptr) to other classes in the library. Since these pointers are public, I need to include them in the wrapper so they can be used. The class looks like this: (leaving out irrelevant parts)

class Application
{
public:
	boost::shared_ptr<CLog>		Log;
	boost::shared_ptr<CKernel>	Kernel;
	// And some more pointers

	Application	();
	~Application	();
	void Execute	();
};

Wrapping the constructor/destructor/Execute function was easy enough. However, I'm not sure what to do with the pointers to the other classes, since those classes are unmanaged too. One thing I thought of was to write managed versions of these classes as well, and replace the pointers in my managed Application class with pointers to those newly created managed versions of CLog and CKernel. I'm not sure if this is the best/only way to go though, and it seems like a lot of work. Can anyone tell me how to do this? This is my wrapped class so far:

	public ref class cApp
	{
	private:
		Application* application;

	public:
		cApp()
		{
			application = new Application();
		}

		~cApp()
		{
			delete application;
		}

		void Execute()
		{
			application->Execute();
		}
	};

Thanks a lot in advance for any help!
Advertisement
C# doesn't know anything about an unmanaged object addressed by a pointer, and can't do anything with it.

So yes, if you want to be able to interact with the log and kernel objects in c#, you'll need to wrap them up, whether by putting them in their own containers, or giving the application class functions to interact with them.
It is still not clear to me how to solve this. Suppose I go with the method of wrapping up the other classes too, how do I represent them in a way that matches the C++ representation?

Right now, calling the Application in C# is very straightforward:

Namespace.Application App = new Namespace.Application();
App.Execute();

Now when I call a Log function, it should ideally look like this:

App.Log.Something();

so I figure, the managed Application class should hold a data member that provides direct access to the unmanaged class. However, in the unmanaged class, the application class has already constructed a Log instance in its own constructor. This means the managed Application class should not create a new instance, but rather take the existing one from the unmanaged class and assign it to the (managed) data member. Is this possible? Is it the right way of thinking?

A small code example would be of great help if possible, its hard to find good material on this subject.
public ref class cApp{private:	Application* application;        Log^ log;public:	cApp()	{		application = new Application();                log = gcnew Log(application->Log);	}	~cApp()	{		delete application;	}	void Execute()	{		application->Execute();	}        property Log^ Log        {                Namespace::Log^ get() { return log; }        }};public ref class Log{private:    CLog *m_Pointer;internal:    Log(CLog* pointer) { m_Pointer = pointer; }public:    void Method1() { m_Pointer->Method1(); }    void Method2() { m_Pointer->Method2(); }};


Incidentally, if you want to take a look at a full-blown project using C++/CLI, head over to our page for SlimDX. Sometimes it's easiest to wrap your head around the syntax when you can actually look at some examples, which seem to be sorely lacking on the internet.
Mike Popoloski | Journal | SlimDX
Thanks a lot! That's exactly what I needed. I came pretty close myself, but lacked syntactical knowledge. I'm pretty sure I can figure out most of my issues now, but I'll definetly check your page out.
Quote:Original post by Subotron
It is still not clear to me how to solve this. Suppose I go with the method of wrapping up the other classes too, how do I represent them in a way that matches the C++ representation?


You would store references to the managed wrapper versions inside of your app, and you can give those wrappers methods that initialize them... Ah, I think I see what you're asking...

public ref class cApp	{	private:		Application* application;                LogWrapper^    managedLog;                KernelWrapper^ managedKernel;	public:		cApp()		{			application = new Application();                                                // How do we tell this managed object to                         // wrap itself around an unmanaged object,                        // when we can't pass unmanaged data to                        // its managed interface...                         managedLog = gcnew LogWrapper();                         // etc...		}		~cApp()		{			delete application;		}		void Execute()		{			application->Execute();		}	};


Is that what you're saying?

(When you are in mixed-mode, surely there is a way to get at LogWrapper's unmanaged members.... I'm curious about this also)
Quote:Original post by Mike.Popoloski
log = gcnew Log(application->Log);


I was going to suggest that, but I wasn't aware that you could pass an unmanaged pointer to a managed constructor. That was informative!

Quote:Original post by smitty1276
Quote:Original post by Mike.Popoloski
log = gcnew Log(application->Log);


I was going to suggest that, but I wasn't aware that you could pass an unmanaged pointer to a managed constructor. That was informative!


Glad to see I'm not the only one having use for this topic :) thanks for your reply, it's good to see all fingers pointing in the same direction, gives me some confirmation this is a good way to do it :)

This topic is closed to new replies.

Advertisement