Non-COM DLLs in C#

This post is a short and very express version of my learnings on how to interact with non com dlls (Native code compiled) such as a C dll, in a C# WCF, which made me loose a lot of time and effort as i didn’t find any good article explaining how should i pass as a parameter a pointer to of a string or how should i pass a whole object based on a custom struct as a parameter with the insurance that all parameters are in the correct order for example.

So in this post i have the following topics:

  • Differences between C types and C# types
  • Import a native DLL
  • What is Marshall Class and why should i use it
  • Define a struct layout
  • Pointers in C#
  • Unsafe code

Differences between C types and C# types

One of the first things you should know is that types in C/C++ or even VB6 are different from C# types. Another important thing is that if you are working in a 64 bit machine and the dll was compiled in a 32 bit machine an int in native code is the equivalent to a short in C# well as a meter of fact C# value types have half of the size of native code ones with some exceptions (double for instance) as you can see in the next table.

C Code Types
Size (Bits)
C# Types
Size (Bits)

char

8

sbyte

8

unsigned char

16

short

16

int

long (32 bits machines)

32

int

32

long (64 bits machines)

64

long

64

float

32

float

32

double

64

double

64

Import a native DLL

To import a native DLL you cannot add a reference to it and start working, you need to define all the methods in C#, which means you need to know what methods exist in the DLL, with a special method attribute and special signature keywords.

For example, to define a method from an external native DLL you should use the attribute [DLLImport(path_to_dll)] and define the method as static and extern:

[DllImport(@”.\mynoncom.dll”)]
private static extern int open_connection(IntPtr pointerRef);

As you can already see in the method signature i use a variable of type IntPtr as a parameter, this is a possible C# pointer, but i will talk about it later in this article. 

Now you should do this for every method you want to use. My advice is that you declare it as private and than wrap it in another method, mainly because you might want to define special behaviors, such as the type you want a parameter to have when you pass it to the unmanaged code,  and you should define it in the private one. This is just a tip for best practice.

What is Marshall Class and why should i use it

Marshaling is a System.Runtime.InteropServices that allows you to make several operations over unmanaged memory, code and types such as mapping from managed types to unmanaged types or copying unmanaged memory blocks.

This is related to what i said about “the type you want a parameter to have when you pass it to the unmanaged code” i referred in the previous point in which we can map types so that the native code can work with them.

Let make an example, imagine that your C Dll demands that one of its methods parameter is a pointer to the first element of an array. Without using Marshall class you need to write code in an unsafe block code and change the project properties to allow unsafe code, this is dangerous as you let programmers and YOU, interact directly with memory block, risking to damage your memory, with Marshall you can do this without interacting directly with memory and you don’t need to change your project properties.

So how should you pass the pointer to the first element of an array? Just pass the array normally and then in your method signature add the following:

        [DllImport(“.\mynoncom.dll”)]
        public static extern int get_docs(
        [MarshalAs(UnmanagedType.LPArray)] [Out] int[] docs);

As you can see you Marshall directly in the method signature. You have several more Unmanaged types:

image

You should Marshall every variables you are sending to your unmanaged code. To int, string, short, map all of them to unmanaged types.

Another thing Marshall Class allows you to do is to retrieve the pointer of an object….

Pointers in C#

You probably know that C# allows you to use an unsafe code block in which you can retrieve pointer of object in C style:

unsafe{

int* p = &Myinteger;

}

However as i mentioned before you must enable unsafe code in you project properties and this is not good as one of C# big advantage is that it gives you safe code in managed code. This is the opposite, unsafe code with unmanaged code. Solution: Use Marshal:

public static int conn_Open(string address)
        {
            var pointer = Marshal.StringToBSTR(address);

            return etcom_open(pointer);
        }

This method above is an example of how to get an int as the value of the memory block location, which by other words is a pointer to that string. This Marshal example will retrieve an int which can be mapped to IntPtr as you saw in my early examples.

Define a struct layout

Another cool attribute i discovered in the one that will allow you pass a custom c# struct insuring that all your struct attributes are passed exactly on your declaration position, which is [StructLayout(LayoutKind.Sequential)]. This will control your fisical layout of the struct, which is useful in cases where your native dll processes those attributes according to its sizes and types.

An example:

   [StructLayout(LayoutKind.Sequential)]
    public struct myStruct    {
        public int doc_type;
        public int number;
        public int nr_lines;

        public int vendor;
        public int terminal;  

       public double discount;
        public double total;

    }

Thank you!

Anúncios

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s