[SHELL32] Implement the 'Advanced' button of the 'File Types' dialog (#565)
[reactos.git] / dll / win32 / shell32 / dialogs / folder_options.cpp
1 /*
2 * Open With Context Menu extension
3 *
4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org>
5 * Copyright 2016-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "precomp.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL (fprop);
25
26 /// Folder Options:
27 /// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}
28 /// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210
29 /// Verbs: Open / RunAs
30 /// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0
31
32 /// ShellFolder Attributes: 0x0
33
34 typedef struct
35 {
36 WCHAR FileExtension[30];
37 WCHAR FileDescription[100];
38 WCHAR ClassKey[MAX_PATH];
39 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 }