|
7 | 7 |
|
8 | 8 | #include "bin/platform.h"
|
9 | 9 |
|
| 10 | +#include <comdef.h> |
10 | 11 | #include <crtdbg.h>
|
| 12 | +#include <wbemidl.h> |
| 13 | +#include <wrl/client.h> |
| 14 | +#undef interface |
| 15 | +#include <string> |
11 | 16 |
|
12 | 17 | #include "bin/console.h"
|
13 | 18 | #include "bin/file.h"
|
|
20 | 25 | #include "bin/utils.h"
|
21 | 26 | #include "bin/utils_win.h"
|
22 | 27 |
|
| 28 | +#pragma comment(lib, "wbemuuid.lib") |
| 29 | + |
| 30 | +using Microsoft::WRL::ComPtr; |
| 31 | + |
23 | 32 | namespace dart {
|
24 | 33 | namespace bin {
|
25 | 34 |
|
@@ -110,6 +119,18 @@ class PlatformWin {
|
110 | 119 | DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformWin);
|
111 | 120 | };
|
112 | 121 |
|
| 122 | +class CoInitializeScope : public ValueObject { |
| 123 | + public: |
| 124 | + CoInitializeScope() { hres = CoInitializeEx(0, COINIT_MULTITHREADED); } |
| 125 | + |
| 126 | + ~CoInitializeScope() { CoUninitialize(); } |
| 127 | + |
| 128 | + bool IsInitialized() const { return !FAILED(hres); } |
| 129 | + |
| 130 | + private: |
| 131 | + HRESULT hres; |
| 132 | +}; |
| 133 | + |
113 | 134 | bool Platform::Initialize() {
|
114 | 135 | PlatformWin::InitOnce();
|
115 | 136 | return true;
|
@@ -166,10 +187,87 @@ static const char* VersionNumber() {
|
166 | 187 | return DartUtils::ScopedCStringFormatted("%d.%d", major, minor);
|
167 | 188 | }
|
168 | 189 |
|
| 190 | +static const char* GetEdition() { |
| 191 | + HRESULT hres; |
| 192 | + |
| 193 | + CoInitializeScope co_initialize_scope; |
| 194 | + if (!co_initialize_scope.IsInitialized()) { |
| 195 | + return nullptr; |
| 196 | + } |
| 197 | + |
| 198 | + hres = CoInitializeSecurity( |
| 199 | + nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, |
| 200 | + RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr); |
| 201 | + if (FAILED(hres)) { |
| 202 | + return nullptr; |
| 203 | + } |
| 204 | + |
| 205 | + ComPtr<IWbemLocator> locator; |
| 206 | + hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, |
| 207 | + IID_PPV_ARGS(&locator)); |
| 208 | + if (FAILED(hres)) { |
| 209 | + return nullptr; |
| 210 | + } |
| 211 | + |
| 212 | + ComPtr<IWbemServices> service; |
| 213 | + hres = locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, 0, |
| 214 | + NULL, 0, 0, &service); |
| 215 | + if (FAILED(hres)) { |
| 216 | + return nullptr; |
| 217 | + } |
| 218 | + |
| 219 | + hres = CoSetProxyBlanket(service.Get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, |
| 220 | + nullptr, RPC_C_AUTHN_LEVEL_CALL, |
| 221 | + RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE); |
| 222 | + if (FAILED(hres)) { |
| 223 | + return nullptr; |
| 224 | + } |
| 225 | + |
| 226 | + ComPtr<IEnumWbemClassObject> enumerator; |
| 227 | + hres = service->ExecQuery( |
| 228 | + bstr_t("WQL"), bstr_t("SELECT * FROM Win32_OperatingSystem"), |
| 229 | + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, |
| 230 | + &enumerator); |
| 231 | + if (FAILED(hres)) { |
| 232 | + return nullptr; |
| 233 | + } |
| 234 | + |
| 235 | + ComPtr<IWbemClassObject> query_results; |
| 236 | + ULONG uReturn = 0; |
| 237 | + if (FAILED(hres) || enumerator == nullptr) { |
| 238 | + return nullptr; |
| 239 | + } |
| 240 | + |
| 241 | + hres = enumerator->Next(WBEM_INFINITE, 1, &query_results, &uReturn); |
| 242 | + if (FAILED(hres)) { |
| 243 | + return nullptr; |
| 244 | + } |
| 245 | + |
| 246 | + VARIANT caption; |
| 247 | + hres = query_results->Get(L"Caption", 0, &caption, 0, 0); |
| 248 | + if (FAILED(hres)) { |
| 249 | + return nullptr; |
| 250 | + } |
| 251 | + |
| 252 | + // We got an edition, skip Microsoft prefix and convert to UTF8. |
| 253 | + wchar_t* edition = caption.bstrVal; |
| 254 | + static const wchar_t kMicrosoftPrefix[] = L"Microsoft "; |
| 255 | + static constexpr size_t kMicrosoftPrefixLen = |
| 256 | + ARRAY_SIZE(kMicrosoftPrefix) - 1; |
| 257 | + if (wcsncmp(edition, kMicrosoftPrefix, kMicrosoftPrefixLen) == 0) { |
| 258 | + edition += kMicrosoftPrefixLen; |
| 259 | + } |
| 260 | + |
| 261 | + char* result = StringUtilsWin::WideToUtf8(edition); |
| 262 | + VariantClear(&caption); |
| 263 | + return result; |
| 264 | +} |
| 265 | + |
169 | 266 | const char* Platform::OperatingSystemVersion() {
|
170 |
| - // Get the product name, e.g. "Windows 10 Home". |
171 |
| - const char* name; |
172 |
| - if (!GetCurrentVersionString(L"ProductName", &name)) { |
| 267 | + // Get the product name, e.g. "Windows 11 Home" via WMI and fallback to the |
| 268 | + // ProductName on error. |
| 269 | + const char* name = GetEdition(); |
| 270 | + if (name == nullptr && !GetCurrentVersionString(L"ProductName", &name)) { |
173 | 271 | return nullptr;
|
174 | 272 | }
|
175 | 273 |
|
|
0 commit comments