Ver Fonte

libobs: Find windows version

This uses three methods of obtaining the actual windows version,
RtlGetVersion which is the ntdll version of GetVersionEx that bypasses
the manifest check garbage, looking up the file version of a file that
is most likely to be updated per windows version (ntoskrnl), and the
registry.  Of the three values, it chooses the highest windows version
obtained by the three.

Closes obsproject/obs-studio#2294
jp9000 há 5 anos atrás
pai
commit
de3de2a217
1 ficheiros alterados com 114 adições e 22 exclusões
  1. 114 22
      libobs/util/platform-windows.c

+ 114 - 22
libobs/util/platform-windows.c

@@ -31,6 +31,8 @@
 
 #include "../../deps/w32-pthreads/pthread.h"
 
+#define MAX_SZ_LEN 256
+
 static bool have_clockfreq = false;
 static LARGE_INTEGER clock_freq;
 static uint32_t winver = 0;
@@ -857,6 +859,108 @@ void get_reg_dword(HKEY hkey, LPCWSTR sub_key, LPCWSTR value_name,
 
 #define WINVER_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
 
+static inline void rtl_get_ver(struct win_version_info *ver)
+{
+	RTL_OSVERSIONINFOEXW osver = {0};
+	HMODULE ntdll = GetModuleHandleW(L"ntdll");
+	NTSTATUS s;
+
+	NTSTATUS(WINAPI * get_ver)
+	(RTL_OSVERSIONINFOEXW *) =
+		(void *)GetProcAddress(ntdll, "RtlGetVersion");
+	if (!get_ver) {
+		return;
+	}
+
+	osver.dwOSVersionInfoSize = sizeof(osver);
+	s = get_ver(&osver);
+	if (s < 0) {
+		return;
+	}
+
+	ver->major = osver.dwMajorVersion;
+	ver->minor = osver.dwMinorVersion;
+	ver->build = osver.dwBuildNumber;
+	ver->revis = 0;
+}
+
+static inline bool get_reg_sz(HKEY key, const wchar_t *val, wchar_t *buf,
+			      const size_t size)
+{
+	DWORD dwsize = (DWORD)size;
+	LSTATUS status;
+
+	status = RegQueryValueExW(key, val, NULL, NULL, (LPBYTE)buf, &dwsize);
+	buf[(size / sizeof(wchar_t)) - 1] = 0;
+	return status == ERROR_SUCCESS;
+}
+
+static inline void get_reg_ver(struct win_version_info *ver)
+{
+	HKEY key;
+	DWORD size, dw_val;
+	LSTATUS status;
+	wchar_t str[MAX_SZ_LEN];
+
+	status = RegOpenKeyW(HKEY_LOCAL_MACHINE, WINVER_REG_KEY, &key);
+	if (status != ERROR_SUCCESS)
+		return;
+
+	size = sizeof(dw_val);
+
+	status = RegQueryValueExW(key, L"CurrentMajorVersionNumber", NULL, NULL,
+				  (LPBYTE)&dw_val, &size);
+	if (status == ERROR_SUCCESS)
+		ver->major = (int)dw_val;
+
+	status = RegQueryValueExW(key, L"CurrentMinorVersionNumber", NULL, NULL,
+				  (LPBYTE)&dw_val, &size);
+	if (status == ERROR_SUCCESS)
+		ver->minor = (int)dw_val;
+
+	status = RegQueryValueExW(key, L"UBR", NULL, NULL, (LPBYTE)&dw_val,
+				  &size);
+	if (status == ERROR_SUCCESS)
+		ver->revis = (int)dw_val;
+
+	if (get_reg_sz(key, L"CurrentBuildNumber", str, sizeof(str))) {
+		ver->build = wcstol(str, NULL, 10);
+	}
+
+	RegCloseKey(key);
+}
+
+static inline bool version_higher(struct win_version_info *cur,
+				  struct win_version_info *new)
+{
+	if (new->major > cur->major) {
+		return true;
+	}
+
+	if (new->major == cur->major) {
+		if (new->minor > cur->minor) {
+			return true;
+		}
+		if (new->minor == cur->minor) {
+			if (new->build > cur->build) {
+				return true;
+			}
+			if (new->build == cur->build) {
+				return new->revis > cur->revis;
+			}
+		}
+	}
+
+	return false;
+}
+
+static inline void use_higher_ver(struct win_version_info *cur,
+				  struct win_version_info *new)
+{
+	if (version_higher(cur, new))
+		*cur = *new;
+}
+
 void get_win_ver(struct win_version_info *info)
 {
 	static struct win_version_info ver = {0};
@@ -866,31 +970,19 @@ void get_win_ver(struct win_version_info *info)
 		return;
 
 	if (!got_version) {
-		get_dll_ver(L"kernel32", &ver);
-		got_version = true;
-
-		if (ver.major == 10) {
-			HKEY key;
-			DWORD size, win10_revision;
-			LSTATUS status;
+		struct win_version_info reg_ver = {0};
+		struct win_version_info rtl_ver = {0};
+		struct win_version_info nto_ver = {0};
 
-			status = RegOpenKeyW(HKEY_LOCAL_MACHINE, WINVER_REG_KEY,
-					     &key);
-			if (status != ERROR_SUCCESS)
-				return;
+		get_reg_ver(&reg_ver);
+		rtl_get_ver(&rtl_ver);
+		get_dll_ver(L"ntoskrnl.exe", &nto_ver);
 
-			size = sizeof(win10_revision);
+		ver = reg_ver;
+		use_higher_ver(&ver, &rtl_ver);
+		use_higher_ver(&ver, &nto_ver);
 
-			status = RegQueryValueExW(key, L"UBR", NULL, NULL,
-						  (LPBYTE)&win10_revision,
-						  &size);
-			if (status == ERROR_SUCCESS)
-				ver.revis = (int)win10_revision > ver.revis
-						    ? (int)win10_revision
-						    : ver.revis;
-
-			RegCloseKey(key);
-		}
+		got_version = true;
 	}
 
 	*info = ver;