From b3a25bcf8bdebb4fde966449032777857a08dcd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Thu, 5 Oct 2023 22:42:17 +0200 Subject: [PATCH] [DESK] Reimplement InstallScreenSaverW to behave similarly to Windows' one (#5766) CORE-6812 ; see also commit ff0951356 (r66688) This function "just" changes the per-user SCRNSAVE.EXE registry value to point to the new specified file, changes the SPI values and opens the desk.cpl "Screensaver" property tab for letting the user change the new selected screensaver properties. In particular, it does *NOT* copy the specified file to System32 or anything else (and doesn't verify that it is a valid PE executable). Our previous implementation did none of that, and was also relying on some private setupapi functions. We now behave closer to Windows' desk.cpl. Additionally: - ReactOS-specific feature (compile-time define) disabled by default: Verify that the specified file actually exists, before changing the screensaver. - Use NDEBUG, disabling DPRINT by default; - Improve InstallScreenSaver[A,W] spec entries; - Remove NUM_APPLETS define and use _countof() instead. --- dll/cpl/desk/desk.c | 129 +++++++++++++++++++++++++++++------------ dll/cpl/desk/desk.spec | 5 +- 2 files changed, 94 insertions(+), 40 deletions(-) diff --git a/dll/cpl/desk/desk.c b/dll/cpl/desk/desk.c index 0bbfc7a4a0e..ce780332d91 100644 --- a/dll/cpl/desk/desk.c +++ b/dll/cpl/desk/desk.c @@ -13,9 +13,17 @@ #include #include +#define NDEBUG #include -#define NUM_APPLETS (1) + +/* Enable this for InstallScreenSaverW() to determine a possible full path + * to the specified screensaver file, verify its existence and use it. + * (NOTE: This is not Windows desk.cpl-compatible.) */ +// #define CHECK_SCR_FULL_PATH + + +VOID WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow); static LONG APIENTRY DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam); @@ -26,11 +34,11 @@ INT_PTR CALLBACK AppearancePageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPAR INT_PTR CALLBACK SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); UINT CALLBACK SettingsPageCallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); -HINSTANCE hApplet = 0; -HWND hCPLWindow; +HINSTANCE hApplet = NULL; +HWND hCPLWindow = NULL; /* Applets */ -APPLET Applets[NUM_APPLETS] = +APPLET Applets[] = { { IDC_DESK_ICON, @@ -211,8 +219,8 @@ DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam) g_GlobalData.bmMonHeight = bitmap.bmHeight; } - ZeroMemory(&psh, sizeof(PROPSHEETHEADER)); - psh.dwSize = sizeof(PROPSHEETHEADER); + ZeroMemory(&psh, sizeof(psh)); + psh.dwSize = sizeof(psh); psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE | PSH_USEICONID; psh.hwndParent = hCPLWindow; psh.hInstance = hApplet; @@ -226,7 +234,7 @@ DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam) /* Allow shell extensions to replace the background page */ hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Desk"), MAX_DESK_PAGES - psh.nPages); - for (i = 0; i != sizeof(PropPages) / sizeof(PropPages[0]); i++) + for (i = 0; i < _countof(PropPages); i++) { if (pwszSelectedTab && wcsicmp(pwszSelectedTab, PropPages[i].Name) == 0) psh.nStartPage = i; @@ -276,10 +284,10 @@ CPlApplet(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2) return TRUE; case CPL_GETCOUNT: - return NUM_APPLETS; + return _countof(Applets); case CPL_INQUIRE: - if (i < NUM_APPLETS) + if (i < _countof(Applets)) { CPLINFO *CPlInfo = (CPLINFO*)lParam2; CPlInfo->lData = 0; @@ -294,14 +302,14 @@ CPlApplet(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2) break; case CPL_DBLCLK: - if (i < NUM_APPLETS) + if (i < _countof(Applets)) Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2); else return TRUE; break; case CPL_STARTWPARMSW: - if (i < NUM_APPLETS) + if (i < _countof(Applets)) return Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2); break; } @@ -317,45 +325,90 @@ InstallScreenSaverW( IN LPCWSTR pszFile, IN UINT nCmdShow) { - WCHAR pszSystemDir[MAX_PATH]; - WCHAR pszDrive[3]; - WCHAR pszPath[MAX_PATH]; - WCHAR pszFilename[MAX_PATH]; - WCHAR pszExt[MAX_PATH]; - LPWSTR pszOutName; - UINT uCompressionType=FILE_COMPRESSION_NONE; - DWORD dwSourceSize; - DWORD dwTargetSize; - DWORD rc; + LRESULT rc; + HKEY regKey; + INT Timeout; +#ifdef CHECK_SCR_FULL_PATH + HANDLE hFile; + WIN32_FIND_DATAW fdFile; +#endif + DWORD dwLen; + WCHAR szFullPath[MAX_PATH]; if (!pszFile) { - DPRINT("InstallScreenSaver() null file\n"); + DPRINT1("InstallScreenSaver() null file\n"); SetLastError(ERROR_INVALID_PARAMETER); return; } DPRINT("InstallScreenSaver() Installing screensaver %ls\n", pszFile); - rc = SetupGetFileCompressionInfoW(pszFile, &pszOutName, &dwSourceSize, &dwTargetSize, &uCompressionType); - if (ERROR_SUCCESS != rc) +#ifdef CHECK_SCR_FULL_PATH + /* Retrieve the actual path to the file and verify whether it exists */ + dwLen = GetFullPathNameW(pszFile, _countof(szFullPath), szFullPath, NULL); + if (dwLen == 0 || dwLen > _countof(szFullPath)) { - DPRINT("InstallScreenSaver() SetupGetFileCompressionInfo failed with error 0x%lx\n", rc); - SetLastError(rc); + DPRINT1("InstallScreenSaver() File %ls not accessible\n", pszFile); return; } - if (!GetSystemDirectoryW((LPWSTR)pszSystemDir, sizeof(pszSystemDir)/sizeof(WCHAR))) + hFile = FindFirstFile(szFullPath, &fdFile); + if (hFile == INVALID_HANDLE_VALUE) { - MyFree(pszOutName); - DPRINT("InstallScreenSaver() GetSystemDirectory failed with error 0x%lx\n", GetLastError()); + DPRINT1("InstallScreenSaver() File %ls not found\n", pszFile); return; } - _wsplitpath(pszOutName, pszDrive, pszPath, pszFilename, pszExt); - MyFree(pszOutName); - StringCbCatW(pszSystemDir, sizeof(pszSystemDir), L"\\"); - StringCbCatW(pszSystemDir, sizeof(pszSystemDir), pszFilename); - StringCbCatW(pszSystemDir, sizeof(pszSystemDir), pszExt); - rc = SetupDecompressOrCopyFileW(pszFile, pszSystemDir, &uCompressionType); - DPRINT("InstallScreenSaver() Copying to %ls, compression type %d return 0x%lx\n", pszFile, uCompressionType, rc); + FindClose(hFile); + /* Use the full file path from now on */ + pszFile = szFullPath; +#endif + + rc = RegOpenKeyExW(HKEY_CURRENT_USER, + L"Control Panel\\Desktop", + 0, + KEY_SET_VALUE, + ®Key); + if (rc == ERROR_SUCCESS) + { + /* Set the screensaver */ + SIZE_T Length = (wcslen(pszFile) + 1) * sizeof(WCHAR); + rc = RegSetValueExW(regKey, + L"SCRNSAVE.EXE", + 0, + REG_SZ, + (PBYTE)pszFile, + (DWORD)Length); + RegCloseKey(regKey); + } + if (rc != ERROR_SUCCESS) + { + DPRINT1("InstallScreenSaver() Could not change the current screensaver\n"); + return; + } + + SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_UPDATEINIFILE); + + /* If no screensaver timeout is present, default to 10 minutes (600 seconds) */ + Timeout = 0; + if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT, 0, &Timeout, 0) || (Timeout <= 0)) + SystemParametersInfoW(SPI_SETSCREENSAVETIMEOUT, 600, 0, SPIF_UPDATEINIFILE); + + /* Retrieve the name of this current instance of desk.cpl */ + dwLen = GetModuleFileNameW(hApplet, szFullPath, _countof(szFullPath)); + if ((dwLen == 0) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + /* We failed, copy the default value */ + StringCchCopyW(szFullPath, _countof(szFullPath), L"desk.cpl"); + } + + /* Build the desk.cpl command-line to start the ScreenSaver page. + * Equivalent to: "desk.cpl,ScreenSaver,@ScreenSaver" */ + rc = StringCchCatW(szFullPath, _countof(szFullPath), L",,1"); + if (FAILED(rc)) + return; + + /* Open the ScreenSaver page in this desk.cpl instance */ + DPRINT("InstallScreenSaver() Starting '%ls'\n", szFullPath); + Control_RunDLLW(hWindow, hInstance, szFullPath, nCmdShow); } void @@ -371,7 +424,7 @@ InstallScreenSaverA( if (!pszFile) { - DPRINT("InstallScreenSaver() null file\n"); + DPRINT1("InstallScreenSaver() null file\n"); SetLastError(ERROR_INVALID_PARAMETER); return; } @@ -393,7 +446,7 @@ InstallScreenSaverA( } if (!lpwString) { - DPRINT("InstallScreenSaver() not enough memory to convert string to unicode\n"); + DPRINT1("InstallScreenSaver() not enough memory to convert string to unicode\n"); return; } diff --git a/dll/cpl/desk/desk.spec b/dll/cpl/desk/desk.spec index ab028545161..b108c44825f 100644 --- a/dll/cpl/desk/desk.spec +++ b/dll/cpl/desk/desk.spec @@ -1,6 +1,7 @@ @ stdcall CPlApplet(ptr long ptr ptr) @ stdcall DisplayClassInstaller(long ptr ptr) @ stdcall DisplaySaveSettings(ptr ptr) -@ stdcall InstallScreenSaverW(long long ptr long) -@ stdcall InstallScreenSaverA(long long ptr long) +@ stdcall InstallScreenSaver(ptr ptr str long) InstallScreenSaverA +@ stdcall InstallScreenSaverA(ptr ptr str long) +@ stdcall InstallScreenSaverW(ptr ptr wstr long) @ stdcall MonitorClassInstaller(long ptr ptr)