1 #ifndef LAZYLOAD_H
2 #define LAZYLOAD_H
3 
4 /*
5  * A pair of macros to simplify loading of DLL functions. Example:
6  *
7  *   DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,
8  *                     LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
9  *
10  *   if (!INIT_PROC_ADDR(CreateHardLinkW))
11  *           return error("Could not find CreateHardLinkW() function";
12  *
13  *   if (!CreateHardLinkW(source, target, NULL))
14  *           return error("could not create hardlink from %S to %S",
15  *                        source, target);
16  */
17 
18 typedef void (*FARVOIDPROC)(void);
19 
20 struct proc_addr {
21 	const char *const dll;
22 	const char *const function;
23 	FARVOIDPROC pfunction;
24 	unsigned initialized : 1;
25 };
26 
27 /* Declares a function to be loaded dynamically from a DLL. */
28 #define DECLARE_PROC_ADDR(dll, rettype, function, ...) \
29 	static struct proc_addr proc_addr_##function = \
30 	{ #dll, #function, NULL, 0 }; \
31 	typedef rettype (WINAPI *proc_type_##function)(__VA_ARGS__); \
32 	static proc_type_##function function
33 
34 /*
35  * Loads a function from a DLL (once-only).
36  * Returns non-NULL function pointer on success.
37  * Returns NULL + errno == ENOSYS on failure.
38  * This function is not thread-safe.
39  */
40 #define INIT_PROC_ADDR(function) \
41 	(function = (proc_type_##function)get_proc_addr(&proc_addr_##function))
42 
43 static inline FARVOIDPROC get_proc_addr(struct proc_addr *proc)
44 {
45 	/* only do this once */
46 	if (!proc->initialized) {
47 		HANDLE hnd;
48 		proc->initialized = 1;
49 		hnd = LoadLibraryExA(proc->dll, NULL,
50 				     LOAD_LIBRARY_SEARCH_SYSTEM32);
51 		if (hnd)
52 			proc->pfunction = (FARVOIDPROC)GetProcAddress(hnd,
53 							proc->function);
54 	}
55 	/* set ENOSYS if DLL or function was not found */
56 	if (!proc->pfunction)
57 		errno = ENOSYS;
58 	return proc->pfunction;
59 }
60 
61 #endif
62