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 @@ +

+ What's New for + D 0.112 +

+ +Jan 26, 2005 +

+ +Note: This is a library only change, the dmd executables are still +at 0.111. + +

New/Changed Features

+ + +

What's New for D 0.111 diff -uNr dmd-0.111/dmd/html/d/dll.html dmd-0.112/dmd/html/d/dll.html --- dmd-0.111/dmd/html/d/dll.html 1970-01-01 01:00:00.000000000 +0100 +++ dmd-0.112/dmd/html/d/dll.html 2005-01-26 23:10:24.000000000 +0100 @@ -0,0 +1,658 @@ + + + + + +Digital Mars - Writing Win32 DLLs in D + + + + +www.digitalmars.com + +[Home] +[Search] +[D] + +
Last update Jan 26, 2005 +
+ +

Writing Win32 DLLs in D

+ + DLLs (Dynamic Link Libraries) are one of the foundations + of system programming for Windows. The D programming + language enables the creation of several different types of + DLLs. +

+ + 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. + +

+ +

DLLs with a C Interface

+ + A DLL presenting a C interface can connect to any other code + in a language that supports calling C functions in a DLL. + + DLLs can be created in D in roughly the same way as in C. + A DllMain() + is required, looking like: + +
+	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: + + + 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. + Alternatively, use implib. + Here's an example of a simple DLL with a function print() + which prints a string: + +

mydll2.d:

+
+module mydll;
+export void dllprint() { printf("hello dll world\n"); }
+	
+ +

mydll.def:

+
+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: + +

test.d:

+
+import mydll;
+
+int main()
+{
+   mydll.dllprint();
+   return 0;
+}
+	
+ + Create a clone of mydll2.d that doesn't have the function bodies: + +

mydll.d:

+
+export void dllprint();
+	
+ + Compile and link with the command: +
+dmd test.d mydll.lib
+	
+ + and run: +
+C:>test
+hello dll world
+C:>
+	
+ + + +

Memory Allocation

+ + D DLLs use garbage collected memory management. The question is what + happens when pointers to allocated data cross DLL boundaries? + If the DLL presents a C interface, one would assume the reason + for that is to connect with code written in other languages. + Those other languages will not know anything about D's memory + management. Thus, the C interface will have to shield the + DLL's callers from needing to know anything about it. +

+ + There are many approaches to solving this problem: + +

+ +

COM Programming

+ + Many Windows API interfaces are in terms of COM (Common Object Model) + objects (also called OLE or ActiveX objects). A COM object is an object + who's first field is a pointer to a vtbl[], and the first 3 entries + in that vtbl[] are for QueryInterface(), AddRef(), and Release(). +

+ + 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. + +

D code calling D code in DLLs

+ + Having DLLs in D be able to talk to each other as if they + were statically linked together is, of course, very desirable + as code between applications can be shared, and different + DLLs can be independently developed. +

+ + 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();
+}
+	
+ +
+
DllMain +
This is the main entry point for any D DLL. It gets called + by the C startup code + (for DMC++, the source is \dm\src\win32\dllstart.c). + The printf's are placed there so one can trace how it gets + called. + Notice that the initialization and termination code seen in + the earlier DllMain sample code isn't there. + This is because the initialization will depend on who is loading + the DLL, and how it is loaded (statically or dynamically). + There isn't much to do here. + The only oddity is the setting of std.d.stdio._fcloseallp to + null. If this is not set to null, the C runtime will flush + and close all the standard I/O buffers (like stdout, + stderr, etc.) + shutting off further output. Setting it to null defers the + responsibility for that to the caller of the DLL. +

+ +

MyDLL_Initialize +
So instead we'll have our own DLL initialization routine so + exactly when it is called can be controlled. + It must be called after the caller has initialized itself, + the Phobos runtime library, and the module constructors + (this would normally be by the time main() was entered). + This function takes one argument, a handle to the + caller's gc. We'll see how that handle is obtained later. + Instead of gc_init() being called to initialize + the DLL's gc, std.gc.setGCHandle() is called and passed the + handle to which gc to use. + This step informs the caller's gc + which data areas of the DLL to scan. + Afterwards follows the call to the _minit() to initialize the + module tables, and _moduleCtor() to run the module constructors. + _moduleUnitTests() is optional and runs the DLL's unit tests. + The function is exported as that is how a function is made + visible outside of a DLL. +

