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 <vladimir@thecybershadow.net>
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 import ae.sys.windows.exception;
22 
23 /// Loads or retrieves the handle of a DLL.
24 /// As there will be only one template instantiation
25 /// per unique DLL string, LoadLibrary will be called
26 /// at most once per unique "dll" parameter.
27 @property HMODULE moduleHandle(string dll)()
28 {
29 	static HMODULE hModule = null;
30 	if (!hModule)
31 		hModule = LoadLibrary(dll).wenforce("LoadLibrary");
32 	return hModule;
33 }
34 
35 /// Given a static function declaration, generate a loader with the same name in the current scope
36 /// that loads the function dynamically from the given DLL.
37 mixin template DynamicLoad(alias F, string DLL, string NAME=__traits(identifier, F))
38 {
39 	static import std.traits;
40 
41 	static std.traits.ReturnType!F loader(ARGS...)(ARGS args)
42 	{
43 		alias typeof(&F) FP;
44 		static FP fp = null;
45 		if (!fp)
46 			fp = cast(FP)wenforce(GetProcAddress(moduleHandle!DLL, NAME), "GetProcAddress");
47 		return fp(args);
48 	}
49 
50 	mixin(`alias loader!(std.traits.ParameterTypeTuple!F) ` ~ NAME ~ `;`);
51 }
52 
53 /// Ditto
54 mixin template DynamicLoadMulti(string DLL, FUNCS...)
55 {
56 	static if (FUNCS.length)
57 	{
58 		mixin DynamicLoad!(FUNCS[0], DLL);
59 		mixin DynamicLoadMulti!(DLL, FUNCS[1..$]);
60 	}
61 }
62 
63 version(unittest) mixin(importWin32!q{winuser});
64 
65 ///
66 unittest
67 {
68 	mixin DynamicLoad!(GetVersion, "kernel32.dll");
69 	GetVersion(); // called via GetProcAddress
70 
71 	// Multiple imports
72 	mixin DynamicLoadMulti!("user32.dll", GetDC, ReleaseDC);
73 }