Contents
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page.
Requires a signed-in GitHub account. This works well for small changes.
If you'd like to make larger changes you may want to consider using
a local clone.
Creating Windows DLLs
Build a DLL
Code for the DLL
- Create the file mydll.d:
module mydll; import core.sys.windows.dll; import core.stdc.stdio; mixin SimpleDllMain; export void entry() { printf("called mydll.entry()\n"); }
- Compile and link the DLL:
dmd -shared mydll
which will create the files mydll.lib (the import library) and mydll.dll (the dll). - Create the file mydll.di:
module mydll; export void entry();
- Create the file myexe.d:
module myexe; import mydll; int main() { mydll.entry(); return 0; }
- Compile the myexe.d file and link is with the mydll.lib
file to create the myexe.exe file:
dmd myexe.d mydll.lib
- Run myexe:
C:> myexe called mydll.entry()
DllMain - Entry Point
A Windows DLL must have an entry point, much like the main function in an executable. It looks like:module dllmain; // nice to always name it this import core.sys.windows.windef : HINSTANCE, BOOL, DWORD, LPVOID; import core.sys.windows.winnt; import core.sys.windows.dll : dll_process_attach, dll_process_detach, dll_thread_attach, dll_thread_detach; __gshared HINSTANCE g_hInst; // saved instance handle for the DLL /*********************************** * DLL entry point. * Params: * hInstance = instance handle for the DLL * ulReason = why the DllMain is being called * fImpLoad = null if Dll is explicitly loaded, !null if implicitly loaded * Returns: * true for success, false for failure */ extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID fImpLoad) { switch (ulReason) { case DLL_PROCESS_ATTACH: // when the DLL is first loaded g_hInst = hInstance; // save it for later return dll_process_attach(hInstance, true); // perform process-relative initialization case DLL_PROCESS_DETACH: // when DLL is being unloaded return dll_process_detach(hInstance, true); // perform process-relative teardown case DLL_THREAD_ATTACH: // new thread initialization return dll_thread_attach(true, true); // perform thread-relative initialization case DLL_THREAD_DETACH: // thread is ending return dll_thread_detach(true, true); // perform thread teardown default: assert(0); } }Or, since this is just boilerplate code, this will do nicely:
module dllmain; import core.sys.windows.dll; mixin SimpleDllMain;The compiler recognizes DllMain, and emits a reference to __acrtused_dll which will pull in the DLL support code from the C runtime library. It will also cause the addition of the debug runtime library (for symbolic debug compiles) or the default runtime library (otherwise) to be searched by the linker.
Exporting Definitions
In order for an executable to reference a name in the DLL, that name must be exported by the DLL. For example, to export the symbol func from this module:module mydll; export int func() { return 3; }the compiler inserts the following Export Definition directive into the object file:
EXPDEF expflag=x00, export '__D5mydll4funcFZi', internal '', ordinal=x0for OMF files, and the equivalent in MSCOFF object files. EXPDEF informs the linker that mydll.func is to be put in the export table of the DLL being linked. That's the only addition to the object file.
Importing Declarations
The EXE file, when a DLL is attached to it, needs to know how to call it. This is called importing a declaration from the DLL. Prepare an import file mydll.di:module mydll; export int func(); // note no function body
module myexe; import mydll; int test() { return func(); }Compiling myexe.d uncovers the magic:
extrn __imp___D5mydll4funcFZi __D5myexe4testFZi comdat call dword ptr __imp___D5mydll4funcFZi retA direct call is not made to mydll.func(), instead an indirect call to mydll.func() is made via a pointer to mydll.func(), and the pointer’s name is __imp___D5mydll4func.
Import Library
Exporting the definitions from the dll's object file, and hooking the exe file up to the dll's exports requires an additional file, the import library. The import library is automatically created by the linker when the dll is linked. This library then must be added to the link step when linking the executable file.
References
Copyright © 1999-2024 by the D Language Foundation | Page generated by
Ddoc on Mon Oct 14 11:27:42 2024