Click here to Skip to main content
Click here to Skip to main content

Exporting functions in C#/VB.NET to native code

By , 19 Nov 2012
Rate this:
Please Sign up or sign in to vote.

Introduction

The following article discusses how one would achieve exporting a function from C#/VB.NET code to be used in native code (such as C/C++). I've seen a few methods around the internet about doing this, but most of them require you to tediously add things to your project to identify methods that will be exported, such as this. With that, these articles inspired this project which is an extension of the IL-compiler from one of my previous articles.

How it works

As I previously mentioned, this article is built upon one of my previous articles (link above). This required the InlineILCompiler.exe tool from the previous article. The way this works is I have modified InlineILCompiler.exe to add a new directive which I called .exportnative. This directive marks methods so that the tool knows what to export.

Here's how the magic works: Find out how many methods are being invoked. Once this is done, we add .vtfixup directives and .data directives for each function. With only one method being exported, here's a sample:

.vtfixup [1] int32 fromunmanaged at VT1
.data VT1 = int32(0) 

According to this, it's also important to note that the .corflags directive needs to be changed to 2. I haven't actually tested if it works without this, but as far as I could see, Delphi .NET uses this corflag as well when exporting functions so I assumed it was required.

.corflags 0x00000002 

According to what I saw in Delphi.NET as well, a method must also apply a modopt() declaring a calling convention. I chose to always use stdcall as a standard. So, we end up with an exported method having the following definition:

.method public hidebysig static void  modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) DllMain() cil managed

Inside of that method, we need to declare the virtual table entry it is associated with as well as the export entry and name.

.vtentry 1 : 1
.export [1] as DllMain 

This is done for every method being exported which is all handled automatically by InlineILCompiler.exe.

Implementation

Exporting a method is incredibly easy. I'm not going to provide any elaborate guides about marshalling between native code and managed code as I think you can find other articles which cover this fairly well. As a rule of thumb, your methods shouldn't return anything greater than 4 bytes (int), anything larger than that should be passed using a ref or out parameter.

It's important to note that the name you use with .exportnative must be the same as the .NET function's name and that method must be static.

Here's an example of an exported function (C#):

public struct Foo
{
    public int A;
        public int B;
        public int C;
}

public static void CreateFoo(out Foo foo)
{
#if IL
    .exportnative CreateFoo
#endif
        foo = new Foo();
        foo.A = 22;
        foo.B = 44;
        foo.C = 55;
}

And now, here's using the code (C):

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <Windows.h>

struct Foo_t
{
    int32_t A;
    int32_t B;
    int32_t C;
};

typedef void (__stdcall *LPFCREATEFOO)(struct Foo_t *foo);

int main(void)
{
    HMODULE mod;
    LPFCREATEFOO CreateFoo;
    struct Foo_t foo;

    mod = LoadLibraryA("ExportNativeTest.dll");
    CreateFoo = (LPFCREATEFOO)GetProcAddress(mod, "CreateFoo");
    
    CreateFoo(&foo);
    printf("%d %d %d\r\n", foo.A, foo.B, foo.C);

    return 0;
}

Closing Remarks

I find it kind of disappointing Microsoft has a standardized DllImport attribute but not a standardized a DllExport attribute and such hacks need to be developed to achieve it. I expected .NET 4.5 to have such an attribute, but alas it did not which was disappointing as it doesn't seem like they will be adding one anytime soon. I currently have not tested the limitations of using these natively exported methods, so if anyone would like to provide any feedback about bugs, etc., it would be greatly appreciated. I hope you enjoyed the article and learned something new or useful.

History 

  • Sunday, August 12, 2012: Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

roylawliet
Student
Canada Canada
I was born March 15th 1994 and I have been programming for about 5 years now and working with C# for about 3 years. I am experienced in a variety of programming languages such as C/C++, Delphi, VB.NET, F#, and Python. I absolutely love learning new things about computer science, so I'm always doing research and often reinventing the wheel to get a better grasp on concepts.

Comments and Discussions

 
QuestionUsing C# class PinmemberDavide Zaccanti24-Aug-12 7:04 
AnswerRe: Using C# class Pinmemberroylawliet24-Aug-12 7:57 
GeneralRe: Using C# class PinmemberDavide Zaccanti26-Aug-12 20:09 
QuestionNice PinmemberCIDev16-Aug-12 4:34 
GeneralMy vote of 5 Pinmemberbitterskittles15-Aug-12 6:56 
GeneralRe: My vote of 5 Pinmemberroylawliet15-Aug-12 15:53 
GeneralCool Tool, but ... Pinmemberernie100013-Aug-12 23:56 
GeneralRe: Cool Tool, but ... Pinmemberroylawliet14-Aug-12 2:13 
GeneralRe: Cool Tool, but ... Pinmemberernie100014-Aug-12 3:01 
GeneralRe: Cool Tool, but ... Pinmemberroylawliet14-Aug-12 8:46 
GeneralRe: Cool Tool, but ... Pinmemberernie100014-Aug-12 20:40 
GeneralMy vote of 5 Pinmemberbartolo13-Aug-12 0:46 
QuestionA notice for viewers on August 12 2012 Pinmemberroylawliet12-Aug-12 13:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140421.2 | Last Updated 19 Nov 2012
Article Copyright 2012 by roylawliet
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid