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