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

How to Automate Exporting .NET Function to Unmanaged Programs

By , 21 Nov 2006
 

Introduction

Exporting functions to unmanaged programs - why not? I don't want to change *.il files by hand. I need to automate this. So here we go...

Background

A few days ago, I was writing a program (Terminal Services addin). The first problem was that I couldn't write this in C# ... Ok. I started writing it in C++/CLI. But there was another problem - mstsc.exe doesn't like to load such a library. Ok. No problem. I started another project (in C++/CLI - the first I change to pure C++) which exports one function. The first library loaded the second one and everything worked. But for dependencies, I needed easy deployment without installing VC80 runtimes... So I tried to find a way to export the function from C#. And I found it. While I was working with a project, I compiled it often and changing *.il files by hand was really annoying. That's why I made this tool. (Anyway later I found that the first library can be written in C# but it is a topic for another article - "How to write Terminal Services addin in pure C#" .)

Using the Code

Well the code is just the code ... it's a home-grown parser with some other functionality... So I'll rather write how to use it (and sometimes how it works).

Beginning

What you need to use it:

  • Framework 2.0 SDK
  • Visual Studio 2005 (optional)

First you should download the code (there are two projects ExportDll.exe and ExportDllAttribute.dll) and build it.

Then you should know how to use it... After creating the library project in C# or VB.NET, you need to add dependency to ExportDllAttribute. "Oh no, not another dependency" - you'll say. Easy ... just wait ... This library contains an attribute which tells ExportDll.exe that some function needs to be exported.

How It Works

As I said, ExportDll.exe needs to know which functions need to be exported. So you'll write something like this:

public class SomeClassName
{
    //second parameter of attribute is calling convention,
    //default is StdCall but u can use others fx.:
    [ExportDllAttribute.ExportDll("ExportNameOfFunction",
    System.Runtime.InteropServices.CallingConvention.Cdecl)]
    public static void SomeFunctionName()
    {
        System.Console.WriteLine("I really do nothing");
    }
}

After compiling, you need to use ExportDll tool to export this:

ExportDll.exe full_path_to_yours_dll\yoursdll.dll [/Release|/Debug]

Note: /Release flag is default. What exactly does ExportDll do:

  • Reads DLL as assembly and makes a dictionary of exported function
  • Decompiles DLL
  • Searches and replaces some stuff in IL code (If you want to know what, read the article that I mentioned in the "Background" section.)
  • Deletes ExportDllAttribute dependency

    .assembly extern ExportDllAttribute
    {
      .ver x:x:x:x
    }

    and

    .custom instance void
        [ExportDllAttribute]ExportDllAttribute.ExportDllAttribute ...
  • Compiles modified IL code again

Post-building in Visual Studio 2005

How? It's easy... Just add in Project property named "Post-build event command".

"path_to_tools\ExportDll.exe" "$(TargetPath)" /$(ConfigurationName)

OMG! It's Not Working

Hmm... Yes, forgot to mention about ExportDll.exe.cofig ...

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" 
        type="System.Configuration.ApplicationSettingsGroup, 
        System, Version=2.0.0.0, Culture=neutral, 
        PublicKeyToken=b77a5c561934e089" >
            <section name="ExportDll.Properties.Settings"
        type="System.Configuration.ClientSettingsSection,
        System, Version=2.0.0.0, Culture=neutral,
        PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <applicationSettings>
        <ExportDll.Properties.Settings>
            <setting name="ildasmpath" serializeAs="String">
                <value>C:\Program Files\
                Microsoft Visual Studio 8\SDK\v2.0\Bin\ildasm.exe</value>
            </setting>
            <setting name="ilasmpath" serializeAs="String">
                <value>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ilasm.exe
                </value>
            </setting>
        </ExportDll.Properties.Settings>
    </applicationSettings>
</configuration>

You need to configure path to ilasm and ildasm.

Updates

New version

  • now accept MarshalAsAtrribute
  • new commands in command line support: first had to be TargetPath then you can add:
    /release or /debug - /release id default
    /AnyCPU or /x64 - /AnyCPU is default its for 32/64 bit (for itanium add /PE64 /ITANIUM)
    ... any valid command for ildasm.exe
  • support fo x64
    "path_to_tools\ExportDll.exe" "$(TargetPath)" /$(ConfigurationName) /$(PlatformName)
    if PlatformName == "AnyCPU" then compiles for 32 bit
    if PlatformName == "x64" then compiles for 64 bit
  • now its compiled for runtime 4.0(ExportDll.exe) and 2.0 (ExportDllAttribut.dll) so it should be working for frameworks 2.0 - 4.0
  • it can compile for 2.0 or 4.0 runtime (runtime its not framework - frm 3.0 and 3.5 are using 2.0 runtime)
    it can be change by changing ilasmpath setting so:
    2.0 => C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ilasm.exe
    4.0 => C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe

References

License

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

About the Author

Selvin
Systems / Hardware Administrator
Poland Poland
Member
No Biography provided

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

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: Declare someclass where?memberocean_blue417 May '11 - 21:35 
Thanks Selvin,
 
My problem is simpel, i have a .Net made dll file and i want export some functions from that dll file. Can u help me to use ure code? Thanks
GeneralRe: Declare someclass where?memberSelvin17 May '11 - 21:45 
My program cant't change already existing dll
You need compile this dll and add ExportDll atribute to the exported function
Look at wcf sample from post above.
It contains C# and c++ project
In C# project we export some function and in C++ project we call it.
...works fascinates me...i can stare it for hours...

