Win32: simplify loading of DLL functions

Dynamic loading of DLL functions is duplicated in several places in Git for Windows' source code. This patch adds a pair of macros to simplify the process: the DECLARE_PROC_ADDR(<dll>, <return-type>, <function-name>, ...<function-parameter-types>...) macro to be used at the beginning of a code block, and the INIT_PROC_ADDR(<function-name>) macro to call before using the declared function. The return value of the INIT_PROC_ADDR() call has to be checked; If it is NULL, the function was not found in the specified DLL. Example: DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW, LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); if (!INIT_PROC_ADDR(CreateHardLinkW)) return error("Could not find CreateHardLinkW() function"; if (!CreateHardLinkW(source, target, NULL)) return error("could not create hardlink from %S to %S", source, target); return 0; Signed-off-by: Karsten Blees <blees@dcon.de> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Sep 25, 2017 at 18:06 UTC db2f7c48cb30f8fdcb2933aa7d9890b34e0c4e94
1 file changed +57
compat/win32/lazyload.h new
+57
@@ -0,0 +1,57 @@
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 +struct proc_addr {
19 + const char *const dll;
20 + const char *const function;
21 + FARPROC pfunction;
22 + unsigned initialized : 1;
23 +};
24 +
25 +/* Declares a function to be loaded dynamically from a DLL. */
26 +#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \
27 + static struct proc_addr proc_addr_##function = \
28 + { #dll, #function, NULL, 0 }; \
29 + static rettype (WINAPI *function)(__VA_ARGS__)
30 +
31 +/*
32 + * Loads a function from a DLL (once-only).
33 + * Returns non-NULL function pointer on success.
34 + * Returns NULL + errno == ENOSYS on failure.
35 + * This function is not thread-safe.
36 + */
37 +#define INIT_PROC_ADDR(function) \
38 + (function = get_proc_addr(&proc_addr_##function))
39 +
40 +static inline void *get_proc_addr(struct proc_addr *proc)
41 +{
42 + /* only do this once */
43 + if (!proc->initialized) {
44 + HANDLE hnd;
45 + proc->initialized = 1;
46 + hnd = LoadLibraryExA(proc->dll, NULL,
47 + LOAD_LIBRARY_SEARCH_SYSTEM32);
48 + if (hnd)
49 + proc->pfunction = GetProcAddress(hnd, proc->function);
50 + }
51 + /* set ENOSYS if DLL or function was not found */
52 + if (!proc->pfunction)
53 + errno = ENOSYS;
54 + return proc->pfunction;
55 +}
56 +
57 +#endif