mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 16:32:18 +01:00 
			
		
		
		
	Merge branch 'improve-win32-version' into 'main'
gutils.c: Improve g_get_os_info() for Windows 10/Server 2008 R2+ Closes #2443 See merge request GNOME/glib!2351
This commit is contained in:
		| @@ -39,6 +39,7 @@ void g_console_win32_init (void); | ||||
| void g_clock_win32_init (void); | ||||
| void g_crash_handler_win32_init (void); | ||||
| void g_crash_handler_win32_deinit (void); | ||||
| gboolean _g_win32_call_rtl_version (OSVERSIONINFOEXW *info); | ||||
| extern HMODULE glib_dll; | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -1294,18 +1294,58 @@ static gchar * | ||||
| get_windows_version (gboolean with_windows) | ||||
| { | ||||
|   GString *version = g_string_new (NULL); | ||||
|   gboolean is_win_server = FALSE; | ||||
|  | ||||
|   if (g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_ANY)) | ||||
|     { | ||||
|       gchar *win10_release; | ||||
|       gboolean is_win11 = FALSE; | ||||
|       OSVERSIONINFOEXW osinfo; | ||||
|  | ||||
|       g_string_append (version, "10"); | ||||
|       /* Are we on Windows 2016/2019/2022 Server? */ | ||||
|       is_win_server = g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_SERVER); | ||||
|  | ||||
|       if (!g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_WORKSTATION)) | ||||
|         g_string_append (version, " Server"); | ||||
|       /* | ||||
|        * This always succeeds if we get here, since the | ||||
|        * g_win32_check_windows_version() already did this! | ||||
|        * We want the OSVERSIONINFOEXW here for more even | ||||
|        * fine-grained versioning items | ||||
|        */ | ||||
|       _g_win32_call_rtl_version (&osinfo); | ||||
|  | ||||
|       /* Windows 10 is identified by its release number, such as | ||||
|        * 1511, 1607, 1703, 1709, 1803, 1809 or 1903. | ||||
|       if (!is_win_server) | ||||
|         { | ||||
|           /* | ||||
|            * Windows 11 is actually Windows 10.0.22000+, | ||||
|            * so look at the build number | ||||
|            */ | ||||
|           is_win11 = (osinfo.dwBuildNumber >= 22000); | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           /* | ||||
|            * Windows 2022 Server is actually Windows 10.0.20348+, | ||||
|            * Windows 2019 Server is actually Windows 10.0.17763+, | ||||
|            * Windows 2016 Server is actually Windows 10.0.14393+, | ||||
|            * so look at the build number | ||||
|            */ | ||||
|           g_string_append (version, "Server"); | ||||
|           if (osinfo.dwBuildNumber >= 20348) | ||||
|             g_string_append (version, " 2022"); | ||||
|           else if (osinfo.dwBuildNumber >= 17763) | ||||
|             g_string_append (version, " 2019"); | ||||
|           else | ||||
|             g_string_append (version, " 2016"); | ||||
|         } | ||||
|  | ||||
|       if (is_win11) | ||||
|         g_string_append (version, "11"); | ||||
|       else if (!is_win_server) | ||||
|         g_string_append (version, "10"); | ||||
|  | ||||
|       /* Windows 10/Server 2016+ is identified by its ReleaseId or | ||||
|        * DisplayVersion (since 20H2), such as | ||||
|        * 1511, 1607, 1703, 1709, 1803, 1809 or 1903 etc. | ||||
|        * The first version of Windows 10 has no release number. | ||||
|        */ | ||||
|       win10_release = get_registry_str (HKEY_LOCAL_MACHINE, | ||||
| @@ -1316,7 +1356,26 @@ get_windows_version (gboolean with_windows) | ||||
|                                         L"ReleaseId"); | ||||
|  | ||||
|       if (win10_release != NULL) | ||||
|         g_string_append_printf (version, " %s", win10_release); | ||||
|         { | ||||
|           if (g_strcmp0 (win10_release, "2009") != 0) | ||||
|             g_string_append_printf (version, " %s", win10_release); | ||||
|           else | ||||
|             { | ||||
|               g_free (win10_release); | ||||
|  | ||||
|               win10_release = get_registry_str (HKEY_LOCAL_MACHINE, | ||||
|                                                 L"SOFTWARE" | ||||
|                                                 L"\\Microsoft" | ||||
|                                                 L"\\Windows NT" | ||||
|                                                 L"\\CurrentVersion", | ||||
|                                                 L"DisplayVersion"); | ||||
|  | ||||
|               if (win10_release != NULL) | ||||
|                 g_string_append_printf (version, " %s", win10_release); | ||||
|               else | ||||
|                 g_string_append_printf (version, " 2009"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|       g_free (win10_release); | ||||
|     } | ||||
| @@ -1324,10 +1383,10 @@ get_windows_version (gboolean with_windows) | ||||
|     { | ||||
|       gchar *win81_update; | ||||
|  | ||||
|       g_string_append (version, "8.1"); | ||||
|  | ||||
|       if (!g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_WORKSTATION)) | ||||
|         g_string_append (version, " Server"); | ||||
|       if (g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_WORKSTATION)) | ||||
|         g_string_append (version, "8.1"); | ||||
|       else | ||||
|         g_string_append (version, "Server 2012 R2"); | ||||
|  | ||||
|       win81_update = get_windows_8_1_update (); | ||||
|  | ||||
| @@ -1347,8 +1406,23 @@ get_windows_version (gboolean with_windows) | ||||
|  | ||||
|           g_string_append (version, versions[i].version); | ||||
|  | ||||
|           if (!g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_WORKSTATION)) | ||||
|             g_string_append (version, " Server"); | ||||
|           if (g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_SERVER)) | ||||
|             { | ||||
|               /* | ||||
|                * This condition should now always hold, since Windows | ||||
|                * 7+/Server 2008 R2+ is now required | ||||
|                */ | ||||
|               if (versions[i].major == 6) | ||||
|                 { | ||||
|                   g_string_append (version, "Server"); | ||||
|                   if (versions[i].minor == 2) | ||||
|                     g_string_append (version, " 2012"); | ||||
|                   else if (versions[i].minor == 1) | ||||
|                     g_string_append (version, " 2008 R2"); | ||||
|                   else | ||||
|                     g_string_append (version, " 2008"); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|           g_string_append (version, versions[i].spversion); | ||||
|         } | ||||
|   | ||||
| @@ -491,6 +491,48 @@ G_GNUC_END_IGNORE_DEPRECATIONS | ||||
|   return dirname; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * private API to call Windows's RtlGetVersion(), which may need to be called | ||||
|  * via GetProcAddress() | ||||
|  */ | ||||
| gboolean | ||||
| _g_win32_call_rtl_version (OSVERSIONINFOEXW *info) | ||||
| { | ||||
|   static OSVERSIONINFOEXW result; | ||||
|   static gsize inited = 0; | ||||
|  | ||||
|   g_return_val_if_fail (info != NULL, FALSE); | ||||
|  | ||||
|   if (g_once_init_enter (&inited)) | ||||
|     { | ||||
| #if WINAPI_FAMILY != MODERN_API_FAMILY | ||||
|       /* For non-modern UI Apps, use the LoadLibraryW()/GetProcAddress() thing */ | ||||
|       typedef NTSTATUS (WINAPI fRtlGetVersion) (PRTL_OSVERSIONINFOEXW); | ||||
|  | ||||
|       fRtlGetVersion *RtlGetVersion; | ||||
|       HMODULE hmodule = LoadLibraryW (L"ntdll.dll"); | ||||
|       g_return_val_if_fail (hmodule != NULL, FALSE); | ||||
|  | ||||
|       RtlGetVersion = (fRtlGetVersion *) GetProcAddress (hmodule, "RtlGetVersion"); | ||||
|       g_return_val_if_fail (RtlGetVersion != NULL, FALSE); | ||||
| #endif | ||||
|  | ||||
|       memset (&result, 0, sizeof (OSVERSIONINFOEXW)); | ||||
|       result.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW); | ||||
|  | ||||
|       RtlGetVersion (&result); | ||||
|  | ||||
| #if WINAPI_FAMILY != MODERN_API_FAMILY | ||||
|       FreeLibrary (hmodule); | ||||
| #endif | ||||
|       g_once_init_leave (&inited, TRUE); | ||||
|     } | ||||
|  | ||||
|   *info = result; | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * g_win32_check_windows_version: | ||||
|  * @major: major version of Windows | ||||
| @@ -526,31 +568,13 @@ g_win32_check_windows_version (const gint major, | ||||
|   gboolean is_ver_checked = FALSE; | ||||
|   gboolean is_type_checked = FALSE; | ||||
|  | ||||
| #if WINAPI_FAMILY != MODERN_API_FAMILY | ||||
|   /* For non-modern UI Apps, use the LoadLibraryW()/GetProcAddress() thing */ | ||||
|   typedef NTSTATUS (WINAPI fRtlGetVersion) (PRTL_OSVERSIONINFOEXW); | ||||
|  | ||||
|   fRtlGetVersion *RtlGetVersion; | ||||
|   HMODULE hmodule; | ||||
| #endif | ||||
|   /* We Only Support Checking for XP or later */ | ||||
|   g_return_val_if_fail (major >= 5 && (major <= 6 || major == 10), FALSE); | ||||
|   g_return_val_if_fail ((major >= 5 && minor >= 1) || major >= 6, FALSE); | ||||
|  | ||||
|   /* Check for Service Pack Version >= 0 */ | ||||
|   g_return_val_if_fail (spver >= 0, FALSE); | ||||
|  | ||||
| #if WINAPI_FAMILY != MODERN_API_FAMILY | ||||
|   hmodule = LoadLibraryW (L"ntdll.dll"); | ||||
|   g_return_val_if_fail (hmodule != NULL, FALSE); | ||||
|  | ||||
|   RtlGetVersion = (fRtlGetVersion *) GetProcAddress (hmodule, "RtlGetVersion"); | ||||
|   g_return_val_if_fail (RtlGetVersion != NULL, FALSE); | ||||
| #endif | ||||
|  | ||||
|   memset (&osverinfo, 0, sizeof (OSVERSIONINFOEXW)); | ||||
|   osverinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW); | ||||
|   RtlGetVersion (&osverinfo); | ||||
|   g_return_val_if_fail (_g_win32_call_rtl_version (&osverinfo), FALSE); | ||||
|  | ||||
|   /* check the OS and Service Pack Versions */ | ||||
|   if (osverinfo.dwMajorVersion > (DWORD) major) | ||||
| @@ -588,10 +612,6 @@ g_win32_check_windows_version (const gint major, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| #if WINAPI_FAMILY != MODERN_API_FAMILY | ||||
|   FreeLibrary (hmodule); | ||||
| #endif | ||||
|  | ||||
|   return is_ver_checked && is_type_checked; | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user