Skip to content

Commit 2a11f80

Browse files
authored
Merge pull request #3628 from WalterBright/dll-windows
Add article on building Windows DLLs
2 parents a87e81d + f691e1f commit 2a11f80

File tree

7 files changed

+238
-5
lines changed

7 files changed

+238
-5
lines changed

articles/RefReturnScope.dd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ a scoped value, no matter how twisty the code is.)
200200
)
201201

202202
Macros:
203-
TITLE=Coralling Wild Pointers With $(D ref return scope)
203+
TITLE=Coralling Wild Pointers With ref return scope
204204
ITEMR=$(LI $(RELATIVE_LINK2 $1, $+))
205205
ITEM=<hr>$(H3 <a name="$1">$+</a>)
206206
SUBNAV=$(SUBNAV_ARTICLES)

articles/dll-windows.dd

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
Ddoc
2+
3+
$(D_S $(TITLE)
4+
5+
$(HEADERNAV_TOC)
6+
7+
Windows DLLs (aka shared libraries) are a method of sharing instances of executable
8+
code and data between process. Although they perform the same role as shared libraries
9+
in other systems like Linux, OSX, and FreeBSD, they are implemented quite differently.
10+
The information in this article is specific to Windows DLLs.
11+
12+
13+
$(H2 Build a DLL)
14+
15+
$(H3 Code for the DLL)
16+
17+
$(OL
18+
$(LI Create the file myll.d:
19+
20+
---
21+
module mydll;
22+
23+
import core.sys.windows.dll;
24+
import core.stdc.stdio;
25+
26+
mixin SimpleDllMain;
27+
28+
export void entry()
29+
{
30+
printf("called mydll.entry()\n");
31+
}
32+
---
33+
)
34+
35+
$(LI Compile and link the DLL:
36+
37+
$(CONSOLE
38+
dmd -shared mydll
39+
)
40+
41+
which will create the files $(TT mydll.lib) (the $(I import library)) and
42+
$(TT mydll.dll) (the $(I dll)).
43+
)
44+
45+
46+
$(LI Create the file mydll.di:
47+
48+
---
49+
module mydll;
50+
51+
export void entry();
52+
---
53+
)
54+
55+
$(LI Create the file myexe.d:
56+
57+
---
58+
module myexe;
59+
60+
import mydll;
61+
62+
int main()
63+
{
64+
mydll.entry();
65+
return 0;
66+
}
67+
---
68+
)
69+
70+
$(LI Compile the $(TT myexe.d) file and link is with the $(TT mydll.lib)
71+
file to create the $(TT myexe.exe) file:
72+
$(CONSOLE
73+
dmd myexe.d mydll.lib
74+
)
75+
)
76+
77+
$(LI Run myexe:
78+
79+
$(CONSOLE
80+
C:> myexe
81+
called mydll.entry()
82+
)
83+
)
84+
85+
86+
$(H2 DllMain - Entry Point)
87+
88+
A Windows DLL must have an entry point, much like the `main` function in an executable.
89+
It looks like:
90+
91+
---
92+
module dllmain; // nice to always name it this
93+
94+
import core.sys.windows.windef : HINSTANCE, BOOL, DWORD, LPVOID;
95+
import core.sys.windows.winnt;
96+
import core.sys.windows.dll : dll_process_attach, dll_process_detach,
97+
dll_thread_attach, dll_thread_detach;
98+
99+
__gshared HINSTANCE g_hInst; // saved instance handle for the DLL
100+
101+
/***********************************
102+
* DLL entry point.
103+
* Params:
104+
* hInstance = instance handle for the DLL
105+
* ulReason = why the DllMain is being called
106+
* fImpLoad = null if Dll is explicitly loaded, !null if implicitly loaded
107+
* Returns:
108+
* true for success, false for failure
109+
*/
110+
extern (Windows)
111+
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID fImpLoad)
112+
{
113+
switch (ulReason)
114+
{
115+
case DLL_PROCESS_ATTACH: // when the DLL is first loaded
116+
g_hInst = hInstance; // save it for later
117+
return dll_process_attach(hInstance, true); // perform process-relative initialization
118+
119+
case DLL_PROCESS_DETACH: // when DLL is being unloaded
120+
return dll_process_detach(hInstance, true); // perform process-relative teardown
121+
122+
case DLL_THREAD_ATTACH: // new thread initialization
123+
return dll_thread_attach(true, true); // perform thread-relative initialization
124+
125+
case DLL_THREAD_DETACH: // thread is ending
126+
return dll_thread_detach(true, true); // perform thread teardown
127+
128+
default:
129+
assert(0);
130+
}
131+
}
132+
---
133+
134+
Or, since this is just boilerplate code, this will do nicely:
135+
136+
---
137+
module dllmain;
138+
139+
import core.sys.windows.dll;
140+
141+
mixin SimpleDllMain;
142+
---
143+
144+
The compiler recognizes `DllMain`, and emits a reference to `__acrtused_dll` which will
145+
pull in the DLL support code from the C runtime library. It will also cause the addition
146+
of the debug runtime library
147+
(for symbolic debug compiles) or the default runtime library (otherwise) to be searched
148+
by the linker.
149+
150+
151+
$(H2 Exporting Definitions)
152+
153+
In order for an executable to reference a name in the DLL, that name must be $(I exported)
154+
by the DLL. For example, to export the symbol `func` from this module:
155+
156+
---
157+
module mydll;
158+
export int func() { return 3; }
159+
---
160+
161+
the compiler inserts the following Export Definition directive into the object file:
162+
163+
164+
$(CONSOLE
165+
EXPDEF expflag=x00, export '__D5mydll4funcFZi', internal '', ordinal=x0
166+
)
167+
168+
for OMF files, and the equivalent in MSCOFF object files.
169+
$(TT EXPDEF) informs the linker that `mydll.func` is to be put in the export
170+
table of the DLL being linked. That's the only addition to the object file.
171+
172+
173+
$(H2 Importing Declarations)
174+
175+
The EXE file, when a DLL is attached to it, needs to know how to call it. This is
176+
called importing a declaration from the DLL. Prepare an import file $(TT mydll.di):
177+
178+
---
179+
module mydll;
180+
export int func(); // note no function body
181+
---
182+
183+
---
184+
module myexe;
185+
import mydll;
186+
187+
int test() { return func(); }
188+
---
189+
190+
Compiling $(TT myexe.d) uncovers the magic:
191+
192+
---
193+
extrn __imp___D5mydll4funcFZi
194+
195+
__D5myexe4testFZi comdat
196+
call dword ptr __imp___D5mydll4funcFZi
197+
ret
198+
---
199+
200+
A direct call is not made to `mydll.func()`, instead an indirect call to `mydll.func()` is
201+
made via a pointer to `mydll.func()`, and the pointer’s name is `__imp___D5mydll4func`.
202+
)
203+
204+
$(H2 Import Library)
205+
206+
$(P Exporting the definitions from the dll's object file, and hooking the exe file up to
207+
the dll's exports requires an additional file, the import library. The import library is
208+
automatically created by the linker when the dll is linked. This library then must be added
209+
to the link step when linking the executable file.)
210+
211+
$(H2 $(LNAME2 references, References))
212+
213+
$(OL
214+
$(LI $(LINK2 https://wiki.dlang.org/Win32_DLLs_in_D, Win32 DLLs in D))
215+
)
216+
217+
)
218+
219+
Macros:
220+
TITLE=Creating Windows DLLs
221+
SUBNAV=$(SUBNAV_ARTICLES)

articles/index.dd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ $(D_S Articles,
195195
cause memory corruption and other problems.
196196
)
197197
)
198+
$(DIVC item,
199+
$(H4 $(LINK2 $(ROOT_DIR)articles/dll-windows.html,
200+
Creating Windows DLLs))
201+
$(P
202+
Windows DLLs are quite different from shared libraries
203+
on other platforms. This article shows how to do them.
204+
)
205+
)
198206
)
199207
)
200208
)

