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 
16 
17 import win32.winbase;
18 import win32.windef;
19 
20 import ae.sys.windows.exception;
21 
22 /// Loads or retrieves the handle of a DLL.
23 /// As there will be only one template instantiation
24 /// per unique DLL string, LoadLibrary will be called
25 /// at most once per unique "dll" parameter.
26 @property HMODULE moduleHandle(string dll)()
27 {
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 		alias typeof(&F) FP;
43 		static FP fp = null;
44 		if (!fp)
45 			fp = cast(FP)wenforce(GetProcAddress(moduleHandle!DLL, NAME), "GetProcAddress");
46 		return fp(args);
47 	}
48 
49 	mixin(`alias loader!(std.traits.ParameterTypeTuple!F) ` ~ NAME ~ `;`);
50 }
51 
52 /// Ditto
53 mixin template DynamicLoad(string DLL, FUNCS...)
54 {
55 	static if (FUNCS.length)
56 	{
57 		mixin DynamicLoad!(FUNCS[0], DLL);
58 		mixin DynamicLoad!(DLL, FUNCS[1..$]);
59 	}
60 }
61 
62 version(unittest) import win32.winuser;
63 
64 ///
65 unittest
66 {
67 	mixin DynamicLoad!(GetVersion, "kernel32.dll");
68 	GetVersion(); // called via GetProcAddress
69 
70 	// Multiple imports
71 	mixin DynamicLoad!("user32.dll", GetDC, ReleaseDC);
72 }