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