From 4b46eafd356987c33e9e57a83155ceccbfb796db Mon Sep 17 00:00:00 2001 From: Mina Brown Date: Sat, 9 Aug 2025 11:56:59 -0400 Subject: [PATCH] Save and load preferences using the registry Preferences are now saved and loaded using the registry. They are loaded at application startup and written to the registry every time a change is made. If no preferences are present in the registry yet, the current display mode is used for both battery and AC power. --- README.md | 4 +- WinPowerDMS/WinPowerDMS.c | 98 +++++++++++++++++++++++++++++---------- 2 files changed, 76 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 7242287..ea489fa 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ Currently a work in progress. Not very useful yet since it doesn't save your pre This is a simple C program written using Visual Studio 2022 that has no external dependencies. It should support Windows Vista or higher, but this hasn't been tested yet. ## TODO -- [ ] Save preferences to the Windows registry. +- [x] Save preferences to the Windows registry. - [ ] Add a checkbox to preferences for starting at login. - [ ] Add an icon. - [ ] Add behavior for when multiple displays are connected. - [ ] Block program from running when the system has no battery. -- [ ] Make the default display mode the current one instead of the highest resolution if there are no preferences set. +- [x] Make the default display mode the current one instead of the highest resolution if there are no preferences set. - [ ] Make an actual about dialog. \ No newline at end of file diff --git a/WinPowerDMS/WinPowerDMS.c b/WinPowerDMS/WinPowerDMS.c index ca3963d..a7b5c6d 100644 --- a/WinPowerDMS/WinPowerDMS.c +++ b/WinPowerDMS/WinPowerDMS.c @@ -14,14 +14,11 @@ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #define TRAY_ICON_ID 1001 typedef struct { - int width; - int height; - int refresh; + DWORD width; + DWORD height; + DWORD refresh; } DISPLAY_MODE; -static DISPLAY_MODE modeBatt = { 0 }; -static DISPLAY_MODE modeAC = { 0 }; - BOOL DisplayModeEquals(const DISPLAY_MODE* a, const DISPLAY_MODE* b) { return a->width == b->width && a->height == b->height && a->refresh == b->refresh; } @@ -125,6 +122,52 @@ static void TestDisplayMode(HWND hDlg, DISPLAY_MODE* mode) { } } +typedef struct { + DISPLAY_MODE modeBatt; + DISPLAY_MODE modeAC; +} WINPOWERDMS_PREFS; + +static WINPOWERDMS_PREFS userPrefs = { 0 }; + +// Save user preferences to registry. +static BOOL SavePrefs(void) { + HKEY regKey; + if (!RegCreateKeyEx( + HKEY_CURRENT_USER, L"SOFTWARE\\WinPowerDMS", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, ®Key, NULL + )) { + RegSetKeyValue(regKey, L"Battery", L"Width", REG_DWORD, &userPrefs.modeBatt.width, sizeof(userPrefs.modeBatt.width)); + RegSetKeyValue(regKey, L"Battery", L"Height", REG_DWORD, &userPrefs.modeBatt.height, sizeof(userPrefs.modeBatt.height)); + RegSetKeyValue(regKey, L"Battery", L"Refresh Rate", REG_DWORD, &userPrefs.modeBatt.refresh, sizeof(userPrefs.modeBatt.refresh)); + RegSetKeyValue(regKey, L"AC Power", L"Width", REG_DWORD, &userPrefs.modeAC.width, sizeof(userPrefs.modeAC.width)); + RegSetKeyValue(regKey, L"AC Power", L"Height", REG_DWORD, &userPrefs.modeAC.height, sizeof(userPrefs.modeAC.height)); + RegSetKeyValue(regKey, L"AC Power", L"Refresh Rate", REG_DWORD, &userPrefs.modeAC.refresh, sizeof(userPrefs.modeAC.refresh)); + return TRUE; + } + else return FALSE; +} + +// Load user preferences from registry. +static BOOL LoadPrefs(void) { + HKEY regKey; + if (!RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\WinPowerDMS", 0, KEY_READ, ®Key)) { + DWORD keySize = sizeof(DWORD); + RegGetValue(regKey, L"Battery", L"Width", RRF_RT_REG_DWORD, NULL, &userPrefs.modeBatt.width, &keySize); + keySize = sizeof(DWORD); + RegGetValue(regKey, L"Battery", L"Height", RRF_RT_REG_DWORD, NULL, &userPrefs.modeBatt.height, &keySize); + keySize = sizeof(DWORD); + RegGetValue(regKey, L"Battery", L"Refresh Rate", RRF_RT_REG_DWORD, NULL, &userPrefs.modeBatt.refresh, &keySize); + keySize = sizeof(DWORD); + RegGetValue(regKey, L"AC Power", L"Width", RRF_RT_REG_DWORD, NULL, &userPrefs.modeAC.width, &keySize); + keySize = sizeof(DWORD); + RegGetValue(regKey, L"AC Power", L"Height", RRF_RT_REG_DWORD, NULL, &userPrefs.modeAC.height, &keySize); + keySize = sizeof(DWORD); + RegGetValue(regKey, L"AC Power", L"Refresh Rate", RRF_RT_REG_DWORD, NULL, &userPrefs.modeAC.refresh, &keySize); + return TRUE; + } + else return FALSE; +} + static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: { @@ -154,21 +197,17 @@ static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam, // Add to both combo boxes and check if this is the mode that was set. SendMessage(hComboBatt, CB_ADDSTRING, 0, (LPARAM)resText); - if (DisplayModeEquals(&modeBatt, ¤tMode)) + if (DisplayModeEquals(&userPrefs.modeBatt, ¤tMode)) SendMessage(hComboBatt, CB_SETCURSEL, modeCount, 0); SendMessage(hComboAC, CB_ADDSTRING, 0, (LPARAM)resText); - if (DisplayModeEquals(&modeAC, ¤tMode)) + if (DisplayModeEquals(&userPrefs.modeAC, ¤tMode)) SendMessage(hComboAC, CB_SETCURSEL, modeCount, 0); ++modeCount; lastMode = currentMode; } } - - // select the highest display mode if one hasn't been selected yet - if (!MODE_SELECTED(modeBatt)) SendMessage(hComboBatt, CB_SETCURSEL, modeCount - 1, 0); - if (!MODE_SELECTED(modeAC)) SendMessage(hComboAC, CB_SETCURSEL, modeCount - 1, 0); return TRUE; } @@ -176,8 +215,9 @@ static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam, switch (LOWORD(wParam)) { case IDC_BUTTON_APPLY: case IDOK: { - modeBatt = GetModeFromCB(hDlg, IDC_COMBO_BATT); - modeAC = GetModeFromCB(hDlg, IDC_COMBO_AC); + userPrefs.modeBatt = GetModeFromCB(hDlg, IDC_COMBO_BATT); + userPrefs.modeAC = GetModeFromCB(hDlg, IDC_COMBO_AC); + SavePrefs(); if (LOWORD(wParam) == IDC_BUTTON_APPLY) return TRUE; } case IDCANCEL: { @@ -208,18 +248,17 @@ enum TRAY_IDS { }; static NOTIFYICONDATA nid; -static HWND hWnd; static HMENU hMenu; -static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { +static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_TRAYICON: if (lParam == WM_RBUTTONUP) { POINT pt; GetCursorPos(&pt); - SetForegroundWindow(hwnd); // Required for menu to disappear correctly + SetForegroundWindow(hWnd); // Required for menu to disappear correctly - TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL); + TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL); } break; @@ -232,7 +271,7 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l MessageBoxW(NULL, L"WinPowerDMS\nA utility for switching the resolution of your laptop's display based on the current power state.", L"About", MB_OK | MB_ICONINFORMATION); break; case ID_TRAY_EXIT: - DestroyWindow(hwnd); + DestroyWindow(hWnd); break; } break; @@ -247,17 +286,28 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l OutputDebugString(L"Power status changed\n"); SYSTEM_POWER_STATUS powerStatus; if (GetSystemPowerStatus(&powerStatus)) { - ChangeDisplayMode(powerStatus.ACLineStatus ? &modeAC : &modeBatt, CDS_UPDATEREGISTRY); + ChangeDisplayMode(powerStatus.ACLineStatus ? &userPrefs.modeAC : &userPrefs.modeBatt, CDS_UPDATEREGISTRY); } } break; } - return DefWindowProc(hwnd, uMsg, wParam, lParam); + return DefWindowProc(hWnd, uMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - // Initialize the controls - InitCommonControls(); + if (!LoadPrefs()) { // set both battery and AC to current display mode if there are no preferences set + DEVMODE currentMode = { .dmSize = sizeof(currentMode) }; + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, ¤tMode); + DISPLAY_MODE mode = { + .width = currentMode.dmPelsWidth, + .height = currentMode.dmPelsHeight, + .refresh = currentMode.dmDisplayFrequency + }; + userPrefs.modeAC = mode; + userPrefs.modeBatt = mode; + } + + InitCommonControls(); // Initialize modern controls WNDCLASS wc = { 0 }; wc.lpfnWndProc = WindowProc; @@ -266,7 +316,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine RegisterClass(&wc); - hWnd = CreateWindowEx(0, L"TrayAppClass", NULL, 0, 0, 0, 0, 0, + HWND hWnd = CreateWindowEx(0, L"TrayAppClass", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL); RegisterPowerSettingNotification(hWnd, &GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE);