1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2016 - 2022, Steve Holme, <steve_holme@hotmail.com>.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * SPDX-License-Identifier: curl
23 ***************************************************************************/
25 #include "curl_setup.h"
29 #include <curl/curl.h>
30 #include "version_win32.h"
33 /* The last #include files should be: */
34 #include "curl_memory.h"
37 /* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
38 and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
39 struct OUR_OSVERSIONINFOEXW {
40 ULONG dwOSVersionInfoSize;
45 WCHAR szCSDVersion[128];
46 USHORT wServicePackMajor;
47 USHORT wServicePackMinor;
54 * curlx_verify_windows_version()
56 * This is used to verify if we are running on a specific windows version.
60 * majorVersion [in] - The major version number.
61 * minorVersion [in] - The minor version number.
62 * buildVersion [in] - The build version number. If 0, this parameter is
64 * platform [in] - The optional platform identifier.
65 * condition [in] - The test condition used to specifier whether we are
66 * checking a version less then, equal to or greater than
67 * what is specified in the major and minor version
70 * Returns TRUE if matched; otherwise FALSE.
72 bool curlx_verify_windows_version(const unsigned int majorVersion,
73 const unsigned int minorVersion,
74 const unsigned int buildVersion,
75 const PlatformIdentifier platform,
76 const VersionCondition condition)
80 #if defined(CURL_WINDOWS_APP)
83 /* We have no way to determine the Windows version from Windows apps,
84 so let's assume we're running on the target Windows version. */
85 const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
86 const WORD targetVersion = (WORD)_WIN32_WINNT;
89 case VERSION_LESS_THAN:
90 matched = targetVersion < fullVersion;
93 case VERSION_LESS_THAN_EQUAL:
94 matched = targetVersion <= fullVersion;
98 matched = targetVersion == fullVersion;
101 case VERSION_GREATER_THAN_EQUAL:
102 matched = targetVersion >= fullVersion;
105 case VERSION_GREATER_THAN:
106 matched = targetVersion > fullVersion;
110 if(matched && (platform == PLATFORM_WINDOWS)) {
111 /* we're always running on PLATFORM_WINNT */
114 #elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
115 (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
118 memset(&osver, 0, sizeof(osver));
119 osver.dwOSVersionInfoSize = sizeof(osver);
121 /* Find out Windows version */
122 if(GetVersionEx(&osver)) {
123 /* Verify the Operating System version number */
125 case VERSION_LESS_THAN:
126 if(osver.dwMajorVersion < majorVersion ||
127 (osver.dwMajorVersion == majorVersion &&
128 osver.dwMinorVersion < minorVersion) ||
129 (buildVersion != 0 &&
130 (osver.dwMajorVersion == majorVersion &&
131 osver.dwMinorVersion == minorVersion &&
132 osver.dwBuildNumber < buildVersion)))
136 case VERSION_LESS_THAN_EQUAL:
137 if(osver.dwMajorVersion < majorVersion ||
138 (osver.dwMajorVersion == majorVersion &&
139 osver.dwMinorVersion < minorVersion) ||
140 (osver.dwMajorVersion == majorVersion &&
141 osver.dwMinorVersion == minorVersion &&
142 (buildVersion == 0 ||
143 osver.dwBuildNumber <= buildVersion)))
148 if(osver.dwMajorVersion == majorVersion &&
149 osver.dwMinorVersion == minorVersion &&
150 (buildVersion == 0 ||
151 osver.dwBuildNumber == buildVersion))
155 case VERSION_GREATER_THAN_EQUAL:
156 if(osver.dwMajorVersion > majorVersion ||
157 (osver.dwMajorVersion == majorVersion &&
158 osver.dwMinorVersion > minorVersion) ||
159 (osver.dwMajorVersion == majorVersion &&
160 osver.dwMinorVersion == minorVersion &&
161 (buildVersion == 0 ||
162 osver.dwBuildNumber >= buildVersion)))
166 case VERSION_GREATER_THAN:
167 if(osver.dwMajorVersion > majorVersion ||
168 (osver.dwMajorVersion == majorVersion &&
169 osver.dwMinorVersion > minorVersion) ||
170 (buildVersion != 0 &&
171 (osver.dwMajorVersion == majorVersion &&
172 osver.dwMinorVersion == minorVersion &&
173 osver.dwBuildNumber > buildVersion)))
178 /* Verify the platform identifier (if necessary) */
181 case PLATFORM_WINDOWS:
182 if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
187 if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
191 default: /* like platform == PLATFORM_DONT_CARE */
198 struct OUR_OSVERSIONINFOEXW osver;
202 BYTE spMajorCondition;
203 BYTE spMinorCondition;
204 DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
205 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
207 typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
208 (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
209 static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
210 static bool onetime = true; /* safe because first call is during init */
213 pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
214 (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
219 case VERSION_LESS_THAN:
220 majorCondition = VER_LESS;
221 minorCondition = VER_LESS;
222 buildCondition = VER_LESS;
223 spMajorCondition = VER_LESS_EQUAL;
224 spMinorCondition = VER_LESS_EQUAL;
227 case VERSION_LESS_THAN_EQUAL:
228 majorCondition = VER_LESS_EQUAL;
229 minorCondition = VER_LESS_EQUAL;
230 buildCondition = VER_LESS_EQUAL;
231 spMajorCondition = VER_LESS_EQUAL;
232 spMinorCondition = VER_LESS_EQUAL;
236 majorCondition = VER_EQUAL;
237 minorCondition = VER_EQUAL;
238 buildCondition = VER_EQUAL;
239 spMajorCondition = VER_GREATER_EQUAL;
240 spMinorCondition = VER_GREATER_EQUAL;
243 case VERSION_GREATER_THAN_EQUAL:
244 majorCondition = VER_GREATER_EQUAL;
245 minorCondition = VER_GREATER_EQUAL;
246 buildCondition = VER_GREATER_EQUAL;
247 spMajorCondition = VER_GREATER_EQUAL;
248 spMinorCondition = VER_GREATER_EQUAL;
251 case VERSION_GREATER_THAN:
252 majorCondition = VER_GREATER;
253 minorCondition = VER_GREATER;
254 buildCondition = VER_GREATER;
255 spMajorCondition = VER_GREATER_EQUAL;
256 spMinorCondition = VER_GREATER_EQUAL;
263 memset(&osver, 0, sizeof(osver));
264 osver.dwOSVersionInfoSize = sizeof(osver);
265 osver.dwMajorVersion = majorVersion;
266 osver.dwMinorVersion = minorVersion;
267 osver.dwBuildNumber = buildVersion;
268 if(platform == PLATFORM_WINDOWS)
269 osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
270 else if(platform == PLATFORM_WINNT)
271 osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
273 cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
274 cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
275 cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
276 cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
278 if(platform != PLATFORM_DONT_CARE) {
279 cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
280 dwTypeMask |= VER_PLATFORMID;
283 /* Later versions of Windows have version functions that may not return the
284 real version of Windows unless the application is so manifested. We prefer
285 the real version always, so we use the Rtl variant of the function when
286 possible. Note though the function signatures have underlying fundamental
287 types that are the same, the return values are different. */
288 if(pRtlVerifyVersionInfo)
289 matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
291 matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm);
293 /* Compare the build number separately. VerifyVersionInfo normally compares
294 major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not
295 do the same for build (eg 1.9 build 222 is not less than 2.0 build 111).
296 Build comparison is only needed when build numbers are equal (eg 1.9 is
297 always less than 2.0 so build comparison is not needed). */
298 if(matched && buildVersion &&
299 (condition == VERSION_EQUAL ||
300 ((condition == VERSION_GREATER_THAN_EQUAL ||
301 condition == VERSION_LESS_THAN_EQUAL) &&
302 curlx_verify_windows_version(majorVersion, minorVersion, 0,
303 platform, VERSION_EQUAL)))) {
305 cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
306 dwTypeMask = VER_BUILDNUMBER;
307 if(pRtlVerifyVersionInfo)
308 matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
310 matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,