OSDN Git Service

Implement a generic legacy platform support infrastructure.
[mingw/mingw-org-wsl.git] / w32api / lib / availapi.c
1 /*
2  * availapi.c
3  *
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
6  * versions of Windows.
7  *
8  * $Id$
9  *
10  * Written by Keith Marshall <keith@users.osdn.me>
11  * Copyright (C) 2021, MinGW.org Project
12  *
13  *
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:
20  *
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
23  * Software.
24  *
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.
32  *
33  *
34  * Compile this module multiple times, once for each entry-point resolver
35  * which is required; the specifics of the resolver are determined thus:
36  *
37  *   $ gcc -c -D_bound availapi.c -o bound.o
38  *
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:
42  *
43  *   $ gcc -c -D_unbound availapi.c -o unbound.o
44  *
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:
48  *
49  *   $ gcc -c -D_lib=DLLNAME [-D_bound] availapi.c -o dllentry.o
50  *
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().
59  *
60  */
61 #include "legacy.h"
62
63 #if defined _lib
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):
72  *
73  *        Alias     DLL Name
74  *        --------  -------- */
75 # define  k32entry  kernel32
76
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:
80  */
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
85
86 /* Implement the appropriately named entry-point resolver function...
87  */
88 void *_entry_point(_lib) (void *hook, const char *procname)
89 # if defined _bound
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)...
93    */
94   return __bound_dll_entry_point( hook, _dll(_lib), procname );
95 }
96 # else
97 { /* ...or otherwise, for a DLL which MAY need to be explicitly
98    * loaded, on demand.
99    */
100   return __unbound_dll_entry_point( hook, _dll(_lib), procname );
101 }
102 # endif
103 #elif defined _bound
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.
107  */
108 void *__bound_dll_entry_point
109 ( void *hook, const char *dllname, const char *procname )
110 {
111   /* If the passed entry-point hook has already been assigned, then
112    * there is nothing more to do, other than to return it...
113    */
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.
119      */
120     HMODULE dll = GetModuleHandleA( dllname );
121     hook = (dll == NULL) ? GetProcAddress( dll, procname ) : API_UNSUPPORTED;
122   }
123   /* In any case, we return the (possibly updated) hook, which should
124    * then be recorded by the caller.
125    */
126   return hook;
127 }
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.
132  */
133 void *__unbound_dll_entry_point
134 ( void *hook, const char *dllname, const char *procname )
135 {
136   /* If the passed entry-point hook has already been assigned, then
137    * there is nothing more to do, other than to return it...
138    */
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...
143      */
144     HMODULE dll = GetModuleHandleA( dllname );
145     if( (dll == NULL) && ((dll = LoadLibraryA( dllname )) == NULL) )
146       /*
147        * ...marking the hook as permanently unsupported, in the
148        * event of failure to map the DLL...
149        */
150       return hook = API_UNSUPPORTED;
151
152     /* ...otherwise, updating it to reflect the lookup result.
153      */
154     hook = GetProcAddress( dll, procname );
155   }
156   /* In any case, we return the (possibly updated) hook, which should
157    * then be recorded by the caller.
158    */
159   return hook;
160 }
161 #else
162 /* None of the mandatory -D_spec arguments have been specified; we need
163  * at least one of...
164  */
165 # error "A -D_lib=DLLNAME, -D_bound, or -D_unbound argument is required."
166 #endif
167
168 /* $RCSfile$: end of file */