GeneralMy vote of 5memberjoffreyb11 May '11 - 17:51 
Worked great! You saved my day Smile | :)
GeneralN0 exported functions...memberDonald Neisler15 Mar '11 - 10:34 
I ran this process and ran dllviewer and it shows no exported functions. I tried this in C# and vb.net and could not get either to work. Any assistance would be great.
GeneralRe: N0 exported functions...memberSelvin18 Mar '11 - 16:39 
try this solution http://sites.google.com/site/robertgiesecke/[^] or read comment abot new version
...works fascinates me...i can stare it for hours...

GeneralTAB Key not workingmembervss15 Mar '11 - 6:23 
Hi.
 
I have created a C# DLL with form and create a function to start the dialog.
 
I have user DLLExport project to create an unmanaged interface to VC 6.0.
 
When i use the dll in a VC 6.0 project the TAB keys don't work.
 
Any ideas?
GeneralRe: TAB Key not workingmemberSelvin18 Mar '11 - 16:34 
try to run dialog in other thread
 

void exportfunction()
{
ManualResetEvent wait = new ManualResetEvent(false);
var thread = new Thread(() =>
{
Application.Run(new Form1(wait));
//in OnClosed add "wait.Set();"
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
wait.WaitOne();
 
}
 
or even in new AppDomain
...works fascinates me...i can stare it for hours...

GeneralMarshalling Objectmembersaplpete24 Jan '11 - 7:46 
I use our solution with great success!
 
Now I tried the following:
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
 
namespace ConnectionDLL
{
public class ConnectionSQLServer
{
[ExportDllAttribute.ExportDll("Connection",
System.Runtime.InteropServices.CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.AsAny)]
public static SqlConnection Connect(String Datenbank)
{
string connectionString = null;
SqlConnection cnn ;
connectionString = "Data Source=PETER-PC\\PETER;database=AdoDB;User ID=Test;Password=testtest";
cnn = new SqlConnection(connectionString);
try
{
//cnn.Open();
}
catch (Exception ex)
{
//
}
return cnn;
}
}
}
 
I want to use the exported DLL like this in EXCEL:
 
Private Declare Function Connection Lib "C:\Dokumente und Einstellungen\Peter\Eigene Dateien\Visual Studio 2008\Projects\ConnectionDLL\ConnectionDLL\bin\Debug\connectiondll.dll" _
(ByVal stDB As String) As Object

Sub SQL()
 
Dim conn1 As New Connection
Dim rec As New Recordset
Dim comm As New Command
 
conn1 = Connection("AdoDB")
conn1.Open
comm.ActiveConnection = conn1
SQLcmd = "SELECT Zuname FROM adressen where Vorname ='Markus'"
comm.CommandText = SQLcmd
rec.Open comm
ActiveCell.Value = 0
ActiveCell.CopyFromRecordset rec
End Sub
 
By the way - I didn't already use the parameter in den function "connection"! The objective of the DLL is to hide the SQLAuthentification, because if you hide the SQLAuthentification in the EXCEL module you are not safe, you can read the module which is secured with a password very easy with open office.
 
Excel crashes .... what's wrong?
GeneralRe: Marshalling ObjectmemberSelvin24 Jan '11 - 23:18 
1) this is not a solution ... you can easily find "SQLAuthentification" using .net reflector
2) System.Data.SqlClient.SqlConnection != ADODB.Connection that's why excel crashes ... if u really want to do it this way u need to add references to ADODB in .NET project and use ADODB.Connection it instead of SqlConnection
3) u can also build ".NET addin to excel" or "Excel automation in .NET" without any VBA code ...
...works fascinates me...i can stare it for hours...

GeneralRe: Marshalling Objectmembersaplpete25 Jan '11 - 10:35 
Tanks a lot for your immediate reply!
 
Excel still crashes! My new code:
---------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
using System.Data;
using System.Data.OleDb;
using ADODB;
 
namespace ConnectionDLL
{
public class ConnectionSQLServer
{
[ExportDllAttribute.ExportDll("Connect",
System.Runtime.InteropServices.CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.AsAny)]
public static ADODB.Connection Connect(String Datenbank)
{
ADODB.Connection cnn = new ADODB.Connection();
int intConnectionMode = (int)ConnectModeEnum.adModeUnknown;
String Username = "Test";
String Password = "testtest";
cnn.Open("Provider='SQLOLEDB';Data Source='PETER-PC\\PETER'; Initial Catalog='"+ Datenbank + "';",Username , Password, intConnectionMode);
return cnn;
}
}
}
 
---------------------------------
Private Declare Function Connect Lib "C:\Dokumente und Einstellungen\Peter\Eigene Dateien\Visual Studio 2008\Projects\ConnectionDLL\ConnectionDLL\bin\Debug\connectiondll.dll" _
(ByVal stDB As String) As ADODB.Connection

Sub SQL()
Dim conn1 As New ADODB.Connection
Dim rec As New ADODB.Recordset
Dim comm As New ADODB.Command
conn1 = Connect("AdoDB")
conn1.Open
comm.ActiveConnection = conn1
SQLcmd = "SELECT Zuname FROM adressen where Vorname ='Markus'"
comm.CommandText = SQLcmd
rec.Open comm
ActiveCell.Value = 0
ActiveCell.CopyFromRecordset rec
End Sub

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 22 Nov 2006
Article Copyright 2006 by Selvin
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid