4 * Provides generic DLL entry-point lookup helper functions, to facilitate
5 * run-time linking of API functions which may not be supported in legacy
10 * Written by Keith Marshall <keith@users.osdn.me>
11 * Copyright (C) 2021, MinGW.org Project
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
21 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
34 * Compile this module multiple times, once for each entry-point resolver
35 * which is required; the specifics of the resolver are determined thus:
37 * $ gcc -c -D_bound availapi.c -o bound.o
39 * will create a generic resolver, named __bound_dll_entry_point(), which
40 * will resolve entry-points ONLY within DLLs which have been explicitly
41 * loaded beforehand. Conversely:
43 * $ gcc -c -D_unbound availapi.c -o unbound.o
45 * will create a generic resolver, named __unbound_dll_entry_point(); this
46 * will attempt to load a named DLL, if it is not already mapped, before it
47 * attempts to resolve a named entry-point within it. Finally:
49 * $ gcc -c -D_lib=DLLNAME [-D_bound] availapi.c -o dllentry.o
51 * will create a resolver specific to the DLL specified by DLLNAME, (the
52 * file-name only part of the DLL name, WITHOUT either the ".dll" suffix,
53 * or any preceding directory path qualification; this resolver will be
54 * named __DLLNAME_entry_point(). If the "-D_lib=DLLNAME" specification
55 * is accompanied by the optional "-D_bound" flag, this resolver will be
56 * implemented as a thin wrapper around __bound_dll_entry_point(); OTOH,
57 * if the "-D_bound" flag is not specified, it will be implemented as a
58 * thin wrapper around __unbound_dll_entry_point().
64 /* The entry-point resolver is to be associated with a specifically
65 * named DLL; define a set of mappings between preferred object file
66 * names (aliases), and their associated DLL names; (note that this
67 * facility is primarily provided to accommodate makefile mapping of
68 * resolver object file names to DLL names; the DLLNAME reference,
69 * within the command line "-D_lib=DLLNAME" specification, is given
70 * as the alias, but within the resolver FUNCTION name, it is ALWAYS
71 * set to match the "DLL Name" entry from the following table):
74 * -------- -------- */
75 # define k32entry kernel32
77 /* Provide a set of macros, to derive the entry-point resolver name,
78 * and its associated DLL name, from the command line assignment for
79 * the object file's base name:
81 # define _dll(_lib) _as_string(_lib) ".dll"
82 # define _entry(_lib) __##_lib##_entry_point
83 # define _entry_point(_lib) _entry(_lib)
84 # define _as_string(_name) #_name
86 /* Implement the appropriately named entry-point resolver function...
88 void *_entry_point(_lib) (void *hook, const char *procname)
90 { /* ...in terms of the appropiate resolver for a DLL which is
91 * expected to have been implicitly loaded, (i.e. explicitly
92 * bound to the executable, at link-time)...
94 return __bound_dll_entry_point( hook, _dll(_lib), procname );
97 { /* ...or otherwise, for a DLL which MAY need to be explicitly
100 return __unbound_dll_entry_point( hook, _dll(_lib), procname );
104 /* This entry-point resolver is to be generic, w.r.t. the DLL name
105 * with which it will be associated, but will require that the named
106 * DLL has been explicitly bound to the application, at link-time.
108 void *__bound_dll_entry_point
109 ( void *hook, const char *dllname, const char *procname )
111 /* If the passed entry-point hook has already been assigned, then
112 * there is nothing more to do, other than to return it...
114 if( hook == API_UNCHECKED )
115 { /* ...otherwise, we perform a DLL entry-point lookup, considering
116 * only DLLs which are already mapped into the address space of the
117 * calling process, and subsequently updating the hook to represent
118 * the entry-point, or mark it as permanently unsupported.
120 HMODULE dll = GetModuleHandleA( dllname );
121 hook = (dll == NULL) ? GetProcAddress( dll, procname ) : API_UNSUPPORTED;
123 /* In any case, we return the (possibly updated) hook, which should
124 * then be recorded by the caller.
128 #elif defined _unbound
129 /* This entry-point resolver performs a similar function to that above,
130 * except that it will attempt to explicitly load any named DLL which is
131 * not already mapped into the address space of the calling process.
133 void *__unbound_dll_entry_point
134 ( void *hook, const char *dllname, const char *procname )
136 /* If the passed entry-point hook has already been assigned, then
137 * there is nothing more to do, other than to return it...
139 if( hook == API_UNCHECKED )
140 { /* ...otherwise, we perform a DLL entry-point lookup, loading
141 * the named DLL, if it has not yet been mapped into the address
142 * space of the calling process...
144 HMODULE dll = GetModuleHandleA( dllname );
145 if( (dll == NULL) && ((dll = LoadLibraryA( dllname )) == NULL) )
147 * ...marking the hook as permanently unsupported, in the
148 * event of failure to map the DLL...
150 return hook = API_UNSUPPORTED;
152 /* ...otherwise, updating it to reflect the lookup result.
154 hook = GetProcAddress( dll, procname );
156 /* In any case, we return the (possibly updated) hook, which should
157 * then be recorded by the caller.
162 /* None of the mandatory -D_spec arguments have been specified; we need
165 # error "A -D_lib=DLLNAME, -D_bound, or -D_unbound argument is required."
168 /* $RCSfile$: end of file */