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:

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

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

If I use "[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4)]" (the code which I think is wrong) the function will be exported but it does'nt work with VBA.

If I use "[return: MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]" (the code which I think is correct) then I get an error while exporting the function ( .... this german message with HRESULT: 0x80131402 at the end).

Does ExportDLL also work in .Net 3.5 ? Is this still the simplest way to expose .Net methods to older Win32 clients ?

Any suggestions and good advice is welcome ! Thanks !

btw,
I'm just entering this arena of .Net development. I need to be able to call a .Net based web service client (which i already implemented in a C# testproject) from a Delphi (version 3) application.

Hi
When I run dependency walker over a dll that has been created using ExportDll I get the following dlls that could not be found:
c:\windows\system32\ADVAPI32.DLL
c:\windows\system32\MPR.DLL
c:\windows\system32\SHLWAPI.DLL
c:\windows\system32\USER32.DLL

We are having the same issue. Tried the example C# code and everything works fine. When we try it with VB.NET then all we see on the output from ExportDll.exe is "Debug: false" and the command prompt returns.

I created a dll in Visual Basic using Visual Studio 2008 and I need to export the only function (Ocr) in the dll. I tried what you wrote at "http://www.codeproject.com/KB/dotnet/DllExport.aspx" to export my dll but it doesn't change when I compile it since when I use Dependecy Walker I don't see any exported method in my dll. I summarize what I did following your instructions:

1)I created my dll in Visual Studio 2008 as a project Class Library in Visual Basic.My dll is called Bollettino.dll. It contains only a Sub called Ocr.

2) I downloaded the ExportDll code and I added ExportAttribute.dll as an address in my project .

Doc1 = New MODI.Document
Doc1.Create(inputFile)
Doc1.OCR() ' this will ocr all pages of a multi-page tiff file
Doc1.Save() ' this will save the deskewed reoriented images, and the OCR text, back to the inputFile

For imageCounter As Integer = 0 To (Doc1.Images.Count - 1) ' work your way through each page of results
strRecText &= Doc1.Images(imageCounter).Layout.Text ' this puts the ocr results into a string
Next

When i add the exporting to post build action, it works without any problem. But when I try to do it manually like ExportDLL.exe path\dll_name, then i am getting following messages and it doesn't work.