book/dlang.org.ddoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,9 @@ $(SUBNAV_TEMPLATE
486486
$(ROOT_DIR)articles/d-array-article.html, D Slices,
487487
$(ROOT_DIR)articles/cppcontracts.html, D's Contract Programming,
488488
$(ROOT_DIR)articles/template-comparison.html, Template Comparison,
489-
$(ROOT_DIR)articles/dll-linux.html, Writing Shared Libraries
489+
$(ROOT_DIR)articles/dll-linux.html, Writing Shared Libraries,
490+
$(ROOT_DIR)articles/RefReturnScope.html, Coralling Wild Pointers With ref return scope,
491+
$(ROOT_DIR)articles/dll-windows.html, Creating Windows DLLs
490492
))
491493
)
492494
SUBNAV_FOUNDATION=

css/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ in the narrow layouts without JS. */
452452
{
453453
display: block;
454454
position: relative;
455-
white-space: nowrap;
455+
/* white-space: nowrap; */
456456
}
457457

458458
.subnav li.active > a

dlang.org.ddoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,9 @@ $(SUBNAV_TEMPLATE
493493
$(ROOT_DIR)articles/template-comparison.html, Template Comparison,
494494
$(ROOT_DIR)articles/d-array-article.html, D Slices,
495495
$(ROOT_DIR)articles/cppcontracts.html, D's Contract Programming,
496-
$(ROOT_DIR)articles/dll-linux.html, Writing Shared Libraries
496+
$(ROOT_DIR)articles/dll-linux.html, Writing Shared Libraries for Linux,
497+
$(ROOT_DIR)articles/RefReturnScope.html, Coralling Wild Pointers With ref return scope,
498+
$(ROOT_DIR)articles/dll-windows.html, Creating Windows DLLs
497499
))
498500
)
499501
SUBNAV_FOUNDATION=

posix.mak

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ ARTICLE_FILES=$(addprefix articles/, index builtin code_coverage const-faq \
338338
migrate-to-shared mixin pretod rationale regular-expression \
339339
safed templates-revisited variadic-function-templates warnings \
340340
cppcontracts template-comparison dll-linux \
341-
RefReturnScope \
341+
RefReturnScope dll-windows \
342342
)
343343

344344
# Website root filenames. They have extension .dd in the source

0 commit comments

Comments
 (0)