1 /*
2 * 'General' tab property sheet of 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 static const LPCWSTR s_pszExplorerKey =
27 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer";
28
29 /////////////////////////////////////////////////////////////////////////////
30 // Shell settings
31
32 EXTERN_C void
SHELL32_GetDefaultShellState(LPSHELLSTATE pss)33 SHELL32_GetDefaultShellState(LPSHELLSTATE pss)
34 {
35 ZeroMemory(pss, sizeof(*pss));
36 pss->fShowAllObjects = TRUE;
37 pss->fShowExtensions = TRUE;
38 pss->fShowCompColor = TRUE;
39 pss->fDoubleClickInWebView = TRUE;
40 pss->fShowAttribCol = TRUE; // ROS defaults to Details view with this column on
41 pss->fShowInfoTip = TRUE;
42 pss->fShowSuperHidden = FALSE;
43 pss->lParamSort = SHFSF_COL_NAME;
44 pss->iSortDirection = 1;
45 pss->version = REGSHELLSTATE_VERSION;
46 pss->fSepProcess = FALSE;
47 pss->fStartPanelOn = FALSE; // Note: This should be changed to TRUE when the modern start menu is implemented
48 }
49
50 EXTERN_C LSTATUS
SHELL32_WriteRegShellState(PREGSHELLSTATE prss)51 SHELL32_WriteRegShellState(PREGSHELLSTATE prss)
52 {
53 prss->dwSize = REGSHELLSTATE_SIZE;
54 prss->ss.version = REGSHELLSTATE_VERSION;
55 return SHSetValueW(HKEY_CURRENT_USER, s_pszExplorerKey, L"ShellState",
56 REG_BINARY, prss, prss->dwSize);
57 }
58
59 // bDoubleClick is TRUE if "Double-click to open an item (single-click to select)".
60 // bDoubleClick is FALSE if "Single-click to open an item (point to select)".
61 //////////////////////////////////////////////////////////////////////////////
62 // API Monitor:
63 // SHLWAPI.dll RegOpenKeyExW ( 0x000000c8, NULL, 0, MAXIMUM_ALLOWED, 0x00def234 ) ERROR_SUCCESS 0.0000243
64 // SHLWAPI.dll RegSetValueExW ( 0x000003e8, "ShellState", 0, REG_BINARY, 0x000c2050, 36 ) ERROR_SUCCESS 0.0001028
65 // SHLWAPI.dll RegCloseKey ( 0x000003e8 ) ERROR_SUCCESS 0.0000081
66 // Explorer.EXE SHSettingsChanged ( 0, "ShellState" ) 0.0000131
67 static BOOL
IntSetShellStateSettings(BOOL bDoubleClick,BOOL bUseCommonTasks)68 IntSetShellStateSettings(BOOL bDoubleClick, BOOL bUseCommonTasks)
69 {
70 SHELLSTATE shellstate;
71 shellstate.fDoubleClickInWebView = !!bDoubleClick;
72 shellstate.fWebView = !!bUseCommonTasks;
73 SHGetSetSettings(&shellstate, SSF_DOUBLECLICKINWEBVIEW | SSF_WEBVIEW, TRUE);
74
75 SHSettingsChanged(0, L"ShellState");
76 return TRUE;
77 }
78
79 //////////////////////////////////////////////////////////////////////////////
80 // API Monitor:
81 // SHLWAPI.dll RegOpenKeyExW ( 0x000000c8, NULL, 0, MAXIMUM_ALLOWED, 0x0007e484 ) ERROR_SUCCESS 0.0000388
82 // SHLWAPI.dll RegQueryValueExW ( 0x000005a8, "ShellState", NULL, 0x0007e474, 0x000c2050, 0x0007e4fc ) ERROR_SUCCESS 0.0000271
83 // SHLWAPI.dll RegCloseKey ( 0x000005a8 ) ERROR_SUCCESS 0.0000112
84 EXTERN_C BOOL
SHELL32_ReadRegShellState(PREGSHELLSTATE prss)85 SHELL32_ReadRegShellState(PREGSHELLSTATE prss)
86 {
87 DWORD dwSize = sizeof(REGSHELLSTATE);
88 LSTATUS err = SHGetValueW(HKEY_CURRENT_USER, s_pszExplorerKey,
89 L"ShellState", NULL, prss, &dwSize);
90 return err == ERROR_SUCCESS && prss->dwSize >= REGSHELLSTATE_SIZE;
91 }
92
93 // bIconUnderline is TRUE if "Underline icon titles only when I point at them".
94 // bIconUnderline is FALSE if "Underline icon titles consistent with my browser".
95 //////////////////////////////////////////////////////////////////////////////
96 // API Monitor:
97 // SHELL32.dll SHRegGetUSValueW ( "Software\Microsoft\Windows\CurrentVersion\Explorer", "IconUnderline", NULL, 0x00d2f324, 0x00d2f328, FALSE, 0x00d2f32c, 4 ) ERROR_SUCCESS 0.0002484
98 // SHELL32.dll IsDlgButtonChecked ( 0x0005009e, 30104 ) BST_CHECKED 0.0000212
99 // SHELL32.dll SHRegSetUSValueW ( "Software\Microsoft\Windows\CurrentVersion\Explorer", "IconUnderline", 0, 0x00d2f314, 4, 6 ) ERROR_SUCCESS 0.0008300
100 // Explorer.EXE SHSettingsChanged ( 0, "Software\Microsoft\Windows\CurrentVersion\Explorer\IconUnderline" ) 0.0000092
IntSetUnderlineState(BOOL bIconUnderline)101 static BOOL IntSetUnderlineState(BOOL bIconUnderline)
102 {
103 LSTATUS Status;
104 DWORD dwValue = (bIconUnderline ? 3 : 2), dwSize = sizeof(DWORD);
105 Status = SHRegSetUSValue(s_pszExplorerKey, L"IconUnderline", REG_NONE,
106 &dwValue, dwSize, SHREGSET_FORCE_HKCU | SHREGSET_HKLM);
107 if (Status != ERROR_SUCCESS)
108 return FALSE;
109
110 SHSettingsChanged(0, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\IconUnderline");
111 return TRUE;
112 }
113
IntGetUnderlineState(VOID)114 static BOOL IntGetUnderlineState(VOID)
115 {
116 DWORD dwValue, dwDefault = 2, dwSize = sizeof(DWORD);
117 SHRegGetUSValue(s_pszExplorerKey, L"IconUnderline", NULL, &dwValue, &dwSize, FALSE, &dwDefault, sizeof(DWORD));
118 return dwValue == 3;
119 }
120
121 // bNewWindowMode is TRUE if "Open each folder in its own window".
122 // bNewWindowMode is FALSE if "Open each folder in the same window".
123 //////////////////////////////////////////////////////////////////////////////
124 // API Monitor:
125 // SHELL32.dll RegCreateKeyExW ( HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState", 0, NULL, 0, KEY_SET_VALUE, NULL, 0x00d2f2b8, NULL ) ERROR_SUCCESS 0.0000455
126 // SHELL32.dll RegSetValueExW ( 0x00000854, "Settings", 0, REG_BINARY, 0x0210f170, 12 ) ERROR_SUCCESS 0.0001472
127 // SHELL32.dll RegSetValueExW ( 0x00000854, "FullPath", 0, REG_DWORD, 0x00d2f2ac, 4 ) ERROR_SUCCESS 0.0000168
128 // SHELL32.dll RegCloseKey ( 0x00000854 ) ERROR_SUCCESS 0.0000000
IntSetNewWindowMode(BOOL bNewWindowMode)129 static HRESULT IntSetNewWindowMode(BOOL bNewWindowMode)
130 {
131 CABINETSTATE cs;
132 if (!ReadCabinetState(&cs, sizeof(cs)))
133 return E_FAIL;
134
135 BOOL changed = !!cs.fNewWindowMode != !!bNewWindowMode;
136 cs.fNewWindowMode = !!bNewWindowMode;
137 return WriteCabinetState(&cs) ? (changed ? S_OK : S_FALSE) : E_FAIL;
138 }
139
IntGetNewWindowMode(VOID)140 static BOOL IntGetNewWindowMode(VOID)
141 {
142 CABINETSTATE cs;
143 if (!ReadCabinetState(&cs, sizeof(cs)))
144 return FALSE;
145
146 return !!cs.fNewWindowMode;
147 }
148
149 /////////////////////////////////////////////////////////////////////////////
150 // GeneralDlg
151
152 typedef struct GENERAL_DIALOG
153 {
154 HICON hTaskIcon;
155 HICON hFolderIcon;
156 HICON hClickIcon;
157 } GENERAL_DIALOG, *PGENERAL_DIALOG;
158
159 static VOID
GeneralDlg_UpdateIcons(HWND hDlg,UINT nCtrlID,PGENERAL_DIALOG pGeneral)160 GeneralDlg_UpdateIcons(HWND hDlg, UINT nCtrlID, PGENERAL_DIALOG pGeneral)
161 {
162 HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL;
163 LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL;
164
165 // Show task setting icon.
166 if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED)
167 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS);
168 else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED)
169 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS);
170
171 if (lpTaskIconName)
172 {
173 hTaskIcon = (HICON)LoadImage(shell32_hInstance, lpTaskIconName,
174 IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
175 if (hTaskIcon)
176 {
177 HWND hwndTaskIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_TASKICON);
178 SendMessage(hwndTaskIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hTaskIcon);
179 }
180 }
181
182 // Show Folder setting icons
183 if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED)
184 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW);
185 else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED)
186 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW);
187
188 if (lpFolderIconName)
189 {
190 hFolderIcon = (HICON)LoadImage(shell32_hInstance, lpFolderIconName,
191 IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
192 if (hFolderIcon)
193 {
194 HWND hwndFolderIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_FOLDERICON);
195 SendMessage(hwndFolderIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hFolderIcon);
196 }
197 }
198
199 // Show click setting icon
200 if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED)
201 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN);
202 else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED)
203 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN);
204
205 if (lpClickIconName)
206 {
207 hClickIcon = (HICON)LoadImage(shell32_hInstance, lpClickIconName,
208 IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
209 if (hClickIcon)
210 {
211 HWND hwndClickIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_CLICKICON);
212 SendMessage(hwndClickIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hClickIcon);
213 }
214 }
215
216 // Replace icons
217 if (hTaskIcon)
218 {
219 DestroyIcon(pGeneral->hTaskIcon);
220 pGeneral->hTaskIcon = hTaskIcon;
221 }
222 if (hFolderIcon)
223 {
224 DestroyIcon(pGeneral->hFolderIcon);
225 pGeneral->hFolderIcon = hFolderIcon;
226 }
227 if (hClickIcon)
228 {
229 DestroyIcon(pGeneral->hClickIcon);
230 pGeneral->hClickIcon = hClickIcon;
231 }
232
233 if (nCtrlID == IDC_FOLDER_OPTIONS_SINGLECLICK)
234 {
235 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER), TRUE);
236 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULPOINT), TRUE);
237 }
238
239 if (nCtrlID == IDC_FOLDER_OPTIONS_DOUBLECLICK)
240 {
241 CheckRadioButton(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULBROWSER);
242 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER), FALSE);
243 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULPOINT), FALSE);
244 }
245 }
246
247 static void
GeneralDlg_StoreToUI(HWND hwndDlg,BOOL bDoubleClick,BOOL bUseCommonTasks,BOOL bUnderline,BOOL bNewWindowMode,PGENERAL_DIALOG pGeneral)248 GeneralDlg_StoreToUI(HWND hwndDlg, BOOL bDoubleClick, BOOL bUseCommonTasks,
249 BOOL bUnderline, BOOL bNewWindowMode, PGENERAL_DIALOG pGeneral)
250 {
251 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS), bUseCommonTasks); // FIXME: ROS DefView does not support WebView nor the tasks pane
252
253 if (bUseCommonTasks)
254 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS, IDC_FOLDER_OPTIONS_COMMONTASKS);
255 else
256 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS);
257
258 if (bDoubleClick)
259 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK);
260 else
261 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK, IDC_FOLDER_OPTIONS_SINGLECLICK);
262
263 if (bNewWindowMode)
264 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW);
265 else
266 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW, IDC_FOLDER_OPTIONS_SAMEWINDOW);
267
268 if (!bDoubleClick)
269 {
270 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER), TRUE);
271 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT), TRUE);
272 if (bUnderline)
273 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULPOINT);
274 else
275 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULBROWSER);
276 }
277 else
278 {
279 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER), FALSE);
280 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT), FALSE);
281 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULBROWSER);
282 }
283 }
284
285 static BOOL
GeneralDlg_OnInitDialog(HWND hwndDlg,PGENERAL_DIALOG pGeneral)286 GeneralDlg_OnInitDialog(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
287 {
288 SHELLSTATE ss;
289 SHGetSetSettings(&ss, SSF_DOUBLECLICKINWEBVIEW | SSF_WEBVIEW, FALSE);
290 BOOL bDoubleClick = !!ss.fDoubleClickInWebView;
291 BOOL bUseCommonTasks = !!ss.fWebView;
292 BOOL bUnderline = IntGetUnderlineState();
293 BOOL bNewWindowMode = IntGetNewWindowMode();
294
295 GeneralDlg_StoreToUI(hwndDlg, bDoubleClick, bUseCommonTasks, bUnderline, bNewWindowMode, pGeneral);
296 GeneralDlg_UpdateIcons(hwndDlg, 0, pGeneral);
297
298 return TRUE;
299 }
300
301 static void
GeneralDlg_OnRestoreDefaults(HWND hwndDlg,PGENERAL_DIALOG pGeneral)302 GeneralDlg_OnRestoreDefaults(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
303 {
304 // default values
305 BOOL bDoubleClick = TRUE;
306 BOOL bUseCommonTasks = TRUE;
307 BOOL bUnderline = FALSE;
308 BOOL bNewWindowMode = (_WIN32_WINNT < _WIN32_WINNT_WIN2K);
309
310 GeneralDlg_StoreToUI(hwndDlg, bDoubleClick, bUseCommonTasks, bUnderline, bNewWindowMode, pGeneral);
311 GeneralDlg_UpdateIcons(hwndDlg, 0, pGeneral);
312 }
313
314 static BOOL
GeneralDlg_OnApply(HWND hwndDlg,PGENERAL_DIALOG pGeneral)315 GeneralDlg_OnApply(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
316 {
317 BOOL bDoubleClick = !(IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED);
318 BOOL bUseCommonTasks = (IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED);
319 BOOL bUnderline = (IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT) == BST_CHECKED);
320 BOOL bNewWindowMode = !(IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED);
321
322 IntSetUnderlineState(bUnderline);
323 BOOL updateCabinets = IntSetNewWindowMode(bNewWindowMode) == S_OK;
324 IntSetShellStateSettings(bDoubleClick, bUseCommonTasks);
325 if (updateCabinets)
326 PostCabinetMessage(CWM_STATECHANGE, 0, 0);
327 return TRUE;
328 }
329
330 INT_PTR CALLBACK
FolderOptionsGeneralDlg(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)331 FolderOptionsGeneralDlg(
332 HWND hwndDlg,
333 UINT uMsg,
334 WPARAM wParam,
335 LPARAM lParam)
336 {
337 static GENERAL_DIALOG general;
338
339 switch (uMsg)
340 {
341 case WM_INITDIALOG:
342 general.hTaskIcon = NULL;
343 general.hFolderIcon = NULL;
344 general.hClickIcon = NULL;
345 return GeneralDlg_OnInitDialog(hwndDlg, &general);
346
347 case WM_COMMAND:
348 switch (LOWORD(wParam))
349 {
350 case IDC_FOLDER_OPTIONS_COMMONTASKS:
351 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS:
352 case IDC_FOLDER_OPTIONS_SAMEWINDOW:
353 case IDC_FOLDER_OPTIONS_OWNWINDOW:
354 case IDC_FOLDER_OPTIONS_SINGLECLICK:
355 case IDC_FOLDER_OPTIONS_DOUBLECLICK:
356 case IDC_FOLDER_OPTIONS_ULBROWSER:
357 case IDC_FOLDER_OPTIONS_ULPOINT:
358 if (HIWORD(wParam) == BN_CLICKED)
359 {
360 GeneralDlg_UpdateIcons(hwndDlg, LOWORD(wParam), &general);
361
362 // Enable the 'Apply' button
363 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
364 }
365 break;
366 case IDC_FOLDER_OPTIONS_RESTORE:
367 if (HIWORD(wParam) == BN_CLICKED)
368 {
369 GeneralDlg_OnRestoreDefaults(hwndDlg, &general);
370
371 // Enable the 'Apply' button
372 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
373 }
374 break;
375 }
376 break;
377
378 case WM_NOTIFY:
379 {
380 LPNMHDR pnmh = (LPNMHDR)lParam;
381
382 switch (pnmh->code)
383 {
384 case PSN_SETACTIVE:
385 break;
386
387 case PSN_APPLY:
388 return GeneralDlg_OnApply(hwndDlg, &general);
389 }
390 break;
391 }
392
393 case WM_DESTROY:
394 DestroyIcon(general.hTaskIcon);
395 DestroyIcon(general.hFolderIcon);
396 DestroyIcon(general.hClickIcon);
397 break;
398
399 default:
400 return FALSE;
401 }
402 return FALSE;
403 }
404