diff -uNr dmd-0.111/dmd/html/d/changelog.html dmd-0.112/dmd/html/d/changelog.html --- dmd-0.111/dmd/html/d/changelog.html 2005-01-18 16:37:04.000000000 +0100 +++ dmd-0.112/dmd/html/d/changelog.html 2005-01-27 01:03:32.000000000 +0100 @@ -1,7 +1,7 @@ +
+ +Note: This is a library only change, the dmd executables are still +at 0.111. + +
+
+[Home]
+[Search]
+[D]
+
++ + For background information on what DLLs are and how they work + Chapter 11 of Jeffrey Richter's book + + Advanced Windows is indispensible. +
+ + This guide will show how to create DLLs of various types with D. + +
+ +
+ 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 @5 ++ + The 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 WRITE ++ + Put 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.dll ++ + which 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.lib ++ + and run: +
+C:>test +hello dll world +C:> ++ + + +
+ + There are many approaches to solving this problem: + +
+ + For understanding COM, Kraig Brockshmidt's + + Inside OLE + is an indispensible resource. +
+ + 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.
+
++ + The underlying difficulty is what to do about garbage collection (gc). + Each EXE and DLL will have their own gc instance. While + these gc's can coexist without stepping on each other, + it's redundant and inefficient to have multiple gc's running. + The idea explored here is to pick one gc and have the DLLs + redirect their gc's to use that one. The one gc used here will be + the one in the EXE file, although it's also possible to make a + seperate DLL just for the gc. +
+ + The example will show both how to statically load a DLL, and + to dynamically load/unload it. +
+ + Starting with the code for the DLL, mydll.d: +
+/*
+ * MyDll demonstration of how to write D DLLs.
+ */
+
+import std.c.stdio;
+import std.c.stdlib;
+import std.string;
+import std.c.windows.windows;
+import std.gc;
+
+HINSTANCE g_hInst;
+
+extern (C)
+{
+ void _minit();
+ void _moduleCtor();
+ void _moduleDtor();
+ void _moduleUnitTests();
+}
+
+extern (Windows)
+ BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
+{
+ switch (ulReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ printf("DLL_PROCESS_ATTACH\n");
+ break;
+
+ case DLL_PROCESS_DETACH:
+ printf("DLL_PROCESS_DETACH\n");
+ std.c.stdio._fcloseallp = null; // so stdio doesn't get closed
+ break;
+
+ case DLL_THREAD_ATTACH:
+ printf("DLL_THREAD_ATTACH\n");
+ return false;
+
+ case DLL_THREAD_DETACH:
+ printf("DLL_THREAD_DETACH\n");
+ return false;
+ }
+ g_hInst = hInstance;
+ return true;
+}
+
+export void MyDLL_Initialize(void* gc)
+{
+ printf("MyDLL_Initialize()\n");
+ std.gc.setGCHandle(gc);
+ _minit();
+ _moduleCtor();
+// _moduleUnitTests();
+}
+
+export void MyDLL_Terminate()
+{
+ printf("MyDLL_Terminate()\n");
+ _moduleDtor(); // run module destructors
+ std.gc.endGCHandle();
+}
+
+static this()
+{
+ printf("static this for mydll\n");
+}
+
+static ~this()
+{
+ printf("static ~this for mydll\n");
+}
+
+/* --------------------------------------------------------- */
+
+class MyClass
+{
+ char[] concat(char[] a, char[] b)
+ {
+ return a ~ " " ~ b;
+ }
+
+ void free(char[] s)
+ {
+ delete s;
+ }
+}
+
+export MyClass getMyClass()
+{
+ return new MyClass();
+}
+
+
+ + +
+ +
+ +
+ +
+ +
+ +
+ +
+ LIBRARY MYDLL + DESCRIPTION 'MyDll demonstration DLL' + EXETYPE NT + CODE PRELOAD DISCARDABLE + DATA PRELOAD SINGLE+ -g turns on debug info generation, and + -L/map generates a map file mydll.map. +
+ +
+ +
+import std.stdio;
+import std.gc;
+
+import mydll;
+
+//version=DYNAMIC_LOAD;
+
+version (DYNAMIC_LOAD)
+{
+ import std.c.windows.windows;
+
+ alias void function(void*) MyDLL_Initialize_fp;
+ alias void function() MyDLL_Terminate_fp;
+ alias MyClass function() getMyClass_fp;
+
+ int main()
+ { HMODULE h;
+ FARPROC fp;
+ MyDLL_Initialize_fp mydll_initialize;
+ MyDLL_Terminate_fp mydll_terminate;
+
+ getMyClass_fp getMyClass;
+ MyClass c;
+
+ printf("Start Dynamic Link...\n");
+
+ h = LoadLibraryA("mydll.dll");
+ if (h == null)
+ { printf("error loading mydll.dll\n");
+ return 1;
+ }
+
+ fp = GetProcAddress(h, "D5mydll16MyDLL_InitializeFPvZv");
+ if (fp == null)
+ { printf("error loading symbol MyDLL_Initialize()\n");
+ return 1;
+ }
+
+ mydll_initialize = cast(MyDLL_Initialize_fp) fp;
+ (*mydll_initialize)(std.gc.getGCHandle());
+
+ fp = GetProcAddress(h, "D5mydll10getMyClassFZC5mydll7MyClass");
+ if (fp == null)
+ { printf("error loading symbol getMyClass()\n");
+ return 1;
+ }
+
+ getMyClass = cast(getMyClass_fp) fp;
+ c = (*getMyClass)();
+ foo(c);
+
+ fp = GetProcAddress(h, "D5mydll15MyDLL_TerminateFZv");
+ if (fp == null)
+ { printf("error loading symbol MyDLL_Terminate()\n");
+ return 1;
+ }
+
+ mydll_terminate = cast(MyDLL_Terminate_fp) fp;
+ (*mydll_terminate)();
+
+ if (FreeLibrary(h) == FALSE)
+ { printf("error freeing mydll.dll\n");
+ return 1;
+ }
+
+ printf("End...\n");
+ return 0;
+ }
+}
+else
+{ // static link the DLL
+
+ int main()
+ {
+ printf("Start Static Link...\n");
+ MyDLL_Initialize(std.gc.getGCHandle());
+ foo(getMyClass());
+ MyDLL_Terminate();
+ printf("End...\n");
+ return 0;
+ }
+}
+
+void foo(MyClass c)
+{
+ char[] s;
+
+ s = c.concat("Hello", "world!");
+ writefln(s);
+ c.free(s);
+ delete c;
+}
+
+
+ Let's start with the statically linked version, which is simpler.
+ It's compiled and linked with the command:
+ dmd test mydll.lib -g+ Note how it is linked with mydll.lib, the import library + for mydll.dll. + The code is straightforward, it initializes mydll.lib with + a call to MyDLL_Initialize(), passing the handle + to test.exe's gc. + Then, we can use the DLL and call its functions just as if + it were part of test.exe. In foo(), gc memory + is allocated and freed both by test.exe and mydll.dll. + When we're done using the DLL, it is terminated with + MyDLL_Terminate(). +
+ + Running it looks like this: +
+DLL_PROCESS_ATTACH +Start Static Link... +MyDLL_Initialize() +static this for mydll +Hello world! +MyDLL_Terminate() +static ~this for mydll +End...+ + The dynamically linked version is a little harder to set up. + Compile and link it with the command: +
dmd test -version=DYNAMIC_LOAD -g+ The import library mydll.lib is not needed. + The DLL is loaded with a call to + LoadLibraryA(), + and each exported function has to be retrieved via + a call to + GetProcAddress(). + An easy way to get the decorated name to pass to GetProcAddress() + is to copy and paste it from the generated mydll.map file + under the Export heading. + Once this is done, we can use the member functions of the + DLL classes as if they were part of test.exe. + When done, release the DLL with + FreeLibrary(). +
+ + Running it looks like this: +
+Start Dynamic Link... +DLL_PROCESS_ATTACH +MyDLL_Initialize() +static this for mydll +Hello world! +MyDLL_Terminate() +static ~this for mydll +DLL_PROCESS_DETACH +End...+ + +
Floating literalss can have embedded '_' characters, which are ignored.
diff -uNr dmd-0.111/dmd/html/d/toc.html dmd-0.112/dmd/html/d/toc.html
--- dmd-0.111/dmd/html/d/toc.html 2004-12-30 01:56:36.000000000 +0100
+++ dmd-0.112/dmd/html/d/toc.html 2005-01-26 17:38:12.000000000 +0100
@@ -54,6 +54,7 @@
· Application Binary Interface
· Phobos (Runtime Library)
· D for Win32
+· Win32 DLLs in D
· C .h to D Modules
· FAQ
· Style Guide
@@ -64,6 +65,10 @@
· Acknowledgements