cffee8bee11a6155765cc0a734585f131f38f592
[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-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "precomp.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL (fprop);
25
26 /// Folder Options:
27 /// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}
28 /// 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 if (dwID == DWORD(-1))
363 return NULL;
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)
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 if (pEntry->dwType == AETYPE_GROUP)
544 {
545 pEntry->hkeyRoot = NULL;
546 pEntry->szRegPath[0] = 0;
547 pEntry->szValueName[0] = 0;
548 pEntry->dwCheckedValue = 0;
549 pEntry->bHasUncheckedValue = FALSE;
550 pEntry->dwUncheckedValue = 0;
551 pEntry->dwDefaultValue = 0;
552 pEntry->hItem = NULL;
553 pEntry->bGrayed = FALSE;
554 pEntry->bChecked = FALSE;
555 }
556 else
557 {
558 // HKeyRoot
559 Value = DWORD(HKEY_CURRENT_USER);
560 Size = sizeof(Value);
561 RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&Value), &Size);
562 pEntry->hkeyRoot = HKEY(Value);
563
564 // RegPath
565 pEntry->szRegPath[0] = 0;
566 Size = sizeof(szText);
567 RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size);
568 lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath));
569
570 // ValueName
571 pEntry->szValueName[0] = 0;
572 Size = sizeof(szText);
573 RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size);
574 lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName));
575
576 // CheckedValue
577 Size = sizeof(Value);
578 Value = 0x00000001;
579 RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size);
580 pEntry->dwCheckedValue = Value;
581
582 // UncheckedValue
583 Size = sizeof(Value);
584 Value = 0x00000000;
585 pEntry->bHasUncheckedValue = TRUE;
586 if (RegQueryValueExW(hKey, L"UncheckedValue", NULL,
587 NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS)
588 {
589 pEntry->bHasUncheckedValue = FALSE;
590 }
591 pEntry->dwUncheckedValue = Value;
592
593 // DefaultValue
594 Size = sizeof(Value);
595 Value = 0x00000001;
596 RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size);
597 pEntry->dwDefaultValue = Value;
598
599 // hItem
600 pEntry->hItem = NULL;
601
602 // bGrayed, bChecked
603 HKEY hkeyTarget;
604 Value = pEntry->dwDefaultValue;
605 pEntry->bGrayed = TRUE;
606 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0,
607 KEY_READ, &hkeyTarget) == ERROR_SUCCESS)
608 {
609 Size = sizeof(Value);
610 if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL,
611 LPBYTE(&Value), &Size) == ERROR_SUCCESS)
612 {
613 pEntry->bGrayed = FALSE;
614 }
615 RegCloseKey(hkeyTarget);
616 }
617 pEntry->bChecked = (Value == pEntry->dwCheckedValue);
618 }
619
620 // Grayed (ReactOS extension)
621 Size = sizeof(Value);
622 Value = FALSE;
623 RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size);
624 if (!pEntry->bGrayed)
625 pEntry->bGrayed = Value;
626
627 BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP);
628 dwParentID = pEntry->dwID;
629 ++s_AdvancedCount;
630
631 if (!bIsGroup)
632 return TRUE; // success
633
634 // load the children
635 dwIndex = 0;
636 while (RegEnumKeyW(hKey, dwIndex, szKeyName,
637 _countof(szKeyName)) == ERROR_SUCCESS)
638 {
639 HKEY hkeyChild;
640 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ,
641 &hkeyChild) != ERROR_SUCCESS)
642 {
643 ++dwIndex;
644 continue; // failure
645 }
646
647 Advanced_LoadTree(hkeyChild, szKeyName, dwParentID);
648 RegCloseKey(hkeyChild);
649
650 ++dwIndex;
651 }
652
653 return TRUE; // success
654 }
655
656 static BOOL
657 Advanced_LoadAll(VOID)
658 {
659 static const WCHAR s_szAdvanced[] =
660 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
661
662 // free if already existed
663 if (s_Advanced)
664 {
665 free(s_Advanced);
666 s_Advanced = NULL;
667 }
668 s_AdvancedCount = 0;
669
670 HKEY hKey;
671 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szAdvanced, 0,
672 KEY_READ, &hKey) != ERROR_SUCCESS)
673 {
674 return FALSE; // failure
675 }
676
677 // load the children
678 WCHAR szKeyName[64];
679 DWORD dwIndex = 0;
680 while (RegEnumKeyW(hKey, dwIndex, szKeyName,
681 _countof(szKeyName)) == ERROR_SUCCESS)
682 {
683 HKEY hkeyChild;
684 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ,
685 &hkeyChild) != ERROR_SUCCESS)
686 {
687 ++dwIndex;
688 continue; // failure
689 }
690
691 Advanced_LoadTree(hkeyChild, szKeyName, DWORD(-1));
692 RegCloseKey(hkeyChild);
693
694 ++dwIndex;
695 }
696
697 RegCloseKey(hKey);
698
699 return TRUE; // success
700 }
701
702 static int
703 Advanced_Compare(const void *x, const void *y)
704 {
705 ADVANCED_ENTRY *pEntry1 = (ADVANCED_ENTRY *)x;
706 ADVANCED_ENTRY *pEntry2 = (ADVANCED_ENTRY *)y;
707
708 DWORD dwParentID1 = pEntry1->dwParentID;
709 DWORD dwParentID2 = pEntry2->dwParentID;
710
711 if (dwParentID1 == dwParentID2)
712 return lstrcmpi(pEntry1->szText, pEntry2->szText);
713
714 DWORD i, m, n;
715 const UINT MAX_DEPTH = 32;
716 ADVANCED_ENTRY *pArray1[MAX_DEPTH];
717 ADVANCED_ENTRY *pArray2[MAX_DEPTH];
718
719 // Make ancestor lists
720 for (i = m = n = 0; i < MAX_DEPTH; ++i)
721 {
722 ADVANCED_ENTRY *pParent1 = Advanced_GetItem(dwParentID1);
723 ADVANCED_ENTRY *pParent2 = Advanced_GetItem(dwParentID2);
724 if (!pParent1 && !pParent2)
725 break;
726
727 if (pParent1)
728 {
729 pArray1[m++] = pParent1;
730 dwParentID1 = pParent1->dwParentID;
731 }
732 if (pParent2)
733 {
734 pArray2[n++] = pParent2;
735 dwParentID2 = pParent2->dwParentID;
736 }
737 }
738
739 UINT k = min(m, n);
740 for (i = 0; i < k; ++i)
741 {
742 INT nCompare = lstrcmpi(pArray1[m - i - 1]->szText, pArray2[n - i - 1]->szText);
743 if (nCompare < 0)
744 return -1;
745 if (nCompare > 0)
746 return 1;
747 }
748
749 if (m < n)
750 return -1;
751 if (m > n)
752 return 1;
753 return lstrcmpi(pEntry1->szText, pEntry2->szText);
754 }
755
756 static VOID
757 Advanced_SortAll(VOID)
758 {
759 qsort(s_Advanced, s_AdvancedCount, sizeof(ADVANCED_ENTRY), Advanced_Compare);
760 }
761
762 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
763
764 static VOID
765 UpdateGeneralIcons(HWND hDlg)
766 {
767 HWND hwndTaskIcon, hwndFolderIcon, hwndClickIcon;
768 HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL;
769 LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL;
770
771 // show task setting icon
772 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED)
773 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS);
774 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED)
775 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS);
776
777 if (lpTaskIconName)
778 {
779 hTaskIcon = (HICON)LoadImage(shell32_hInstance,
780 lpTaskIconName,
781 IMAGE_ICON,
782 0,
783 0,
784 LR_DEFAULTCOLOR);
785 if (hTaskIcon)
786 {
787 hwndTaskIcon = GetDlgItem(hDlg,
788 IDC_FOLDER_OPTIONS_TASKICON);
789 if (hwndTaskIcon)
790 {
791 SendMessage(hwndTaskIcon,
792 STM_SETIMAGE,
793 IMAGE_ICON,
794 (LPARAM)hTaskIcon);
795 }
796 }
797 }
798
799 // show Folder setting icons
800 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED)
801 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW);
802 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED)
803 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW);
804
805 if (lpFolderIconName)
806 {
807 hFolderIcon = (HICON)LoadImage(shell32_hInstance,
808 lpFolderIconName,
809 IMAGE_ICON,
810 0,
811 0,
812 LR_DEFAULTCOLOR);
813 if (hFolderIcon)
814 {
815 hwndFolderIcon = GetDlgItem(hDlg,
816 IDC_FOLDER_OPTIONS_FOLDERICON);
817 if (hwndFolderIcon)
818 {
819 SendMessage(hwndFolderIcon,
820 STM_SETIMAGE,
821 IMAGE_ICON,
822 (LPARAM)hFolderIcon);
823 }
824 }
825 }
826
827 // Show click setting icon
828 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED)
829 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN);
830 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED)
831 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN);
832
833 if (lpClickIconName)
834 {
835 hClickIcon = (HICON)LoadImage(shell32_hInstance,
836 lpClickIconName,
837 IMAGE_ICON,
838 0,
839 0,
840 LR_DEFAULTCOLOR);
841 if (hClickIcon)
842 {
843 hwndClickIcon = GetDlgItem(hDlg,
844 IDC_FOLDER_OPTIONS_CLICKICON);
845 if (hwndClickIcon)
846 {
847 SendMessage(hwndClickIcon,
848 STM_SETIMAGE,
849 IMAGE_ICON,
850 (LPARAM)hClickIcon);
851 }
852 }
853 }
854
855 // Clean up
856 if(hTaskIcon)
857 DeleteObject(hTaskIcon);
858 if(hFolderIcon)
859 DeleteObject(hFolderIcon);
860 if(hClickIcon)
861 DeleteObject(hClickIcon);
862
863 return;
864 }
865
866 INT_PTR
867 CALLBACK
868 FolderOptionsGeneralDlg(
869 HWND hwndDlg,
870 UINT uMsg,
871 WPARAM wParam,
872 LPARAM lParam
873 )
874 {
875 switch(uMsg)
876 {
877 case WM_INITDIALOG:
878 // FIXME
879 break;
880
881 case WM_COMMAND:
882 switch (LOWORD(wParam))
883 {
884 case IDC_FOLDER_OPTIONS_COMMONTASKS:
885 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS:
886 case IDC_FOLDER_OPTIONS_SAMEWINDOW:
887 case IDC_FOLDER_OPTIONS_OWNWINDOW:
888 case IDC_FOLDER_OPTIONS_SINGLECLICK:
889 case IDC_FOLDER_OPTIONS_DOUBLECLICK:
890 if (HIWORD(wParam) == BN_CLICKED)
891 {
892 UpdateGeneralIcons(hwndDlg);
893
894 /* Enable the 'Apply' button */
895 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
896 }
897 break;
898 }
899 break;
900
901 case WM_NOTIFY:
902 {
903 LPNMHDR pnmh = (LPNMHDR)lParam;
904
905 switch (pnmh->code)
906 {
907 case PSN_SETACTIVE:
908 break;
909
910 case PSN_APPLY:
911 break;
912 }
913 break;
914 }
915
916 case WM_DESTROY:
917 break;
918
919 default:
920 return FALSE;
921 }
922 return FALSE;
923 }
924
925 static BOOL
926 ViewDlg_OnInitDialog(HWND hwndDlg)
927 {
928 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
929
930 s_hImageList = CreateTreeImageList();
931 TreeView_SetImageList(hwndTreeView, s_hImageList, TVSIL_NORMAL);
932
933 Advanced_LoadAll();
934 Advanced_SortAll();
935 Advanced_InsertAll(hwndTreeView);
936
937 return TRUE; // set focus
938 }
939
940 static BOOL
941 ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem)
942 {
943 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
944
945 // get the item
946 TV_ITEM Item;
947 INT i;
948 ZeroMemory(&Item, sizeof(Item));
949 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM;
950 Item.hItem = hItem;
951 if (!TreeView_GetItem(hwndTreeView, &Item))
952 return FALSE; // no such item
953
954 ADVANCED_ENTRY *pEntry = Advanced_GetItem(Item.lParam);
955 if (pEntry == NULL)
956 return FALSE; // no such item
957 if (pEntry->bGrayed)
958 return FALSE; // disabled
959
960 // toggle check mark
961 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
962 switch (pEntry->dwType)
963 {
964 case AETYPE_CHECKBOX:
965 pEntry->bChecked = !pEntry->bChecked;
966 break;
967 case AETYPE_RADIO:
968 // reset all the entries of the same parent
969 for (i = 0; i < s_AdvancedCount; ++i)
970 {
971 ADVANCED_ENTRY *pEntry2 = &s_Advanced[i];
972 if (pEntry->dwParentID == pEntry2->dwParentID)
973 {
974 pEntry2->bChecked = FALSE;
975
976 Item.hItem = pEntry2->hItem;
977 INT iImage = Advanced_GetImage(pEntry2);
978 Item.iImage = Item.iSelectedImage = iImage;
979 TreeView_SetItem(hwndTreeView, &Item);
980 }
981 }
982 pEntry->bChecked = TRUE;
983 break;
984 default:
985 return FALSE; // failure
986 }
987 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry);
988 Item.hItem = hItem;
989 TreeView_SetItem(hwndTreeView, &Item);
990
991 // redraw the item
992 RECT rcItem;
993 TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE);
994 InvalidateRect(hwndTreeView, &rcItem, TRUE);
995 return TRUE; // success
996 }
997
998 static VOID
999 ViewDlg_OnTreeViewClick(HWND hwndDlg)
1000 {
1001 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
1002
1003 // do hit test to get the clicked item
1004 TV_HITTESTINFO HitTest;
1005 ZeroMemory(&HitTest, sizeof(HitTest));
1006 DWORD dwPos = GetMessagePos();
1007 HitTest.pt.x = LOWORD(dwPos);
1008 HitTest.pt.y = HIWORD(dwPos);
1009 ScreenToClient(hwndTreeView, &HitTest.pt);
1010 HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest);
1011
1012 // toggle the check mark if possible
1013 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem))
1014 {
1015 // property sheet was changed
1016 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1017 }
1018 }
1019
1020 static void
1021 ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown)
1022 {
1023 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
1024
1025 if (KeyDown->wVKey == VK_SPACE)
1026 {
1027 // [Space] key was pressed
1028 HTREEITEM hItem = TreeView_GetSelection(hwndTreeView);
1029 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem))
1030 {
1031 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1032 }
1033 }
1034 }
1035
1036 static INT_PTR
1037 ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw)
1038 {
1039 NMCUSTOMDRAW& nmcd = Draw->nmcd;
1040 switch (nmcd.dwDrawStage)
1041 {
1042 case CDDS_PREPAINT:
1043 return CDRF_NOTIFYITEMDRAW; // for CDDS_ITEMPREPAINT
1044
1045 case CDDS_ITEMPREPAINT:
1046 if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected
1047 {
1048 LPARAM lParam = nmcd.lItemlParam;
1049 ADVANCED_ENTRY *pEntry = Advanced_GetItem(lParam);
1050 if (pEntry && pEntry->bGrayed) // disabled
1051 {
1052 // draw as grayed
1053 Draw->clrText = GetSysColor(COLOR_GRAYTEXT);
1054 Draw->clrTextBk = GetSysColor(COLOR_WINDOW);
1055 return CDRF_NEWFONT;
1056 }
1057 }
1058 break;
1059
1060 default:
1061 break;
1062 }
1063 return CDRF_DODEFAULT;
1064 }
1065
1066 static VOID
1067 Advanced_RestoreDefaults(HWND hwndDlg)
1068 {
1069 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
1070
1071 for (INT i = 0; i < s_AdvancedCount; ++i)
1072 {
1073 // ignore if the type is group
1074 ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1075 if (pEntry->dwType == AETYPE_GROUP)
1076 continue;
1077
1078 // set default value on registry
1079 HKEY hKey;
1080 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath,
1081 0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
1082 {
1083 continue;
1084 }
1085 RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD,
1086 LPBYTE(pEntry->dwDefaultValue), sizeof(DWORD));
1087 RegCloseKey(hKey);
1088
1089 // update check status
1090 pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue);
1091
1092 // update the image
1093 TV_ITEM Item;
1094 ZeroMemory(&Item, sizeof(Item));
1095 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1096 Item.hItem = pEntry->hItem;
1097 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry);
1098 TreeView_SetItem(hwndTreeView, &Item);
1099 }
1100
1101 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1102 }
1103
1104 /* FIXME: These macros should not be defined here */
1105 #ifndef SSF_SHOWSUPERHIDDEN
1106 #define SSF_SHOWSUPERHIDDEN 0x00040000
1107 #endif
1108 #ifndef SSF_SEPPROCESS
1109 #define SSF_SEPPROCESS 0x00080000
1110 #endif
1111
1112 static VOID
1113 ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask)
1114 {
1115 for (INT i = 0; i < s_AdvancedCount; ++i)
1116 {
1117 const ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1118 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed)
1119 continue;
1120
1121 BOOL bChecked = pEntry->bChecked;
1122
1123 // FIXME: Add more items
1124 if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0)
1125 {
1126 pSS->fShowSuperHidden = !bChecked ? 1 : 0;
1127 *pdwMask |= SSF_SHOWSUPERHIDDEN;
1128 continue;
1129 }
1130 if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0)
1131 {
1132 pSS->fSepProcess = bChecked ? 1 : 0;
1133 *pdwMask |= SSF_SEPPROCESS;
1134 continue;
1135 }
1136 if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0)
1137 {
1138 pSS->fShowAllObjects = !bChecked ? 1 : 0;
1139 *pdwMask |= SSF_SHOWALLOBJECTS;
1140 continue;
1141 }
1142 if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0)
1143 {
1144 pSS->fShowExtensions = !bChecked ? 1 : 0;
1145 *pdwMask |= SSF_SHOWEXTENSIONS;
1146 continue;
1147 }
1148 if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0)
1149 {
1150 pSS->fShowCompColor = bChecked ? 1 : 0;
1151 *pdwMask |= SSF_SHOWCOMPCOLOR;
1152 continue;
1153 }
1154 if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0)
1155 {
1156 pSS->fShowInfoTip = bChecked ? 1 : 0;
1157 *pdwMask |= SSF_SHOWINFOTIP;
1158 continue;
1159 }
1160 }
1161 }
1162
1163 extern "C"
1164 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet);
1165
1166 static BOOL CALLBACK RefreshBrowsersCallback (HWND hWnd, LPARAM msg)
1167 {
1168 WCHAR ClassName[100];
1169 if (GetClassName(hWnd, ClassName, 100))
1170 {
1171 if (!wcscmp(ClassName, L"Progman") ||
1172 !wcscmp(ClassName, L"CabinetWClass") ||
1173 !wcscmp(ClassName, L"ExploreWClass"))
1174 {
1175 PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0);
1176 }
1177 }
1178 return TRUE;
1179 }
1180
1181 static VOID
1182 ViewDlg_Apply(HWND hwndDlg)
1183 {
1184 for (INT i = 0; i < s_AdvancedCount; ++i)
1185 {
1186 // ignore the entry if the type is group or the entry is grayed
1187 ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1188 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed)
1189 continue;
1190
1191 // open the registry key
1192 HKEY hkeyTarget;
1193 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0,
1194 KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS)
1195 {
1196 continue;
1197 }
1198
1199 // checked or unchecked?
1200 DWORD dwValue, dwSize;
1201 if (pEntry->bChecked)
1202 {
1203 dwValue = pEntry->dwCheckedValue;
1204 }
1205 else
1206 {
1207 if (pEntry->bHasUncheckedValue)
1208 {
1209 dwValue = pEntry->dwUncheckedValue;
1210 }
1211 else
1212 {
1213 // there is no unchecked value
1214 RegCloseKey(hkeyTarget);
1215 continue; // ignore
1216 }
1217 }
1218
1219 // set the value
1220 dwSize = sizeof(dwValue);
1221 RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD,
1222 LPBYTE(&dwValue), dwSize);
1223
1224 // close now
1225 RegCloseKey(hkeyTarget);
1226 }
1227
1228 // scan advanced settings for user's settings
1229 DWORD dwMask = 0;
1230 SHELLSTATE ShellState;
1231 ZeroMemory(&ShellState, sizeof(ShellState));
1232 ScanAdvancedSettings(&ShellState, &dwMask);
1233
1234 // update user's settings
1235 SHGetSetSettings(&ShellState, dwMask, TRUE);
1236
1237 // notify all
1238 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0);
1239
1240 EnumWindows(RefreshBrowsersCallback, NULL);
1241 }
1242
1243 INT_PTR CALLBACK
1244 FolderOptionsViewDlg(
1245 HWND hwndDlg,
1246 UINT uMsg,
1247 WPARAM wParam,
1248 LPARAM lParam)
1249 {
1250 INT_PTR Result;
1251 NMTVCUSTOMDRAW *Draw;
1252
1253 switch(uMsg)
1254 {
1255 case WM_INITDIALOG:
1256 return ViewDlg_OnInitDialog(hwndDlg);
1257 case WM_COMMAND:
1258 switch (LOWORD(wParam))
1259 {
1260 case 14004: // Restore Defaults
1261 Advanced_RestoreDefaults(hwndDlg);
1262 break;
1263 }
1264 break;
1265 case WM_NOTIFY:
1266 switch (LPNMHDR(lParam)->code)
1267 {
1268 case NM_CLICK: // clicked on treeview
1269 ViewDlg_OnTreeViewClick(hwndDlg);
1270 break;
1271 case NM_CUSTOMDRAW: // custom draw (for graying)
1272 Draw = (NMTVCUSTOMDRAW *)lParam;
1273 Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw);
1274 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result);
1275 return Result;
1276 case TVN_KEYDOWN: // key is down
1277 ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam);
1278 break;
1279 case PSN_APPLY: // [Apply] is clicked
1280 ViewDlg_Apply(hwndDlg);
1281 break;
1282 default:
1283 break;
1284 }
1285 break;
1286 }
1287
1288 return FALSE;
1289 }
1290
1291 static
1292 VOID
1293 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl)
1294 {
1295 RECT clientRect;
1296 LVCOLUMNW col;
1297 WCHAR szName[50];
1298 DWORD dwStyle;
1299 int columnSize = 140;
1300
1301
1302 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR)))
1303 {
1304 /* default to english */
1305 wcscpy(szName, L"Extensions");
1306 }
1307
1308 /* make sure its null terminated */
1309 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
1310
1311 GetClientRect(hDlgCtrl, &clientRect);
1312 ZeroMemory(&col, sizeof(LV_COLUMN));
1313 columnSize = 140; //FIXME
1314 col.iSubItem = 0;
1315 col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
1316 col.fmt = LVCFMT_FIXED_WIDTH;
1317 col.cx = columnSize | LVCFMT_LEFT;
1318 col.cchTextMax = wcslen(szName);
1319 col.pszText = szName;
1320 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col);
1321
1322 if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR)))
1323 {
1324 /* default to english */
1325 wcscpy(szName, L"File Types");
1326 ERR("Failed to load localized string!\n");
1327 }
1328
1329 col.iSubItem = 1;
1330 col.cx = clientRect.right - clientRect.left - columnSize;
1331 col.cchTextMax = wcslen(szName);
1332 col.pszText = szName;
1333 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col);
1334
1335 /* set full select style */
1336 dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1337 dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
1338 SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
1339 }
1340
1341 INT
1342 FindItem(HWND hDlgCtrl, WCHAR * ItemName)
1343 {
1344 LVFINDINFOW findInfo;
1345 ZeroMemory(&findInfo, sizeof(LVFINDINFOW));
1346
1347 findInfo.flags = LVFI_STRING;
1348 findInfo.psz = ItemName;
1349 return ListView_FindItem(hDlgCtrl, 0, &findInfo);
1350 }
1351
1352 static BOOL
1353 DeleteExt(HWND hwndDlg, LPCWSTR pszExt)
1354 {
1355 if (*pszExt != L'.')
1356 return FALSE;
1357
1358 HKEY hKey;
1359 LONG nResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, pszExt, 0, KEY_READ, &hKey);
1360 if (nResult != ERROR_SUCCESS)
1361 return FALSE;
1362
1363 WCHAR szValue[64];
1364 DWORD cbValue = sizeof(szValue);
1365 nResult = RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(szValue), &cbValue);
1366 RegCloseKey(hKey);
1367 if (nResult != ERROR_SUCCESS)
1368 return FALSE;
1369
1370 if (szValue[0])
1371 SHDeleteKeyW(HKEY_CLASSES_ROOT, szValue);
1372
1373 return SHDeleteKeyW(HKEY_CLASSES_ROOT, pszExt) == ERROR_SUCCESS;
1374 }
1375
1376 static
1377 VOID
1378 InsertFileType(HWND hDlgCtrl, WCHAR * szName, PINT iItem, WCHAR * szFile)
1379 {
1380 PFOLDER_FILE_TYPE_ENTRY Entry;
1381 HKEY hKey;
1382 LVITEMW lvItem;
1383 DWORD dwSize;
1384 DWORD dwType;
1385
1386 if (szName[0] != L'.')
1387 {
1388 /* FIXME handle URL protocol handlers */
1389 return;
1390 }
1391
1392 /* allocate file type entry */
1393 Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY));
1394
1395 if (!Entry)
1396 return;
1397
1398 /* open key */
1399 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
1400 {
1401 HeapFree(GetProcessHeap(), 0, Entry);
1402 return;
1403 }
1404
1405 /* FIXME check for duplicates */
1406
1407 /* query for the default key */
1408 dwSize = sizeof(Entry->ClassKey);
1409 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS)
1410 {
1411 /* no link available */
1412 Entry->ClassKey[0] = 0;
1413 }
1414
1415 if (Entry->ClassKey[0])
1416 {
1417 HKEY hTemp;
1418 /* try open linked key */
1419 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS)
1420 {
1421 /* use linked key */
1422 RegCloseKey(hKey);
1423 hKey = hTemp;
1424 }
1425 }
1426
1427 /* read friendly type name */
1428 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS)
1429 {
1430 /* read file description */
1431 dwSize = sizeof(Entry->FileDescription);
1432 Entry->FileDescription[0] = 0;
1433
1434 /* read default key */
1435 RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize);
1436 }
1437
1438 /* Read the EditFlags value */
1439 Entry->EditFlags = 0;
1440 if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize))
1441 {
1442 if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD))
1443 RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize);
1444 }
1445
1446 /* close key */
1447 RegCloseKey(hKey);
1448
1449 /* Do not add excluded entries */
1450 if (Entry->EditFlags & 0x00000001) //FTA_Exclude
1451 {
1452 HeapFree(GetProcessHeap(), 0, Entry);
1453 return;
1454 }
1455
1456 /* convert extension to upper case */
1457 wcscpy(Entry->FileExtension, szName);
1458 _wcsupr(Entry->FileExtension);
1459
1460 if (!Entry->FileDescription[0])
1461 {
1462 /* construct default 'FileExtensionFile' by formatting the uppercase extension
1463 with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File' */
1464
1465 StringCchPrintf(Entry->FileDescription, _countof(Entry->FileDescription), szFile, &Entry->FileExtension[1]);
1466 }
1467
1468 ZeroMemory(&lvItem, sizeof(LVITEMW));
1469 lvItem.mask = LVIF_TEXT | LVIF_PARAM;
1470 lvItem.iSubItem = 0;
1471 lvItem.pszText = &Entry->FileExtension[1];
1472 lvItem.iItem = *iItem;
1473 lvItem.lParam = (LPARAM)Entry;
1474 (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
1475
1476 ZeroMemory(&lvItem, sizeof(LVITEMW));
1477 lvItem.mask = LVIF_TEXT;
1478 lvItem.pszText = Entry->FileDescription;
1479 lvItem.iItem = *iItem;
1480 lvItem.iSubItem = 1;
1481 ListView_SetItem(hDlgCtrl, &lvItem);
1482
1483 (*iItem)++;
1484 }
1485
1486 static
1487 int
1488 CALLBACK
1489 ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
1490 {
1491 PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2;
1492 int x;
1493
1494 Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1;
1495 Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2;
1496
1497 x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension);
1498 if (x != 0)
1499 return x;
1500
1501 return wcsicmp(Entry1->FileDescription, Entry2->FileDescription);
1502 }
1503
1504 static
1505 PFOLDER_FILE_TYPE_ENTRY
1506 InitializeFileTypesListCtrl(HWND hwndDlg)
1507 {
1508 HWND hDlgCtrl;
1509 DWORD dwIndex = 0;
1510 WCHAR szName[50];
1511 WCHAR szFile[100];
1512 DWORD dwName;
1513 LVITEMW lvItem;
1514 INT iItem = 0;
1515
1516 hDlgCtrl = GetDlgItem(hwndDlg, 14000);
1517 InitializeFileTypesListCtrlColumns(hDlgCtrl);
1518
1519 szFile[0] = 0;
1520 if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile)))
1521 {
1522 /* default to english */
1523 wcscpy(szFile, L"%s File");
1524 }
1525 szFile[(_countof(szFile)) - 1] = 0;
1526
1527 dwName = _countof(szName);
1528
1529 while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1530 {
1531 InsertFileType(hDlgCtrl, szName, &iItem, szFile);
1532 dwName = _countof(szName);
1533 }
1534
1535 /* Leave if the list is empty */
1536 if (iItem == 0)
1537 return NULL;
1538
1539 /* sort list */
1540 ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL);
1541
1542 /* select first item */
1543 ZeroMemory(&lvItem, sizeof(LVITEMW));
1544 lvItem.mask = LVIF_STATE;
1545 lvItem.stateMask = (UINT)-1;
1546 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
1547 lvItem.iItem = 0;
1548 ListView_SetItem(hDlgCtrl, &lvItem);
1549
1550 lvItem.mask = LVIF_PARAM;
1551 ListView_GetItem(hDlgCtrl, &lvItem);
1552
1553 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
1554 }
1555
1556 static
1557 PFOLDER_FILE_TYPE_ENTRY
1558 FindSelectedItem(
1559 HWND hDlgCtrl)
1560 {
1561 UINT Count, Index;
1562 LVITEMW lvItem;
1563
1564 Count = ListView_GetItemCount(hDlgCtrl);
1565
1566 for (Index = 0; Index < Count; Index++)
1567 {
1568 ZeroMemory(&lvItem, sizeof(LVITEM));
1569 lvItem.mask = LVIF_PARAM | LVIF_STATE;
1570 lvItem.iItem = Index;
1571 lvItem.stateMask = (UINT) - 1;
1572
1573 if (ListView_GetItem(hDlgCtrl, &lvItem))
1574 {
1575 if (lvItem.state & LVIS_SELECTED)
1576 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
1577 }
1578 }
1579
1580 return NULL;
1581 }
1582
1583 struct NEWEXT_DIALOG
1584 {
1585 HWND hwndDlg;
1586 HWND hwndLV;
1587 RECT rcDlg;
1588 BOOL bAdvanced;
1589 INT dy;
1590 WCHAR szExt[16];
1591 WCHAR szFileType[64];
1592 };
1593
1594 static VOID
1595 NewExtDlg_OnAdvanced(HWND hwndDlg, NEWEXT_DIALOG *pNewExt)
1596 {
1597 // If "Advanced" button was clicked, then we shrink or expand the dialog.
1598 WCHAR szText[64];
1599 RECT rc, rc1, rc2;
1600
1601 GetWindowRect(hwndDlg, &rc);
1602 rc.bottom = rc.top + (pNewExt->rcDlg.bottom - pNewExt->rcDlg.top);
1603
1604 GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc1);
1605 MapWindowPoints(NULL, hwndDlg, (POINT *)&rc1, 2);
1606
1607 GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rc2);
1608 MapWindowPoints(NULL, hwndDlg, (POINT *)&rc2, 2);
1609
1610 if (pNewExt->bAdvanced)
1611 {
1612 rc1.top += pNewExt->dy;
1613 rc1.bottom += pNewExt->dy;
1614
1615 rc2.top += pNewExt->dy;
1616 rc2.bottom += pNewExt->dy;
1617
1618 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_SHOWNOACTIVATE);
1619 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_SHOWNOACTIVATE);
1620
1621 LoadStringW(shell32_hInstance, IDS_NEWEXT_ADVANCED_LEFT, szText, _countof(szText));
1622 SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, szText);
1623
1624 SetFocus(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX));
1625 }
1626 else
1627 {
1628 rc1.top -= pNewExt->dy;
1629 rc1.bottom -= pNewExt->dy;
1630
1631 rc2.top -= pNewExt->dy;
1632 rc2.bottom -= pNewExt->dy;
1633
1634 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_HIDE);
1635 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_HIDE);
1636
1637 LoadStringW(shell32_hInstance, IDS_NEWEXT_ADVANCED_RIGHT, szText, _countof(szText));
1638 SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, szText);
1639
1640 rc.bottom -= pNewExt->dy;
1641
1642 LoadStringW(shell32_hInstance, IDS_NEWEXT_NEW, szText, _countof(szText));
1643 SetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, szText);
1644 }
1645
1646 HDWP hDWP = BeginDeferWindowPos(3);
1647
1648 if (hDWP)
1649 hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDOK), NULL,
1650 rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
1651 SWP_NOACTIVATE | SWP_NOZORDER);
1652 if (hDWP)
1653 hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDCANCEL), NULL,
1654 rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top,
1655 SWP_NOACTIVATE | SWP_NOZORDER);
1656 if (hDWP)
1657 hDWP = DeferWindowPos(hDWP, hwndDlg, NULL,
1658 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
1659 SWP_NOACTIVATE | SWP_NOZORDER);
1660
1661 if (hDWP)
1662 EndDeferWindowPos(hDWP);
1663 }
1664
1665 static BOOL
1666 NewExtDlg_OnInitDialog(HWND hwndDlg, NEWEXT_DIALOG *pNewExt)
1667 {
1668 WCHAR szText[64];
1669
1670 pNewExt->hwndDlg = hwndDlg;
1671 pNewExt->bAdvanced = FALSE;
1672
1673 GetWindowRect(hwndDlg, &pNewExt->rcDlg);
1674
1675 RECT rc1, rc2;
1676 GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_EDIT), &rc1);
1677 GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), &rc2);
1678 pNewExt->dy = rc2.top - rc1.top;
1679
1680 LoadStringW(shell32_hInstance, IDS_NEWEXT_NEW, szText, _countof(szText));
1681 SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_ADDSTRING, 0, (LPARAM)szText);
1682 SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_SETCURSEL, 0, 0);
1683
1684 SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_EDIT, EM_SETLIMITTEXT, _countof(pNewExt->szExt) - 1, 0);
1685
1686 NewExtDlg_OnAdvanced(hwndDlg, pNewExt);
1687
1688 return TRUE;
1689 }
1690
1691 static void
1692 StringTrimW(LPWSTR pszText)
1693 {
1694 LPWSTR pch = pszText;
1695 while (iswspace(*pch))
1696 pch++;
1697
1698 LPWSTR pchFirst, pchLast;
1699 pchFirst = pchLast = pch;
1700 while (*pch && !iswspace(*pch))
1701 {
1702 ++pch;
1703 pchLast = pch;
1704 }
1705
1706 INT_PTR cch = pchLast - pchFirst;
1707 MoveMemory(pszText, pchFirst, cch * sizeof(WCHAR));
1708 pszText[cch] = 0;
1709 }
1710
1711 static BOOL
1712 NewExtDlg_OnOK(HWND hwndDlg, NEWEXT_DIALOG *pNewExt)
1713 {
1714 LV_FINDINFO find;
1715 INT iItem;
1716
1717 GetDlgItemTextW(hwndDlg, IDC_NEWEXT_EDIT, pNewExt->szExt, _countof(pNewExt->szExt));
1718 StringTrimW(pNewExt->szExt);
1719 CharUpperW(pNewExt->szExt);
1720
1721 GetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, pNewExt->szFileType, _countof(pNewExt->szFileType));
1722 StringTrimW(pNewExt->szFileType);
1723
1724 if (pNewExt->szExt[0] == 0)
1725 {
1726 WCHAR szText[128], szTitle[128];
1727 LoadStringW(shell32_hInstance, IDS_NEWEXT_SPECIFY_EXT, szText, _countof(szText));
1728 szText[_countof(szText) - 1] = 0;
1729 LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szTitle, _countof(szTitle));
1730 szTitle[_countof(szTitle) - 1] = 0;
1731 MessageBoxW(hwndDlg, szText, szTitle, MB_ICONERROR);
1732 return FALSE;
1733 }
1734
1735 ZeroMemory(&find, sizeof(find));
1736 find.flags = LVFI_STRING;
1737 if (pNewExt->szExt[0] == L'.')
1738 {
1739 find.psz = &pNewExt->szExt[1];
1740 }
1741 else
1742 {
1743 find.psz = pNewExt->szExt;
1744 }
1745
1746 iItem = ListView_FindItem(pNewExt->hwndLV, -1, &find);
1747 if (iItem >= 0)
1748 {
1749 // already exists
1750 WCHAR szText[256], szFormat[256], szTitle[64], szFileType[64];
1751
1752 // get file type
1753 LV_ITEM item;
1754 ZeroMemory(&item, sizeof(item));
1755 item.mask = LVIF_TEXT;
1756 item.pszText = szFileType;
1757 item.cchTextMax = _countof(szFileType);
1758 item.iItem = iItem;
1759 item.iSubItem = 1;
1760 ListView_GetItem(pNewExt->hwndLV, &item);
1761
1762 // get text
1763 LoadStringW(shell32_hInstance, IDS_NEWEXT_ALREADY_ASSOC, szFormat, _countof(szFormat));
1764 szText[_countof(szFormat) - 1] = 0;
1765 StringCchPrintfW(szText, _countof(szText), szFormat, find.psz, szFileType, find.psz, szFileType);
1766
1767 // get title
1768 LoadStringW(shell32_hInstance, IDS_NEWEXT_EXT_IN_USE, szTitle, _countof(szTitle));
1769 szTitle[_countof(szTitle) - 1] = 0;
1770
1771 if (MessageBoxW(hwndDlg, szText, szTitle, MB_ICONWARNING | MB_YESNO) == IDNO)
1772 {
1773 return FALSE;
1774 }
1775
1776 // Delete the extension
1777 CStringW strExt(L".");
1778 strExt += find.psz;
1779 strExt.MakeLower();
1780 DeleteExt(hwndDlg, strExt);
1781
1782 // Delete the item
1783 ListView_DeleteItem(pNewExt->hwndLV, iItem);
1784 }
1785
1786 EndDialog(hwndDlg, IDOK);
1787 return TRUE;
1788 }
1789
1790 // IDD_NEWEXTENSION dialog
1791 INT_PTR
1792 CALLBACK
1793 NewExtensionDlgProc(
1794 HWND hwndDlg,
1795 UINT uMsg,
1796 WPARAM wParam,
1797 LPARAM lParam)
1798 {
1799 static NEWEXT_DIALOG *s_pNewExt = NULL;
1800
1801 switch (uMsg)
1802 {
1803 case WM_INITDIALOG:
1804 s_pNewExt = (NEWEXT_DIALOG *)lParam;
1805 NewExtDlg_OnInitDialog(hwndDlg, s_pNewExt);
1806 return TRUE;
1807 case WM_COMMAND:
1808 switch (LOWORD(wParam))
1809 {
1810 case IDOK:
1811 NewExtDlg_OnOK(hwndDlg, s_pNewExt);
1812 break;
1813 case IDCANCEL:
1814 EndDialog(hwndDlg, IDCANCEL);
1815 break;
1816 case IDC_NEWEXT_ADVANCED:
1817 s_pNewExt->bAdvanced = !s_pNewExt->bAdvanced;
1818 NewExtDlg_OnAdvanced(hwndDlg, s_pNewExt);
1819 break;
1820 }
1821 break;
1822 }
1823 return 0;
1824 }
1825
1826 static BOOL
1827 FileTypesDlg_AddExt(HWND hwndDlg, LPCWSTR pszExt, LPCWSTR pszFileType)
1828 {
1829 DWORD dwValue = 1;
1830 HKEY hKey;
1831 WCHAR szKey[13]; // max. "ft4294967295" + "\0"
1832 LONG nResult;
1833
1834 // Search the next "ft%06u" key name
1835 do
1836 {
1837 StringCchPrintfW(szKey, _countof(szKey), TEXT("ft%06u"), dwValue);
1838
1839 nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hKey);
1840 if (nResult != ERROR_SUCCESS)
1841 break;
1842
1843 RegCloseKey(hKey);
1844 ++dwValue;
1845 } while (dwValue != 0);
1846
1847 RegCloseKey(hKey);
1848
1849 if (dwValue == 0)
1850 return FALSE;
1851
1852 // Create new "ft%06u" key
1853 nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
1854 if (ERROR_SUCCESS != nResult)
1855 return FALSE;
1856
1857 RegCloseKey(hKey);
1858
1859 // Create the ".ext" key
1860 WCHAR szExt[16];
1861 if (*pszExt == L'.')
1862 ++pszExt;
1863 StringCchPrintfW(szExt, _countof(szExt), TEXT(".%s"), pszExt);
1864 CharLowerW(szExt);
1865 nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
1866 CharUpperW(szExt);
1867 if (ERROR_SUCCESS != nResult)
1868 return FALSE;
1869
1870 // Set the default value of ".ext" to "ft%06u"
1871 DWORD dwSize = (lstrlen(szKey) + 1) * sizeof(WCHAR);
1872 RegSetValueExW(hKey, NULL, 0, REG_SZ, (BYTE *)szKey, dwSize);
1873
1874 RegCloseKey(hKey);
1875
1876 // Make up the file type name
1877 WCHAR szFile[100], szFileFormat[100];
1878 LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFileFormat, _countof(szFileFormat));
1879 szFile[_countof(szFileFormat) - 1] = 0;
1880 StringCchPrintfW(szFile, _countof(szFile), szFileFormat, &szExt[1]);
1881
1882 // Insert an item to listview
1883 HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1884 INT iItem = ListView_GetItemCount(hListView);
1885 INT iItemCopy = iItem;
1886 InsertFileType(hListView, szExt, &iItemCopy, szFile);
1887
1888 LV_ITEM item;
1889 ZeroMemory(&item, sizeof(item));
1890 item.mask = LVIF_STATE | LVIF_TEXT;
1891 item.iItem = iItem;
1892 item.state = LVIS_SELECTED | LVIS_FOCUSED;
1893 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1894 item.pszText = &szExt[1];
1895 ListView_SetItem(hListView, &item);
1896
1897 item.pszText = szFile;
1898 item.iSubItem = 1;
1899 ListView_SetItem(hListView, &item);
1900
1901 ListView_EnsureVisible(hListView, iItem, FALSE);
1902
1903 return TRUE;
1904 }
1905
1906 static BOOL
1907 FileTypesDlg_RemoveExt(HWND hwndDlg)
1908 {
1909 HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1910
1911 INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
1912 if (iItem == -1)
1913 return FALSE;
1914
1915 WCHAR szExt[20];
1916 szExt[0] = L'.';
1917 ListView_GetItemText(hListView, iItem, 0, &szExt[1], _countof(szExt) - 1);
1918 CharLowerW(szExt);
1919
1920 if (DeleteExt(hwndDlg, szExt))
1921 {
1922 ListView_DeleteItem(hListView, iItem);
1923 return TRUE;
1924 }
1925 return FALSE;
1926 }
1927
1928 // IDD_FOLDER_OPTIONS_FILETYPES dialog
1929 INT_PTR
1930 CALLBACK
1931 FolderOptionsFileTypesDlg(
1932 HWND hwndDlg,
1933 UINT uMsg,
1934 WPARAM wParam,
1935 LPARAM lParam)
1936 {
1937 LPNMLISTVIEW lppl;
1938 LVITEMW lvItem;
1939 WCHAR Buffer[255], FormatBuffer[255];
1940 PFOLDER_FILE_TYPE_ENTRY pItem;
1941 OPENASINFO Info;
1942 NEWEXT_DIALOG newext;
1943
1944 switch(uMsg)
1945 {
1946 case WM_INITDIALOG:
1947 pItem = InitializeFileTypesListCtrl(hwndDlg);
1948
1949 /* Disable the Delete button if the listview is empty or
1950 the selected item should not be deleted by the user */
1951 if (pItem == NULL || (pItem->EditFlags & 0x00000010)) // FTA_NoRemove
1952 EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
1953 return TRUE;
1954
1955 case WM_COMMAND:
1956 switch(LOWORD(wParam))
1957 {
1958 case IDC_FILETYPES_NEW:
1959 newext.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1960 if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_NEWEXTENSION),
1961 hwndDlg, NewExtensionDlgProc, (LPARAM)&newext))
1962 {
1963 FileTypesDlg_AddExt(hwndDlg, newext.szExt, newext.szFileType);
1964 }
1965 break;
1966 case IDC_FILETYPES_DELETE:
1967 {
1968 CStringW strRemoveExt(MAKEINTRESOURCEW(IDS_REMOVE_EXT));
1969 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
1970 if (MessageBoxW(hwndDlg, strRemoveExt, strTitle, MB_ICONQUESTION | MB_YESNO) == IDYES)
1971 {
1972 FileTypesDlg_RemoveExt(hwndDlg);
1973 }
1974 }
1975 break;
1976 case IDC_FILETYPES_CHANGE:
1977 pItem = FindSelectedItem(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
1978 if (pItem)
1979 {
1980 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT;
1981 Info.pcszClass = pItem->FileExtension;
1982 SHOpenWithDialog(hwndDlg, &Info);
1983 }
1984 break;
1985 }
1986 break;
1987
1988 case WM_NOTIFY:
1989 lppl = (LPNMLISTVIEW) lParam;
1990
1991 if (lppl->hdr.code == LVN_ITEMCHANGING)
1992 {
1993 ZeroMemory(&lvItem, sizeof(LVITEM));
1994 lvItem.mask = LVIF_PARAM;
1995 lvItem.iItem = lppl->iItem;
1996 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&lvItem))
1997 return TRUE;
1998
1999 pItem = (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
2000 if (!pItem)
2001 return TRUE;
2002
2003 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
2004 {
2005 /* new focused item */
2006 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILS, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
2007 {
2008 /* use default english format string */
2009 wcscpy(FormatBuffer, L"Details for '%s' extension");
2010 }
2011
2012 /* format buffer */
2013 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1]);
2014 /* update dialog */
2015 SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DETAILS_GROUPBOX, Buffer);
2016
2017 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILSADV, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
2018 {
2019 /* use default english format string */
2020 wcscpy(FormatBuffer, L"Files with extension '%s' are of type '%s'. To change settings that affect all '%s' files, click Advanced.");
2021 }
2022 /* format buffer */
2023 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1], &pItem->FileDescription[0], &pItem->FileDescription[0]);
2024 /* update dialog */
2025 SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DESCRIPTION, Buffer);
2026
2027 /* Enable the Delete button */
2028 if (pItem->EditFlags & 0x00000010) // FTA_NoRemove
2029 EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
2030 else
2031 EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), TRUE);
2032 }
2033 }
2034 else if (lppl->hdr.code == PSN_SETACTIVE)
2035 {
2036 /* On page activation, set the focus to the listview */
2037 SetFocus(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
2038 }
2039 break;
2040 }
2041
2042 return FALSE;
2043 }
2044
2045 static
2046 VOID
2047 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst)
2048 {
2049 PROPSHEETHEADERW pinfo;
2050 HPROPSHEETPAGE hppages[3];
2051 HPROPSHEETPAGE hpage;
2052 UINT num_pages = 0;
2053 WCHAR szOptions[100];
2054
2055 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL);
2056 if (hpage)
2057 hppages[num_pages++] = hpage;
2058
2059 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL);
2060 if (hpage)
2061 hppages[num_pages++] = hpage;
2062
2063 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL);
2064 if (hpage)
2065 hppages[num_pages++] = hpage;
2066
2067 szOptions[0] = L'\0';
2068 LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR));
2069 szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0';
2070
2071 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
2072 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
2073 pinfo.dwFlags = PSH_NOCONTEXTHELP;
2074 pinfo.nPages = num_pages;
2075 pinfo.phpage = hppages;
2076 pinfo.pszCaption = szOptions;
2077
2078 PropertySheetW(&pinfo);
2079 }
2080
2081 static
2082 VOID
2083 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow)
2084 {
2085 switch(fOptions)
2086 {
2087 case 0:
2088 ShowFolderOptionsDialog(hWnd, hInst);
2089 break;
2090 case 1:
2091 // show taskbar options dialog
2092 FIXME("notify explorer to show taskbar options dialog");
2093 //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0);
2094 break;
2095 default:
2096 FIXME("unrecognized options id %d\n", fOptions);
2097 }
2098 }
2099
2100 /*************************************************************************
2101 * Options_RunDLL (SHELL32.@)
2102 */
2103 EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
2104 {
2105 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
2106 }
2107
2108 /*************************************************************************
2109 * Options_RunDLLA (SHELL32.@)
2110 */
2111 EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
2112 {
2113 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
2114 }
2115
2116 /*************************************************************************
2117 * Options_RunDLLW (SHELL32.@)
2118 */
2119 EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
2120 {
2121 Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow);
2122 }