Skip to content

Commit

Permalink
fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
georgexu99 authored and MarshallOfSound committed Jul 28, 2020
1 parent 38fafe4 commit 7c33881
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 15 deletions.
11 changes: 10 additions & 1 deletion docs/api/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,13 @@ Returns `Object`:
should restore the state from the previous session. This indicates that the
app should restore the windows that were open the last time the app was
closed. This setting is not available on [MAS builds][mas-builds].
* `executableWillLaunchAtLogin` Boolean _Windows_ - `true` if app is set to open at login and its run key is not deactivated. This differs from `openAtLogin` as it ignores the `args` option, this property will be true if the given executable would be launched at login with **any** arguments.
* `launchItems` Object[] _Windows_
* `name` String _Windows_ - name value of a registry entry.
* `path` String _Windows_ - The executable to an app that corresponds to a registry entry.
* `args` String[] _Windows_ - the command-line arguments to pass to the executable.
* `scope` String _Windows_ - one of `user` or `machine`. Indicates whether the registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`.
* `enabled` Boolean _Windows_ - `true` if the app registry key is startup approved and therfore shows as `enabled` in Task Manager and Windows settings.

### `app.setLoginItemSettings(settings)` _macOS_ _Windows_

Expand All @@ -1231,7 +1238,9 @@ Returns `Object`:
* `args` String[] (optional) _Windows_ - The command-line arguments to pass to
the executable. Defaults to an empty array. Take care to wrap paths in
quotes.

* `enabled` Boolean (optional) _Windows_ - `true` will change the startup approved registry key and `enable / disable` the App in Task Manager and Windows Settings.
Defaults to `true`.
* `name` String (optional) _Windows_ - value name to write into registry. Defaults to the app's AppUserModelId().
Set the app's login item settings.

To work with Electron's `autoUpdater` on Windows, which uses [Squirrel][Squirrel-Windows],
Expand Down
40 changes: 40 additions & 0 deletions shell/browser/api/electron_api_app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,37 @@ struct Converter<JumpListResult> {
};
#endif

#if defined(OS_WIN)
template <>
struct Converter<Browser::LaunchItem> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
Browser::LaunchItem* out) {
gin_helper::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;

dict.Get("name", &(out->name));
dict.Get("path", &(out->path));
dict.Get("args", &(out->args));
dict.Get("scope", &(out->scope));
dict.Get("enabled", &(out->enabled));
return true;
}

static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
Browser::LaunchItem val) {
gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(isolate);
dict.Set("name", val.name);
dict.Set("path", val.path);
dict.Set("args", val.args);
dict.Set("scope", val.scope);
dict.Set("enabled", val.enabled);
return dict.GetHandle();
}
};
#endif

template <>
struct Converter<Browser::LoginItemSettings> {
static bool FromV8(v8::Isolate* isolate,
Expand All @@ -347,6 +378,10 @@ struct Converter<Browser::LoginItemSettings> {
dict.Get("openAsHidden", &(out->open_as_hidden));
dict.Get("path", &(out->path));
dict.Get("args", &(out->args));
#if defined(OS_WIN)
dict.Get("enabled", &(out->enabled));
dict.Get("name", &(out->name));
#endif
return true;
}

Expand All @@ -358,6 +393,11 @@ struct Converter<Browser::LoginItemSettings> {
dict.Set("restoreState", val.restore_state);
dict.Set("wasOpenedAtLogin", val.opened_at_login);
dict.Set("wasOpenedAsHidden", val.opened_as_hidden);
#if defined(OS_WIN)
dict.Set("launchItems", val.launch_items);
dict.Set("executableWillLaunchAtLogin",
val.executable_will_launch_at_login);
#endif
return dict.GetHandle();
}
};
Expand Down
6 changes: 6 additions & 0 deletions shell/browser/browser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ void RunQuitClosure(base::OnceClosure quit) {

} // namespace

#if defined(OS_WIN)
Browser::LaunchItem::LaunchItem() = default;
Browser::LaunchItem::~LaunchItem() = default;
Browser::LaunchItem::LaunchItem(const LaunchItem& other) = default;
#endif

Browser::LoginItemSettings::LoginItemSettings() = default;
Browser::LoginItemSettings::~LoginItemSettings() = default;
Browser::LoginItemSettings::LoginItemSettings(const LoginItemSettings& other) =
Expand Down
21 changes: 21 additions & 0 deletions shell/browser/browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,20 @@ class Browser : public WindowListObserver {
bool SetBadgeCount(int count);
int GetBadgeCount();

#if defined(OS_WIN)
struct LaunchItem {
base::string16 name;
base::string16 path;
base::string16 scope;
std::vector<base::string16> args;
bool enabled = true;

LaunchItem();
~LaunchItem();
LaunchItem(const LaunchItem&);
};
#endif

// Set/Get the login item settings of the app
struct LoginItemSettings {
bool open_at_login = false;
Expand All @@ -120,6 +134,13 @@ class Browser : public WindowListObserver {
base::string16 path;
std::vector<base::string16> args;

#if defined(OS_WIN)
bool enabled = true;
bool executable_will_launch_at_login = false;
std::vector<LaunchItem> launch_items;
base::string16 name = base::string16();
#endif

LoginItemSettings();
~LoginItemSettings();
LoginItemSettings(const LoginItemSettings&);
Expand Down
142 changes: 138 additions & 4 deletions shell/browser/browser_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "base/base_paths.h"
#include "base/file_version_info.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
Expand Down Expand Up @@ -180,6 +181,87 @@ bool FormatCommandLineString(base::string16* exe,
return true;
}

// Helper for GetLoginItemSettings().
// iterates over all the entries in a windows registry path and returns
// a list of launchItem with matching paths to our application.
// if a launchItem with a matching path also has a matching entry within the
// startup_approved_key_path, set executable_will_launch_at_login to be `true`
std::vector<Browser::LaunchItem> GetLoginItemSettingsHelper(
base::win::RegistryValueIterator* it,
boolean* executable_will_launch_at_login,
base::string16 scope,
const Browser::LoginItemSettings& options) {
std::vector<Browser::LaunchItem> launch_items;

while (it->Valid()) {
base::string16 exe = options.path;
if (FormatCommandLineString(&exe, options.args)) {
// add launch item to vector if it has a matching path (case-insensitive)
if ((base::CompareCaseInsensitiveASCII(it->Value(), exe.c_str())) == 0) {
Browser::LaunchItem launch_item;
base::string16 launch_path = options.path;
if (!(launch_path.size() > 0)) {
GetProcessExecPath(&launch_path);
}
launch_item.name = it->Name();
launch_item.path = launch_path;
launch_item.args = options.args;
launch_item.scope = scope;
launch_item.enabled = true;

// attempt to update launch_item.enabled if there is a matching key
// value entry in the StartupApproved registry
HKEY hkey;
// StartupApproved registry path
LPCTSTR path = TEXT(
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApp"
"roved\\Run");
LONG res;
if (scope == L"user") {
res =
RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_QUERY_VALUE, &hkey);
} else {
res =
RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_QUERY_VALUE, &hkey);
}
if (res == ERROR_SUCCESS) {
DWORD type, size;
wchar_t startup_binary[12];
LONG result =
RegQueryValueEx(hkey, it->Name(), nullptr, &type,
reinterpret_cast<BYTE*>(&startup_binary),
&(size = sizeof(startup_binary)));
if (result == ERROR_SUCCESS) {
if (type == REG_BINARY) {
// any other binary other than this indicates that the program is
// not set to launch at login
wchar_t binary_accepted[12] = {0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
wchar_t binary_accepted_alt[12] = {0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
std::string reg_binary(reinterpret_cast<char*>(binary_accepted));
std::string reg_binary_alt(
reinterpret_cast<char*>(binary_accepted_alt));
std::string reg_startup_binary(
reinterpret_cast<char*>(startup_binary));
launch_item.enabled = (reg_binary == reg_startup_binary) ||
(reg_binary == reg_binary_alt);
}
}
}

*executable_will_launch_at_login =
*executable_will_launch_at_login || launch_item.enabled;
launch_items.push_back(launch_item);
}
}
it->operator++();
}
return launch_items;
}

std::unique_ptr<FileVersionInfo> FetchFileVersionInfo() {
base::FilePath path;

Expand Down Expand Up @@ -512,16 +594,46 @@ bool Browser::SetBadgeCount(int count) {
}

void Browser::SetLoginItemSettings(LoginItemSettings settings) {
base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
base::string16 key_path =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
base::win::RegKey key(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS);

base::string16 startup_approved_key_path =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved"
L"\\Run";
base::win::RegKey startup_approved_key(
HKEY_CURRENT_USER, startup_approved_key_path.c_str(), KEY_ALL_ACCESS);
PCWSTR key_name =
settings.name.size() > 0 ? settings.name.c_str() : GetAppUserModelID();

if (settings.open_at_login) {
base::string16 exe = settings.path;
if (FormatCommandLineString(&exe, settings.args)) {
key.WriteValue(GetAppUserModelID(), exe.c_str());
key.WriteValue(key_name, exe.c_str());

if (settings.enabled) {
startup_approved_key.DeleteValue(key_name);
} else {
HKEY hard_key;
LPCTSTR path = TEXT(
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApp"
"roved\\Run");
LONG res =
RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_ALL_ACCESS, &hard_key);

if (res == ERROR_SUCCESS) {
UCHAR disable_startup_binary[] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
RegSetValueEx(hard_key, key_name, 0, REG_BINARY,
reinterpret_cast<const BYTE*>(disable_startup_binary),
sizeof(disable_startup_binary));
}
}
}
} else {
key.DeleteValue(GetAppUserModelID());
// if open at login is false, delete both values
startup_approved_key.DeleteValue(key_name);
key.DeleteValue(key_name);
}
}

Expand All @@ -532,13 +644,35 @@ Browser::LoginItemSettings Browser::GetLoginItemSettings(
base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
base::string16 keyVal;

// keep old openAtLogin behaviour
if (!FAILED(key.ReadValue(GetAppUserModelID(), &keyVal))) {
base::string16 exe = options.path;
if (FormatCommandLineString(&exe, options.args)) {
settings.open_at_login = keyVal == exe;
}
}

// iterate over current user and machine registries and populate launch items
// if there exists a launch entry with property enabled=='true',
// set executable_will_launch_at_login to 'true'.
boolean executable_will_launch_at_login = false;
std::vector<Browser::LaunchItem> launch_items;
base::win::RegistryValueIterator hkcu_iterator(HKEY_CURRENT_USER,
keyPath.c_str());
base::win::RegistryValueIterator hklm_iterator(HKEY_LOCAL_MACHINE,
keyPath.c_str());

launch_items = GetLoginItemSettingsHelper(
&hkcu_iterator, &executable_will_launch_at_login, L"user", options);
std::vector<Browser::LaunchItem> launch_items_hklm =
GetLoginItemSettingsHelper(&hklm_iterator,
&executable_will_launch_at_login, L"machine",
options);
launch_items.insert(launch_items.end(), launch_items_hklm.begin(),
launch_items_hklm.end());

settings.executable_will_launch_at_login = executable_will_launch_at_login;
settings.launch_items = launch_items;
return settings;
}

Expand Down

0 comments on commit 7c33881

Please sign in to comment.