diff --git a/package-lock.json b/package-lock.json index 260c4aef67e..eb3f6db49ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "@vscode/vscode-languagedetection": "1.0.23", "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", - "@vscode/windows-registry": "^1.1.0", + "@vscode/windows-registry": "^1.2.0", "@xterm/addon-clipboard": "^0.3.0-beta.167", "@xterm/addon-image": "^0.10.0-beta.167", "@xterm/addon-ligatures": "^0.11.0-beta.167", @@ -3818,9 +3818,9 @@ } }, "node_modules/@vscode/windows-registry": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vscode/windows-registry/-/windows-registry-1.1.3.tgz", - "integrity": "sha512-si8+b+2Wh0x2X6W2+kgDyLJD9hyGIrjUo1X/7RWlvsxyI5+Pg+bpdHJrVYtIW4cHOPVB0FYFaN1UZndbUbU5lQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vscode/windows-registry/-/windows-registry-1.2.0.tgz", + "integrity": "sha512-IouvAGIIjPDKsLlBkdjVgfHrE+s4aESXzyQWwEPzbzHumKbCqIL5n54PNX0R4PHkYQlbinVrXn282KGSO4cr9A==", "hasInstallScript": true, "license": "MIT" }, diff --git a/package.json b/package.json index e5e265ac8c1..d82bf82e5de 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "@vscode/vscode-languagedetection": "1.0.23", "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", - "@vscode/windows-registry": "^1.1.0", + "@vscode/windows-registry": "^1.2.0", "@xterm/addon-clipboard": "^0.3.0-beta.167", "@xterm/addon-image": "^0.10.0-beta.167", "@xterm/addon-ligatures": "^0.11.0-beta.167", diff --git a/remote/package-lock.json b/remote/package-lock.json index 625b7143211..49b97cb47d0 100644 --- a/remote/package-lock.json +++ b/remote/package-lock.json @@ -21,7 +21,7 @@ "@vscode/tree-sitter-wasm": "^0.3.0", "@vscode/vscode-languagedetection": "1.0.23", "@vscode/windows-process-tree": "^0.6.0", - "@vscode/windows-registry": "^1.1.0", + "@vscode/windows-registry": "^1.2.0", "@xterm/addon-clipboard": "^0.3.0-beta.167", "@xterm/addon-image": "^0.10.0-beta.167", "@xterm/addon-ligatures": "^0.11.0-beta.167", @@ -571,9 +571,9 @@ } }, "node_modules/@vscode/windows-registry": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vscode/windows-registry/-/windows-registry-1.1.3.tgz", - "integrity": "sha512-si8+b+2Wh0x2X6W2+kgDyLJD9hyGIrjUo1X/7RWlvsxyI5+Pg+bpdHJrVYtIW4cHOPVB0FYFaN1UZndbUbU5lQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vscode/windows-registry/-/windows-registry-1.2.0.tgz", + "integrity": "sha512-IouvAGIIjPDKsLlBkdjVgfHrE+s4aESXzyQWwEPzbzHumKbCqIL5n54PNX0R4PHkYQlbinVrXn282KGSO4cr9A==", "hasInstallScript": true, "license": "MIT" }, diff --git a/remote/package.json b/remote/package.json index ecc25ae5590..2de8217e16d 100644 --- a/remote/package.json +++ b/remote/package.json @@ -16,7 +16,7 @@ "@vscode/tree-sitter-wasm": "^0.3.0", "@vscode/vscode-languagedetection": "1.0.23", "@vscode/windows-process-tree": "^0.6.0", - "@vscode/windows-registry": "^1.1.0", + "@vscode/windows-registry": "^1.2.0", "@xterm/addon-clipboard": "^0.3.0-beta.167", "@xterm/addon-image": "^0.10.0-beta.167", "@xterm/addon-ligatures": "^0.11.0-beta.167", diff --git a/src/vs/base/node/windowsVersion.ts b/src/vs/base/node/windowsVersion.ts new file mode 100644 index 00000000000..95dd8e78c47 --- /dev/null +++ b/src/vs/base/node/windowsVersion.ts @@ -0,0 +1,113 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as os from 'os'; +import { isWindows } from '../common/platform.js'; + +let versionInfo: { release: string; buildNumber: number } | undefined; + +/** + * Initializes the Windows version cache by reading from the registry. + * + * On Windows 8.1+, the `os.release()` function may return incorrect version numbers + * due to the deprecated GetVersionEx API returning compatibility-shimmed values + * when the application doesn't have a proper manifest. Reading from the registry + * gives us the real version. + * + * See: https://github.com/microsoft/vscode/issues/197444 + */ +export async function initWindowsVersionInfo() { + if (versionInfo) { + return; + } + + if (!isWindows) { + versionInfo = { release: os.release(), buildNumber: 0 }; + return; + } + + let buildNumber: number | undefined; + let release: string | undefined; + try { + const Registry = await import('@vscode/windows-registry'); + const versionKey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'; + + const build = Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', versionKey, 'CurrentBuild'); + if (build !== undefined) { + buildNumber = parseInt(build, 10); + if (isNaN(buildNumber)) { + buildNumber = undefined; + } + } + + const major = Registry.GetDWORDRegKey('HKEY_LOCAL_MACHINE', versionKey, 'CurrentMajorVersionNumber'); + const minor = Registry.GetDWORDRegKey('HKEY_LOCAL_MACHINE', versionKey, 'CurrentMinorVersionNumber'); + if (major !== undefined && minor !== undefined && build !== undefined) { + release = `${major}.${minor}.${build}`; + } + } catch { + // ignore + } finally { + versionInfo = { + release: release || os.release(), + buildNumber: buildNumber || getWindowsBuildNumberFromOsRelease() + }; + } +} + +/** + * Gets Windows version information from the registry. + * @returns The Windows version in Major.Minor.Build format (e.g., "10.0.19041") + */ +export async function getWindowsRelease(): Promise { + if (!versionInfo) { + await initWindowsVersionInfo(); + } + return versionInfo!.release; +} + +/** + * Gets the Windows build number from the registry. + * @returns The Windows build number (e.g., 19041 for Windows 10 2004) + */ +export async function getWindowsBuildNumberAsync(): Promise { + if (!versionInfo) { + await initWindowsVersionInfo(); + } + return versionInfo!.buildNumber; +} + +/** + * Synchronous version of getWindowsBuildNumberAsync(). + * @returns The Windows build number (e.g., 19041 for Windows 10 2004) + */ +export function getWindowsBuildNumberSync(): number { + if (versionInfo) { + return versionInfo.buildNumber; + } else { + return isWindows ? getWindowsBuildNumberFromOsRelease() : 0; + } +} + +/** + * Gets the cached Windows release string synchronously. + * Falls back to os.release() if the cache hasn't been initialized yet. + * @returns The Windows version in Major.Minor.Build format (e.g., "10.0.19041") + */ +export function getWindowsReleaseSync(): string { + return versionInfo?.release ?? os.release(); +} + +/** + * Parses the Windows build number from os.release(). + * This is used as a fallback when registry reading is not available. + */ +function getWindowsBuildNumberFromOsRelease(): number { + const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); + if (osVersion && osVersion.length === 4) { + return parseInt(osVersion[3], 10); + } + return 0; +} diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index eb7e0193373..82d80db5bdc 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -22,6 +22,7 @@ import { IProcessEnvironment, isLinux, isMacintosh, isWindows, OS } from '../../ import { cwd } from '../../base/common/process.js'; import { rtrim, trim } from '../../base/common/strings.js'; import { Promises as FSPromises } from '../../base/node/pfs.js'; +import { initWindowsVersionInfo } from '../../base/node/windowsVersion.js'; import { ProxyChannel } from '../../base/parts/ipc/common/ipc.js'; import { Client as NodeIPCClient } from '../../base/parts/ipc/common/ipc.net.js'; import { connect as nodeIPCConnect, serve as nodeIPCServe, Server as NodeIPCServer, XDG_RUNTIME_DIR } from '../../base/parts/ipc/node/ipc.net.js'; @@ -282,7 +283,10 @@ class CodeMain { stateService.init(), // Configuration service - configurationService.initialize() + configurationService.initialize(), + + // Accurate Windows version info. + isWindows ? initWindowsVersionInfo() : Promise.resolve() ]); // Initialize user data profiles after initializing the state diff --git a/src/vs/platform/remote/node/wsl.ts b/src/vs/platform/remote/node/wsl.ts index 12935846db9..60b96f3dd78 100644 --- a/src/vs/platform/remote/node/wsl.ts +++ b/src/vs/platform/remote/node/wsl.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as fs from 'fs'; -import * as os from 'os'; import * as cp from 'child_process'; import { join } from '../../../base/common/path.js'; +import { getWindowsBuildNumberAsync } from '../../../base/node/windowsVersion.js'; let hasWSLFeaturePromise: Promise | undefined; @@ -18,8 +18,8 @@ export async function hasWSLFeatureInstalled(refresh = false): Promise } async function testWSLFeatureInstalled(): Promise { - const windowsBuildNumber = getWindowsBuildNumber(); - if (windowsBuildNumber === undefined) { + const windowsBuildNumber = await getWindowsBuildNumberAsync(); + if (windowsBuildNumber === 0) { return false; } if (windowsBuildNumber >= 22000) { @@ -47,14 +47,6 @@ async function testWSLFeatureInstalled(): Promise { return false; } -function getWindowsBuildNumber(): number | undefined { - const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); - if (osVersion) { - return parseInt(osVersion[3]); - } - return undefined; -} - function getSystem32Path(subPath: string): string | undefined { const systemRoot = process.env['SystemRoot']; if (systemRoot) { diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index e73086df28c..2f8d40d6ac0 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -18,7 +18,7 @@ import { escapeNonWindowsPath } from '../common/terminalEnvironment.js'; import type { ISerializeOptions, SerializeAddon as XtermSerializeAddon } from '@xterm/addon-serialize'; import type { Unicode11Addon as XtermUnicode11Addon } from '@xterm/addon-unicode11'; import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs, ITerminalTabLayoutInfoDto } from '../common/terminalProcess.js'; -import { getWindowsBuildNumber, sanitizeEnvForLogging } from './terminalEnvironment.js'; +import { sanitizeEnvForLogging } from './terminalEnvironment.js'; import { TerminalProcess } from './terminalProcess.js'; import { localize } from '../../../nls.js'; import { ignoreProcessNames } from './childProcessMonitor.js'; @@ -33,6 +33,7 @@ import * as performance from '../../../base/common/performance.js'; import pkg from '@xterm/headless'; import { AutoRepliesPtyServiceContribution } from './terminalContrib/autoReplies/autoRepliesContribController.js'; import { hasKey, isFunction, isNumber, isString } from '../../../base/common/types.js'; +import { getWindowsBuildNumberAsync } from '../../../base/node/windowsVersion.js'; type XtermTerminal = pkg.Terminal; const { Terminal: XtermTerminal } = pkg; @@ -510,10 +511,10 @@ export class PtyService extends Disposable implements IPtyService { if (!isWindows) { return original; } - if (getWindowsBuildNumber() < 17063) { + if (await getWindowsBuildNumberAsync() < 17063) { return original.replace(/\\/g, '/'); } - const wslExecutable = this._getWSLExecutablePath(); + const wslExecutable = await this._getWSLExecutablePath(); if (!wslExecutable) { return original; } @@ -528,10 +529,10 @@ export class PtyService extends Disposable implements IPtyService { // The backend is Windows, for example a local Windows workspace with a wsl session in // the terminal. if (isWindows) { - if (getWindowsBuildNumber() < 17063) { + if (await getWindowsBuildNumberAsync() < 17063) { return original; } - const wslExecutable = this._getWSLExecutablePath(); + const wslExecutable = await this._getWSLExecutablePath(); if (!wslExecutable) { return original; } @@ -547,8 +548,8 @@ export class PtyService extends Disposable implements IPtyService { return original; } - private _getWSLExecutablePath(): string | undefined { - const useWSLexe = getWindowsBuildNumber() >= 16299; + private async _getWSLExecutablePath(): Promise { + const useWSLexe = await getWindowsBuildNumberAsync() >= 16299; const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); const systemRoot = process.env['SystemRoot']; if (systemRoot) { diff --git a/src/vs/platform/terminal/node/terminalEnvironment.ts b/src/vs/platform/terminal/node/terminalEnvironment.ts index 62a0c53bb88..5aa0a0dd13a 100644 --- a/src/vs/platform/terminal/node/terminalEnvironment.ts +++ b/src/vs/platform/terminal/node/terminalEnvironment.ts @@ -18,15 +18,7 @@ import { MergedEnvironmentVariableCollection } from '../common/environmentVariab import { chmod, realpathSync, mkdirSync } from 'fs'; import { promisify } from 'util'; import { isString, SingleOrMany } from '../../../base/common/types.js'; - -export function getWindowsBuildNumber(): number { - const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); - let buildNumber: number = 0; - if (osVersion && osVersion.length === 4) { - buildNumber = parseInt(osVersion[3]); - } - return buildNumber; -} +import { getWindowsBuildNumberAsync } from '../../../base/node/windowsVersion.js'; export interface IShellIntegrationConfigInjection { readonly type: 'injection'; @@ -83,7 +75,8 @@ export async function getShellIntegrationInjection( return { type: 'failure', reason: ShellIntegrationInjectionFailureReason.IgnoreShellIntegrationFlag }; } // Shell integration requires Windows 10 build 18309+ (ConPTY support) - if (isWindows && getWindowsBuildNumber() < 18309) { + const windowsBuildNumber = isWindows ? await getWindowsBuildNumberAsync() : 0; + if (isWindows && windowsBuildNumber < 18309) { return { type: 'failure', reason: ShellIntegrationInjectionFailureReason.UnsupportedWindowsBuild }; } @@ -103,7 +96,7 @@ export async function getShellIntegrationInjection( const scopedDownShellEnvs = ['PATH', 'VIRTUAL_ENV', 'HOME', 'SHELL', 'PWD']; if (shellLaunchConfig.shellIntegrationEnvironmentReporting) { if (isWindows) { - const enableWindowsEnvReporting = options.windowsUseConptyDll || getWindowsBuildNumber() >= 22631 && shell !== 'bash.exe'; + const enableWindowsEnvReporting = options.windowsUseConptyDll || windowsBuildNumber >= 22631 && shell !== 'bash.exe'; if (enableWindowsEnvReporting) { envMixin['VSCODE_SHELL_ENV_REPORTING'] = scopedDownShellEnvs.join(','); } diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index 1f49fa67daa..60563ff6487 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -17,10 +17,11 @@ import { ILogService, LogLevel } from '../../log/common/log.js'; import { IProductService } from '../../product/common/productService.js'; import { FlowControlConstants, IShellLaunchConfig, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap, ProcessPropertyType, TerminalShellType, IProcessReadyEvent, ITerminalProcessOptions, PosixShellType, IProcessReadyWindowsPty, GeneralShellType, ITerminalLaunchResult } from '../common/terminal.js'; import { ChildProcessMonitor } from './childProcessMonitor.js'; -import { getShellIntegrationInjection, getWindowsBuildNumber, IShellIntegrationConfigInjection, sanitizeEnvForLogging } from './terminalEnvironment.js'; +import { getShellIntegrationInjection, IShellIntegrationConfigInjection, sanitizeEnvForLogging } from './terminalEnvironment.js'; import { WindowsShellHelper } from './windowsShellHelper.js'; import { IPty, IPtyForkOptions, IWindowsPtyForkOptions, spawn } from 'node-pty'; import { isNumber } from '../../../base/common/types.js'; +import { getWindowsBuildNumberSync } from '../../../base/node/windowsVersion.js'; const enum ShutdownConstants { /** @@ -150,7 +151,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess this._initialCwd = cwd; this._properties[ProcessPropertyType.InitialCwd] = this._initialCwd; this._properties[ProcessPropertyType.Cwd] = this._initialCwd; - const useConpty = process.platform === 'win32' && getWindowsBuildNumber() >= 18309; + const useConpty = process.platform === 'win32' && getWindowsBuildNumberSync() >= 18309; const useConptyDll = useConpty && this._options.windowsUseConptyDll; this._ptyOptions = { name, @@ -625,7 +626,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess getWindowsPty(): IProcessReadyWindowsPty | undefined { return isWindows ? { backend: 'conpty', - buildNumber: getWindowsBuildNumber() + buildNumber: getWindowsBuildNumberSync() } : undefined; } } diff --git a/src/vs/platform/terminal/node/terminalProfiles.ts b/src/vs/platform/terminal/node/terminalProfiles.ts index ea98eb66fb0..e3198558e68 100644 --- a/src/vs/platform/terminal/node/terminalProfiles.ts +++ b/src/vs/platform/terminal/node/terminalProfiles.ts @@ -16,8 +16,8 @@ import { enumeratePowerShellInstallations } from '../../../base/node/powershell. import { IConfigurationService } from '../../configuration/common/configuration.js'; import { ILogService } from '../../log/common/log.js'; import { ITerminalEnvironment, ITerminalExecutable, ITerminalProfile, ITerminalProfileSource, ITerminalUnsafePath, ProfileSource, TerminalIcon, TerminalSettingId } from '../common/terminal.js'; -import { getWindowsBuildNumber } from './terminalEnvironment.js'; import { ThemeIcon } from '../../../base/common/themables.js'; +import { getWindowsBuildNumberAsync } from '../../../base/node/windowsVersion.js'; const enum Constants { UnixShellsPath = '/etc/shells' @@ -86,7 +86,7 @@ async function detectAvailableWindowsProfiles( // WSL 2 released in the May 2020 Update, this is where the `-d` flag was added that we depend // upon - const allowWslDiscovery = getWindowsBuildNumber() >= 19041; + const allowWslDiscovery = await getWindowsBuildNumberAsync() >= 19041; await initializeWindowsProfiles(testPwshSourcePaths); diff --git a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts index bb03a05958b..4b7ab9e50c7 100644 --- a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts @@ -10,7 +10,8 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/c import { NullLogService } from '../../../log/common/log.js'; import { IProductService } from '../../../product/common/productService.js'; import { ITerminalProcessOptions } from '../../common/terminal.js'; -import { getShellIntegrationInjection, getWindowsBuildNumber, IShellIntegrationConfigInjection, type IShellIntegrationInjectionFailure, sanitizeEnvForLogging } from '../../node/terminalEnvironment.js'; +import { getShellIntegrationInjection, IShellIntegrationConfigInjection, type IShellIntegrationInjectionFailure, sanitizeEnvForLogging } from '../../node/terminalEnvironment.js'; +import { getWindowsBuildNumberSync } from '../../../../base/node/windowsVersion.js'; const enabledProcessOptions: ITerminalProcessOptions = { shellIntegration: { enabled: true, suggestEnabled: false, nonce: '' }, windowsUseConptyDll: false, environmentVariableCollections: undefined, workspaceFolder: undefined, isScreenReaderOptimized: false }; const disabledProcessOptions: ITerminalProcessOptions = { shellIntegration: { enabled: false, suggestEnabled: false, nonce: '' }, windowsUseConptyDll: false, environmentVariableCollections: undefined, workspaceFolder: undefined, isScreenReaderOptimized: false }; @@ -32,14 +33,14 @@ suite('platform - terminalEnvironment', async () => { suite('getShellIntegrationInjection', async () => { suite('should not enable', async () => { // This test is only expected to work on Windows 10 build 18309 and above - (getWindowsBuildNumber() < 18309 ? test.skip : test)('when isFeatureTerminal or when no executable is provided', async () => { + (getWindowsBuildNumberSync() < 18309 ? test.skip : test)('when isFeatureTerminal or when no executable is provided', async () => { strictEqual((await getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, enabledProcessOptions, defaultEnvironment, logService, productService, true)).type, 'failure'); strictEqual((await getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: false }, enabledProcessOptions, defaultEnvironment, logService, productService, true)).type, 'injection'); }); }); // These tests are only expected to work on Windows 10 build 18309 and above - (getWindowsBuildNumber() < 18309 ? suite.skip : suite)('pwsh', async () => { + (getWindowsBuildNumberSync() < 18309 ? suite.skip : suite)('pwsh', async () => { const expectedPs1 = process.platform === 'win32' ? `try { . "${repoRoot}\\out\\vs\\workbench\\contrib\\terminal\\common\\scripts\\shellIntegration.ps1" } catch {}` : `. "${repoRoot}/out/vs/workbench/contrib/terminal/common/scripts/shellIntegration.ps1"`; diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index 05c4489758b..698d277ca28 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -7,7 +7,8 @@ import * as os from 'os'; import { IntervalTimer, timeout } from '../../../base/common/async.js'; import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js'; import { Emitter, Event } from '../../../base/common/event.js'; -import { isMacintosh } from '../../../base/common/platform.js'; +import { isMacintosh, isWindows } from '../../../base/common/platform.js'; +import { getWindowsReleaseSync } from '../../../base/node/windowsVersion.js'; import { IMeteredConnectionService } from '../../meteredConnection/common/meteredConnection.js'; import { IConfigurationService } from '../../configuration/common/configuration.js'; import { IEnvironmentMainService } from '../../environment/electron-main/environmentMainService.js'; @@ -32,10 +33,13 @@ export function createUpdateURL(baseUpdateUrl: string, platform: string, quality } /** - * Builds common headers for macOS update requests, including those issued + * Builds common headers for update requests, including those issued * via Electron's auto-updater (e.g. setFeedURL({ url, headers })) and - * manual HTTP requests that bypass the auto-updater. On macOS, this includes - * the Darwin kernel version which the update server uses for EOL detection. + * manual HTTP requests that bypass the auto-updater. The headers include + * OS version information which the update server uses for EOL detection. + * + * On macOS, the User-Agent includes the Darwin kernel version. + * On Windows, the User-Agent includes accurate Windows version from the registry. */ export function getUpdateRequestHeaders(productVersion: string): Record | undefined { if (isMacintosh) { @@ -45,6 +49,15 @@ export function getUpdateRequestHeaders(productVersion: string): Record(asJson) .then(update => { const updateType = getUpdateType(); @@ -362,7 +363,8 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun { detached: true, stdio: ['ignore', 'ignore', 'ignore'], - windowsVerbatimArguments: true + windowsVerbatimArguments: true, + env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' } } ); @@ -494,7 +496,8 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun } else { spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], { detached: true, - stdio: ['ignore', 'ignore', 'ignore'] + stdio: ['ignore', 'ignore', 'ignore'], + env: { ...process.env, __COMPAT_LAYER: 'RunAsInvoker' } }); } }