[SHELL32] -The only change I did in the previous patch was buggy.
[reactos.git] / reactos / dll / win32 / shell32 / dialogs / folder_options.cpp
1 /*
2 * Open With Context Menu extension
3 *
4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org>
5 * Copyright 2016-2017 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 #define MAX_PROPERTY_SHEET_PAGE (32)
27
28 /// Folder Options:
29 /// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}
30 /// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210
31 /// Verbs: Open / RunAs
32 /// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0
33
34 /// ShellFolder Attributes: 0x0
35
36 typedef struct
37 {
38 WCHAR FileExtension[30];
39 WCHAR FileDescription[100];
40 WCHAR ClassKey[MAX_PATH];
41 DWORD EditFlags;
42 } FOLDER_FILE_TYPE_ENTRY, *PFOLDER_FILE_TYPE_ENTRY;
43
44 // uniquely-defined icon entry for Advanced Settings
45 typedef struct ADVANCED_ICON
46 {
47 WCHAR szPath[MAX_PATH];
48 UINT nIconIndex;
49 } ADVANCED_ICON;
50
51 // predefined icon IDs (See CreateTreeImageList function below)
52 #define I_CHECKED 0
53 #define I_UNCHECKED 1
54 #define I_CHECKED_DISABLED 2
55 #define I_UNCHECKED_DISABLED 3
56 #define I_RADIO_CHECKED 4
57 #define I_RADIO_UNCHECKED 5
58 #define I_RADIO_CHECKED_DISABLED 6
59 #define I_RADIO_UNCHECKED_DISABLED 7
60
61 #define PREDEFINED_ICON_COUNT 8
62
63 // definition of icon stock
64 static ADVANCED_ICON * s_AdvancedIcons = NULL;
65 static INT s_AdvancedIconCount = 0;
66 static HIMAGELIST s_hImageList = NULL;
67
68 static INT
69 Advanced_FindIcon(LPCWSTR pszPath, UINT nIconIndex)
70 {
71 for (INT i = PREDEFINED_ICON_COUNT; i < s_AdvancedIconCount; ++i)
72 {
73 ADVANCED_ICON *pIcon = &s_AdvancedIcons[i];
74 if (pIcon->nIconIndex == nIconIndex &&
75 lstrcmpiW(pIcon->szPath, pszPath) == 0)
76 {
77 return i; // icon ID
78 }
79 }
80 return -1; // not found
81 }
82
83 static INT
84 Advanced_AddIcon(LPCWSTR pszPath, UINT nIconIndex)
85 {
86 ADVANCED_ICON *pAllocated;
87
88 // return the ID if already existed
89 INT nIconID = Advanced_FindIcon(pszPath, nIconIndex);
90 if (nIconID != -1)
91 return nIconID; // already exists
92
93 // extract a small icon
94 HICON hIconSmall = NULL;
95 ExtractIconExW(pszPath, nIconIndex, NULL, &hIconSmall, 1);
96 if (hIconSmall == NULL)
97 return -1; // failure
98
99 // resize s_AdvancedIcons
100 size_t Size = (s_AdvancedIconCount + 1) * sizeof(ADVANCED_ICON);
101 pAllocated = (ADVANCED_ICON *)realloc(s_AdvancedIcons, Size);
102 if (pAllocated == NULL)
103 return -1; // failure
104 else
105 s_AdvancedIcons = pAllocated;
106
107 // save icon information
108 ADVANCED_ICON *pIcon = &s_AdvancedIcons[s_AdvancedIconCount];
109 lstrcpynW(pIcon->szPath, pszPath, _countof(pIcon->szPath));
110 pIcon->nIconIndex = nIconIndex;
111
112 // add the icon to the image list
113 ImageList_AddIcon(s_hImageList, hIconSmall);
114
115 // increment the counter
116 nIconID = s_AdvancedIconCount;
117 ++s_AdvancedIconCount;
118
119 DestroyIcon(hIconSmall);
120
121 return nIconID; // newly-added icon ID
122 }
123
124 // types of Advanced Setting entry
125 typedef enum ADVANCED_ENTRY_TYPE
126 {
127 AETYPE_GROUP,
128 AETYPE_CHECKBOX,
129 AETYPE_RADIO,
130 } ADVANCED_ENTRY_TYPE;
131
132 // an entry info of Advanced Settings
133 typedef struct ADVANCED_ENTRY
134 {
135 DWORD dwID; // entry ID
136 DWORD dwParentID; // parent entry ID
137 DWORD dwResourceID; // resource ID
138 WCHAR szKeyName[64]; // entry key name
139 DWORD dwType; // ADVANCED_ENTRY_TYPE
140 DWORD dwOrdinal; // ordinal number
141 WCHAR szText[MAX_PATH]; // text
142 INT nIconID; // icon ID (See ADVANCED_ICON)
143
144 HKEY hkeyRoot; // registry root key
145 WCHAR szRegPath[MAX_PATH]; // registry path
146 WCHAR szValueName[64]; // registry value name
147
148 DWORD dwCheckedValue; // checked value
149 DWORD dwUncheckedValue; // unchecked value
150 DWORD dwDefaultValue; // defalut value
151 BOOL bHasUncheckedValue; // If FALSE, UncheckedValue is invalid
152
153 HTREEITEM hItem; // for TreeView
154 BOOL bGrayed; // disabled?
155 BOOL bChecked; // checked?
156 } ADVANCED_ENTRY, *PADVANCED_ENTRY;
157
158 // definition of advanced entries
159 static ADVANCED_ENTRY * s_Advanced = NULL;
160 static INT s_AdvancedCount = 0;
161
162 static HBITMAP
163 Create24BppBitmap(HDC hDC, INT cx, INT cy)
164 {
165 BITMAPINFO bi;
166 LPVOID pvBits;
167
168 ZeroMemory(&bi, sizeof(bi));
169 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
170 bi.bmiHeader.biWidth = cx;
171 bi.bmiHeader.biHeight = cy;
172 bi.bmiHeader.biPlanes = 1;
173 bi.bmiHeader.biBitCount = 24;
174 bi.bmiHeader.biCompression = BI_RGB;
175
176 HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0);
177 return hbm;
178 }
179
180 static HBITMAP
181 CreateCheckImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE)
182 {
183 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
184 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
185
186 HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon);
187 if (hbm == NULL)
188 return NULL; // failure
189
190 RECT Rect, BoxRect;
191 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
192 BoxRect = Rect;
193 InflateRect(&BoxRect, -1, -1);
194
195 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
196 {
197 UINT uState = DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_MONO;
198 if (bCheck)
199 uState |= DFCS_CHECKED;
200 if (!bEnabled)
201 uState |= DFCS_INACTIVE;
202 DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
203 }
204 SelectObject(hDC, hbmOld);
205
206 return hbm; // success
207 }
208
209 static HBITMAP
210 CreateCheckMask(HDC hDC)
211 {
212 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
213 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
214
215 HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL);
216 if (hbm == NULL)
217 return NULL; // failure
218
219 RECT Rect, BoxRect;
220 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
221 BoxRect = Rect;
222 InflateRect(&BoxRect, -1, -1);
223
224 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
225 {
226 FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH)));
227 FillRect(hDC, &BoxRect, HBRUSH(GetStockObject(BLACK_BRUSH)));
228 }
229 SelectObject(hDC, hbmOld);
230
231 return hbm; // success
232 }
233
234 static HBITMAP
235 CreateRadioImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE)
236 {
237 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
238 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
239
240 HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon);
241 if (hbm == NULL)
242 return NULL; // failure
243
244 RECT Rect, BoxRect;
245 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
246 BoxRect = Rect;
247 InflateRect(&BoxRect, -1, -1);
248
249 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
250 {
251 UINT uState = DFCS_BUTTONRADIOIMAGE | DFCS_FLAT | DFCS_MONO;
252 if (bCheck)
253 uState |= DFCS_CHECKED;
254 if (!bEnabled)
255 uState |= DFCS_INACTIVE;
256 DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
257 }
258 SelectObject(hDC, hbmOld);
259
260 return hbm; // success
261 }
262
263 static HBITMAP
264 CreateRadioMask(HDC hDC)
265 {
266 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
267 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
268
269 HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL);
270 if (hbm == NULL)
271 return NULL; // failure
272
273 RECT Rect, BoxRect;
274 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
275 BoxRect = Rect;
276 InflateRect(&BoxRect, -1, -1);
277
278 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
279 {
280 FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH)));
281 UINT uState = DFCS_BUTTONRADIOMASK | DFCS_FLAT | DFCS_MONO;
282 DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
283 }
284 SelectObject(hDC, hbmOld);
285
286 return hbm; // success
287 }
288
289 static HIMAGELIST
290 CreateTreeImageList(VOID)
291 {
292 HIMAGELIST hImageList;
293 hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 9, 1);
294 if (hImageList == NULL)
295 return NULL; // failure
296
297 // free if existed
298 if (s_AdvancedIcons)
299 {
300 free(s_AdvancedIcons);
301 s_AdvancedIcons = NULL;
302 }
303 s_AdvancedIconCount = 0;
304
305 // allocate now
306 ADVANCED_ICON *pAllocated;
307 size_t Size = PREDEFINED_ICON_COUNT * sizeof(ADVANCED_ICON);
308 pAllocated = (ADVANCED_ICON *)calloc(1, Size);
309 if (pAllocated == NULL)
310 return NULL; // failure
311
312 s_AdvancedIconCount = PREDEFINED_ICON_COUNT;
313 s_AdvancedIcons = pAllocated;
314
315 // add the predefined icons
316
317 HDC hDC = CreateCompatibleDC(NULL);
318 HBITMAP hbmMask = CreateCheckMask(hDC);
319
320 HBITMAP hbmChecked, hbmUnchecked;
321
322 hbmChecked = CreateCheckImage(hDC, TRUE);
323 ImageList_Add(hImageList, hbmChecked, hbmMask);
324 DeleteObject(hbmChecked);
325
326 hbmUnchecked = CreateCheckImage(hDC, FALSE);
327 ImageList_Add(hImageList, hbmUnchecked, hbmMask);
328 DeleteObject(hbmUnchecked);
329
330 hbmChecked = CreateCheckImage(hDC, TRUE, FALSE);
331 ImageList_Add(hImageList, hbmChecked, hbmMask);
332 DeleteObject(hbmChecked);
333
334 hbmUnchecked = CreateCheckImage(hDC, FALSE, FALSE);
335 ImageList_Add(hImageList, hbmUnchecked, hbmMask);
336 DeleteObject(hbmUnchecked);
337
338 DeleteObject(hbmMask);
339 hbmMask = CreateRadioMask(hDC);
340
341 hbmChecked = CreateRadioImage(hDC, TRUE);
342 ImageList_Add(hImageList, hbmChecked, hbmMask);
343 DeleteObject(hbmChecked);
344
345 hbmUnchecked = CreateRadioImage(hDC, FALSE);
346 ImageList_Add(hImageList, hbmUnchecked, hbmMask);
347 DeleteObject(hbmUnchecked);
348
349 hbmChecked = CreateRadioImage(hDC, TRUE, FALSE);
350 ImageList_Add(hImageList, hbmChecked, hbmMask);
351 DeleteObject(hbmChecked);
352
353 hbmUnchecked = CreateRadioImage(hDC, FALSE, FALSE);
354 ImageList_Add(hImageList, hbmUnchecked, hbmMask);
355 DeleteObject(hbmUnchecked);
356
357 DeleteObject(hbmMask);
358
359 return hImageList;
360 }
361
362 static ADVANCED_ENTRY *
363 Advanced_GetItem(DWORD dwID)
364 {
365 for (INT i = 0; i < s_AdvancedCount; ++i)
366 {
367 ADVANCED_ENTRY *pEntry = &s_Advanced[i];
368 if (pEntry->dwID == dwID)
369 return pEntry;
370 }
371 return NULL; // failure
372 }
373
374 static INT
375 Advanced_GetImage(ADVANCED_ENTRY *pEntry)
376 {
377 switch (pEntry->dwType)
378 {
379 case AETYPE_GROUP:
380 return pEntry->nIconID;
381
382 case AETYPE_CHECKBOX:
383 if (pEntry->bGrayed)
384 {
385 if (pEntry->bChecked)
386 return I_CHECKED_DISABLED;
387 else
388 return I_UNCHECKED_DISABLED;
389 }
390 else
391 {
392 if (pEntry->bChecked)
393 return I_CHECKED;
394 else
395 return I_UNCHECKED;
396 }
397
398 case AETYPE_RADIO:
399 if (pEntry->bGrayed)
400 {
401 if (pEntry->bChecked)
402 return I_RADIO_CHECKED_DISABLED;
403 else
404 return I_RADIO_UNCHECKED_DISABLED;
405 }
406 else
407 {
408 if (pEntry->bChecked)
409 return I_RADIO_CHECKED;
410 else
411 return I_RADIO_UNCHECKED;
412 }
413 }
414 return -1; // failure
415 }
416
417 static VOID
418 Advanced_InsertEntry(HWND hwndTreeView, ADVANCED_ENTRY *pEntry)
419 {
420 ADVANCED_ENTRY *pParent = Advanced_GetItem(pEntry->dwParentID);
421 HTREEITEM hParent = TVI_ROOT;
422 if (pParent != NULL)
423 hParent = pParent->hItem;
424
425 TV_INSERTSTRUCT Insertion;
426 ZeroMemory(&Insertion, sizeof(Insertion));
427 Insertion.hParent = hParent;
428 Insertion.hInsertAfter = TVI_LAST;
429 Insertion.item.mask =
430 TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
431 Insertion.item.pszText = pEntry->szText;
432
433 INT iImage = Advanced_GetImage(pEntry);
434 Insertion.item.iImage = Insertion.item.iSelectedImage = iImage;
435 Insertion.item.lParam = pEntry->dwID;
436 pEntry->hItem = TreeView_InsertItem(hwndTreeView, &Insertion);
437 }
438
439 static VOID
440 Advanced_InsertAll(HWND hwndTreeView)
441 {
442 TreeView_DeleteAllItems(hwndTreeView);
443
444 // insert the entries
445 ADVANCED_ENTRY *pEntry;
446 for (INT i = 0; i < s_AdvancedCount; ++i)
447 {
448 pEntry = &s_Advanced[i];
449 Advanced_InsertEntry(hwndTreeView, pEntry);
450 }
451
452 // expand all
453 for (INT i = 0; i < s_AdvancedCount; ++i)
454 {
455 pEntry = &s_Advanced[i];
456 if (pEntry->dwType == AETYPE_GROUP)
457 {
458 TreeView_Expand(hwndTreeView, pEntry->hItem, TVE_EXPAND);
459 }
460 }
461 }
462
463 static BOOL
464 Advanced_LoadTree(HKEY hKey, LPCWSTR pszKeyName, DWORD dwParentID)
465 {
466 DWORD dwIndex;
467 WCHAR szKeyName[64], szText[MAX_PATH], *pch;
468 DWORD Size, Value;
469 ADVANCED_ENTRY *pAllocated;
470
471 // resize s_Advanced
472 Size = (s_AdvancedCount + 1) * sizeof(ADVANCED_ENTRY);
473 pAllocated = (ADVANCED_ENTRY *)realloc(s_Advanced, Size);
474 if (pAllocated == NULL)
475 return FALSE; // failure
476 else
477 s_Advanced = pAllocated;
478
479 ADVANCED_ENTRY *pEntry = &s_Advanced[s_AdvancedCount];
480
481 // dwID, dwParentID, szKeyName
482 pEntry->dwID = s_AdvancedCount;
483 pEntry->dwParentID = dwParentID;
484 lstrcpynW(pEntry->szKeyName, pszKeyName, _countof(pEntry->szKeyName));
485
486 // Text, ResourceID
487 pEntry->szText[0] = 0;
488 pEntry->dwResourceID = 0;
489 szText[0] = 0;
490 Size = sizeof(szText);
491 RegQueryValueExW(hKey, L"Text", NULL, NULL, LPBYTE(szText), &Size);
492 if (szText[0] == L'@')
493 {
494 pch = wcsrchr(szText, L',');
495 if (pch)
496 {
497 *pch = 0;
498 dwIndex = abs(_wtoi(pch + 1));
499 pEntry->dwResourceID = dwIndex;
500 }
501 HINSTANCE hInst = LoadLibraryW(&szText[1]);
502 LoadStringW(hInst, dwIndex, szText, _countof(szText));
503 FreeLibrary(hInst);
504 }
505 else
506 {
507 pEntry->dwResourceID = DWORD(-1);
508 }
509 lstrcpynW(pEntry->szText, szText, _countof(pEntry->szText));
510
511 // Type
512 szText[0] = 0;
513 RegQueryValueExW(hKey, L"Type", NULL, NULL, LPBYTE(szText), &Size);
514 if (lstrcmpiW(szText, L"checkbox") == 0)
515 pEntry->dwType = AETYPE_CHECKBOX;
516 else if (lstrcmpiW(szText, L"radio") == 0)
517 pEntry->dwType = AETYPE_RADIO;
518 else if (lstrcmpiW(szText, L"group") == 0)
519 pEntry->dwType = AETYPE_GROUP;
520 else
521 return FALSE; // failure
522
523 pEntry->nIconID = -1;
524 if (pEntry->dwType == AETYPE_GROUP)
525 {
526 // Bitmap (Icon)
527 UINT nIconIndex = 0;
528 Size = sizeof(szText);
529 szText[0] = 0;
530 RegQueryValueExW(hKey, L"Bitmap", NULL, NULL, LPBYTE(szText), &Size);
531
532 WCHAR szExpanded[MAX_PATH];
533 ExpandEnvironmentStringsW(szText, szExpanded, _countof(szExpanded));
534 pch = wcsrchr(szExpanded, L',');
535 if (pch)
536 {
537 *pch = 0;
538 nIconIndex = abs(_wtoi(pch + 1));
539 }
540 pEntry->nIconID = Advanced_AddIcon(szExpanded, nIconIndex);
541 }
542
543 // Ordinal (ReactOS extension)
544 Size = sizeof(Value);
545 Value = DWORD(-1);
546 RegQueryValueExW(hKey, L"Ordinal", NULL, NULL, LPBYTE(&Value), &Size);
547 pEntry->dwOrdinal = Value;
548
549 if (pEntry->dwType == AETYPE_GROUP)
550 {
551 pEntry->hkeyRoot = NULL;
552 pEntry->szRegPath[0] = 0;
553 pEntry->szValueName[0] = 0;
554 pEntry->dwCheckedValue = 0;
555 pEntry->bHasUncheckedValue = FALSE;
556 pEntry->dwUncheckedValue = 0;
557 pEntry->dwDefaultValue = 0;
558 pEntry->hItem = NULL;
559 pEntry->bGrayed = FALSE;
560 pEntry->bChecked = FALSE;
561 }
562 else
563 {
564 // HKeyRoot
565 Value = DWORD(HKEY_CURRENT_USER);
566 Size = sizeof(Value);
567 RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&Value), &Size);
568 pEntry->hkeyRoot = HKEY(Value);
569
570 // RegPath
571 pEntry->szRegPath[0] = 0;
572 Size = sizeof(szText);
573 RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size);
574 lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath));
575
576 // ValueName
577 pEntry->szValueName[0] = 0;
578 Size = sizeof(szText);
579 RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size);
580 lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName));
581
582 // CheckedValue
583 Size = sizeof(Value);
584 Value = 0x00000001;
585 RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size);
586 pEntry->dwCheckedValue = Value;
587
588 // UncheckedValue
589 Size = sizeof(Value);
590 Value = 0x00000000;
591 pEntry->bHasUncheckedValue = TRUE;
592 if (RegQueryValueExW(hKey, L"UncheckedValue", NULL,
593 NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS)
594 {
595 pEntry->bHasUncheckedValue = FALSE;
596 }
597 pEntry->dwUncheckedValue = Value;
598
599 // DefaultValue
600 Size = sizeof(Value);
601 Value = 0x00000001;
602 RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size);
603 pEntry->dwDefaultValue = Value;
604
605 // hItem
606 pEntry->hItem = NULL;
607
608 // bGrayed, bChecked
609 HKEY hkeyTarget;
610 Value = pEntry->dwDefaultValue;
611 pEntry->bGrayed = TRUE;
612 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0,
613 KEY_READ, &hkeyTarget) == ERROR_SUCCESS)
614 {
615 Size = sizeof(Value);
616 if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL,
617 LPBYTE(&Value), &Size) == ERROR_SUCCESS)
618 {
619 pEntry->bGrayed = FALSE;
620 }
621 RegCloseKey(hkeyTarget);
622 }
623 pEntry->bChecked = (Value == pEntry->dwCheckedValue);
624 }
625
626 // Grayed (ReactOS extension)
627 Size = sizeof(Value);
628 Value = FALSE;
629 RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size);
630 if (!pEntry->bGrayed)
631 pEntry->bGrayed = Value;
632
633 BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP);
634 dwParentID = pEntry->dwID;
635 ++s_AdvancedCount;
636
637 if (!bIsGroup)
638 return TRUE; // success
639
640 // load the children
641 dwIndex = 0;
642 while (RegEnumKeyW(hKey, dwIndex, szKeyName,
643 _countof(szKeyName)) == ERROR_SUCCESS)
644 {
645 HKEY hkeyChild;
646 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ,
647 &hkeyChild) != ERROR_SUCCESS)
648 {
649 ++dwIndex;
650 continue; // failure
651 }
652
653 Advanced_LoadTree(hkeyChild, szKeyName, dwParentID);
654 RegCloseKey(hkeyChild);
655
656 ++dwIndex;
657 }
658
659 return TRUE; // success
660 }
661
662 static BOOL
663 Advanced_LoadAll(VOID)
664 {
665 static const WCHAR s_szAdvanced[] =
666 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
667
668 // free if already existed
669 if (s_Advanced)
670 {
671 free(s_Advanced);
672 s_Advanced = NULL;
673 }
674 s_AdvancedCount = 0;
675
676 HKEY hKey;
677 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szAdvanced, 0,
678 KEY_READ, &hKey) != ERROR_SUCCESS)
679 {
680 return FALSE; // failure
681 }
682
683 // load the children
684 WCHAR szKeyName[64];
685 DWORD dwIndex = 0;
686 while (RegEnumKeyW(hKey, dwIndex, szKeyName,
687 _countof(szKeyName)) == ERROR_SUCCESS)
688 {
689 HKEY hkeyChild;
690 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ,
691 &hkeyChild) != ERROR_SUCCESS)
692 {
693 ++dwIndex;
694 continue; // failure
695 }
696
697 Advanced_LoadTree(hkeyChild, szKeyName, DWORD(-1));
698 RegCloseKey(hkeyChild);
699
700 ++dwIndex;
701 }
702
703 RegCloseKey(hKey);
704
705 return TRUE; // success
706 }
707
708 static int
709 Advanced_Compare(const void *x, const void *y)
710 {
711 ADVANCED_ENTRY *pEntry1 = (ADVANCED_ENTRY *)x;
712 ADVANCED_ENTRY *pEntry2 = (ADVANCED_ENTRY *)y;
713 if (pEntry1->dwOrdinal < pEntry2->dwOrdinal)
714 return -1;
715 if (pEntry1->dwOrdinal > pEntry2->dwOrdinal)
716 return 1;
717 return 0;
718 }
719
720 static VOID
721 Advanced_SortAll(VOID)
722 {
723 qsort(s_Advanced, s_AdvancedCount, sizeof(ADVANCED_ENTRY), Advanced_Compare);
724 }
725
726 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
727
728 static VOID
729 UpdateGeneralIcons(HWND hDlg)
730 {
731 HWND hwndTaskIcon, hwndFolderIcon, hwndClickIcon;
732 HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL;
733 LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL;
734
735 // show task setting icon
736 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED)
737 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS);
738 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED)
739 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS);
740
741 if (lpTaskIconName)
742 {
743 hTaskIcon = (HICON)LoadImage(shell32_hInstance,
744 lpTaskIconName,
745 IMAGE_ICON,
746 0,
747 0,
748 LR_DEFAULTCOLOR);
749 if (hTaskIcon)
750 {
751 hwndTaskIcon = GetDlgItem(hDlg,
752 IDC_FOLDER_OPTIONS_TASKICON);
753 if (hwndTaskIcon)
754 {
755 SendMessage(hwndTaskIcon,
756 STM_SETIMAGE,
757 IMAGE_ICON,
758 (LPARAM)hTaskIcon);
759 }
760 }
761 }
762
763 // show Folder setting icons
764 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED)
765 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW);
766 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED)
767 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW);
768
769 if (lpFolderIconName)
770 {
771 hFolderIcon = (HICON)LoadImage(shell32_hInstance,
772 lpFolderIconName,
773 IMAGE_ICON,
774 0,
775 0,
776 LR_DEFAULTCOLOR);
777 if (hFolderIcon)
778 {
779 hwndFolderIcon = GetDlgItem(hDlg,
780 IDC_FOLDER_OPTIONS_FOLDERICON);
781 if (hwndFolderIcon)
782 {
783 SendMessage(hwndFolderIcon,
784 STM_SETIMAGE,
785 IMAGE_ICON,
786 (LPARAM)hFolderIcon);
787 }
788 }
789 }
790
791 // Show click setting icon
792 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED)
793 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN);
794 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED)
795 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN);
796
797 if (lpClickIconName)
798 {
799 hClickIcon = (HICON)LoadImage(shell32_hInstance,
800 lpClickIconName,
801 IMAGE_ICON,
802 0,
803 0,
804 LR_DEFAULTCOLOR);
805 if (hClickIcon)
806 {
807 hwndClickIcon = GetDlgItem(hDlg,
808 IDC_FOLDER_OPTIONS_CLICKICON);
809 if (hwndClickIcon)
810 {
811 SendMessage(hwndClickIcon,
812 STM_SETIMAGE,
813 IMAGE_ICON,
814 (LPARAM)hClickIcon);
815 }
816 }
817 }
818
819 // Clean up
820 if(hTaskIcon)
821 DeleteObject(hTaskIcon);
822 if(hFolderIcon)
823 DeleteObject(hFolderIcon);
824 if(hClickIcon)
825 DeleteObject(hClickIcon);
826
827 return;
828 }
829
830 INT_PTR
831 CALLBACK
832 FolderOptionsGeneralDlg(
833 HWND hwndDlg,
834 UINT uMsg,
835 WPARAM wParam,
836 LPARAM lParam
837 )
838 {
839 switch(uMsg)
840 {
841 case WM_INITDIALOG:
842 // FIXME
843 break;
844
845 case WM_COMMAND:
846 switch (LOWORD(wParam))
847 {
848 case IDC_FOLDER_OPTIONS_COMMONTASKS:
849 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS:
850 case IDC_FOLDER_OPTIONS_SAMEWINDOW:
851 case IDC_FOLDER_OPTIONS_OWNWINDOW:
852 case IDC_FOLDER_OPTIONS_SINGLECLICK:
853 case IDC_FOLDER_OPTIONS_DOUBLECLICK:
854 if (HIWORD(wParam) == BN_CLICKED)
855 {
856 UpdateGeneralIcons(hwndDlg);
857
858 /* Enable the 'Apply' button */
859 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
860 }
861 break;
862 }
863 break;
864
865 case WM_NOTIFY:
866 {
867 LPNMHDR pnmh = (LPNMHDR)lParam;
868
869 switch (pnmh->code)
870 {
871 case PSN_SETACTIVE:
872 break;
873
874 case PSN_APPLY:
875 break;
876 }
877 break;
878 }
879
880 case WM_DESTROY:
881 break;
882
883 default:
884 return FALSE;
885 }
886 return FALSE;
887 }
888
889 static BOOL
890 ViewDlg_OnInitDialog(HWND hwndDlg)
891 {
892 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
893
894 s_hImageList = CreateTreeImageList();
895 TreeView_SetImageList(hwndTreeView, s_hImageList, TVSIL_NORMAL);
896
897 Advanced_LoadAll();
898 Advanced_SortAll();
899 Advanced_InsertAll(hwndTreeView);
900
901 return TRUE; // set focus
902 }
903
904 static BOOL
905 ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem)
906 {
907 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
908
909 // get the item
910 TV_ITEM Item;
911 INT i;
912 ZeroMemory(&Item, sizeof(Item));
913 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM;
914 Item.hItem = hItem;
915 if (!TreeView_GetItem(hwndTreeView, &Item))
916 return FALSE; // no such item
917
918 ADVANCED_ENTRY *pEntry = Advanced_GetItem(Item.lParam);
919 if (pEntry == NULL)
920 return FALSE; // no such item
921 if (pEntry->bGrayed)
922 return FALSE; // disabled
923
924 // toggle check mark
925 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
926 switch (pEntry->dwType)
927 {
928 case AETYPE_CHECKBOX:
929 pEntry->bChecked = !pEntry->bChecked;
930 break;
931 case AETYPE_RADIO:
932 // reset all the entries of the same parent
933 for (i = 0; i < s_AdvancedCount; ++i)
934 {
935 ADVANCED_ENTRY *pEntry2 = &s_Advanced[i];
936 if (pEntry->dwParentID == pEntry2->dwParentID)
937 {
938 pEntry2->bChecked = FALSE;
939
940 Item.hItem = pEntry2->hItem;
941 INT iImage = Advanced_GetImage(pEntry2);
942 Item.iImage = Item.iSelectedImage = iImage;
943 TreeView_SetItem(hwndTreeView, &Item);
944 }
945 }
946 pEntry->bChecked = TRUE;
947 break;
948 default:
949 return FALSE; // failure
950 }
951 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry);
952 Item.hItem = hItem;
953 TreeView_SetItem(hwndTreeView, &Item);
954
955 // redraw the item
956 RECT rcItem;
957 TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE);
958 InvalidateRect(hwndTreeView, &rcItem, TRUE);
959 return TRUE; // success
960 }
961
962 static VOID
963 ViewDlg_OnTreeViewClick(HWND hwndDlg)
964 {
965 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
966
967 // do hit test to get the clicked item
968 TV_HITTESTINFO HitTest;
969 ZeroMemory(&HitTest, sizeof(HitTest));
970 DWORD dwPos = GetMessagePos();
971 HitTest.pt.x = LOWORD(dwPos);
972 HitTest.pt.y = HIWORD(dwPos);
973 ScreenToClient(hwndTreeView, &HitTest.pt);
974 HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest);
975
976 // toggle the check mark if possible
977 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem))
978 {
979 // property sheet was changed
980 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
981 }
982 }
983
984 static void
985 ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown)
986 {
987 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
988
989 if (KeyDown->wVKey == VK_SPACE)
990 {
991 // [Space] key was pressed
992 HTREEITEM hItem = TreeView_GetSelection(hwndTreeView);
993 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem))
994 {
995 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
996 }
997 }
998 }
999
1000 static INT_PTR
1001 ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw)
1002 {
1003 NMCUSTOMDRAW& nmcd = Draw->nmcd;
1004 switch (nmcd.dwDrawStage)
1005 {
1006 case CDDS_PREPAINT:
1007 return CDRF_NOTIFYITEMDRAW; // for CDDS_ITEMPREPAINT
1008
1009 case CDDS_ITEMPREPAINT:
1010 if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected
1011 {
1012 LPARAM lParam = nmcd.lItemlParam;
1013 ADVANCED_ENTRY *pEntry = Advanced_GetItem(lParam);
1014 if (pEntry && pEntry->bGrayed) // disabled
1015 {
1016 // draw as grayed
1017 Draw->clrText = GetSysColor(COLOR_GRAYTEXT);
1018 Draw->clrTextBk = GetSysColor(COLOR_WINDOW);
1019 return CDRF_NEWFONT;
1020 }
1021 }
1022 break;
1023
1024 default:
1025 break;
1026 }
1027 return CDRF_DODEFAULT;
1028 }
1029
1030 static VOID
1031 Advanced_RestoreDefaults(HWND hwndDlg)
1032 {
1033 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
1034
1035 for (INT i = 0; i < s_AdvancedCount; ++i)
1036 {
1037 // ignore if the type is group
1038 ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1039 if (pEntry->dwType == AETYPE_GROUP)
1040 continue;
1041
1042 // set default value on registry
1043 HKEY hKey;
1044 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath,
1045 0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
1046 {
1047 continue;
1048 }
1049 RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD,
1050 LPBYTE(pEntry->dwDefaultValue), sizeof(DWORD));
1051 RegCloseKey(hKey);
1052
1053 // update check status
1054 pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue);
1055
1056 // update the image
1057 TV_ITEM Item;
1058 ZeroMemory(&Item, sizeof(Item));
1059 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1060 Item.hItem = pEntry->hItem;
1061 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry);
1062 TreeView_SetItem(hwndTreeView, &Item);
1063 }
1064
1065 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1066 }
1067
1068 /* FIXME: These macros should not be defined here */
1069 #ifndef SSF_SHOWSUPERHIDDEN
1070 #define SSF_SHOWSUPERHIDDEN 0x00040000
1071 #endif
1072 #ifndef SSF_SEPPROCESS
1073 #define SSF_SEPPROCESS 0x00080000
1074 #endif
1075
1076 static VOID
1077 ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask)
1078 {
1079 for (INT i = 0; i < s_AdvancedCount; ++i)
1080 {
1081 const ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1082 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed)
1083 continue;
1084
1085 BOOL bChecked = pEntry->bChecked;
1086
1087 // FIXME: Add more items
1088 if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0)
1089 {
1090 pSS->fShowSuperHidden = !bChecked ? 1 : 0;
1091 *pdwMask |= SSF_SHOWSUPERHIDDEN;
1092 continue;
1093 }
1094 if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0)
1095 {
1096 pSS->fSepProcess = bChecked ? 1 : 0;
1097 *pdwMask |= SSF_SEPPROCESS;
1098 continue;
1099 }
1100 if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0)
1101 {
1102 pSS->fShowAllObjects = !bChecked ? 1 : 0;
1103 *pdwMask |= SSF_SHOWALLOBJECTS;
1104 continue;
1105 }
1106 if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0)
1107 {
1108 pSS->fShowExtensions = !bChecked ? 1 : 0;
1109 *pdwMask |= SSF_SHOWEXTENSIONS;
1110 continue;
1111 }
1112 if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0)
1113 {
1114 pSS->fShowCompColor = bChecked ? 1 : 0;
1115 *pdwMask |= SSF_SHOWCOMPCOLOR;
1116 continue;
1117 }
1118 if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0)
1119 {
1120 pSS->fShowInfoTip = bChecked ? 1 : 0;
1121 *pdwMask |= SSF_SHOWINFOTIP;
1122 continue;
1123 }
1124 }
1125 }
1126
1127 extern "C"
1128 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet);
1129
1130 static BOOL CALLBACK RefreshBrowsersCallback (HWND hWnd, LPARAM msg)
1131 {
1132 WCHAR ClassName[100];
1133 if (GetClassName(hWnd, ClassName, 100))
1134 {
1135 if (!wcscmp(ClassName, L"Progman") ||
1136 !wcscmp(ClassName, L"CabinetWClass") ||
1137 !wcscmp(ClassName, L"ExploreWClass"))
1138 {
1139 PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0);
1140 }
1141 }
1142 return TRUE;
1143 }
1144
1145 static VOID
1146 ViewDlg_Apply(HWND hwndDlg)
1147 {
1148 for (INT i = 0; i < s_AdvancedCount; ++i)
1149 {
1150 // ignore the entry if the type is group or the entry is grayed
1151 ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1152 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed)
1153 continue;
1154
1155 // open the registry key
1156 HKEY hkeyTarget;
1157 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0,
1158 KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS)
1159 {
1160 continue;
1161 }
1162
1163 // checked or unchecked?
1164 DWORD dwValue, dwSize;
1165 if (pEntry->bChecked)
1166 {
1167 dwValue = pEntry->dwCheckedValue;
1168 }
1169 else
1170 {
1171 if (pEntry->bHasUncheckedValue)
1172 {
1173 dwValue = pEntry->dwUncheckedValue;
1174 }
1175 else
1176 {
1177 // there is no unchecked value
1178 RegCloseKey(hkeyTarget);
1179 continue; // ignore
1180 }
1181 }
1182
1183 // set the value
1184 dwSize = sizeof(dwValue);
1185 RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD,
1186 LPBYTE(&dwValue), dwSize);
1187
1188 // close now
1189 RegCloseKey(hkeyTarget);
1190 }
1191
1192 // scan advanced settings for user's settings
1193 DWORD dwMask = 0;
1194 SHELLSTATE ShellState;
1195 ZeroMemory(&ShellState, sizeof(ShellState));
1196 ScanAdvancedSettings(&ShellState, &dwMask);
1197
1198 // update user's settings
1199 SHGetSetSettings(&ShellState, dwMask, TRUE);
1200
1201 // notify all
1202 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0);
1203
1204 EnumWindows(RefreshBrowsersCallback, NULL);
1205 }
1206
1207 INT_PTR CALLBACK
1208 FolderOptionsViewDlg(
1209 HWND hwndDlg,
1210 UINT uMsg,
1211 WPARAM wParam,
1212 LPARAM lParam)
1213 {
1214 INT_PTR Result;
1215 NMTVCUSTOMDRAW *Draw;
1216
1217 switch(uMsg)
1218 {
1219 case WM_INITDIALOG:
1220 return ViewDlg_OnInitDialog(hwndDlg);
1221 case WM_COMMAND:
1222 switch (LOWORD(wParam))
1223 {
1224 case 14004: // Restore Defaults
1225 Advanced_RestoreDefaults(hwndDlg);
1226 break;
1227 }
1228 break;
1229 case WM_NOTIFY:
1230 switch (LPNMHDR(lParam)->code)
1231 {
1232 case NM_CLICK: // clicked on treeview
1233 ViewDlg_OnTreeViewClick(hwndDlg);
1234 break;
1235 case NM_CUSTOMDRAW: // custom draw (for graying)
1236 Draw = (NMTVCUSTOMDRAW *)lParam;
1237 Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw);
1238 SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, Result);
1239 return Result;
1240 case TVN_KEYDOWN: // key is down
1241 ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam);
1242 break;
1243 case PSN_APPLY: // [Apply] is clicked
1244 ViewDlg_Apply(hwndDlg);
1245 break;
1246 default:
1247 break;
1248 }
1249 break;
1250 }
1251
1252 return FALSE;
1253 }
1254
1255 static
1256 VOID
1257 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl)
1258 {
1259 RECT clientRect;
1260 LVCOLUMNW col;
1261 WCHAR szName[50];
1262 DWORD dwStyle;
1263 int columnSize = 140;
1264
1265
1266 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR)))
1267 {
1268 /* default to english */
1269 wcscpy(szName, L"Extensions");
1270 }
1271
1272 /* make sure its null terminated */
1273 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
1274
1275 GetClientRect(hDlgCtrl, &clientRect);
1276 ZeroMemory(&col, sizeof(LV_COLUMN));
1277 columnSize = 140; //FIXME
1278 col.iSubItem = 0;
1279 col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
1280 col.fmt = LVCFMT_FIXED_WIDTH;
1281 col.cx = columnSize | LVCFMT_LEFT;
1282 col.cchTextMax = wcslen(szName);
1283 col.pszText = szName;
1284 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col);
1285
1286 if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR)))
1287 {
1288 /* default to english */
1289 wcscpy(szName, L"File Types");
1290 ERR("Failed to load localized string!\n");
1291 }
1292
1293 col.iSubItem = 1;
1294 col.cx = clientRect.right - clientRect.left - columnSize;
1295 col.cchTextMax = wcslen(szName);
1296 col.pszText = szName;
1297 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col);
1298
1299 /* set full select style */
1300 dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1301 dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
1302 SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
1303 }
1304
1305 INT
1306 FindItem(HWND hDlgCtrl, WCHAR * ItemName)
1307 {
1308 LVFINDINFOW findInfo;
1309 ZeroMemory(&findInfo, sizeof(LVFINDINFOW));
1310
1311 findInfo.flags = LVFI_STRING;
1312 findInfo.psz = ItemName;
1313 return ListView_FindItem(hDlgCtrl, 0, &findInfo);
1314 }
1315
1316 static
1317 VOID
1318 InsertFileType(HWND hDlgCtrl, WCHAR * szName, PINT iItem, WCHAR * szFile)
1319 {
1320 PFOLDER_FILE_TYPE_ENTRY Entry;
1321 HKEY hKey;
1322 LVITEMW lvItem;
1323 DWORD dwSize;
1324 DWORD dwType;
1325
1326 if (szName[0] != L'.')
1327 {
1328 /* FIXME handle URL protocol handlers */
1329 return;
1330 }
1331
1332 /* allocate file type entry */
1333 Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY));
1334
1335 if (!Entry)
1336 return;
1337
1338 /* open key */
1339 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
1340 {
1341 HeapFree(GetProcessHeap(), 0, Entry);
1342 return;
1343 }
1344
1345 /* FIXME check for duplicates */
1346
1347 /* query for the default key */
1348 dwSize = sizeof(Entry->ClassKey);
1349 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS)
1350 {
1351 /* no link available */
1352 Entry->ClassKey[0] = 0;
1353 }
1354
1355 if (Entry->ClassKey[0])
1356 {
1357 HKEY hTemp;
1358 /* try open linked key */
1359 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS)
1360 {
1361 /* use linked key */
1362 RegCloseKey(hKey);
1363 hKey = hTemp;
1364 }
1365 }
1366
1367 /* read friendly type name */
1368 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS)
1369 {
1370 /* read file description */
1371 dwSize = sizeof(Entry->FileDescription);
1372 Entry->FileDescription[0] = 0;
1373
1374 /* read default key */
1375 RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize);
1376 }
1377
1378 /* Read the EditFlags value */
1379 Entry->EditFlags = 0;
1380 if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize))
1381 {
1382 if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD))
1383 RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize);
1384 }
1385
1386 /* close key */
1387 RegCloseKey(hKey);
1388
1389 /* Do not add excluded entries */
1390 if (Entry->EditFlags & 0x00000001) //FTA_Exclude
1391 {
1392 HeapFree(GetProcessHeap(), 0, Entry);
1393 return;
1394 }
1395
1396 /* convert extension to upper case */
1397 wcscpy(Entry->FileExtension, szName);
1398 _wcsupr(Entry->FileExtension);
1399
1400 if (!Entry->FileDescription[0])
1401 {
1402 /* construct default 'FileExtensionFile' by formatting the uppercase extension
1403 with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File' */
1404
1405 StringCchPrintf(Entry->FileDescription, _countof(Entry->FileDescription), szFile, &Entry->FileExtension[1]);
1406 }
1407
1408 ZeroMemory(&lvItem, sizeof(LVITEMW));
1409 lvItem.mask = LVIF_TEXT | LVIF_PARAM;
1410 lvItem.iSubItem = 0;
1411 lvItem.pszText = &Entry->FileExtension[1];
1412 lvItem.iItem = *iItem;
1413 lvItem.lParam = (LPARAM)Entry;
1414 (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
1415
1416 ZeroMemory(&lvItem, sizeof(LVITEMW));
1417 lvItem.mask = LVIF_TEXT;
1418 lvItem.pszText = Entry->FileDescription;
1419 lvItem.iItem = *iItem;
1420 lvItem.iSubItem = 1;
1421 ListView_SetItem(hDlgCtrl, &lvItem);
1422
1423 (*iItem)++;
1424 }
1425
1426 static
1427 int
1428 CALLBACK
1429 ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
1430 {
1431 PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2;
1432 int x;
1433
1434 Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1;
1435 Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2;
1436
1437 x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension);
1438 if (x != 0)
1439 return x;
1440
1441 return wcsicmp(Entry1->FileDescription, Entry2->FileDescription);
1442 }
1443
1444 static
1445 PFOLDER_FILE_TYPE_ENTRY
1446 InitializeFileTypesListCtrl(HWND hwndDlg)
1447 {
1448 HWND hDlgCtrl;
1449 DWORD dwIndex = 0;
1450 WCHAR szName[50];
1451 WCHAR szFile[100];
1452 DWORD dwName;
1453 LVITEMW lvItem;
1454 INT iItem = 0;
1455
1456 hDlgCtrl = GetDlgItem(hwndDlg, 14000);
1457 InitializeFileTypesListCtrlColumns(hDlgCtrl);
1458
1459 szFile[0] = 0;
1460 if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile)))
1461 {
1462 /* default to english */
1463 wcscpy(szFile, L"%s File");
1464 }
1465 szFile[(_countof(szFile)) - 1] = 0;
1466
1467 dwName = _countof(szName);
1468
1469 while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1470 {
1471 InsertFileType(hDlgCtrl, szName, &iItem, szFile);
1472 dwName = _countof(szName);
1473 }
1474
1475 /* Leave if the list is empty */
1476 if (iItem == 0)
1477 return NULL;
1478
1479 /* sort list */
1480 ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL);
1481
1482 /* select first item */
1483 ZeroMemory(&lvItem, sizeof(LVITEMW));
1484 lvItem.mask = LVIF_STATE;
1485 lvItem.stateMask = (UINT)-1;
1486 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
1487 lvItem.iItem = 0;
1488 ListView_SetItem(hDlgCtrl, &lvItem);
1489
1490 lvItem.mask = LVIF_PARAM;
1491 ListView_GetItem(hDlgCtrl, &lvItem);
1492
1493 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
1494 }
1495
1496 static
1497 PFOLDER_FILE_TYPE_ENTRY
1498 FindSelectedItem(
1499 HWND hDlgCtrl)
1500 {
1501 UINT Count, Index;
1502 LVITEMW lvItem;
1503
1504 Count = ListView_GetItemCount(hDlgCtrl);
1505
1506 for (Index = 0; Index < Count; Index++)
1507 {
1508 ZeroMemory(&lvItem, sizeof(LVITEM));
1509 lvItem.mask = LVIF_PARAM | LVIF_STATE;
1510 lvItem.iItem = Index;
1511 lvItem.stateMask = (UINT) - 1;
1512
1513 if (ListView_GetItem(hDlgCtrl, &lvItem))
1514 {
1515 if (lvItem.state & LVIS_SELECTED)
1516 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
1517 }
1518 }
1519
1520 return NULL;
1521 }
1522
1523 INT_PTR
1524 CALLBACK
1525 FolderOptionsFileTypesDlg(
1526 HWND hwndDlg,
1527 UINT uMsg,
1528 WPARAM wParam,
1529 LPARAM lParam)
1530 {
1531 LPNMLISTVIEW lppl;
1532 LVITEMW lvItem;
1533 WCHAR Buffer[255], FormatBuffer[255];
1534 PFOLDER_FILE_TYPE_ENTRY pItem;
1535 OPENASINFO Info;
1536
1537 switch(uMsg)
1538 {
1539 case WM_INITDIALOG:
1540 pItem = InitializeFileTypesListCtrl(hwndDlg);
1541
1542 /* Disable the Delete button if the listview is empty or
1543 the selected item should not be deleted by the user */
1544 if (pItem == NULL || (pItem->EditFlags & 0x00000010)) // FTA_NoRemove
1545 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
1546 return TRUE;
1547
1548 case WM_COMMAND:
1549 switch(LOWORD(wParam))
1550 {
1551 case 14006:
1552 pItem = FindSelectedItem(GetDlgItem(hwndDlg, 14000));
1553 if (pItem)
1554 {
1555 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT;
1556 Info.pcszClass = pItem->FileExtension;
1557 SHOpenWithDialog(hwndDlg, &Info);
1558 }
1559 break;
1560 }
1561 break;
1562
1563 case WM_NOTIFY:
1564 lppl = (LPNMLISTVIEW) lParam;
1565
1566 if (lppl->hdr.code == LVN_ITEMCHANGING)
1567 {
1568 ZeroMemory(&lvItem, sizeof(LVITEM));
1569 lvItem.mask = LVIF_PARAM;
1570 lvItem.iItem = lppl->iItem;
1571 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&lvItem))
1572 return TRUE;
1573
1574 pItem = (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
1575 if (!pItem)
1576 return TRUE;
1577
1578 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
1579 {
1580 /* new focused item */
1581 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILS, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
1582 {
1583 /* use default english format string */
1584 wcscpy(FormatBuffer, L"Details for '%s' extension");
1585 }
1586
1587 /* format buffer */
1588 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1]);
1589 /* update dialog */
1590 SetDlgItemTextW(hwndDlg, 14003, Buffer);
1591
1592 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILSADV, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
1593 {
1594 /* use default english format string */
1595 wcscpy(FormatBuffer, L"Files with extension '%s' are of type '%s'. To change settings that affect all '%s' files, click Advanced.");
1596 }
1597 /* format buffer */
1598 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1], &pItem->FileDescription[0], &pItem->FileDescription[0]);
1599 /* update dialog */
1600 SetDlgItemTextW(hwndDlg, 14007, Buffer);
1601
1602 /* Enable the Delete button */
1603 if (pItem->EditFlags & 0x00000010) // FTA_NoRemove
1604 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
1605 else
1606 EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE);
1607 }
1608 }
1609 else if (lppl->hdr.code == PSN_SETACTIVE)
1610 {
1611 /* On page activation, set the focus to the listview */
1612 SetFocus(GetDlgItem(hwndDlg, 14000));
1613 }
1614 break;
1615 }
1616
1617 return FALSE;
1618 }
1619
1620 static
1621 VOID
1622 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst)
1623 {
1624 PROPSHEETHEADERW pinfo;
1625 HPROPSHEETPAGE hppages[3];
1626 HPROPSHEETPAGE hpage;
1627 UINT num_pages = 0;
1628 WCHAR szOptions[100];
1629
1630 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL);
1631 if (hpage)
1632 hppages[num_pages++] = hpage;
1633
1634 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL);
1635 if (hpage)
1636 hppages[num_pages++] = hpage;
1637
1638 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL);
1639 if (hpage)
1640 hppages[num_pages++] = hpage;
1641
1642 szOptions[0] = L'\0';
1643 LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR));
1644 szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0';
1645
1646 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
1647 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
1648 pinfo.dwFlags = PSH_NOCONTEXTHELP;
1649 pinfo.nPages = num_pages;
1650 pinfo.phpage = hppages;
1651 pinfo.pszCaption = szOptions;
1652
1653 PropertySheetW(&pinfo);
1654 }
1655
1656 static
1657 VOID
1658 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow)
1659 {
1660 switch(fOptions)
1661 {
1662 case 0:
1663 ShowFolderOptionsDialog(hWnd, hInst);
1664 break;
1665 case 1:
1666 // show taskbar options dialog
1667 FIXME("notify explorer to show taskbar options dialog");
1668 //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0);
1669 break;
1670 default:
1671 FIXME("unrecognized options id %d\n", fOptions);
1672 }
1673 }
1674
1675 /*************************************************************************
1676 * Options_RunDLL (SHELL32.@)
1677 */
1678 EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
1679 {
1680 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
1681 }
1682
1683 /*************************************************************************
1684 * Options_RunDLLA (SHELL32.@)
1685 */
1686 EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
1687 {
1688 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
1689 }
1690
1691 /*************************************************************************
1692 * Options_RunDLLW (SHELL32.@)
1693 */
1694 EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
1695 {
1696 Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow);
1697 }