Instead of the:
#include <windows.h>of C, in D there is:
import std.c.windows.windows;
extern (Windows) { ... function declarations ... }The Windows linkage attribute sets both the calling convention and the name mangling scheme to be compatible with Windows.
For functions that in C would be __declspec(dllimport) or __declspec(dllexport), use the export attribute:
export void func(int foo);If no function body is given, it's imported. If a function body is given, it's exported.
These are required:
import std.c.windows.windows; extern (C) void gc_init(); extern (C) void gc_term(); extern (C) void _minit(); extern (C) void _moduleCtor(); extern (C) void _moduleUnitTests(); extern (Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int result; gc_init(); // initialize garbage collector _minit(); // initialize module constructor table try { _moduleCtor(); // call module constructors _moduleUnitTests(); // run unit tests (optional) result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } catch (Object o) // catch any uncaught exceptions { MessageBoxA(null, cast(char *)o.toString(), "Error", MB_OK | MB_ICONEXCLAMATION); result = 0; // failed } gc_term(); // run finalizers; terminate garbage collector return result; } int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { ... insert user code here ... }The myWinMain() function is where the user code goes, the rest of WinMain is boilerplate to initialize and shut down the D runtime system.
EXETYPE NT SUBSYSTEM WINDOWSWithout those, Win32 will open a text console window whenever the application is run.
import std.c.windows.windows; HINSTANCE g_hInst; extern (C) { void gc_init(); void gc_term(); void _minit(); void _moduleCtor(); void _moduleUnitTests(); } extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: gc_init(); // initialize GC _minit(); // initialize module list _moduleCtor(); // run module constructors _moduleUnitTests(); // run module unit tests break; case DLL_PROCESS_DETACH: gc_term(); // shut down GC break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: // Multiple threads not supported yet return false; } g_hInst=hInstance; return true; }Notes:
LIBRARY MYDLL DESCRIPTION 'My DLL written in D' EXETYPE NT CODE PRELOAD DISCARDABLE DATA PRELOAD SINGLE EXPORTS DllGetClassObject @2 DllCanUnloadNow @3 DllRegisterServer @4 DllUnregisterServer @5The functions in the EXPORTS list are for illustration. Replace them with the actual exported functions from MYDLL. Alternatively, use implib. Here's an example of a simple DLL with a function print() which prints a string:
module mydll; export void dllprint() { printf("hello dll world\n"); }
LIBRARY "mydll.dll" EXETYPE NT SUBSYSTEM WINDOWS CODE SHARED EXECUTE DATA WRITEPut the code above that contains DllMain() into a file dll.d. Compile and link the dll with the following command:
dmd -ofmydll.dll mydll2.d dll.d mydll.def implib/system mydll.lib mydll.dllwhich will create mydll.dll and mydll.lib. Now for a program, test.d, which will use the dll:
import mydll; int main() { mydll.dllprint(); return 0; }Create a clone of mydll2.d that doesn't have the function bodies:
export void dllprint();Compile and link with the command:
dmd test.d mydll.liband run:
C:>test hello dll world C:>
There are many approaches to solving this problem. The most practical approaches are to assume that other DLLs have no idea about D. To that end, one of these should work:
COM objects are analogous to D interfaces. Any COM object can be expressed as a D interface, and every D object with an interface X can be exposed as a COM object X. This means that D is compatible with COM objects implemented in other languages.
While not strictly necessary, the Phobos library provides an Object useful as a super class for all D COM objects, called ComObject. ComObject provides a default implementation for QueryInterface(), AddRef(), and Release().
Windows COM objects use the Windows calling convention, which is not the default for D, so COM functions need to have the attribute extern (Windows). So, to write a COM object:
import std.c.windows.com; class MyCOMobject : ComObject { extern (Windows): ... }The sample code includes an example COM client program and server DLL.