• entries
146
436
• views
198156

# Managed DLL goodness.

139 views

Using managed code in an unmanaged application.
Not surprisingly, the steps required to use a managed DLL in unmanaged code is roughly the same.

However, before we get to that, I should mention another way in which one can access .Net classes. That is through COM. When you build a .Net application you can use tools provided with the .Net SDK to generate a COM based wrapper around the .Net classes.

First up, we'll need a simple class to export from a Class Library. In our case I've chosen to use the following:
using System;using System.Runtime.InteropServices;namespace ManagedDll {	[StructLayout(LayoutKind.Sequential)]	public struct DataPacket {		public DataPacket(int num) {			number = num;		}		public int number;	}	public class MyThingy {		public void DoSomething(ref DataPacket packet) {			Console.WriteLine("Old value: {0}", packet.number);			Random r = new Random();			packet.number = r.Next(100);		}		public DataPacket GetSomething() {			return new DataPacket(13);		}	}}

Note that we have two things here that we'll need to do. First we'll need to be able to replicate the structure in our unmanaged code, along with calling the member functions of the MyThingy class. If you are wondering about the StructLayout attribute that I have applied to the DataPacket class, it forces the structure to be laid out in memory in the order that I specify the members. You can also use an Explicit layout which will let you directly specify the byte offsets of each element, however that is not needed for this case. The reason why I have applied that attribute is because I know that I am going to have to marshal it to it's unmanaged counterpart.

For the unmanaged code, I've chosen to once again expose an interface to the class, along with a factory function to create an instance of the actual class. The unmanaged structure is also provided in the interface header for simplicity.
#pragma once#ifdef _MSC_VER#ifdef MANAGEDDLLWRAPPER_EXPORTS#define DLLIMP __declspec(dllexport)#else#define DLLIMP __declspec(dllimport)#endif#else#define DLLIMP#endifstruct DataPacket {	DataPacket() {}	DataPacket(int num) : number(num) {}	int number;};struct IThingy {	virtual void DoSomething(DataPacket& packet) = 0;	virtual DataPacket GetSomething() = 0;	virtual void Release() = 0;};extern "C" DLLIMP IThingy* GetThingy();typedef IThingy* (*GetThingySignature)();

The next stage is to provide a concrete implementation of the IThingy interface, which in this case I call MyThingyWrapper.
#include "IThingy.h"#include using namespace System;using namespace System::Runtime::InteropServices;class MyThingyWrapper : public IThingy {public:	MyThingyWrapper() {		myThingy = gcnew ManagedDll::MyThingy();	}	void DoSomething(DataPacket& packet) {		ManagedDll::DataPacket^ managedPacket;		managedPacket = safe_cast(Marshal::PtrToStructure(IntPtr(static_cast<void*>(&packet)), ManagedDll::DataPacket::typeid));		myThingy->DoSomething(*managedPacket);		Marshal::StructureToPtr(managedPacket, IntPtr(static_cast<void*>(&packet)), false);	}	DataPacket GetSomething() {		DataPacket packet;		Marshal::StructureToPtr(myThingy->GetSomething(), IntPtr(static_cast<void*>(&packet)), false);		return packet;	}	void Release() {		delete this;	}private:	gcroot myThingy;};IThingy* GetThingy() {	return new MyThingyWrapper();}

Note how I use the Marshal class to easily convert the managed structure to the unmanaged structure and back. Finally, the gcroot might need a bit of explaining. It basically allows me to hold a reference to a managed class in an unmanaged class (the MyThingyWrapper is not a managed class). When the wrapper is released, then the gcroot will also be released, and the reference will be freed. Makes it nice and simple to deal with managed classes in unmanaged code.

## 1 Comment

Washu, I would bear your children if I could. But I can't. Because I'm a guy, you know? But still...

Seriously, though, you rock. Always nice to find something interesting when I read through the latest journals, even if it is something I will most likely never, ever use. [grin]