diff --git a/server/src/os/windows/registry.cpp b/server/src/os/windows/registry.cpp new file mode 100644 index 00000000..29469f25 --- /dev/null +++ b/server/src/os/windows/registry.cpp @@ -0,0 +1,97 @@ +/** + * server/src/os/windows/registry.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2022 Reinder Feenstra + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "registry.hpp" +#include +#include + +namespace Windows::Registry { + +const char* runKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; +//const char* runTraintasticServerKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\TraintasticServer"; +const char* startupApprovedKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run"; +const char* traintasticServerKey = "TraintasticServer"; +const WCHAR* traintasticServerKeyW = L"TraintasticServer"; +const DWORD startupEnabled = 2; +const DWORD startupDisabled = 3; + +bool addRun() +{ + bool success = false; + HKEY key; + LSTATUS r = RegOpenKeyExA(HKEY_CURRENT_USER, runKey, 0, KEY_WRITE, &key); + if(r == ERROR_SUCCESS) + { + std::basic_string path; + path.resize(MAX_PATH); + path[0] = '"'; + const DWORD l = GetModuleFileNameW(nullptr, path.data() + 1, path.size() - 1); + if(l > 0) + { + path.resize(1 + l); + path.append(L"\" --tray"); + + r = RegSetValueExW(key, traintasticServerKeyW, 0, REG_SZ, reinterpret_cast(path.c_str()), (path.size() + 1) * sizeof(WCHAR)); + success = (r == ERROR_SUCCESS); + } + RegCloseKey(key); + } + return success; +} + +bool getStartUpApproved(bool& enabled) +{ + bool success = false; + HKEY key; + LSTATUS r = RegOpenKeyExA(HKEY_CURRENT_USER, startupApprovedKey, 0, KEY_READ, &key); + if(r == ERROR_SUCCESS) + { + DWORD data[3]; + DWORD size = sizeof(data); + r = RegGetValueA(key, nullptr, traintasticServerKey, RRF_RT_REG_BINARY, nullptr, &data, &size); + if(r == ERROR_SUCCESS) + { + enabled = (data[0] == startupEnabled); + success = true; + } + RegCloseKey(key); + } + return success; +} + +bool setStartUpApproved(bool enabled) +{ + bool success = false; + HKEY key; + LSTATUS r = RegOpenKeyExA(HKEY_CURRENT_USER, startupApprovedKey, 0, KEY_WRITE, &key); + if(r == ERROR_SUCCESS) + { + DWORD data[3] = {enabled ? startupEnabled : startupDisabled, 0, 0}; + DWORD size = sizeof(data); + r = RegSetValueExA(key, traintasticServerKey, 0, REG_BINARY, reinterpret_cast(&data), size); + success = (r == ERROR_SUCCESS); + RegCloseKey(key); + } + return success; +} + +} diff --git a/server/src/os/windows/registry.hpp b/server/src/os/windows/registry.hpp new file mode 100644 index 00000000..884bbfc3 --- /dev/null +++ b/server/src/os/windows/registry.hpp @@ -0,0 +1,35 @@ +/** + * server/src/os/windows/registry.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2022 Reinder Feenstra + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TRAINTASTIC_SERVER_OS_WINDOWS_REGISTRY_HPP +#define TRAINTASTIC_SERVER_OS_WINDOWS_REGISTRY_HPP + +namespace Windows::Registry { + +bool addRun(); + +bool getStartUpApproved(bool& enabled); +bool setStartUpApproved(bool enabled); + +} + +#endif diff --git a/server/src/os/windows/trayicon.cpp b/server/src/os/windows/trayicon.cpp index c2ec836b..97e3c228 100644 --- a/server/src/os/windows/trayicon.cpp +++ b/server/src/os/windows/trayicon.cpp @@ -25,6 +25,7 @@ #include #include #include "consolewindow.hpp" +#include "registry.hpp" #include "../../core/eventloop.hpp" #include "../../traintastic/traintastic.hpp" #include "../../utils/setthreadname.hpp" @@ -79,9 +80,15 @@ void TrayIcon::run() menuAddItem(MenuItem::AllowClientServerRestart, "Allow client to restart server"); menuAddItem(MenuItem::AllowClientServerShutdown, "Allow client to shutdown server"); menuAddSeperator(); + menuAddItem(MenuItem::StartAutomaticallyAtLogon, "Start automatically at logon"); + menuAddSeperator(); menuAddItem(MenuItem::Restart, "Restart"); menuAddItem(MenuItem::Shutdown, "Shutdown"); + bool startUpApproved = false; + Registry::getStartUpApproved(startUpApproved); + menuSetItemChecked(MenuItem::StartAutomaticallyAtLogon, startUpApproved); + // setup tray icon: static NOTIFYICONDATA notifyIconData; memset(¬ifyIconData, 0, sizeof(notifyIconData)); @@ -206,6 +213,16 @@ LRESULT CALLBACK TrayIcon::windowProc(_In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARA }); break; } + case MenuItem::StartAutomaticallyAtLogon: + { + bool startUpApproved = !menuGetItemChecked(MenuItem::StartAutomaticallyAtLogon); + if(startUpApproved) + Registry::addRun(); + Registry::setStartUpApproved(startUpApproved); + if(Registry::getStartUpApproved(startUpApproved)) + menuSetItemChecked(MenuItem::StartAutomaticallyAtLogon, startUpApproved); + break; + } } break; @@ -245,6 +262,12 @@ void TrayIcon::menuAddSeperator() InsertMenuItem(s_menu, GetMenuItemCount(s_menu), TRUE, &item); } +bool TrayIcon::menuGetItemChecked(MenuItem id) +{ + assert(s_menu); + return GetMenuState(s_menu, static_cast(id), MF_BYCOMMAND) & MF_CHECKED; +} + void TrayIcon::menuSetItemChecked(MenuItem id, bool checked) { assert(s_menu); diff --git a/server/src/os/windows/trayicon.hpp b/server/src/os/windows/trayicon.hpp index bfdcb958..fae41a64 100644 --- a/server/src/os/windows/trayicon.hpp +++ b/server/src/os/windows/trayicon.hpp @@ -46,6 +46,7 @@ class TrayIcon ShowHideConsole = 3, AllowClientServerRestart = 4, AllowClientServerShutdown = 5, + StartAutomaticallyAtLogon = 6, }; struct TraintasticSettings @@ -68,6 +69,7 @@ class TrayIcon static void menuAddItem(MenuItem id, const LPSTR text, bool enabled = true); static void menuAddSeperator(); + static bool menuGetItemChecked(MenuItem id); static void menuSetItemChecked(MenuItem id, bool checked); static void getSettings();