version_win32.c (8114B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Steve Holme, <steve_holme@hotmail.com>. 9 * 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. 13 * 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. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "../curl_setup.h" 26 27 #ifdef _WIN32 28 29 #include <curl/curl.h> 30 #include "version_win32.h" 31 #include "warnless.h" 32 33 /* The last 2 #include files should be in this order */ 34 #include "../curl_memory.h" 35 #include "../memdebug.h" 36 37 /* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW) 38 and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */ 39 struct OUR_OSVERSIONINFOEXW { 40 ULONG dwOSVersionInfoSize; 41 ULONG dwMajorVersion; 42 ULONG dwMinorVersion; 43 ULONG dwBuildNumber; 44 ULONG dwPlatformId; 45 WCHAR szCSDVersion[128]; 46 USHORT wServicePackMajor; 47 USHORT wServicePackMinor; 48 USHORT wSuiteMask; 49 UCHAR wProductType; 50 UCHAR wReserved; 51 }; 52 53 /* 54 * curlx_verify_windows_version() 55 * 56 * This is used to verify if we are running on a specific Windows version. 57 * 58 * Parameters: 59 * 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 63 * ignored. 64 * platform [in] - The optional platform identifier. 65 * condition [in] - The test condition used to specifier whether we are 66 * checking a version less than, equal to or greater than 67 * what is specified in the major and minor version 68 * numbers. 69 * 70 * Returns TRUE if matched; otherwise FALSE. 71 */ 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) 77 { 78 bool matched = FALSE; 79 80 #ifdef CURL_WINDOWS_UWP 81 /* We have no way to determine the Windows version from Windows apps, 82 so let's assume we are running on the target Windows version. */ 83 const WORD fullVersion = MAKEWORD(minorVersion, majorVersion); 84 const WORD targetVersion = (WORD)_WIN32_WINNT; 85 86 (void)buildVersion; 87 88 switch(condition) { 89 case VERSION_LESS_THAN: 90 matched = targetVersion < fullVersion; 91 break; 92 93 case VERSION_LESS_THAN_EQUAL: 94 matched = targetVersion <= fullVersion; 95 break; 96 97 case VERSION_EQUAL: 98 matched = targetVersion == fullVersion; 99 break; 100 101 case VERSION_GREATER_THAN_EQUAL: 102 matched = targetVersion >= fullVersion; 103 break; 104 105 case VERSION_GREATER_THAN: 106 matched = targetVersion > fullVersion; 107 break; 108 } 109 110 if(matched && (platform == PLATFORM_WINDOWS)) { 111 /* we are always running on PLATFORM_WINNT */ 112 matched = FALSE; 113 } 114 #elif defined(UNDER_CE) 115 (void)majorVersion; 116 (void)minorVersion; 117 (void)buildVersion; 118 (void)platform; 119 (void)condition; 120 #else 121 ULONGLONG cm = 0; 122 struct OUR_OSVERSIONINFOEXW osver; 123 BYTE majorCondition; 124 BYTE minorCondition; 125 BYTE buildCondition; 126 BYTE spMajorCondition; 127 BYTE spMinorCondition; 128 DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION | 129 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; 130 131 typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN) 132 (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG); 133 static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo; 134 static bool onetime = TRUE; /* safe because first call is during init */ 135 136 if(onetime) { 137 pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, 138 (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo"))); 139 onetime = FALSE; 140 } 141 142 switch(condition) { 143 case VERSION_LESS_THAN: 144 majorCondition = VER_LESS; 145 minorCondition = VER_LESS; 146 buildCondition = VER_LESS; 147 spMajorCondition = VER_LESS_EQUAL; 148 spMinorCondition = VER_LESS_EQUAL; 149 break; 150 151 case VERSION_LESS_THAN_EQUAL: 152 majorCondition = VER_LESS_EQUAL; 153 minorCondition = VER_LESS_EQUAL; 154 buildCondition = VER_LESS_EQUAL; 155 spMajorCondition = VER_LESS_EQUAL; 156 spMinorCondition = VER_LESS_EQUAL; 157 break; 158 159 case VERSION_EQUAL: 160 majorCondition = VER_EQUAL; 161 minorCondition = VER_EQUAL; 162 buildCondition = VER_EQUAL; 163 spMajorCondition = VER_GREATER_EQUAL; 164 spMinorCondition = VER_GREATER_EQUAL; 165 break; 166 167 case VERSION_GREATER_THAN_EQUAL: 168 majorCondition = VER_GREATER_EQUAL; 169 minorCondition = VER_GREATER_EQUAL; 170 buildCondition = VER_GREATER_EQUAL; 171 spMajorCondition = VER_GREATER_EQUAL; 172 spMinorCondition = VER_GREATER_EQUAL; 173 break; 174 175 case VERSION_GREATER_THAN: 176 majorCondition = VER_GREATER; 177 minorCondition = VER_GREATER; 178 buildCondition = VER_GREATER; 179 spMajorCondition = VER_GREATER_EQUAL; 180 spMinorCondition = VER_GREATER_EQUAL; 181 break; 182 183 default: 184 return FALSE; 185 } 186 187 memset(&osver, 0, sizeof(osver)); 188 osver.dwOSVersionInfoSize = sizeof(osver); 189 osver.dwMajorVersion = majorVersion; 190 osver.dwMinorVersion = minorVersion; 191 osver.dwBuildNumber = buildVersion; 192 if(platform == PLATFORM_WINDOWS) 193 osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; 194 else if(platform == PLATFORM_WINNT) 195 osver.dwPlatformId = VER_PLATFORM_WIN32_NT; 196 197 cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition); 198 cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition); 199 cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition); 200 cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition); 201 202 if(platform != PLATFORM_DONT_CARE) { 203 cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); 204 dwTypeMask |= VER_PLATFORMID; 205 } 206 207 /* Later versions of Windows have version functions that may not return the 208 real version of Windows unless the application is so manifested. We prefer 209 the real version always, so we use the Rtl variant of the function when 210 possible. Note though the function signatures have underlying fundamental 211 types that are the same, the return values are different. */ 212 if(pRtlVerifyVersionInfo) 213 matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); 214 else 215 matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm); 216 217 /* Compare the build number separately. VerifyVersionInfo normally compares 218 major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not 219 do the same for build (eg 1.9 build 222 is not less than 2.0 build 111). 220 Build comparison is only needed when build numbers are equal (eg 1.9 is 221 always less than 2.0 so build comparison is not needed). */ 222 if(matched && buildVersion && 223 (condition == VERSION_EQUAL || 224 ((condition == VERSION_GREATER_THAN_EQUAL || 225 condition == VERSION_LESS_THAN_EQUAL) && 226 curlx_verify_windows_version(majorVersion, minorVersion, 0, 227 platform, VERSION_EQUAL)))) { 228 229 cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition); 230 dwTypeMask = VER_BUILDNUMBER; 231 if(pRtlVerifyVersionInfo) 232 matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); 233 else 234 matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, 235 dwTypeMask, cm); 236 } 237 238 #endif 239 240 return matched; 241 } 242 243 #endif /* _WIN32 */