PInvoke ( How to Call C from C# )

I will be coding some C# stuff for Windows this year. We have a bunch of C/C++ APIs which we want to make available to our customers from C#, however, since I have known of the Mono existence for a while, I quickly realized that 90% the C# interfaces I will code on Windows for our C/C++ APIs can be made available for our Linux product as well. This post will briefly show how to call C/C++ code from C#.

As most of the readers probably know, C# is one of the primary languages of the .NET platform, thus, runs in a managed environment and cannot call unmanaged code w/o some intermediate mechanism, but don’t fear, it is quite easy, that mechanism is PInvoke, that stands for Platform Invoke. Let’s see an example of how it is done, on Linux.

1. Create a C file, libtest.c with this content:


#include <stdio.h>

void print(const char *message)
{

        printf("%s\\n", message);
}

That’s a simple pseudo-wrapper for printf. But represents any C function in the library you want to call. If you have a C++ function don’t forget to put extern “C” to avoid mangling the name.

2. Compile it as a shared library: gcc -fPIC -shared libtest.c -o libtest.so

3. Let’s create the C# file that will call our C API. It’s quite easy using PInvoke, all we need is define our entry points.

using System;

using System.Runtime.InteropServices;

public class Tester 
{
        [DllImport("libtest.so", EntryPoint="print")]

        static extern void print(string message);

        public static void Main(string[] args)
        {

                print("Hello World C# => C++");
        }
}

We define a test class that declares a method “print”. However we do not write the body of the method since we declare it extern and static because it will not depend on the class instance data. Using C# attribute DllImport we specify the DLL ( in Linux, the shared object ) where the method will be defined.

4. Compile the C# file: mcs test.cs

5. Run it: mono test.exe

Unless you have the library libtest.so in a standard library path like “/usr/lib”, you are likely to see a System.DllNotFoundException, to fix this you can move your libtest.so to /usr/lib, or better yet, just add your CWD to the library path: export LD_LIBRARY_PATH=`pwd`

6. Run it again 🙂 … now you should see the hello world C# => C++ message.

The DllImport attribute supports other arguments to tweak its behavior, refer to MSDN for DllImport documentation. Also keep in mind this is a extremely simple example, when more complex data types are involved we need to read about marshaling.

So that’s it, in my next post I will write about how to call C# code from C/C++ using COM Interop and managed C++.

This entry was posted in C/C++, linux, windows. Bookmark the permalink.

3 Responses to PInvoke ( How to Call C from C# )

  1. Pingback: 可以从C #调用c函数。网 – CodingBlog

  2. moy says:

    Just add more DllImpor lines with the C# prototype.

  3. Andy says:

    Hi,

    how to call more than one function, such as:
    [DllImport(“libtest.so”, EntryPoint=”print”)]
    [DllImport(“libtest.so”, EntryPoint=”println”)]
    ….

Leave a Reply

Your email address will not be published. Required fields are marked *

*