Despite what Vithal said, it is possible to do this using a little known technique called reverse P/Invoke.
However, as the C# compiler doesn't support DLL exports directly, you have to create the C# dll, edit the IL to insert an .export directive for each method you want to export and then recompile the dll using a tool called ilasm.exe.
Also, as C knows nothing about objects, this will only work with static methods whose parameters and return types are simple types.
Although none of this is particularly difficult, it is rather messy so I'll try to describe each step in turn.
First, go into the Visual Studio command prompt, type: notepad multiply.cs, enter the following code and save it:
using System;
public static class Arithmetic
{
public static int Multiply(int num1, int num2)
{
return num1 * num2;
}
}
Now type the following at the command prompt to compile this into a .dll
csc /t:library multiply.cs
Next type this at the command prompt to extract the IL from the dll using ildasm.exe and put it into a file called multiply2.il:
ildasm multiply.dll /out=multiply2.il
Next open multiply2.il in notepad and insert the line I've highlighted (which will cause the Multiply method to be available as a DLL export) and save it:
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.1
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly multiply
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module multiply.dll
// MVID: {2E01BB12-10AB-4E3A-9E16-6921ADAAAA0D}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x003D0000
// =============== CLASS MEMBERS DECLARATION ===================
.class public abstract auto ansi sealed beforefieldinit Arithmetic
extends [mscorlib]System.Object
{
.method public hidebysig static int32 Multiply(int32 num1,
int32 num2) cil managed
{
.export [1] as Multiply
// Code size 9 (0x9)
.maxstack 2
.locals init (int32 V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: mul
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
} // end of method Arithmetic::Multiply
} // end of class Arithmetic
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file multiply2.res
Now recompile the dll (as multiply2.dll) using ilasm.exe by typing the following line at the command prompt:
ilasm /DLL multiply2.il
Next, open notepad to create a C file (test.c say) to import and call the Multiply function from the C# dll, and save it:
#include <windows.h>
typedef int (*MyFunc)(int, int); /* define function pointer to call function in dll */
int main()
{
int result;
MyFunc multiply; /* declare variable of function pointer type */
HINSTANCE hInst = LoadLibrary("multiply2.dll"); /* load dll and get its handle */
if (hInst) /* if handle is not null */
{
multiply = (MyFunc)GetProcAddress(hInst, "Multiply"); /* get function address */
if(multiply) /* if pointer is not null, call function via the pointer */
{
result = multiply(2, 3);
printf("%d x %d = %d", 2, 3, result);
}
FreeLibrary(hInst); /* unload dll */
}
else
{
printf("Unable to load dll");
}
return 0;
}
Finally, compile this using:
cl test.c
and run the resulting test.exe.
If it works properly, you should see the following output:
2 x 3 = 6