zip
stdio
int printf(char* format, ...)
C printf() function.
D for Win32
This describes the D implementation for 32 bit Windows systems. Naturally, Windows specific D features are not portable to other platforms.
Instead of the:
#include
of C, in D there is:
import windows;
Calling Conventions
In C, the Windows API calling conventions are __stdcall. In D, it is simply:
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.
Windows Executables
Windows GUI applications can be written with D. A sample such can be found in \dmd\samples\d\winsamp.d
These are required:
-
Instead of a main function serving as the entry point, a WinMain function is needed.
-
WinMain must follow this form:
-
import 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 = doit(); // insert user code here
-
}
-
-
catch (Object o) // catch any uncaught exceptions
-
{
-
MessageBoxA(null, (char *)o.toString(), "Error",
-
MB_OK | MB_ICONEXCLAMATION);
-
result = 0; // failed
-
}
-
-
gc_term(); // run finalizers; terminate garbage collector
-
return result;
-
}
The doit() function is where the user code goes, the rest of WinMain is boilerplate to initialize and shut down the D runtime system.
-
A .def (Module Definition File) with at least the following two lines in it:
-
EXETYPE NT
-
SUBSYSTEM WINDOWS
Without those, Win32 will open a text console window whenever the application is run.
-
The presence of WinMain() is recognized by the compiler causing it to emit a reference to __acrtused and the phobos.lib runtime library.
DLLs (Dynamic Link Libraries)
DLLs can be created in D in roughly the same way as in C. A DllMain() is required, looking like:
import 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:
-
The _moduleUnitTests() call is optional.
-
It's a little crude, I hope to improve it.
-
The presence of DllMain() is recognized by the compiler causing it to emit a reference to __acrtused_dll and the phobos.lib runtime library.
Link with a .def (Module Definition File) along the lines of:
LIBRARY MYDLL
DESCRIPTION 'My DLL written in D'
EXETYPE NT
CODE PRELOAD DISCARDABLE
DATA PRELOAD SINGLE
EXPORTS
DllGetClassObject @2
DllCanUnloadNow @3
DllRegisterServer @4
DllUnregisterServer @5
The functions in the EXPORTS list are for illustration. Replace them with the actual exported functions from MYDLL.
Memory Allocation
D DLLs use garbage collected memory management. The question is what happens when pointers to allocated data cross DLL boundaries? Other DLLs, or callers to a D DLL, may even be written in another language and may have no idea how to interface with D's garbage collector.
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:
-
Do not return pointers to D gc allocated memory to the caller of the DLL. Instead, have the caller allocate a buffer, and have the DLL fill in that buffer.
-
Retain a pointer to the data within the D DLL so the GC will not free it. Establish a protocol where the caller informs the D DLL when it is safe to free the data.
-
Use operating system primitives like VirtualAlloc() to allocate memory to be transferred between DLLs.
-
Use COM interfaces, rather than D class objects. D supports the AddRef()/Release() protocol for COM interfaces. Most languages implemented on Win32 have support for COM, making it a good choice.
Share with your friends: |