Search notes:

Calling an unmanaged DLL from C-Sharp (C#)

This is an attempt at summing up the results of some experiments that I conducted that aimed at calling an unmanaged DLL from C#.

callee.c

First, we need some C code that implements the functionality of the DLL we want to call.
For demonstration purposes, it is sufficient to create one (simple) function:
__declspec(dllexport) int times_5(int i) {
  return 5*i;
}
Github repository about-C-Sharp, path: /call-dll/platform-bitness/callee.c
Because I am interested in how 32-bit and 64-bit DLLs can be called from .NET programs, I will create two versions of the DLL: callee_x86.dll and callee_x64.dll.

caller.cs

Then, we also need the C-Sharp source code that calls the function that was defined in the DLL. Of particular interest is the .NET namespace System.Runtime.InteropServices which allows to associate an identifier with a function in a DLL.
The source code uses the definition of CALLEE_x68 to determine which of the DLLs should be used to call.
__declspec(dllexport) int times_5(int i) {
  return 5*i;
}
Github repository about-C-Sharp, path: /call-dll/platform-bitness/callee.c

Makefile

The following Makefile creates 6 executable for any combination of the two DLLs and three -platform options for the C# compiler (anycpu, x64, x86). These executables are created with the following makefile:
cl_path=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\bin\Hostx86

all:                            \
     caller_x86__callee_x86.exe \
     caller_x64__callee_x86.exe \
     caller_any__callee_x86.exe \
     caller_x86__callee_x64.exe \
     caller_x64__callee_x64.exe \
     caller_any__callee_x64.exe

caller_x86__callee_x86.exe: caller.cs callee_x86.dll
	@csc -nologo -define:CALLEE_X86 -platform:x86    $< -out:$@

caller_x64__callee_x86.exe: caller.cs callee_x86.dll
	@csc -nologo -define:CALLEE_X86 -platform:x64    $< -out:$@

caller_any__callee_x86.exe: caller.cs callee_x86.dll
	@csc -nologo -define:CALLEE_X86 -platform:anycpu $< -out:$@

caller_x86__callee_x64.exe: caller.cs callee_x64.dll
	@csc -nologo                    -platform:x86    $< -out:$@

caller_x64__callee_x64.exe: caller.cs callee_x64.dll
	@csc -nologo                    -platform:x64    $< -out:$@

caller_any__callee_x64.exe: caller.cs callee_x64.dll
	@csc -nologo                    -platform:anycpu $< -out:$@

callee_x86.dll: callee_x86.obj
	@"$(cl_path)\x86\link" /nologo /nodefaultlib /noentry /DLL $< /out:$@

callee_x86.obj: callee.c Makefile
	@"$(cl_path)\x86\cl" /nologo -c $< /Fo$@

callee_x64.dll: callee_x64.obj
	@"$(cl_path)\x64\link" /nologo /nodefaultlib /noentry /DLL $< /out:$@

callee_x64.obj: callee.c Makefile
	@"$(cl_path)\x64\cl" /nologo -c $< /Fo$@

clean:
	@del  *.exe 2>nul
	@del  *.dll 2>nul
	@del  *.obj 2>nul
	@del  *.lib 2>nul
	@del  *.exp 2>nul
Github repository about-C-Sharp, path: /call-dll/platform-bitness/Makefile
The six executables that the makefile produces are:
name Runs OK?
caller_any__callee_x64.exe
caller_any__callee_x86.exe
caller_x64__callee_x64.exe
caller_x64__callee_x86.exe
caller_x86__callee_x64.exe
caller_x86__callee_x86.exe
The executables that didn't run threw an exception: Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format.

Index