blob: f2bb96c89c735c67ab9915e6ced1e9feabb043b4 [file] [log] [blame]
Johannes Schindelindb2f7c42017-09-25 18:06:24 +02001#ifndef LAZYLOAD_H
2#define LAZYLOAD_H
3
4/*
5 * A pair of macros to simplify loading of DLL functions. Example:
6 *
Matthias Aßhauer4a9b2042022-01-08 16:02:30 +00007 * DECLARE_PROC_ADDR(kernel32.dll, BOOL, WINAPI, CreateHardLinkW,
Johannes Schindelindb2f7c42017-09-25 18:06:24 +02008 * 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
Carlo Marcelo Arenas Belón2d84c4e2021-09-26 03:05:12 -070018typedef void (*FARVOIDPROC)(void);
19
Johannes Schindelindb2f7c42017-09-25 18:06:24 +020020struct proc_addr {
21 const char *const dll;
22 const char *const function;
Carlo Marcelo Arenas Belón2d84c4e2021-09-26 03:05:12 -070023 FARVOIDPROC pfunction;
Johannes Schindelindb2f7c42017-09-25 18:06:24 +020024 unsigned initialized : 1;
25};
26
27/* Declares a function to be loaded dynamically from a DLL. */
Matthias Aßhauer4a9b2042022-01-08 16:02:30 +000028#define DECLARE_PROC_ADDR(dll, rettype, convention, function, ...) \
Johannes Schindelindb2f7c42017-09-25 18:06:24 +020029 static struct proc_addr proc_addr_##function = \
30 { #dll, #function, NULL, 0 }; \
Matthias Aßhauer4a9b2042022-01-08 16:02:30 +000031 typedef rettype (convention *proc_type_##function)(__VA_ARGS__); \
Johannes Sixtd2c470f2021-09-26 03:05:11 -070032 static proc_type_##function function
Johannes Schindelindb2f7c42017-09-25 18:06:24 +020033
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) \
Johannes Sixtd2c470f2021-09-26 03:05:11 -070041 (function = (proc_type_##function)get_proc_addr(&proc_addr_##function))
Johannes Schindelindb2f7c42017-09-25 18:06:24 +020042
Carlo Marcelo Arenas Belón2d84c4e2021-09-26 03:05:12 -070043static inline FARVOIDPROC get_proc_addr(struct proc_addr *proc)
Johannes Schindelindb2f7c42017-09-25 18:06:24 +020044{
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)
Carlo Marcelo Arenas Belón2d84c4e2021-09-26 03:05:12 -070052 proc->pfunction = (FARVOIDPROC)GetProcAddress(hnd,
53 proc->function);
Johannes Schindelindb2f7c42017-09-25 18:06:24 +020054 }
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