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     WCHAR ClassName[64];
40     DWORD EditFlags;
41     WCHAR AppName[64];
42     HICON hIconLarge;
43     HICON hIconSmall;
44     WCHAR ProgramPath[MAX_PATH];
45     WCHAR IconPath[MAX_PATH];
46     INT nIconIndex;
47 } FOLDER_FILE_TYPE_ENTRY, *PFOLDER_FILE_TYPE_ENTRY;
48 
49 // uniquely-defined icon entry for Advanced Settings
50 typedef struct ADVANCED_ICON
51 {
52     WCHAR   szPath[MAX_PATH];
53     UINT    nIconIndex;
54 } ADVANCED_ICON;
55 
56 // predefined icon IDs (See CreateTreeImageList function below)
57 #define I_CHECKED                   0
58 #define I_UNCHECKED                 1
59 #define I_CHECKED_DISABLED          2
60 #define I_UNCHECKED_DISABLED        3
61 #define I_RADIO_CHECKED             4
62 #define I_RADIO_UNCHECKED           5
63 #define I_RADIO_CHECKED_DISABLED    6
64 #define I_RADIO_UNCHECKED_DISABLED  7
65 
66 #define PREDEFINED_ICON_COUNT       8
67 
68 // definition of icon stock
69 static ADVANCED_ICON *  s_AdvancedIcons         = NULL;
70 static INT              s_AdvancedIconCount     = 0;
71 static HIMAGELIST       s_hImageList            = NULL;
72 
73 static INT
74 Advanced_FindIcon(LPCWSTR pszPath, UINT nIconIndex)
75 {
76     for (INT i = PREDEFINED_ICON_COUNT; i < s_AdvancedIconCount; ++i)
77     {
78         ADVANCED_ICON *pIcon = &s_AdvancedIcons[i];
79         if (pIcon->nIconIndex == nIconIndex &&
80             lstrcmpiW(pIcon->szPath, pszPath) == 0)
81         {
82             return i;   // icon ID
83         }
84     }
85     return -1;  // not found
86 }
87 
88 static INT
89 Advanced_AddIcon(LPCWSTR pszPath, UINT nIconIndex)
90 {
91     ADVANCED_ICON *pAllocated;
92 
93     // return the ID if already existed
94     INT nIconID = Advanced_FindIcon(pszPath, nIconIndex);
95     if (nIconID != -1)
96         return nIconID;     // already exists
97 
98     // extract a small icon
99     HICON hIconSmall = NULL;
100     ExtractIconExW(pszPath, nIconIndex, NULL, &hIconSmall, 1);
101     if (hIconSmall == NULL)
102         return -1;      // failure
103 
104     // resize s_AdvancedIcons
105     size_t Size = (s_AdvancedIconCount + 1) * sizeof(ADVANCED_ICON);
106     pAllocated = (ADVANCED_ICON *)realloc(s_AdvancedIcons, Size);
107     if (pAllocated == NULL)
108         return -1;      // failure
109     else
110         s_AdvancedIcons = pAllocated;
111 
112     // save icon information
113     ADVANCED_ICON *pIcon = &s_AdvancedIcons[s_AdvancedIconCount];
114     lstrcpynW(pIcon->szPath, pszPath, _countof(pIcon->szPath));
115     pIcon->nIconIndex = nIconIndex;
116 
117     // add the icon to the image list
118     ImageList_AddIcon(s_hImageList, hIconSmall);
119 
120     // increment the counter
121     nIconID = s_AdvancedIconCount;
122     ++s_AdvancedIconCount;
123 
124     DestroyIcon(hIconSmall);
125 
126     return nIconID;     // newly-added icon ID
127 }
128 
129 // types of Advanced Setting entry
130 typedef enum ADVANCED_ENTRY_TYPE
131 {
132     AETYPE_GROUP,
133     AETYPE_CHECKBOX,
134     AETYPE_RADIO,
135 } ADVANCED_ENTRY_TYPE;
136 
137 // an entry info of Advanced Settings
138 typedef struct ADVANCED_ENTRY
139 {
140     DWORD   dwID;                   // entry ID
141     DWORD   dwParentID;             // parent entry ID
142     DWORD   dwResourceID;           // resource ID
143     WCHAR   szKeyName[64];          // entry key name
144     DWORD   dwType;                 // ADVANCED_ENTRY_TYPE
145     WCHAR   szText[MAX_PATH];       // text
146     INT     nIconID;                // icon ID (See ADVANCED_ICON)
147 
148     HKEY    hkeyRoot;               // registry root key
149     WCHAR   szRegPath[MAX_PATH];    // registry path
150     WCHAR   szValueName[64];        // registry value name
151 
152     DWORD   dwCheckedValue;         // checked value
153     DWORD   dwUncheckedValue;       // unchecked value
154     DWORD   dwDefaultValue;         // defalut value
155     BOOL    bHasUncheckedValue;     // If FALSE, UncheckedValue is invalid
156 
157     HTREEITEM   hItem;              // for TreeView
158     BOOL        bGrayed;            // disabled?
159     BOOL        bChecked;           // checked?
160 } ADVANCED_ENTRY, *PADVANCED_ENTRY;
161 
162 // definition of advanced entries
163 static ADVANCED_ENTRY *     s_Advanced = NULL;
164 static INT                  s_AdvancedCount = 0;
165 
166 static HBITMAP
167 Create24BppBitmap(HDC hDC, INT cx, INT cy)
168 {
169     BITMAPINFO bi;
170     LPVOID pvBits;
171 
172     ZeroMemory(&bi, sizeof(bi));
173     bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
174     bi.bmiHeader.biWidth = cx;
175     bi.bmiHeader.biHeight = cy;
176     bi.bmiHeader.biPlanes = 1;
177     bi.bmiHeader.biBitCount = 24;
178     bi.bmiHeader.biCompression = BI_RGB;
179 
180     HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0);
181     return hbm;
182 }
183 
184 static HBITMAP BitmapFromIcon(HICON hIcon, INT cx, INT cy)
185 {
186     HDC hDC = CreateCompatibleDC(NULL);
187     if (!hDC)
188         return NULL;
189 
190     HBITMAP hbm = Create24BppBitmap(hDC, cx, cy);
191     if (!hbm)
192     {
193         DeleteDC(hDC);
194         return NULL;
195     }
196 
197     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
198     {
199         RECT rc = { 0, 0, cx, cy };
200         FillRect(hDC, &rc, HBRUSH(COLOR_3DFACE + 1));
201         if (hIcon)
202         {
203             DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);
204         }
205     }
206     SelectObject(hDC, hbmOld);
207     DeleteDC(hDC);
208 
209     return hbm;
210 }
211 
212 static HBITMAP
213 CreateCheckImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE)
214 {
215     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
216     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
217 
218     HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon);
219     if (hbm == NULL)
220         return NULL;    // failure
221 
222     RECT Rect, BoxRect;
223     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
224     BoxRect = Rect;
225     InflateRect(&BoxRect, -1, -1);
226 
227     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
228     {
229         UINT uState = DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_MONO;
230         if (bCheck)
231             uState |= DFCS_CHECKED;
232         if (!bEnabled)
233             uState |= DFCS_INACTIVE;
234         DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
235     }
236     SelectObject(hDC, hbmOld);
237 
238     return hbm;     // success
239 }
240 
241 static HBITMAP
242 CreateCheckMask(HDC hDC)
243 {
244     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
245     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
246 
247     HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL);
248     if (hbm == NULL)
249         return NULL;    // failure
250 
251     RECT Rect, BoxRect;
252     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
253     BoxRect = Rect;
254     InflateRect(&BoxRect, -1, -1);
255 
256     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
257     {
258         FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH)));
259         FillRect(hDC, &BoxRect, HBRUSH(GetStockObject(BLACK_BRUSH)));
260     }
261     SelectObject(hDC, hbmOld);
262 
263     return hbm;     // success
264 }
265 
266 static HBITMAP
267 CreateRadioImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE)
268 {
269     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
270     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
271 
272     HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon);
273     if (hbm == NULL)
274         return NULL;    // failure
275 
276     RECT Rect, BoxRect;
277     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
278     BoxRect = Rect;
279     InflateRect(&BoxRect, -1, -1);
280 
281     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
282     {
283         UINT uState = DFCS_BUTTONRADIOIMAGE | DFCS_FLAT | DFCS_MONO;
284         if (bCheck)
285             uState |= DFCS_CHECKED;
286         if (!bEnabled)
287             uState |= DFCS_INACTIVE;
288         DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
289     }
290     SelectObject(hDC, hbmOld);
291 
292     return hbm;     // success
293 }
294 
295 static HBITMAP
296 CreateRadioMask(HDC hDC)
297 {
298     INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON);
299     INT cySmallIcon = GetSystemMetrics(SM_CYSMICON);
300 
301     HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL);
302     if (hbm == NULL)
303         return NULL;    // failure
304 
305     RECT Rect, BoxRect;
306     SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon);
307     BoxRect = Rect;
308     InflateRect(&BoxRect, -1, -1);
309 
310     HGDIOBJ hbmOld = SelectObject(hDC, hbm);
311     {
312         FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH)));
313         UINT uState = DFCS_BUTTONRADIOMASK | DFCS_FLAT | DFCS_MONO;
314         DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState);
315     }
316     SelectObject(hDC, hbmOld);
317 
318     return hbm;     // success
319 }
320 
321 static HIMAGELIST
322 CreateTreeImageList(VOID)
323 {
324     HIMAGELIST hImageList;
325     hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 9, 1);
326     if (hImageList == NULL)
327         return NULL;    // failure
328 
329     // free if existed
330     if (s_AdvancedIcons)
331     {
332         free(s_AdvancedIcons);
333         s_AdvancedIcons = NULL;
334     }
335     s_AdvancedIconCount = 0;
336 
337     // allocate now
338     ADVANCED_ICON *pAllocated;
339     size_t Size = PREDEFINED_ICON_COUNT * sizeof(ADVANCED_ICON);
340     pAllocated = (ADVANCED_ICON *)calloc(1, Size);
341     if (pAllocated == NULL)
342         return NULL;    // failure
343 
344     s_AdvancedIconCount = PREDEFINED_ICON_COUNT;
345     s_AdvancedIcons = pAllocated;
346 
347     // add the predefined icons
348 
349     HDC hDC = CreateCompatibleDC(NULL);
350     HBITMAP hbmMask = CreateCheckMask(hDC);
351 
352     HBITMAP hbmChecked, hbmUnchecked;
353 
354     hbmChecked = CreateCheckImage(hDC, TRUE);
355     ImageList_Add(hImageList, hbmChecked, hbmMask);
356     DeleteObject(hbmChecked);
357 
358     hbmUnchecked = CreateCheckImage(hDC, FALSE);
359     ImageList_Add(hImageList, hbmUnchecked, hbmMask);
360     DeleteObject(hbmUnchecked);
361 
362     hbmChecked = CreateCheckImage(hDC, TRUE, FALSE);
363     ImageList_Add(hImageList, hbmChecked, hbmMask);
364     DeleteObject(hbmChecked);
365 
366     hbmUnchecked = CreateCheckImage(hDC, FALSE, FALSE);
367     ImageList_Add(hImageList, hbmUnchecked, hbmMask);
368     DeleteObject(hbmUnchecked);
369 
370     DeleteObject(hbmMask);
371     hbmMask = CreateRadioMask(hDC);
372 
373     hbmChecked = CreateRadioImage(hDC, TRUE);
374     ImageList_Add(hImageList, hbmChecked, hbmMask);
375     DeleteObject(hbmChecked);
376 
377     hbmUnchecked = CreateRadioImage(hDC, FALSE);
378     ImageList_Add(hImageList, hbmUnchecked, hbmMask);
379     DeleteObject(hbmUnchecked);
380 
381     hbmChecked = CreateRadioImage(hDC, TRUE, FALSE);
382     ImageList_Add(hImageList, hbmChecked, hbmMask);
383     DeleteObject(hbmChecked);
384 
385     hbmUnchecked = CreateRadioImage(hDC, FALSE, FALSE);
386     ImageList_Add(hImageList, hbmUnchecked, hbmMask);
387     DeleteObject(hbmUnchecked);
388 
389     DeleteObject(hbmMask);
390 
391     return hImageList;
392 }
393 
394 static ADVANCED_ENTRY *
395 Advanced_GetItem(DWORD dwID)
396 {
397     if (dwID == DWORD(-1))
398         return NULL;
399 
400     for (INT i = 0; i < s_AdvancedCount; ++i)
401     {
402         ADVANCED_ENTRY *pEntry = &s_Advanced[i];
403         if (pEntry->dwID == dwID)
404             return pEntry;
405     }
406     return NULL;    // failure
407 }
408 
409 static INT
410 Advanced_GetImage(ADVANCED_ENTRY *pEntry)
411 {
412     switch (pEntry->dwType)
413     {
414         case AETYPE_GROUP:
415             return pEntry->nIconID;
416 
417         case AETYPE_CHECKBOX:
418             if (pEntry->bGrayed)
419             {
420                 if (pEntry->bChecked)
421                     return I_CHECKED_DISABLED;
422                 else
423                     return I_UNCHECKED_DISABLED;
424             }
425             else
426             {
427                 if (pEntry->bChecked)
428                     return I_CHECKED;
429                 else
430                     return I_UNCHECKED;
431             }
432 
433         case AETYPE_RADIO:
434             if (pEntry->bGrayed)
435             {
436                 if (pEntry->bChecked)
437                     return I_RADIO_CHECKED_DISABLED;
438                 else
439                     return I_RADIO_UNCHECKED_DISABLED;
440             }
441             else
442             {
443                 if (pEntry->bChecked)
444                     return I_RADIO_CHECKED;
445                 else
446                     return I_RADIO_UNCHECKED;
447             }
448     }
449     return -1;  // failure
450 }
451 
452 static VOID
453 Advanced_InsertEntry(HWND hwndTreeView, ADVANCED_ENTRY *pEntry)
454 {
455     ADVANCED_ENTRY *pParent = Advanced_GetItem(pEntry->dwParentID);
456     HTREEITEM hParent = TVI_ROOT;
457     if (pParent)
458         hParent = pParent->hItem;
459 
460     TV_INSERTSTRUCT Insertion;
461     ZeroMemory(&Insertion, sizeof(Insertion));
462     Insertion.hParent = hParent;
463     Insertion.hInsertAfter = TVI_LAST;
464     Insertion.item.mask =
465         TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
466     Insertion.item.pszText = pEntry->szText;
467 
468     INT iImage = Advanced_GetImage(pEntry);
469     Insertion.item.iImage = Insertion.item.iSelectedImage = iImage;
470     Insertion.item.lParam = pEntry->dwID;
471     pEntry->hItem = TreeView_InsertItem(hwndTreeView, &Insertion);
472 }
473 
474 static VOID
475 Advanced_InsertAll(HWND hwndTreeView)
476 {
477     TreeView_DeleteAllItems(hwndTreeView);
478 
479     // insert the entries
480     ADVANCED_ENTRY *pEntry;
481     for (INT i = 0; i < s_AdvancedCount; ++i)
482     {
483         pEntry = &s_Advanced[i];
484         Advanced_InsertEntry(hwndTreeView, pEntry);
485     }
486 
487     // expand all
488     for (INT i = 0; i < s_AdvancedCount; ++i)
489     {
490         pEntry = &s_Advanced[i];
491         if (pEntry->dwType == AETYPE_GROUP)
492         {
493             TreeView_Expand(hwndTreeView, pEntry->hItem, TVE_EXPAND);
494         }
495     }
496 }
497 
498 static BOOL
499 Advanced_LoadTree(HKEY hKey, LPCWSTR pszKeyName, DWORD dwParentID)
500 {
501     DWORD dwIndex;
502     WCHAR szKeyName[64], szText[MAX_PATH], *pch;
503     DWORD Size, Value;
504     ADVANCED_ENTRY *pAllocated;
505 
506     // resize s_Advanced
507     Size = (s_AdvancedCount + 1) * sizeof(ADVANCED_ENTRY);
508     pAllocated = (ADVANCED_ENTRY *)realloc(s_Advanced, Size);
509     if (pAllocated == NULL)
510         return FALSE;   // failure
511     else
512         s_Advanced = pAllocated;
513 
514     ADVANCED_ENTRY *pEntry = &s_Advanced[s_AdvancedCount];
515 
516     // dwID, dwParentID, szKeyName
517     pEntry->dwID = s_AdvancedCount;
518     pEntry->dwParentID = dwParentID;
519     lstrcpynW(pEntry->szKeyName, pszKeyName, _countof(pEntry->szKeyName));
520 
521     // Text, ResourceID
522     pEntry->szText[0] = 0;
523     pEntry->dwResourceID = 0;
524     szText[0] = 0;
525     Size = sizeof(szText);
526     RegQueryValueExW(hKey, L"Text", NULL, NULL, LPBYTE(szText), &Size);
527     if (szText[0] == L'@')
528     {
529         pch = wcsrchr(szText, L',');
530         if (pch)
531         {
532             *pch = 0;
533             dwIndex = abs(_wtoi(pch + 1));
534             pEntry->dwResourceID = dwIndex;
535         }
536         HINSTANCE hInst = LoadLibraryW(&szText[1]);
537         LoadStringW(hInst, dwIndex, szText, _countof(szText));
538         FreeLibrary(hInst);
539     }
540     else
541     {
542         pEntry->dwResourceID = DWORD(-1);
543     }
544     lstrcpynW(pEntry->szText, szText, _countof(pEntry->szText));
545 
546     // Type
547     szText[0] = 0;
548     RegQueryValueExW(hKey, L"Type", NULL, NULL, LPBYTE(szText), &Size);
549     if (lstrcmpiW(szText, L"checkbox") == 0)
550         pEntry->dwType = AETYPE_CHECKBOX;
551     else if (lstrcmpiW(szText, L"radio") == 0)
552         pEntry->dwType = AETYPE_RADIO;
553     else if (lstrcmpiW(szText, L"group") == 0)
554         pEntry->dwType = AETYPE_GROUP;
555     else
556         return FALSE;   // failure
557 
558     pEntry->nIconID = -1;
559     if (pEntry->dwType == AETYPE_GROUP)
560     {
561         // Bitmap (Icon)
562         UINT nIconIndex = 0;
563         Size = sizeof(szText);
564         szText[0] = 0;
565         RegQueryValueExW(hKey, L"Bitmap", NULL, NULL, LPBYTE(szText), &Size);
566 
567         WCHAR szExpanded[MAX_PATH];
568         ExpandEnvironmentStringsW(szText, szExpanded, _countof(szExpanded));
569         pch = wcsrchr(szExpanded, L',');
570         if (pch)
571         {
572             *pch = 0;
573             nIconIndex = abs(_wtoi(pch + 1));
574         }
575         pEntry->nIconID = Advanced_AddIcon(szExpanded, nIconIndex);
576     }
577 
578     if (pEntry->dwType == AETYPE_GROUP)
579     {
580         pEntry->hkeyRoot = NULL;
581         pEntry->szRegPath[0] = 0;
582         pEntry->szValueName[0] = 0;
583         pEntry->dwCheckedValue = 0;
584         pEntry->bHasUncheckedValue = FALSE;
585         pEntry->dwUncheckedValue = 0;
586         pEntry->dwDefaultValue = 0;
587         pEntry->hItem = NULL;
588         pEntry->bGrayed = FALSE;
589         pEntry->bChecked = FALSE;
590     }
591     else
592     {
593         // HKeyRoot
594         Value = DWORD(HKEY_CURRENT_USER);
595         Size = sizeof(Value);
596         RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&Value), &Size);
597         pEntry->hkeyRoot = HKEY(Value);
598 
599         // RegPath
600         pEntry->szRegPath[0] = 0;
601         Size = sizeof(szText);
602         RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size);
603         lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath));
604 
605         // ValueName
606         pEntry->szValueName[0] = 0;
607         Size = sizeof(szText);
608         RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size);
609         lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName));
610 
611         // CheckedValue
612         Size = sizeof(Value);
613         Value = 0x00000001;
614         RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size);
615         pEntry->dwCheckedValue = Value;
616 
617         // UncheckedValue
618         Size = sizeof(Value);
619         Value = 0x00000000;
620         pEntry->bHasUncheckedValue = TRUE;
621         if (RegQueryValueExW(hKey, L"UncheckedValue", NULL,
622                              NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS)
623         {
624             pEntry->bHasUncheckedValue = FALSE;
625         }
626         pEntry->dwUncheckedValue = Value;
627 
628         // DefaultValue
629         Size = sizeof(Value);
630         Value = 0x00000001;
631         RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size);
632         pEntry->dwDefaultValue = Value;
633 
634         // hItem
635         pEntry->hItem = NULL;
636 
637         // bGrayed, bChecked
638         HKEY hkeyTarget;
639         Value = pEntry->dwDefaultValue;
640         pEntry->bGrayed = TRUE;
641         if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0,
642                           KEY_READ, &hkeyTarget) == ERROR_SUCCESS)
643         {
644             Size = sizeof(Value);
645             if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL,
646                                  LPBYTE(&Value), &Size) == ERROR_SUCCESS)
647             {
648                 pEntry->bGrayed = FALSE;
649             }
650             RegCloseKey(hkeyTarget);
651         }
652         pEntry->bChecked = (Value == pEntry->dwCheckedValue);
653     }
654 
655     // Grayed (ReactOS extension)
656     Size = sizeof(Value);
657     Value = FALSE;
658     RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size);
659     if (!pEntry->bGrayed)
660         pEntry->bGrayed = Value;
661 
662     BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP);
663     dwParentID = pEntry->dwID;
664     ++s_AdvancedCount;
665 
666     if (!bIsGroup)
667         return TRUE;    // success
668 
669     // load the children
670     dwIndex = 0;
671     while (RegEnumKeyW(hKey, dwIndex, szKeyName,
672                        _countof(szKeyName)) == ERROR_SUCCESS)
673     {
674         HKEY hkeyChild;
675         if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ,
676                           &hkeyChild) != ERROR_SUCCESS)
677         {
678             ++dwIndex;
679             continue;   // failure
680         }
681 
682         Advanced_LoadTree(hkeyChild, szKeyName, dwParentID);
683         RegCloseKey(hkeyChild);
684 
685         ++dwIndex;
686     }
687 
688     return TRUE;    // success
689 }
690 
691 static BOOL
692 Advanced_LoadAll(VOID)
693 {
694     static const WCHAR s_szAdvanced[] =
695         L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
696 
697     // free if already existed
698     if (s_Advanced)
699     {
700         free(s_Advanced);
701         s_Advanced = NULL;
702     }
703     s_AdvancedCount = 0;
704 
705     HKEY hKey;
706     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szAdvanced, 0,
707                       KEY_READ, &hKey) != ERROR_SUCCESS)
708     {
709         return FALSE;   // failure
710     }
711 
712     // load the children
713     WCHAR szKeyName[64];
714     DWORD dwIndex = 0;
715     while (RegEnumKeyW(hKey, dwIndex, szKeyName,
716                        _countof(szKeyName)) == ERROR_SUCCESS)
717     {
718         HKEY hkeyChild;
719         if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ,
720                           &hkeyChild) != ERROR_SUCCESS)
721         {
722             ++dwIndex;
723             continue;   // failure
724         }
725 
726         Advanced_LoadTree(hkeyChild, szKeyName, DWORD(-1));
727         RegCloseKey(hkeyChild);
728 
729         ++dwIndex;
730     }
731 
732     RegCloseKey(hKey);
733 
734     return TRUE;    // success
735 }
736 
737 static int
738 Advanced_Compare(const void *x, const void *y)
739 {
740     ADVANCED_ENTRY *pEntry1 = (ADVANCED_ENTRY *)x;
741     ADVANCED_ENTRY *pEntry2 = (ADVANCED_ENTRY *)y;
742 
743     DWORD dwParentID1 = pEntry1->dwParentID;
744     DWORD dwParentID2 = pEntry2->dwParentID;
745 
746     if (dwParentID1 == dwParentID2)
747         return lstrcmpi(pEntry1->szText, pEntry2->szText);
748 
749     DWORD i, m, n;
750     const UINT MAX_DEPTH = 32;
751     ADVANCED_ENTRY *pArray1[MAX_DEPTH];
752     ADVANCED_ENTRY *pArray2[MAX_DEPTH];
753 
754     // Make ancestor lists
755     for (i = m = n = 0; i < MAX_DEPTH; ++i)
756     {
757         ADVANCED_ENTRY *pParent1 = Advanced_GetItem(dwParentID1);
758         ADVANCED_ENTRY *pParent2 = Advanced_GetItem(dwParentID2);
759         if (!pParent1 && !pParent2)
760             break;
761 
762         if (pParent1)
763         {
764             pArray1[m++] = pParent1;
765             dwParentID1 = pParent1->dwParentID;
766         }
767         if (pParent2)
768         {
769             pArray2[n++] = pParent2;
770             dwParentID2 = pParent2->dwParentID;
771         }
772     }
773 
774     UINT k = min(m, n);
775     for (i = 0; i < k; ++i)
776     {
777         INT nCompare = lstrcmpi(pArray1[m - i - 1]->szText, pArray2[n - i - 1]->szText);
778         if (nCompare < 0)
779             return -1;
780         if (nCompare > 0)
781             return 1;
782     }
783 
784     if (m < n)
785         return -1;
786     if (m > n)
787         return 1;
788     return lstrcmpi(pEntry1->szText, pEntry2->szText);
789 }
790 
791 static VOID
792 Advanced_SortAll(VOID)
793 {
794     qsort(s_Advanced, s_AdvancedCount, sizeof(ADVANCED_ENTRY), Advanced_Compare);
795 }
796 
797 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
798 
799 static VOID
800 UpdateGeneralIcons(HWND hDlg)
801 {
802     HWND hwndTaskIcon, hwndFolderIcon, hwndClickIcon;
803     HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL;
804     LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL;
805 
806     // show task setting icon
807     if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED)
808         lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS);
809     else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED)
810         lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS);
811 
812     if (lpTaskIconName)
813     {
814         hTaskIcon = (HICON)LoadImage(shell32_hInstance,
815                                               lpTaskIconName,
816                                               IMAGE_ICON,
817                                               0,
818                                               0,
819                                               LR_DEFAULTCOLOR);
820         if (hTaskIcon)
821         {
822             hwndTaskIcon = GetDlgItem(hDlg,
823                                     IDC_FOLDER_OPTIONS_TASKICON);
824             if (hwndTaskIcon)
825             {
826                 SendMessage(hwndTaskIcon,
827                             STM_SETIMAGE,
828                             IMAGE_ICON,
829                             (LPARAM)hTaskIcon);
830             }
831         }
832     }
833 
834     // show Folder setting icons
835     if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED)
836         lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW);
837     else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED)
838         lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW);
839 
840     if (lpFolderIconName)
841     {
842         hFolderIcon = (HICON)LoadImage(shell32_hInstance,
843                                               lpFolderIconName,
844                                               IMAGE_ICON,
845                                               0,
846                                               0,
847                                               LR_DEFAULTCOLOR);
848         if (hFolderIcon)
849         {
850             hwndFolderIcon = GetDlgItem(hDlg,
851                                     IDC_FOLDER_OPTIONS_FOLDERICON);
852             if (hwndFolderIcon)
853             {
854                 SendMessage(hwndFolderIcon,
855                             STM_SETIMAGE,
856                             IMAGE_ICON,
857                             (LPARAM)hFolderIcon);
858             }
859         }
860     }
861 
862     // Show click setting icon
863     if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED)
864         lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN);
865     else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED)
866         lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN);
867 
868     if (lpClickIconName)
869     {
870         hClickIcon = (HICON)LoadImage(shell32_hInstance,
871                                               lpClickIconName,
872                                               IMAGE_ICON,
873                                               0,
874                                               0,
875                                               LR_DEFAULTCOLOR);
876         if (hClickIcon)
877         {
878             hwndClickIcon = GetDlgItem(hDlg,
879                                     IDC_FOLDER_OPTIONS_CLICKICON);
880             if (hwndClickIcon)
881             {
882                 SendMessage(hwndClickIcon,
883                             STM_SETIMAGE,
884                             IMAGE_ICON,
885                             (LPARAM)hClickIcon);
886             }
887         }
888     }
889 
890     // Clean up
891     if(hTaskIcon)
892         DeleteObject(hTaskIcon);
893     if(hFolderIcon)
894         DeleteObject(hFolderIcon);
895     if(hClickIcon)
896         DeleteObject(hClickIcon);
897 
898     return;
899 }
900 
901 INT_PTR
902 CALLBACK
903 FolderOptionsGeneralDlg(
904     HWND hwndDlg,
905     UINT uMsg,
906     WPARAM wParam,
907     LPARAM lParam
908 )
909 {
910     switch(uMsg)
911     {
912         case WM_INITDIALOG:
913             // FIXME
914             break;
915 
916         case WM_COMMAND:
917             switch (LOWORD(wParam))
918             {
919                 case IDC_FOLDER_OPTIONS_COMMONTASKS:
920                 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS:
921                 case IDC_FOLDER_OPTIONS_SAMEWINDOW:
922                 case IDC_FOLDER_OPTIONS_OWNWINDOW:
923                 case IDC_FOLDER_OPTIONS_SINGLECLICK:
924                 case IDC_FOLDER_OPTIONS_DOUBLECLICK:
925                     if (HIWORD(wParam) == BN_CLICKED)
926                     {
927                         UpdateGeneralIcons(hwndDlg);
928 
929                         /* Enable the 'Apply' button */
930                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
931                     }
932                     break;
933             }
934             break;
935 
936         case WM_NOTIFY:
937         {
938             LPNMHDR pnmh = (LPNMHDR)lParam;
939 
940             switch (pnmh->code)
941             {
942                 case PSN_SETACTIVE:
943                     break;
944 
945                 case PSN_APPLY:
946                     break;
947             }
948             break;
949         }
950 
951         case WM_DESTROY:
952             break;
953 
954          default:
955              return FALSE;
956     }
957     return FALSE;
958 }
959 
960 static BOOL
961 ViewDlg_OnInitDialog(HWND hwndDlg)
962 {
963     HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
964 
965     s_hImageList = CreateTreeImageList();
966     TreeView_SetImageList(hwndTreeView, s_hImageList, TVSIL_NORMAL);
967 
968     Advanced_LoadAll();
969     Advanced_SortAll();
970     Advanced_InsertAll(hwndTreeView);
971 
972     return TRUE;    // set focus
973 }
974 
975 static BOOL
976 ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem)
977 {
978     HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
979 
980     // get the item
981     TV_ITEM Item;
982     INT i;
983     ZeroMemory(&Item, sizeof(Item));
984     Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM;
985     Item.hItem = hItem;
986     if (!TreeView_GetItem(hwndTreeView, &Item))
987         return FALSE;       // no such item
988 
989     ADVANCED_ENTRY *pEntry = Advanced_GetItem(Item.lParam);
990     if (pEntry == NULL)
991         return FALSE;       // no such item
992     if (pEntry->bGrayed)
993         return FALSE;       // disabled
994 
995     // toggle check mark
996     Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
997     switch (pEntry->dwType)
998     {
999         case AETYPE_CHECKBOX:
1000             pEntry->bChecked = !pEntry->bChecked;
1001             break;
1002 
1003         case AETYPE_RADIO:
1004             // reset all the entries of the same parent
1005             for (i = 0; i < s_AdvancedCount; ++i)
1006             {
1007                 ADVANCED_ENTRY *pEntry2 = &s_Advanced[i];
1008                 if (pEntry->dwParentID == pEntry2->dwParentID)
1009                 {
1010                     pEntry2->bChecked = FALSE;
1011 
1012                     Item.hItem = pEntry2->hItem;
1013                     INT iImage = Advanced_GetImage(pEntry2);
1014                     Item.iImage = Item.iSelectedImage = iImage;
1015                     TreeView_SetItem(hwndTreeView, &Item);
1016                 }
1017             }
1018             pEntry->bChecked = TRUE;
1019             break;
1020 
1021         default:
1022             return FALSE;   // failure
1023     }
1024     Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry);
1025     Item.hItem = hItem;
1026     TreeView_SetItem(hwndTreeView, &Item);
1027 
1028     // redraw the item
1029     RECT rcItem;
1030     TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE);
1031     InvalidateRect(hwndTreeView, &rcItem, TRUE);
1032     return TRUE;    // success
1033 }
1034 
1035 static VOID
1036 ViewDlg_OnTreeViewClick(HWND hwndDlg)
1037 {
1038     HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
1039 
1040     // do hit test to get the clicked item
1041     TV_HITTESTINFO HitTest;
1042     ZeroMemory(&HitTest, sizeof(HitTest));
1043     DWORD dwPos = GetMessagePos();
1044     HitTest.pt.x = LOWORD(dwPos);
1045     HitTest.pt.y = HIWORD(dwPos);
1046     ScreenToClient(hwndTreeView, &HitTest.pt);
1047     HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest);
1048 
1049     // toggle the check mark if possible
1050     if (ViewDlg_ToggleCheckItem(hwndDlg, hItem))
1051     {
1052         // property sheet was changed
1053         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1054     }
1055 }
1056 
1057 static void
1058 ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown)
1059 {
1060     HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
1061 
1062     if (KeyDown->wVKey == VK_SPACE)
1063     {
1064         // [Space] key was pressed
1065         HTREEITEM hItem = TreeView_GetSelection(hwndTreeView);
1066         if (ViewDlg_ToggleCheckItem(hwndDlg, hItem))
1067         {
1068             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1069         }
1070     }
1071 }
1072 
1073 static INT_PTR
1074 ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw)
1075 {
1076     NMCUSTOMDRAW& nmcd = Draw->nmcd;
1077     switch (nmcd.dwDrawStage)
1078     {
1079         case CDDS_PREPAINT:
1080             return CDRF_NOTIFYITEMDRAW;     // for CDDS_ITEMPREPAINT
1081 
1082         case CDDS_ITEMPREPAINT:
1083             if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected
1084             {
1085                 LPARAM lParam = nmcd.lItemlParam;
1086                 ADVANCED_ENTRY *pEntry = Advanced_GetItem(lParam);
1087                 if (pEntry && pEntry->bGrayed) // disabled
1088                 {
1089                     // draw as grayed
1090                     Draw->clrText = GetSysColor(COLOR_GRAYTEXT);
1091                     Draw->clrTextBk = GetSysColor(COLOR_WINDOW);
1092                     return CDRF_NEWFONT;
1093                 }
1094             }
1095             break;
1096 
1097         default:
1098             break;
1099     }
1100     return CDRF_DODEFAULT;
1101 }
1102 
1103 static VOID
1104 Advanced_RestoreDefaults(HWND hwndDlg)
1105 {
1106     HWND hwndTreeView = GetDlgItem(hwndDlg, 14003);
1107 
1108     for (INT i = 0; i < s_AdvancedCount; ++i)
1109     {
1110         // ignore if the type is group
1111         ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1112         if (pEntry->dwType == AETYPE_GROUP)
1113             continue;
1114 
1115         // set default value on registry
1116         HKEY hKey;
1117         if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath,
1118                           0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
1119         {
1120             continue;
1121         }
1122         RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD,
1123                        LPBYTE(pEntry->dwDefaultValue), sizeof(DWORD));
1124         RegCloseKey(hKey);
1125 
1126         // update check status
1127         pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue);
1128 
1129         // update the image
1130         TV_ITEM Item;
1131         ZeroMemory(&Item, sizeof(Item));
1132         Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1133         Item.hItem = pEntry->hItem;
1134         Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry);
1135         TreeView_SetItem(hwndTreeView, &Item);
1136     }
1137 
1138     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1139 }
1140 
1141 /* FIXME: These macros should not be defined here */
1142 #ifndef SSF_SHOWSUPERHIDDEN
1143     #define SSF_SHOWSUPERHIDDEN     0x00040000
1144 #endif
1145 #ifndef SSF_SEPPROCESS
1146     #define SSF_SEPPROCESS          0x00080000
1147 #endif
1148 
1149 static VOID
1150 ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask)
1151 {
1152     for (INT i = 0; i < s_AdvancedCount; ++i)
1153     {
1154         const ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1155         if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed)
1156             continue;
1157 
1158         BOOL bChecked = pEntry->bChecked;
1159 
1160         // FIXME: Add more items
1161         if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0)
1162         {
1163             pSS->fShowSuperHidden = !bChecked ? 1 : 0;
1164             *pdwMask |= SSF_SHOWSUPERHIDDEN;
1165             continue;
1166         }
1167         if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0)
1168         {
1169             pSS->fSepProcess = bChecked ? 1 : 0;
1170             *pdwMask |= SSF_SEPPROCESS;
1171             continue;
1172         }
1173         if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0)
1174         {
1175             pSS->fShowAllObjects = !bChecked ? 1 : 0;
1176             *pdwMask |= SSF_SHOWALLOBJECTS;
1177             continue;
1178         }
1179         if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0)
1180         {
1181             pSS->fShowExtensions = !bChecked ? 1 : 0;
1182             *pdwMask |= SSF_SHOWEXTENSIONS;
1183             continue;
1184         }
1185         if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0)
1186         {
1187             pSS->fShowCompColor = bChecked ? 1 : 0;
1188             *pdwMask |= SSF_SHOWCOMPCOLOR;
1189             continue;
1190         }
1191         if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0)
1192         {
1193             pSS->fShowInfoTip = bChecked ? 1 : 0;
1194             *pdwMask |= SSF_SHOWINFOTIP;
1195             continue;
1196         }
1197     }
1198 }
1199 
1200 extern "C"
1201 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet);
1202 
1203 static BOOL CALLBACK RefreshBrowsersCallback (HWND hWnd, LPARAM msg)
1204 {
1205     WCHAR ClassName[100];
1206     if (GetClassName(hWnd, ClassName, 100))
1207     {
1208         if (!wcscmp(ClassName, L"Progman") ||
1209             !wcscmp(ClassName, L"CabinetWClass") ||
1210             !wcscmp(ClassName, L"ExploreWClass"))
1211         {
1212             PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0);
1213         }
1214     }
1215     return TRUE;
1216 }
1217 
1218 static VOID
1219 ViewDlg_Apply(HWND hwndDlg)
1220 {
1221     for (INT i = 0; i < s_AdvancedCount; ++i)
1222     {
1223         // ignore the entry if the type is group or the entry is grayed
1224         ADVANCED_ENTRY *pEntry = &s_Advanced[i];
1225         if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed)
1226             continue;
1227 
1228         // open the registry key
1229         HKEY hkeyTarget;
1230         if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0,
1231                           KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS)
1232         {
1233             continue;
1234         }
1235 
1236         // checked or unchecked?
1237         DWORD dwValue, dwSize;
1238         if (pEntry->bChecked)
1239         {
1240             dwValue = pEntry->dwCheckedValue;
1241         }
1242         else
1243         {
1244             if (pEntry->bHasUncheckedValue)
1245             {
1246                 dwValue = pEntry->dwUncheckedValue;
1247             }
1248             else
1249             {
1250                 // there is no unchecked value
1251                 RegCloseKey(hkeyTarget);
1252                 continue;   // ignore
1253             }
1254         }
1255 
1256         // set the value
1257         dwSize = sizeof(dwValue);
1258         RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD,
1259                        LPBYTE(&dwValue), dwSize);
1260 
1261         // close now
1262         RegCloseKey(hkeyTarget);
1263     }
1264 
1265     // scan advanced settings for user's settings
1266     DWORD dwMask = 0;
1267     SHELLSTATE ShellState;
1268     ZeroMemory(&ShellState, sizeof(ShellState));
1269     ScanAdvancedSettings(&ShellState, &dwMask);
1270 
1271     // update user's settings
1272     SHGetSetSettings(&ShellState, dwMask, TRUE);
1273 
1274     // notify all
1275     SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0);
1276 
1277     EnumWindows(RefreshBrowsersCallback, NULL);
1278 }
1279 
1280 INT_PTR CALLBACK
1281 FolderOptionsViewDlg(
1282     HWND    hwndDlg,
1283     UINT    uMsg,
1284     WPARAM  wParam,
1285     LPARAM  lParam)
1286 {
1287     INT_PTR Result;
1288     NMTVCUSTOMDRAW *Draw;
1289 
1290     switch(uMsg)
1291     {
1292         case WM_INITDIALOG:
1293             return ViewDlg_OnInitDialog(hwndDlg);
1294 
1295         case WM_COMMAND:
1296             switch (LOWORD(wParam))
1297             {
1298                 case 14004: // Restore Defaults
1299                     Advanced_RestoreDefaults(hwndDlg);
1300                     break;
1301             }
1302             break;
1303 
1304         case WM_NOTIFY:
1305             switch (LPNMHDR(lParam)->code)
1306             {
1307                 case NM_CLICK:  // clicked on treeview
1308                     ViewDlg_OnTreeViewClick(hwndDlg);
1309                     break;
1310 
1311                 case NM_CUSTOMDRAW:     // custom draw (for graying)
1312                     Draw = (NMTVCUSTOMDRAW *)lParam;
1313                     Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw);
1314                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result);
1315                     return Result;
1316 
1317                 case TVN_KEYDOWN:       // key is down
1318                     ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam);
1319                     break;
1320 
1321                 case PSN_APPLY:         // [Apply] is clicked
1322                     ViewDlg_Apply(hwndDlg);
1323                     break;
1324 
1325                 default:
1326                     break;
1327             }
1328             break;
1329     }
1330 
1331     return FALSE;
1332 }
1333 
1334 static
1335 VOID
1336 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl)
1337 {
1338     RECT clientRect;
1339     LVCOLUMNW col;
1340     WCHAR szName[50];
1341     DWORD dwStyle;
1342     int columnSize = 140;
1343 
1344 
1345     if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR)))
1346     {
1347         /* default to english */
1348         wcscpy(szName, L"Extensions");
1349     }
1350 
1351     /* make sure its null terminated */
1352     szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
1353 
1354     GetClientRect(hDlgCtrl, &clientRect);
1355     ZeroMemory(&col, sizeof(LV_COLUMN));
1356     columnSize = 140; //FIXME
1357     col.iSubItem   = 0;
1358     col.mask      = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
1359     col.fmt = LVCFMT_FIXED_WIDTH;
1360     col.cx         = columnSize | LVCFMT_LEFT;
1361     col.cchTextMax = wcslen(szName);
1362     col.pszText    = szName;
1363     (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col);
1364 
1365     if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR)))
1366     {
1367         /* default to english */
1368         wcscpy(szName, L"File Types");
1369         ERR("Failed to load localized string!\n");
1370     }
1371 
1372     col.iSubItem   = 1;
1373     col.cx         = clientRect.right - clientRect.left - columnSize;
1374     col.cchTextMax = wcslen(szName);
1375     col.pszText    = szName;
1376     (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col);
1377 
1378     /* set full select style */
1379     dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1380     dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
1381     SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
1382 }
1383 
1384 static BOOL
1385 DeleteExt(HWND hwndDlg, LPCWSTR pszExt)
1386 {
1387     if (*pszExt != L'.')
1388         return FALSE;
1389 
1390     // open ".ext" key
1391     HKEY hKey;
1392     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
1393         return FALSE;
1394 
1395     // query "extfile" key name
1396     WCHAR szValue[64] = { 0 };
1397     DWORD cbValue = sizeof(szValue);
1398     RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(szValue), &cbValue);
1399     RegCloseKey(hKey);
1400 
1401     // delete "extfile" key (if any)
1402     if (szValue[0])
1403         SHDeleteKeyW(HKEY_CLASSES_ROOT, szValue);
1404 
1405     // delete ".ext" key
1406     return SHDeleteKeyW(HKEY_CLASSES_ROOT, pszExt) == ERROR_SUCCESS;
1407 }
1408 
1409 static inline HICON
1410 DoExtractIcon(PFOLDER_FILE_TYPE_ENTRY Entry, LPCWSTR IconPath,
1411               INT iIndex = 0, BOOL bSmall = FALSE)
1412 {
1413     HICON hIcon = NULL;
1414 
1415     if (iIndex < 0)
1416     {
1417         // A negative value will be interpreted as a negated resource ID.
1418         iIndex = -iIndex;
1419 
1420         INT cx, cy;
1421         HINSTANCE hDLL = LoadLibraryExW(IconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
1422         if (bSmall)
1423         {
1424             cx = GetSystemMetrics(SM_CXSMICON);
1425             cy = GetSystemMetrics(SM_CYSMICON);
1426         }
1427         else
1428         {
1429             cx = GetSystemMetrics(SM_CXICON);
1430             cy = GetSystemMetrics(SM_CYICON);
1431         }
1432         hIcon = HICON(LoadImageW(hDLL, MAKEINTRESOURCEW(iIndex), IMAGE_ICON,
1433                                  cx, cy, 0));
1434         FreeLibrary(hDLL);
1435     }
1436     else
1437     {
1438         // A positive value is icon index.
1439         if (bSmall)
1440             ExtractIconExW(IconPath, iIndex, NULL, &hIcon, 1);
1441         else
1442             ExtractIconExW(IconPath, iIndex, &hIcon, NULL, 1);
1443     }
1444     return hIcon;
1445 }
1446 
1447 static void
1448 DoFileTypeIconLocation(PFOLDER_FILE_TYPE_ENTRY Entry, LPCWSTR IconLocation)
1449 {
1450     // Expand the REG_EXPAND_SZ string by environment variables
1451     WCHAR szLocation[MAX_PATH + 32];
1452     if (!ExpandEnvironmentStringsW(IconLocation, szLocation, _countof(szLocation)))
1453     {
1454         return;
1455     }
1456 
1457     Entry->nIconIndex = PathParseIconLocationW(szLocation);
1458     StringCchCopyW(Entry->IconPath, _countof(Entry->IconPath), szLocation);
1459     Entry->hIconLarge = DoExtractIcon(Entry, szLocation, Entry->nIconIndex, FALSE);
1460     Entry->hIconSmall = DoExtractIcon(Entry, szLocation, Entry->nIconIndex, TRUE);
1461 }
1462 
1463 static BOOL
1464 GetFileTypeIconsEx(PFOLDER_FILE_TYPE_ENTRY Entry, LPCWSTR IconLocation)
1465 {
1466     Entry->hIconLarge = Entry->hIconSmall = NULL;
1467 
1468     if (lstrcmpiW(Entry->FileExtension, L".exe") == 0 ||
1469         lstrcmpiW(Entry->FileExtension, L".scr") == 0)
1470     {
1471         // It's an executable
1472         Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE));
1473         Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE), IMAGE_ICON,
1474             GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
1475         StringCchCopyW(Entry->IconPath, _countof(Entry->IconPath), L"%SystemRoot%\\system32\\shell32.dll");
1476         Entry->nIconIndex = -IDI_SHELL_EXE;
1477     }
1478     else if (lstrcmpW(IconLocation, L"%1") == 0)
1479     {
1480         return FALSE;   // self icon
1481     }
1482     else
1483     {
1484         DoFileTypeIconLocation(Entry, IconLocation);
1485     }
1486 
1487     return Entry->hIconLarge && Entry->hIconSmall;
1488 }
1489 
1490 static BOOL
1491 GetFileTypeIconsByKey(HKEY hKey, PFOLDER_FILE_TYPE_ENTRY Entry)
1492 {
1493     Entry->hIconLarge = Entry->hIconSmall = NULL;
1494 
1495     // Open the "DefaultIcon" registry key
1496     HKEY hDefIconKey;
1497     LONG nResult = RegOpenKeyExW(hKey, L"DefaultIcon", 0, KEY_READ, &hDefIconKey);
1498     if (nResult != ERROR_SUCCESS)
1499         return FALSE;
1500 
1501     // Get the icon location
1502     WCHAR szLocation[MAX_PATH + 32] = { 0 };
1503     DWORD dwSize = sizeof(szLocation);
1504     nResult = RegQueryValueExW(hDefIconKey, NULL, NULL, NULL, LPBYTE(szLocation), &dwSize);
1505 
1506     RegCloseKey(hDefIconKey);
1507 
1508     if (nResult != ERROR_SUCCESS || szLocation[0] == 0)
1509         return FALSE;
1510 
1511     return GetFileTypeIconsEx(Entry, szLocation);
1512 }
1513 
1514 static BOOL
1515 QueryFileDescription(LPCWSTR ProgramPath, LPWSTR pszName, INT cchName)
1516 {
1517     SHFILEINFOW FileInfo = { 0 };
1518     if (SHGetFileInfoW(ProgramPath, 0, &FileInfo, sizeof(FileInfo), SHGFI_DISPLAYNAME))
1519     {
1520         StringCchCopyW(pszName, cchName, FileInfo.szDisplayName);
1521         return TRUE;
1522     }
1523 
1524     return !!GetFileTitleW(ProgramPath, pszName, cchName);
1525 }
1526 
1527 static void
1528 SetFileTypeEntryDefaultIcon(PFOLDER_FILE_TYPE_ENTRY Entry)
1529 {
1530     Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS));
1531     INT cxSmall = GetSystemMetrics(SM_CXSMICON);
1532     INT cySmall = GetSystemMetrics(SM_CYSMICON);
1533     Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS),
1534                                          IMAGE_ICON, cxSmall, cySmall, 0));
1535     StringCchCopyW(Entry->IconPath, _countof(Entry->IconPath), L"%SystemRoot%\\system32\\shell32.dll");
1536     Entry->nIconIndex = -IDI_SHELL_FOLDER_OPTIONS;
1537 }
1538 
1539 static BOOL
1540 InsertFileType(HWND hListView, LPCWSTR szName, INT iItem, LPCWSTR szFile)
1541 {
1542     PFOLDER_FILE_TYPE_ENTRY Entry;
1543     HKEY hKey;
1544     LVITEMW lvItem;
1545     DWORD dwSize;
1546     DWORD dwType;
1547 
1548     if (szName[0] != L'.')
1549     {
1550         /* FIXME handle URL protocol handlers */
1551         return FALSE;
1552     }
1553 
1554     // get imagelists of listview
1555     HIMAGELIST himlLarge = ListView_GetImageList(hListView, LVSIL_NORMAL);
1556     HIMAGELIST himlSmall = ListView_GetImageList(hListView, LVSIL_SMALL);
1557 
1558     /* allocate file type entry */
1559     Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY));
1560     if (!Entry)
1561         return FALSE;
1562 
1563     /* open key */
1564     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
1565     {
1566         HeapFree(GetProcessHeap(), 0, Entry);
1567         return FALSE;
1568     }
1569 
1570     /* FIXME check for duplicates */
1571 
1572     /* query for the default key */
1573     dwSize = sizeof(Entry->ClassKey);
1574     if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS)
1575     {
1576         /* no link available */
1577         Entry->ClassKey[0] = 0;
1578     }
1579 
1580     Entry->ClassName[0] = 0;
1581     if (Entry->ClassKey[0])
1582     {
1583         HKEY hTemp;
1584         /* try open linked key */
1585         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS)
1586         {
1587             DWORD dwSize = sizeof(Entry->ClassName);
1588             RegQueryValueExW(hTemp, NULL, NULL, NULL, LPBYTE(Entry->ClassName), &dwSize);
1589 
1590             /* use linked key */
1591             RegCloseKey(hKey);
1592             hKey = hTemp;
1593         }
1594     }
1595 
1596     /* read friendly type name */
1597     if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS)
1598     {
1599         /* read file description */
1600         dwSize = sizeof(Entry->FileDescription);
1601         Entry->FileDescription[0] = 0;
1602 
1603         /* read default key */
1604         RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize);
1605     }
1606 
1607     /* Read the EditFlags value */
1608     Entry->EditFlags = 0;
1609     if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize))
1610     {
1611         if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD))
1612             RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize);
1613     }
1614 
1615     /* convert extension to upper case */
1616     wcscpy(Entry->FileExtension, szName);
1617     _wcsupr(Entry->FileExtension);
1618 
1619     /* get icon */
1620     if (!GetFileTypeIconsByKey(hKey, Entry))
1621     {
1622         // set default icon
1623         SetFileTypeEntryDefaultIcon(Entry);
1624     }
1625 
1626     /* close key */
1627     RegCloseKey(hKey);
1628 
1629     // get program path and app name
1630     DWORD cch = _countof(Entry->ProgramPath);
1631     if (S_OK == AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE,
1632                                   Entry->FileExtension, NULL, Entry->ProgramPath, &cch))
1633     {
1634         QueryFileDescription(Entry->ProgramPath, Entry->AppName, _countof(Entry->AppName));
1635     }
1636     else
1637     {
1638         Entry->ProgramPath[0] = Entry->AppName[0] = 0;
1639     }
1640 
1641     // add icon to imagelist
1642     INT iLargeImage = -1, iSmallImage = -1;
1643     if (Entry->hIconLarge && Entry->hIconSmall)
1644     {
1645         iLargeImage = ImageList_AddIcon(himlLarge, Entry->hIconLarge);
1646         iSmallImage = ImageList_AddIcon(himlSmall, Entry->hIconSmall);
1647         ASSERT(iLargeImage == iSmallImage);
1648     }
1649 
1650     /* Do not add excluded entries */
1651     if (Entry->EditFlags & 0x00000001) //FTA_Exclude
1652     {
1653         DestroyIcon(Entry->hIconLarge);
1654         DestroyIcon(Entry->hIconSmall);
1655         HeapFree(GetProcessHeap(), 0, Entry);
1656         return FALSE;
1657     }
1658 
1659     if (!Entry->FileDescription[0])
1660     {
1661         /* construct default 'FileExtensionFile' by formatting the uppercase extension
1662            with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File' */
1663 
1664         StringCchPrintf(Entry->FileDescription, _countof(Entry->FileDescription), szFile, &Entry->FileExtension[1]);
1665     }
1666 
1667     ZeroMemory(&lvItem, sizeof(LVITEMW));
1668     lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
1669     lvItem.iSubItem = 0;
1670     lvItem.pszText = &Entry->FileExtension[1];
1671     lvItem.iItem = iItem;
1672     lvItem.lParam = (LPARAM)Entry;
1673     lvItem.iImage = iSmallImage;
1674     SendMessageW(hListView, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
1675 
1676     ZeroMemory(&lvItem, sizeof(LVITEMW));
1677     lvItem.mask = LVIF_TEXT;
1678     lvItem.pszText = Entry->FileDescription;
1679     lvItem.iItem = iItem;
1680     lvItem.iSubItem = 1;
1681     ListView_SetItem(hListView, &lvItem);
1682 
1683     return TRUE;
1684 }
1685 
1686 static
1687 int
1688 CALLBACK
1689 ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
1690 {
1691     PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2;
1692     int x;
1693 
1694     Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1;
1695     Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2;
1696 
1697     x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension);
1698     if (x != 0)
1699         return x;
1700 
1701     return wcsicmp(Entry1->FileDescription, Entry2->FileDescription);
1702 }
1703 
1704 static
1705 PFOLDER_FILE_TYPE_ENTRY
1706 InitializeFileTypesListCtrl(HWND hwndDlg)
1707 {
1708     HWND hDlgCtrl;
1709     DWORD dwIndex = 0;
1710     WCHAR szName[50];
1711     WCHAR szFile[100];
1712     DWORD dwName;
1713     LVITEMW lvItem;
1714     INT iItem = 0;
1715     HIMAGELIST himlLarge, himlSmall;
1716 
1717     // create imagelists
1718     himlLarge = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1719                                  ILC_COLOR32 | ILC_MASK, 256, 20);
1720     himlSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
1721                                  ILC_COLOR32 | ILC_MASK, 256, 20);
1722 
1723     // set imagelists to listview.
1724     hDlgCtrl = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1725     ListView_SetImageList(hDlgCtrl, himlLarge, LVSIL_NORMAL);
1726     ListView_SetImageList(hDlgCtrl, himlSmall, LVSIL_SMALL);
1727 
1728     InitializeFileTypesListCtrlColumns(hDlgCtrl);
1729 
1730     szFile[0] = 0;
1731     if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile)))
1732     {
1733         /* default to english */
1734         wcscpy(szFile, L"%s File");
1735     }
1736     szFile[(_countof(szFile)) - 1] = 0;
1737 
1738     dwName = _countof(szName);
1739 
1740     while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1741     {
1742         if (InsertFileType(hDlgCtrl, szName, iItem, szFile))
1743             ++iItem;
1744         dwName = _countof(szName);
1745     }
1746 
1747     /* Leave if the list is empty */
1748     if (iItem == 0)
1749         return NULL;
1750 
1751     /* sort list */
1752     ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL);
1753 
1754     /* select first item */
1755     ZeroMemory(&lvItem, sizeof(LVITEMW));
1756     lvItem.mask = LVIF_STATE;
1757     lvItem.stateMask = (UINT)-1;
1758     lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
1759     lvItem.iItem = 0;
1760     ListView_SetItem(hDlgCtrl, &lvItem);
1761 
1762     lvItem.mask = LVIF_PARAM;
1763     ListView_GetItem(hDlgCtrl, &lvItem);
1764 
1765     return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
1766 }
1767 
1768 static inline
1769 PFOLDER_FILE_TYPE_ENTRY
1770 GetListViewEntry(HWND hListView, INT iItem = -1)
1771 {
1772     if (iItem == -1)
1773     {
1774         iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
1775         if (iItem == -1)
1776             return NULL;
1777     }
1778 
1779     LV_ITEMW lvItem = { LVIF_PARAM, iItem };
1780     if (ListView_GetItem(hListView, &lvItem))
1781         return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
1782 
1783     return NULL;
1784 }
1785 
1786 struct NEWEXT_DIALOG
1787 {
1788     HWND hwndLV;
1789     RECT rcDlg;
1790     BOOL bAdvanced;
1791     INT dy;
1792     WCHAR szExt[16];
1793     WCHAR szFileType[64];
1794 };
1795 
1796 static VOID
1797 NewExtDlg_OnAdvanced(HWND hwndDlg, NEWEXT_DIALOG *pNewExt)
1798 {
1799     // If "Advanced" button was clicked, then we shrink or expand the dialog.
1800     WCHAR szText[64];
1801     RECT rc, rc1, rc2;
1802 
1803     GetWindowRect(hwndDlg, &rc);
1804     rc.bottom = rc.top + (pNewExt->rcDlg.bottom - pNewExt->rcDlg.top);
1805 
1806     GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc1);
1807     MapWindowPoints(NULL, hwndDlg, (POINT *)&rc1, 2);
1808 
1809     GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rc2);
1810     MapWindowPoints(NULL, hwndDlg, (POINT *)&rc2, 2);
1811 
1812     if (pNewExt->bAdvanced)
1813     {
1814         rc1.top += pNewExt->dy;
1815         rc1.bottom += pNewExt->dy;
1816 
1817         rc2.top += pNewExt->dy;
1818         rc2.bottom += pNewExt->dy;
1819 
1820         ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_SHOWNOACTIVATE);
1821         ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_SHOWNOACTIVATE);
1822 
1823         LoadStringW(shell32_hInstance, IDS_NEWEXT_ADVANCED_LEFT, szText, _countof(szText));
1824         SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, szText);
1825 
1826         SetFocus(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX));
1827     }
1828     else
1829     {
1830         rc1.top -= pNewExt->dy;
1831         rc1.bottom -= pNewExt->dy;
1832 
1833         rc2.top -= pNewExt->dy;
1834         rc2.bottom -= pNewExt->dy;
1835 
1836         ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_HIDE);
1837         ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_HIDE);
1838 
1839         LoadStringW(shell32_hInstance, IDS_NEWEXT_ADVANCED_RIGHT, szText, _countof(szText));
1840         SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, szText);
1841 
1842         rc.bottom -= pNewExt->dy;
1843 
1844         LoadStringW(shell32_hInstance, IDS_NEWEXT_NEW, szText, _countof(szText));
1845         SetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, szText);
1846     }
1847 
1848     HDWP hDWP = BeginDeferWindowPos(3);
1849 
1850     if (hDWP)
1851         hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDOK), NULL,
1852                               rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
1853                               SWP_NOACTIVATE | SWP_NOZORDER);
1854     if (hDWP)
1855         hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDCANCEL), NULL,
1856                               rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top,
1857                               SWP_NOACTIVATE | SWP_NOZORDER);
1858     if (hDWP)
1859         hDWP = DeferWindowPos(hDWP, hwndDlg, NULL,
1860                               rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
1861                               SWP_NOACTIVATE | SWP_NOZORDER);
1862 
1863     if (hDWP)
1864         EndDeferWindowPos(hDWP);
1865 }
1866 
1867 static BOOL
1868 NewExtDlg_OnInitDialog(HWND hwndDlg, NEWEXT_DIALOG *pNewExt)
1869 {
1870     WCHAR szText[64];
1871 
1872     pNewExt->bAdvanced = FALSE;
1873 
1874     GetWindowRect(hwndDlg, &pNewExt->rcDlg);
1875 
1876     RECT rc1, rc2;
1877     GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_EDIT), &rc1);
1878     GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), &rc2);
1879     pNewExt->dy = rc2.top - rc1.top;
1880 
1881     LoadStringW(shell32_hInstance, IDS_NEWEXT_NEW, szText, _countof(szText));
1882     SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_ADDSTRING, 0, (LPARAM)szText);
1883     SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_SETCURSEL, 0, 0);
1884 
1885     SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_EDIT, EM_SETLIMITTEXT, _countof(pNewExt->szExt) - 1, 0);
1886 
1887     NewExtDlg_OnAdvanced(hwndDlg, pNewExt);
1888 
1889     return TRUE;
1890 }
1891 
1892 static LPCWSTR s_pszSpace = L" \t\n\r\f\v";
1893 
1894 static BOOL
1895 NewExtDlg_OnOK(HWND hwndDlg, NEWEXT_DIALOG *pNewExt)
1896 {
1897     LV_FINDINFO find;
1898     INT iItem;
1899 
1900     GetDlgItemTextW(hwndDlg, IDC_NEWEXT_EDIT, pNewExt->szExt, _countof(pNewExt->szExt));
1901     StrTrimW(pNewExt->szExt, s_pszSpace);
1902     CharUpperW(pNewExt->szExt);
1903 
1904     GetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, pNewExt->szFileType, _countof(pNewExt->szFileType));
1905     StrTrimW(pNewExt->szFileType, s_pszSpace);
1906 
1907     if (pNewExt->szExt[0] == 0)
1908     {
1909         WCHAR szText[128], szTitle[128];
1910         LoadStringW(shell32_hInstance, IDS_NEWEXT_SPECIFY_EXT, szText, _countof(szText));
1911         szText[_countof(szText) - 1] = 0;
1912         LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szTitle, _countof(szTitle));
1913         szTitle[_countof(szTitle) - 1] = 0;
1914         MessageBoxW(hwndDlg, szText, szTitle, MB_ICONERROR);
1915         return FALSE;
1916     }
1917 
1918     ZeroMemory(&find, sizeof(find));
1919     find.flags = LVFI_STRING;
1920     if (pNewExt->szExt[0] == L'.')
1921     {
1922         find.psz = &pNewExt->szExt[1];
1923     }
1924     else
1925     {
1926         find.psz = pNewExt->szExt;
1927     }
1928 
1929     iItem = ListView_FindItem(pNewExt->hwndLV, -1, &find);
1930     if (iItem >= 0)
1931     {
1932         // already exists
1933         WCHAR szText[256], szFormat[256], szTitle[64], szFileType[64];
1934 
1935         // get file type
1936         LV_ITEM item;
1937         ZeroMemory(&item, sizeof(item));
1938         item.mask = LVIF_TEXT;
1939         item.pszText = szFileType;
1940         item.cchTextMax = _countof(szFileType);
1941         item.iItem = iItem;
1942         item.iSubItem = 1;
1943         ListView_GetItem(pNewExt->hwndLV, &item);
1944 
1945         // get text
1946         LoadStringW(shell32_hInstance, IDS_NEWEXT_ALREADY_ASSOC, szFormat, _countof(szFormat));
1947         szText[_countof(szFormat) - 1] = 0;
1948         StringCchPrintfW(szText, _countof(szText), szFormat, find.psz, szFileType, find.psz, szFileType);
1949 
1950         // get title
1951         LoadStringW(shell32_hInstance, IDS_NEWEXT_EXT_IN_USE, szTitle, _countof(szTitle));
1952         szTitle[_countof(szTitle) - 1] = 0;
1953 
1954         if (MessageBoxW(hwndDlg, szText, szTitle, MB_ICONWARNING | MB_YESNO) == IDNO)
1955         {
1956             return FALSE;
1957         }
1958 
1959         // Delete the extension
1960         CStringW strExt(L".");
1961         strExt += find.psz;
1962         strExt.MakeLower();
1963         DeleteExt(hwndDlg, strExt);
1964 
1965         // Delete the item
1966         ListView_DeleteItem(pNewExt->hwndLV, iItem);
1967     }
1968 
1969     EndDialog(hwndDlg, IDOK);
1970     return TRUE;
1971 }
1972 
1973 // IDD_NEWEXTENSION dialog
1974 INT_PTR
1975 CALLBACK
1976 NewExtensionDlgProc(
1977     HWND hwndDlg,
1978     UINT uMsg,
1979     WPARAM wParam,
1980     LPARAM lParam)
1981 {
1982     static NEWEXT_DIALOG *s_pNewExt = NULL;
1983 
1984     switch (uMsg)
1985     {
1986         case WM_INITDIALOG:
1987             s_pNewExt = (NEWEXT_DIALOG *)lParam;
1988             NewExtDlg_OnInitDialog(hwndDlg, s_pNewExt);
1989             return TRUE;
1990 
1991         case WM_COMMAND:
1992             switch (LOWORD(wParam))
1993             {
1994                 case IDOK:
1995                     NewExtDlg_OnOK(hwndDlg, s_pNewExt);
1996                     break;
1997 
1998                 case IDCANCEL:
1999                     EndDialog(hwndDlg, IDCANCEL);
2000                     break;
2001 
2002                 case IDC_NEWEXT_ADVANCED:
2003                     s_pNewExt->bAdvanced = !s_pNewExt->bAdvanced;
2004                     NewExtDlg_OnAdvanced(hwndDlg, s_pNewExt);
2005                     break;
2006             }
2007             break;
2008     }
2009     return 0;
2010 }
2011 
2012 static BOOL
2013 FileTypesDlg_AddExt(HWND hwndDlg, LPCWSTR pszExt, LPCWSTR pszFileType)
2014 {
2015     DWORD dwValue = 1;
2016     HKEY hKey;
2017     WCHAR szKey[13];    // max. "ft4294967295" + "\0"
2018     LONG nResult;
2019 
2020     // Search the next "ft%06u" key name
2021     do
2022     {
2023         StringCchPrintfW(szKey, _countof(szKey), TEXT("ft%06u"), dwValue);
2024 
2025         nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hKey);
2026         if (nResult != ERROR_SUCCESS)
2027             break;
2028 
2029         RegCloseKey(hKey);
2030         ++dwValue;
2031     } while (dwValue != 0);
2032 
2033     RegCloseKey(hKey);
2034 
2035     if (dwValue == 0)
2036         return FALSE;
2037 
2038     // Create new "ft%06u" key
2039     nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
2040     if (ERROR_SUCCESS != nResult)
2041         return FALSE;
2042 
2043     RegCloseKey(hKey);
2044 
2045     // Create the ".ext" key
2046     WCHAR szExt[16];
2047     if (*pszExt == L'.')
2048         ++pszExt;
2049     StringCchPrintfW(szExt, _countof(szExt), TEXT(".%s"), pszExt);
2050     CharLowerW(szExt);
2051     nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
2052     CharUpperW(szExt);
2053     if (ERROR_SUCCESS != nResult)
2054         return FALSE;
2055 
2056     // Set the default value of ".ext" to "ft%06u"
2057     DWORD dwSize = (lstrlen(szKey) + 1) * sizeof(WCHAR);
2058     RegSetValueExW(hKey, NULL, 0, REG_SZ, (BYTE *)szKey, dwSize);
2059 
2060     RegCloseKey(hKey);
2061 
2062     // Make up the file type name
2063     WCHAR szFile[100], szFileFormat[100];
2064     LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFileFormat, _countof(szFileFormat));
2065     szFile[_countof(szFileFormat) - 1] = 0;
2066     StringCchPrintfW(szFile, _countof(szFile), szFileFormat, &szExt[1]);
2067 
2068     // Insert an item to the listview
2069     HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
2070     INT iItem = ListView_GetItemCount(hListView);
2071     if (!InsertFileType(hListView, szExt, iItem, szFile))
2072         return FALSE;
2073 
2074     LV_ITEM item;
2075     ZeroMemory(&item, sizeof(item));
2076     item.mask = LVIF_STATE | LVIF_TEXT;
2077     item.iItem = iItem;
2078     item.state = LVIS_SELECTED | LVIS_FOCUSED;
2079     item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2080     item.pszText = &szExt[1];
2081     ListView_SetItem(hListView, &item);
2082 
2083     item.pszText = szFile;
2084     item.iSubItem = 1;
2085     ListView_SetItem(hListView, &item);
2086 
2087     ListView_EnsureVisible(hListView, iItem, FALSE);
2088 
2089     return TRUE;
2090 }
2091 
2092 static BOOL
2093 FileTypesDlg_RemoveExt(HWND hwndDlg)
2094 {
2095     HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
2096 
2097     INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
2098     if (iItem == -1)
2099         return FALSE;
2100 
2101     WCHAR szExt[20];
2102     szExt[0] = L'.';
2103     ListView_GetItemText(hListView, iItem, 0, &szExt[1], _countof(szExt) - 1);
2104     CharLowerW(szExt);
2105 
2106     DeleteExt(hwndDlg, szExt);
2107     ListView_DeleteItem(hListView, iItem);
2108     return TRUE;
2109 }
2110 
2111 static void
2112 FileTypesDlg_OnItemChanging(HWND hwndDlg, PFOLDER_FILE_TYPE_ENTRY pEntry)
2113 {
2114     WCHAR Buffer[255];
2115     static HBITMAP s_hbmProgram = NULL;
2116 
2117     // format buffer and set groupbox text
2118     CStringW strFormat(MAKEINTRESOURCEW(IDS_FILE_DETAILS));
2119     StringCchPrintfW(Buffer, _countof(Buffer), strFormat, &pEntry->FileExtension[1]);
2120     SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DETAILS_GROUPBOX, Buffer);
2121 
2122     // format buffer and set description
2123     strFormat.LoadString(IDS_FILE_DETAILSADV);
2124     StringCchPrintfW(Buffer, _countof(Buffer), strFormat,
2125                      &pEntry->FileExtension[1], pEntry->FileDescription,
2126                      pEntry->FileDescription);
2127     SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DESCRIPTION, Buffer);
2128 
2129     // delete previous program image
2130     if (s_hbmProgram)
2131     {
2132         DeleteObject(s_hbmProgram);
2133         s_hbmProgram = NULL;
2134     }
2135 
2136     // set program image
2137     HICON hIconSm = NULL;
2138     ExtractIconExW(pEntry->ProgramPath, 0, NULL, &hIconSm, 1);
2139     s_hbmProgram = BitmapFromIcon(hIconSm, 16, 16);
2140     DestroyIcon(hIconSm);
2141     SendDlgItemMessageW(hwndDlg, IDC_FILETYPES_ICON, STM_SETIMAGE, IMAGE_BITMAP, LPARAM(s_hbmProgram));
2142 
2143     // set program name
2144     if (pEntry->AppName[0])
2145         SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, pEntry->AppName);
2146     else
2147         SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, L"ReactOS");
2148 
2149     /* Enable the Delete button */
2150     if (pEntry->EditFlags & 0x00000010) // FTA_NoRemove
2151         EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
2152     else
2153         EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), TRUE);
2154 }
2155 
2156 struct EDITTYPE_DIALOG
2157 {
2158     HWND hwndLV;
2159     FOLDER_FILE_TYPE_ENTRY *pEntry;
2160     CSimpleMap<CStringW, CStringW> CommandLineMap;
2161     WCHAR szIconPath[MAX_PATH];
2162     INT nIconIndex;
2163     WCHAR szDefaultVerb[64];
2164 };
2165 
2166 static BOOL
2167 EditTypeDlg_ReadClass(HWND hwndDlg, EDITTYPE_DIALOG *pEditType, LPCWSTR ClassKey)
2168 {
2169     // open class key
2170     HKEY hClassKey;
2171     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, ClassKey, 0, KEY_READ, &hClassKey) != ERROR_SUCCESS)
2172         return FALSE;
2173 
2174     // open "shell" key
2175     HKEY hShellKey;
2176     if (RegOpenKeyExW(hClassKey, L"shell", 0, KEY_READ, &hShellKey) != ERROR_SUCCESS)
2177     {
2178         RegCloseKey(hClassKey);
2179         return FALSE;
2180     }
2181 
2182     WCHAR DefaultVerb[64];
2183     DWORD dwSize = sizeof(DefaultVerb);
2184     if (RegQueryValueExW(hShellKey, NULL, NULL, NULL, LPBYTE(DefaultVerb), &dwSize) == ERROR_SUCCESS)
2185     {
2186         StringCchCopyW(pEditType->szDefaultVerb, _countof(pEditType->szDefaultVerb), DefaultVerb);
2187     }
2188     else
2189     {
2190         StringCchCopyW(pEditType->szDefaultVerb, _countof(pEditType->szDefaultVerb), L"open");
2191     }
2192 
2193     // enumerate shell verbs
2194     WCHAR szVerbName[64];
2195     DWORD dwIndex = 0;
2196     while (RegEnumKeyW(hShellKey, dwIndex, szVerbName, _countof(szVerbName)) == ERROR_SUCCESS)
2197     {
2198         // open verb key
2199         HKEY hVerbKey;
2200         LONG nResult = RegOpenKeyExW(hShellKey, szVerbName, 0, KEY_READ, &hVerbKey);
2201         if (nResult == ERROR_SUCCESS)
2202         {
2203             // open command key
2204             HKEY hCommandKey;
2205             nResult = RegOpenKeyExW(hVerbKey, L"command", 0, KEY_READ, &hCommandKey);
2206             if (nResult == ERROR_SUCCESS)
2207             {
2208                 // get command line
2209                 WCHAR szValue[MAX_PATH + 32];
2210                 dwSize = sizeof(szValue);
2211                 nResult = RegQueryValueExW(hCommandKey, NULL, NULL, NULL, LPBYTE(szValue), &dwSize);
2212                 if (nResult == ERROR_SUCCESS)
2213                 {
2214                     pEditType->CommandLineMap.SetAt(szVerbName, szValue);
2215                 }
2216 
2217                 RegCloseKey(hCommandKey);
2218             }
2219 
2220             RegCloseKey(hVerbKey);
2221         }
2222         SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_ADDSTRING, 0, LPARAM(szVerbName));
2223         ++dwIndex;
2224     }
2225 
2226     RegCloseKey(hShellKey);
2227     RegCloseKey(hClassKey);
2228 
2229     return TRUE;
2230 }
2231 
2232 static BOOL
2233 EditTypeDlg_WriteClass(HWND hwndDlg, EDITTYPE_DIALOG *pEditType,
2234                        LPCWSTR ClassKey, LPCWSTR ClassName, INT cchName)
2235 {
2236     FOLDER_FILE_TYPE_ENTRY *pEntry = pEditType->pEntry;
2237 
2238     if (ClassKey[0] == 0)
2239         return FALSE;
2240 
2241     // create or open class key
2242     HKEY hClassKey;
2243     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, ClassKey, 0, NULL, 0, KEY_WRITE, NULL, &hClassKey, NULL) != ERROR_SUCCESS)
2244         return FALSE;
2245 
2246     // create "DefaultIcon" key
2247     if (pEntry->IconPath[0])
2248     {
2249         HKEY hDefaultIconKey;
2250         if (RegCreateKeyExW(hClassKey, L"DefaultIcon", 0, NULL, 0, KEY_WRITE, NULL, &hDefaultIconKey, NULL) == ERROR_SUCCESS)
2251         {
2252             WCHAR szText[MAX_PATH];
2253             StringCchPrintfW(szText, _countof(szText), L"%s,%d", pEntry->IconPath, pEntry->nIconIndex);
2254 
2255             // set icon location
2256             DWORD dwSize = (lstrlenW(szText) + 1) * sizeof(WCHAR);
2257             RegSetValueExW(hDefaultIconKey, NULL, 0, REG_EXPAND_SZ, LPBYTE(szText), dwSize);
2258 
2259             RegCloseKey(hDefaultIconKey);
2260         }
2261     }
2262 
2263     // create "shell" key
2264     HKEY hShellKey;
2265     if (RegCreateKeyExW(hClassKey, L"shell", 0, NULL, 0, KEY_WRITE, NULL, &hShellKey, NULL) != ERROR_SUCCESS)
2266     {
2267         RegCloseKey(hClassKey);
2268         return FALSE;
2269     }
2270 
2271     // delete shell commands
2272     WCHAR szVerbName[64];
2273     DWORD dwIndex = 0;
2274     while (RegEnumKeyW(hShellKey, dwIndex, szVerbName, _countof(szVerbName)) == ERROR_SUCCESS)
2275     {
2276         if (pEditType->CommandLineMap.FindKey(szVerbName) == -1)
2277         {
2278             // doesn't exist in CommandLineMap, then delete it
2279             if (SHDeleteKeyW(hShellKey, szVerbName) == ERROR_SUCCESS)
2280             {
2281                 --dwIndex;
2282             }
2283         }
2284         ++dwIndex;
2285     }
2286 
2287     // set default action
2288     RegSetValueExW(hShellKey, NULL, 0, REG_SZ, LPBYTE(pEditType->szDefaultVerb), sizeof(pEditType->szDefaultVerb));
2289 
2290     // write shell commands
2291     const INT nCount = pEditType->CommandLineMap.GetSize();
2292     for (INT i = 0; i < nCount; ++i)
2293     {
2294         CStringW& key = pEditType->CommandLineMap.GetKeyAt(i);
2295         CStringW& value = pEditType->CommandLineMap.GetValueAt(i);
2296 
2297         // create verb key
2298         HKEY hVerbKey;
2299         if (RegCreateKeyExW(hShellKey, key, 0, NULL, 0, KEY_WRITE, NULL, &hVerbKey, NULL) == ERROR_SUCCESS)
2300         {
2301             // create command key
2302             HKEY hCommandKey;
2303             if (RegCreateKeyExW(hVerbKey, L"command", 0, NULL, 0, KEY_WRITE, NULL, &hCommandKey, NULL) == ERROR_SUCCESS)
2304             {
2305                 // write the default value
2306                 DWORD dwSize = (value.GetLength() + 1) * sizeof(WCHAR);
2307                 RegSetValueExW(hCommandKey, NULL, 0, REG_EXPAND_SZ, LPBYTE(LPCWSTR(value)), dwSize);
2308 
2309                 RegCloseKey(hCommandKey);
2310             }
2311 
2312             RegCloseKey(hVerbKey);
2313         }
2314     }
2315 
2316     // set class name to class key
2317     RegSetValueExW(hClassKey, NULL, 0, REG_SZ, LPBYTE(ClassName), cchName);
2318 
2319     RegCloseKey(hShellKey);
2320     RegCloseKey(hClassKey);
2321 
2322     return TRUE;
2323 }
2324 
2325 static BOOL
2326 EditTypeDlg_OnInitDialog(HWND hwndDlg, EDITTYPE_DIALOG *pEditType)
2327 {
2328     FOLDER_FILE_TYPE_ENTRY *pEntry = pEditType->pEntry;
2329     StringCchCopyW(pEditType->szIconPath, _countof(pEditType->szIconPath), pEntry->IconPath);
2330     pEditType->nIconIndex = pEntry->nIconIndex;
2331     StringCchCopyW(pEditType->szDefaultVerb, _countof(pEditType->szDefaultVerb), L"open");
2332 
2333     // set info
2334     SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_ICON, STM_SETICON, (WPARAM)pEntry->hIconLarge, 0);
2335     SetDlgItemTextW(hwndDlg, IDC_EDITTYPE_TEXT, pEntry->ClassName);
2336     EditTypeDlg_ReadClass(hwndDlg, pEditType, pEntry->ClassKey);
2337     InvalidateRect(GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX), NULL, TRUE);
2338 
2339     // is listbox empty?
2340     if (SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETCOUNT, 0, 0) == 0)
2341     {
2342         EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_EDIT_BUTTON), FALSE);
2343         EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_REMOVE), FALSE);
2344         EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
2345     }
2346     else
2347     {
2348         // select first item
2349         SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_SETCURSEL, 0, 0);
2350     }
2351 
2352     EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SAME_WINDOW), FALSE);
2353 
2354     return TRUE;
2355 }
2356 
2357 static BOOL
2358 EditTypeDlg_OnRemove(HWND hwndDlg, EDITTYPE_DIALOG *pEditType)
2359 {
2360     // get current selection
2361     INT iItem = SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETCURSEL, 0, 0);
2362     if (iItem == LB_ERR)
2363         return FALSE;
2364 
2365     // ask user for removal
2366     CStringW strText(MAKEINTRESOURCEW(IDS_REMOVE_ACTION));
2367     CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
2368     if (MessageBoxW(hwndDlg, strText, strTitle, MB_ICONINFORMATION | MB_YESNO) == IDNO)
2369         return FALSE;
2370 
2371     // get text
2372     WCHAR szText[64];
2373     szText[0] = 0;
2374     SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETTEXT, iItem, (LPARAM)szText);
2375     StrTrimW(szText, s_pszSpace);
2376 
2377     // remove it
2378     pEditType->CommandLineMap.Remove(szText);
2379     SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_DELETESTRING, iItem, 0);
2380     return TRUE;
2381 }
2382 
2383 static BOOL
2384 EditTypeDlg_UpdateEntryIcon(HWND hwndDlg, EDITTYPE_DIALOG *pEditType, LPCWSTR IconPath, INT IconIndex)
2385 {
2386     FOLDER_FILE_TYPE_ENTRY *pEntry = pEditType->pEntry;
2387 
2388     BOOL bIconSet = FALSE;
2389     if (IconPath && IconPath[0])
2390     {
2391         DestroyIcon(pEntry->hIconLarge);
2392         DestroyIcon(pEntry->hIconSmall);
2393         pEntry->hIconLarge = DoExtractIcon(pEntry, IconPath, IconIndex, FALSE);
2394         pEntry->hIconSmall = DoExtractIcon(pEntry, IconPath, IconIndex, TRUE);
2395 
2396         bIconSet = (pEntry->hIconLarge && pEntry->hIconSmall);
2397     }
2398     if (bIconSet)
2399     {
2400         StringCchCopyW(pEntry->IconPath, _countof(pEntry->IconPath), IconPath);
2401         pEntry->nIconIndex = IconIndex;
2402     }
2403     else
2404     {
2405         SetFileTypeEntryDefaultIcon(pEntry);
2406     }
2407 
2408     HWND hListView = pEditType->hwndLV;
2409     HIMAGELIST himlLarge = ListView_GetImageList(hListView, LVSIL_NORMAL);
2410     HIMAGELIST himlSmall = ListView_GetImageList(hListView, LVSIL_SMALL);
2411 
2412     INT iLargeImage = ImageList_AddIcon(himlLarge, pEntry->hIconLarge);
2413     INT iSmallImage = ImageList_AddIcon(himlSmall, pEntry->hIconSmall);
2414     ASSERT(iLargeImage == iSmallImage);
2415 
2416     INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
2417     if (iItem != -1)
2418     {
2419         LV_ITEMW Item = { LVIF_IMAGE, iItem };
2420         Item.iImage = iSmallImage;
2421         ListView_SetItem(hListView, &Item);
2422     }
2423     return TRUE;
2424 }
2425 
2426 static void
2427 EditTypeDlg_OnOK(HWND hwndDlg, EDITTYPE_DIALOG *pEditType)
2428 {
2429     FOLDER_FILE_TYPE_ENTRY *pEntry = pEditType->pEntry;
2430 
2431     // get class name
2432     GetDlgItemTextW(hwndDlg, IDC_EDITTYPE_TEXT, pEntry->ClassName, _countof(pEntry->ClassName));
2433     StrTrimW(pEntry->ClassName, s_pszSpace);
2434 
2435     // update entry icon
2436     EditTypeDlg_UpdateEntryIcon(hwndDlg, pEditType, pEditType->szIconPath, pEditType->nIconIndex);
2437 
2438     // write registry
2439     EditTypeDlg_WriteClass(hwndDlg, pEditType, pEntry->ClassKey, pEntry->ClassName, _countof(pEntry->ClassName));
2440 
2441     // update the icon cache
2442     SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, NULL, NULL);
2443 
2444     EndDialog(hwndDlg, IDOK);
2445 }
2446 
2447 struct ACTION_DIALOG
2448 {
2449     HWND hwndLB;
2450     WCHAR ClassName[64];
2451     WCHAR szAction[64];
2452     WCHAR szApp[MAX_PATH];
2453     BOOL bUseDDE;
2454 };
2455 
2456 static void
2457 NewAct_OnOK(HWND hwndDlg, ACTION_DIALOG *pNewAct)
2458 {
2459     GetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, pNewAct->szAction, _countof(pNewAct->szAction));
2460     GetDlgItemTextW(hwndDlg, IDC_ACTION_APP, pNewAct->szApp, _countof(pNewAct->szApp));
2461     StrTrimW(pNewAct->szAction, s_pszSpace);
2462     StrTrimW(pNewAct->szApp, s_pszSpace);
2463     if (pNewAct->szAction[0] == 0)
2464     {
2465         // action is empty, error
2466         HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
2467         SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
2468         SetFocus(hwndCtrl);
2469         CStringW strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION));
2470         CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
2471         MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
2472         return;
2473     }
2474     if (pNewAct->szApp[0] == 0 || GetFileAttributesW(pNewAct->szApp) == 0xFFFFFFFF)
2475     {
2476         // app is invalid
2477         HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_APP);
2478         SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
2479         SetFocus(hwndCtrl);
2480         CStringW strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM));
2481         CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
2482         MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
2483         return;
2484     }
2485     EndDialog(hwndDlg, IDOK);
2486 }
2487 
2488 static void
2489 Action_OnBrowse(HWND hwndDlg, ACTION_DIALOG *pNewAct, BOOL bEdit = FALSE)
2490 {
2491     WCHAR szFile[MAX_PATH];
2492     szFile[0] = 0;
2493 
2494     WCHAR szFilter[MAX_PATH];
2495     LoadStringW(shell32_hInstance, IDS_EXE_FILTER, szFilter, _countof(szFilter));
2496 
2497     CStringW strTitle(MAKEINTRESOURCEW(IDS_OPEN_WITH));
2498 
2499     OPENFILENAMEW ofn;
2500     ZeroMemory(&ofn, sizeof(ofn));
2501     ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
2502     ofn.hwndOwner = hwndDlg;
2503     ofn.lpstrFilter = szFilter;
2504     ofn.lpstrFile = szFile;
2505     ofn.nMaxFile = _countof(szFile);
2506     ofn.lpstrTitle = strTitle;
2507     ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
2508     ofn.lpstrDefExt = L"exe";
2509     if (GetOpenFileNameW(&ofn))
2510     {
2511         if (bEdit)
2512         {
2513             CStringW str = szFile;
2514             str += L" \"%1\"";
2515             SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, str);
2516         }
2517         else
2518         {
2519             SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, szFile);
2520         }
2521     }
2522 }
2523 
2524 INT_PTR CALLBACK
2525 NewActionDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
2526 {
2527     static ACTION_DIALOG *s_pNewAct = NULL;
2528 
2529     switch (uMsg)
2530     {
2531         case WM_INITDIALOG:
2532             s_pNewAct = (ACTION_DIALOG *)lParam;
2533             s_pNewAct->bUseDDE = FALSE;
2534             EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_USE_DDE), FALSE);
2535             return TRUE;
2536 
2537         case WM_COMMAND:
2538             switch (LOWORD(wParam))
2539             {
2540                 case IDOK:
2541                     NewAct_OnOK(hwndDlg, s_pNewAct);
2542                     break;
2543 
2544                 case IDCANCEL:
2545                     EndDialog(hwndDlg, IDCANCEL);
2546                     break;
2547 
2548                 case IDC_ACTION_BROWSE:
2549                     Action_OnBrowse(hwndDlg, s_pNewAct, FALSE);
2550                     break;
2551             }
2552             break;
2553     }
2554     return 0;
2555 }
2556 
2557 static void
2558 EditAct_OnOK(HWND hwndDlg, ACTION_DIALOG *pEditAct)
2559 {
2560     GetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, pEditAct->szAction, _countof(pEditAct->szAction));
2561     GetDlgItemTextW(hwndDlg, IDC_ACTION_APP, pEditAct->szApp, _countof(pEditAct->szApp));
2562     StrTrimW(pEditAct->szAction, s_pszSpace);
2563     StrTrimW(pEditAct->szApp, s_pszSpace);
2564     if (pEditAct->szAction[0] == 0)
2565     {
2566         HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
2567         SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
2568         SetFocus(hwndCtrl);
2569         CStringW strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION));
2570         CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
2571         MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
2572     }
2573     if (pEditAct->szApp[0] == 0)
2574     {
2575         HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_APP);
2576         SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
2577         SetFocus(hwndCtrl);
2578         CStringW strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM));
2579         CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
2580         MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
2581     }
2582     EndDialog(hwndDlg, IDOK);
2583 }
2584 
2585 INT_PTR CALLBACK
2586 EditActionDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
2587 {
2588     static ACTION_DIALOG *s_pEditAct = NULL;
2589 
2590     switch (uMsg)
2591     {
2592         case WM_INITDIALOG:
2593             s_pEditAct = (ACTION_DIALOG *)lParam;
2594             s_pEditAct->bUseDDE = FALSE;
2595             SetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, s_pEditAct->szAction);
2596             SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, s_pEditAct->szApp);
2597             EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_USE_DDE), FALSE);
2598             EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_ACTION), FALSE);
2599             {
2600                 // set title
2601                 CStringW str(MAKEINTRESOURCEW(IDS_EDITING_ACTION));
2602                 str += s_pEditAct->ClassName;
2603                 SetWindowTextW(hwndDlg, str);
2604             }
2605             return TRUE;
2606 
2607         case WM_COMMAND:
2608             switch (LOWORD(wParam))
2609             {
2610                 case IDOK:
2611                     EditAct_OnOK(hwndDlg, s_pEditAct);
2612                     break;
2613 
2614                 case IDCANCEL:
2615                     EndDialog(hwndDlg, IDCANCEL);
2616                     break;
2617 
2618                 case IDC_ACTION_BROWSE:
2619                     Action_OnBrowse(hwndDlg, s_pEditAct, TRUE);
2620                     break;
2621             }
2622             break;
2623     }
2624     return 0;
2625 }
2626 
2627 static void
2628 EditTypeDlg_OnChangeIcon(HWND hwndDlg, EDITTYPE_DIALOG *pEditType)
2629 {
2630     WCHAR szPath[MAX_PATH];
2631     INT IconIndex;
2632 
2633     ExpandEnvironmentStringsW(pEditType->szIconPath, szPath, _countof(szPath));
2634     IconIndex = pEditType->nIconIndex;
2635     if (PickIconDlg(hwndDlg, szPath, _countof(szPath), &IconIndex))
2636     {
2637         // replace Windows directory with "%SystemRoot%" (for portability)
2638         WCHAR szWinDir[MAX_PATH];
2639         GetWindowsDirectoryW(szWinDir, _countof(szWinDir));
2640         if (wcsstr(szPath, szWinDir) == 0)
2641         {
2642             CStringW str(L"%SystemRoot%");
2643             str += &szPath[wcslen(szWinDir)];
2644             StringCchCopyW(szPath, _countof(szPath), LPCWSTR(str));
2645         }
2646 
2647         // update FOLDER_FILE_TYPE_ENTRY
2648         FOLDER_FILE_TYPE_ENTRY *pEntry = pEditType->pEntry;
2649         DestroyIcon(pEntry->hIconLarge);
2650         DestroyIcon(pEntry->hIconSmall);
2651         pEntry->hIconLarge = DoExtractIcon(pEntry, szPath, IconIndex, FALSE);
2652         pEntry->hIconSmall = DoExtractIcon(pEntry, szPath, IconIndex, TRUE);
2653 
2654         // update EDITTYPE_DIALOG
2655         StringCchCopyW(pEditType->szIconPath, _countof(pEditType->szIconPath), szPath);
2656         pEditType->nIconIndex = IconIndex;
2657 
2658         // set icon to dialog
2659         SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_ICON, STM_SETICON, (WPARAM)pEntry->hIconLarge, 0);
2660     }
2661 }
2662 
2663 static BOOL
2664 EditTypeDlg_OnDrawItem(HWND hwndDlg, LPDRAWITEMSTRUCT pDraw, EDITTYPE_DIALOG *pEditType)
2665 {
2666     WCHAR szText[64];
2667     HFONT hFont, hFont2;
2668 
2669     if (!pDraw)
2670         return FALSE;
2671 
2672     // fill rect and set colors
2673     if (pDraw->itemState & ODS_SELECTED)
2674     {
2675         FillRect(pDraw->hDC, &pDraw->rcItem, HBRUSH(COLOR_HIGHLIGHT + 1));
2676         SetTextColor(pDraw->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
2677         SetBkColor(pDraw->hDC, GetSysColor(COLOR_HIGHLIGHT));
2678     }
2679     else
2680     {
2681         FillRect(pDraw->hDC, &pDraw->rcItem, HBRUSH(COLOR_WINDOW + 1));
2682         SetTextColor(pDraw->hDC, GetSysColor(COLOR_WINDOWTEXT));
2683         SetBkColor(pDraw->hDC, GetSysColor(COLOR_WINDOW));
2684     }
2685 
2686     // get listbox text
2687     SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETTEXT, pDraw->itemID, (LPARAM)szText);
2688 
2689     // is it default?
2690     hFont = (HFONT)SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, WM_GETFONT, 0, 0);
2691     if (lstrcmpiW(pEditType->szDefaultVerb, szText) == 0)
2692     {
2693         // default. set bold
2694         LOGFONTW lf;
2695         GetObject(hFont, sizeof(lf), &lf);
2696         lf.lfWeight = FW_BOLD;
2697         hFont2 = CreateFontIndirectW(&lf);
2698         if (hFont2)
2699         {
2700             HGDIOBJ hFontOld = SelectObject(pDraw->hDC, hFont2);
2701             InflateRect(&pDraw->rcItem, -2, -2);
2702             DrawTextW(pDraw->hDC, szText, -1, &pDraw->rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
2703             InflateRect(&pDraw->rcItem, 2, 2);
2704             SelectObject(pDraw->hDC, hFontOld);
2705             DeleteObject(hFont2);
2706         }
2707     }
2708     else
2709     {
2710         // non-default
2711         InflateRect(&pDraw->rcItem, -2, -2);
2712         DrawTextW(pDraw->hDC, szText, -1, &pDraw->rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
2713         InflateRect(&pDraw->rcItem, 2, 2);
2714     }
2715 
2716     // draw focus rect
2717     if (pDraw->itemState & ODS_FOCUS)
2718     {
2719         DrawFocusRect(pDraw->hDC, &pDraw->rcItem);
2720     }
2721     return TRUE;
2722 }
2723 
2724 static BOOL
2725 EditTypeDlg_OnMeasureItem(HWND hwndDlg, LPMEASUREITEMSTRUCT pMeasure, EDITTYPE_DIALOG *pEditType)
2726 {
2727     if (!pMeasure)
2728         return FALSE;
2729 
2730     HWND hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
2731 
2732     RECT rc;
2733     GetClientRect(hwndLB, &rc);
2734 
2735     HDC hDC = GetDC(hwndLB);
2736     if (hDC)
2737     {
2738         TEXTMETRICW tm;
2739         GetTextMetricsW(hDC, &tm);
2740         pMeasure->itemWidth = rc.right - rc.left;
2741         pMeasure->itemHeight = tm.tmHeight + 4;
2742         ReleaseDC(hwndLB, hDC);
2743         return TRUE;
2744     }
2745     return FALSE;
2746 }
2747 
2748 static void
2749 EditTypeDlg_OnCommand(HWND hwndDlg, UINT id, UINT code, EDITTYPE_DIALOG *pEditType)
2750 {
2751     INT iItem, iIndex;
2752     ACTION_DIALOG action;
2753     switch (id)
2754     {
2755         case IDOK:
2756             EditTypeDlg_OnOK(hwndDlg, pEditType);
2757             break;
2758 
2759         case IDCANCEL:
2760             EndDialog(hwndDlg, IDCANCEL);
2761             break;
2762 
2763         case IDC_EDITTYPE_CHANGE_ICON:
2764             EditTypeDlg_OnChangeIcon(hwndDlg, pEditType);
2765             break;
2766 
2767         case IDC_EDITTYPE_NEW:
2768             action.bUseDDE = FALSE;
2769             action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
2770             StringCchPrintfW(action.ClassName, _countof(action.ClassName), pEditType->pEntry->ClassName);
2771             // open 'New Action' dialog
2772             if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ACTION), hwndDlg,
2773                                         NewActionDlgProc, LPARAM(&action)))
2774             {
2775                 if (SendMessageW(action.hwndLB, LB_FINDSTRING, -1, (LPARAM)action.szAction) != LB_ERR)
2776                 {
2777                     // already exists, error
2778                     HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
2779                     SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
2780                     SetFocus(hwndCtrl);
2781 
2782                     CStringW strText, strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
2783                     strText.Format(IDS_ACTION_EXISTS, action.szAction);
2784                     MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
2785                 }
2786                 else
2787                 {
2788                     // add it
2789                     CStringW strCommandLine = action.szApp;
2790                     strCommandLine += L" \"%1\"";
2791                     pEditType->CommandLineMap.SetAt(action.szAction, strCommandLine);
2792                     SendMessageW(action.hwndLB, LB_ADDSTRING, 0, LPARAM(action.szAction));
2793                     if (SendMessageW(action.hwndLB, LB_GETCOUNT, 0, 0) == 1)
2794                     {
2795                         // set default
2796                         StringCchCopyW(pEditType->szDefaultVerb, _countof(pEditType->szDefaultVerb), action.szAction);
2797                         InvalidateRect(action.hwndLB, NULL, TRUE);
2798                     }
2799                 }
2800             }
2801             break;
2802 
2803         case IDC_EDITTYPE_LISTBOX:
2804             if (code == LBN_SELCHANGE)
2805             {
2806                 action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
2807                 INT iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
2808                 SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
2809                 if (lstrcmpiW(action.szAction, pEditType->szDefaultVerb) == 0)
2810                 {
2811                     EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
2812                 }
2813                 else
2814                 {
2815                     EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), TRUE);
2816                 }
2817                 break;
2818             }
2819             else if (code != LBN_DBLCLK)
2820             {
2821                 break;
2822             }
2823             // FALL THROUGH
2824 
2825         case IDC_EDITTYPE_EDIT_BUTTON:
2826             action.bUseDDE = FALSE;
2827             action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
2828             StringCchPrintfW(action.ClassName, _countof(action.ClassName), pEditType->pEntry->ClassName);
2829             iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
2830             if (iItem == LB_ERR)
2831                 break;
2832 
2833             // get action
2834             SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
2835 
2836             // get app
2837             {
2838                 iIndex = pEditType->CommandLineMap.FindKey(action.szAction);
2839                 CStringW str = pEditType->CommandLineMap.GetValueAt(iIndex);
2840                 StringCchCopyW(action.szApp, _countof(action.szApp), LPCWSTR(str));
2841             }
2842 
2843             // open dialog
2844             if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ACTION), hwndDlg,
2845                                         EditActionDlgProc, LPARAM(&action)))
2846             {
2847                 SendMessageW(action.hwndLB, LB_DELETESTRING, iItem, 0);
2848                 SendMessageW(action.hwndLB, LB_INSERTSTRING, iItem, LPARAM(action.szAction));
2849                 pEditType->CommandLineMap.SetAt(action.szAction, action.szApp);
2850             }
2851             break;
2852 
2853         case IDC_EDITTYPE_REMOVE:
2854             EditTypeDlg_OnRemove(hwndDlg, pEditType);
2855             break;
2856 
2857         case IDC_EDITTYPE_SET_DEFAULT:
2858             action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
2859             iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
2860             if (iItem == LB_ERR)
2861                 break;
2862 
2863             SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
2864 
2865             // set default
2866             StringCchCopyW(pEditType->szDefaultVerb, _countof(pEditType->szDefaultVerb), action.szAction);
2867             EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
2868             InvalidateRect(action.hwndLB, NULL, TRUE);
2869             break;
2870     }
2871 }
2872 
2873 INT_PTR CALLBACK
2874 EditTypeDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
2875 {
2876     static EDITTYPE_DIALOG *s_pEditType = NULL;
2877     LPDRAWITEMSTRUCT pDraw;
2878     LPMEASUREITEMSTRUCT pMeasure;
2879 
2880     switch (uMsg)
2881     {
2882         case WM_INITDIALOG:
2883             s_pEditType = (EDITTYPE_DIALOG *)lParam;
2884             return EditTypeDlg_OnInitDialog(hwndDlg, s_pEditType);
2885 
2886         case WM_DRAWITEM:
2887             pDraw = LPDRAWITEMSTRUCT(lParam);
2888             return EditTypeDlg_OnDrawItem(hwndDlg, pDraw, s_pEditType);
2889 
2890         case WM_MEASUREITEM:
2891             pMeasure = LPMEASUREITEMSTRUCT(lParam);
2892             return EditTypeDlg_OnMeasureItem(hwndDlg, pMeasure, s_pEditType);
2893 
2894         case WM_COMMAND:
2895             EditTypeDlg_OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), s_pEditType);
2896             break;
2897     }
2898 
2899     return 0;
2900 }
2901 
2902 static void
2903 EditTypeDlg_OnDelete(HWND hwndDlg)
2904 {
2905     CStringW strRemoveExt(MAKEINTRESOURCEW(IDS_REMOVE_EXT));
2906     CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
2907     if (MessageBoxW(hwndDlg, strRemoveExt, strTitle, MB_ICONQUESTION | MB_YESNO) == IDYES)
2908     {
2909         FileTypesDlg_RemoveExt(hwndDlg);
2910     }
2911 }
2912 
2913 // IDD_FOLDER_OPTIONS_FILETYPES dialog
2914 INT_PTR
2915 CALLBACK
2916 FolderOptionsFileTypesDlg(
2917     HWND hwndDlg,
2918     UINT uMsg,
2919     WPARAM wParam,
2920     LPARAM lParam)
2921 {
2922     LPNMLISTVIEW lppl;
2923     PFOLDER_FILE_TYPE_ENTRY pItem;
2924     OPENASINFO Info;
2925     NEWEXT_DIALOG newext;
2926     EDITTYPE_DIALOG edittype;
2927 
2928     switch(uMsg)
2929     {
2930         case WM_INITDIALOG:
2931             pItem = InitializeFileTypesListCtrl(hwndDlg);
2932 
2933             /* Disable the Delete button if the listview is empty or
2934                the selected item should not be deleted by the user */
2935             if (pItem == NULL || (pItem->EditFlags & 0x00000010)) // FTA_NoRemove
2936                 EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
2937             return TRUE;
2938 
2939         case WM_COMMAND:
2940             switch(LOWORD(wParam))
2941             {
2942                 case IDC_FILETYPES_NEW:
2943                     newext.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
2944                     if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_NEWEXTENSION),
2945                                                 hwndDlg, NewExtensionDlgProc, (LPARAM)&newext))
2946                     {
2947                         FileTypesDlg_AddExt(hwndDlg, newext.szExt, newext.szFileType);
2948                     }
2949                     break;
2950 
2951                 case IDC_FILETYPES_DELETE:
2952                     EditTypeDlg_OnDelete(hwndDlg);
2953                     break;
2954 
2955                 case IDC_FILETYPES_CHANGE:
2956                     pItem = GetListViewEntry(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
2957                     if (pItem)
2958                     {
2959                         Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT;
2960                         Info.pcszClass = pItem->FileExtension;
2961                         SHOpenWithDialog(hwndDlg, &Info);
2962                     }
2963                     break;
2964 
2965                 case IDC_FILETYPES_ADVANCED:
2966                     edittype.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
2967                     edittype.pEntry = GetListViewEntry(edittype.hwndLV);
2968                     DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_EDITTYPE),
2969                                     hwndDlg, EditTypeDlgProc, (LPARAM)&edittype);
2970                     break;
2971             }
2972             break;
2973 
2974         case WM_NOTIFY:
2975             lppl = (LPNMLISTVIEW) lParam;
2976             switch (lppl->hdr.code)
2977             {
2978                 case LVN_KEYDOWN:
2979                 {
2980                     LV_KEYDOWN *pKeyDown = (LV_KEYDOWN *)lParam;
2981                     if (pKeyDown->wVKey == VK_DELETE)
2982                     {
2983                         EditTypeDlg_OnDelete(hwndDlg);
2984                     }
2985                     break;
2986                 }
2987 
2988                 case NM_DBLCLK:
2989                     edittype.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
2990                     edittype.pEntry = GetListViewEntry(edittype.hwndLV);
2991                     DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_EDITTYPE),
2992                                     hwndDlg, EditTypeDlgProc, (LPARAM)&edittype);
2993                     break;
2994 
2995                 case LVN_DELETEALLITEMS:
2996                     return FALSE;   // send LVN_DELETEITEM
2997 
2998                 case LVN_DELETEITEM:
2999                     pItem = GetListViewEntry(lppl->hdr.hwndFrom, lppl->iItem);
3000                     if (pItem)
3001                     {
3002                         DestroyIcon(pItem->hIconLarge);
3003                         DestroyIcon(pItem->hIconSmall);
3004                         HeapFree(GetProcessHeap(), 0, pItem);
3005                     }
3006                     return FALSE;
3007 
3008                 case LVN_ITEMCHANGING:
3009                     pItem = GetListViewEntry(lppl->hdr.hwndFrom, lppl->iItem);
3010                     if (!pItem)
3011                     {
3012                         return TRUE;
3013                     }
3014 
3015                     if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
3016                     {
3017                         FileTypesDlg_OnItemChanging(hwndDlg, pItem);
3018                     }
3019                     break;
3020 
3021                 case PSN_SETACTIVE:
3022                     /* On page activation, set the focus to the listview */
3023                     SetFocus(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
3024                     break;
3025             }
3026             break;
3027     }
3028 
3029     return FALSE;
3030 }
3031 
3032 static
3033 VOID
3034 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst)
3035 {
3036     PROPSHEETHEADERW pinfo;
3037     HPROPSHEETPAGE hppages[3];
3038     HPROPSHEETPAGE hpage;
3039     UINT num_pages = 0;
3040     WCHAR szOptions[100];
3041 
3042     hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL);
3043     if (hpage)
3044         hppages[num_pages++] = hpage;
3045 
3046     hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL);
3047     if (hpage)
3048         hppages[num_pages++] = hpage;
3049 
3050     hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL);
3051     if (hpage)
3052         hppages[num_pages++] = hpage;
3053 
3054     szOptions[0] = L'\0';
3055     LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR));
3056     szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0';
3057 
3058     memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
3059     pinfo.dwSize = sizeof(PROPSHEETHEADERW);
3060     pinfo.dwFlags = PSH_NOCONTEXTHELP;
3061     pinfo.nPages = num_pages;
3062     pinfo.phpage = hppages;
3063     pinfo.pszCaption = szOptions;
3064 
3065     PropertySheetW(&pinfo);
3066 }
3067 
3068 static
3069 VOID
3070 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow)
3071 {
3072     switch(fOptions)
3073     {
3074         case 0:
3075             ShowFolderOptionsDialog(hWnd, hInst);
3076             break;
3077 
3078         case 1:
3079             // show taskbar options dialog
3080             FIXME("notify explorer to show taskbar options dialog");
3081             //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0);
3082             break;
3083 
3084         default:
3085             FIXME("unrecognized options id %d\n", fOptions);
3086     }
3087 }
3088 
3089 /*************************************************************************
3090  *              Options_RunDLL (SHELL32.@)
3091  */
3092 EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
3093 {
3094     Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
3095 }
3096 
3097 /*************************************************************************
3098  *              Options_RunDLLA (SHELL32.@)
3099  */
3100 EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
3101 {
3102     Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
3103 }
3104 
3105 /*************************************************************************
3106  *              Options_RunDLLW (SHELL32.@)
3107  */
3108 EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
3109 {
3110     Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow);
3111 }
3112