• entries
    146
  • comments
    436
  • views
    197742

Managed DLL goodness.

Sign in to follow this  

129 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
#endif

struct 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.
Sign in to follow this  


1 Comment


Recommended Comments

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]

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now