1 /**
2  * Windows DLL utility code.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.sys.windows.dll;
15 version (Windows):
16 
17 import ae.sys.windows.imports;
18 mixin(importWin32!q{winbase});
19 mixin(importWin32!q{windef});
20 
21 /// Loads or retrieves the handle of a DLL.
22 /// As there will be only one template instantiation
23 /// per unique DLL string, LoadLibrary will be called
24 /// at most once per unique "dll" parameter.
25 @property HMODULE moduleHandle(string dll)()
26 {
27 	import ae.sys.windows.exception;
28 	static HMODULE hModule = null;
29 	if (!hModule)
30 		hModule = LoadLibrary(dll).wenforce("LoadLibrary");
31 	return hModule;
32 }
33 
34 /// Given a static function declaration, generate a loader with the same name in the current scope
35 /// that loads the function dynamically from the given DLL.
36 mixin template DynamicLoad(alias F, string DLL, string NAME=__traits(identifier, F))
37 {
38 	static import std.traits;
39 
40 	static std.traits.ReturnType!F _loader(ARGS...)(ARGS args)
41 	{
42 		import ae.sys.windows.exception;
43 		import ae.sys.windows.imports;
44 		mixin(importWin32!q{winbase});
45 
46 		alias typeof(&F) FP;
47 		static FP fp = null;
48 		if (!fp)
49 			fp = cast(FP)wenforce(GetProcAddress(moduleHandle!DLL, NAME), "GetProcAddress");
50 		return fp(args);
51 	}
52 
53 	mixin(`alias _loader!(std.traits.ParameterTypeTuple!F) ` ~ NAME ~ `;`);
54 }
55 
56 /// Ditto
57 mixin template DynamicLoadMulti(string DLL, FUNCS...)
58 {
59 	static if (FUNCS.length)
60 	{
61 		mixin DynamicLoad!(FUNCS[0], DLL);
62 		mixin DynamicLoadMulti!(DLL, FUNCS[1..$]);
63 	}
64 }
65 
66 version(unittest) mixin(importWin32!q{winuser});
67 
68 ///
69 unittest
70 {
71 	mixin DynamicLoad!(GetVersion, "kernel32.dll");
72 	GetVersion(); // called via GetProcAddress
73 
74 	// Multiple imports
75 	mixin DynamicLoadMulti!("user32.dll", GetDC, ReleaseDC);
76 }