Update: Please read the article "Marshalling Compiler" about an online Marshalling Compiler which takes a C style header as input and converts it into an import of a native DLL in managed C# source code.
The compiler can be found at: http://mc.rednael.com
When you (or your bosses) have made the choice to develop your software in Microsoft’s .Net languages, like C-Sharp (C#), J-Sharp or VB, there may come a time when you need some functionality from a native DLL (or C++ DLL) which is not written in .Net and doesn’t support a COM interface.
In such a case you need at least a C style header file (.h) or a firm description of the DLL’s methods and inner workings. With that information you can write a wrapper-class in your favorite .Net language, which will enable you to use the DLL as if it was written in .Net.I will be using C# code to show you how I’ve done this.
For my project I had access to a header file (including helpful comments) that was provided by the author. This provided me with enough information to write my wrapper-class.
First of all we need to know a little about types. Native types v.s. managed. There are a few native types that you can use without conversion between .Net code and the DLL.
Interoperable types are:• int (and all integral types, like short, long, ushort, uint and ulong)• float (and all other floating point types, like double)• byte (it’s an unsigned integral type actually)• * (pointer, only in unsafe mode)• void (not really a type though)
There might be some others which look like they are interoperable, but in fact they are not:• char (C-style char is one byte, .Net char is two bytes (unicode))• bool (C-style bool is actually an integral type)• enum (C-style enum is an integral type, .Net style can have many types)
So, for any type that is not interoperable, you’ll need to manually convert them in order to use them. Also, for sake of usefulness, you should convert a regular pointer (*) to the IntPtr type. That way the code that uses your wrapper-class does not have to use the keyword “unsafe”.
But how to convert them? Well, first we need to have a look a the method (or function) definition. Below you see an example from a C-style header file:
typedef struct _sysRef sysRef; unsigned int initSystem(const char *fileName, sysRef **system);
Let me explain a bit about the above example. The first line defines an empty structure, to be used as a reference pointer. The second line defines a function which takes two parameters, filename and system . Filename is a pointer to the first element of a null-terminated array of C-style chars. System is a reference to a pointer to a struct. Also, the function returns a value of type unsigned int.
Now the first question is not how to convert, but what to convert. Namely, there is no need to convert the empty structure. Its only function is to be a reference point (where you point a pointer to). So we can simply use a void* to hold the same reference.
To use any native DLL in your .Net code, You first have import the function from the DLL. This is just like declaring a method.Below you see the import which uses only interoperable types:
[DllImport(@“C:\mylib.dll”, EntryPoint = "initSystem")] public static extern uint initSystem(void* fileName, void* system);
Now, don’t worry. Your wrapper interface is not going to expose the pointers. Instead I don’t want to pass the uint (in this case an error code) as a return value, but instead I want to pass the pointer to the system as a return value. I’ll convert the uint error code into an exception.
My wrapper will expose an interface such as:
public static IntPtr initSystem(string _fileName)
When you look at the examples, you may have noticed the original system parameter is made out of two pointers(**). It works like this. The first pointer points to the next pointer which points to the structure. It’s called a referenced pointer.Why is this done? Well, in this case it is to use the parameter as an output parameter. The idea is that you allocate memory to hold a pointer, and pass a pointer to that allocated memory as the parameter. Then, in that allocated memory, the function writes a pointer to the structure. So that when the function is finished and returns, the pointer to the allocated memory now actually points to the pointer (written by the function). The only thing left to do now is to de-reference the pointer, so that you can use it.
Then the filename parameter. It’s originally a constant char*. A pointer to the first element of an array of chars. As you know, native chars are not the same as .Net chars so we need to convert this param. We do know how the native char array is built up in memory. Namely, a native char is similar to one byte and a native array of bytes simply consists of bytes in a row. The end of the array is defined by a null-byte at the end of the array.
So, to wrap this function we need to do to manual conversions. The example below shows how you can do so:
public static IntPtr initSystem(string _fileName) { IntPtr refPtr = IntPtr.Zero; IntPtr filePtr = IntPtr.Zero; try { //convert from string to pointers filePtr = Marshal.StringToHGlobalAnsi(_fileName); //alloc mem for system pointer refPtr = Marshal.AllocHGlobal(IntPtr.Size); //call external method uint err = initSystem(filePtr.ToPointer(), refPtr.ToPointer()); //check for errors if (err != 0) throw new Exception(“Error is: “ + err); //unreference system pointer return Marshal.ReadIntPtr(refPtr); } finally { //clean up memory if (refPtr != IntPtr.Zero) Marshal.FreeHGlobal(refPtr); if (filePtr != IntPtr.Zero) Marshal.FreeHGlobal(filePtr); } }
Let’s first look at the filename parameter. In my wrapper it’s a string, in the import it’s a void*. So the string needs to be converted to a void*. This void* must point to an sequential list of bytes (one for each character in the filename) terminated by a null byte..Net has made this easy for you. Simply use the Marshal.StringToHGlobalAnsi. This method allocates new memory on the heap and copies and converts all the characters in the string to that newly allocated memory. It results into an IntPtr object. This object contains the method ToPointer, which passes you the void*.BE SURE to free the IntPtr! As said, memory has been allocated on the heap. This allocation will not be freed by GarbageCollector. You have to do this yourself by invoking the method Marshal.FreeHGlobal, passing the IntPtr as the parameter.When you do not free your allocated memory, eventually all memory will be allocated by your program resulting in out-of-memory errors. We call this a memory leak.
Now, the system parameter is a bit less easy. First we need to allocate enough memory to hold a pointer. This we do by calling Marshal.AllocHGlobal. The parameter specifies the number of bytes to allocate. For a pointer on a 32 bit machine, this is 4 bytes. To be sure that your program also runs on other types of machines, don’t just type in 4, but use the static Size property of the IntPtr class. This property always contains the right number of bytes for the current system.Again, this method also returns a IntPtr object which can be converted to an void*.After the external function returns, the allocated memory now contains a pointer to the system object. Simply read it out by calling Marshal.ReadIntPtr. You pass the pointer to the allocated memory and the method will read the (4) bytes and convert that into an IntPtr. This is the IntPtr we need. The pointer is now de-referenced.Again, be sure to free the allocated memory, as otherwise you have created a memory leak. When you free the memory, it will not wipeout the de-referenced pointer as the Marshal.ReadIntPtr method has created a new pointer for you in managed memory.
For more questions, leave a comment and I will try to answer.
UPDATE: How to pass structures
This update is an answer on Paulo's comment.
Hi Paulo,
Well actually marshalling structs is quite well documented by Microsoft, you only need to know how to find it, as they have made it quite hard to find.
Take a look at the StructLayoutAttribute class and the examples that come with it.http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx
Please know this about structs in a .Net environment... they’re not like C++ structures. Structs in .Net are more like classes, with their own constructors, properties and methods. But you are able to shape the structures of interoperable types with the StructLayoutAttribute class.
I would use the LayoutKind.Explicit as this gives me complete control over memory placement. It also enables you to skip some uninteresting fields of the structure by simply leaving some blank space in your structure.
There are several ways to pass the struct.from the example on MSDN:
[DllImport("kernel32.dll")] public static extern void GetSystemTime([MarshalAs(UnmanagedType.LPStruct)]MySystemTime st);
As you can see in the example, you can simply define the marshalling in the import.
Though this is probably the easiest way to do it, it’s not the way I’m feeling comfortable with. This is mainly because (probably like you) I originally come from an Assembly/C++ environment where I know what is going on and I’m the big cheese of control in my software. It must be crystal clear to me when to allocate or free memory, etc.
So to keep control, I would rather create the structure, fill the fields and use the System.Runtime.InteropServices.GCHandle to pin the structure and pass the pointer as parameter to the method.(please note that the GCHandle itself is also a structure and not a class )
The following is a complete example:
[DllImport(DLL, EntryPoint = "SomeFunction")] public static extern void* SomeFunction(void* structure); //------------------------------------------------------------------------- [StructLayout(LayoutKind.Explicit, Size=3)] public struct SomeStruct { [FieldOffset(0)]public byte fieldOne; [FieldOffset(1)]public ushort fieldTwo; } //------------------------------------------------------------------------- [StructLayout(LayoutKind.Explicit, Size=3)] public struct SomeOtherStruct { [FieldOffset(0)]public ushort fieldA; [FieldOffset(2)]public byte fieldB; } //------------------------------------------------------------------------- public static SomeStruct test(SomeOtherStruct _myStruct) { GCHandle hndl = new GCHandle(); try { //get pinned pointer to struct hndl = GCHandle.Alloc(_myStruct, GCHandleType.Pinned); IntPtr pntr = hndl.AddrOfPinnedObject(); //call external method IntPtr structOut = new IntPtr(SomeFunction(pntr.ToPointer())); //return the structure return (SomeStruct)Marshal.PtrToStructure(structOut, typeof(SomeStruct)); } finally { //cleanup memory if (hndl.IsAllocated) hndl.Free(); } }
[DllImport(DLL, EntryPoint = "SomeFunction")] public static extern void* SomeFunction(void* structure);
Please make sure that the returned structure does not need to be freed, or if it does, free it :) The Marshal.PtrToStructure method creates a new structure with no references to the returned pointer.
If all of this doesn’t suit your style, you can also simply allocate a specific size of unmanaged memory and map all the variables (pointers) yourself, or even copy the values directly to that block of unmanaged memory.
Remember Me
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.