D语言创建和调用DLL学习笔记
测试环境:win10 64bit+dmd2.103.0+vs community 2015(cl.exe即vc链接)。
一、创建dll的步骤
- 创建dllmain.d
1 import core.sys.windows.windows; 2 import core.sys.windows.dll; 3 4 __gshared HINSTANCE g_hInst; 5 6 extern (Windows) 7 BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) 8 { 9 switch (ulReason) 10 { 11 case DLL_PROCESS_ATTACH: 12 g_hInst = hInstance; 13 dll_process_attach( hInstance, true ); 14 break; 15 16 case DLL_PROCESS_DETACH: 17 dll_process_detach( hInstance, true ); 18 break; 19 20 case DLL_THREAD_ATTACH: 21 dll_thread_attach( true, true ); 22 break; 23 24 case DLL_THREAD_DETACH: 25 dll_thread_detach( true, true ); 26 break; 27 default:break; 28 } 29 30 return true; 31 } 32
2. 创建导出函数模块mydll.d
1 module mydll; 2 import core.stdc.stdio; 3 4 export void dllprint() 5 { 6 printf("hello dll world\n"); 7 } 8
3. 创建模块定义文件mydll.def
1 LIBRARY "mydll.dll" 2 EXETYPE NT 3 SUBSYSTEM WINDOWS 4 CODE SHARED EXECUTE 5 DATA WRITE
4. 编译生成mydll.lib和mydll.dll的批处理文件build_dll.bat。-m64指示编译器和连接器生成64位静态库和动态库。
1 rem set PATH=c:\person\dmd2\windows\bin;c:\person\dmd2\windows\lib;%PATH% 2 dmd -m64 -ofmydll.dll mydll.d dllmain.d mydll.def 3 pause
查看目录文件夹确保mydll.lib和mydll.dll已生成
5. 创建子目录\test,在其内创建导出函数接口文件(类同c的头文件,只有函数声明,没有实现)模块mydll.di,将模块mydll.d里的实现部分剥离
1 /module mydll; 2 3 export void dllprint(); 4
6. 在子目录\test下创建测试主程序模块test.d,程序运行时动态链接mydll.di
1 module test; 2 3 import mydll; 4 import std.stdio; 5 int main() 6 { 7 mydll.dllprint(); 8 9 readln; 10 return 0; 11 }
7. 编译测试程序批处理文件buid_test.bat,注意不需要mydll.d即包含函数实现的这个模块文件,这也是库(lib/dll)的目的和作用所在。-m64 指示生成64位应用程序。
1 rem set PATH=c:\person\dmd2\windows\bin;c:\person\dmd2\windows\lib;%PATH% 2 dmd -m64 test.d mydll.lib 3 pause
8. 查看目录内test.exe已生成,再次留意这里必要的文件是test.d ,mydll.lib,mydll.dll,和头文件mydll.di,没有mydll.d
9. 运行test.exe
二、代码内调用dll
- 创建class_from_dll.d,这次将导出函数模块放在一起。另外除了自由函数动态库的生成,也测试类方法(class method)动态库的生成与调用。
1 module class_from_dll; 2 3 import core.sys.windows.windows; 4 import core.sys.windows.dll; 5 6 7 __gshared HINSTANCE g_hInst; 8 9 version(Windows) 10 { 11 12 //mixin SimpleDLLMain; 13 extern (Windows) 14 BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) 15 { 16 switch (ulReason) 17 { 18 case DLL_PROCESS_ATTACH: 19 g_hInst = hInstance; 20 dll_process_attach( hInstance, true ); 21 break; 22 23 case DLL_PROCESS_DETACH: 24 dll_process_detach( hInstance, true ); 25 break; 26 27 case DLL_THREAD_ATTACH: 28 dll_thread_attach( true, true ); 29 break; 30 31 case DLL_THREAD_DETACH: 32 dll_thread_detach( true, true ); 33 break; 34 default:break; 35 } 36 37 return true; 38 } 39 } 40 41 extern(C): 42 export void showMessage() 43 { 44 //printf is ok of course 45 //import core.stdc.stdio; 46 //printf("Hello from exported function showMessage().\n"); 47 48 import std.stdio; 49 writeln("Hello from exported function showMessage()."); 50 } 51 52 53 export class ClassFromDLL 54 { 55 void print() 56 { 57 //printf ok; 58 //import core.stdc.stdio; 59 //printf("Hello from exported Class.print().\n"); 60 61 import std.stdio; 62 writeln("Hello from exported Class.print()."); 63 } 64 } 65 export ClassFromDLL factory(){return new ClassFromDLL;}
2. 创建导出函数头文件模块class_from_dll.di
1 module class_from_dll; 2 3 extern(C): 4 extern void showMessage(); 5 extern class ClassFromDLL 6 { 7 void print(); 8 } 9 extern ClassFromDLL factory();
3. 创建测试主程序模块app.d,代码内调用dll
1 module app; 2 3 import std.stdio; 4 import core.runtime; 5 import core.sys.windows.windows; 6 import core.sys.windows.winbase:GetProcAddress; 7 8 import class_from_dll;// .di 9 10 void print_from_main() 11 { 12 writeln("Hello from main function print_from_main()."); 13 } 14 15 void main() 16 { 17 //dmd 2.04x的时候需要call Runtime.initialize()和Runtime.unloadLibrary(lib); 18 //Runtime.initialize(); 19 void* lib = Runtime.loadLibrary("class_from_dll.dll"); 20 21 auto print=cast(void function())GetProcAddress(lib,"showMessage"); 22 23 print(); 24 25 26 auto factoryFunction = cast(typeof(&factory))GetProcAddress(lib, factory.mangleof); 27 ClassFromDLL cls = factoryFunction(); 28 cls.print(); 29 30 //Runtime.unloadLibrary(lib); 31 32 print_from_main(); 33 34 writeln("\nDone.\nPress any key to exit..."); 35 36 readln; 37 }
4. 一切就绪,这次将创建库(lib/dll)和测试主程序的编译放在一个批处理文件里buildAll.bat一键完成。-m64指示生成64位静态库、动态库和最终的测试应用程序。
注意这次生成主程序时不需用静态库class_from_dll.lib
1 rem set PATH=c:\person\dmd2\windows\bin;c:\person\dmd2\windows\lib;%PATH% 2 dmd -m64 -shared class_from_dll.d 3 dmd -m64 app.d class_from_dll.di 4 pause
5. 查看目录内class_from_dll.lib,class_from_dll.dll,以及app.exe应已生成。
6. 运行app.exe