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
 

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
Member
Hey guys, my name is Roy. I was born March 15th 1994 and I am currently a student at the University of Waterloo. 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.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionUsing C# classmemberDavide Zaccanti24 Aug '12 - 7:04 
AnswerRe: Using C# classmemberroylawliet24 Aug '12 - 7:57 
GeneralRe: Using C# classmemberDavide Zaccanti26 Aug '12 - 20:09 
QuestionNicememberCIDev16 Aug '12 - 4:34 
GeneralMy vote of 5memberbitterskittles15 Aug '12 - 6:56 
GeneralRe: My vote of 5memberroylawliet15 Aug '12 - 15:53 
GeneralCool Tool, but ...memberernie100013 Aug '12 - 23:56 
GeneralRe: Cool Tool, but ...memberroylawliet14 Aug '12 - 2:13 
GeneralRe: Cool Tool, but ...memberernie100014 Aug '12 - 3:01 
GeneralRe: Cool Tool, but ...memberroylawliet14 Aug '12 - 8:46 
GeneralRe: Cool Tool, but ...memberernie100014 Aug '12 - 20:40 
GeneralMy vote of 5memberbartolo13 Aug '12 - 0:46 
QuestionA notice for viewers on August 12 2012memberroylawliet12 Aug '12 - 13:51 

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

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