The MinGW.org Windows System Libraries
修订版 | 475f0b6dd1ccc2714a75aa2a36a73c95e73c15c0 (tree) |
---|---|
时间 | 2021-05-26 00:06:58 |
作者 | Keith Marshall <keith@user...> |
Commiter | Keith Marshall |
Add "legacy-safe" emulation of Microsoft's version helpers API.
@@ -1,5 +1,21 @@ | ||
1 | 1 | 2021-05-25 Keith Marshall <keith@users.osdn.me> |
2 | 2 | |
3 | + Add "legacy-safe" emulation of Microsoft's version helpers API. | |
4 | + | |
5 | + * include/versionhelpers.h: New file; it defines the API, as specified | |
6 | + in Microsoft's official "Version Helper" on-line documentation. | |
7 | + | |
8 | + * lib/osvercmp.c: New file; it implements... | |
9 | + (__mingw_osver_at_least, __mingw_osver_server): ...these "legacy-safe" | |
10 | + helper functions; deployed as regular object modules, included in... | |
11 | + (libkernel32.a): ...this W32API import library, they wrap calls to... | |
12 | + (VerSetConditionMask, VerifyVersionInfoA): ...these KERNEL32.DLL | |
13 | + functions, forwarding calls only if supported. | |
14 | + | |
15 | + * Makefile.in (kernel32.a): Add osvercmp.$OBJEXT dependency. | |
16 | + | |
17 | +2021-05-25 Keith Marshall <keith@users.osdn.me> | |
18 | + | |
3 | 19 | Correct an entry-point look-up logic defect. |
4 | 20 | |
5 | 21 | * lib/availapi.c (__bound_dll_entry_point) [dll == NULL]: Should be... |
@@ -125,7 +125,7 @@ lib%.a: %.def | ||
125 | 125 | $(if $(filter-out $<,$^),$(AR) $(ARFLAGS) $@ $(filter-out $<,$^)) |
126 | 126 | |
127 | 127 | vpath %.c ${srcdir}/lib |
128 | -libkernel32.a: k32entry.$(OBJEXT) bound.$(OBJEXT) | |
128 | +libkernel32.a: $(addsuffix .$(OBJEXT),k32entry bound osvercmp) | |
129 | 129 | |
130 | 130 | NO_ALIGN_FLAGS := -fno-align-jumps -fno-align-functions |
131 | 131 | bound.$(OBJEXT) unbound.$(OBJEXT): %.$(OBJEXT): availapi.c |
@@ -0,0 +1,103 @@ | ||
1 | +/* | |
2 | + * versionhelpers.h | |
3 | + * | |
4 | + * A MinGW emulation of the API implementation, first provided by Microsoft | |
5 | + * as a component of the Windows-8.1 software development kit, with addition | |
6 | + * of fail-safe support for use on legacy Windows versions. | |
7 | + * | |
8 | + * Note that use of the APIs, declared herein, is NOT recommended; usually, | |
9 | + * there are better ways to check for availablity of specific features, than | |
10 | + * to blindly rely on OS version number comparisons. | |
11 | + * | |
12 | + * | |
13 | + * $Id$ | |
14 | + * | |
15 | + * Written by Keith Marshall <keith@users.osdn.me> | |
16 | + * Copyright (C) 2021, MinGW.org Project | |
17 | + * | |
18 | + * | |
19 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
20 | + * copy of this software and associated documentation files (the "Software"), | |
21 | + * to deal in the Software without restriction, including without limitation | |
22 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
23 | + * and/or sell copies of the Software, and to permit persons to whom the | |
24 | + * Software is furnished to do so, subject to the following conditions: | |
25 | + * | |
26 | + * The above copyright notice and this permission notice (including the next | |
27 | + * paragraph) shall be included in all copies or substantial portions of the | |
28 | + * Software. | |
29 | + * | |
30 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
31 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
32 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
33 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
34 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
35 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
36 | + * DEALINGS IN THE SOFTWARE. | |
37 | + * | |
38 | + */ | |
39 | +#ifndef _VERSIONHELPERS_H | |
40 | +#define _VERSIONHELPERS_H | |
41 | +#pragma GCC system_header | |
42 | + | |
43 | +#include <windef.h> | |
44 | + | |
45 | +_BEGIN_C_DECLS | |
46 | + | |
47 | +/* These API declarations have been written from scratch, without reference, | |
48 | + * in any way, to the original Microsoft implementation. Although Microsoft | |
49 | + * did not provide their implementation until publication of the Win-8.1 SDK, | |
50 | + * it is understood, from their public documentation, that the underlying API | |
51 | + * has been available since Win-2K, and that the Win-8.1 SDK implementation | |
52 | + * is backward-compatible with all Win-NT versions since then; however, it | |
53 | + * is not clear how fail-safe it may be, should a dependent application be | |
54 | + * deployed on Win-9x, Win-NT4, or earlier. | |
55 | + * | |
56 | + * To address this uncertainty, this MinGW implementation is based on the | |
57 | + * following pair of wrapper functions, provided in LIBMINGW32.A; these will | |
58 | + * delegate to the VerifyVersionInfo() API, after confirming that the host | |
59 | + * platform supports it, while exhibiting suitable fail-safe behaviour, in | |
60 | + * case it does not. | |
61 | + */ | |
62 | +BOOL __mingw_osver_at_least( DWORD, DWORD, DWORD ); | |
63 | +BOOL __mingw_osver_server( void ); | |
64 | + | |
65 | +/* The actual version helper APIs take the form of in-line functions. | |
66 | + */ | |
67 | +#define VERSIONHELPERAPI \ | |
68 | +static __inline__ __attribute__((__always_inline__)) BOOL | |
69 | + | |
70 | +/* This first pair of functions require distinct implementations... | |
71 | + */ | |
72 | +VERSIONHELPERAPI IsWindowsServer() | |
73 | +{ return __mingw_osver_server(); } | |
74 | + | |
75 | +VERSIONHELPERAPI | |
76 | +IsWindowsVersionOrGreater( WORD __major, WORD __minor, WORD __sp ) | |
77 | +{ return __mingw_osver_at_least( __major, __minor, __sp ); } | |
78 | + | |
79 | +/* ...while the remainder are sufficiently generic to lend themselves to | |
80 | + * instantiation by use of a common convenience macro: | |
81 | + */ | |
82 | +#undef __mingw_generic_version_helper | |
83 | +#define __mingw_generic_version_helper( FUNCTION, M, N, S ) \ | |
84 | +VERSIONHELPERAPI FUNCTION( void ){ return __mingw_osver_at_least( M, N, S ); } | |
85 | + | |
86 | +__mingw_generic_version_helper( IsWindowsXPOrGreater, 5, 1, 0 ) | |
87 | +__mingw_generic_version_helper( IsWindowsXPSP1OrGreater, 5, 1, 1 ) | |
88 | +__mingw_generic_version_helper( IsWindowsXPSP2OrGreater, 5, 1, 2 ) | |
89 | +__mingw_generic_version_helper( IsWindowsXPSP3OrGreater, 5, 1, 3 ) | |
90 | +__mingw_generic_version_helper( IsWindowsVistaOrGreater, 6, 0, 0 ) | |
91 | +__mingw_generic_version_helper( IsWindowsVistaSP1OrGreater, 6, 0, 0 ) | |
92 | +__mingw_generic_version_helper( IsWindowsVistaSP2OrGreater, 6, 0, 2 ) | |
93 | +__mingw_generic_version_helper( IsWindows7OrGreater, 6, 1, 0 ) | |
94 | +__mingw_generic_version_helper( IsWindows7SP1OrGreater, 6, 1, 1 ) | |
95 | +__mingw_generic_version_helper( IsWindows8OrGreater, 6, 2, 0 ) | |
96 | +__mingw_generic_version_helper( IsWindows8Point1OrGreater, 6, 3, 0 ) | |
97 | +__mingw_generic_version_helper( IsWindows10OrGreater, 10, 0, 0 ) | |
98 | + | |
99 | +#undef __mingw_generic_version_helper | |
100 | + | |
101 | +_END_C_DECLS | |
102 | + | |
103 | +#endif /* !_VERSIONHELPERS_H: $RCSfile$: end of file */ |
@@ -0,0 +1,178 @@ | ||
1 | +/* | |
2 | + * osvercmp.c | |
3 | + * | |
4 | + * Implements a pair of wrappers for the WinAPI VerifyVersionInfo() API, | |
5 | + * to facilitate provision of support for a MinGW emulation of Microsoft's | |
6 | + * <versionhelpers.h>. Although Microsoft first provided this as part of | |
7 | + * the SDK for Windows-8.1, the underlying VerifyVersionInfo() API has | |
8 | + * been supported since Win2K; the wrappers, implemented herein, extend | |
9 | + * support to legacy platforms, providing fail-safe handling on earlier | |
10 | + * platforms, which lack the VerifyVersionInfo() API. | |
11 | + * | |
12 | + * | |
13 | + * $Id$ | |
14 | + * | |
15 | + * Written by Keith Marshall <keith@users.osdn.me> | |
16 | + * Copyright (C) 2021, MinGW.org Project | |
17 | + * | |
18 | + * | |
19 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
20 | + * copy of this software and associated documentation files (the "Software"), | |
21 | + * to deal in the Software without restriction, including without limitation | |
22 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
23 | + * and/or sell copies of the Software, and to permit persons to whom the | |
24 | + * Software is furnished to do so, subject to the following conditions: | |
25 | + * | |
26 | + * The above copyright notice and this permission notice (including the next | |
27 | + * paragraph) shall be included in all copies or substantial portions of the | |
28 | + * Software. | |
29 | + * | |
30 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
31 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
32 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
33 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
34 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
35 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
36 | + * DEALINGS IN THE SOFTWARE. | |
37 | + * | |
38 | + * | |
39 | + * Since the underlying VerifyVersionInfo() API was not introduced until | |
40 | + * Win-2K, and MinGW's WinAPI is nominally compiled with legacy version | |
41 | + * guarantees for Win-NT4 only, we must create a clean slate... | |
42 | + * | |
43 | + */ | |
44 | +#undef NTDDI_VERSION | |
45 | +#undef _WIN32_WINDOWS | |
46 | +#undef _WIN32_WINNT | |
47 | + | |
48 | +/* ...whence we may request exposure of, and access to, the necessary | |
49 | + * Win-2K API features; (note that this does not preclude use on earlier | |
50 | + * legacy platforms, since the implementation incorporates appropriate | |
51 | + * fail-safe handling). | |
52 | + */ | |
53 | +#define _WIN32_WINNT _WIN32_WINNT_WIN2K | |
54 | + | |
55 | +#include <winbase.h> | |
56 | +#include <versionhelpers.h> | |
57 | + | |
58 | +#include "legacy.h" | |
59 | + | |
60 | +/* We need a function pointer type definition, matching the signature of | |
61 | + * VerifyVersionInfo(), so that we may verify its availability, BEFORE we | |
62 | + * attempt to invoke it indirectly. | |
63 | + */ | |
64 | +typedef BOOL WINAPI (*validator_fn)( OSVERSIONINFOEXA *, DWORD, DWORDLONG ); | |
65 | + | |
66 | +static validator_fn __mingw_osver_comparator( void ) | |
67 | +{ | |
68 | + /* Internal helper function, to look up, and store, the entry point | |
69 | + * address of VerifyVersionInfo(), if it is available in KERNEL32.DLL; | |
70 | + * (note that this is a one-time initialization, within the lifetime | |
71 | + * of the calling process). | |
72 | + */ | |
73 | + static void *entry = API_UNCHECKED; | |
74 | + entry = __kernel32_entry_point( entry, "VerifyVersionInfoA" ); | |
75 | + return (validator_fn)(entry); | |
76 | +} | |
77 | + | |
78 | +/* For OS version comparisons, we need to inspect the major, and minor | |
79 | + * version numbers, both for the base OS, and any applied service packs... | |
80 | + */ | |
81 | +static const WORD __mingw_osver_mask = VER_MAJORVERSION | |
82 | +| VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; | |
83 | + | |
84 | +static DWORDLONG __mingw_osver_test( void ) | |
85 | +{ /* ...selecting the "greater-than-or-equal" comparison mode for each, | |
86 | + * in turn, as facilitated by this internal helper function; (note | |
87 | + * that, once again, this performs a one-time initialization of the | |
88 | + * comparison selector, for each item of version information). | |
89 | + */ | |
90 | + static DWORDLONG test = 0LL; | |
91 | + if( test == 0LL ) | |
92 | + { /* We need to initialize it, on this occasion; loop over the bits | |
93 | + * of the comparison selector mask, associating the appropriate | |
94 | + * comparison type with each which is set. | |
95 | + */ | |
96 | + for( DWORD mask = 1; mask < __mingw_osver_mask; mask <<= 1 ) | |
97 | + if( (mask & __mingw_osver_mask) != 0 ) | |
98 | + VER_SET_CONDITION( test, mask, VER_GREATER_EQUAL ); | |
99 | + } | |
100 | + return test; | |
101 | +} | |
102 | + | |
103 | +BOOL __mingw_osver_at_least( DWORD __major, DWORD __minor, DWORD __sp ) | |
104 | +{ | |
105 | + /* This is the public entry point, through which OS version number | |
106 | + * comparison requests may be directed to VerifyVersionInfo()... | |
107 | + */ | |
108 | + validator_fn chk; | |
109 | + if( (chk = __mingw_osver_comparator()) != (validator_fn)(API_UNSUPPORTED) ) | |
110 | + { | |
111 | + /* ...subject to initialization having established a valid entry | |
112 | + * point address, to which we pass the request via the pointer. | |
113 | + */ | |
114 | + OSVERSIONINFOEXA osinfo = | |
115 | + { sizeof osinfo, __major, __minor, 0, 0, "", __sp, 0, 0, 0, 0 }; | |
116 | + return chk( &osinfo, __mingw_osver_mask, __mingw_osver_test() ); | |
117 | + } | |
118 | + | |
119 | + /* If we get to here, initialization failed to identify a valid | |
120 | + * entry point address, for VerifyVersionInfo(); this represents | |
121 | + * the fail-safe handling, for legacy platforms. | |
122 | + */ | |
123 | + SetLastError( ERROR_OLD_WIN_VERSION ); | |
124 | + return FALSE; | |
125 | +} | |
126 | + | |
127 | +/* In the case of the server platform identification test, we again | |
128 | + * must perform an OS version check, but this must be augmented by a | |
129 | + * product type assessment... | |
130 | + */ | |
131 | +static const WORD __mingw_osplatform_mask = VER_PRODUCT_TYPE | |
132 | +| __mingw_osver_mask; | |
133 | + | |
134 | +static DWORDLONG __mingw_osplatform_test( void ) | |
135 | +{ /* ...for which (a copy of) the version number comparison selector | |
136 | + * must be augmented by addition of an equality comparator selector | |
137 | + * for the server product type identifier; (as previously, this is | |
138 | + * again established as a one-time initialization). | |
139 | + */ | |
140 | + static DWORDLONG test = 0LL; | |
141 | + if( test == 0LL ) | |
142 | + { /* We need to initialize it, on this occasion. | |
143 | + */ | |
144 | + test = __mingw_osver_test(); | |
145 | + VER_SET_CONDITION( test, VER_PRODUCT_TYPE, VER_EQUAL ); | |
146 | + } | |
147 | + return test; | |
148 | +} | |
149 | + | |
150 | +BOOL __mingw_osver_server( void ) | |
151 | +{ /* This alternative public entry point is specific to the server | |
152 | + * platform identification test; as in the preceding case of more | |
153 | + * generalized version number comparisons, this is also delegated | |
154 | + * to the VerifyVersionInfo() API, using the same entry point | |
155 | + * reference pointer... | |
156 | + */ | |
157 | + validator_fn chk; | |
158 | + if( (chk = __mingw_osver_comparator()) != (validator_fn)(API_UNSUPPORTED) ) | |
159 | + { | |
160 | + /* ...once again, subject to successful initialization; in this | |
161 | + * case, it is the server characterization property which is of | |
162 | + * primary interest, but we do also require an OS version which | |
163 | + * corresponds to Win-2K, or later. | |
164 | + */ | |
165 | + OSVERSIONINFOEXA osinfo = | |
166 | + { sizeof osinfo, 5, 0, 0, 0, "", 0, 0, 0, VER_NT_SERVER, 0 }; | |
167 | + return chk( &osinfo, __mingw_osplatform_mask, __mingw_osplatform_test() ); | |
168 | + } | |
169 | + | |
170 | + /* If we get to here, initialization failed to identify a valid | |
171 | + * entry point address, for VerifyVersionInfo(); this represents | |
172 | + * the fail-safe handling, for legacy platforms. | |
173 | + */ | |
174 | + SetLastError( ERROR_OLD_WIN_VERSION ); | |
175 | + return FALSE; | |
176 | +} | |
177 | + | |
178 | +/* $RCSfile$: end of file */ |