├── .gitignore ├── AnyFSE.suo ├── src ├── Resource.rc ├── AppSettings │ ├── AppSettings.def │ ├── SettingsPages │ │ ├── SettingsPage.hpp │ │ ├── SupportPage.hpp │ │ ├── UpdatePage.hpp │ │ ├── TroubleshootPage.hpp │ │ ├── SupportPage.cpp │ │ ├── StartupPage.hpp │ │ ├── SplashPage.hpp │ │ ├── StartupEditDlg.hpp │ │ ├── LauncherPage.hpp │ │ ├── TroubleshootPage.cpp │ │ ├── UpdatePage.cpp │ │ └── StartupEditDlg.cpp │ ├── SettingsLayout.hpp │ ├── AppSettings.cpp │ └── SettingsDialog.tpp ├── Updater │ ├── Updater.AppSettings.hpp │ ├── Updater.cpp │ ├── Updater.AppControl.hpp │ ├── Updater.hpp │ ├── Updater.Command.hpp │ └── Updater.AppSettings.cpp ├── Tools │ ├── PowerEfficiency.hpp │ ├── Notification.hpp │ ├── Packages.hpp │ ├── Icon.hpp │ ├── Unicode.hpp │ ├── Window.hpp │ ├── Packages.cpp │ ├── List.hpp │ ├── Event.hpp │ ├── PowerEfficiency.cpp │ ├── Process.hpp │ ├── Registry.hpp │ ├── Unicode.cpp │ ├── Event.cpp │ ├── Window.cpp │ ├── DoubleBufferedPaint.hpp │ └── Notification.cpp ├── resource.h ├── AppService │ ├── Service.rc │ ├── AppServiceStateLoop.hpp │ ├── AppService.hpp │ ├── AppServiceStateLoop.cpp │ └── ETWMonitor.hpp ├── AppUninstaller │ └── Uninstaller.rc ├── AppInstaller │ ├── Installer.rc │ └── AppInstaller_PostMortem.cpp ├── FluentDesign │ ├── Align.hpp │ ├── FluentControl.hpp │ ├── Dialog.hpp │ ├── Theme_Reflow.cpp │ ├── Align.cpp │ ├── Toggle.hpp │ ├── Static.hpp │ ├── TextBox.hpp │ ├── ScrollView.hpp │ ├── Popup.hpp │ ├── ComboBox.hpp │ ├── FluentControl.cpp │ └── Button.hpp ├── AppControl │ ├── Launchers.hpp │ ├── GamingExperience.hpp │ ├── AppControl.hpp │ ├── Launchers.cpp │ ├── VideoPlayer.hpp │ ├── GamingExperience.cpp │ ├── AppControlStateLoop.hpp │ └── MainWindow.hpp ├── App │ ├── Application.hpp │ ├── AppEvents.hpp │ ├── IPCChannel.hpp │ └── AppStateLoop.hpp ├── ToolsEx │ ├── Admin.hpp │ ├── TaskManager.hpp │ ├── ProcessEx.hpp │ ├── Admin.cpp │ ├── Minidump.hpp │ └── ProcessEx.cpp └── Logging │ ├── LogManager.hpp │ ├── Logger.hpp │ └── Logger.cpp ├── media ├── AnyFSEIcon.ico └── AnyFSEinstaller.ico ├── AnyFSE.vcxproj.user ├── AnyFSE.Settings.vcxproj.user ├── AnyFSE.Uninstaller.vcxproj.user ├── AnyFSE.Service.vcxproj.user ├── .vscode ├── c_cpp_properties.json ├── launch.json └── settings.json ├── LICENSE ├── AnyFSE.Version.props ├── AnyFSE.Service.vcxproj ├── AnyFSE.vcxproj.filters ├── AnyFSE.Settings.vcxproj ├── AnyFSE.vcxproj └── AnyFSE.sln /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | .vs 4 | -------------------------------------------------------------------------------- /AnyFSE.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashpynov/AnyFSE/HEAD/AnyFSE.suo -------------------------------------------------------------------------------- /src/Resource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashpynov/AnyFSE/HEAD/src/Resource.rc -------------------------------------------------------------------------------- /media/AnyFSEIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashpynov/AnyFSE/HEAD/media/AnyFSEIcon.ico -------------------------------------------------------------------------------- /src/AppSettings/AppSettings.def: -------------------------------------------------------------------------------- 1 | LIBRARY "AnyFSE.Settings.dll" 2 | EXPORTS 3 | Main @1 4 | -------------------------------------------------------------------------------- /media/AnyFSEinstaller.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashpynov/AnyFSE/HEAD/media/AnyFSEinstaller.ico -------------------------------------------------------------------------------- /src/Updater/Updater.AppSettings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace AnyFSE::Updater 7 | { 8 | void NotifyConfigUpdated(); 9 | } -------------------------------------------------------------------------------- /AnyFSE.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /AnyFSE.Settings.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /AnyFSE.Uninstaller.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /AnyFSE.Service.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | -------------------------------------------------------------------------------- /src/Updater/Updater.cpp: -------------------------------------------------------------------------------- 1 | #include "Tools/Process.hpp" 2 | #include "Updater/Updater.hpp" 3 | #include 4 | 5 | namespace AnyFSE::Updater 6 | { 7 | const std::wstring RELEASE_PAGE = L"https://github.com/ashpynov/AnyFSE/releases/tag/"; 8 | 9 | void ShowVersion(const std::wstring &tag) 10 | { 11 | Process::StartProtocol(RELEASE_PAGE + tag); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Updater/Updater.AppControl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace AnyFSE::Updater 7 | { 8 | int GetSince(const std::wstring &lastCheck); 9 | int ScheduledCheckAsync(const std::wstring &lastCheck, int checkInterval, bool includePreRelease, HWND hWnd, UINT uMsg); 10 | bool UpdaterHandleCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); 11 | } 12 | -------------------------------------------------------------------------------- /src/Tools/PowerEfficiency.hpp: -------------------------------------------------------------------------------- 1 | // Power efficiency helpers 2 | #pragma once 3 | 4 | #include 5 | 6 | namespace AnyFSE::Tools { 7 | // Force low-power mode for current process and threads (enable/disable). 8 | // If `bEnable` is true, lower process priority and enable execution-speed throttling. 9 | // If `bEnable` is false, restore normal priority and disable throttling. 10 | void EnablePowerEfficencyMode(bool bEnable); 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64", 5 | "includePath": [ 6 | "${workspaceFolder}/src" 7 | ], 8 | "defines": [ 9 | "_DEBUG", 10 | "UNICODE", 11 | "_UNICODE" 12 | ], 13 | "windowsSdkVersion": "10.0.26100.0", 14 | "cStandard": "c17", 15 | "cppStandard": "c++17", 16 | "intelliSenseMode": "windows-msvc-x64" 17 | } 18 | ], 19 | "version": 4 20 | } -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Resource.rc 4 | // 5 | #define IDS_TIP 1 6 | 7 | #define IDI_ICON 101 8 | #define IDR_POPUP 102 9 | #define ID_CONFIGURE 40001 10 | #define ID_QUIT 40002 11 | 12 | // Next default values for new objects 13 | // 14 | #ifdef APSTUDIO_INVOKED 15 | #ifndef APSTUDIO_READONLY_SYMBOLS 16 | #define _APS_NEXT_RESOURCE_VALUE 108 17 | #define _APS_NEXT_COMMAND_VALUE 40003 18 | #define _APS_NEXT_CONTROL_VALUE 1025 19 | #define _APS_NEXT_SYMED_VALUE 101 20 | #endif 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /src/Tools/Notification.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace AnyFSE::Tools 7 | { 8 | struct Notification 9 | { 10 | // Show a tray balloon. If hwnd is non-NULL, reuse it (assumes app already added an icon for that hwnd). 11 | // If hwnd is NULL, a temporary hidden window and icon will be created for the notification. 12 | static void Show(HWND hwnd, const std::wstring& title, const std::wstring& message, const std::wstring& launchUrl = L""); 13 | 14 | static void ShowNewVersion(HWND hwnd, const std::wstring &version, const std::wstring &launchUrl = L""); 15 | static void ShowCurrentVersion(HWND hwnd, bool installed); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/SettingsPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "FluentDesign/SettingsLine.hpp" 6 | 7 | namespace AnyFSE::App::AppSettings::Settings 8 | { 9 | class SettingsDialog; 10 | 11 | namespace Page 12 | { 13 | class SettingsPage 14 | { 15 | public: 16 | virtual ~SettingsPage() = default; 17 | 18 | virtual std::list &GetSettingsLines() = 0; 19 | 20 | virtual void AddPage(std::list& settingPageList, ULONG &top) = 0; 21 | virtual void LoadControls() = 0; 22 | virtual void SaveControls() = 0; 23 | }; 24 | } 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/SupportPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "FluentDesign/Theme.hpp" 5 | #include "AppSettings/SettingsPages/SettingsPage.hpp" 6 | 7 | namespace AnyFSE::App::AppSettings::Settings::Page 8 | { 9 | using namespace FluentDesign; 10 | 11 | class SupportPage : public SettingsPage 12 | { 13 | Theme &m_theme; 14 | SettingsDialog &m_dialog; 15 | 16 | public: 17 | SupportPage(Theme& theme, SettingsDialog &dialog) 18 | : m_theme(theme) 19 | , m_dialog(dialog) 20 | 21 | {} 22 | 23 | std::list &GetSettingsLines() { return m_pageLinesList; }; 24 | 25 | void AddPage(std::list& settingPageList, ULONG &top); 26 | void LoadControls() {}; 27 | void SaveControls() {}; 28 | 29 | private: 30 | std::list m_pageLinesList; 31 | }; 32 | }; -------------------------------------------------------------------------------- /src/Updater/Updater.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace AnyFSE::Updater 7 | { 8 | enum UpdaterState 9 | { 10 | Idle = 0, 11 | Done = Idle, 12 | NetworkFailed, 13 | CheckingUpdate, 14 | Downloading, 15 | ReadyForUpdate 16 | }; 17 | 18 | struct UpdateInfo 19 | { 20 | UpdaterState uiState = UpdaterState::Idle; 21 | std::wstring newVersion; 22 | std::wstring downloadPath; 23 | long long lCommandAge = 0; 24 | UpdaterState uiCommand = UpdaterState::Idle; 25 | }; 26 | 27 | void Subscribe(HWND hWnd, UINT uMsg); 28 | void CheckUpdateAsync(bool includePreRelease, HWND hWnd, UINT uMsg); 29 | void UpdateAsync(const std::wstring &tag, bool silentUpdatee, HWND hWnd, UINT uMsg); 30 | Updater::UpdateInfo GetLastUpdateInfo(); 31 | void ShowVersion(const std::wstring &tag); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/AppService/Service.rc: -------------------------------------------------------------------------------- 1 | 2 | 1 VERSIONINFO 3 | FILEVERSION VER_VERSION 4 | PRODUCTVERSION VER_VERSION 5 | FILEFLAGSMASK 0x3fL 6 | #ifdef _DEBUG 7 | FILEFLAGS 0x1L 8 | #else 9 | FILEFLAGS 0x0L 10 | #endif 11 | FILEOS 0x40004L 12 | FILETYPE 0x1L 13 | FILESUBTYPE 0x0L 14 | BEGIN 15 | BLOCK "StringFileInfo" 16 | BEGIN 17 | BLOCK "040904b0" 18 | BEGIN 19 | VALUE "CompanyName", COMPANY_NAME 20 | VALUE "FileDescription", FILE_DESCRIPTION 21 | VALUE "FileVersion", VER_VERSION_STR 22 | VALUE "InternalName", INTERNAL_NAME 23 | VALUE "LegalCopyright", LEGAL_COPYRIGHT 24 | VALUE "OriginalFilename", ORIGINAL_FILENAME 25 | VALUE "ProductName", PRODUCT_NAME 26 | VALUE "ProductVersion", VER_VERSION_STR 27 | END 28 | END 29 | BLOCK "VarFileInfo" 30 | BEGIN 31 | VALUE "Translation", 0x409, 1200 32 | END 33 | END 34 | -------------------------------------------------------------------------------- /src/AppUninstaller/Uninstaller.rc: -------------------------------------------------------------------------------- 1 | 2 | 1 VERSIONINFO 3 | FILEVERSION VER_VERSION 4 | PRODUCTVERSION VER_VERSION 5 | FILEFLAGSMASK 0x3fL 6 | #ifdef _DEBUG 7 | FILEFLAGS 0x1L 8 | #else 9 | FILEFLAGS 0x0L 10 | #endif 11 | FILEOS 0x40004L 12 | FILETYPE 0x1L 13 | FILESUBTYPE 0x0L 14 | BEGIN 15 | BLOCK "StringFileInfo" 16 | BEGIN 17 | BLOCK "040904b0" 18 | BEGIN 19 | VALUE "CompanyName", COMPANY_NAME 20 | VALUE "FileDescription", FILE_DESCRIPTION 21 | VALUE "FileVersion", VER_VERSION_STR 22 | VALUE "InternalName", INTERNAL_NAME 23 | VALUE "LegalCopyright", LEGAL_COPYRIGHT 24 | VALUE "OriginalFilename", ORIGINAL_FILENAME 25 | VALUE "ProductName", PRODUCT_NAME 26 | VALUE "ProductVersion", VER_VERSION_STR 27 | END 28 | END 29 | BLOCK "VarFileInfo" 30 | BEGIN 31 | VALUE "Translation", 0x409, 1200 32 | END 33 | END 34 | 35 | 2 ICON "..\\..\\media\\AnyFSEInstaller.ico" 36 | -------------------------------------------------------------------------------- /src/AppInstaller/Installer.rc: -------------------------------------------------------------------------------- 1 | 2 | 1 VERSIONINFO 3 | FILEVERSION VER_VERSION 4 | PRODUCTVERSION VER_VERSION 5 | FILEFLAGSMASK 0x3fL 6 | #ifdef _DEBUG 7 | FILEFLAGS 0x1L 8 | #else 9 | FILEFLAGS 0x0L 10 | #endif 11 | FILEOS 0x40004L 12 | FILETYPE 0x1L 13 | FILESUBTYPE 0x0L 14 | BEGIN 15 | BLOCK "StringFileInfo" 16 | BEGIN 17 | BLOCK "040904b0" 18 | BEGIN 19 | VALUE "CompanyName", COMPANY_NAME 20 | VALUE "FileDescription", FILE_DESCRIPTION 21 | VALUE "FileVersion", VER_VERSION_STR 22 | VALUE "InternalName", INTERNAL_NAME 23 | VALUE "LegalCopyright", LEGAL_COPYRIGHT 24 | VALUE "OriginalFilename", ORIGINAL_FILENAME 25 | VALUE "ProductName", PRODUCT_NAME 26 | VALUE "ProductVersion", VER_VERSION_STR 27 | END 28 | END 29 | BLOCK "VarFileInfo" 30 | BEGIN 31 | VALUE "Translation", 0x409, 1200 32 | END 33 | END 34 | 35 | 2 ICON "..\\..\\media\\AnyFSEInstaller.ico" 36 | 37 | 3 ZIP BUILD_ARCHIVE -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Artem Shpynov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/FluentDesign/Align.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace FluentDesign::Align 6 | { 7 | typedef BYTE Anchor; 8 | enum Side: Anchor 9 | { 10 | None = 0, 11 | Left = 1, 12 | Right = 2, 13 | Center = 3, 14 | Top = Left, 15 | Bottom = Right 16 | }; 17 | 18 | struct Margins 19 | { 20 | float Left; 21 | float Top; 22 | float Right; 23 | float Bottom; 24 | }; 25 | 26 | Side LeftSide(Anchor anchor); 27 | Side TopSide(Anchor anchor); 28 | Side RightSide(Anchor anchor); 29 | Side BottomSide(Anchor anchor); 30 | 31 | Anchor Align(Side left, Side top, Side right = None, Side bottom = None); 32 | 33 | Anchor TopLeft(); 34 | Anchor TopRight(); 35 | Anchor BottomLeft(); 36 | Anchor BottomRight(); 37 | Anchor Client(); 38 | Anchor TopClient(); 39 | Anchor BottomClient(); 40 | 41 | float HSide(Side side, const Gdiplus::RectF &rect, float size); 42 | float VSide(Side side, const Gdiplus::RectF &rect, float size); 43 | } 44 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/UpdatePage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "FluentDesign/Theme.hpp" 5 | #include "AppSettings/SettingsPages/SettingsPage.hpp" 6 | 7 | namespace AnyFSE::App::AppSettings::Settings::Page 8 | { 9 | using namespace FluentDesign; 10 | 11 | class UpdatePage : public SettingsPage 12 | { 13 | Theme &m_theme; 14 | SettingsDialog &m_dialog; 15 | 16 | public: 17 | UpdatePage(Theme& theme, SettingsDialog &dialog) 18 | : m_theme(theme) 19 | , m_dialog(dialog) 20 | , m_checkIntervalCombo(m_theme) 21 | , m_preReleaseToggle(m_theme) 22 | , m_notificationsToggle(m_theme) 23 | {} 24 | 25 | std::list &GetSettingsLines() { return m_pageLinesList; }; 26 | 27 | void AddPage(std::list& settingPageList, ULONG &top); 28 | void LoadControls(); 29 | void SaveControls(); 30 | 31 | private: 32 | std::list m_pageLinesList; 33 | 34 | ComboBox m_checkIntervalCombo; 35 | Toggle m_preReleaseToggle; 36 | Toggle m_notificationsToggle; 37 | 38 | void OpenUpdateSettingsPage(); 39 | void UpdateSettingsChangedCheck(); 40 | void UpdateSettingsChanged(); 41 | }; 42 | }; -------------------------------------------------------------------------------- /AnyFSE.Version.props: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 0.10.4 6 | AnyFSE 7 | Artem Shpynov 8 | Copyright © 2025 Artem Shpynov. All rights reserved. 9 | $(TargetName) 10 | 11 | 12 | 13 | 14 | VER_VERSION=$(AssemblyVersion.Replace('.', ',')),0; 15 | VER_VERSION_STR=\"$(AssemblyVersion)\"; 16 | COMPANY_NAME=\"$(AssemblyCompany)\"; 17 | PRODUCT_NAME=\"$(AssemblyProduct)\"; 18 | FILE_DESCRIPTION=\"$(AssemblyDescription)\"; 19 | INTERNAL_NAME=\"$(AssemblyInternalName)\"; 20 | LEGAL_COPYRIGHT=\"$(AssemblyCopyright)\"; 21 | ORIGINAL_FILENAME=\"$(TargetName)$(TargetExt)\"; 22 | %(PreprocessorDefinitions) 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/AppControl/Launchers.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | namespace AnyFSE::App::AppControl::Launchers 27 | { 28 | void LauncherOnBoot(); 29 | void PlayniteOnBoot(); 30 | } -------------------------------------------------------------------------------- /src/App/Application.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | #include 26 | 27 | namespace AnyFSE::App 28 | { 29 | typedef INT_PTR (*MainFunc)(HINSTANCE, HINSTANCE, LPSTR, int); 30 | } -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/TroubleshootPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "FluentDesign/Theme.hpp" 5 | #include "FluentDesign/ComboBox.hpp" 6 | #include "FluentDesign/Toggle.hpp" 7 | #include "AppSettings/SettingsPages/SettingsPage.hpp" 8 | 9 | namespace AnyFSE::App::AppSettings::Settings::Page 10 | { 11 | using namespace FluentDesign; 12 | 13 | class TroubleshootPage : public SettingsPage 14 | { 15 | Theme &m_theme; 16 | SettingsDialog &m_dialog; 17 | 18 | public: 19 | TroubleshootPage(Theme& theme, SettingsDialog &dialog) 20 | : m_theme(theme) 21 | , m_dialog(dialog) 22 | , m_troubleLogLevelCombo(m_theme) 23 | , m_troubleAggressiveToggle(m_theme) 24 | , m_troubleExitOnExitToggle(m_theme) 25 | {} 26 | 27 | std::list &GetSettingsLines() { return m_pageLinesList; }; 28 | 29 | void AddPage(std::list& settingPageList, ULONG &top); 30 | void LoadControls(); 31 | void SaveControls(); 32 | 33 | private: 34 | std::list m_pageLinesList; 35 | 36 | void OpenTroubleshootSettingsPage(); 37 | void OnGotoLogsFolder(); 38 | 39 | ComboBox m_troubleLogLevelCombo; 40 | Toggle m_troubleAggressiveToggle; 41 | Toggle m_troubleExitOnExitToggle; 42 | }; 43 | }; -------------------------------------------------------------------------------- /AnyFSE.Service.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17.0 5 | Win32Proj 6 | {4B2F1E9A-8C3D-4E76-9A1F-2D8C5A3B7E9F} 7 | AnyFSE 8 | AnyFSE.Service 9 | Application 10 | 10.0 11 | AnyFSE System service monitoring module 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Tools/Packages.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #include 25 | 26 | namespace AnyFSE::Tools 27 | { 28 | class Packages 29 | { 30 | public: 31 | static std::wstring GetAppxInstallLocation(const std::wstring &packageName); 32 | }; 33 | } -------------------------------------------------------------------------------- /src/ToolsEx/Admin.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include 26 | #include 27 | 28 | 29 | namespace AnyFSE::ToolsEx::Admin 30 | { 31 | BOOL IsRunningAsAdministrator(); 32 | BOOL RequestAdminElevation(const std::wstring& args = L""); 33 | } -------------------------------------------------------------------------------- /src/ToolsEx/TaskManager.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | namespace AnyFSE::ToolsEx::TaskManager 27 | { 28 | bool CreateTask(const std::wstring& exeFile = L""); 29 | bool StartTask(); 30 | bool RemoveTask(); 31 | std::wstring GetInstallPath(); 32 | } 33 | -------------------------------------------------------------------------------- /AnyFSE.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | 26 | 27 | Resource Files 28 | 29 | 30 | 31 | 32 | Resource Files 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Updater/Updater.Command.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Updater/Updater.hpp" 6 | 7 | namespace AnyFSE::Updater 8 | { 9 | enum COMMAND 10 | { 11 | SUBSCRIBE = 0, 12 | CHECK, 13 | UPDATE, 14 | GETUPDATEINFO, 15 | NOTIFYCONFIGUPDATED 16 | }; 17 | 18 | struct SUBSCRIPTION 19 | { 20 | HWND hWnd; 21 | UINT uMsg; 22 | }; 23 | 24 | struct UPDATECHECK 25 | { 26 | BOOL bIncludePreRelease; 27 | HWND hWnd; 28 | UINT uMsg; 29 | }; 30 | 31 | struct UPDATEUPDATE 32 | { 33 | std::wstring newVersion; 34 | BOOL bSilent; 35 | HWND hWnd; 36 | UINT uMsg; 37 | }; 38 | 39 | struct UPDATEINFO 40 | { 41 | UpdaterState uiState; 42 | wchar_t newVersion[MAX_PATH]; 43 | wchar_t downloadPath[MAX_PATH]; 44 | long long lCommandAge; 45 | UpdaterState uiCommand; 46 | 47 | void put(UpdateInfo i) 48 | { 49 | uiState = i.uiState; 50 | lCommandAge = i.lCommandAge; 51 | uiCommand = i.uiCommand; 52 | wcsncpy_s(newVersion, i.newVersion.c_str(), MAX_PATH - 1); 53 | wcsncpy_s(downloadPath, i.downloadPath.c_str(), MAX_PATH - 1); 54 | } 55 | }; 56 | 57 | struct CONFIGUPDATED 58 | { 59 | int iCheckInterval; 60 | bool bPreRelease; 61 | bool bNotifications; 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /src/Tools/Icon.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | #include 27 | #include 28 | #include "GdiPlus.hpp" 29 | 30 | namespace AnyFSE::Tools::Icon 31 | { 32 | HICON LoadIcon(const std::wstring& icon, int size = 256); 33 | Gdiplus::Bitmap * LoadBitmapFromIcon(const std::wstring &icon, int iconSize = 256); 34 | } 35 | -------------------------------------------------------------------------------- /AnyFSE.Settings.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AnyFSE.Settings 5 | DynamicLibrary 6 | .dll 7 | {7F3A9B1C-82D4-4E5F-91A6-B8C7D2E4F619} 8 | AnyFSE Settings module 9 | 10 | 11 | 12 | 13 | 14 | src\AppSettings\AppSettings.def 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/Tools/Unicode.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | 30 | namespace AnyFSE::Tools::Unicode 31 | { 32 | std::wstring to_wstring(const std::string& str); 33 | std::string to_string(const std::wstring& wstr); 34 | std::wstring to_lower(const std::wstring &str); 35 | } 36 | 37 | namespace Unicode = AnyFSE::Tools::Unicode; -------------------------------------------------------------------------------- /src/ToolsEx/ProcessEx.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace AnyFSE::ToolsEx::ProcessEx 32 | { 33 | HRESULT Kill(const std::wstring& processName); 34 | HRESULT KillSystem(DWORD processId); 35 | HRESULT Kill(DWORD processId); 36 | } 37 | 38 | namespace ProcessEx = AnyFSE::ToolsEx::ProcessEx; -------------------------------------------------------------------------------- /src/AppSettings/SettingsLayout.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace AnyFSE::App::AppSettings::Settings::Layout 4 | { 5 | static const int OKWidth = 100; 6 | static const int CloseWidth = 150; 7 | static const int UninstallWidth = 100; 8 | 9 | static const int BrowseWidth = 130; 10 | static const int BrowseHeight = 32; 11 | 12 | static const int StartupMenuButtonWidth = 24; 13 | static const int StartupMenuButtonHeight = 36; 14 | 15 | static const int StartupAddWidth = 100; 16 | static const int StartupAddHeight = 32; 17 | 18 | static const int MaxWidth = 1024; 19 | static const int Border = 3; 20 | static const int MarginLeft = 32; 21 | static const int MarginTop = 60; 22 | static const int MarginRight = 32; 23 | static const int MarginBottom = 32; 24 | static const int ButtonPadding = 16; 25 | static const int ButtonHeight = 32; 26 | static const int UpdateHeight = 36; 27 | 28 | static const int LineHeight = 67; 29 | static const int LinePadding = 8; 30 | static const int LineHeightSmall = 45; 31 | static const int LinePaddingSmall = 4; 32 | static const int LineSmallMargin = 52; 33 | 34 | static const int CustomSettingsWidth = 220; 35 | static const int CustomSettingsHeight = 44; 36 | 37 | static const int LauncherComboWidth = 280; 38 | static const int LauncherBrowsePadding = -12; 39 | static const int LauncherBrowseLineHeight = 57; 40 | 41 | static const int BackButtonSize = 34; 42 | static const int BackButtonMargin = 4; 43 | 44 | static const int CaptionButtonWidth = 48; 45 | static const int CaptionHeight = 36; 46 | }; -------------------------------------------------------------------------------- /src/Tools/Window.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | #include 27 | #include 28 | #include "GdiPlus.hpp" 29 | 30 | namespace AnyFSE::Tools::Window 31 | { 32 | BOOL GetChildRect(HWND hwnd, RECT *rect); 33 | BOOL MoveWindow(HWND hwnd, RECT * rect, BOOL bRepaint); 34 | BOOL MoveWindow(HWND hwnd, int dx, int dy, BOOL bRepaint); 35 | BOOL MouseInClientRect(HWND, RECT *rect = NULL, int inflate = 0); 36 | } 37 | 38 | namespace Window = AnyFSE::Tools::Window; -------------------------------------------------------------------------------- /src/FluentDesign/FluentControl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Tools/GdiPlus.hpp" 4 | #include "FluentDesign/Theme.hpp" 5 | #include "FluentDesign/Align.hpp" 6 | 7 | namespace FluentDesign 8 | { 9 | class FluentControl 10 | { 11 | public: 12 | typedef BOOL (*GetParentRectFunc)(Theme&, HWND, LPRECT); 13 | 14 | protected: 15 | static BOOL GetParentRect(Theme &, HWND hWnd, LPRECT prc) { return GetClientRect(hWnd, prc); } 16 | 17 | protected: 18 | 19 | GetParentRectFunc m_getParentRect = GetParentRect; 20 | Align::Margins m_designMargins; 21 | Align::Anchor m_anchor = Align::None; 22 | 23 | protected: 24 | Theme &m_theme; 25 | HWND m_hWnd; 26 | 27 | FluentControl(Theme &theme) 28 | : m_theme(theme) 29 | , m_hWnd(nullptr) 30 | {} 31 | 32 | 33 | FluentControl(Theme &theme, Align::Anchor align, GetParentRectFunc getParentRect = GetParentRect) 34 | : FluentControl(theme) 35 | { 36 | SetAnchor(align, getParentRect); 37 | } 38 | 39 | virtual ~FluentControl() {} // for dynamic_cast 40 | 41 | void AnchoredSizePos(HWND hParent, int &x, int &y, int &cx, int &cy); 42 | 43 | public: 44 | HWND GetHwnd() const { return m_hWnd; } 45 | 46 | void SetAnchor(Align::Anchor anchor, GetParentRectFunc getParentRect = GetParentRect); 47 | void SetSize(LONG cx, LONG cy); 48 | void StoreDesign(); 49 | HDWP ReflowControl(HDWP hdwp = nullptr); 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/SupportPage.cpp: -------------------------------------------------------------------------------- 1 | #include "Tools/Event.hpp" 2 | #include "AppSettings/SettingsLayout.hpp" 3 | #include "AppSettings/SettingsDialog.hpp" 4 | #include "SupportPage.hpp" 5 | 6 | 7 | namespace AnyFSE::App::AppSettings::Settings::Page 8 | { 9 | void SupportPage::AddPage(std::list& settingPageList, ULONG &top) 10 | { 11 | m_dialog.AddSettingsLine(settingPageList, top, 12 | L"Related support", 13 | L"", 14 | Layout::LineHeightSmall, 0, 0 15 | ).SetState(FluentDesign::SettingsLine::Caption); 16 | 17 | SettingsLine &support = m_dialog.AddSettingsLine(settingPageList, top, 18 | L"Support and community", 19 | L"", 20 | Layout::LineHeight, 0, 0); 21 | 22 | support.SetIcon(L'\xF6FA'); 23 | support.OnChanged += delegateparam(m_dialog.UpdateLine, &support); 24 | 25 | SettingsLine &links = m_dialog.AddSettingsLine(settingPageList, top, 26 | L"", 27 | L"", 28 | Layout::LineHeightSmall, Layout::LinePadding, Layout::LineSmallMargin); 29 | 30 | support.AddGroupItem(&links); 31 | 32 | // links.SetMaxColumns(1); 33 | links.AddLinkButton(L"Discord AnyFSE community channel", L"https://discord.gg/AfkERzTEut"); 34 | links.AddLinkButton(L"GitHub repository", L"https://github.com/ashpynov/AnyFSE/"); 35 | links.AddLinkButton(L"Report issue or feature request", L"https://github.com/ashpynov/AnyFSE/issues"); 36 | links.AddLinkButton(L"Navigate to log files folder", Config::GetModulePath() + L"\\logs"); 37 | 38 | support.SetState(FluentDesign::SettingsLine::Opened); 39 | 40 | } 41 | }; -------------------------------------------------------------------------------- /AnyFSE.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17.0 5 | Win32Proj 6 | {C4D8E9A2-1B7F-43C5-9D0E-F8A2B6C7D1E3} 7 | AnyFSE 8 | AnyFSE 9 | Application 10 | 10.0 11 | AnyFSE Home application launcher 12 | 13 | 14 | 15 | 16 | 17 | api-ms-win-gaming-experience-l1-1-0.dll;GdiPlus.dll 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/Tools/Packages.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "Packages.hpp" 8 | 9 | namespace AnyFSE::Tools 10 | { 11 | std::wstring Packages::GetAppxInstallLocation(const std::wstring &packageName) 12 | { 13 | UINT32 count = 0; 14 | UINT32 bufferLength = 0; 15 | 16 | // Search for packages with the specific name pattern 17 | std::wstring searchPattern = packageName; 18 | 19 | // First call to get the count and buffer size 20 | LONG result = GetPackagesByPackageFamily( 21 | searchPattern.c_str(), 22 | &count, 23 | nullptr, 24 | &bufferLength, 25 | nullptr); 26 | 27 | if (result == ERROR_INSUFFICIENT_BUFFER && count > 0) 28 | { 29 | std::vector buffer(bufferLength); 30 | std::vector packageFullNames(count); 31 | 32 | // Second call to get the actual package names 33 | result = GetPackagesByPackageFamily( 34 | searchPattern.c_str(), 35 | &count, 36 | packageFullNames.data(), 37 | &bufferLength, 38 | buffer.data()); 39 | 40 | if (result == ERROR_SUCCESS && count > 0) 41 | { 42 | // Get the install path for the first matching package 43 | WCHAR path[MAX_PATH]; 44 | UINT32 pathLength = MAX_PATH; 45 | 46 | if (GetStagedPackagePathByFullName(buffer.data(), &pathLength, path) == ERROR_SUCCESS) 47 | { 48 | return std::wstring(path); 49 | } 50 | } 51 | } 52 | 53 | return L""; 54 | } 55 | } -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/StartupPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "FluentDesign/Theme.hpp" 5 | #include "FluentDesign/Button.hpp" 6 | #include "FluentDesign/Toggle.hpp" 7 | #include "AppSettings/SettingsPages/SettingsPage.hpp" 8 | 9 | namespace AnyFSE::App::AppSettings::Settings::Page 10 | { 11 | using namespace FluentDesign; 12 | 13 | class StartupPage : public SettingsPage 14 | { 15 | Theme &m_theme; 16 | SettingsDialog &m_dialog; 17 | 18 | public: 19 | StartupPage(Theme& theme, SettingsDialog &dialog) 20 | : m_theme(theme) 21 | , m_dialog(dialog) 22 | , m_startupAddButton(m_theme) 23 | {} 24 | 25 | std::list &GetSettingsLines() { return m_pageLinesList; }; 26 | 27 | void AddPage(std::list& settingPageList, ULONG &top); 28 | void LoadControls(); 29 | void SaveControls(); 30 | 31 | private: 32 | std::list m_pageLinesList; 33 | 34 | SettingsLine * m_pStartupPageLine = nullptr; 35 | SettingsLine * m_pStartupPageAppsHeader = nullptr; 36 | 37 | Button m_startupAddButton; 38 | std::list m_startupToggles; 39 | std::list m_pStartupAppLines; 40 | 41 | void OpenStartupSettingsPage(); 42 | void OpenMSSettingsStartupApps(); 43 | 44 | void AddStartupAppLine(const std::wstring &path, const std::wstring &args, bool enabled); 45 | Toggle *GetStartupLineToggle(SettingsLine *pLine); 46 | void SetStartupAppLine(SettingsLine *pLine, const std::wstring &path, const std::wstring &args); 47 | void OnStartupAdd(); 48 | void OnStartupModify(SettingsLine *pLine); 49 | void OnStartupDelete(SettingsLine *pLine); 50 | 51 | }; 52 | }; -------------------------------------------------------------------------------- /src/App/AppEvents.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | namespace AnyFSE::App 27 | { 28 | enum class AppEvents : int 29 | { 30 | CONNECT = 0, 31 | START, 32 | START_APPS, 33 | XBOX_DETECTED, 34 | LAUNCHER_STOPPED, 35 | GAMEMODE_ENTER, 36 | GAMEMODE_EXIT, 37 | OPEN_HOME, 38 | OPEN_DEVICE_FORM, 39 | XBOX_DENY, 40 | XBOX_ALLOW, 41 | SUSPEND_SERVICE, 42 | EXIT_SERVICE, 43 | QUERY_END_SESSION, 44 | END_SESSION, 45 | RESTART_SERVICE, 46 | DISCONNECT, 47 | RELOAD_SERVICE, 48 | }; 49 | } 50 | 51 | using namespace AnyFSE::App; 52 | -------------------------------------------------------------------------------- /src/AppControl/GamingExperience.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | #include 26 | #include 27 | #include 28 | #include "Tools/Event.hpp" 29 | 30 | namespace AnyFSE::App::AppControl 31 | { 32 | class GamingExperience 33 | { 34 | private: 35 | GAMING_FULL_SCREEN_EXPERIENCE_REGISTRATION m_fseHandle; 36 | 37 | static void Callback(GamingExperience * This); 38 | 39 | public: 40 | static bool ApiIsAvailable; 41 | static bool IsActive(); 42 | static bool ExitFSEMode(); 43 | GamingExperience(); 44 | ~GamingExperience(); 45 | 46 | Event OnExperienseChanged; 47 | 48 | }; 49 | } 50 | 51 | using namespace AnyFSE::App::AppControl; -------------------------------------------------------------------------------- /src/FluentDesign/Dialog.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Theme.hpp" 3 | 4 | namespace FluentDesign 5 | { 6 | 7 | class IDialog 8 | { 9 | public: 10 | virtual void Create() = 0; 11 | virtual float GetFooterDesignHeight() const = 0; 12 | virtual void OnOK() = 0; 13 | virtual void OnCancel() = 0; 14 | 15 | virtual INT_PTR InstanceDialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) = 0; 16 | virtual BOOL OnInitDialog(HWND hwnd) = 0; 17 | virtual BOOL OnDpiChanged(HWND hwnd) = 0; 18 | virtual BOOL OnPaint(HWND hwnd) = 0; 19 | virtual BOOL OnErase(HDC hdc, HWND child) = 0; 20 | 21 | virtual SIZE GetDialogDesignSize() = 0; 22 | }; 23 | 24 | class Dialog: public IDialog 25 | { 26 | protected: 27 | Theme m_theme; 28 | HWND m_hDialog = nullptr; 29 | 30 | std::map m_designedPositions; 31 | 32 | void CenterDialog(HWND hwnd); 33 | 34 | BOOL OnInitDialog(HWND hwnd); 35 | BOOL OnDpiChanged(HWND hwnd); 36 | BOOL OnPaint(HWND hwnd); 37 | BOOL OnErase(HDC hdc, HWND child); 38 | BOOL OnNcCalcSize(HWND hwnd, NCCALCSIZE_PARAMS *params); 39 | 40 | INT_PTR InstanceDialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 41 | static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 42 | 43 | INT_PTR Show(HWND hParent); 44 | 45 | Dialog(){} 46 | 47 | /* default implementations */ 48 | float GetFooterDesignHeight() const { return 0.f; }; 49 | void OnCancel(); 50 | void OnOK(); 51 | virtual Theme::Colors GetDialogColor() { return Theme::Colors::Dialog; }; 52 | virtual Theme::Colors GetFooterColor() { return Theme::Colors::Footer; }; 53 | }; 54 | } -------------------------------------------------------------------------------- /src/FluentDesign/Theme_Reflow.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include "Theme.hpp" 26 | #include "FluentDesign/FluentControl.hpp" 27 | 28 | namespace FluentDesign 29 | { 30 | const void Theme::ReflowChilds(HWND parent) 31 | { 32 | HWND hChild = GetWindow(parent, GW_CHILD); 33 | HDWP hdwp = BeginDeferWindowPos(3); 34 | while (hChild) 35 | { 36 | FluentControl *pControl = dynamic_cast((FluentControl*)GetWindowLongPtr(hChild, GWLP_USERDATA)); 37 | if (pControl) 38 | { 39 | hdwp = pControl->ReflowControl(hdwp); 40 | } 41 | hChild = GetWindow(hChild, GW_HWNDNEXT); 42 | } 43 | if (hdwp) 44 | { 45 | EndDeferWindowPos(hdwp); 46 | } 47 | }; 48 | } -------------------------------------------------------------------------------- /src/AppService/AppServiceStateLoop.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | #include "App/AppEvents.hpp" 27 | #include "App/AppStateLoop.hpp" 28 | #include "Tools/Event.hpp" 29 | 30 | namespace AnyFSE::App::AppService::StateLoop 31 | { 32 | 33 | class AppServiceStateLoop: public App::StateLoop::AppStateLoop 34 | { 35 | public: 36 | AppServiceStateLoop(); 37 | ~AppServiceStateLoop(); 38 | 39 | Event OnXboxDeny; 40 | Event OnXboxAllow; 41 | Event OnExit; 42 | Event OnRestart; 43 | Event OnConnect; 44 | Event OnReload; 45 | Event OnSuspend; 46 | 47 | private: 48 | virtual void ProcessEvent(AppEvents event); 49 | }; 50 | } 51 | 52 | using namespace AnyFSE::App::AppService::StateLoop; -------------------------------------------------------------------------------- /src/Tools/List.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | namespace AnyFSE::Tools::List 28 | { 29 | template 30 | size_t index_of(const T& list, const V &value); 31 | 32 | const size_t npos = static_cast(-1); 33 | 34 | template 35 | size_t index_of(const T& list, const V& value) { 36 | auto it = std::find(list.begin(), list.end(), value); 37 | return (it != list.end()) ? std::distance(list.begin(), it) : npos; 38 | } 39 | 40 | template 41 | size_t index_of_if(const T& list, Predicate pred) { 42 | auto it = std::find_if(list.begin(), list.end(), pred); 43 | return (it != list.end()) ? std::distance(list.begin(), it) : npos; 44 | } 45 | } 46 | 47 | namespace List = AnyFSE::Tools::List; 48 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/SplashPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "FluentDesign/Theme.hpp" 5 | #include "AppSettings/SettingsPages/SettingsPage.hpp" 6 | 7 | namespace AnyFSE::App::AppSettings::Settings::Page 8 | { 9 | using namespace FluentDesign; 10 | 11 | class SplashPage : public SettingsPage 12 | { 13 | Theme &m_theme; 14 | SettingsDialog &m_dialog; 15 | 16 | public: 17 | SplashPage(Theme& theme, SettingsDialog &dialog) 18 | : m_theme(theme) 19 | , m_dialog(dialog) 20 | , m_showAnimationToggle(m_theme) 21 | , m_showLogoToggle(m_theme) 22 | , m_showTextToggle(m_theme) 23 | , m_showVideoToggle(m_theme) 24 | , m_videoLoopToggle(m_theme) 25 | , m_videoMuteToggle(m_theme) 26 | , m_videoPauseToggle(m_theme) 27 | , m_customTextEdit(m_theme) 28 | , m_splashCustomVideoEdit(m_theme) 29 | {} 30 | 31 | std::list &GetSettingsLines() { return m_pageLinesList; }; 32 | 33 | void AddPage(std::list& settingPageList, ULONG &top); 34 | void LoadControls(); 35 | void SaveControls(); 36 | 37 | private: 38 | std::list m_pageLinesList; 39 | 40 | Toggle m_showAnimationToggle; 41 | Toggle m_showLogoToggle; 42 | Toggle m_showTextToggle; 43 | Toggle m_showVideoToggle; 44 | Toggle m_videoLoopToggle; 45 | Toggle m_videoMuteToggle; 46 | Toggle m_videoPauseToggle; 47 | 48 | TextBox m_customTextEdit; 49 | TextBox m_splashCustomVideoEdit; 50 | 51 | SettingsLine * m_pSplashTextLine = nullptr; 52 | SettingsLine * m_pSplashLogoLine = nullptr; 53 | SettingsLine * m_pSplashVideoLine = nullptr; 54 | 55 | void OnGotoSplashFolder(); 56 | void OpenSplashSettingsPage(); 57 | void OnShowTextChanged(); 58 | void OnShowLogoChanged(); 59 | void OnShowVideoChanged(); 60 | }; 61 | }; -------------------------------------------------------------------------------- /src/Tools/Event.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | 30 | #define delegate(func) [This = this]() { This->func(); } 31 | #define delegateparam(func, param) [This = this, Param = param]() { This->func(Param); } 32 | 33 | namespace AnyFSE::Tools 34 | { 35 | class Event 36 | { 37 | protected: 38 | std::vector> callbacks; 39 | 40 | public: 41 | void operator =(std::function callback); 42 | void operator +=(std::function callback); 43 | void operator -=(const std::function& callback); 44 | void Notify(); 45 | void Clear(); 46 | bool HasSubscribe(); 47 | 48 | Event() {}; 49 | Event(std::function callback); 50 | 51 | }; 52 | } 53 | using namespace AnyFSE::Tools; -------------------------------------------------------------------------------- /src/FluentDesign/Align.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Align.hpp" 3 | 4 | namespace FluentDesign::Align 5 | { 6 | Anchor Align(Side left, Side top, Side right, Side bottom) 7 | { 8 | return (left << 6) | (top << 4) | (right << 2) | bottom; 9 | } 10 | 11 | Side LeftSide(Anchor anchor) { return (Side)((anchor >> 6 ) & Side::Center); } 12 | Side TopSide(Anchor anchor) { return (Side)((anchor >> 4 ) & Side::Center); } 13 | Side RightSide(Anchor anchor) { return (Side)((anchor >> 2 ) & Side::Center); } 14 | Side BottomSide(Anchor anchor) { return (Side)(anchor & Side::Center); } 15 | 16 | Anchor TopLeft() { return Align(Side::Left, Side::Top); } 17 | Anchor TopRight() { return Align(Side::Right, Side::Top); } 18 | Anchor BottomLeft() { return Align(Side::Left, Side::Bottom); } 19 | Anchor BottomRight() { return Align(Side::Right, Side::Bottom); } 20 | Anchor Client() { return Align(Side::Left, Side::Top, Side::Right, Side::Bottom); } 21 | Anchor TopClient() { return Align(Side::Left, Side::Top, Side::Right, Side::Top); } 22 | Anchor BottomClient() { return Align(Side::Left, Side::Top, Side::Right, Side::Top); } 23 | 24 | float HSide(Side side, const Gdiplus::RectF& rect, float size) 25 | { 26 | switch (side) 27 | { 28 | case Align::Side::Left: 29 | return rect.GetLeft(); 30 | case Align::Side::Right: 31 | return rect.GetRight(); 32 | case Align::Side::Center: 33 | return rect.GetLeft() + rect.Width / 2; 34 | } 35 | return size; 36 | } 37 | 38 | float VSide(Side side, const Gdiplus::RectF& rect, float size) 39 | { 40 | switch (side) 41 | { 42 | case Align::Side::Top: 43 | return rect.GetTop(); 44 | case Align::Side::Bottom: 45 | return rect.GetBottom(); 46 | case Align::Side::Center: 47 | return rect.GetTop() + rect.Height/ 2; 48 | } 49 | return size; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug AnyFSE", 9 | "type": "cppvsdbg", 10 | "request": "launch", 11 | "program": "AnyFSE.exe", 12 | "args": [""], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}/bin/Debug", 15 | "environment": [], 16 | "preLaunchTask": "Build AnyFSE App Debug" 17 | }, 18 | { 19 | "name": "Debug AnyFSE.Service", 20 | "type": "cppvsdbg", 21 | "request": "launch", 22 | "program": "AnyFSE.Service.exe", 23 | "args": ["/suspend"], 24 | 25 | "stopAtEntry": false, 26 | "cwd": "${workspaceFolder}/bin/Debug", 27 | "environment": [], 28 | "preLaunchTask": "Build AnyFSE.Service Debug" 29 | }, 30 | { 31 | "name": "Debug Installer", 32 | "type": "cppvsdbg", 33 | "request": "launch", 34 | "program": "AnyFSE.Installer.exe", 35 | "args": [""], 36 | "stopAtEntry": false, 37 | "cwd": "${workspaceFolder}/bin/Debug", 38 | "environment": [], 39 | "preLaunchTask": "Build AnyFSE.Installer Debug" 40 | }, 41 | { 42 | "name": "Debug Uninstaller", 43 | "type": "cppvsdbg", 44 | "request": "launch", 45 | "program": "unins000.exe", 46 | "stopAtEntry": false, 47 | "cwd": "${workspaceFolder}/bin/Debug", 48 | "environment": [], 49 | "preLaunchTask": "Build AnyFSE.Uninstaller Debug" 50 | } 51 | ], 52 | "compounds": [ 53 | { 54 | "name": "Debug Service/Control", 55 | "configurations": ["Debug AnyFSE.Service", "Debug AnyFSE"], 56 | "stopAll": true 57 | } 58 | ] 59 | } -------------------------------------------------------------------------------- /src/AppControl/AppControl.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | #include 27 | 28 | namespace AnyFSE::App::AppControl 29 | { 30 | namespace Window { class MainWindow; } 31 | namespace StateLoop { class AppControlStateLoop; } 32 | 33 | class AppControl 34 | { 35 | static int CallLibrary(const WCHAR *library, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); 36 | public: 37 | static int ShowAdminError(); 38 | static int ShowSettings(); 39 | static int StartControl(StateLoop::AppControlStateLoop & AppControlStateLoop, Window::MainWindow &mainWindow); 40 | static void InitCustomControls(); 41 | static bool AsControl(LPSTR lpCmdLine); 42 | static bool IsServiceAvailable(); 43 | static bool AsSettings(LPSTR lpCmdLine); 44 | static bool NeedAdmin(LPSTR lpCmdLine); 45 | static int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); 46 | }; 47 | } -------------------------------------------------------------------------------- /src/Tools/PowerEfficiency.cpp: -------------------------------------------------------------------------------- 1 | // Implementation of power efficiency helpers 2 | #include "Tools/PowerEfficiency.hpp" 3 | #include "Logging/LogManager.hpp" 4 | 5 | namespace AnyFSE::Tools 6 | { 7 | 8 | static Logger log = LogManager::GetLogger("PowerEfficiency"); 9 | 10 | void EnablePowerEfficencyMode(bool bEnable) 11 | { 12 | log.Info("Power Efficiency mode -> %s", bEnable ? "enable" : "disable"); 13 | 14 | // Change process priority 15 | if (bEnable) 16 | { 17 | if (!SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS)) 18 | { 19 | log.Warn("SetPriorityClass(IDLE) failed: %d", GetLastError()); 20 | } 21 | } 22 | else 23 | { 24 | if (!SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS)) 25 | { 26 | log.Warn("SetPriorityClass(NORMAL) failed: %d", GetLastError()); 27 | } 28 | } 29 | 30 | // Try to (en|dis)able process-level power throttling (execution speed) 31 | PROCESS_POWER_THROTTLING_STATE pState = {}; 32 | pState.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION; 33 | pState.ControlMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED; 34 | pState.StateMask = bEnable ? PROCESS_POWER_THROTTLING_EXECUTION_SPEED : 0; 35 | if (!SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &pState, sizeof(pState))) 36 | { 37 | log.Warn("SetProcessInformation(ProcessPowerThrottling) %s failed: %d", bEnable ? "enable" : "disable", GetLastError()); 38 | } 39 | 40 | // Try to (en|dis)able thread-level throttling for the current thread 41 | THREAD_POWER_THROTTLING_STATE tState = {}; 42 | tState.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION; 43 | tState.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED; 44 | tState.StateMask = bEnable ? THREAD_POWER_THROTTLING_EXECUTION_SPEED : 0; 45 | if (!SetThreadInformation(GetCurrentThread(), ThreadPowerThrottling, &tState, sizeof(tState))) 46 | { 47 | log.Warn("SetThreadInformation(ThreadPowerThrottling) %s failed: %d", bEnable ? "enable" : "disable", GetLastError()); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Updater/Updater.AppSettings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Configuration/Config.hpp" 5 | #include "Updater/Updater.hpp" 6 | #include "Updater/Updater.AppControl.hpp" 7 | #include "Updater/Updater.Command.hpp" 8 | #include "Updater.AppSettings.hpp" 9 | 10 | namespace AnyFSE::Updater 11 | { 12 | // No global updater instance here; prefer per-instance Updater passed to callers. 13 | static UINT WM_UPDATER_COMMAND = RegisterWindowMessage(L"AnyFSE.Updater.Command"); 14 | 15 | static LRESULT UpdaterSendCommand(COMMAND command, LPARAM lParam) 16 | { 17 | static HWND hostWindow = NULL; 18 | if (!hostWindow || !IsWindow(hostWindow)) 19 | { 20 | hostWindow = FindWindow(L"AnyFSE", NULL); 21 | } 22 | 23 | return SendMessage(hostWindow, WM_UPDATER_COMMAND, (WPARAM) command, lParam); 24 | } 25 | 26 | void Subscribe(HWND hWnd, UINT uMsg) 27 | { 28 | SUBSCRIPTION s{hWnd, uMsg}; 29 | UpdaterSendCommand(COMMAND::SUBSCRIBE, (LPARAM)&s); 30 | } 31 | 32 | void CheckUpdateAsync(bool includePreRelease, HWND hWnd, UINT uMsg) 33 | { 34 | UPDATECHECK uc{includePreRelease, hWnd, uMsg}; 35 | UpdaterSendCommand(COMMAND::CHECK, (LPARAM)&uc); 36 | } 37 | 38 | void UpdateAsync(const std::wstring &tag, bool silentUpdate, HWND hWnd, UINT uMsg) 39 | { 40 | UPDATEUPDATE uu{tag, silentUpdate, hWnd, uMsg }; 41 | UpdaterSendCommand(COMMAND::UPDATE, (LPARAM)&uu); 42 | } 43 | 44 | Updater::UpdateInfo GetLastUpdateInfo() 45 | { 46 | UPDATEINFO ui; 47 | UpdaterSendCommand(COMMAND::GETUPDATEINFO, (LPARAM)&ui); 48 | 49 | return Updater::UpdateInfo{ 50 | ui.uiState, 51 | ui.newVersion, 52 | ui.downloadPath, 53 | ui.lCommandAge, 54 | ui.uiCommand 55 | }; 56 | } 57 | 58 | void AnyFSE::Updater::NotifyConfigUpdated() 59 | { 60 | CONFIGUPDATED cu{ 61 | Config::UpdateCheckInterval, 62 | Config::UpdatePreRelease, 63 | Config::UpdateNotifications, 64 | }; 65 | UpdaterSendCommand(COMMAND::NOTIFYCONFIGUPDATED, (LPARAM)&cu); 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/Tools/Process.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace AnyFSE::Tools::Process 32 | { 33 | HWND FindAppWindow(HANDLE hProcess); 34 | DWORD FindFirstByExe(const std::wstring &processPath); 35 | DWORD FindFirstByName(const std::wstring& processName); 36 | DWORD StartProtocol(const std::wstring &command); 37 | DWORD StartProcess(const std::wstring &command, const std::wstring &arguments); 38 | HWND GetWindow(const std::wstring &processName, DWORD exStyle, const std::wstring &className, const std::wstring &windowTitle, DWORD style=0, DWORD noStyle=0); 39 | HWND GetWindow(const std::set& processIds, DWORD exStyle, const std::wstring &className =L"", const std::wstring &windowTitle=L"", DWORD style=0, DWORD noStyle=0); 40 | size_t FindAllByName(const std::wstring &processName, std::set & result); 41 | BOOL EnumWindowsAlt(HWND start, BOOL (*callback)(HWND, LPARAM), LPARAM lParam); 42 | bool BringWindowToForeground(HWND hWnd, int nShowCmd = SW_SHOWDEFAULT); 43 | } 44 | 45 | namespace Process = AnyFSE::Tools::Process; -------------------------------------------------------------------------------- /src/Logging/LogManager.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "Logger.hpp" 31 | 32 | namespace AnyFSE::Logging 33 | { 34 | class LogManager 35 | { 36 | friend class Logger; 37 | 38 | private: 39 | static std::ofstream LogWriter; 40 | static std::mutex WriteLock; 41 | static LogLevels Level; 42 | static std::string ApplicationName; 43 | static bool LogToConsole; 44 | static std::wstring FilePath; 45 | 46 | LogManager() {}; 47 | ~LogManager(); 48 | 49 | static std::string FormatString(const char* format, va_list args); 50 | // Helper methods 51 | static void WriteMessage(LogLevels level, const std::string &loggerName, const char* format, va_list args); 52 | 53 | public: 54 | static void DeleteLog(); 55 | static void Initialize(const std::string &appName, LogLevels level = LogLevels::Trace, const std::wstring &filePath = L""); 56 | static Logger GetLogger(const std::string &loggerName = ""); 57 | static const char * LogLevelToString(LogLevels level); 58 | }; 59 | } 60 | 61 | using namespace AnyFSE::Logging; 62 | -------------------------------------------------------------------------------- /src/Tools/Registry.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include 26 | #include 27 | 28 | namespace AnyFSE::Tools 29 | { 30 | class Registry 31 | { 32 | public: 33 | static std::wstring ReadString(const std::wstring &subKey, const std::wstring &valueName, const std::wstring &defaultValue = L""); 34 | static DWORD ReadDWORD(const std::wstring &subKey, const std::wstring &valueName, DWORD defaultValue = 0); 35 | static bool ReadBool(const std::wstring &subKey, const std::wstring &valueName, bool defaultValue = false); 36 | 37 | static bool WriteString(const std::wstring &subKey, const std::wstring &valueName, const std::wstring &value); 38 | static bool WriteDWORD(const std::wstring &subKey, const std::wstring &valueName, DWORD value); 39 | static bool WriteBool(const std::wstring &subKey, const std::wstring &valueName, bool value); 40 | static bool WriteBinary(const std::wstring &subKey, const std::wstring &valueName, const BYTE* data, DWORD size); 41 | 42 | // Utility methods 43 | static bool DeleteValue(const std::wstring &subKey, const std::wstring &valueName); 44 | static bool DeleteKey(const std::wstring &subKey); 45 | 46 | static HKEY GetRootKey(const std::wstring& subKey, std::wstring& actualPath); 47 | }; 48 | } 49 | using namespace AnyFSE::Tools; -------------------------------------------------------------------------------- /src/Tools/Unicode.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "Logging/LogManager.hpp" 31 | #include "Unicode.hpp" 32 | #include 33 | 34 | namespace AnyFSE::Tools::Unicode 35 | { 36 | std::string to_string(const std::wstring& wstr) 37 | { 38 | int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); 39 | if (len <= 0) return ""; 40 | 41 | std::string result; 42 | result.resize(len - 1); // Exact size needed 43 | WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &result[0], len, nullptr, nullptr); 44 | return result; 45 | } 46 | 47 | std::wstring to_wstring(const std::string& str) 48 | { 49 | int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0); 50 | if (len <= 0) return L""; 51 | 52 | std::wstring result; 53 | result.resize(len - 1); // Exact size needed 54 | MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &result[0], len); 55 | return result; 56 | } 57 | std::wstring to_lower(const std::wstring &str) 58 | { 59 | std::wstring wstr = str; 60 | std::transform(wstr.begin(), wstr.end(), wstr.begin(), ::towlower); 61 | return wstr; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/AppSettings/AppSettings.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include 26 | #include "Logging/LogManager.hpp" 27 | #include "Configuration/Config.hpp" 28 | #include "Tools/Process.hpp" 29 | 30 | #include "AppSettings/SettingsDialog.hpp" 31 | 32 | #pragma comment(lib, "comctl32.lib") 33 | #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 34 | 35 | 36 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) 37 | { 38 | 39 | return TRUE; 40 | } 41 | 42 | __declspec(dllexport) 43 | int WINAPI Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 44 | { 45 | HWND hDialogWnd = Process::GetWindow(std::set{GetCurrentProcessId()}, 0 , L"#32770", L""); 46 | if (hDialogWnd) 47 | { 48 | ShowWindow(hDialogWnd, SW_SHOWNORMAL); 49 | Process::BringWindowToForeground(hDialogWnd); 50 | return 0; 51 | } 52 | 53 | Config::Load(); 54 | Config::GetStartupConfigured(); 55 | 56 | AnyFSE::Logging::LogManager::Initialize("AnyFSE.Settings", Config::LogLevel, Config::LogPath); 57 | SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); 58 | 59 | int result = (int)AnyFSE::App::AppSettings::Settings::SettingsDialog().Show(hInstance); 60 | return result; 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /src/AppService/AppService.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | #pragma once 24 | 25 | #include 26 | #include "AppService/ETWMonitor.hpp" 27 | #include "AppService/AppServiceStateLoop.hpp" 28 | 29 | namespace AnyFSE::App::AppService 30 | { 31 | class AppService 32 | { 33 | static HWND m_hwnd; 34 | static ETWMonitor etwMonitor; 35 | static AppServiceStateLoop AppControlStateLoop; 36 | static bool xboxIsDenied; 37 | static const std::wstring XBoxProcessName; 38 | static bool m_suspended; 39 | 40 | public: 41 | static int WINAPI ServiceMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine); 42 | static BOOL ExitService(int nState); 43 | static void Restart(bool bSuspended = false); 44 | 45 | private: 46 | static bool IsSystemAccount(); 47 | static bool StartServiceTask(); 48 | static BOOL LaunchAppInUserSession(DWORD sessionId); 49 | 50 | static void RegisterSuspendEvent(); 51 | static void RegisterEvents(); 52 | 53 | static void StartMonitoring(bool bSuspended); 54 | static void StopMonitoring(); 55 | static void KillXbox(); 56 | static LRESULT BackgroundWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 57 | static void CreateBackgroundWindow(); 58 | static int MonitorSessions(); 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/StartupEditDlg.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Tools/Gdiplus.hpp" 4 | #include "FluentDesign/Theme.hpp" 5 | #include "FluentDesign/Dialog.hpp" 6 | #include "FluentDesign/Static.hpp" 7 | #include "FluentDesign/Button.hpp" 8 | #include "FluentDesign/TextBox.hpp" 9 | 10 | namespace AnyFSE::App::AppSettings::Settings 11 | { 12 | using namespace FluentDesign; 13 | class StartupEditDlg : protected Dialog 14 | { 15 | private: 16 | const int Layout_DialogWidth = 480; 17 | const int Layout_DialogHeight = 280; 18 | const int Layout_Margins = 16; 19 | const int Layout_CaptionHeight = 56; 20 | const int Layout_TextHeight = 30; 21 | const int Layout_ButtonWidth = 216; 22 | const int Layout_BrowseButtonWidth = 80; 23 | const int Layout_ButtonHeight = 32; 24 | const int Layout_EditHeight = 36; 25 | const int Layout_ButtonPadding = 16; 26 | 27 | std::wstring &m_refPath; 28 | std::wstring &m_refArgs; 29 | 30 | Button m_okButton; 31 | Button m_cancelButton; 32 | Button m_browseButton; 33 | 34 | TextBox m_pathEdit; 35 | TextBox m_argsEdit; 36 | 37 | Static m_captionStatic; 38 | Static m_pathStatic; 39 | Static m_argsStatic; 40 | 41 | StartupEditDlg(std::wstring& refPath, std::wstring &refArgs ) 42 | : Dialog() 43 | , m_refPath(refPath) 44 | , m_refArgs(refArgs) 45 | , m_okButton(m_theme) 46 | , m_cancelButton(m_theme) 47 | , m_browseButton(m_theme) 48 | , m_pathEdit(m_theme) 49 | , m_argsEdit(m_theme) 50 | , m_captionStatic(m_theme) 51 | , m_pathStatic(m_theme) 52 | , m_argsStatic(m_theme) 53 | {} 54 | 55 | void OnOk(); 56 | void OnCancel(); 57 | void OnBrowse(); 58 | 59 | void ValidatePath(); 60 | 61 | public: 62 | static INT_PTR EditApp(HWND hParent, std::wstring &refPath, std::wstring &refArgs); 63 | 64 | /** Interface **/ 65 | void Create(); 66 | float GetFooterDesignHeight() const { return float(Layout_Margins + Layout_ButtonHeight + Layout_ButtonPadding); } 67 | SIZE GetDialogDesignSize() { return SIZE{Layout_DialogWidth, Layout_DialogHeight}; } 68 | Theme::Colors GetDialogColor() { return Theme::Colors::Panel; }; 69 | Theme::Colors GetFooterColor() { return Theme::Colors::Footer; }; 70 | }; 71 | } -------------------------------------------------------------------------------- /src/AppSettings/SettingsDialog.tpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include "SettingsDialog.hpp" 28 | 29 | namespace AnyFSE::App::AppSettings::Settings 30 | { 31 | using namespace FluentDesign; 32 | 33 | template 34 | FluentDesign::SettingsLine& SettingsDialog::AddSettingsLine(std::list& page, 35 | ULONG &top, const std::wstring& name, const std::wstring& desc, T& control, 36 | int height, int padding, int contentMargin, int contentWidth, int contentHeight ) 37 | { 38 | RECT rect; 39 | GetDialogCenteredRect(m_theme, m_hDialog, &rect); 40 | int width = rect.right - rect.left 41 | - m_theme.DpiScale(Layout::MarginLeft - Layout::Border) 42 | - m_theme.DpiScale(Layout::MarginRight - Layout::Border); 43 | 44 | page.emplace_back( 45 | m_theme, m_hScrollView, name, desc, 46 | m_theme.DpiScale(Layout::MarginLeft - Layout::Border), 47 | top, width, 48 | m_theme.DpiScale(height), 49 | padding, 50 | [&](HWND parent) 51 | { 52 | control.Create(parent, 0, 0, m_theme.DpiScale(contentWidth), m_theme.DpiScale(contentHeight)); 53 | return control.GetHwnd(); 54 | } 55 | ); 56 | 57 | top += m_theme.DpiScale(height + padding); 58 | if (contentMargin) 59 | { 60 | page.back().SetLeftMargin(contentMargin); 61 | } 62 | 63 | return page.back(); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/FluentDesign/Toggle.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Tools/Event.hpp" 32 | #include "Theme.hpp" 33 | #include "FluentControl.hpp" 34 | 35 | namespace FluentDesign 36 | { 37 | class Toggle : public FluentControl 38 | { 39 | 40 | private: 41 | static const int Layout_ItemHeight = 20; 42 | static const int Layout_ItemWidth = 40; 43 | static const int Layout_TextWidth = 32; 44 | 45 | 46 | bool m_buttonPressed; 47 | bool m_buttonMouseOver; 48 | int m_pressedPos = 0; 49 | int m_thumbShift = 0; 50 | int m_pressedPath = 0; 51 | bool m_isChecked; 52 | 53 | static LRESULT CALLBACK ToggleSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 54 | UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 55 | 56 | void HandleMouse(HWND hWnd, UINT uMsg, LPARAM lParam); 57 | void DrawButton(HWND hWnd, HDC hdc, RECT rc); 58 | 59 | void UpdateLayout(); 60 | 61 | 62 | public: 63 | Toggle(Theme& theme); 64 | Toggle( 65 | Theme& theme, 66 | HWND hParent, 67 | int x, int y, 68 | int width, int height); 69 | 70 | HWND Create(HWND hParent, int x, int y, int width, int height); 71 | 72 | ~Toggle(); 73 | 74 | void SetCheck(bool isChecked); 75 | bool GetCheck(); 76 | Event OnChanged; 77 | }; 78 | } -------------------------------------------------------------------------------- /AnyFSE.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.14.36408.4 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnyFSE.Service", "AnyFSE.Service.vcxproj", "{4B2F1E9A-8C3D-4E76-9A1F-2D8C5A3B7E9F}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnyFSE.Settings", "AnyFSE.Settings.vcxproj", "{7F3A9B1C-82D4-4E5F-91A6-B8C7D2E4F619}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnyFSE", "AnyFSE.vcxproj", "{C4D8E9A2-1B7F-43C5-9D0E-F8A2B6C7D1E3}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Uninstaller", "AnyFSE.Uninstaller.vcxproj", "{A3F1C4B2-8D9E-4F67-92A1-5B3C8D7E6F4A}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|x64 = Debug|x64 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {4B2F1E9A-8C3D-4E76-9A1F-2D8C5A3B7E9F}.Debug|x64.ActiveCfg = Debug|x64 21 | {4B2F1E9A-8C3D-4E76-9A1F-2D8C5A3B7E9F}.Debug|x64.Build.0 = Debug|x64 22 | {4B2F1E9A-8C3D-4E76-9A1F-2D8C5A3B7E9F}.Release|x64.ActiveCfg = Release|x64 23 | {4B2F1E9A-8C3D-4E76-9A1F-2D8C5A3B7E9F}.Release|x64.Build.0 = Release|x64 24 | {A3B8C1D2-E4F5-6789-ABCD-EF0123456789}.Debug|x64.ActiveCfg = Debug|x64 25 | {A3B8C1D2-E4F5-6789-ABCD-EF0123456789}.Debug|x64.Build.0 = Debug|x64 26 | {A3B8C1D2-E4F5-6789-ABCD-EF0123456789}.Release|x64.ActiveCfg = Release|x64 27 | {A3B8C1D2-E4F5-6789-ABCD-EF0123456789}.Release|x64.Build.0 = Release|x64 28 | {7F3A9B1C-82D4-4E5F-91A6-B8C7D2E4F619}.Debug|x64.ActiveCfg = Debug|x64 29 | {7F3A9B1C-82D4-4E5F-91A6-B8C7D2E4F619}.Debug|x64.Build.0 = Debug|x64 30 | {7F3A9B1C-82D4-4E5F-91A6-B8C7D2E4F619}.Release|x64.ActiveCfg = Release|x64 31 | {7F3A9B1C-82D4-4E5F-91A6-B8C7D2E4F619}.Release|x64.Build.0 = Release|x64 32 | {C4D8E9A2-1B7F-43C5-9D0E-F8A2B6C7D1E3}.Debug|x64.ActiveCfg = Debug|x64 33 | {C4D8E9A2-1B7F-43C5-9D0E-F8A2B6C7D1E3}.Debug|x64.Build.0 = Debug|x64 34 | {C4D8E9A2-1B7F-43C5-9D0E-F8A2B6C7D1E3}.Release|x64.ActiveCfg = Release|x64 35 | {C4D8E9A2-1B7F-43C5-9D0E-F8A2B6C7D1E3}.Release|x64.Build.0 = Release|x64 36 | {A3F1C4B2-8D9E-4F67-92A1-5B3C8D7E6F4A}.Debug|x64.ActiveCfg = Debug|x64 37 | {A3F1C4B2-8D9E-4F67-92A1-5B3C8D7E6F4A}.Debug|x64.Build.0 = Debug|x64 38 | {A3F1C4B2-8D9E-4F67-92A1-5B3C8D7E6F4A}.Release|x64.ActiveCfg = Release|x64 39 | {A3F1C4B2-8D9E-4F67-92A1-5B3C8D7E6F4A}.Release|x64.Build.0 = Release|x64 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | GlobalSection(ExtensibilityGlobals) = postSolution 45 | SolutionGuid = {698B0A0D-0DE2-4FCC-A757-2755EDD033E1} 46 | EndGlobalSection 47 | EndGlobal 48 | -------------------------------------------------------------------------------- /src/Tools/Event.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include "Event.hpp" 26 | #include "Logging/LogManager.hpp" 27 | 28 | namespace AnyFSE::Tools 29 | { 30 | static Logger log = LogManager::GetLogger("Event"); 31 | 32 | Event::Event(std::function callback) 33 | { 34 | callbacks.push_back(callback); 35 | } 36 | 37 | void Event::Clear() 38 | { 39 | callbacks.clear(); 40 | } 41 | 42 | bool Event::HasSubscribe() 43 | { 44 | return callbacks.size(); 45 | } 46 | 47 | void Event::operator=(std::function callback) 48 | { 49 | callbacks.clear(); 50 | callbacks.push_back(callback); 51 | } 52 | 53 | void Event::operator+=(std::function callback) 54 | { 55 | callbacks.push_back(callback); 56 | } 57 | 58 | // Remove callback (equivalent to C# -=) 59 | void Event::operator-=(const std::function& callback) 60 | { 61 | callbacks.erase( 62 | std::remove_if(callbacks.begin(), callbacks.end(), 63 | [&callback](const std::function& func) { 64 | // Compare the target addresses (limited but works for some cases) 65 | return func.target_type() == callback.target_type() && 66 | func.target() == callback.target(); 67 | }), 68 | callbacks.end() 69 | ); 70 | } 71 | 72 | void Event::Notify() 73 | { 74 | for (auto& callback : callbacks) 75 | { 76 | if (callback) 77 | { 78 | callback(); 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/Tools/Window.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "Logging/LogManager.hpp" 31 | #include "Tools/Window.hpp" 32 | #include 33 | #include 34 | #include "Packages.hpp" 35 | 36 | 37 | namespace AnyFSE::Tools::Window 38 | { 39 | static Logger log = LogManager::GetLogger("Tools/Window"); 40 | 41 | BOOL GetChildRect(HWND hwnd, RECT * rect) 42 | { 43 | GetWindowRect(hwnd, rect); 44 | MapWindowPoints(NULL, GetParent(hwnd), (LPPOINT)rect, 2); 45 | return TRUE; 46 | } 47 | 48 | BOOL MoveWindow(HWND hwnd, int dx, int dy, BOOL bRepaint) 49 | { 50 | RECT rect; 51 | GetChildRect(hwnd, &rect); 52 | OffsetRect(&rect, dx, dy); 53 | ::MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, bRepaint); 54 | return TRUE; 55 | } 56 | 57 | BOOL MoveWindow(HWND hwnd, RECT* rect, BOOL bRepaint) 58 | { 59 | ::MoveWindow(hwnd, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, bRepaint); 60 | return TRUE; 61 | } 62 | 63 | BOOL MouseInClientRect(HWND hWnd, RECT *rect, int inflate) 64 | { 65 | RECT hitRect; 66 | if (rect == NULL) 67 | { 68 | GetClientRect(hWnd, &hitRect); 69 | } 70 | else 71 | { 72 | hitRect = *rect; 73 | } 74 | 75 | InflateRect(&hitRect, inflate, inflate); 76 | 77 | POINT pt; 78 | GetCursorPos(&pt); 79 | MapWindowPoints(NULL, hWnd, &pt, 1); 80 | 81 | return PtInRect(&hitRect, pt); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Logging/Logger.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | #ifdef _TRACE 27 | #define TRACE log.Trace 28 | #else 29 | #define TRACE(...) 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | namespace AnyFSE::Logging 38 | { 39 | enum class LogLevels 40 | { 41 | Disabled, 42 | Critical, 43 | Error, 44 | Warn, 45 | Info, 46 | Debug, 47 | Trace, 48 | Max 49 | }; 50 | 51 | class Logger 52 | { 53 | friend class LogManager; 54 | private: 55 | std::string m_loggerName; 56 | void WriteMessage(LogLevels level, const char * format, va_list args = NULL); 57 | 58 | public: 59 | Logger(const std::string& name); 60 | static std::exception APIError(DWORD errorCode = 0, const char * prefix = ""); 61 | static std::exception APIError(const char * prefix); 62 | void Trace(const char * format, ...); 63 | void Trace(const std::exception &exception, const char * format, ...); 64 | void Debug(const char * format, ...); 65 | void Debug(const std::exception &exception, const char * format, ...); 66 | void Info(const char * format, ...); 67 | void Info(const std::exception &exception, const char * format, ...); 68 | void Warn(const char * format, ...); 69 | void Warn(const std::exception &exception, const char * format, ...); 70 | void Error(const char * format, ...); 71 | void Error(const std::exception &exception, const char * format, ...); 72 | void Critical(const char * format, ...); 73 | void Critical(const std::exception &exception, const char * format, ...); 74 | }; 75 | } 76 | 77 | using namespace AnyFSE::Logging; 78 | -------------------------------------------------------------------------------- /src/AppControl/Launchers.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include "Logging/LogManager.hpp" 28 | #include "Configuration/Config.hpp" 29 | #include "Launchers.hpp" 30 | 31 | 32 | namespace AnyFSE::App::AppControl::Launchers 33 | { 34 | static Logger log = LogManager::GetLogger("Launchers"); 35 | 36 | void LauncherOnBoot() 37 | { 38 | switch (Config::Launcher.Type) 39 | { 40 | case LauncherType::PlayniteDesktop: 41 | case LauncherType::PlayniteFullscreen: 42 | return PlayniteOnBoot(); 43 | }; 44 | } 45 | 46 | void PlayniteOnBoot() 47 | { 48 | if (Config::CleanupFailedStart) 49 | { 50 | log.Debug("Cleanup Playnite safe startup flag"); 51 | 52 | namespace fs = std::filesystem; 53 | fs::path path = fs::path(Config::Launcher.StartCommand); 54 | 55 | fs::path configPath = path.parent_path(); 56 | bool isPortable = !fs::exists(configPath.append(L"unins000.exe")); 57 | 58 | if (!isPortable) 59 | { 60 | log.Debug("Playnite is not portable, config is in %%APPDATA%%"); 61 | 62 | wchar_t buffer[MAX_PATH] = {0}; 63 | if (ExpandEnvironmentStringsW(L"%APPDATA%\\Playnite", buffer, MAX_PATH)) 64 | { 65 | configPath = fs::path(buffer); 66 | } 67 | } 68 | 69 | fs::path flagFile = configPath.append(L"safestart.flag"); 70 | 71 | if(fs::exists(flagFile)) 72 | { 73 | log.Debug("Safestart flag is exist at %s, deleting", flagFile.string().c_str()); 74 | fs::remove(flagFile); 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/AppService/AppServiceStateLoop.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #include "Configuration/Config.hpp" 25 | #include "Tools/Process.hpp" 26 | #include "Logging/LogManager.hpp" 27 | #include "AppService/AppServiceStateLoop.hpp" 28 | 29 | namespace AnyFSE::App::AppService::StateLoop 30 | { 31 | static Logger log = LogManager::GetLogger("Manager/Service"); 32 | 33 | AppServiceStateLoop::AppServiceStateLoop() : AppStateLoop(true) {} 34 | 35 | AppServiceStateLoop::~AppServiceStateLoop() {} 36 | 37 | void AppServiceStateLoop::ProcessEvent(AppEvents event) 38 | { 39 | switch (event) 40 | { 41 | case AppEvents::CONNECT: 42 | log.Info("AppControl connected" ); 43 | OnConnect.Notify(); 44 | NotifyRemote(event); 45 | return; 46 | case AppEvents::RELOAD_SERVICE: 47 | return OnReload.Notify(); 48 | 49 | case AppEvents::LAUNCHER_STOPPED: 50 | case AppEvents::XBOX_DETECTED: 51 | case AppEvents::OPEN_HOME: 52 | case AppEvents::OPEN_DEVICE_FORM: 53 | NotifyRemote(event); 54 | return; 55 | 56 | case AppEvents::XBOX_DENY: 57 | return OnXboxDeny.Notify(); 58 | 59 | case AppEvents::XBOX_ALLOW: 60 | return OnXboxAllow.Notify(); 61 | 62 | case AppEvents::EXIT_SERVICE: 63 | return OnExit.Notify(); 64 | 65 | case AppEvents::RESTART_SERVICE: 66 | return OnRestart.Notify(); 67 | 68 | case AppEvents::DISCONNECT: 69 | case AppEvents::SUSPEND_SERVICE: 70 | return OnSuspend.Notify(); 71 | 72 | default: 73 | log.Trace("Recieved event by service %d", event); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/LauncherPage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Configuration/Config.hpp" 5 | #include "FluentDesign/Theme.hpp" 6 | #include "FluentDesign/ComboBox.hpp" 7 | #include "FluentDesign/TextBox.hpp" 8 | #include "FluentDesign/Toggle.hpp" 9 | #include "AppSettings/SettingsPages/SettingsPage.hpp" 10 | 11 | namespace AnyFSE::App::AppSettings::Settings::Page 12 | { 13 | using namespace FluentDesign; 14 | 15 | class LauncherPage : public SettingsPage 16 | { 17 | Theme &m_theme; 18 | SettingsDialog &m_dialog; 19 | 20 | public: 21 | LauncherPage(Theme& theme, SettingsDialog &dialog) 22 | : m_theme(theme) 23 | , m_dialog(dialog) 24 | , m_launcherCombo(m_theme) 25 | , m_browseButton(m_theme) 26 | , m_fseOnStartupToggle(m_theme) 27 | , m_customSettingsToggle(m_theme) 28 | , m_additionalArgumentsEdit(m_theme) 29 | , m_processNameEdit(m_theme) 30 | , m_titleEdit(m_theme) 31 | , m_classEdit(m_theme) 32 | , m_processNameAltEdit(m_theme) 33 | , m_titleAltEdit(m_theme) 34 | , m_classAltEdit(m_theme) 35 | , m_customResetButton(m_theme) 36 | , m_customSettingsState(SettingsLine::Closed) 37 | {} 38 | 39 | std::list &GetSettingsLines() { return m_pageLinesList; }; 40 | 41 | void AddPage(std::list& settingPageList, ULONG &top); 42 | void LoadControls(); 43 | void SaveControls(); 44 | 45 | private: 46 | std::list m_pageLinesList; 47 | 48 | bool m_isCustom = false; 49 | bool m_isAggressive = false; 50 | bool m_enterOnStartup = false; 51 | 52 | LauncherConfig m_config; 53 | LauncherConfig m_defaultConfig; 54 | std::wstring m_currentLauncherPath; 55 | std::list m_launchersList; 56 | 57 | 58 | ComboBox m_launcherCombo; 59 | Button m_browseButton; 60 | Toggle m_fseOnStartupToggle; 61 | Toggle m_customSettingsToggle; 62 | Button m_customResetButton; 63 | 64 | TextBox m_additionalArgumentsEdit; 65 | TextBox m_processNameEdit; 66 | TextBox m_titleEdit; 67 | TextBox m_classEdit; 68 | TextBox m_processNameAltEdit; 69 | TextBox m_titleAltEdit; 70 | TextBox m_classAltEdit; 71 | 72 | SettingsLine * m_pFseOnStartupLine = nullptr; 73 | SettingsLine * m_pCustomSettingsLine = nullptr; 74 | 75 | SettingsLine::State m_customSettingsState; 76 | 77 | void AddCustomPage(); 78 | 79 | void OnBrowseLauncher(); 80 | void OnCustomChanged(); 81 | void OnCustomReset(); 82 | void UpdateCustomResetEnabled(); 83 | void OpenSettingsPage(); 84 | void OpenCustomSettingsPage(); 85 | void UpdateControls(); 86 | void OnLauncherChanged(); 87 | void UpdateCombo(); 88 | void UpdateCustomSettings(); 89 | }; 90 | }; -------------------------------------------------------------------------------- /src/Tools/DoubleBufferedPaint.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include 26 | 27 | namespace FluentDesign 28 | { 29 | class DoubleBuferedPaint 30 | { 31 | PAINTSTRUCT m_ps; 32 | RECT m_rect; 33 | HDC m_hdc; 34 | HDC m_hdcMem; 35 | HBITMAP m_hbmMem; 36 | HBITMAP m_hOldBitmap; 37 | int m_width; 38 | int m_height; 39 | HWND m_hWnd; 40 | 41 | public: 42 | DoubleBuferedPaint(HWND hwnd) 43 | : m_hWnd(hwnd) 44 | { 45 | m_hdc = BeginPaint(m_hWnd, &m_ps); 46 | GetClientRect(m_hWnd, &m_rect); 47 | m_width = m_rect.right - m_rect.left; 48 | m_height = m_rect.bottom - m_rect.top; 49 | 50 | // === DOUBLE BUFFERING START === 51 | m_hdcMem = CreateCompatibleDC(m_hdc); 52 | m_hbmMem = CreateCompatibleBitmap(m_hdc, m_width, m_height); 53 | m_hOldBitmap = (HBITMAP)SelectObject(m_hdcMem, m_hbmMem); 54 | 55 | HWND parent = GetParent(m_hWnd); 56 | if (parent) 57 | { 58 | SendMessage(parent, WM_ERASEBKGND, (WPARAM)m_hdcMem, (LPARAM)m_hWnd); 59 | } 60 | } 61 | 62 | HDC MemDC() 63 | { 64 | return m_hdcMem; 65 | } 66 | 67 | RECT ClientRect() 68 | { 69 | return m_rect; 70 | } 71 | 72 | ~DoubleBuferedPaint() 73 | { 74 | // === DOUBLE BUFFERING - COPY TO SCREEN === 75 | BitBlt(m_hdc, 0, 0, m_width, m_height, m_hdcMem, 0, 0, SRCCOPY); 76 | 77 | // === CLEANUP DOUBLE BUFFERING === 78 | SelectObject(m_hdcMem, m_hOldBitmap); 79 | SelectClipRgn(m_hdc, NULL); 80 | DeleteObject(m_hbmMem); 81 | DeleteDC(m_hdcMem); 82 | 83 | EndPaint(m_hWnd, &m_ps); 84 | } 85 | }; 86 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "explorer.fileNesting.enabled": true, 3 | "explorer.fileNesting.patterns": { 4 | "*.cpp": "${basename}.h, ${basename}.hpp, ${basename}.tpp, ${basename}.cpp, ${basename}_*.cpp", 5 | "*.sln": "${basename}.*.vcxproj, ${basename}.vcxproj.*, ${basename}.*.vcxproj.user, ${basename}.vcxproj, ${basename}.sln, ${basename}.suo, ${basename}.*.props", 6 | "*.rc" : "${basename}.rc, ${basename}.h, ${basename}.aps" 7 | }, 8 | "explorer.excludeGitIgnore": true, 9 | "files.associations": { 10 | "Makefile": "makefile", 11 | "*.script": "lua", 12 | "*.xaml": "xml", 13 | "*.reds": "redscript", 14 | "xtree": "cpp", 15 | "xutility": "cpp", 16 | "xstring": "cpp", 17 | "algorithm": "cpp", 18 | "atomic": "cpp", 19 | "bit": "cpp", 20 | "cctype": "cpp", 21 | "charconv": "cpp", 22 | "clocale": "cpp", 23 | "cmath": "cpp", 24 | "compare": "cpp", 25 | "concepts": "cpp", 26 | "cstdarg": "cpp", 27 | "cstddef": "cpp", 28 | "cstdint": "cpp", 29 | "cstdio": "cpp", 30 | "cstdlib": "cpp", 31 | "cstring": "cpp", 32 | "ctime": "cpp", 33 | "cwchar": "cpp", 34 | "exception": "cpp", 35 | "format": "cpp", 36 | "fstream": "cpp", 37 | "initializer_list": "cpp", 38 | "ios": "cpp", 39 | "iosfwd": "cpp", 40 | "iostream": "cpp", 41 | "istream": "cpp", 42 | "iterator": "cpp", 43 | "limits": "cpp", 44 | "list": "cpp", 45 | "locale": "cpp", 46 | "map": "cpp", 47 | "memory": "cpp", 48 | "new": "cpp", 49 | "optional": "cpp", 50 | "ostream": "cpp", 51 | "sstream": "cpp", 52 | "stdexcept": "cpp", 53 | "streambuf": "cpp", 54 | "string": "cpp", 55 | "system_error": "cpp", 56 | "tuple": "cpp", 57 | "type_traits": "cpp", 58 | "typeinfo": "cpp", 59 | "utility": "cpp", 60 | "vector": "cpp", 61 | "xfacet": "cpp", 62 | "xiosbase": "cpp", 63 | "xlocale": "cpp", 64 | "xlocbuf": "cpp", 65 | "xlocinfo": "cpp", 66 | "xlocmes": "cpp", 67 | "xlocmon": "cpp", 68 | "xlocnum": "cpp", 69 | "xloctime": "cpp", 70 | "xmemory": "cpp", 71 | "xtr1common": "cpp", 72 | "iomanip": "cpp", 73 | "mutex": "cpp", 74 | "ratio": "cpp", 75 | "stop_token": "cpp", 76 | "thread": "cpp", 77 | "functional": "cpp", 78 | "filesystem": "cpp", 79 | "chrono": "cpp", 80 | "forward_list": "cpp", 81 | "unordered_map": "cpp", 82 | "xhash": "cpp", 83 | "*.c_pp": "cpp", 84 | "condition_variable": "cpp", 85 | "deque": "cpp", 86 | "queue": "cpp", 87 | "set": "cpp", 88 | "any": "cpp", 89 | "array": "cpp", 90 | "numeric": "cpp", 91 | "ranges": "cpp", 92 | "span": "cpp", 93 | "valarray": "cpp", 94 | "coroutine": "cpp", 95 | "source_location": "cpp" 96 | } 97 | } -------------------------------------------------------------------------------- /src/FluentDesign/Static.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Tools/GdiPlus.hpp" 32 | #include "Tools/Event.hpp" 33 | #include "Theme.hpp" 34 | #include "FluentControl.hpp" 35 | 36 | namespace FluentDesign 37 | { 38 | class Static : public FluentControl 39 | { 40 | 41 | private: 42 | int m_designWidth = 0; 43 | int m_designHeight = 0; 44 | 45 | bool m_large; 46 | 47 | std::wstring m_text; 48 | Theme::Colors m_colorId; 49 | Gdiplus::StringFormat m_format; 50 | Gdiplus::Image * m_pImage; 51 | 52 | static LRESULT CALLBACK StaticSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 53 | UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 54 | 55 | void DrawStatic(HWND hWnd, HDC hdc, RECT rc); 56 | 57 | void UpdateLayout(); 58 | 59 | public: 60 | Static(Theme &theme, Align::Anchor align = Align::None, GetParentRectFunc getParentRect = GetParentRect); 61 | Static( 62 | Theme& theme, 63 | HWND hParent, 64 | int x, int y, 65 | int width, int height); 66 | 67 | Static& SetAnchor(Align::Anchor anchor, GetParentRectFunc getParentRect = GetParentRect) 68 | { 69 | FluentControl::SetAnchor(anchor, getParentRect); 70 | return *this; 71 | } 72 | 73 | HWND Create(HWND hParent, const std::wstring &text, int x, int y, int width, int height); 74 | 75 | HWND Create(HWND hParent, int x, int y, int width, int height); 76 | 77 | void SetText(const std::wstring& text); 78 | 79 | void SetColor(Theme::Colors colorId); 80 | void SetLarge(bool large); 81 | void Invalidate(); 82 | Gdiplus::StringFormat &Format() { return m_format; }; 83 | void LoadIcon(const std::wstring &iconPath, int iconSize); 84 | 85 | ~Static(); 86 | }; 87 | } -------------------------------------------------------------------------------- /src/FluentDesign/TextBox.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Theme.hpp" 32 | #include "FluentControl.hpp" 33 | #include "Tools/Event.hpp" 34 | 35 | namespace FluentDesign 36 | { 37 | 38 | class TextBox : public FluentControl 39 | { 40 | private: 41 | HWND m_hTextBox = nullptr; 42 | HWND m_hParent = nullptr; 43 | 44 | int m_borderWidth = 1; 45 | 46 | int m_cornerRadius = 8; 47 | int m_marginLeft = 8; 48 | int m_marginRight = 8; 49 | int m_marginTop = 8; 50 | int m_marginBottom = 8; 51 | 52 | 53 | // State 54 | bool m_hasFocus = false; 55 | bool m_mouseOver = false; 56 | 57 | int m_designedWidth = 0; 58 | 59 | // Text 60 | std::wstring m_placeholder; 61 | bool m_showPlaceholder = false; 62 | 63 | public: 64 | TextBox(Theme &theme); 65 | TextBox( 66 | Theme& theme, 67 | HWND hParent, 68 | int x, int y, 69 | int width, int height); 70 | 71 | ~TextBox(); 72 | 73 | HWND Create(HWND hParent, int x, int y, int width, int height); 74 | void Destroy(); 75 | 76 | HWND GetTextBoxHandle() const { return m_hTextBox; } 77 | std::wstring GetText() const; 78 | 79 | // Setters 80 | void SetText(const std::wstring &text); 81 | void UpdateLayout(); 82 | 83 | void Show(bool bShow); 84 | 85 | Event OnChanged; 86 | 87 | 88 | private: 89 | void OnSize(); 90 | void UpdateTextBoxColors(); 91 | void Invalidate(); 92 | void DrawContainer(HDC hdc); 93 | static LRESULT CALLBACK ContainerSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 94 | static LRESULT CALLBACK TextBoxSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 95 | }; 96 | 97 | } // namespace FluentDesign -------------------------------------------------------------------------------- /src/AppControl/VideoPlayer.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace AnyFSE::App::AppControl::Window 33 | { 34 | class CriticalSectionLock { 35 | private: 36 | CRITICAL_SECTION* m_cs; 37 | 38 | public: 39 | explicit CriticalSectionLock(CRITICAL_SECTION* cs) : m_cs(cs) { 40 | EnterCriticalSection(m_cs); 41 | } 42 | 43 | ~CriticalSectionLock() { 44 | LeaveCriticalSection(m_cs); 45 | } 46 | 47 | // Prevent copying 48 | CriticalSectionLock(const CriticalSectionLock&) = delete; 49 | CriticalSectionLock& operator=(const CriticalSectionLock&) = delete; 50 | }; 51 | 52 | class SimpleVideoPlayer : public IMFPMediaPlayerCallback 53 | { 54 | private: 55 | IMFPMediaPlayer *m_pPlayer; 56 | HWND m_hwndVideo; 57 | BOOL m_bInitialized; 58 | bool m_loop; 59 | bool m_pause; 60 | 61 | DWORD m_startLoop; 62 | DWORD m_endLoop; 63 | DWORD m_duration; 64 | bool m_mutedLoop; 65 | 66 | std::wstring m_loadedVideo; 67 | 68 | volatile long m_refCount; 69 | 70 | MFP_MEDIAPLAYER_STATE m_desiredState; 71 | CRITICAL_SECTION m_cs; 72 | 73 | void ParseLoopTimings(const std::wstring& path); 74 | 75 | DWORD GetDuration(IMFPMediaPlayer *player); 76 | HRESULT Rewind(IMFPMediaPlayer *player, DWORD position); 77 | BOOL ShowVideo(bool bShow=true); 78 | 79 | public: 80 | SimpleVideoPlayer(); 81 | ~SimpleVideoPlayer(); 82 | 83 | // Combined load and play 84 | HRESULT Load(const WCHAR *videoFile, bool mute, bool loop, bool pause, HWND hwndParent); 85 | HRESULT Play(); 86 | HRESULT Stop(); 87 | void Close(); 88 | void Resize(); 89 | 90 | ULONG AddRef(); 91 | HRESULT QueryInterface(REFIID riid, void **ppv); 92 | ULONG Release(); 93 | 94 | void OnMediaPlayerEvent(MFP_EVENT_HEADER *pEventHeader); 95 | }; 96 | } -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/TroubleshootPage.cpp: -------------------------------------------------------------------------------- 1 | #include "Tools/Event.hpp" 2 | #include "Tools/Unicode.hpp" 3 | #include "Logging/LogManager.hpp" 4 | #include "AppSettings/SettingsLayout.hpp" 5 | #include "AppSettings/SettingsDialog.hpp" 6 | #include "TroubleshootPage.hpp" 7 | 8 | 9 | namespace AnyFSE::App::AppSettings::Settings::Page 10 | { 11 | void TroubleshootPage::AddPage(std::list& settingPageList, ULONG &top) 12 | { 13 | SettingsLine & dialogLine = m_dialog.AddSettingsLine(settingPageList, top, 14 | L"Debug and Troubleshoot", 15 | L"Configure logs and advanced parameters", 16 | Layout::LineHeight, Layout::LinePadding, 0); 17 | 18 | dialogLine.SetState(FluentDesign::SettingsLine::Next); 19 | dialogLine.SetIcon(L'\xEBE8'); 20 | dialogLine.OnChanged += delegate(OpenTroubleshootSettingsPage); 21 | 22 | ULONG topPage = 0; 23 | FluentDesign::SettingsLine &logLevel = m_dialog.AddSettingsLine(m_pageLinesList, 24 | topPage, 25 | L"Log level", 26 | L"Enable logs at specified level", 27 | m_troubleLogLevelCombo, 28 | Layout::LineHeight, Layout::LinePadding, 0, 29 | Layout::LauncherComboWidth); 30 | 31 | logLevel.OnLink = delegate(OnGotoLogsFolder); 32 | 33 | for (int i = (int)LogLevels::Disabled; i < (int)LogLevels::Max; i++) 34 | { 35 | std::wstring level = Unicode::to_wstring(LogManager::LogLevelToString((LogLevels)i)); 36 | wchar_t buff[2] = {(wchar_t)i, 0}; 37 | m_troubleLogLevelCombo.AddItem(level, L"", buff); 38 | } 39 | 40 | m_dialog.AddSettingsLine(m_pageLinesList, 41 | topPage, 42 | L"Aggressive Mode", 43 | L"More simple and robust logic on XboxApp start, but you will lose any manual access to the XboxApp", 44 | m_troubleAggressiveToggle, 45 | Layout::LineHeight, Layout::LinePadding, 0); 46 | 47 | m_dialog.AddSettingsLine(m_pageLinesList, 48 | topPage, 49 | L"Leave full screen on Home app exit", 50 | L"Exit to desktop mode after Home app was exited", 51 | m_troubleExitOnExitToggle, 52 | Layout::LineHeight, Layout::LinePadding, 0); 53 | } 54 | 55 | void TroubleshootPage::LoadControls() 56 | { 57 | m_troubleLogLevelCombo.SelectItem(min(max((int)LogLevels::Disabled, (int)Config::LogLevel), (int)LogLevels::Max)); 58 | m_troubleAggressiveToggle.SetCheck(Config::AggressiveMode); 59 | m_troubleExitOnExitToggle.SetCheck(Config::ExitFSEOnHomeExit); 60 | } 61 | 62 | void TroubleshootPage::SaveControls() 63 | { 64 | Config::LogLevel = (LogLevels)m_troubleLogLevelCombo.GetSelectedIndex(); 65 | Config::AggressiveMode = m_troubleAggressiveToggle.GetCheck(); 66 | Config::ExitFSEOnHomeExit = m_troubleExitOnExitToggle.GetCheck(); 67 | } 68 | 69 | void TroubleshootPage::OpenTroubleshootSettingsPage() 70 | { 71 | m_dialog.SwitchActivePage(L"Troubleshoot", &m_pageLinesList); 72 | } 73 | 74 | void TroubleshootPage::OnGotoLogsFolder() 75 | { 76 | std::wstring path = Config::GetModulePath() + L"\\logs"; 77 | 78 | CreateDirectoryW(path.c_str(), NULL); 79 | Process::StartProtocol(L"\"" + path + L"\""); 80 | } 81 | 82 | }; -------------------------------------------------------------------------------- /src/FluentDesign/ScrollView.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Tools/Event.hpp" 32 | #include "Theme.hpp" 33 | #include "FluentControl.hpp" 34 | 35 | namespace FluentDesign 36 | { 37 | class ScrollView : public FluentControl 38 | { 39 | static LRESULT CALLBACK ScrollViewSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 40 | UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 41 | 42 | int m_contentHeight; 43 | int m_scrollPos; 44 | int m_viewHeight = 0; 45 | 46 | RECT m_scrollBarRect; 47 | RECT m_thumbRect; 48 | 49 | bool m_hovered; 50 | bool m_dragging; 51 | int m_dragStartScrollPos; 52 | int m_dragStartMousePos; 53 | 54 | void SetOffset(int newOffset); 55 | 56 | void CalculateRects(); 57 | LRESULT OnPaint(HWND hWnd); 58 | 59 | public: 60 | ScrollView(Theme &theme, Align::Anchor align = Align::Client(), GetParentRectFunc getParentRect = GetParentRect); 61 | ScrollView(Theme& theme, HWND hParent, int x, int y, int width, int height); 62 | 63 | ScrollView& SetAnchor(Align::Anchor anchor, GetParentRectFunc getParentRect = GetParentRect) 64 | { 65 | FluentControl::SetAnchor(anchor, getParentRect); 66 | return *this; 67 | } 68 | 69 | HWND Create(HWND hParent, int x, int y, int width, int height); 70 | 71 | void SetContentHeight(int newHeight); 72 | void UpdateScrollBar(); 73 | void ScrollTo(int newPos); 74 | void EnsureVisible(const RECT &rcItem); 75 | void ScrollBy(int delta); 76 | int GetScrollPos() const; 77 | 78 | ~ScrollView(); 79 | 80 | void OnResize(int newWidth, int newHeight); 81 | 82 | LRESULT OnVScroll(int nScrollCode, int nPos); 83 | LRESULT OnMouseWheel(int delta); 84 | LRESULT OnMouseMove(); 85 | LRESULT OnMouseLeave(); 86 | LRESULT OnLButtonDown(); 87 | LRESULT OnLButtonUp(); 88 | LRESULT OnEraseBkgnd(HDC hdc, HWND child); 89 | }; 90 | } -------------------------------------------------------------------------------- /src/Tools/Notification.cpp: -------------------------------------------------------------------------------- 1 | #include "Tools/Notification.hpp" 2 | #include "Tools/Unicode.hpp" 3 | #include "resource.h" 4 | #include 5 | #include "Notification.hpp" 6 | 7 | #ifndef VER_VERSION_STR 8 | #define VER_VERSION_STR "0.0.0" 9 | #endif 10 | 11 | namespace AnyFSE::Tools 12 | { 13 | void Notification::Show(HWND hwnd, const std::wstring& title, const std::wstring& message, const std::wstring& /*launchUrl*/ ) 14 | { 15 | bool createdWindow = false; 16 | HWND hWnd = hwnd; 17 | 18 | // If no hwnd provided, create a temporary hidden window and add an icon 19 | WNDCLASSW wc = {0}; 20 | if (!hWnd) 21 | { 22 | createdWindow = true; 23 | wc.lpfnWndProc = DefWindowProcW; 24 | wc.hInstance = GetModuleHandleW(NULL); 25 | wc.lpszClassName = L"AnyFSE_Updater_NotifyWnd"; 26 | RegisterClassW(&wc); 27 | 28 | hWnd = CreateWindowExW(0, wc.lpszClassName, L"", 0, 0,0,0,0, HWND_MESSAGE, NULL, wc.hInstance, NULL); 29 | if (!hWnd) { 30 | UnregisterClassW(wc.lpszClassName, wc.hInstance); 31 | return; 32 | } 33 | 34 | NOTIFYICONDATAW notifyData = {0}; 35 | notifyData.cbSize = sizeof(notifyData); 36 | notifyData.hWnd = hWnd; 37 | notifyData.uID = 1; 38 | notifyData.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; 39 | notifyData.hIcon = LoadIconW(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON)); 40 | wcscpy_s(notifyData.szTip, _countof(notifyData.szTip), L"AnyFSE"); 41 | Shell_NotifyIconW(NIM_ADD, ¬ifyData); 42 | } 43 | 44 | // Show balloon/info using provided or created hwnd. We assume uID==1 for the icon. 45 | NOTIFYICONDATAW notifyInfo = {0}; 46 | notifyInfo.cbSize = sizeof(notifyInfo); 47 | notifyInfo.hWnd = hWnd; 48 | notifyInfo.uID = 1; 49 | notifyInfo.uFlags = NIF_INFO; 50 | wcscpy_s(notifyInfo.szInfoTitle, _countof(notifyInfo.szInfoTitle), title.c_str()); 51 | wcscpy_s(notifyInfo.szInfo, _countof(notifyInfo.szInfo), message.c_str()); 52 | notifyInfo.dwInfoFlags = NIIF_INFO; 53 | 54 | Shell_NotifyIconW(NIM_MODIFY, ¬ifyInfo); 55 | 56 | // If we created the window/icon, remove it after a short delay 57 | if (createdWindow) 58 | { 59 | Sleep(1000); 60 | NOTIFYICONDATAW notifyDelete = {0}; 61 | notifyDelete.cbSize = sizeof(notifyDelete); 62 | notifyDelete.hWnd = hWnd; 63 | notifyDelete.uID = 1; 64 | Shell_NotifyIconW(NIM_DELETE, ¬ifyDelete); 65 | DestroyWindow(hWnd); 66 | UnregisterClassW(wc.lpszClassName, wc.hInstance); 67 | } 68 | } 69 | void Notification::ShowNewVersion(HWND hwnd, const std::wstring &version, const std::wstring &launchUrl) 70 | { 71 | if (version.empty()) 72 | { 73 | return; 74 | } 75 | std::wstring msg = L"New version " + version + L" is available."; 76 | Tools::Notification::Show(hwnd, L"AnyFSE Update available", msg); 77 | } 78 | 79 | void Notification::ShowCurrentVersion(HWND hwnd, bool installed) 80 | { 81 | std::wstring msg = L"Current version is " + Unicode::to_wstring(VER_VERSION_STR); 82 | Tools::Notification::Show(hwnd, installed ? L"AnyFSE was installed" : L"AnyFSE was updated", msg); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/FluentDesign/Popup.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Tools/Event.hpp" 32 | #include "Theme.hpp" 33 | #include "FluentControl.hpp" 34 | 35 | namespace FluentDesign 36 | { 37 | class Popup : public FluentControl 38 | { 39 | public: 40 | struct PopupItem 41 | { 42 | std::wstring name; 43 | std::wstring icon; 44 | std::function callback; 45 | 46 | PopupItem(const std::wstring& itemGlyph, const std::wstring& itemName, std::function itemCallback) 47 | : name(itemName) 48 | , icon(itemGlyph) 49 | , callback(itemCallback) 50 | {} 51 | }; 52 | private: 53 | static const int Layout_ItemHeight = 38; 54 | static const int Layout_LeftMargin = 16; 55 | static const int Layout_ImageSize = 18; 56 | static const int Layout_IconMargin = 8; 57 | static const int Layout_CornerRadius = 8; 58 | 59 | bool m_popupVisible; 60 | int m_selectedIndex; 61 | int m_hoveredIndex; 62 | std::vector m_popupItems; 63 | 64 | public: 65 | Popup(Theme &theme) 66 | : FluentControl(theme) 67 | , m_selectedIndex(-1) 68 | , m_hoveredIndex(-1) 69 | , m_popupVisible(false) 70 | { 71 | } 72 | 73 | HWND GetHwnd() { return m_popupVisible ? m_hWnd : nullptr; } 74 | 75 | void Show(HWND hParent, int x, int y, const std::vector& items, int width, int flags = TPM_RIGHTALIGN); 76 | void Hide(); 77 | 78 | void OnPaint(HWND hWnd); 79 | void OnMouseMove(HWND hWnd, LPARAM lParam); 80 | void OnLButtonDown(HWND hWnd, LPARAM lParam); 81 | void OnCaptureChanged(HWND hWnd, LPARAM lParam); 82 | void OnKeyDown(HWND hWnd, WPARAM wParam); 83 | 84 | static LRESULT PopupSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 85 | 86 | void DrawPopupBackground(HWND hWnd, HDC hdc, RECT rect); 87 | void DrawPopupItemBackground(HWND hWnd, HDC hdc, RECT itemRect, int itemId); 88 | void DrawPopupItem(HWND hWnd, HDC hdc, RECT itemRect, int itemId); 89 | 90 | void HandleListClick(int index); 91 | }; 92 | } -------------------------------------------------------------------------------- /src/ToolsEx/Admin.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #include "Admin.hpp" 25 | #include "Tools/Process.hpp" 26 | 27 | namespace AnyFSE::ToolsEx::Admin 28 | { 29 | BOOL IsRunningAsAdministrator() 30 | { 31 | BOOL fRet = FALSE; 32 | HANDLE hToken = NULL; 33 | 34 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) 35 | { 36 | TOKEN_ELEVATION Elevation; 37 | DWORD cbSize = sizeof(TOKEN_ELEVATION); 38 | 39 | if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) 40 | { 41 | fRet = Elevation.TokenIsElevated; 42 | } 43 | } 44 | 45 | if (hToken) 46 | { 47 | CloseHandle(hToken); 48 | } 49 | 50 | return fRet; 51 | } 52 | 53 | BOOL RequestAdminElevation(const std::wstring& args) 54 | { 55 | wchar_t modulePath[MAX_PATH]; 56 | GetModuleFileName(NULL, modulePath, MAX_PATH); 57 | 58 | SHELLEXECUTEINFO sei = { sizeof(sei) }; 59 | sei.lpVerb = L"runas"; // Request UAC elevation 60 | sei.lpFile = modulePath; 61 | sei.nShow = SW_SHOWNORMAL; 62 | sei.fMask = SEE_MASK_NOCLOSEPROCESS; 63 | 64 | if (!args.empty()) 65 | { 66 | sei.lpParameters = args.c_str(); 67 | } 68 | 69 | if (ShellExecuteEx(&sei)) 70 | { 71 | if (sei.hProcess) 72 | { 73 | // Wait for the process to start (but not necessarily show window) 74 | WaitForInputIdle(sei.hProcess, 5000); 75 | 76 | HWND hWnd = 0; 77 | DWORD timeout = GetTickCount() + 3000; 78 | do 79 | { 80 | hWnd = Tools::Process::FindAppWindow(sei.hProcess); 81 | if (hWnd) 82 | { 83 | Tools::Process::BringWindowToForeground(hWnd); 84 | break; 85 | } 86 | else 87 | { 88 | Sleep(0); 89 | } 90 | } while (!hWnd && GetTickCount() < timeout ); 91 | 92 | CloseHandle(sei.hProcess); 93 | } 94 | exit(0); 95 | } 96 | 97 | return false; 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Logging/Logger.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "Logger.hpp" 32 | #include "LogManager.hpp" 33 | 34 | namespace AnyFSE::Logging 35 | { 36 | Logger::Logger(const std::string &name) 37 | { 38 | m_loggerName = name; 39 | } 40 | std::exception Logger::APIError(const char * prefix) 41 | { 42 | return APIError(0, prefix); 43 | } 44 | std::exception Logger::APIError(DWORD code, const char * prefix) 45 | { 46 | DWORD errorCode = code ? code : GetLastError(); 47 | if (!code) 48 | { 49 | return std::runtime_error(""); 50 | } 51 | 52 | LPSTR messageBuffer = nullptr; 53 | DWORD size = FormatMessageA( 54 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 55 | FORMAT_MESSAGE_FROM_SYSTEM | 56 | FORMAT_MESSAGE_IGNORE_INSERTS, 57 | NULL, 58 | errorCode, 59 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 60 | (LPSTR)&messageBuffer, 61 | 0, 62 | NULL); 63 | 64 | std::string message; 65 | if (size > 0) 66 | { 67 | message.assign(messageBuffer, size); 68 | LocalFree(messageBuffer); 69 | } 70 | else 71 | { 72 | message = "Unknown error code: " + std::to_string(errorCode); 73 | } 74 | 75 | return std::runtime_error(std::string(prefix) + message + " (Error " + std::to_string(errorCode) + ")"); 76 | } 77 | 78 | #define LOGGER(__level__) \ 79 | void Logger::__level__(const char * format, ...) \ 80 | {\ 81 | va_list args;\ 82 | va_start(args, format);\ 83 | WriteMessage(LogLevels::__level__, format, args);\ 84 | va_end(args);\ 85 | }\ 86 | void Logger::__level__(const std::exception &exception, const char * format, ...) \ 87 | {\ 88 | va_list args;\ 89 | va_start(args, format);\ 90 | WriteMessage(LogLevels::__level__, format, args);\ 91 | va_end(args);\ 92 | WriteMessage(LogLevels::__level__, exception.what());\ 93 | } 94 | 95 | LOGGER(Trace) 96 | LOGGER(Debug) 97 | LOGGER(Info) 98 | LOGGER(Warn) 99 | LOGGER(Error) 100 | LOGGER(Critical) 101 | 102 | void Logger::WriteMessage(LogLevels level, const char * format, va_list args) 103 | { 104 | LogManager::WriteMessage(level, m_loggerName, format, args); 105 | } 106 | } -------------------------------------------------------------------------------- /src/AppControl/GamingExperience.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "Logging/LogManager.hpp" 29 | #include "GamingExperience.hpp" 30 | 31 | 32 | #pragma comment(lib, "delayimp.lib") 33 | #pragma comment(lib, "windowsapp.lib") 34 | #pragma comment(lib, "onecore.lib") 35 | 36 | namespace AnyFSE::App::AppControl 37 | { 38 | static Logger log = LogManager::GetLogger("GamingExperience"); 39 | 40 | bool isApiSetImplemented( const std::string& api ) 41 | { 42 | HMODULE hDll = NULL; 43 | bool result = ::IsApiSetImplemented(api.c_str()) 44 | && (hDll = LoadLibraryA((api + ".dll").c_str())) 45 | && GetProcAddress(hDll, "RegisterGamingFullScreenExperienceChangeNotification"); 46 | if (hDll) 47 | { 48 | FreeLibrary(hDll); 49 | } 50 | return result; 51 | } 52 | 53 | bool GamingExperience::ApiIsAvailable = isApiSetImplemented("api-ms-win-gaming-experience-l1-1-0"); 54 | 55 | bool GamingExperience::IsActive() 56 | { 57 | return ApiIsAvailable && IsGamingFullScreenExperienceActive(); 58 | } 59 | 60 | bool GamingExperience::ExitFSEMode() 61 | { 62 | SetGamingFullScreenExperience(FALSE); 63 | return false; 64 | } 65 | 66 | GamingExperience::GamingExperience() 67 | { 68 | m_fseHandle = nullptr; 69 | if (ApiIsAvailable) 70 | { 71 | RegisterGamingFullScreenExperienceChangeNotification((VOID(CALLBACK *)(LPVOID))Callback, this, &m_fseHandle); 72 | if (m_fseHandle != nullptr) 73 | { 74 | log.Debug( 75 | "FullScreenExperienceChangeNotification is registered. " 76 | "Current mode is %s", 77 | GamingExperience::IsActive() ? "Fullscreeen experience" : "Windows Desktop" 78 | ); 79 | } 80 | else 81 | { 82 | log.Error(log.APIError(), "FullScreenExperienceChangeNotification registation failed"); 83 | } 84 | } 85 | } 86 | //static 87 | void GamingExperience::Callback(GamingExperience * This) 88 | { 89 | This->OnExperienseChanged.Notify(); 90 | } 91 | 92 | GamingExperience::~GamingExperience() 93 | { 94 | if (m_fseHandle != nullptr && ApiIsAvailable) 95 | { 96 | UnregisterGamingFullScreenExperienceChangeNotification(m_fseHandle); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/UpdatePage.cpp: -------------------------------------------------------------------------------- 1 | #include "Updater/Updater.AppSettings.hpp" 2 | #include "Tools/Event.hpp" 3 | #include "AppSettings/SettingsLayout.hpp" 4 | #include "AppSettings/SettingsDialog.hpp" 5 | #include "UpdatePage.hpp" 6 | 7 | 8 | namespace AnyFSE::App::AppSettings::Settings::Page 9 | { 10 | void UpdatePage::AddPage(std::list& settingPageList, ULONG &top) 11 | { 12 | RECT rect; 13 | GetClientRect(m_dialog.GetHwnd(), &rect); 14 | 15 | SettingsLine & dialogLine = m_dialog.AddSettingsLine(settingPageList, top, 16 | L"Update settings", 17 | L"Change period and settings of new version check", 18 | Layout::LineHeight, Layout::LinePadding, 0); 19 | 20 | dialogLine.SetState(FluentDesign::SettingsLine::Next); 21 | dialogLine.SetIcon(L'\xEDAB'); 22 | dialogLine.OnChanged += delegate(OpenUpdateSettingsPage); 23 | 24 | ULONG topPage = 0; 25 | 26 | m_dialog.AddSettingsLine(m_pageLinesList, topPage, 27 | L"Check period", 28 | L"New version check period", 29 | m_checkIntervalCombo, 30 | Layout::LineHeight, Layout::LinePadding, 0); 31 | 32 | m_checkIntervalCombo.OnChanged = delegate(UpdateSettingsChangedCheck); 33 | 34 | m_checkIntervalCombo.AddItem(L"Manual", L"", {(wchar_t)-2, 0}); 35 | m_checkIntervalCombo.AddItem(L"On settings open", L"", {(wchar_t)-1, 0}); 36 | m_checkIntervalCombo.AddItem(L"On windows boot", L"", {(wchar_t)0, 0}); 37 | 38 | m_checkIntervalCombo.AddItem(L"Hourly", L"", {(wchar_t)1, 0}); 39 | m_checkIntervalCombo.AddItem(L"Daily", L"", {(wchar_t)24, 0}); 40 | m_checkIntervalCombo.AddItem(L"Weekly", L"", {(wchar_t)168, 0}); 41 | m_checkIntervalCombo.AddItem(L"Monthly", L"", {(wchar_t)720, 0}); 42 | 43 | 44 | m_dialog.AddSettingsLine(m_pageLinesList, topPage, 45 | L"Include pre-release versions", 46 | L"Pre-release versions are less stable", 47 | m_preReleaseToggle, 48 | Layout::LineHeight, Layout::LinePadding, 0); 49 | 50 | m_preReleaseToggle.OnChanged = delegate(UpdateSettingsChangedCheck); 51 | 52 | m_dialog.AddSettingsLine(m_pageLinesList, topPage, 53 | L"Show notifications", 54 | L"Show popup notifications if new version available", 55 | m_notificationsToggle, 56 | Layout::LineHeight, Layout::LinePadding, 0); 57 | 58 | m_notificationsToggle.OnChanged = delegate(SaveControls); 59 | } 60 | 61 | void UpdatePage::LoadControls() 62 | { 63 | m_checkIntervalCombo.SelectItem({(wchar_t)Config::UpdateCheckInterval, 0}); 64 | m_preReleaseToggle.SetCheck(Config::UpdatePreRelease); 65 | m_notificationsToggle.SetCheck(Config::UpdateNotifications); 66 | } 67 | 68 | void UpdatePage::SaveControls() 69 | { 70 | Config::UpdateCheckInterval = (int)(short)m_checkIntervalCombo.GetCurentValue().c_str()[0]; 71 | Config::UpdatePreRelease = m_preReleaseToggle.GetCheck(); 72 | Config::UpdateNotifications = m_notificationsToggle.GetCheck(); 73 | Updater::NotifyConfigUpdated(); 74 | } 75 | 76 | void UpdatePage::OpenUpdateSettingsPage() 77 | { 78 | m_dialog.SwitchActivePage(L"Update settings", &m_pageLinesList); 79 | } 80 | 81 | void UpdatePage::UpdateSettingsChangedCheck() 82 | { 83 | UpdateSettingsChanged(); 84 | if (Config::UpdateCheckInterval == -1) 85 | { 86 | Updater::CheckUpdateAsync(Config::UpdatePreRelease, m_dialog.GetHwnd(), SettingsDialog::WM_UPDATE_NOTIFICATION); 87 | } 88 | } 89 | 90 | void UpdatePage::UpdateSettingsChanged() 91 | { 92 | SaveControls(); 93 | PostMessage(m_dialog.GetHwnd(), SettingsDialog::WM_UPDATE_NOTIFICATION, 0, 0); 94 | } 95 | }; -------------------------------------------------------------------------------- /src/ToolsEx/Minidump.hpp: -------------------------------------------------------------------------------- 1 | // Header-only minidump helper for AnyFSE 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #pragma comment(lib, "Dbghelp.lib") 10 | 11 | namespace ToolsEx 12 | { 13 | inline bool WriteMiniDump(EXCEPTION_POINTERS* pExceptionInfo) 14 | { 15 | wchar_t modulePath[MAX_PATH] = {0}; 16 | if (!GetModuleFileNameW(NULL, modulePath, MAX_PATH)) 17 | return false; 18 | 19 | // Derive directory (exe folder) and executable base name 20 | wchar_t* lastSlash = wcsrchr(modulePath, L'\\'); 21 | std::wstring exeDir = modulePath; 22 | std::wstring exeName = modulePath; 23 | if (lastSlash) 24 | { 25 | exeDir.assign(modulePath, (size_t)(lastSlash - modulePath)); 26 | exeName = lastSlash + 1; 27 | } 28 | 29 | // strip extension from exeName 30 | size_t dot = exeName.rfind(L'.'); 31 | if (dot != std::wstring::npos) 32 | exeName.erase(dot); 33 | 34 | // ensure dumps directory exists: \dumps 35 | std::wstring dumpsDir = exeDir + L"\\dumps"; 36 | if (!CreateDirectoryW(dumpsDir.c_str(), NULL)) 37 | { 38 | DWORD err = GetLastError(); 39 | if (err != ERROR_ALREADY_EXISTS) 40 | { 41 | // if we cannot create dumps dir, fall back to exeDir 42 | dumpsDir = exeDir; 43 | } 44 | } 45 | 46 | // timestamp 47 | std::time_t t = std::time(nullptr); 48 | struct tm tm; 49 | localtime_s(&tm, &t); 50 | 51 | wchar_t filename[MAX_PATH]; 52 | _snwprintf_s(filename, _countof(filename), _TRUNCATE, 53 | L"%s-%04d%02d%02d-%02d%02d%02d.dmp", 54 | exeName.c_str(), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 55 | tm.tm_hour, tm.tm_min, tm.tm_sec); 56 | 57 | std::wstring fullPath = dumpsDir + L"\\" + filename; 58 | 59 | HANDLE hFile = CreateFileW(fullPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 60 | bool wrote = false; 61 | if (hFile != INVALID_HANDLE_VALUE) 62 | { 63 | MINIDUMP_EXCEPTION_INFORMATION mei; 64 | mei.ThreadId = GetCurrentThreadId(); 65 | mei.ExceptionPointers = pExceptionInfo; 66 | mei.ClientPointers = FALSE; 67 | 68 | BOOL ok = MiniDumpWriteDump( 69 | GetCurrentProcess(), 70 | GetCurrentProcessId(), 71 | hFile, 72 | (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData | MiniDumpWithFullMemoryInfo), 73 | pExceptionInfo ? &mei : nullptr, 74 | nullptr, 75 | nullptr); 76 | 77 | CloseHandle(hFile); 78 | wrote = (ok == TRUE); 79 | } 80 | 81 | // Notify user about the crash and dump path (or failure) 82 | std::wstring msg; 83 | if (wrote) 84 | { 85 | msg = L"The application has crashed. A minidump was written to:\r\n" + fullPath; 86 | } 87 | else 88 | { 89 | msg = L"The application has crashed. Failed to write minidump. Attempted path:\r\n" + fullPath; 90 | } 91 | MessageBoxW(NULL, msg.c_str(), L"Application Error", MB_OK | MB_ICONERROR); 92 | 93 | return wrote; 94 | } 95 | 96 | inline LONG WINAPI AnyFSEUnhandledExceptionFilter(EXCEPTION_POINTERS* pExceptionInfo) 97 | { 98 | WriteMiniDump(pExceptionInfo); 99 | return EXCEPTION_EXECUTE_HANDLER; 100 | } 101 | 102 | inline void InstallUnhandledExceptionHandler() 103 | { 104 | SetUnhandledExceptionFilter(AnyFSEUnhandledExceptionFilter); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/AppControl/AppControlStateLoop.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | #include "App/AppStateLoop.hpp" 26 | #include "App/AppEvents.hpp" 27 | 28 | namespace AnyFSE::App::AppControl::Window { class MainWindow; } 29 | 30 | namespace AnyFSE::App::AppControl::StateLoop 31 | { 32 | 33 | class AppControlStateLoop: public App::StateLoop::AppStateLoop 34 | { 35 | private: 36 | Window::MainWindow &m_splash; 37 | std::uint64_t m_preventTimer; 38 | std::uint64_t m_waitLauncherTimer; 39 | std::uint64_t m_exitingTimer; 40 | std::uint64_t m_restartDelayTimer; 41 | 42 | 43 | LONGLONG m_xboxAge; 44 | LONGLONG m_deviceFormAge; 45 | LONGLONG m_homeAge; 46 | 47 | DWORD launcherPid; 48 | LONGLONG m_waitStartTime; 49 | bool m_isRestart; 50 | 51 | 52 | public: 53 | AppControlStateLoop(Window::MainWindow &splash); 54 | ~AppControlStateLoop(); 55 | 56 | private: 57 | virtual void ProcessEvent(AppEvents event); 58 | void OnStart(); 59 | void OnStartApps(); 60 | void OnXboxDetected(); 61 | void OnLauncherStopped(); 62 | void OnGameModeEnter(); 63 | void OnGameModeExit(); 64 | void OnDeviceForm(); 65 | void OnQueryEndSession(); 66 | void OnEndSession(); 67 | void OnDisconnect(); 68 | void OnOpenHome(); 69 | void OnLauncherTimer(); 70 | void OnPreventTimer(); 71 | void OnExitingTimer(); 72 | 73 | bool IsInFSEMode(); 74 | bool IsLauncherActive(); 75 | bool IsLauncherStarted(); 76 | bool IsLauncherProcess(); 77 | bool IsSplashActive(); 78 | bool IsPreventIsActive(); 79 | bool IsWaitingLauncher(); 80 | bool IsYoungXbox(); 81 | bool IsOnTaskSwitcher(); 82 | bool IsExiting(); 83 | bool IsOnGamebar(); 84 | bool IsHomeLaunch(); 85 | bool IsXboxActive(); 86 | bool IsOnSettings(); 87 | 88 | void ShowSplash(); 89 | void StartSplash(); 90 | void KillXbox(); 91 | void ExitFSEMode(); 92 | void StartLauncher(); 93 | void RestartLauncher(); 94 | void WaitLauncher(); 95 | void CloseSplash(); 96 | void PreventTimeout(); 97 | void FocusLauncher(); 98 | 99 | HWND GetLauncherWindow(); 100 | }; 101 | } 102 | 103 | using namespace AnyFSE::App::AppControl::StateLoop; -------------------------------------------------------------------------------- /src/App/IPCChannel.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include "App/AppEvents.hpp" 30 | #include "Logging/LogManager.hpp" 31 | 32 | namespace AnyFSE::App 33 | { 34 | #pragma pack(push, 1) 35 | struct Message 36 | { 37 | AppEvents event; 38 | LONGLONG ticks; 39 | }; 40 | #pragma pack(pop) 41 | 42 | class IPCChannel 43 | { 44 | public: 45 | enum class ConnectionState 46 | { 47 | Disconnected, 48 | Connecting, 49 | Connected 50 | }; 51 | 52 | IPCChannel(const std::wstring &name, bool isServer, HANDLE cancelEvent = NULL); 53 | ~IPCChannel(); 54 | 55 | static bool IsServerAvailable(const std::wstring &name); 56 | 57 | // Connection state queries 58 | ConnectionState GetConnectionState() const; 59 | bool IsConnected() const; 60 | bool IsConnecting() const; 61 | bool IsDisconnected() const; 62 | 63 | // Async I/O operations 64 | bool Wait(DWORD timeout); 65 | bool Read(Message *message); 66 | bool StartAsyncRead(); 67 | bool IsReadPending() const; 68 | void CancelRead(); 69 | 70 | // Write operation (non-reentrant, drops message on timeout) 71 | bool Write(const Message *message, DWORD timeout = 3000); 72 | 73 | // Event management 74 | void SetCancelEvent(HANDLE cancelEvent); 75 | 76 | // Connection management 77 | void ResetConnection(); 78 | 79 | private: 80 | // Internal state management 81 | bool EnsurePipeReady(DWORD timeout); 82 | bool EnsureNamedPipe(DWORD timeout); 83 | bool ServerWaitForConnection(DWORD timeout); 84 | 85 | // Read operations 86 | bool CheckDataAvailableImmediately(); 87 | bool CheckPendingReadCompletion(DWORD timeout); 88 | bool StartAsyncReadAndWait(DWORD timeout); 89 | bool CompletePendingRead(Message *message); 90 | bool ReadAvailableData(Message *message); 91 | 92 | // Write operations 93 | bool AsyncWriteWithTimeout(const Message *message, DWORD timeout); 94 | 95 | // Member variables 96 | std::wstring m_pipeName; 97 | bool m_isServer; 98 | HANDLE m_pipeHandle; 99 | HANDLE m_cancelEvent; 100 | OVERLAPPED m_connectOverlap; 101 | OVERLAPPED m_readOverlap; 102 | OVERLAPPED m_writeOverlap; 103 | ConnectionState m_connectionState; 104 | bool m_readPending; 105 | bool m_writePending; 106 | Message m_pendingMessage; 107 | Logger log; 108 | 109 | static const DWORD BUFFER_SIZE = sizeof(Message)*100; 110 | static const DWORD CONNECT_TIMEOUT = 5000; 111 | static const DWORD WRITE_TIMEOUT = 3000; 112 | }; 113 | } -------------------------------------------------------------------------------- /src/ToolsEx/ProcessEx.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "Logging/LogManager.hpp" 34 | #include "Tools/Process.hpp" 35 | #include "Tools/Unicode.hpp" 36 | #include "ProcessEx.hpp" 37 | 38 | #pragma comment(lib, "psapi.lib") 39 | 40 | namespace AnyFSE::ToolsEx::ProcessEx 41 | { 42 | static Logger log = LogManager::GetLogger("ProcessEx"); 43 | 44 | HRESULT Kill(const std::wstring &processName) 45 | { 46 | DWORD processId = Process::FindFirstByName(processName); 47 | if (processId == 0) 48 | { 49 | log.Error("Kill process failed: %s process tot found", Unicode::to_string(processName).c_str()); 50 | return ERROR_PROC_NOT_FOUND; 51 | } 52 | 53 | log.Debug("Process %s found with id: %u", Unicode::to_string(processName).c_str(), processId); 54 | return Kill(processId); 55 | } 56 | 57 | HRESULT KillSystem(DWORD processId) 58 | { 59 | if (processId == 0) 60 | { 61 | return ERROR_INVALID_PARAMETER; 62 | } 63 | 64 | // Method 2: Run taskkill with runas for elevated privileges 65 | std::wstring command = L"/C taskkill /F /PID " + std::to_wstring(processId); 66 | 67 | SHELLEXECUTEINFOW sei = {sizeof(sei)}; 68 | sei.lpFile = L"cmd.exe"; 69 | sei.lpParameters = command.c_str(); 70 | sei.nShow = SW_HIDE; 71 | sei.fMask = SEE_MASK_NOCLOSEPROCESS; 72 | 73 | if (!ShellExecuteExW(&sei)) 74 | { 75 | DWORD error = GetLastError(); 76 | return HRESULT_FROM_WIN32(error); 77 | } 78 | 79 | if (sei.hProcess) 80 | { 81 | // Wait for the process to complete 82 | WaitForSingleObject(sei.hProcess, 10000); // Wait up to 10 seconds 83 | CloseHandle(sei.hProcess); 84 | } 85 | return NULL; 86 | } 87 | 88 | HRESULT Kill(DWORD processId) 89 | { 90 | if (processId == 0) 91 | { 92 | return ERROR_INVALID_PARAMETER; 93 | } 94 | 95 | HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, processId); 96 | if (hProcess == NULL) 97 | { 98 | log.Error(log.APIError(), "Kill process. OpenProcess failed"); 99 | return GetLastError(); 100 | } 101 | 102 | if (!TerminateProcess(hProcess, 0)) 103 | { 104 | log.Error(log.APIError(), "Kill process. TerminateProcess failed"); 105 | HRESULT error = GetLastError(); 106 | CloseHandle(hProcess); 107 | return error; 108 | } 109 | 110 | CloseHandle(hProcess); 111 | return ERROR_SUCCESS; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/FluentDesign/ComboBox.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Tools/Event.hpp" 32 | #include "Theme.hpp" 33 | #include "FluentControl.hpp" 34 | 35 | namespace FluentDesign 36 | { 37 | class ComboBox : public FluentControl 38 | { 39 | struct ComboItem 40 | { 41 | std::wstring name; 42 | std::wstring icon; 43 | std::wstring value; 44 | int iconIndex; 45 | }; 46 | 47 | private: 48 | static const int Layout_ItemHeight = 38; 49 | static const int Layout_ImageSize = 20; 50 | static const int Layout_LeftMargin = 16; 51 | static const int Layout_IconMargin = 8; 52 | static const int Layout_ChevronMargin = 16; 53 | static const int Layout_CornerRadius = 8; 54 | 55 | HIMAGELIST m_hImageList = NULL; 56 | 57 | std::vector m_comboItems; 58 | 59 | bool m_buttonPressed; 60 | bool m_buttonMouseOver; 61 | 62 | int m_designWidth = 0; 63 | 64 | // Listbox part 65 | HWND m_hPopupList; 66 | bool m_popupVisible; 67 | int m_selectedIndex; 68 | int m_originalIndex = 0; 69 | int m_hoveredIndex; 70 | 71 | static LRESULT CALLBACK ComboBoxSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 72 | UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 73 | 74 | static LRESULT CALLBACK PopupListSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 75 | UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 76 | 77 | void HandleMouse(HWND hWnd, UINT uMsg); 78 | void DrawComboBackground(HWND hWnd, HDC hdc, RECT rc); 79 | void DrawComboItem(HWND hWnd, HDC hdc, RECT rect, int itemId); 80 | void DrawComboChevron(HWND hWnd, HDC hdc, RECT rect); 81 | void DrawPopupBackground(HWND hWnd, HDC hdc, RECT rect); 82 | void DrawPopupItem(HWND hWnd, HDC hdc, RECT rect, int itemId); 83 | void HandleListClick(int index); 84 | 85 | void UpdateLayout(); 86 | 87 | public: 88 | ComboBox(Theme& theme); 89 | ComboBox( 90 | Theme& theme, 91 | HWND hParent, 92 | int x, int y, 93 | int width, int height); 94 | 95 | HWND Create(HWND hParent, int x, int y, int width, int height); 96 | 97 | ~ComboBox(); 98 | 99 | int AddItem(const std::wstring &name, const std::wstring &icon, const std::wstring &value, int pos = -1); 100 | int Reset(); 101 | void SelectItem(int index); 102 | void SelectItem(const std::wstring &value); 103 | std::wstring GetCurentValue(); 104 | int GetSelectedIndex() const { return m_selectedIndex; }; 105 | Event OnChanged; 106 | 107 | void ShowPopup(); 108 | void HidePopup(); 109 | }; 110 | } -------------------------------------------------------------------------------- /src/App/AppStateLoop.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "Logging/LogManager.hpp" 38 | #include "App/IPCChannel.hpp" 39 | #include "App/AppStateLoop.hpp" 40 | 41 | namespace AnyFSE::App::StateLoop 42 | { 43 | 44 | class AppStateLoop 45 | { 46 | friend class AppControlStateLoop; 47 | static const int MESSAGES_EOL = 5000; 48 | 49 | protected: 50 | AnyFSE::App::IPCChannel m_ipcChannel; 51 | 52 | public: 53 | // Event enum - you can extend this as needed 54 | 55 | AppStateLoop(bool isServer); 56 | virtual ~AppStateLoop(); 57 | 58 | // Delete copy constructor and assignment operator 59 | AppStateLoop(const AppStateLoop &) = delete; 60 | AppStateLoop &operator=(const AppStateLoop &) = delete; 61 | 62 | // Event management - public interface 63 | void Notify(AppEvents event); 64 | bool NotifyRemote(AppEvents event, DWORD timeout = 5000); 65 | 66 | // Main control functions 67 | void Start(); 68 | void Stop(); 69 | void Wait(DWORD timeout); 70 | bool IsRunning() { return m_isRunning.load(); } 71 | 72 | protected: 73 | // Timer management - only available to derived classes in event handlers 74 | uint64_t SetTimer(std::chrono::milliseconds timeout, std::function callback, bool recurring = false); 75 | void CancelTimer(uint64_t id); 76 | 77 | // Pure virtual function to handle events - must be implemented by derived class 78 | virtual void ProcessEvent(AppEvents event) = 0; 79 | 80 | private: 81 | // Thread-safe queue for events 82 | std::queue m_eventQueue; 83 | std::mutex m_queueMutex; 84 | 85 | HANDLE m_hQueueCondition; 86 | 87 | HANDLE m_hReadPipe; 88 | HANDLE m_hWritePipe; 89 | 90 | Logger _log; 91 | // Timer management - only accessed from processing thread 92 | struct TimerInfo 93 | { 94 | std::chrono::steady_clock::time_point expirationTime; 95 | std::function callback; 96 | bool isRecurring = false; 97 | std::chrono::milliseconds interval; 98 | bool isInvalid = false; 99 | }; 100 | 101 | std::map m_timersMap; 102 | uint64_t m_nextTimerId{1}; 103 | 104 | // Control flags 105 | std::atomic m_isRunning{false}; 106 | std::thread m_thread; 107 | 108 | // Private methods 109 | void ProcessingCycle(); 110 | std::optional GetNextTimeout(); 111 | void CheckExpiredTimers(); 112 | }; 113 | 114 | } // namespace AnyFSE::App 115 | 116 | -------------------------------------------------------------------------------- /src/AppSettings/SettingsPages/StartupEditDlg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "StartupEditDlg.hpp" 3 | 4 | namespace AnyFSE::App::AppSettings::Settings 5 | { 6 | void StartupEditDlg::OnOk() 7 | { 8 | m_refPath = m_pathEdit.GetText(); 9 | m_refArgs = m_argsEdit.GetText(); 10 | FluentDesign::Dialog::OnOK(); 11 | } 12 | 13 | void StartupEditDlg::OnCancel() 14 | { 15 | FluentDesign::Dialog::OnCancel(); 16 | } 17 | 18 | void StartupEditDlg::OnBrowse() 19 | { 20 | OPENFILENAME ofn = {}; 21 | WCHAR szFile[MAX_PATH + 1] = {}; 22 | 23 | wcsncpy_s(szFile, m_pathEdit.GetText().c_str(), MAX_PATH); 24 | 25 | ofn.lStructSize = sizeof(ofn); 26 | ofn.hwndOwner = m_hDialog; 27 | ofn.lpstrFile = szFile; 28 | ofn.nMaxFile = sizeof(szFile); 29 | ofn.lpstrFilter = L"Executable (*.exe)\0*.exe\0\0"; 30 | ofn.nFilterIndex = 1; 31 | ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 32 | 33 | if (GetOpenFileName(&ofn)) 34 | { 35 | m_pathEdit.SetText(szFile); 36 | ValidatePath(); 37 | } 38 | } 39 | 40 | void StartupEditDlg::ValidatePath() 41 | { 42 | namespace fs = std::filesystem; 43 | m_okButton.Enable(fs::exists(fs::path(m_pathEdit.GetText()))); 44 | } 45 | 46 | INT_PTR StartupEditDlg::EditApp(HWND hParent, std::wstring &refPath, std::wstring &refArgs) 47 | { 48 | StartupEditDlg dialog(refPath, refArgs); 49 | return dialog.Show(hParent); 50 | } 51 | 52 | void StartupEditDlg::Create() 53 | { 54 | RECT rc; 55 | GetClientRect(m_hDialog, &rc); 56 | InflateRect(&rc, -m_theme.DpiScale(Layout_Margins), -m_theme.DpiScale(Layout_Margins)); 57 | int width = rc.right - rc.left; 58 | int top = rc.top; 59 | 60 | m_captionStatic.Create(m_hDialog, m_refPath.empty() ? L"Add application" : L"Edit application", 61 | rc.left, top, width, m_theme.DpiScale(Layout_CaptionHeight) 62 | ); 63 | m_captionStatic.SetLarge(true); 64 | top += m_theme.DpiScale(Layout_CaptionHeight); 65 | 66 | m_pathStatic.Create(m_hDialog, L"Select app to execute", rc.left, top, width, m_theme.DpiScale(Layout_TextHeight)); 67 | m_pathStatic.Format().SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentFar); 68 | 69 | top += m_theme.DpiScale(Layout_TextHeight); 70 | 71 | m_pathEdit.Create(m_hDialog, rc.left, top, 72 | width - m_theme.DpiScale(Layout_BrowseButtonWidth + Layout_ButtonPadding), 73 | m_theme.DpiScale(Layout_EditHeight) 74 | ); 75 | 76 | m_browseButton.Create(m_hDialog, L"Browse", delegate(OnBrowse), 77 | rc.right - m_theme.DpiScale(Layout_BrowseButtonWidth), 78 | top + (Layout_EditHeight - Layout_ButtonHeight) / 2, 79 | m_theme.DpiScale(Layout_BrowseButtonWidth), 80 | m_theme.DpiScale(Layout_ButtonHeight) 81 | ); 82 | top += m_theme.DpiScale(Layout_EditHeight); 83 | 84 | m_argsStatic.Create(m_hDialog, L"Additional startup arguments", 85 | rc.left, top, width, m_theme.DpiScale(Layout_TextHeight) 86 | ); 87 | m_argsStatic.Format().SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentFar); 88 | 89 | top += m_theme.DpiScale(Layout_TextHeight); 90 | m_argsEdit.Create(m_hDialog, rc.left, top, width, m_theme.DpiScale(Layout_EditHeight)); 91 | 92 | m_okButton.Create(m_hDialog, L"OK", delegate(OnOk), 93 | rc.right - m_theme.DpiScale(Layout_ButtonWidth *2 + Layout_ButtonPadding), 94 | rc.bottom - m_theme.DpiScale(Layout_ButtonHeight), 95 | m_theme.DpiScale(Layout_ButtonWidth), m_theme.DpiScale(Layout_ButtonHeight) 96 | ); 97 | m_cancelButton.Create(m_hDialog, L"Cancel", delegate(OnCancel), 98 | rc.right - m_theme.DpiScale(Layout_ButtonWidth), 99 | rc.bottom - m_theme.DpiScale(Layout_ButtonHeight), 100 | m_theme.DpiScale(Layout_ButtonWidth), m_theme.DpiScale(Layout_ButtonHeight) 101 | ); 102 | 103 | m_pathEdit.SetText(m_refPath); 104 | m_pathEdit.OnChanged = delegate(ValidatePath); 105 | 106 | m_argsEdit.SetText(m_refArgs); 107 | 108 | ValidatePath(); 109 | } 110 | } -------------------------------------------------------------------------------- /src/AppControl/MainWindow.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include "VideoPlayer.hpp" 30 | #include "Tools/Event.hpp" 31 | 32 | namespace Gdiplus { class Image; } 33 | 34 | namespace AnyFSE::App::AppControl::Window 35 | { 36 | class MainWindow 37 | { 38 | public: 39 | static const UINT WM_TRAY = WM_USER + 1; 40 | static const UINT WM_UPDATE_NOTIFICATION = WM_USER + 2; 41 | static const UINT WM_UPDATE_CHECK = WM_USER + 3; 42 | static const UINT WM_UPDATE_COMMAND = WM_USER + 4; 43 | private: 44 | const UINT WM_TASKBARCREATED; 45 | const UINT WM_UPDATER_COMMAND; 46 | 47 | HICON m_hIcon = NULL; 48 | HWND m_hWnd; 49 | ATOM m_aClass; 50 | SimpleVideoPlayer m_videoPlayer; 51 | std::wstring m_currentVideo; 52 | 53 | int m_result = ERROR_RESTART_APPLICATION; 54 | bool m_empty = false; 55 | bool m_successChecked = false; 56 | 57 | static WNDCLASS WC; 58 | static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 59 | static void LoadStringSafe(UINT nStrID, LPTSTR szBuf, UINT nBufLen); 60 | void OnCreate(); 61 | void CreateTrayIcon(); 62 | void OnPaint(); 63 | 64 | void OnTray(LPARAM message); 65 | BOOL FreeResources(); 66 | BOOL OnCommand(WORD command); 67 | void OnDestroy(); 68 | 69 | void OnUpdateNotification(); 70 | void OnUpdateCheck(); 71 | void ScheduleCheck(int delay = 60); 72 | void SelectNextVideo(); 73 | 74 | LRESULT CALLBACK HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); 75 | 76 | public: 77 | MainWindow(); 78 | ~MainWindow(); 79 | bool Show(bool empty = false); 80 | bool Start(); 81 | bool Hide(); 82 | bool Create(LPCWSTR className, HINSTANCE hInstance, LPCTSTR windowName); 83 | static int RunLoop(); 84 | 85 | bool IsVisible(); 86 | int ExitOnError(); 87 | 88 | void StartUpdateCheck(); 89 | Event OnStartWindow; 90 | Event OnQueryEndSession; 91 | Event OnEndSession; 92 | Event OnReconfigure; 93 | 94 | private: // Animation 95 | 96 | UINT_PTR m_animationTimerId = 1; 97 | UINT_PTR m_updateTimerId = 2; 98 | UINT_PTR m_hAnimationTimer = NULL; 99 | UINT_PTR m_hUpdateTimer = NULL; 100 | 101 | const int ZOOM_INTERVAL_MS = 20; 102 | 103 | float m_currentZoom = 0.96f; 104 | float m_zoomStep = 0.002f; 105 | float m_zoomDelta = 0.06f; 106 | 107 | ULONG_PTR m_gdiplusToken; 108 | 109 | Gdiplus::Image * m_pLogoImage; 110 | const COLORREF THEME_BACKGROUND_COLOR = RGB(22,22,22); 111 | 112 | 113 | bool InitAnimationResources(); 114 | BOOL LoadLogoImage(); 115 | void OnPaintAnimated(); 116 | void OnTimer(UINT_PTR timerId); 117 | BOOL FreeAnimationResources(); 118 | BOOL StartAnimation(); 119 | BOOL StopAnimation(); 120 | }; 121 | } 122 | 123 | using namespace AnyFSE::App::AppControl::Window; -------------------------------------------------------------------------------- /src/AppService/ETWMonitor.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Tools/Event.hpp" 32 | #include 33 | 34 | namespace AnyFSE::App::AppService 35 | { 36 | class ETWMonitor 37 | { 38 | static const GUID ProcessProviderGuid; 39 | static const GUID RegistryProviderGuid; 40 | 41 | public: 42 | explicit ETWMonitor(const std::wstring &processName); 43 | ~ETWMonitor(); 44 | 45 | HANDLE Start(); 46 | void Stop(); 47 | HANDLE StopAsync(); 48 | Event OnProcessExecuted; 49 | Event OnLauncherStopped; 50 | Event OnHomeAppTouched; 51 | Event OnDeviceFormTouched; 52 | Event OnFailure; 53 | 54 | ULONG EnableRegistryProvider(); 55 | 56 | private: 57 | template 58 | PWCHAR wCharAt(T data, ULONG offset) 59 | { 60 | return (PWCHAR)((PBYTE)data + offset); 61 | } 62 | 63 | template 64 | PWCHAR wCharAtSafe(T data, ULONG offset) 65 | { 66 | return offset ? (PWCHAR)((PBYTE)data + offset) : L""; 67 | } 68 | 69 | void MonitoringThread(); 70 | 71 | void SetTraceProperties(); 72 | ULONG StopSession(); 73 | ULONG StartSession(); 74 | ULONG EnableProcessProvider(); 75 | 76 | ULONG OpenConsumer(); 77 | void StartRealtimeETW(); 78 | void StopRealtimeETW(); 79 | void EnableMonitoringExitLauncher(); 80 | static void WINAPI EventRecordCallback(EVENT_RECORD *eventRecord); 81 | 82 | void TraceEvent(PEVENT_RECORD pEvent, size_t count); 83 | DWORD GetPropertySizeTDH(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, int type, LPCWSTR propertyName); 84 | void DumpEventTDH(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, size_t count); 85 | DWORD FindExploredPid(); 86 | DWORD IsExploredPid(DWORD pid); 87 | DWORD GetExploredPid(); 88 | bool IsExplorerProcessId(LONG pid); 89 | 90 | void ProcessEvent(EVENT_RECORD *eventRecord); 91 | 92 | std::wstring m_processName; 93 | std::wstring m_sessionName; 94 | std::thread m_monitoringThread; 95 | 96 | bool m_trackStop; 97 | std::string m_launcherProcName; 98 | std::string m_LauncherAltProcName; 99 | 100 | std::atomic m_isRunning; 101 | std::atomic m_stopRequested; 102 | HANDLE m_threadHandle; 103 | 104 | // ETW real-time session handles 105 | TRACEHANDLE m_sessionHandle; 106 | TRACEHANDLE m_traceHandle; 107 | TRACEHANDLE m_consumerHandle; 108 | EVENT_TRACE_LOGFILEW m_logFile; 109 | EVENT_TRACE_PROPERTIES *m_pTraceProperties; 110 | 111 | LONG m_explorerProcessId; 112 | void HandleStartProcessEvent(EVENT_RECORD *eventRecord); 113 | void HandleStopProcessEvent(EVENT_RECORD *eventRecord); 114 | void HandleRegistryQueryValueEvent(EVENT_RECORD *eventRecord); 115 | static bool memimem(const char *pData, size_t dataLen, const char *pSample, size_t sampleLen); 116 | }; 117 | 118 | } -------------------------------------------------------------------------------- /src/AppInstaller/AppInstaller_PostMortem.cpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | #include 24 | #include 25 | 26 | #include "Logging/LogManager.hpp" 27 | #include "ToolsEx/TaskManager.hpp" 28 | #include "Tools/Unicode.hpp" 29 | #include "AppInstaller.hpp" 30 | 31 | 32 | namespace AnyFSE 33 | { 34 | namespace fs = std::filesystem; 35 | static Logger log = LogManager::GetLogger("PostMortem"); 36 | 37 | 38 | std::wstring GetModuleVersion(const std::wstring &file) 39 | { 40 | wchar_t modulePath[MAX_PATH] = {0}; 41 | wcsncpy_s(modulePath, file.c_str(), MAX_PATH); 42 | 43 | if (!GetModuleFileNameW(NULL, modulePath, MAX_PATH)) 44 | return L""; 45 | 46 | DWORD dummy = 0; 47 | DWORD len = GetFileVersionInfoSizeW(modulePath, &dummy); 48 | if (len == 0) 49 | return L""; 50 | 51 | std::vector data(len); 52 | if (!GetFileVersionInfoW(modulePath, 0, len, data.data())) 53 | return L""; 54 | 55 | VS_FIXEDFILEINFO *vinfo = nullptr; 56 | UINT size = 0; 57 | if (!VerQueryValueW(data.data(), L"\\", (LPVOID *)&vinfo, &size) || vinfo == nullptr) 58 | return L""; 59 | 60 | DWORD ms = vinfo->dwFileVersionMS; 61 | DWORD ls = vinfo->dwFileVersionLS; 62 | int major = HIWORD(ms); 63 | int minor = LOWORD(ms); 64 | int patch = HIWORD(ls); 65 | 66 | wchar_t buf[64]; 67 | swprintf_s(buf, L"%d.%d.%d", major, minor, patch); 68 | return std::wstring(buf); 69 | } 70 | 71 | void CheckFiles(const std::wstring &base) 72 | { 73 | std::list files 74 | { 75 | L"AnyFSE.exe", 76 | L"AnyFSE.Service.exe", 77 | L"AnyFSE.Settings.dll", 78 | L"unins000.exe", 79 | L"dumps", 80 | }; 81 | 82 | for (auto &f : files) 83 | { 84 | fs::path path(base + L"\\" + f); 85 | log.Info("Check path '%s' - %s%s", 86 | path.string().c_str(), 87 | fs::exists(path) ? "Exists" : "NOT FOUND", 88 | (fs::exists(path) && fs::is_regular_file(path)) ? Unicode::to_string(L" v" + GetModuleVersion(path.wstring())).c_str() : "" 89 | ); 90 | } 91 | }; 92 | 93 | void CheckDumps(const std::wstring &base) 94 | { 95 | log.Info("Check dump files existance"); 96 | fs::path path(base + L"\\dumps"); 97 | if (fs::is_directory(path) && !fs::is_empty(path)) 98 | { 99 | log.Error("Dumps folder is not empty:"); 100 | 101 | for (const auto & entry : fs::directory_iterator(path)) 102 | { 103 | log.Info(">>> %s (%ull bytes)", entry.path().string().c_str(), entry.file_size()); 104 | } 105 | } 106 | else 107 | { 108 | log.Info("No dumps"); 109 | } 110 | } 111 | 112 | void CheckTask(const std::wstring &path) 113 | { 114 | log.Info("Check task existance"); 115 | std::wstring taskPath = ToolsEx::TaskManager::GetInstallPath(); 116 | if (taskPath.empty() || _wcsicmp(taskPath.c_str(), path.c_str())) 117 | { 118 | log.Error("Task error: %s", taskPath.empty() ? "task is not found" : "task is not updated"); 119 | } 120 | else 121 | { 122 | log.Info("Task exists"); 123 | } 124 | } 125 | 126 | void AppInstaller::CollectPostMortemInfo(const std::wstring &path) 127 | { 128 | log.Info("Collecting post-mortem info"); 129 | CheckFiles(path); 130 | CheckDumps(path); 131 | CheckTask(path); 132 | } 133 | } -------------------------------------------------------------------------------- /src/FluentDesign/FluentControl.cpp: -------------------------------------------------------------------------------- 1 | #include "Tools/Window.hpp" 2 | #include "FluentDesign/FluentControl.hpp" 3 | #include "FluentControl.hpp" 4 | 5 | namespace FluentDesign 6 | { 7 | void FluentControl::SetAnchor(Align::Anchor anchor, GetParentRectFunc getParentRect) 8 | { 9 | 10 | m_anchor = anchor; 11 | m_getParentRect = getParentRect; 12 | 13 | if (GetParent(m_hWnd)) 14 | { 15 | StoreDesign(); 16 | } 17 | } 18 | 19 | void FluentControl::StoreDesign() 20 | { 21 | if (m_anchor==Align::None) 22 | { 23 | return; 24 | } 25 | 26 | RECT parentRECT; 27 | m_getParentRect(m_theme, GetParent(m_hWnd), &parentRECT); 28 | Gdiplus::RectF parentRect = m_theme.DpiUnscaleF(parentRECT); 29 | 30 | RECT controlRECT; 31 | Window::GetChildRect(m_hWnd, &controlRECT); 32 | Gdiplus::RectF controlRect = m_theme.DpiUnscaleF(controlRECT); 33 | 34 | m_designMargins.Left = controlRect.GetLeft() - Align::HSide(Align::LeftSide(m_anchor), parentRect, controlRect.GetRight()); 35 | m_designMargins.Top = controlRect.GetTop() - Align::VSide(Align::TopSide(m_anchor), parentRect, controlRect.GetBottom()); 36 | m_designMargins.Right = controlRect.GetRight() - Align::HSide(Align::RightSide(m_anchor), parentRect, controlRect.GetLeft()); 37 | m_designMargins.Bottom = controlRect.GetBottom() - Align::VSide(Align::BottomSide(m_anchor), parentRect, controlRect.GetTop()); 38 | } 39 | 40 | HDWP FluentControl::ReflowControl(HDWP hdwp) 41 | { 42 | if (m_anchor==Align::None) 43 | { 44 | return hdwp; 45 | } 46 | 47 | RECT parentRECT; 48 | m_getParentRect(m_theme, GetParent(m_hWnd), &parentRECT); 49 | Gdiplus::RectF parentRect = m_theme.DpiUnscaleF(parentRECT); 50 | 51 | float l, t, r, b = 0.f; 52 | 53 | l = m_designMargins.Left + Align::HSide(Align::LeftSide(m_anchor), parentRect, 0 ); 54 | t = m_designMargins.Top + Align::VSide(Align::TopSide(m_anchor), parentRect, 0 ); 55 | r = m_designMargins.Right + Align::HSide(Align::RightSide(m_anchor), parentRect, l ); 56 | b = m_designMargins.Bottom + Align::VSide(Align::BottomSide(m_anchor), parentRect, t ); 57 | 58 | Gdiplus::RectF controlRect(l, t, r - l, b - t); 59 | RECT controlRECT = m_theme.DpiScale(controlRect); 60 | if (!hdwp) 61 | { 62 | Window::MoveWindow(m_hWnd, &controlRECT, FALSE); 63 | } 64 | else 65 | { 66 | hdwp = DeferWindowPos(hdwp, m_hWnd, nullptr, 67 | controlRECT.left, controlRECT.top, 68 | controlRECT.right - controlRECT.left, 69 | controlRECT.bottom - controlRECT.top, 70 | SWP_NOZORDER); 71 | } 72 | return hdwp; 73 | } 74 | 75 | void FluentControl::AnchoredSizePos(HWND hParent, int &x, int&y, int &cx, int& cy) 76 | { 77 | if (m_anchor == Align::None) 78 | { 79 | m_designMargins.Left = m_theme.DpiUnscaleF(x); 80 | m_designMargins.Top = m_theme.DpiUnscaleF(y); 81 | m_designMargins.Right = m_theme.DpiUnscaleF(cx); 82 | m_designMargins.Bottom = m_theme.DpiUnscaleF(cy); 83 | 84 | return; 85 | } 86 | 87 | RECT parentRECT; 88 | m_getParentRect(m_theme, hParent, &parentRECT); 89 | Gdiplus::RectF parentRect = Gdiplus::ToRectF(parentRECT); 90 | 91 | m_designMargins.Left = (float)x; 92 | m_designMargins.Top = (float)y; 93 | m_designMargins.Right = (float)cx; 94 | m_designMargins.Bottom = (float)cy; 95 | 96 | x = m_theme.DpiScale(x) + (int)Align::HSide(Align::LeftSide(m_anchor), parentRect, 0); 97 | y = m_theme.DpiScale(y) + (int)Align::VSide(Align::TopSide(m_anchor), parentRect, 0); 98 | 99 | cx = m_theme.DpiScale(cx); 100 | cy = m_theme.DpiScale(cy); 101 | 102 | if (Align::RightSide(m_anchor) != Align::None) // Cx is Right margin 103 | { 104 | cx += (int)Align::HSide(Align::RightSide(m_anchor), parentRect, 0) - x; 105 | } 106 | 107 | if (Align::BottomSide(m_anchor) != Align::None) // CY is Bottom margin 108 | { 109 | cy += (int)Align::VSide(Align::BottomSide(m_anchor), parentRect, 0) - y; 110 | } 111 | } 112 | 113 | void FluentControl::SetSize(LONG cx, LONG cy) 114 | { 115 | RECT rc; 116 | Window::GetChildRect(m_hWnd, &rc); 117 | 118 | if (cx != -1) 119 | { 120 | m_designMargins.Right = m_theme.DpiUnscaleF(cx); 121 | } 122 | 123 | if (cy != -1) 124 | { 125 | m_designMargins.Bottom = m_theme.DpiUnscaleF(cy); 126 | } 127 | ReflowControl(NULL); 128 | RedrawWindow(GetParent(m_hWnd), &rc, 0, RDW_INVALIDATE); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/FluentDesign/Button.hpp: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2025 Artem Shpynov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Tools/Event.hpp" 32 | #include "Theme.hpp" 33 | #include "Popup.hpp" 34 | #include "FluentControl.hpp" 35 | 36 | namespace FluentDesign 37 | { 38 | class Button : public FluentControl 39 | { 40 | 41 | private: 42 | int m_designWidth = 0; 43 | int m_designHeight = 0; 44 | 45 | int m_iconAngle; 46 | int m_startAngle; 47 | int m_endAngle; 48 | int m_stepAngle; 49 | UINT_PTR m_animationTimer; 50 | bool m_animationLoop; 51 | 52 | bool m_buttonPressed; 53 | bool m_buttonMouseOver; 54 | bool m_isIconButton; 55 | bool m_bFlat; 56 | bool m_bSquare; 57 | bool m_isSmallIcon; 58 | int m_cornerRadius = 8; 59 | 60 | std::vector m_menuItems; 61 | int m_menuWidth = 300; 62 | int m_menuAlingment = TPM_RIGHTALIGN; 63 | 64 | Theme::Colors m_textNormalColor; 65 | Theme::Colors m_backgroundNormalColor; 66 | Theme::Colors m_textHoverColor; 67 | Theme::Colors m_backgroundHoverColor; 68 | Theme::Colors m_textPressedColor; 69 | Theme::Colors m_backgroundPressedColor; 70 | 71 | std::wstring m_text; 72 | 73 | LRESULT OnTimer(UINT timerId); 74 | 75 | static LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 76 | UINT_PTR uIdSubclass, DWORD_PTR dwRefData); 77 | 78 | void HandleMouse(HWND hWnd, UINT uMsg, LPARAM lParam); 79 | void DrawButton(HWND hWnd, HDC hdc, RECT rc); 80 | 81 | void UpdateLayout(); 82 | 83 | public: 84 | Button(Theme &theme, Align::Anchor align = Align::None, GetParentRectFunc getParentRect = GetParentRect); 85 | Button( 86 | Theme& theme, 87 | HWND hParent, 88 | int x, int y, 89 | int width, int height); 90 | 91 | Button& SetAnchor(Align::Anchor anchor, GetParentRectFunc getParentRect = GetParentRect) 92 | { 93 | FluentControl::SetAnchor(anchor, getParentRect); 94 | return *this; 95 | } 96 | 97 | Button& Create(HWND hParent, int x, int y, int width, int height); 98 | Button& Create(HWND hParent, const std::wstring& text, const std::function& callback, int x, int y, int width, int height); 99 | 100 | Button& SetText(const std::wstring& text); 101 | Button &SetIcon(const std::wstring &glyph, bool bSmall = false); 102 | Button& Enable(bool bEnable); 103 | Button& SetTabStop(bool bTabStop); 104 | Button& Show(bool bShow); 105 | 106 | Button& SetFlat(bool isFlat); 107 | Button& SetSquare(bool isSquare); 108 | Button& SetAlign(int bsStyle); 109 | void SetAngle(int angle); 110 | Button& SetLinkStyle(); 111 | 112 | void SetSize(SIZE sz) { SetSize(sz.cx, sz.cy); }; 113 | void SetSize(LONG cx, LONG cy); 114 | 115 | Button& SetColors(Theme::Colors textNornal, Theme::Colors backgroundNormal = Theme::Colors::Default, 116 | Theme::Colors textHover = Theme::Colors::Default, Theme::Colors backgroundHover = Theme::Colors::Default, 117 | Theme::Colors textPressed = Theme::Colors::Default, Theme::Colors backgroundPressed = Theme::Colors::Default); 118 | 119 | void SetMenu(const std::vector &items, int nMenuWidth = 300, int nAlignment = TPM_RIGHTALIGN); 120 | void ShowMenu(); 121 | SIZE GetMinSize(); 122 | ~Button(); 123 | 124 | void Animate(int startAngle, int stopAngle, int duration, bool bInfinite); 125 | void CompleteAnimation(); 126 | void CancelAnimation(int endAngle = 0); 127 | 128 | std::wstring& GetText(); 129 | 130 | Event OnChanged; 131 | Event OnButtonDown; 132 | }; 133 | } --------------------------------------------------------------------------------