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 #include <shellapi.h> 12 #include <cplext.h> 13 #include <debug.h> 14 15 #define NUM_APPLETS (1) 16 17 static LONG APIENTRY DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam); 18 19 INT_PTR CALLBACK ThemesPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 20 INT_PTR CALLBACK BackgroundPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 21 INT_PTR CALLBACK ScreenSaverPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 22 INT_PTR CALLBACK AppearancePageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 23 INT_PTR CALLBACK SettingsPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 24 UINT CALLBACK SettingsPageCallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); 25 26 HINSTANCE hApplet = 0; 27 HWND hCPLWindow; 28 29 /* Applets */ 30 APPLET Applets[NUM_APPLETS] = 31 { 32 { 33 IDC_DESK_ICON, 34 IDS_CPLNAME, 35 IDS_CPLDESCRIPTION, 36 DisplayApplet 37 } 38 }; 39 40 HMENU 41 LoadPopupMenu(IN HINSTANCE hInstance, 42 IN LPCTSTR lpMenuName) 43 { 44 HMENU hMenu, hSubMenu = NULL; 45 46 hMenu = LoadMenu(hInstance, 47 lpMenuName); 48 49 if (hMenu != NULL) 50 { 51 hSubMenu = GetSubMenu(hMenu, 52 0); 53 if (hSubMenu != NULL && 54 !RemoveMenu(hMenu, 55 0, 56 MF_BYPOSITION)) 57 { 58 hSubMenu = NULL; 59 } 60 61 DestroyMenu(hMenu); 62 } 63 64 return hSubMenu; 65 } 66 67 static BOOL CALLBACK 68 DisplayAppletPropSheetAddPage(HPROPSHEETPAGE hpage, LPARAM lParam) 69 { 70 PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam; 71 if (ppsh != NULL && ppsh->nPages < MAX_DESK_PAGES) 72 { 73 ppsh->phpage[ppsh->nPages++] = hpage; 74 return TRUE; 75 } 76 77 return FALSE; 78 } 79 80 static BOOL 81 InitPropSheetPage(PROPSHEETHEADER *ppsh, WORD idDlg, DLGPROC DlgProc, LPFNPSPCALLBACK pfnCallback) 82 { 83 HPROPSHEETPAGE hPage; 84 PROPSHEETPAGE psp; 85 86 if (ppsh->nPages < MAX_DESK_PAGES) 87 { 88 ZeroMemory(&psp, sizeof(psp)); 89 psp.dwSize = sizeof(psp); 90 psp.dwFlags = PSP_DEFAULT; 91 if (pfnCallback != NULL) 92 psp.dwFlags |= PSP_USECALLBACK; 93 psp.hInstance = hApplet; 94 psp.pszTemplate = MAKEINTRESOURCE(idDlg); 95 psp.pfnDlgProc = DlgProc; 96 psp.pfnCallback = pfnCallback; 97 98 hPage = CreatePropertySheetPage(&psp); 99 if (hPage != NULL) 100 { 101 return DisplayAppletPropSheetAddPage(hPage, (LPARAM)ppsh); 102 } 103 } 104 105 return FALSE; 106 } 107 108 static const struct 109 { 110 WORD idDlg; 111 DLGPROC DlgProc; 112 LPFNPSPCALLBACK Callback; 113 LPWSTR Name; 114 } PropPages[] = 115 { 116 /* { IDD_THEMES, ThemesPageProc, NULL, L"Themes" }, */ /* TODO: */ 117 { IDD_BACKGROUND, BackgroundPageProc, NULL, L"Desktop" }, 118 { IDD_SCREENSAVER, ScreenSaverPageProc, NULL, L"Screen Saver" }, 119 { IDD_APPEARANCE, AppearancePageProc, NULL, L"Appearance" }, 120 { IDD_SETTINGS, SettingsPageProc, SettingsPageCallbackProc, L"Settings" }, 121 }; 122 123 static int CALLBACK 124 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam) 125 { 126 // NOTE: This callback is needed to set large icon correctly. 127 HICON hIcon; 128 switch (uMsg) 129 { 130 case PSCB_INITIALIZED: 131 { 132 hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_DESK_ICON)); 133 SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); 134 break; 135 } 136 } 137 return 0; 138 } 139 140 /* Display Applet */ 141 static LONG APIENTRY 142 DisplayApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam) 143 { 144 HPROPSHEETPAGE hpsp[MAX_DESK_PAGES]; 145 PROPSHEETHEADER psh; 146 HPSXA hpsxa = NULL; 147 UINT i; 148 LPWSTR *argv = NULL; 149 LPCWSTR pwszSelectedTab = NULL; 150 LPCWSTR pwszFile = NULL; 151 LPCWSTR pwszAction = NULL; 152 INT nPage = 0; 153 154 UNREFERENCED_PARAMETER(wParam); 155 156 hCPLWindow = hwnd; 157 158 if (uMsg == CPL_STARTWPARMSW && lParam) 159 { 160 int argc; 161 int i; 162 163 nPage = _wtoi((PWSTR)lParam); 164 165 #if 0 166 argv = CommandLineToArgvW((LPCWSTR)lParam, &argc); 167 #else 168 argv = CommandLineToArgvW(GetCommandLineW(), &argc); 169 #endif 170 171 if (argv && argc) 172 { 173 for (i = 0; i<argc; i++) 174 { 175 #if 0 176 if (argv[i][0] == L'@') 177 pwszSelectedTab = &argv[i][1]; 178 #else 179 if (wcsncmp(argv[i], L"desk,@", 6) == 0) 180 pwszSelectedTab = &argv[i][6]; 181 #endif 182 else if (wcsncmp(argv[i], L"/Action:", 8) == 0) 183 pwszAction = &argv[i][8]; 184 else if (wcsncmp(argv[i], L"/file:", 6) == 0) 185 pwszFile = &argv[i][6]; 186 } 187 } 188 } 189 190 if(pwszAction && wcsncmp(pwszAction, L"ActivateMSTheme", 15) == 0) 191 { 192 ActivateThemeFile(pwszFile); 193 goto cleanup; 194 } 195 196 g_GlobalData.pwszFile = pwszFile; 197 g_GlobalData.pwszAction = pwszAction; 198 g_GlobalData.desktop_color = GetSysColor(COLOR_DESKTOP); 199 200 ZeroMemory(&psh, sizeof(PROPSHEETHEADER)); 201 psh.dwSize = sizeof(PROPSHEETHEADER); 202 psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE | PSH_USEICONID; 203 psh.hwndParent = hCPLWindow; 204 psh.hInstance = hApplet; 205 psh.pszIcon = MAKEINTRESOURCEW(IDC_DESK_ICON); 206 psh.pszCaption = MAKEINTRESOURCEW(IDS_CPLNAME); 207 psh.nPages = 0; 208 psh.nStartPage = 0; 209 psh.phpage = hpsp; 210 psh.pfnCallback = PropSheetProc; 211 212 /* Allow shell extensions to replace the background page */ 213 hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Desk"), MAX_DESK_PAGES - psh.nPages); 214 215 for (i = 0; i != sizeof(PropPages) / sizeof(PropPages[0]); i++) 216 { 217 if (pwszSelectedTab && wcsicmp(pwszSelectedTab, PropPages[i].Name) == 0) 218 psh.nStartPage = i; 219 220 /* Override the background page if requested by a shell extension */ 221 if (PropPages[i].idDlg == IDD_BACKGROUND && hpsxa != NULL && 222 SHReplaceFromPropSheetExtArray(hpsxa, CPLPAGE_DISPLAY_BACKGROUND, DisplayAppletPropSheetAddPage, (LPARAM)&psh) != 0) 223 { 224 /* The shell extension added one or more pages to replace the background page. 225 Don't create the built-in page anymore! */ 226 continue; 227 } 228 229 InitPropSheetPage(&psh, PropPages[i].idDlg, PropPages[i].DlgProc, PropPages[i].Callback); 230 } 231 232 /* NOTE: Don't call SHAddFromPropSheetExtArray here because this applet only allows 233 replacing the background page but not extending the applet by more pages */ 234 235 if (nPage != 0 && psh.nStartPage == 0) 236 psh.nStartPage = nPage; 237 238 PropertySheet(&psh); 239 240 cleanup: 241 if (hpsxa != NULL) 242 SHDestroyPropSheetExtArray(hpsxa); 243 244 if (argv) 245 LocalFree(argv); 246 247 return TRUE; 248 } 249 250 251 /* Control Panel Callback */ 252 LONG CALLBACK 253 CPlApplet(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2) 254 { 255 UINT i = (UINT)lParam1; 256 257 switch (uMsg) 258 { 259 case CPL_INIT: 260 return TRUE; 261 262 case CPL_GETCOUNT: 263 return NUM_APPLETS; 264 265 case CPL_INQUIRE: 266 if (i < NUM_APPLETS) 267 { 268 CPLINFO *CPlInfo = (CPLINFO*)lParam2; 269 CPlInfo->lData = 0; 270 CPlInfo->idIcon = Applets[i].idIcon; 271 CPlInfo->idName = Applets[i].idName; 272 CPlInfo->idInfo = Applets[i].idDescription; 273 } 274 else 275 { 276 return TRUE; 277 } 278 break; 279 280 case CPL_DBLCLK: 281 if (i < NUM_APPLETS) 282 Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2); 283 else 284 return TRUE; 285 break; 286 287 case CPL_STARTWPARMSW: 288 if (i < NUM_APPLETS) 289 return Applets[i].AppletProc(hwndCPl, uMsg, lParam1, lParam2); 290 break; 291 } 292 293 return FALSE; 294 } 295 296 void 297 WINAPI 298 InstallScreenSaverW( 299 IN HWND hWindow, 300 IN HANDLE hInstance, 301 IN LPCWSTR pszFile, 302 IN UINT nCmdShow) 303 { 304 WCHAR pszSystemDir[MAX_PATH]; 305 WCHAR pszDrive[3]; 306 WCHAR pszPath[MAX_PATH]; 307 WCHAR pszFilename[MAX_PATH]; 308 WCHAR pszExt[MAX_PATH]; 309 LPWSTR pszOutName; 310 UINT uCompressionType=FILE_COMPRESSION_NONE; 311 DWORD dwSourceSize; 312 DWORD dwTargetSize; 313 DWORD rc; 314 315 if (!pszFile) 316 { 317 DPRINT("InstallScreenSaver() null file\n"); 318 SetLastError(ERROR_INVALID_PARAMETER); 319 return; 320 } 321 DPRINT("InstallScreenSaver() Installing screensaver %ls\n", pszFile); 322 323 rc = SetupGetFileCompressionInfoW(pszFile, &pszOutName, &dwSourceSize, &dwTargetSize, &uCompressionType); 324 if (ERROR_SUCCESS != rc) 325 { 326 DPRINT("InstallScreenSaver() SetupGetFileCompressionInfo failed with error 0x%lx\n", rc); 327 SetLastError(rc); 328 return; 329 } 330 if (!GetSystemDirectoryW((LPWSTR)pszSystemDir, sizeof(pszSystemDir)/sizeof(WCHAR))) 331 { 332 MyFree(pszOutName); 333 DPRINT("InstallScreenSaver() GetSystemDirectory failed with error 0x%lx\n", GetLastError()); 334 return; 335 } 336 _wsplitpath(pszOutName, pszDrive, pszPath, pszFilename, pszExt); 337 MyFree(pszOutName); 338 StringCbCatW(pszSystemDir, sizeof(pszSystemDir), L"\\"); 339 StringCbCatW(pszSystemDir, sizeof(pszSystemDir), pszFilename); 340 StringCbCatW(pszSystemDir, sizeof(pszSystemDir), pszExt); 341 rc = SetupDecompressOrCopyFileW(pszFile, pszSystemDir, &uCompressionType); 342 DPRINT("InstallScreenSaver() Copying to %ls, compression type %d return 0x%lx\n", pszFile, uCompressionType, rc); 343 } 344 345 void 346 WINAPI 347 InstallScreenSaverA( 348 IN HWND hWindow, 349 IN HANDLE hInstance, 350 IN LPCSTR pszFile, 351 IN UINT nCmdShow) 352 { 353 LPWSTR lpwString; 354 355 if (!pszFile) 356 { 357 DPRINT("InstallScreenSaver() null file\n"); 358 SetLastError(ERROR_INVALID_PARAMETER); 359 return; 360 } 361 DPRINT("InstallScreenSaver() Install from file %s\n", pszFile); 362 lpwString = pSetupMultiByteToUnicode(pszFile, 0); 363 if (!lpwString) 364 { 365 DPRINT("InstallScreenSaver() not enough memory to convert string to unicode\n"); 366 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 367 return; 368 } 369 InstallScreenSaverW(hWindow, hInstance, lpwString, nCmdShow); 370 MyFree(lpwString); 371 } 372 373 BOOL WINAPI 374 DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpvReserved) 375 { 376 UNREFERENCED_PARAMETER(lpvReserved); 377 378 switch (dwReason) 379 { 380 case DLL_PROCESS_ATTACH: 381 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 382 RegisterPreviewControl(hInstDLL); 383 // case DLL_THREAD_ATTACH: 384 hApplet = hInstDLL; 385 break; 386 387 case DLL_PROCESS_DETACH: 388 UnregisterPreviewControl(hInstDLL); 389 CoUninitialize(); 390 break; 391 } 392 393 return TRUE; 394 } 395