ohmu
·
2026-10-15
1#include "os.h"
2#include "common/strutil.h"
3#include "common/windows/registry.h"
4#include "common/windows/unicode.h"
5
6#include <windows.h>
7
8PWSTR WINAPI BrandingFormatString(PCWSTR format);
9
10static bool getCodeName(FFOSResult* os) {
11 FF_AUTO_CLOSE_FD HANDLE hKey = nullptr;
12 if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, nullptr)) {
13 return false;
14 }
15
16 if (!ffRegReadStrbuf(hKey, L"DisplayVersion", &os->codename, nullptr)) {
17 if (!ffRegReadStrbuf(hKey, L"CSDVersion", &os->codename, nullptr)) { // For Windows 7 and Windows 8
18 if (!ffRegReadStrbuf(hKey, L"ReleaseId", &os->codename, nullptr)) { // For old Windows 10
19 return false;
20 }
21 }
22 }
23
24 return true;
25}
26
27void ffDetectOSImpl(FFOSResult* os) {
28 // https://dennisbabkin.com/blog/?t=how-to-tell-the-real-version-of-windows-your-app-is-running-on#ver_string
29
30 // Reads a single branding field from winbrand.dll. The buffer is allocated with
31 // GlobalAlloc(GMEM_ZEROINIT) by winbrand, so it is ours to release.
32 //
33 // Fields offered by winbrand.dll (enumerated in basebrd.dll's RES_METADATA resource):
34 // %WINDOWS_GENERIC% the OS family, independent of edition and release ("Windows")
35 // %WINDOWS_SHORT% family + release, but hardcoded to "Windows 10" since Windows 10
36 // %WINDOWS_LONG% "<family> <release> <edition> [...]" ("Windows 11 Pro Insider Preview")
37 // %WINDOWS_PRODUCT% the product of the running edition
38 // %WINDOWS_COPYRIGHT%, %MICROSOFT_COMPANYNAME%, %MICROSOFT_ACCOUNT(S)%
39 // There is deliberately no field for the bare release number: basebrd.dll stores it
40 // inside the same per-edition resource as the rest of %WINDOWS_LONG%
41 // ("Windows 11 Pro%1%2"), so the release can only be peeled off that string.
42 const wchar_t* rawName = BrandingFormatString(L"%WINDOWS_LONG%");
43 ffStrbufSetWS(&os->variant, rawName);
44 GlobalFree((HGLOBAL) rawName);
45 ffStrbufSet(&os->prettyName, &os->variant);
46 ffStrbufTrimRight(&os->variant, ' ');
47
48 // WMI returns the "Microsoft" prefix while BrandingFormatString doesn't. Make them consistent.
49 if (ffStrbufStartsWithS(&os->variant, "Microsoft ")) {
50 ffStrbufSubstrAfter(&os->variant, strlen("Microsoft ") - 1);
51 }
52
53 if (os->variant.length == 0) // Windows PE?
54 {
55 FF_AUTO_CLOSE_FD HANDLE hKey = nullptr;
56 if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, nullptr)) {
57 ffRegReadStrbuf(hKey, L"ProductName", &os->variant, nullptr);
58 }
59 }
60
61 ffStrbufSet(&os->prettyName, &os->variant);
62
63 if (ffStrbufStartsWithS(&os->variant, "Windows ")) {
64 ffStrbufAppendS(&os->name, "Windows");
65
66 ffStrbufSubstrAfter(&os->variant, strlen("Windows ") - 1);
67
68 if (ffStrbufStartsWithS(&os->variant, "Server ")) {
69 ffStrbufAppendS(&os->name, " Server");
70 ffStrbufSubstrAfter(&os->variant, strlen(" Server") - 1);
71 } else if (ffStrbufStartsWithS(&os->variant, "Embedded ")) {
72 ffStrbufAppendS(&os->name, " Embedded");
73 ffStrbufSubstrAfter(&os->variant, strlen(" Embedded") - 1);
74 }
75
76 if (ffStrbufStartsWithIgnCaseS(&os->variant, "(TM) ")) {
77 ffStrbufSubstrAfter(&os->variant, strlen(" (TM)") - 1);
78 }
79
80 uint32_t index = ffStrbufFirstIndexC(&os->variant, ' ');
81 ffStrbufAppendNS(&os->version, index, os->variant.chars);
82 ffStrbufSubstrAfter(&os->variant, index);
83
84 // Windows Server 20xx Rx
85 if (ffStrbufEndsWithC(&os->name, 'r')) {
86 if (os->variant.chars[0] == 'R' &&
87 ffCharIsDigit(os->variant.chars[1]) &&
88 (os->variant.chars[2] == '\0' || os->variant.chars[2] == ' ')) {
89 ffStrbufAppendF(&os->version, " R%c", os->variant.chars[1]);
90 ffStrbufSubstrAfter(&os->variant, strlen("Rx ") - 1);
91 }
92 }
93 } else {
94 // Unknown Windows name, please report this
95 ffStrbufAppend(&os->name, &os->variant);
96 ffStrbufClear(&os->variant);
97 }
98
99 ffStrbufAppendF(&os->id, "%s %s", os->name.chars, os->version.chars);
100 ffStrbufSetStatic(&os->idLike, "Windows");
101
102 if (getCodeName(os) && os->codename.length > 0) {
103 ffStrbufAppendF(&os->prettyName, " (%s)", os->codename.chars);
104 }
105}