1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Display Control Panel 4 * FILE: dll/cpl/desk/desk.c 5 * PURPOSE: ReactOS Display Control Panel 6 * 7 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com) 8 */ 9 10 #include "desk.h" 11 12 #include <shellapi.h> 13 #include <cplext.h> 14 #include <winnls.h> 15 16 #define NDEBUG 17 #include <debug.h> 18 19 20 /* Enable this for InstallScreenSaverW() to determine a possible full path 21 * to the specified screensaver file, verify its existence and use it. 22 * (NOTE: This is not Windows desk.cpl-compatible.) */ 23 // #define CHECK_SCR_FULL_PATH 24 25 26 VOID WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow); 27 28 static LONG APIENTRY DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam); 29 30 INT_PTR CALLBACK ThemesPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 31 INT_PTR CALLBACK BackgroundPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 32 INT_PTR CALLBACK ScreenSaverPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 33 INT_PTR CALLBACK AppearancePageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 34 INT_PTR CALLBACK SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 35 UINT CALLBACK SettingsPageCallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); 36 37 HINSTANCE hApplet = NULL; 38 HWND hCPLWindow = NULL; 39 40 /* Applets */ 41 APPLET Applets[] = 42 { 43 { 44 IDC_DESK_ICON, 45 IDS_CPLNAME, 46 IDS_CPLDESCRIPTION, 47 DisplayApplet 48 } 49 }; 50 51 HMENU 52 LoadPopupMenu(IN HINSTANCE hInstance, 53 IN LPCTSTR lpMenuName) 54 { 55 HMENU hMenu, hSubMenu = NULL; 56 57 hMenu = LoadMenu(hInstance, 58 lpMenuName); 59 60 if (hMenu != NULL) 61 { 62 hSubMenu = GetSubMenu(hMenu, 63 0); 64 if (hSubMenu != NULL && 65 !RemoveMenu(hMenu, 66 0, 67 MF_BYPOSITION)) 68 { 69 hSubMenu = NULL; 70 } 71 72 DestroyMenu(hMenu); 73 } 74 75 return hSubMenu; 76 } 77 78 static BOOL CALLBACK 79 DisplayAppletPropSheetAddPage(HPROPSHEETPAGE hpage, LPARAM lParam) 80 { 81 PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam; 82 if (ppsh != NULL && ppsh->nPages < MAX_DESK_PAGES) 83 { 84 ppsh->phpage[ppsh->nPages++] = hpage; 85 return TRUE; 86 } 87 88 return FALSE; 89 } 90 91 static BOOL 92 InitPropSheetPage(PROPSHEETHEADER *ppsh, WORD idDlg, DLGPROC DlgProc, LPFNPSPCALLBACK pfnCallback) 93 { 94 HPROPSHEETPAGE hPage; 95 PROPSHEETPAGE psp; 96 97 if (ppsh->nPages < MAX_DESK_PAGES) 98 { 99 ZeroMemory(&psp, sizeof(psp)); 100 psp.dwSize = sizeof(psp); 101 psp.dwFlags = PSP_DEFAULT; 102 if (pfnCallback != NULL) 103 psp.dwFlags |= PSP_USECALLBACK; 104 psp.hInstance = hApplet; 105 psp.pszTemplate = MAKEINTRESOURCE(idDlg); 106 psp.pfnDlgProc = DlgProc; 107 psp.pfnCallback = pfnCallback; 108 109 hPage = CreatePropertySheetPage(&psp); 110 if (hPage != NULL) 111 { 112 return DisplayAppletPropSheetAddPage(hPage, (LPARAM)ppsh); 113 } 114 } 115 116 return FALSE; 117 } 118 119 static const struct 120 { 121 WORD idDlg; 122 DLGPROC DlgProc; 123 LPFNPSPCALLBACK Callback; 124 LPWSTR Name; 125 } PropPages[] = 126 { 127 /* { IDD_THEMES, ThemesPageProc, NULL, L"Themes" }, */ /* TODO: */ 128 { IDD_BACKGROUND, BackgroundPageProc, NULL, L"Desktop" }, 129 { IDD_SCREENSAVER, ScreenSaverPageProc, NULL, L"Screen Saver" }, 130 { IDD_APPEARANCE, AppearancePageProc, NULL, L"Appearance" }, 131 { IDD_SETTINGS, SettingsPageProc, SettingsPageCallbackProc, L"Settings" }, 132 }; 133 134 static int CALLBACK 135 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam) 136 { 137 // NOTE: This callback is needed to set large icon correctly. 138 HICON hIcon; 139 switch (uMsg) 140 { 141 case PSCB_INITIALIZED: 142 { 143 hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_DESK_ICON)); 144 SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); 145 break; 146 } 147 } 148 return 0; 149 } 150 151 /* Display Applet */ 152 static LONG APIENTRY 153 DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam) 154 { 155 HPROPSHEETPAGE hpsp[MAX_DESK_PAGES]; 156 PROPSHEETHEADER psh; 157 HPSXA hpsxa = NULL; 158 UINT i; 159 LPWSTR *argv = NULL; 160 LPCWSTR pwszSelectedTab = NULL; 161 LPCWSTR pwszFile = NULL; 162 LPCWSTR pwszAction = NULL; 163 INT nPage = 0; 164 BITMAP bitmap; 165 166 UNREFERENCED_PARAMETER(wParam); 167 168 hCPLWindow = hwnd; 169 170 if (uMsg == CPL_STARTWPARMSW && lParam) 171 { 172 int argc; 173 int i; 174 175 nPage = _wtoi((PWSTR)lParam); 176 177 #if 0 178 argv = CommandLineToArgvW((LPCWSTR)lParam, &argc); 179 #else 180 argv = CommandLineToArgvW(GetCommandLineW(), &argc); 181 #endif 182 183 if (argv && argc) 184 { 185 for (i = 0; i<argc; i++) 186 { 187 #if 0 188 if (argv[i][0] == L'@') 189 pwszSelectedTab = &argv[i][1]; 190 #else 191 if (wcsncmp(argv[i], L"desk,@", 6) == 0) 192 pwszSelectedTab = &argv[i][6]; 193 #endif 194 else if (wcsncmp(argv[i], L"/Action:", 8) == 0) 195 pwszAction = &argv[i][8]; 196 else if (wcsncmp(argv[i], L"/file:", 6) == 0) 197 pwszFile = &argv[i][6]; 198 } 199 } 200 } 201 202 if(pwszAction && wcsncmp(pwszAction, L"ActivateMSTheme", 15) == 0) 203 { 204 ActivateThemeFile(pwszFile); 205 goto cleanup; 206 } 207 208 g_GlobalData.pwszFile = pwszFile; 209 g_GlobalData.pwszAction = pwszAction; 210 g_GlobalData.desktop_color = GetSysColor(COLOR_DESKTOP); 211 212 /* Initialize the monitor preview bitmap, used on multiple pages */ 213 g_GlobalData.hMonitorBitmap = LoadBitmapW(hApplet, MAKEINTRESOURCEW(IDC_MONITOR)); 214 if (g_GlobalData.hMonitorBitmap != NULL) 215 { 216 GetObjectW(g_GlobalData.hMonitorBitmap, sizeof(bitmap), &bitmap); 217 218 g_GlobalData.bmMonWidth = bitmap.bmWidth; 219 g_GlobalData.bmMonHeight = bitmap.bmHeight; 220 } 221 222 ZeroMemory(&psh, sizeof(psh)); 223 psh.dwSize = sizeof(psh); 224 psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE | PSH_USEICONID; 225 psh.hwndParent = hCPLWindow; 226 psh.hInstance = hApplet; 227 psh.pszIcon = MAKEINTRESOURCEW(IDC_DESK_ICON); 228 psh.pszCaption = MAKEINTRESOURCEW(IDS_CPLNAME); 229 psh.nPages = 0; 230 psh.nStartPage = 0; 231 psh.phpage = hpsp; 232 psh.pfnCallback = PropSheetProc; 233 234 /* Allow shell extensions to replace the background page */ 235 hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Desk"), MAX_DESK_PAGES - psh.nPages); 236 237 for (i = 0; i < _countof(PropPages); i++) 238 { 239 if (pwszSelectedTab && _wcsicmp(pwszSelectedTab, PropPages[i].Name) == 0) 240 psh.nStartPage = i; 241 242 /* Override the background page if requested by a shell extension */ 243 if (PropPages[i].idDlg == IDD_BACKGROUND && hpsxa != NULL && 244 SHReplaceFromPropSheetExtArray(hpsxa, CPLPAGE_DISPLAY_BACKGROUND, DisplayAppletPropSheetAddPage, (LPARAM)&psh) != 0) 245 { 246 /* The shell extension added one or more pages to replace the background page. 247 Don't create the built-in page anymore! */ 248 continue; 249 } 250 251 InitPropSheetPage(&psh, PropPages[i].idDlg, PropPages[i].DlgProc, PropPages[i].Callback); 252 } 253 254 /* NOTE: Don't call SHAddFromPropSheetExtArray here because this applet only allows 255 replacing the background page but not extending the applet by more pages */ 256 257 if (nPage != 0 && psh.nStartPage == 0) 258 psh.nStartPage = nPage; 259 260 PropertySheet(&psh); 261 262 cleanup: 263 DeleteObject(g_GlobalData.hMonitorBitmap); 264 265 if (hpsxa != NULL) 266 SHDestroyPropSheetExtArray(hpsxa); 267 268 if (argv) 269 LocalFree(argv); 270 271 return TRUE; 272 } 273 274 275 /* Control Panel Callback */ 276 LONG CALLBACK 277 CPlApplet(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2) 278 { 279 UINT i = (UINT)lParam1; 280 281 switch (uMsg) 282 { 283 case CPL_INIT: 284 return TRUE; 285 286 case CPL_GETCOUNT: 287 return _countof(Applets); 288 289 case CPL_INQUIRE: 290 if (i < _countof(Applets)) 291 { 292 CPLINFO *CPlInfo = (CPLINFO*)lParam2; 293 CPlInfo->lData = 0; 294 CPlInfo->idIcon = Applets[i].idIcon; 295 CPlInfo->idName = Applets[i].idName; 296 CPlInfo->idInfo = Applets[i].idDescription; 297 } 298 else 299 { 300 return TRUE; 301 } 302 break; 303 304 case CPL_DBLCLK: 305 if (i < _countof(Applets)) 306 Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2); 307 else 308 return TRUE; 309 break; 310 311 case CPL_STARTWPARMSW: 312 if (i < _countof(Applets)) 313 return Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2); 314 break; 315 } 316 317 return FALSE; 318 } 319 320 void 321 WINAPI 322 InstallScreenSaverW( 323 IN HWND hWindow, 324 IN HANDLE hInstance, 325 IN LPCWSTR pszFile, 326 IN UINT nCmdShow) 327 { 328 LRESULT rc; 329 HKEY regKey; 330 INT Timeout; 331 #ifdef CHECK_SCR_FULL_PATH 332 HANDLE hFile; 333 WIN32_FIND_DATAW fdFile; 334 #endif 335 DWORD dwLen; 336 WCHAR szFullPath[MAX_PATH]; 337 338 if (!pszFile) 339 { 340 DPRINT1("InstallScreenSaver() null file\n"); 341 SetLastError(ERROR_INVALID_PARAMETER); 342 return; 343 } 344 DPRINT("InstallScreenSaver() Installing screensaver %ls\n", pszFile); 345 346 #ifdef CHECK_SCR_FULL_PATH 347 /* Retrieve the actual path to the file and verify whether it exists */ 348 dwLen = GetFullPathNameW(pszFile, _countof(szFullPath), szFullPath, NULL); 349 if (dwLen == 0 || dwLen > _countof(szFullPath)) 350 { 351 DPRINT1("InstallScreenSaver() File %ls not accessible\n", pszFile); 352 return; 353 } 354 hFile = FindFirstFile(szFullPath, &fdFile); 355 if (hFile == INVALID_HANDLE_VALUE) 356 { 357 DPRINT1("InstallScreenSaver() File %ls not found\n", pszFile); 358 return; 359 } 360 FindClose(hFile); 361 /* Use the full file path from now on */ 362 pszFile = szFullPath; 363 #endif 364 365 rc = RegOpenKeyExW(HKEY_CURRENT_USER, 366 L"Control Panel\\Desktop", 367 0, 368 KEY_SET_VALUE, 369 ®Key); 370 if (rc == ERROR_SUCCESS) 371 { 372 /* Set the screensaver */ 373 SIZE_T Length = (wcslen(pszFile) + 1) * sizeof(WCHAR); 374 rc = RegSetValueExW(regKey, 375 L"SCRNSAVE.EXE", 376 0, 377 REG_SZ, 378 (PBYTE)pszFile, 379 (DWORD)Length); 380 RegCloseKey(regKey); 381 } 382 if (rc != ERROR_SUCCESS) 383 { 384 DPRINT1("InstallScreenSaver() Could not change the current screensaver\n"); 385 return; 386 } 387 388 SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_UPDATEINIFILE); 389 390 /* If no screensaver timeout is present, default to 10 minutes (600 seconds) */ 391 Timeout = 0; 392 if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT, 0, &Timeout, 0) || (Timeout <= 0)) 393 SystemParametersInfoW(SPI_SETSCREENSAVETIMEOUT, 600, 0, SPIF_UPDATEINIFILE); 394 395 /* Retrieve the name of this current instance of desk.cpl */ 396 dwLen = GetModuleFileNameW(hApplet, szFullPath, _countof(szFullPath)); 397 if ((dwLen == 0) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 398 { 399 /* We failed, copy the default value */ 400 StringCchCopyW(szFullPath, _countof(szFullPath), L"desk.cpl"); 401 } 402 403 /* Build the desk.cpl command-line to start the ScreenSaver page. 404 * Equivalent to: "desk.cpl,ScreenSaver,@ScreenSaver" */ 405 rc = StringCchCatW(szFullPath, _countof(szFullPath), L",,1"); 406 if (FAILED(rc)) 407 return; 408 409 /* Open the ScreenSaver page in this desk.cpl instance */ 410 DPRINT("InstallScreenSaver() Starting '%ls'\n", szFullPath); 411 Control_RunDLLW(hWindow, hInstance, szFullPath, nCmdShow); 412 } 413 414 void 415 WINAPI 416 InstallScreenSaverA( 417 IN HWND hWindow, 418 IN HANDLE hInstance, 419 IN LPCSTR pszFile, 420 IN UINT nCmdShow) 421 { 422 LPWSTR lpwString; 423 int nLength; 424 425 if (!pszFile) 426 { 427 DPRINT1("InstallScreenSaver() null file\n"); 428 SetLastError(ERROR_INVALID_PARAMETER); 429 return; 430 } 431 432 /* Convert the string to unicode */ 433 lpwString = NULL; 434 nLength = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0); 435 if (nLength != 0) 436 { 437 lpwString = LocalAlloc(LMEM_FIXED, nLength * sizeof(WCHAR)); 438 if (lpwString) 439 { 440 if (!MultiByteToWideChar(CP_ACP, 0, pszFile, -1, lpwString, nLength)) 441 { 442 LocalFree(lpwString); 443 lpwString = NULL; 444 } 445 } 446 } 447 if (!lpwString) 448 { 449 DPRINT1("InstallScreenSaver() not enough memory to convert string to unicode\n"); 450 return; 451 } 452 453 /* Call the unicode function */ 454 InstallScreenSaverW(hWindow, hInstance, lpwString, nCmdShow); 455 456 LocalFree(lpwString); 457 } 458 459 BOOL WINAPI 460 DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpvReserved) 461 { 462 UNREFERENCED_PARAMETER(lpvReserved); 463 464 switch (dwReason) 465 { 466 case DLL_PROCESS_ATTACH: 467 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 468 RegisterPreviewControl(hInstDLL); 469 // case DLL_THREAD_ATTACH: 470 hApplet = hInstDLL; 471 break; 472 473 case DLL_PROCESS_DETACH: 474 UnregisterPreviewControl(hInstDLL); 475 CoUninitialize(); 476 break; 477 } 478 479 return TRUE; 480 } 481