Building your native library

C

Coming soon.

C++

Export members

There are two ways of exporting constructs out of C++.

1. __declspec(dllexport)

This is how to export object-oriented constructs like classes and their members (methods and fields).

Methods get generated and exported with the thiscall calling convention.

Decorate the class or the specific class members you want to export with the compiler extension __declspec( dllexport ). That will generate a .lib file containing information about the exported constructs.

This is what it basically looks like, omitting irrelevant declarations:

class __declspec( dllexport ) Foo {
    <member declarations>
};

Tip: You can simplify the directive using a macro like so:

#define DllExport   __declspec( dllexport )
2. extern "C"

The second deals with compatibility with C. If you have some C-style functions that you want to expose to C then you probably want them to be emitted as CDecl and with C name mangling.

Directly on a declaration (with or without a method body):

extern "C" void Foo();

You can also enclose multiple functions (or variables) in an extern block:

extern "C" {
void Foo();
int Bar();
};

Build library

Then build your C++ code into a shared library (in 2 steps) like so:

g++ -std=c++11 -c -o obj/lib.o <source files>
g++ -shared -static -o bin/lib.dll obj/lib.o -Wl,--out-implib,obj/lib.a

The first command will compile sources without linking, into a relocateable object file. (-c) The parameter also let you escape the requirement of having a main function.

The second command will link the relocateable object file and produce a shared library (-shared) (including all referenced GCC runtime code, -static). This file is our actual library that we will reference from .NET.

* The paths and names can be changed according to your own liking.

Accessing the native library from .NET

Finding the symbols

Assuming that the functions and variables you want to expose are visible (marked as extern or exports), you can use the tool objdump (comes with GCC) to lookup the symbols, i.e. the mangled names, for them:

objdump --syms lib.dll | less

This will list all symbols incrementally. (thanks to the piped less command)

A mangled name will typically be preceded by "__" (two underscores). However, one refers to the symbol only by one underscore, as we will see later.

We will refer to the constructs (functions, methods and global variables etc.) from .NET by their mangled names as shown by the tools.

Build a .NET wrapper

Now that you know the mangled names of your unmanaged methods you can start to model the function signatures as extern methods in .NET in order to do P/Invoke.

For instance, we have a function named "Print" with the signature void Print(const char* str). It would get the mangled name "_ZN5PrintPKc". (The return type is never included in mangled names) We also assume that it is CDecl and that the file is called "lib.dll".

From that knowledge we can construct a P/Invoke method in C# (or any other .NET language) that enables us to invoke the code within the native library:

class NativeMethods {
    [DllImport("lib.dll", EntryPoint = "_ZN5PrintPKc", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public static extern void Print(char* str);
}

Text

Last edited Aug 5, 2014 at 5:36 PM by RobertSundstrom, version 40