1 /*
2  *    Folder Options
3  *
4  * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org>
5  * Copyright 2016-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "precomp.h"
23 
24 WINE_DEFAULT_DEBUG_CHANNEL (fprop);
25 
26 // Folder Options:
27 // CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}
28 
29 /////////////////////////////////////////////////////////////////////////////
30 // strings
31 
32 // path to shell32
33 LPCWSTR g_pszShell32 = L"%SystemRoot%\\system32\\shell32.dll";
34 
35 // the space characters
36 LPCWSTR g_pszSpace = L" \t\n\r\f\v";
37 
38 /////////////////////////////////////////////////////////////////////////////
39 // utility functions
40 
Create24BppBitmap(HDC hDC,INT cx,INT cy)41 HBITMAP Create24BppBitmap(HDC hDC, INT cx, INT cy)
42 {
43     BITMAPINFO bi;
44     LPVOID pvBits;
45 
46     ZeroMemory(&bi, sizeof(bi));
47     bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
48     bi.bmiHeader.biWidth = cx;
49     bi.bmiHeader.biHeight = cy;
50     bi.bmiHeader.biPlanes = 1;
51     bi.bmiHeader.biBitCount = 24;
52     bi.bmiHeader.biCompression = BI_RGB;
53 
54     HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0);
55     return hbm;
56 }
57 
BitmapFromIcon(HICON hIcon,INT cx,INT cy)58 HBITMAP BitmapFromIcon(HICON hIcon, INT cx, INT cy)
59 {
60     HDC hDC = CreateCompatibleDC(NULL);
61     if (!hDC)
62         return NULL;
63 
64     HBITMAP hbm = Create24BppBitmap(hDC, cx, cy);
65     if (!hbm)
66     {
67         DeleteDC(hDC);
68         return NULL;
69     }
70 
71     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
72     {
73         RECT rc = { 0, 0, cx, cy };
74         FillRect(hDC, &rc, HBRUSH(COLOR_3DFACE + 1));
75         if (hIcon)
76         {
77             DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);
78         }
79     }
80     SelectObject(hDC, hbmOld);
81     DeleteDC(hDC);
82 
83     return hbm;
84 }
85 
CreateCheckImage(HDC hDC,BOOL bCheck,BOOL bEnabled)86 HBITMAP CreateCheckImage(HDC hDC, BOOL bCheck, BOOL bEnabled)
87 {
88     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
89     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
90 
91     HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon);
92     if (hbm == NULL)
93         return NULL;    // failure
94 
95     RECT Rect, BoxRect;
96     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
97     BoxRect = Rect;
98     InflateRect(&BoxRect, -1, -1);
99 
100     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
101     {
102         UINT uState = DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_MONO;
103         if (bCheck)
104             uState |= DFCS_CHECKED;
105         if (!bEnabled)
106             uState |= DFCS_INACTIVE;
107         DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
108     }
109     SelectObject(hDC, hbmOld);
110 
111     return hbm;     // success
112 }
113 
CreateCheckMask(HDC hDC)114 HBITMAP CreateCheckMask(HDC hDC)
115 {
116     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
117     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
118 
119     HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL);
120     if (hbm == NULL)
121         return NULL;    // failure
122 
123     RECT Rect, BoxRect;
124     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
125     BoxRect = Rect;
126     InflateRect(&BoxRect, -1, -1);
127 
128     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
129     {
130         FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH)));
131         FillRect(hDC, &BoxRect, HBRUSH(GetStockObject(BLACK_BRUSH)));
132     }
133     SelectObject(hDC, hbmOld);
134 
135     return hbm;     // success
136 }
137 
CreateRadioImage(HDC hDC,BOOL bCheck,BOOL bEnabled)138 HBITMAP CreateRadioImage(HDC hDC, BOOL bCheck, BOOL bEnabled)
139 {
140     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
141     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
142 
143     HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon);
144     if (hbm == NULL)
145         return NULL;    // failure
146 
147     RECT Rect, BoxRect;
148     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
149     BoxRect = Rect;
150     InflateRect(&BoxRect, -1, -1);
151 
152     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
153     {
154         UINT uState = DFCS_BUTTONRADIOIMAGE | DFCS_FLAT | DFCS_MONO;
155         if (bCheck)
156             uState |= DFCS_CHECKED;
157         if (!bEnabled)
158             uState |= DFCS_INACTIVE;
159         DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
160     }
161     SelectObject(hDC, hbmOld);
162 
163     return hbm;     // success
164 }
165 
CreateRadioMask(HDC hDC)166 HBITMAP CreateRadioMask(HDC hDC)
167 {
168     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
169     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
170 
171     HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL);
172     if (hbm == NULL)
173         return NULL;    // failure
174 
175     RECT Rect, BoxRect;
176     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
177     BoxRect = Rect;
178     InflateRect(&BoxRect, -1, -1);
179 
180     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
181     {
182         FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH)));
183         UINT uState = DFCS_BUTTONRADIOMASK | DFCS_FLAT | DFCS_MONO;
184         DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
185     }
186     SelectObject(hDC, hbmOld);
187 
188     return hbm;     // success
189 }
190 
191 /////////////////////////////////////////////////////////////////////////////
192 
193 // CMSGlobalFolderOptionsStub --- The owner window of Folder Options.
194 // This window hides taskbar button of Folder Options.
195 
196 #define GlobalFolderOptionsClassName _T("MSGlobalFolderOptionsStub")
197 
198 class CMSGlobalFolderOptionsStub : public CWindowImpl<CMSGlobalFolderOptionsStub>
199 {
200 public:
201     DECLARE_WND_CLASS_EX(GlobalFolderOptionsClassName, 0, COLOR_WINDOWTEXT)
202 
203     BEGIN_MSG_MAP(CMSGlobalFolderOptionsStub)
204     END_MSG_MAP()
205 };
206 
207 /////////////////////////////////////////////////////////////////////////////
208 
209 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
210 
211 static int CALLBACK
PropSheetProc(HWND hwndDlg,UINT uMsg,LPARAM lParam)212 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
213 {
214     // NOTE: This callback is needed to set large icon correctly.
215     HICON hIcon;
216     switch (uMsg)
217     {
218         case PSCB_INITIALIZED:
219         {
220             hIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS));
221             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
222             break;
223         }
224     }
225     return 0;
226 }
227 
228 enum {
229     PAGE_GENERAL,
230     PAGE_VIEW,
231     PAGE_FILETYPES
232 };
233 
234 static DWORD CALLBACK
ShowFolderOptionsDialogThreadProc(LPVOID param)235 ShowFolderOptionsDialogThreadProc(LPVOID param)
236 {
237     CCoInit com; // Required when started from rundll32 (SHAutoComplete in PickIconDlg)
238     PROPSHEETHEADERW pinfo;
239     HPROPSHEETPAGE hppages[3];
240     HPROPSHEETPAGE hpage;
241     UINT num_pages = 0;
242 
243     hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL);
244     if (hpage)
245         hppages[num_pages++] = hpage;
246 
247     hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL);
248     if (hpage)
249         hppages[num_pages++] = hpage;
250 
251     hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL);
252     if (hpage)
253         hppages[num_pages++] = hpage;
254 
255     // the stub window to hide taskbar button
256     DWORD style = WS_DISABLED | WS_CLIPSIBLINGS | WS_CAPTION;
257     DWORD exstyle = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW;
258     CMSGlobalFolderOptionsStub stub;
259     if (!stub.Create(NULL, NULL, NULL, style, exstyle))
260     {
261         ERR("stub.Create failed\n");
262         return 0;
263     }
264 
265     memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
266     pinfo.dwSize = sizeof(PROPSHEETHEADERW);
267     pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_USEICONID | PSH_USECALLBACK;
268     pinfo.hwndParent = stub;
269     pinfo.nPages = num_pages;
270     pinfo.phpage = hppages;
271     pinfo.hInstance = shell32_hInstance;
272     pinfo.pszIcon = MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS);
273     pinfo.pszCaption = MAKEINTRESOURCEW(IDS_FOLDER_OPTIONS);
274     pinfo.pfnCallback = PropSheetProc;
275     pinfo.nStartPage = PtrToUlong(param);
276 
277     PropertySheetW(&pinfo);
278 
279     stub.DestroyWindow();
280     return 0;
281 }
282 
283 VOID WINAPI
ShowFolderOptionsDialog(UINT Page,BOOL Async=FALSE)284 ShowFolderOptionsDialog(UINT Page, BOOL Async = FALSE)
285 {
286     HWND hWnd = FindWindow(GlobalFolderOptionsClassName, NULL);
287     if (hWnd)
288     {
289         HWND hPop = GetLastActivePopup(hWnd);
290         if (hWnd == GetParent(hPop))
291         {
292             PostMessage(hPop, PSM_SETCURSEL, Page, 0);
293         }
294         SetForegroundWindow(hPop);
295         return;
296     }
297 
298     LPVOID param = UlongToPtr(Page);
299     if (Async)
300         SHCreateThread(ShowFolderOptionsDialogThreadProc, param, 0, 0);
301     else
302         ShowFolderOptionsDialogThreadProc(param); // Rundll32 caller cannot be async!
303 }
304 
305 static VOID
Options_RunDLLCommon(HWND hWnd,HINSTANCE hInst,int fOptions,DWORD nCmdShow)306 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow)
307 {
308     switch(fOptions)
309     {
310         case 0:
311             ShowFolderOptionsDialog(PAGE_GENERAL);
312             break;
313 
314         case 1: // Taskbar settings
315 #if (NTDDI_VERSION >= NTDDI_VISTA)
316         case 3: // Start menu settings
317         case 4: // Tray icon settings
318         case 6: // Taskbar toolbars
319 #endif
320             PostMessage(GetShellWindow(), WM_PROGMAN_OPENSHELLSETTINGS, fOptions, 0);
321             break;
322 
323         case 7: // Windows 8, 10
324             ShowFolderOptionsDialog(PAGE_VIEW);
325             break;
326 
327         default:
328             FIXME("unrecognized options id %d\n", fOptions);
329     }
330 }
331 
332 /*************************************************************************
333  *              Options_RunDLL (SHELL32.@)
334  */
335 EXTERN_C VOID WINAPI
Options_RunDLL(HWND hWnd,HINSTANCE hInst,LPCSTR cmd,DWORD nCmdShow)336 Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
337 {
338     Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
339 }
340 
341 /*************************************************************************
342  *              Options_RunDLLA (SHELL32.@)
343  */
344 EXTERN_C VOID WINAPI
Options_RunDLLA(HWND hWnd,HINSTANCE hInst,LPCSTR cmd,DWORD nCmdShow)345 Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
346 {
347     Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
348 }
349 
350 /*************************************************************************
351  *              Options_RunDLLW (SHELL32.@)
352  */
353 EXTERN_C VOID WINAPI
Options_RunDLLW(HWND hWnd,HINSTANCE hInst,LPCWSTR cmd,DWORD nCmdShow)354 Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
355 {
356     Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow);
357 }
358