diff --git a/shell/browser/browser_win.cc b/shell/browser/browser_win.cc index 5e9d0ab2bff8..bd4faef48476 100644 --- a/shell/browser/browser_win.cc +++ b/shell/browser/browser_win.cc @@ -196,19 +196,30 @@ std::vector GetLoginItemSettingsHelper( const Browser::LoginItemSettings& options) { std::vector launch_items; - while (it->Valid()) { - base::string16 exe = options.path; - if (FormatCommandLineString(&exe, options.args)) { + base::FilePath lookup_exe_path; + if (options.path.empty()) { + base::string16 process_exe_path; + GetProcessExecPath(&process_exe_path); + lookup_exe_path = + base::CommandLine::FromString(process_exe_path).GetProgram(); + } else { + lookup_exe_path = base::CommandLine::FromString(options.path).GetProgram(); + } + + if (!lookup_exe_path.empty()) { + while (it->Valid()) { + base::CommandLine registry_launch_cmd = + base::CommandLine::FromString(it->Value()); + base::FilePath registry_launch_path = registry_launch_cmd.GetProgram(); + bool exe_match = base::FilePath::CompareEqualIgnoreCase( + lookup_exe_path.value(), registry_launch_path.value()); + // add launch item to vector if it has a matching path (case-insensitive) - if ((base::CompareCaseInsensitiveASCII(it->Value(), exe.c_str())) == 0) { + if (exe_match) { Browser::LaunchItem launch_item; - base::string16 launch_path = options.path; - if (launch_path.empty()) { - GetProcessExecPath(&launch_path); - } launch_item.name = it->Name(); - launch_item.path = launch_path; - launch_item.args = options.args; + launch_item.path = registry_launch_path.value(); + launch_item.args = registry_launch_cmd.GetArgs(); launch_item.scope = scope; launch_item.enabled = true; @@ -249,8 +260,8 @@ std::vector GetLoginItemSettingsHelper( reinterpret_cast(binary_accepted_alt)); std::string reg_startup_binary( reinterpret_cast(startup_binary)); - launch_item.enabled = (reg_binary == reg_startup_binary) || - (reg_binary == reg_binary_alt); + launch_item.enabled = (reg_startup_binary == reg_binary) || + (reg_startup_binary == reg_binary_alt); } } } @@ -259,8 +270,8 @@ std::vector GetLoginItemSettingsHelper( *executable_will_launch_at_login || launch_item.enabled; launch_items.push_back(launch_item); } + it->operator++(); } - it->operator++(); } return launch_items; } diff --git a/spec-main/api-app-spec.ts b/spec-main/api-app-spec.ts index 4e247c37acf0..10a54b64f2ad 100644 --- a/spec-main/api-app-spec.ts +++ b/spec-main/api-app-spec.ts @@ -604,6 +604,16 @@ describe('app module', () => { '--processStart', `"${path.basename(process.execPath)}"`, '--process-start-args', '"--hidden"' ]; + const regAddArgs = [ + 'ADD', + 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run', + '/v', + 'additionalEntry', + '/t', + 'REG_BINARY', + '/f', + '/d' + ]; before(function () { if (process.platform === 'linux' || process.mas) this.skip(); @@ -612,11 +622,13 @@ describe('app module', () => { beforeEach(() => { app.setLoginItemSettings({ openAtLogin: false }); app.setLoginItemSettings({ openAtLogin: false, path: updateExe, args: processStartArgs }); + app.setLoginItemSettings({ name: 'additionalEntry', openAtLogin: false }); }); afterEach(() => { app.setLoginItemSettings({ openAtLogin: false }); app.setLoginItemSettings({ openAtLogin: false, path: updateExe, args: processStartArgs }); + app.setLoginItemSettings({ name: 'additionalEntry', openAtLogin: false }); }); ifit(process.platform !== 'win32')('sets and returns the app as a login item', function () { @@ -631,7 +643,7 @@ describe('app module', () => { }); ifit(process.platform === 'win32')('sets and returns the app as a login item (windows)', function () { - app.setLoginItemSettings({ openAtLogin: true }); + app.setLoginItemSettings({ openAtLogin: true, enabled: true }); expect(app.getLoginItemSettings()).to.deep.equal({ openAtLogin: true, openAsHidden: false, @@ -647,6 +659,24 @@ describe('app module', () => { enabled: true }] }); + + app.setLoginItemSettings({ openAtLogin: false }); + app.setLoginItemSettings({ openAtLogin: true, enabled: false }); + expect(app.getLoginItemSettings()).to.deep.equal({ + openAtLogin: true, + openAsHidden: false, + wasOpenedAtLogin: false, + wasOpenedAsHidden: false, + restoreState: false, + executableWillLaunchAtLogin: false, + launchItems: [{ + name: 'electron.app.Electron', + path: process.execPath, + args: [], + scope: 'user', + enabled: false + }] + }); }); ifit(process.platform !== 'win32')('adds a login item that loads in hidden mode', function () { @@ -776,6 +806,117 @@ describe('app module', () => { }] }); }); + + ifit(process.platform === 'win32')('finds launch items independent of args', function () { + app.setLoginItemSettings({ openAtLogin: true, args: ['arg1'] }); + app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: false, args: ['arg2'] }); + expect(app.getLoginItemSettings()).to.deep.equal({ + openAtLogin: false, + openAsHidden: false, + wasOpenedAtLogin: false, + wasOpenedAsHidden: false, + restoreState: false, + executableWillLaunchAtLogin: true, + launchItems: [{ + name: 'additionalEntry', + path: process.execPath, + args: ['arg2'], + scope: 'user', + enabled: false + }, { + name: 'electron.app.Electron', + path: process.execPath, + args: ['arg1'], + scope: 'user', + enabled: true + }] + }); + }); + + ifit(process.platform === 'win32')('finds launch items independent of path quotation or casing', function () { + const expectation = { + openAtLogin: false, + openAsHidden: false, + wasOpenedAtLogin: false, + wasOpenedAsHidden: false, + restoreState: false, + executableWillLaunchAtLogin: true, + launchItems: [{ + name: 'additionalEntry', + path: 'C:\\electron\\myapp.exe', + args: ['arg1'], + scope: 'user', + enabled: true + }] + }; + + app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: true, path: 'C:\\electron\\myapp.exe', args: ['arg1'] }); + expect(app.getLoginItemSettings({ path: '"C:\\electron\\MYAPP.exe"' })).to.deep.equal(expectation); + + app.setLoginItemSettings({ openAtLogin: false, name: 'additionalEntry' }); + app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: true, path: '"C:\\electron\\MYAPP.exe"', args: ['arg1'] }); + expect(app.getLoginItemSettings({ path: 'C:\\electron\\myapp.exe' })).to.deep.equal({ + ...expectation, + launchItems: [ + { + name: 'additionalEntry', + path: 'C:\\electron\\MYAPP.exe', + args: ['arg1'], + scope: 'user', + enabled: true + } + ] + }); + }); + + ifit(process.platform === 'win32')('detects disabled by TaskManager', async function () { + app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: true, args: ['arg1'] }); + const appProcess = cp.spawn('reg', [...regAddArgs, '030000000000000000000000']); + await emittedOnce(appProcess, 'exit'); + expect(app.getLoginItemSettings()).to.deep.equal({ + openAtLogin: false, + openAsHidden: false, + wasOpenedAtLogin: false, + wasOpenedAsHidden: false, + restoreState: false, + executableWillLaunchAtLogin: false, + launchItems: [{ + name: 'additionalEntry', + path: process.execPath, + args: ['arg1'], + scope: 'user', + enabled: false + }] + }); + }); + + ifit(process.platform === 'win32')('detects enabled by TaskManager', async function () { + const expectation = { + openAtLogin: false, + openAsHidden: false, + wasOpenedAtLogin: false, + wasOpenedAsHidden: false, + restoreState: false, + executableWillLaunchAtLogin: true, + launchItems: [{ + name: 'additionalEntry', + path: process.execPath, + args: ['arg1'], + scope: 'user', + enabled: true + }] + }; + + app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: false, args: ['arg1'] }); + let appProcess = cp.spawn('reg', [...regAddArgs, '020000000000000000000000']); + await emittedOnce(appProcess, 'exit'); + expect(app.getLoginItemSettings()).to.deep.equal(expectation); + + app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: false, args: ['arg1'] }); + appProcess = cp.spawn('reg', [...regAddArgs, '000000000000000000000000']); + await emittedOnce(appProcess, 'exit'); + expect(app.getLoginItemSettings()).to.deep.equal(expectation); + }); }); ifdescribe(process.platform !== 'linux')('accessibilitySupportEnabled property', () => {