+ +

MyDLL_Terminate +
Correspondingly, this function terminates the DLL, and is + called prior to unloading it. + It has two jobs; calling the DLL's module destructors via + _moduleDtor() and informing the runtime that + the DLL will no longer be using the caller's gc via + std.gc.endGCHandle(). + That last step is critical, as the DLL will be unmapped from + memory, and if the gc continues to scan its data areas it will + cause segment faults. +

+ +

static this, static ~this +
These are examples of the module's static constructor + and destructor, + here with a print in each to verify that they are running + and when. +

+ +

MyClass +
This is an example of a class that can be exported from + and used by the caller of a DLL. The concat member + function allocates some gc memory, and free frees gc + memory. +

+ +

getMyClass +
An exported factory that allocates an instance of MyClass + and returns a reference to it. +

+ +

+ + To build the mydll.dll DLL: + +
    +
  1. dmd -c mydll -g +
    Compiles mydll.d into mydll.obj. + -g turns on debug info generation. +

    + +

  2. dmd mydll.obj \dmd\lib\gcstub.obj mydll.def -g -L/map +
    Links mydll.obj into a DLL named mydll.dll. + gcstub.obj is not required, but it prevents the bulk + of the gc code from being linked in, since it will not be used + anyway. It saves about 12Kb. + mydll.def is the + Module Definition File, + and has the contents: +
    +	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. +

    + +

  3. implib /noi /system mydll.lib mydll.dll +
    Creates an + import library + mydll.lib suitable + for linking in with an application that will be statically + loading mydll.dll. +

    + +

+ + Here's test.d, a sample application that makes use of + mydll.dll. There are two versions, one statically binds to + the DLL, and the other dynamically loads it. + +
+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...
+ + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
Copyright (c) 1999-2005 by Digital Mars, All Rights Reserved + + + + + diff -uNr dmd-0.111/dmd/html/d/enum.html dmd-0.112/dmd/html/d/enum.html --- dmd-0.111/dmd/html/d/enum.html 2004-09-01 10:10:04.000000000 +0200 +++ dmd-0.112/dmd/html/d/enum.html 2005-01-21 22:02:24.000000000 +0100 @@ -16,7 +16,7 @@ [Home] [Search] [D] -
Last modified Aug 22, 2004. +
Last modified Jan 21, 2005.

Enums - Enumerated Types

@@ -25,8 +25,8 @@ EnumDeclaration: enum Identifier EnumBody enum EnumBody - enum identifier : EnumBaseType EnumBody - enum EnumBaseType : EnumBody + enum Identifier : EnumBaseType EnumBody + enum : EnumBaseType EnumBody EnumBaseType: Type diff -uNr dmd-0.111/dmd/html/d/lex.html dmd-0.112/dmd/html/d/lex.html --- dmd-0.111/dmd/html/d/lex.html 2004-12-30 02:01:08.000000000 +0100 +++ dmd-0.112/dmd/html/d/lex.html 2005-01-19 18:29:14.000000000 +0100 @@ -10,7 +10,7 @@ [Search] [D] -
Last update Dec 30, 2004 +
Last update Jan 19, 2004

Lexical

@@ -641,7 +641,8 @@ Hexadecimal floats are preceded with a 0x and the exponent is a p - or P followed by a power of 2. + or P followed by a decimal number serving as the exponent + of 2.

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


+Tools
+· Profiler
+ +
Comparisons
· D vs C/C++/C#/Java
· Converting C to D
diff -uNr dmd-0.111/dmd/html/d/windows.html dmd-0.112/dmd/html/d/windows.html --- dmd-0.111/dmd/html/d/windows.html 2004-11-08 00:56:54.000000000 +0100 +++ dmd-0.112/dmd/html/d/windows.html 2005-01-26 22:43:10.000000000 +0100 @@ -1,7 +1,7 @@