[SHELL32] Implement Folder Options File Types 'Change' button (#629)
[reactos.git] / dll / win32 / shell32 / dialogs / filetypes.cpp
1 /*
2 * 'File Types' tab property sheet of Folder Options
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 // DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210
27 // Verbs: Open / RunAs
28 // Cmd: rundll32.exe shell32.dll,Options_RunDLL 0
29
30 /////////////////////////////////////////////////////////////////////////////
31
32 typedef struct FILE_TYPE_ENTRY
33 {
34 WCHAR FileExtension[30];
35 WCHAR FileDescription[100];
36 WCHAR ClassKey[MAX_PATH];
37 WCHAR ClassName[64];
38 DWORD EditFlags;
39 WCHAR AppName[64];
40 HICON hIconLarge;
41 HICON hIconSmall;
42 WCHAR ProgramPath[MAX_PATH];
43 WCHAR IconPath[MAX_PATH];
44 INT nIconIndex;
45 } FILE_TYPE_ENTRY, *PFILE_TYPE_ENTRY;
46
47 static BOOL
48 DeleteExt(HWND hwndDlg, LPCWSTR pszExt)
49 {
50 if (*pszExt != L'.')
51 return FALSE;
52
53 // open ".ext" key
54 HKEY hKey;
55 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
56 return FALSE;
57
58 // query "extfile" key name
59 WCHAR szValue[64] = { 0 };
60 DWORD cbValue = sizeof(szValue);
61 RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(szValue), &cbValue);
62 RegCloseKey(hKey);
63
64 // delete "extfile" key (if any)
65 if (szValue[0])
66 SHDeleteKeyW(HKEY_CLASSES_ROOT, szValue);
67
68 // delete ".ext" key
69 return SHDeleteKeyW(HKEY_CLASSES_ROOT, pszExt) == ERROR_SUCCESS;
70 }
71
72 static inline HICON
73 DoExtractIcon(PFILE_TYPE_ENTRY Entry, LPCWSTR IconPath,
74 INT iIndex = 0, BOOL bSmall = FALSE)
75 {
76 HICON hIcon = NULL;
77
78 if (iIndex < 0)
79 {
80 // A negative value will be interpreted as a negated resource ID.
81 iIndex = -iIndex;
82
83 INT cx, cy;
84 HINSTANCE hDLL = LoadLibraryExW(IconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
85 if (bSmall)
86 {
87 cx = GetSystemMetrics(SM_CXSMICON);
88 cy = GetSystemMetrics(SM_CYSMICON);
89 }
90 else
91 {
92 cx = GetSystemMetrics(SM_CXICON);
93 cy = GetSystemMetrics(SM_CYICON);
94 }
95 hIcon = HICON(LoadImageW(hDLL, MAKEINTRESOURCEW(iIndex), IMAGE_ICON,
96 cx, cy, 0));
97 FreeLibrary(hDLL);
98 }
99 else
100 {
101 // A positive value is icon index.
102 if (bSmall)
103 ExtractIconExW(IconPath, iIndex, NULL, &hIcon, 1);
104 else
105 ExtractIconExW(IconPath, iIndex, &hIcon, NULL, 1);
106 }
107 return hIcon;
108 }
109
110 static void
111 DoFileTypeIconLocation(PFILE_TYPE_ENTRY Entry, LPCWSTR IconLocation)
112 {
113 // Expand the REG_EXPAND_SZ string by environment variables
114 WCHAR szLocation[MAX_PATH + 32];
115 if (!ExpandEnvironmentStringsW(IconLocation, szLocation, _countof(szLocation)))
116 return;
117
118 Entry->nIconIndex = PathParseIconLocationW(szLocation);
119 StringCbCopyW(Entry->IconPath, sizeof(Entry->IconPath), szLocation);
120 Entry->hIconLarge = DoExtractIcon(Entry, szLocation, Entry->nIconIndex, FALSE);
121 Entry->hIconSmall = DoExtractIcon(Entry, szLocation, Entry->nIconIndex, TRUE);
122 }
123
124 static BOOL
125 GetFileTypeIconsEx(PFILE_TYPE_ENTRY Entry, LPCWSTR IconLocation)
126 {
127 Entry->hIconLarge = Entry->hIconSmall = NULL;
128
129 if (lstrcmpiW(Entry->FileExtension, L".exe") == 0 ||
130 lstrcmpiW(Entry->FileExtension, L".scr") == 0)
131 {
132 // It's an executable
133 Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE));
134 INT cx = GetSystemMetrics(SM_CXSMICON);
135 INT cy = GetSystemMetrics(SM_CYSMICON);
136 Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE),
137 IMAGE_ICON, cx, cy, 0));
138 StringCbCopyW(Entry->IconPath, sizeof(Entry->IconPath), g_pszShell32);
139 Entry->nIconIndex = -IDI_SHELL_EXE;
140 }
141 else if (lstrcmpW(IconLocation, L"%1") == 0)
142 {
143 return FALSE; // self icon
144 }
145 else
146 {
147 DoFileTypeIconLocation(Entry, IconLocation);
148 }
149
150 return Entry->hIconLarge && Entry->hIconSmall;
151 }
152
153 static BOOL
154 GetFileTypeIconsByKey(HKEY hKey, PFILE_TYPE_ENTRY Entry)
155 {
156 Entry->hIconLarge = Entry->hIconSmall = NULL;
157
158 // Open the "DefaultIcon" registry key
159 HKEY hDefIconKey;
160 LONG nResult = RegOpenKeyExW(hKey, L"DefaultIcon", 0, KEY_READ, &hDefIconKey);
161 if (nResult != ERROR_SUCCESS)
162 return FALSE;
163
164 // Get the icon location
165 WCHAR szLocation[MAX_PATH + 32] = { 0 };
166 DWORD dwSize = sizeof(szLocation);
167 nResult = RegQueryValueExW(hDefIconKey, NULL, NULL, NULL, LPBYTE(szLocation), &dwSize);
168
169 RegCloseKey(hDefIconKey);
170
171 if (nResult != ERROR_SUCCESS || szLocation[0] == 0)
172 return FALSE;
173
174 return GetFileTypeIconsEx(Entry, szLocation);
175 }
176
177 static BOOL
178 QueryFileDescription(LPCWSTR ProgramPath, LPWSTR pszName, INT cchName)
179 {
180 SHFILEINFOW FileInfo = { 0 };
181 if (SHGetFileInfoW(ProgramPath, 0, &FileInfo, sizeof(FileInfo), SHGFI_DISPLAYNAME))
182 {
183 StringCchCopyW(pszName, cchName, FileInfo.szDisplayName);
184 return TRUE;
185 }
186
187 return !!GetFileTitleW(ProgramPath, pszName, cchName);
188 }
189
190 static void
191 SetFileTypeEntryDefaultIcon(PFILE_TYPE_ENTRY Entry)
192 {
193 Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS));
194 INT cxSmall = GetSystemMetrics(SM_CXSMICON);
195 INT cySmall = GetSystemMetrics(SM_CYSMICON);
196 Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS),
197 IMAGE_ICON, cxSmall, cySmall, 0));
198 StringCbCopyW(Entry->IconPath, sizeof(Entry->IconPath), g_pszShell32);
199 Entry->nIconIndex = -IDI_SHELL_FOLDER_OPTIONS;
200 }
201
202 /////////////////////////////////////////////////////////////////////////////
203 // EditTypeDlg
204
205 #define LISTBOX_MARGIN 2
206
207 typedef struct EDITTYPE_DIALOG
208 {
209 HWND hwndLV;
210 PFILE_TYPE_ENTRY pEntry;
211 CSimpleMap<CStringW, CStringW> CommandLineMap;
212 WCHAR szIconPath[MAX_PATH];
213 INT nIconIndex;
214 WCHAR szDefaultVerb[64];
215 } EDITTYPE_DIALOG, *PEDITTYPE_DIALOG;
216
217 static void
218 EditTypeDlg_OnChangeIcon(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
219 {
220 WCHAR szPath[MAX_PATH];
221 INT IconIndex;
222
223 ExpandEnvironmentStringsW(pEditType->szIconPath, szPath, _countof(szPath));
224 IconIndex = pEditType->nIconIndex;
225 if (PickIconDlg(hwndDlg, szPath, _countof(szPath), &IconIndex))
226 {
227 // replace Windows directory with "%SystemRoot%" (for portability)
228 WCHAR szWinDir[MAX_PATH];
229 GetWindowsDirectoryW(szWinDir, _countof(szWinDir));
230 if (wcsstr(szPath, szWinDir) == 0)
231 {
232 CStringW str(L"%SystemRoot%");
233 str += &szPath[wcslen(szWinDir)];
234 StringCbCopyW(szPath, sizeof(szPath), LPCWSTR(str));
235 }
236
237 // update FILE_TYPE_ENTRY
238 PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
239 DestroyIcon(pEntry->hIconLarge);
240 DestroyIcon(pEntry->hIconSmall);
241 pEntry->hIconLarge = DoExtractIcon(pEntry, szPath, IconIndex, FALSE);
242 pEntry->hIconSmall = DoExtractIcon(pEntry, szPath, IconIndex, TRUE);
243
244 // update EDITTYPE_DIALOG
245 StringCbCopyW(pEditType->szIconPath, sizeof(pEditType->szIconPath), szPath);
246 pEditType->nIconIndex = IconIndex;
247
248 // set icon to dialog
249 SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_ICON, STM_SETICON, (WPARAM)pEntry->hIconLarge, 0);
250 }
251 }
252
253 static BOOL
254 EditTypeDlg_OnDrawItem(HWND hwndDlg, LPDRAWITEMSTRUCT pDraw, PEDITTYPE_DIALOG pEditType)
255 {
256 WCHAR szText[64];
257 HFONT hFont, hFont2;
258
259 if (!pDraw)
260 return FALSE;
261
262 // fill rect and set colors
263 if (pDraw->itemState & ODS_SELECTED)
264 {
265 FillRect(pDraw->hDC, &pDraw->rcItem, HBRUSH(COLOR_HIGHLIGHT + 1));
266 SetTextColor(pDraw->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
267 SetBkColor(pDraw->hDC, GetSysColor(COLOR_HIGHLIGHT));
268 }
269 else
270 {
271 FillRect(pDraw->hDC, &pDraw->rcItem, HBRUSH(COLOR_WINDOW + 1));
272 SetTextColor(pDraw->hDC, GetSysColor(COLOR_WINDOWTEXT));
273 SetBkColor(pDraw->hDC, GetSysColor(COLOR_WINDOW));
274 }
275
276 // get listbox text
277 HWND hwndListBox = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
278 SendMessageW(hwndListBox, LB_GETTEXT, pDraw->itemID, (LPARAM)szText);
279
280 // is it default?
281 hFont = (HFONT)SendMessageW(hwndListBox, WM_GETFONT, 0, 0);
282 if (lstrcmpiW(pEditType->szDefaultVerb, szText) == 0)
283 {
284 // default. set bold
285 LOGFONTW lf;
286 GetObject(hFont, sizeof(lf), &lf);
287 lf.lfWeight = FW_BOLD;
288 hFont2 = CreateFontIndirectW(&lf);
289 if (hFont2)
290 {
291 HGDIOBJ hFontOld = SelectObject(pDraw->hDC, hFont2);
292 InflateRect(&pDraw->rcItem, -LISTBOX_MARGIN, -LISTBOX_MARGIN);
293 DrawTextW(pDraw->hDC, szText, -1, &pDraw->rcItem,
294 DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
295 InflateRect(&pDraw->rcItem, LISTBOX_MARGIN, LISTBOX_MARGIN);
296 SelectObject(pDraw->hDC, hFontOld);
297 DeleteObject(hFont2);
298 }
299 }
300 else
301 {
302 // non-default
303 InflateRect(&pDraw->rcItem, -LISTBOX_MARGIN, -LISTBOX_MARGIN);
304 DrawTextW(pDraw->hDC, szText, -1, &pDraw->rcItem,
305 DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
306 InflateRect(&pDraw->rcItem, LISTBOX_MARGIN, LISTBOX_MARGIN);
307 }
308
309 // draw focus rect
310 if (pDraw->itemState & ODS_FOCUS)
311 {
312 DrawFocusRect(pDraw->hDC, &pDraw->rcItem);
313 }
314 return TRUE;
315 }
316
317 static BOOL
318 EditTypeDlg_OnMeasureItem(HWND hwndDlg, LPMEASUREITEMSTRUCT pMeasure, PEDITTYPE_DIALOG pEditType)
319 {
320 if (!pMeasure)
321 return FALSE;
322
323 HWND hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
324
325 HDC hDC = GetDC(hwndLB);
326 if (hDC)
327 {
328 TEXTMETRICW tm;
329 GetTextMetricsW(hDC, &tm);
330 pMeasure->itemHeight = tm.tmHeight + LISTBOX_MARGIN * 2;
331 ReleaseDC(hwndLB, hDC);
332 return TRUE;
333 }
334 return FALSE;
335 }
336
337 /////////////////////////////////////////////////////////////////////////////
338 // NewExtDlg
339
340 typedef struct NEWEXT_DIALOG
341 {
342 HWND hwndLV;
343 RECT rcDlg;
344 BOOL bAdvanced;
345 INT dy;
346 WCHAR szExt[16];
347 WCHAR szFileType[64];
348 } NEWEXT_DIALOG, *PNEWEXT_DIALOG;
349
350 static VOID
351 NewExtDlg_OnAdvanced(HWND hwndDlg, PNEWEXT_DIALOG pNewExt)
352 {
353 // If "Advanced" button was clicked, then we shrink or expand the dialog.
354 RECT rc, rc1, rc2;
355
356 GetWindowRect(hwndDlg, &rc);
357 rc.bottom = rc.top + (pNewExt->rcDlg.bottom - pNewExt->rcDlg.top);
358
359 GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc1);
360 MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc1, 2);
361
362 GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rc2);
363 MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc2, 2);
364
365 if (pNewExt->bAdvanced)
366 {
367 rc1.top += pNewExt->dy;
368 rc1.bottom += pNewExt->dy;
369
370 rc2.top += pNewExt->dy;
371 rc2.bottom += pNewExt->dy;
372
373 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_SHOWNOACTIVATE);
374 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_SHOWNOACTIVATE);
375
376 CStringW strLeft(MAKEINTRESOURCEW(IDS_NEWEXT_ADVANCED_LEFT));
377 SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, strLeft);
378
379 SetFocus(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX));
380 }
381 else
382 {
383 rc1.top -= pNewExt->dy;
384 rc1.bottom -= pNewExt->dy;
385
386 rc2.top -= pNewExt->dy;
387 rc2.bottom -= pNewExt->dy;
388
389 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_HIDE);
390 ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_HIDE);
391
392 CStringW strRight(MAKEINTRESOURCEW(IDS_NEWEXT_ADVANCED_RIGHT));
393 SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, strRight);
394
395 rc.bottom -= pNewExt->dy;
396
397 CStringW strText(MAKEINTRESOURCEW(IDS_NEWEXT_NEW));
398 SetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, strText);
399 }
400
401 HDWP hDWP = BeginDeferWindowPos(3);
402
403 if (hDWP)
404 hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDOK), NULL,
405 rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
406 SWP_NOACTIVATE | SWP_NOZORDER);
407 if (hDWP)
408 hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDCANCEL), NULL,
409 rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top,
410 SWP_NOACTIVATE | SWP_NOZORDER);
411 if (hDWP)
412 hDWP = DeferWindowPos(hDWP, hwndDlg, NULL,
413 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
414 SWP_NOACTIVATE | SWP_NOZORDER);
415
416 if (hDWP)
417 EndDeferWindowPos(hDWP);
418 }
419
420 static BOOL
421 NewExtDlg_OnInitDialog(HWND hwndDlg, PNEWEXT_DIALOG pNewExt)
422 {
423 pNewExt->bAdvanced = FALSE;
424
425 // get window rectangle
426 GetWindowRect(hwndDlg, &pNewExt->rcDlg);
427
428 // get delta Y
429 RECT rc1, rc2;
430 GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_EDIT), &rc1);
431 GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), &rc2);
432 pNewExt->dy = rc2.top - rc1.top;
433
434 // initialize
435 CStringW strText(MAKEINTRESOURCEW(IDS_NEWEXT_NEW));
436 SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_ADDSTRING, 0, (LPARAM)(LPCWSTR)strText);
437 SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_SETCURSEL, 0, 0);
438 SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_EDIT, EM_SETLIMITTEXT, _countof(pNewExt->szExt) - 1, 0);
439
440 // shrink it first time
441 NewExtDlg_OnAdvanced(hwndDlg, pNewExt);
442
443 return TRUE;
444 }
445
446 static BOOL
447 NewExtDlg_OnOK(HWND hwndDlg, PNEWEXT_DIALOG pNewExt)
448 {
449 LV_FINDINFO find;
450 INT iItem;
451
452 GetDlgItemTextW(hwndDlg, IDC_NEWEXT_EDIT, pNewExt->szExt, _countof(pNewExt->szExt));
453 StrTrimW(pNewExt->szExt, g_pszSpace);
454 _wcsupr(pNewExt->szExt);
455
456 GetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, pNewExt->szFileType, _countof(pNewExt->szFileType));
457 StrTrimW(pNewExt->szFileType, g_pszSpace);
458
459 if (pNewExt->szExt[0] == 0)
460 {
461 CStringW strText(MAKEINTRESOURCEW(IDS_NEWEXT_SPECIFY_EXT));
462 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
463 MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
464 return FALSE;
465 }
466
467 ZeroMemory(&find, sizeof(find));
468 find.flags = LVFI_STRING;
469 if (pNewExt->szExt[0] == L'.')
470 {
471 find.psz = &pNewExt->szExt[1];
472 }
473 else
474 {
475 find.psz = pNewExt->szExt;
476 }
477
478 iItem = ListView_FindItem(pNewExt->hwndLV, -1, &find);
479 if (iItem >= 0)
480 {
481 // already exists
482
483 // get file type
484 WCHAR szFileType[64];
485 LV_ITEM item;
486 ZeroMemory(&item, sizeof(item));
487 item.mask = LVIF_TEXT;
488 item.pszText = szFileType;
489 item.cchTextMax = _countof(szFileType);
490 item.iItem = iItem;
491 item.iSubItem = 1;
492 ListView_GetItem(pNewExt->hwndLV, &item);
493
494 // get text
495 CStringW strText;
496 strText.Format(IDS_NEWEXT_ALREADY_ASSOC, find.psz, szFileType, find.psz, szFileType);
497
498 // get title
499 CStringW strTitle;
500 strTitle.LoadString(IDS_NEWEXT_EXT_IN_USE);
501
502 if (MessageBoxW(hwndDlg, strText, strTitle, MB_ICONWARNING | MB_YESNO) == IDNO)
503 {
504 return FALSE;
505 }
506
507 // Delete the extension
508 CStringW strExt(L".");
509 strExt += find.psz;
510 strExt.MakeLower();
511 DeleteExt(hwndDlg, strExt);
512
513 // Delete the item
514 ListView_DeleteItem(pNewExt->hwndLV, iItem);
515 }
516
517 EndDialog(hwndDlg, IDOK);
518 return TRUE;
519 }
520
521 // IDD_NEWEXTENSION
522 static INT_PTR CALLBACK
523 NewExtDlgProc(
524 HWND hwndDlg,
525 UINT uMsg,
526 WPARAM wParam,
527 LPARAM lParam)
528 {
529 static PNEWEXT_DIALOG s_pNewExt = NULL;
530
531 switch (uMsg)
532 {
533 case WM_INITDIALOG:
534 s_pNewExt = (PNEWEXT_DIALOG)lParam;
535 NewExtDlg_OnInitDialog(hwndDlg, s_pNewExt);
536 return TRUE;
537
538 case WM_COMMAND:
539 switch (LOWORD(wParam))
540 {
541 case IDOK:
542 NewExtDlg_OnOK(hwndDlg, s_pNewExt);
543 break;
544
545 case IDCANCEL:
546 EndDialog(hwndDlg, IDCANCEL);
547 break;
548
549 case IDC_NEWEXT_ADVANCED:
550 s_pNewExt->bAdvanced = !s_pNewExt->bAdvanced;
551 NewExtDlg_OnAdvanced(hwndDlg, s_pNewExt);
552 break;
553 }
554 break;
555 }
556 return 0;
557 }
558
559 static BOOL
560 FileTypesDlg_InsertToLV(HWND hListView, LPCWSTR szName, INT iItem, LPCWSTR szFile)
561 {
562 PFILE_TYPE_ENTRY Entry;
563 HKEY hKey;
564 LVITEMW lvItem;
565 DWORD dwSize;
566 DWORD dwType;
567
568 if (szName[0] != L'.')
569 {
570 // FIXME handle URL protocol handlers
571 return FALSE;
572 }
573
574 // get imagelists of listview
575 HIMAGELIST himlLarge = ListView_GetImageList(hListView, LVSIL_NORMAL);
576 HIMAGELIST himlSmall = ListView_GetImageList(hListView, LVSIL_SMALL);
577
578 // allocate file type entry
579 Entry = (PFILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FILE_TYPE_ENTRY));
580 if (!Entry)
581 return FALSE;
582
583 // open key
584 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
585 {
586 HeapFree(GetProcessHeap(), 0, Entry);
587 return FALSE;
588 }
589
590 // FIXME check for duplicates
591
592 // query for the default key
593 dwSize = sizeof(Entry->ClassKey);
594 if (RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(Entry->ClassKey), &dwSize) != ERROR_SUCCESS)
595 {
596 // no link available
597 Entry->ClassKey[0] = 0;
598 }
599
600 Entry->ClassName[0] = 0;
601 if (Entry->ClassKey[0])
602 {
603 HKEY hTemp;
604 // try open linked key
605 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS)
606 {
607 DWORD dwSize = sizeof(Entry->ClassName);
608 RegQueryValueExW(hTemp, NULL, NULL, NULL, LPBYTE(Entry->ClassName), &dwSize);
609
610 // use linked key
611 RegCloseKey(hKey);
612 hKey = hTemp;
613 }
614 }
615
616 // read friendly type name
617 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription,
618 sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS)
619 {
620 // read file description
621 dwSize = sizeof(Entry->FileDescription);
622 Entry->FileDescription[0] = 0;
623
624 // read default key
625 RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(Entry->FileDescription), &dwSize);
626 }
627
628 // Read the EditFlags value
629 Entry->EditFlags = 0;
630 if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize))
631 {
632 if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD))
633 RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize);
634 }
635
636 // convert extension to upper case
637 wcscpy(Entry->FileExtension, szName);
638 _wcsupr(Entry->FileExtension);
639
640 // get icon
641 if (!GetFileTypeIconsByKey(hKey, Entry))
642 {
643 // set default icon
644 SetFileTypeEntryDefaultIcon(Entry);
645 }
646
647 // close key
648 RegCloseKey(hKey);
649
650 // get program path and app name
651 DWORD cch = _countof(Entry->ProgramPath);
652 if (S_OK == AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE,
653 Entry->FileExtension, NULL, Entry->ProgramPath, &cch))
654 {
655 QueryFileDescription(Entry->ProgramPath, Entry->AppName, _countof(Entry->AppName));
656 }
657 else
658 {
659 Entry->ProgramPath[0] = Entry->AppName[0] = 0;
660 }
661
662 // add icon to imagelist
663 INT iLargeImage = -1, iSmallImage = -1;
664 if (Entry->hIconLarge && Entry->hIconSmall)
665 {
666 iLargeImage = ImageList_AddIcon(himlLarge, Entry->hIconLarge);
667 iSmallImage = ImageList_AddIcon(himlSmall, Entry->hIconSmall);
668 ASSERT(iLargeImage == iSmallImage);
669 }
670
671 // Do not add excluded entries
672 if (Entry->EditFlags & 0x00000001) //FTA_Exclude
673 {
674 DestroyIcon(Entry->hIconLarge);
675 DestroyIcon(Entry->hIconSmall);
676 HeapFree(GetProcessHeap(), 0, Entry);
677 return FALSE;
678 }
679
680 if (!Entry->FileDescription[0])
681 {
682 // construct default 'FileExtensionFile' by formatting the uppercase extension
683 // with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File'
684
685 StringCbPrintf(Entry->FileDescription, sizeof(Entry->FileDescription), szFile, &Entry->FileExtension[1]);
686 }
687
688 ZeroMemory(&lvItem, sizeof(LVITEMW));
689 lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
690 lvItem.iSubItem = 0;
691 lvItem.pszText = &Entry->FileExtension[1];
692 lvItem.iItem = iItem;
693 lvItem.lParam = (LPARAM)Entry;
694 lvItem.iImage = iSmallImage;
695 SendMessageW(hListView, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
696
697 ZeroMemory(&lvItem, sizeof(LVITEMW));
698 lvItem.mask = LVIF_TEXT;
699 lvItem.pszText = Entry->FileDescription;
700 lvItem.iItem = iItem;
701 lvItem.iSubItem = 1;
702 ListView_SetItem(hListView, &lvItem);
703
704 return TRUE;
705 }
706
707 static BOOL
708 FileTypesDlg_AddExt(HWND hwndDlg, LPCWSTR pszExt, LPCWSTR pszFileType)
709 {
710 DWORD dwValue = 1;
711 HKEY hKey;
712 WCHAR szKey[13]; // max. "ft4294967295" + "\0"
713 LONG nResult;
714
715 // Search the next "ft%06u" key name
716 do
717 {
718 StringCbPrintfW(szKey, sizeof(szKey), L"ft%06u", dwValue);
719
720 nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hKey);
721 if (nResult != ERROR_SUCCESS)
722 break;
723
724 RegCloseKey(hKey);
725 ++dwValue;
726 } while (dwValue != 0);
727
728 RegCloseKey(hKey);
729
730 if (dwValue == 0)
731 return FALSE;
732
733 // Create new "ft%06u" key
734 nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
735 if (ERROR_SUCCESS != nResult)
736 return FALSE;
737
738 RegCloseKey(hKey);
739
740 // Create the ".ext" key
741 WCHAR szExt[16];
742 if (*pszExt == L'.')
743 ++pszExt;
744 StringCbPrintfW(szExt, sizeof(szExt), L".%s", pszExt);
745 _wcslwr(szExt);
746 nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
747 _wcsupr(szExt);
748 if (ERROR_SUCCESS != nResult)
749 return FALSE;
750
751 // Set the default value of ".ext" to "ft%06u"
752 DWORD dwSize = (lstrlen(szKey) + 1) * sizeof(WCHAR);
753 RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)szKey, dwSize);
754
755 RegCloseKey(hKey);
756
757 // Make up the file type name
758 WCHAR szFile[100];
759 CStringW strFormat(MAKEINTRESOURCEW(IDS_FILE_EXT_TYPE));
760 StringCbPrintfW(szFile, sizeof(szFile), strFormat, &szExt[1]);
761
762 // Insert an item to the listview
763 HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
764 INT iItem = ListView_GetItemCount(hListView);
765 if (!FileTypesDlg_InsertToLV(hListView, szExt, iItem, szFile))
766 return FALSE;
767
768 LV_ITEM item;
769 ZeroMemory(&item, sizeof(item));
770 item.mask = LVIF_STATE | LVIF_TEXT;
771 item.iItem = iItem;
772 item.state = LVIS_SELECTED | LVIS_FOCUSED;
773 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
774 item.pszText = &szExt[1];
775 ListView_SetItem(hListView, &item);
776
777 item.pszText = szFile;
778 item.iSubItem = 1;
779 ListView_SetItem(hListView, &item);
780
781 ListView_EnsureVisible(hListView, iItem, FALSE);
782
783 return TRUE;
784 }
785
786 static BOOL
787 FileTypesDlg_RemoveExt(HWND hwndDlg)
788 {
789 HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
790
791 INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
792 if (iItem == -1)
793 return FALSE;
794
795 WCHAR szExt[20];
796 szExt[0] = L'.';
797 ListView_GetItemText(hListView, iItem, 0, &szExt[1], _countof(szExt) - 1);
798 _wcslwr(szExt);
799
800 DeleteExt(hwndDlg, szExt);
801 ListView_DeleteItem(hListView, iItem);
802 return TRUE;
803 }
804
805 /////////////////////////////////////////////////////////////////////////////
806 // common code of NewActionDlg and EditActionDlg
807
808 typedef struct ACTION_DIALOG
809 {
810 HWND hwndLB;
811 WCHAR ClassName[64];
812 WCHAR szAction[64];
813 WCHAR szApp[MAX_PATH];
814 BOOL bUseDDE;
815 } ACTION_DIALOG, *PACTION_DIALOG;
816
817 static void
818 ActionDlg_OnBrowse(HWND hwndDlg, PACTION_DIALOG pNewAct, BOOL bEdit = FALSE)
819 {
820 WCHAR szFile[MAX_PATH];
821 szFile[0] = 0;
822
823 WCHAR szFilter[MAX_PATH];
824 LoadStringW(shell32_hInstance, IDS_EXE_FILTER, szFilter, _countof(szFilter));
825
826 CStringW strTitle(MAKEINTRESOURCEW(IDS_OPEN_WITH));
827
828 OPENFILENAMEW ofn;
829 ZeroMemory(&ofn, sizeof(ofn));
830 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
831 ofn.hwndOwner = hwndDlg;
832 ofn.lpstrFilter = szFilter;
833 ofn.lpstrFile = szFile;
834 ofn.nMaxFile = _countof(szFile);
835 ofn.lpstrTitle = strTitle;
836 ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
837 ofn.lpstrDefExt = L"exe";
838 if (GetOpenFileNameW(&ofn))
839 {
840 if (bEdit)
841 {
842 CStringW str = szFile;
843 str += L" \"%1\"";
844 SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, str);
845 }
846 else
847 {
848 SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, szFile);
849 }
850 }
851 }
852
853 /////////////////////////////////////////////////////////////////////////////
854 // NewActionDlg
855
856 static void
857 NewActionDlg_OnOK(HWND hwndDlg, PACTION_DIALOG pNewAct)
858 {
859 // check action
860 GetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, pNewAct->szAction, _countof(pNewAct->szAction));
861 StrTrimW(pNewAct->szAction, g_pszSpace);
862 if (pNewAct->szAction[0] == 0)
863 {
864 // action was empty, error
865 HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
866 SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
867 SetFocus(hwndCtrl);
868 CStringW strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION));
869 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
870 MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
871 return;
872 }
873
874 // check app
875 GetDlgItemTextW(hwndDlg, IDC_ACTION_APP, pNewAct->szApp, _countof(pNewAct->szApp));
876 StrTrimW(pNewAct->szApp, g_pszSpace);
877 if (pNewAct->szApp[0] == 0 ||
878 GetFileAttributesW(pNewAct->szApp) == INVALID_FILE_ATTRIBUTES)
879 {
880 // app was empty or invalid
881 HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_APP);
882 SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
883 SetFocus(hwndCtrl);
884 CStringW strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM));
885 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
886 MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
887 return;
888 }
889
890 EndDialog(hwndDlg, IDOK);
891 }
892
893 // IDD_ACTION
894 static INT_PTR CALLBACK
895 NewActionDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
896 {
897 static PACTION_DIALOG s_pNewAct = NULL;
898
899 switch (uMsg)
900 {
901 case WM_INITDIALOG:
902 s_pNewAct = (PACTION_DIALOG)lParam;
903 s_pNewAct->bUseDDE = FALSE;
904 EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_USE_DDE), FALSE);
905 return TRUE;
906
907 case WM_COMMAND:
908 switch (LOWORD(wParam))
909 {
910 case IDOK:
911 NewActionDlg_OnOK(hwndDlg, s_pNewAct);
912 break;
913
914 case IDCANCEL:
915 EndDialog(hwndDlg, IDCANCEL);
916 break;
917
918 case IDC_ACTION_BROWSE:
919 ActionDlg_OnBrowse(hwndDlg, s_pNewAct, FALSE);
920 break;
921 }
922 break;
923 }
924 return 0;
925 }
926
927 /////////////////////////////////////////////////////////////////////////////
928 // EditActionDlg
929
930 static void
931 EditActionDlg_OnOK(HWND hwndDlg, PACTION_DIALOG pEditAct)
932 {
933 // check action
934 GetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, pEditAct->szAction, _countof(pEditAct->szAction));
935 StrTrimW(pEditAct->szAction, g_pszSpace);
936 if (pEditAct->szAction[0] == 0)
937 {
938 // action was empty. show error
939 HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
940 SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
941 SetFocus(hwndCtrl);
942 CStringW strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION));
943 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
944 MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
945 }
946
947 // check app
948 GetDlgItemTextW(hwndDlg, IDC_ACTION_APP, pEditAct->szApp, _countof(pEditAct->szApp));
949 StrTrimW(pEditAct->szApp, g_pszSpace);
950 if (pEditAct->szApp[0] == 0)
951 {
952 // app was empty. show error
953 HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_APP);
954 SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
955 SetFocus(hwndCtrl);
956 CStringW strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM));
957 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
958 MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
959 }
960
961 EndDialog(hwndDlg, IDOK);
962 }
963
964 // IDD_ACTION
965 static INT_PTR CALLBACK
966 EditActionDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
967 {
968 static PACTION_DIALOG s_pEditAct = NULL;
969
970 switch (uMsg)
971 {
972 case WM_INITDIALOG:
973 s_pEditAct = (PACTION_DIALOG)lParam;
974 s_pEditAct->bUseDDE = FALSE;
975 SetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, s_pEditAct->szAction);
976 SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, s_pEditAct->szApp);
977 EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_USE_DDE), FALSE);
978 EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_ACTION), FALSE);
979 {
980 // set title
981 CStringW str(MAKEINTRESOURCEW(IDS_EDITING_ACTION));
982 str += s_pEditAct->ClassName;
983 SetWindowTextW(hwndDlg, str);
984 }
985 return TRUE;
986
987 case WM_COMMAND:
988 switch (LOWORD(wParam))
989 {
990 case IDOK:
991 EditActionDlg_OnOK(hwndDlg, s_pEditAct);
992 break;
993
994 case IDCANCEL:
995 EndDialog(hwndDlg, IDCANCEL);
996 break;
997
998 case IDC_ACTION_BROWSE:
999 ActionDlg_OnBrowse(hwndDlg, s_pEditAct, TRUE);
1000 break;
1001 }
1002 break;
1003 }
1004 return 0;
1005 }
1006
1007 /////////////////////////////////////////////////////////////////////////////
1008 // EditTypeDlg
1009
1010 static BOOL
1011 EditTypeDlg_UpdateEntryIcon(HWND hwndDlg, PEDITTYPE_DIALOG pEditType,
1012 LPCWSTR IconPath, INT IconIndex)
1013 {
1014 PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
1015
1016 BOOL bIconSet = FALSE;
1017 if (IconPath && IconPath[0])
1018 {
1019 DestroyIcon(pEntry->hIconLarge);
1020 DestroyIcon(pEntry->hIconSmall);
1021 pEntry->hIconLarge = DoExtractIcon(pEntry, IconPath, IconIndex, FALSE);
1022 pEntry->hIconSmall = DoExtractIcon(pEntry, IconPath, IconIndex, TRUE);
1023
1024 bIconSet = (pEntry->hIconLarge && pEntry->hIconSmall);
1025 }
1026 if (bIconSet)
1027 {
1028 StringCbCopyW(pEntry->IconPath, sizeof(pEntry->IconPath), IconPath);
1029 pEntry->nIconIndex = IconIndex;
1030 }
1031 else
1032 {
1033 SetFileTypeEntryDefaultIcon(pEntry);
1034 }
1035
1036 HWND hListView = pEditType->hwndLV;
1037 HIMAGELIST himlLarge = ListView_GetImageList(hListView, LVSIL_NORMAL);
1038 HIMAGELIST himlSmall = ListView_GetImageList(hListView, LVSIL_SMALL);
1039
1040 INT iLargeImage = ImageList_AddIcon(himlLarge, pEntry->hIconLarge);
1041 INT iSmallImage = ImageList_AddIcon(himlSmall, pEntry->hIconSmall);
1042 ASSERT(iLargeImage == iSmallImage);
1043
1044 INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
1045 if (iItem != -1)
1046 {
1047 LV_ITEMW Item = { LVIF_IMAGE, iItem };
1048 Item.iImage = iSmallImage;
1049 ListView_SetItem(hListView, &Item);
1050 }
1051 return TRUE;
1052 }
1053
1054 static BOOL
1055 EditTypeDlg_WriteClass(HWND hwndDlg, PEDITTYPE_DIALOG pEditType,
1056 LPCWSTR ClassKey, LPCWSTR ClassName, INT cchName)
1057 {
1058 PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
1059
1060 if (ClassKey[0] == 0)
1061 return FALSE;
1062
1063 // create or open class key
1064 HKEY hClassKey;
1065 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, ClassKey, 0, NULL, 0, KEY_WRITE, NULL,
1066 &hClassKey, NULL) != ERROR_SUCCESS)
1067 {
1068 return FALSE;
1069 }
1070
1071 // create "DefaultIcon" key
1072 if (pEntry->IconPath[0])
1073 {
1074 HKEY hDefaultIconKey;
1075 if (RegCreateKeyExW(hClassKey, L"DefaultIcon", 0, NULL, 0, KEY_WRITE, NULL,
1076 &hDefaultIconKey, NULL) == ERROR_SUCCESS)
1077 {
1078 WCHAR szText[MAX_PATH];
1079 StringCbPrintfW(szText, sizeof(szText), L"%s,%d",
1080 pEntry->IconPath, pEntry->nIconIndex);
1081
1082 // set icon location
1083 DWORD dwSize = (lstrlenW(szText) + 1) * sizeof(WCHAR);
1084 RegSetValueExW(hDefaultIconKey, NULL, 0, REG_EXPAND_SZ, LPBYTE(szText), dwSize);
1085
1086 RegCloseKey(hDefaultIconKey);
1087 }
1088 }
1089
1090 // create "shell" key
1091 HKEY hShellKey;
1092 if (RegCreateKeyExW(hClassKey, L"shell", 0, NULL, 0, KEY_WRITE, NULL,
1093 &hShellKey, NULL) != ERROR_SUCCESS)
1094 {
1095 RegCloseKey(hClassKey);
1096 return FALSE;
1097 }
1098
1099 // delete shell commands
1100 WCHAR szVerbName[64];
1101 DWORD dwIndex = 0;
1102 while (RegEnumKeyW(hShellKey, dwIndex, szVerbName, _countof(szVerbName)) == ERROR_SUCCESS)
1103 {
1104 if (pEditType->CommandLineMap.FindKey(szVerbName) == -1)
1105 {
1106 // doesn't exist in CommandLineMap, then delete it
1107 if (SHDeleteKeyW(hShellKey, szVerbName) == ERROR_SUCCESS)
1108 {
1109 --dwIndex;
1110 }
1111 }
1112 ++dwIndex;
1113 }
1114
1115 // set default action
1116 RegSetValueExW(hShellKey, NULL, 0, REG_SZ,
1117 LPBYTE(pEditType->szDefaultVerb), sizeof(pEditType->szDefaultVerb));
1118
1119 // write shell commands
1120 const INT nCount = pEditType->CommandLineMap.GetSize();
1121 for (INT i = 0; i < nCount; ++i)
1122 {
1123 CStringW& key = pEditType->CommandLineMap.GetKeyAt(i);
1124 CStringW& value = pEditType->CommandLineMap.GetValueAt(i);
1125
1126 // create verb key
1127 HKEY hVerbKey;
1128 if (RegCreateKeyExW(hShellKey, key, 0, NULL, 0, KEY_WRITE, NULL,
1129 &hVerbKey, NULL) == ERROR_SUCCESS)
1130 {
1131 // create command key
1132 HKEY hCommandKey;
1133 if (RegCreateKeyExW(hVerbKey, L"command", 0, NULL, 0, KEY_WRITE, NULL,
1134 &hCommandKey, NULL) == ERROR_SUCCESS)
1135 {
1136 // write the default value
1137 DWORD dwSize = (value.GetLength() + 1) * sizeof(WCHAR);
1138 RegSetValueExW(hCommandKey, NULL, 0, REG_EXPAND_SZ, LPBYTE(LPCWSTR(value)), dwSize);
1139
1140 RegCloseKey(hCommandKey);
1141 }
1142
1143 RegCloseKey(hVerbKey);
1144 }
1145 }
1146
1147 // set class name to class key
1148 RegSetValueExW(hClassKey, NULL, 0, REG_SZ, LPBYTE(ClassName), cchName);
1149
1150 RegCloseKey(hShellKey);
1151 RegCloseKey(hClassKey);
1152
1153 return TRUE;
1154 }
1155
1156 static BOOL
1157 EditTypeDlg_ReadClass(HWND hwndDlg, PEDITTYPE_DIALOG pEditType, LPCWSTR ClassKey)
1158 {
1159 // open class key
1160 HKEY hClassKey;
1161 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, ClassKey, 0, KEY_READ, &hClassKey) != ERROR_SUCCESS)
1162 return FALSE;
1163
1164 // open "shell" key
1165 HKEY hShellKey;
1166 if (RegOpenKeyExW(hClassKey, L"shell", 0, KEY_READ, &hShellKey) != ERROR_SUCCESS)
1167 {
1168 RegCloseKey(hClassKey);
1169 return FALSE;
1170 }
1171
1172 WCHAR DefaultVerb[64];
1173 DWORD dwSize = sizeof(DefaultVerb);
1174 if (RegQueryValueExW(hShellKey, NULL, NULL, NULL,
1175 LPBYTE(DefaultVerb), &dwSize) == ERROR_SUCCESS)
1176 {
1177 StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), DefaultVerb);
1178 }
1179 else
1180 {
1181 StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), L"open");
1182 }
1183
1184 // enumerate shell verbs
1185 WCHAR szVerbName[64];
1186 DWORD dwIndex = 0;
1187 while (RegEnumKeyW(hShellKey, dwIndex, szVerbName, _countof(szVerbName)) == ERROR_SUCCESS)
1188 {
1189 // open verb key
1190 HKEY hVerbKey;
1191 LONG nResult = RegOpenKeyExW(hShellKey, szVerbName, 0, KEY_READ, &hVerbKey);
1192 if (nResult == ERROR_SUCCESS)
1193 {
1194 // open command key
1195 HKEY hCommandKey;
1196 nResult = RegOpenKeyExW(hVerbKey, L"command", 0, KEY_READ, &hCommandKey);
1197 if (nResult == ERROR_SUCCESS)
1198 {
1199 // get command line
1200 WCHAR szValue[MAX_PATH + 32];
1201 dwSize = sizeof(szValue);
1202 nResult = RegQueryValueExW(hCommandKey, NULL, NULL, NULL, LPBYTE(szValue), &dwSize);
1203 if (nResult == ERROR_SUCCESS)
1204 {
1205 pEditType->CommandLineMap.SetAt(szVerbName, szValue);
1206 }
1207
1208 RegCloseKey(hCommandKey);
1209 }
1210
1211 RegCloseKey(hVerbKey);
1212 }
1213 SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_ADDSTRING, 0, LPARAM(szVerbName));
1214 ++dwIndex;
1215 }
1216
1217 RegCloseKey(hShellKey);
1218 RegCloseKey(hClassKey);
1219
1220 return TRUE;
1221 }
1222
1223 static void
1224 EditTypeDlg_OnOK(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
1225 {
1226 PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
1227
1228 // get class name
1229 GetDlgItemTextW(hwndDlg, IDC_EDITTYPE_TEXT, pEntry->ClassName, _countof(pEntry->ClassName));
1230 StrTrimW(pEntry->ClassName, g_pszSpace);
1231
1232 // update entry icon
1233 EditTypeDlg_UpdateEntryIcon(hwndDlg, pEditType, pEditType->szIconPath, pEditType->nIconIndex);
1234
1235 // write registry
1236 EditTypeDlg_WriteClass(hwndDlg, pEditType, pEntry->ClassKey, pEntry->ClassName,
1237 _countof(pEntry->ClassName));
1238
1239 // update the icon cache
1240 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, NULL, NULL);
1241
1242 EndDialog(hwndDlg, IDOK);
1243 }
1244
1245 static BOOL
1246 EditTypeDlg_OnRemove(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
1247 {
1248 // get current selection
1249 INT iItem = SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETCURSEL, 0, 0);
1250 if (iItem == LB_ERR)
1251 return FALSE;
1252
1253 // ask user for removal
1254 CStringW strText(MAKEINTRESOURCEW(IDS_REMOVE_ACTION));
1255 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
1256 if (MessageBoxW(hwndDlg, strText, strTitle, MB_ICONINFORMATION | MB_YESNO) == IDNO)
1257 return FALSE;
1258
1259 // get text
1260 WCHAR szText[64];
1261 szText[0] = 0;
1262 SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETTEXT, iItem, (LPARAM)szText);
1263 StrTrimW(szText, g_pszSpace);
1264
1265 // remove it
1266 pEditType->CommandLineMap.Remove(szText);
1267 SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_DELETESTRING, iItem, 0);
1268 return TRUE;
1269 }
1270
1271 static void
1272 EditTypeDlg_OnCommand(HWND hwndDlg, UINT id, UINT code, PEDITTYPE_DIALOG pEditType)
1273 {
1274 INT iItem, iIndex;
1275 ACTION_DIALOG action;
1276 switch (id)
1277 {
1278 case IDOK:
1279 EditTypeDlg_OnOK(hwndDlg, pEditType);
1280 break;
1281
1282 case IDCANCEL:
1283 EndDialog(hwndDlg, IDCANCEL);
1284 break;
1285
1286 case IDC_EDITTYPE_CHANGE_ICON:
1287 EditTypeDlg_OnChangeIcon(hwndDlg, pEditType);
1288 break;
1289
1290 case IDC_EDITTYPE_NEW:
1291 action.bUseDDE = FALSE;
1292 action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
1293 StringCbPrintfW(action.ClassName, sizeof(action.ClassName), pEditType->pEntry->ClassName);
1294 // open 'New Action' dialog
1295 if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ACTION), hwndDlg,
1296 NewActionDlgProc, LPARAM(&action)))
1297 {
1298 if (SendMessageW(action.hwndLB, LB_FINDSTRING, -1, (LPARAM)action.szAction) != LB_ERR)
1299 {
1300 // already exists, error
1301 HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
1302 SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
1303 SetFocus(hwndCtrl);
1304
1305 CStringW strText, strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
1306 strText.Format(IDS_ACTION_EXISTS, action.szAction);
1307 MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
1308 }
1309 else
1310 {
1311 // add it
1312 CStringW strCommandLine = action.szApp;
1313 strCommandLine += L" \"%1\"";
1314 pEditType->CommandLineMap.SetAt(action.szAction, strCommandLine);
1315 SendMessageW(action.hwndLB, LB_ADDSTRING, 0, LPARAM(action.szAction));
1316 if (SendMessageW(action.hwndLB, LB_GETCOUNT, 0, 0) == 1)
1317 {
1318 // set default
1319 StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), action.szAction);
1320 InvalidateRect(action.hwndLB, NULL, TRUE);
1321 }
1322 }
1323 }
1324 break;
1325
1326 case IDC_EDITTYPE_LISTBOX:
1327 if (code == LBN_SELCHANGE)
1328 {
1329 action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
1330 INT iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
1331 SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
1332 if (lstrcmpiW(action.szAction, pEditType->szDefaultVerb) == 0)
1333 {
1334 EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
1335 }
1336 else
1337 {
1338 EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), TRUE);
1339 }
1340 break;
1341 }
1342 else if (code != LBN_DBLCLK)
1343 {
1344 break;
1345 }
1346 // FALL THROUGH
1347
1348 case IDC_EDITTYPE_EDIT_BUTTON:
1349 action.bUseDDE = FALSE;
1350 action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
1351 StringCbPrintfW(action.ClassName, sizeof(action.ClassName), pEditType->pEntry->ClassName);
1352 iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
1353 if (iItem == LB_ERR)
1354 break;
1355
1356 // get action
1357 SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
1358
1359 // get app
1360 {
1361 iIndex = pEditType->CommandLineMap.FindKey(action.szAction);
1362 CStringW str = pEditType->CommandLineMap.GetValueAt(iIndex);
1363 StringCbCopyW(action.szApp, sizeof(action.szApp), LPCWSTR(str));
1364 }
1365
1366 // open dialog
1367 if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ACTION), hwndDlg,
1368 EditActionDlgProc, LPARAM(&action)))
1369 {
1370 SendMessageW(action.hwndLB, LB_DELETESTRING, iItem, 0);
1371 SendMessageW(action.hwndLB, LB_INSERTSTRING, iItem, LPARAM(action.szAction));
1372 pEditType->CommandLineMap.SetAt(action.szAction, action.szApp);
1373 }
1374 break;
1375
1376 case IDC_EDITTYPE_REMOVE:
1377 EditTypeDlg_OnRemove(hwndDlg, pEditType);
1378 break;
1379
1380 case IDC_EDITTYPE_SET_DEFAULT:
1381 action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
1382 iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
1383 if (iItem == LB_ERR)
1384 break;
1385
1386 SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
1387
1388 // set default
1389 StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), action.szAction);
1390 EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
1391 InvalidateRect(action.hwndLB, NULL, TRUE);
1392 break;
1393 }
1394 }
1395
1396 static BOOL
1397 EditTypeDlg_OnInitDialog(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
1398 {
1399 PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
1400 StringCbCopyW(pEditType->szIconPath, sizeof(pEditType->szIconPath), pEntry->IconPath);
1401 pEditType->nIconIndex = pEntry->nIconIndex;
1402 StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), L"open");
1403
1404 // set info
1405 SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_ICON, STM_SETICON, (WPARAM)pEntry->hIconLarge, 0);
1406 SetDlgItemTextW(hwndDlg, IDC_EDITTYPE_TEXT, pEntry->ClassName);
1407 EditTypeDlg_ReadClass(hwndDlg, pEditType, pEntry->ClassKey);
1408 InvalidateRect(GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX), NULL, TRUE);
1409
1410 // is listbox empty?
1411 if (SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETCOUNT, 0, 0) == 0)
1412 {
1413 EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_EDIT_BUTTON), FALSE);
1414 EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_REMOVE), FALSE);
1415 EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
1416 }
1417 else
1418 {
1419 // select first item
1420 SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_SETCURSEL, 0, 0);
1421 }
1422
1423 EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SAME_WINDOW), FALSE);
1424
1425 return TRUE;
1426 }
1427
1428 // IDD_EDITTYPE
1429 static INT_PTR CALLBACK
1430 EditTypeDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1431 {
1432 static PEDITTYPE_DIALOG s_pEditType = NULL;
1433 LPDRAWITEMSTRUCT pDraw;
1434 LPMEASUREITEMSTRUCT pMeasure;
1435
1436 switch (uMsg)
1437 {
1438 case WM_INITDIALOG:
1439 s_pEditType = (PEDITTYPE_DIALOG)lParam;
1440 return EditTypeDlg_OnInitDialog(hwndDlg, s_pEditType);
1441
1442 case WM_DRAWITEM:
1443 pDraw = LPDRAWITEMSTRUCT(lParam);
1444 return EditTypeDlg_OnDrawItem(hwndDlg, pDraw, s_pEditType);
1445
1446 case WM_MEASUREITEM:
1447 pMeasure = LPMEASUREITEMSTRUCT(lParam);
1448 return EditTypeDlg_OnMeasureItem(hwndDlg, pMeasure, s_pEditType);
1449
1450 case WM_COMMAND:
1451 EditTypeDlg_OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), s_pEditType);
1452 break;
1453 }
1454
1455 return 0;
1456 }
1457
1458 /////////////////////////////////////////////////////////////////////////////
1459 // FileTypesDlg
1460
1461 static INT CALLBACK
1462 FileTypesDlg_CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
1463 {
1464 PFILE_TYPE_ENTRY Entry1, Entry2;
1465 int x;
1466
1467 Entry1 = (PFILE_TYPE_ENTRY)lParam1;
1468 Entry2 = (PFILE_TYPE_ENTRY)lParam2;
1469
1470 x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension);
1471 if (x != 0)
1472 return x;
1473
1474 return wcsicmp(Entry1->FileDescription, Entry2->FileDescription);
1475 }
1476
1477 static VOID
1478 FileTypesDlg_InitListView(HWND hwndDlg, HWND hListView)
1479 {
1480 RECT clientRect;
1481 LVCOLUMNW col;
1482 WCHAR szName[50];
1483 DWORD dwStyle;
1484 INT columnSize = 140;
1485
1486 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, _countof(szName)))
1487 {
1488 // default to english
1489 wcscpy(szName, L"Extensions");
1490 }
1491
1492 // make sure its null terminated
1493 szName[_countof(szName) - 1] = 0;
1494
1495 GetClientRect(hListView, &clientRect);
1496 ZeroMemory(&col, sizeof(LV_COLUMN));
1497 columnSize = 120;
1498 col.iSubItem = 0;
1499 col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
1500 col.fmt = LVCFMT_FIXED_WIDTH;
1501 col.cx = columnSize | LVCFMT_LEFT;
1502 col.cchTextMax = wcslen(szName);
1503 col.pszText = szName;
1504 SendMessageW(hListView, LVM_INSERTCOLUMNW, 0, (LPARAM)&col);
1505
1506 if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, _countof(szName)))
1507 {
1508 // default to english
1509 wcscpy(szName, L"File Types");
1510 ERR("Failed to load localized string!\n");
1511 }
1512
1513 col.iSubItem = 1;
1514 col.cx = clientRect.right - clientRect.left - columnSize;
1515 col.cchTextMax = wcslen(szName);
1516 col.pszText = szName;
1517 SendMessageW(hListView, LVM_INSERTCOLUMNW, 1, (LPARAM)&col);
1518
1519 // set full select style
1520 dwStyle = (DWORD)SendMessage(hListView, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1521 dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
1522 SendMessage(hListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
1523 }
1524
1525 static PFILE_TYPE_ENTRY
1526 FileTypesDlg_DoList(HWND hwndDlg)
1527 {
1528 HWND hListView;
1529 DWORD dwIndex = 0;
1530 WCHAR szName[50];
1531 WCHAR szFile[100];
1532 DWORD dwName;
1533 LVITEMW lvItem;
1534 INT iItem = 0;
1535 HIMAGELIST himlLarge, himlSmall;
1536
1537 // create imagelists
1538 himlLarge = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1539 ILC_COLOR32 | ILC_MASK, 256, 20);
1540 himlSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
1541 ILC_COLOR32 | ILC_MASK, 256, 20);
1542
1543 // set imagelists to listview.
1544 hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1545 ListView_SetImageList(hListView, himlLarge, LVSIL_NORMAL);
1546 ListView_SetImageList(hListView, himlSmall, LVSIL_SMALL);
1547
1548 FileTypesDlg_InitListView(hwndDlg, hListView);
1549
1550 szFile[0] = 0;
1551 if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile)))
1552 {
1553 // default to english
1554 wcscpy(szFile, L"%s File");
1555 }
1556 szFile[(_countof(szFile)) - 1] = 0;
1557
1558 dwName = _countof(szName);
1559
1560 while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName,
1561 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1562 {
1563 if (FileTypesDlg_InsertToLV(hListView, szName, iItem, szFile))
1564 ++iItem;
1565 dwName = _countof(szName);
1566 }
1567
1568 // Leave if the list is empty
1569 if (iItem == 0)
1570 return NULL;
1571
1572 // sort list
1573 ListView_SortItems(hListView, FileTypesDlg_CompareItems, NULL);
1574
1575 // select first item
1576 ZeroMemory(&lvItem, sizeof(LVITEMW));
1577 lvItem.mask = LVIF_STATE;
1578 lvItem.stateMask = (UINT)-1;
1579 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
1580 lvItem.iItem = 0;
1581 ListView_SetItem(hListView, &lvItem);
1582
1583 lvItem.mask = LVIF_PARAM;
1584 ListView_GetItem(hListView, &lvItem);
1585
1586 return (PFILE_TYPE_ENTRY)lvItem.lParam;
1587 }
1588
1589 static inline PFILE_TYPE_ENTRY
1590 FileTypesDlg_GetEntry(HWND hListView, INT iItem = -1)
1591 {
1592 if (iItem == -1)
1593 {
1594 iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
1595 if (iItem == -1)
1596 return NULL;
1597 }
1598
1599 LV_ITEMW lvItem = { LVIF_PARAM, iItem };
1600 if (ListView_GetItem(hListView, &lvItem))
1601 return (PFILE_TYPE_ENTRY)lvItem.lParam;
1602
1603 return NULL;
1604 }
1605
1606 static void
1607 FileTypesDlg_OnDelete(HWND hwndDlg)
1608 {
1609 CStringW strRemoveExt(MAKEINTRESOURCEW(IDS_REMOVE_EXT));
1610 CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
1611 if (MessageBoxW(hwndDlg, strRemoveExt, strTitle, MB_ICONQUESTION | MB_YESNO) == IDYES)
1612 {
1613 FileTypesDlg_RemoveExt(hwndDlg);
1614 }
1615 }
1616
1617 static void
1618 FileTypesDlg_OnItemChanging(HWND hwndDlg, PFILE_TYPE_ENTRY pEntry)
1619 {
1620 WCHAR Buffer[255];
1621 static HBITMAP s_hbmProgram = NULL;
1622
1623 // format buffer and set groupbox text
1624 CStringW strFormat(MAKEINTRESOURCEW(IDS_FILE_DETAILS));
1625 StringCbPrintfW(Buffer, sizeof(Buffer), strFormat, &pEntry->FileExtension[1]);
1626 SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DETAILS_GROUPBOX, Buffer);
1627
1628 // format buffer and set description
1629 strFormat.LoadString(IDS_FILE_DETAILSADV);
1630 StringCbPrintfW(Buffer, sizeof(Buffer), strFormat,
1631 &pEntry->FileExtension[1], pEntry->FileDescription,
1632 pEntry->FileDescription);
1633 SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DESCRIPTION, Buffer);
1634
1635 // delete previous program image
1636 if (s_hbmProgram)
1637 {
1638 DeleteObject(s_hbmProgram);
1639 s_hbmProgram = NULL;
1640 }
1641
1642 // set program image
1643 HICON hIconSm = NULL;
1644 ExtractIconExW(pEntry->ProgramPath, 0, NULL, &hIconSm, 1);
1645 s_hbmProgram = BitmapFromIcon(hIconSm, 16, 16);
1646 DestroyIcon(hIconSm);
1647 SendDlgItemMessageW(hwndDlg, IDC_FILETYPES_ICON, STM_SETIMAGE, IMAGE_BITMAP, LPARAM(s_hbmProgram));
1648
1649 // set program name
1650 if (pEntry->AppName[0])
1651 SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, pEntry->AppName);
1652 else
1653 SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, L"ReactOS");
1654
1655 // Enable the Delete button
1656 if (pEntry->EditFlags & 0x00000010) // FTA_NoRemove
1657 EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
1658 else
1659 EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), TRUE);
1660 }
1661
1662 // IDD_FOLDER_OPTIONS_FILETYPES
1663 INT_PTR CALLBACK
1664 FolderOptionsFileTypesDlg(
1665 HWND hwndDlg,
1666 UINT uMsg,
1667 WPARAM wParam,
1668 LPARAM lParam)
1669 {
1670 LPNMLISTVIEW lppl;
1671 PFILE_TYPE_ENTRY pEntry;
1672 OPENASINFO Info;
1673 NEWEXT_DIALOG newext;
1674 EDITTYPE_DIALOG edittype;
1675
1676 switch (uMsg)
1677 {
1678 case WM_INITDIALOG:
1679 pEntry = FileTypesDlg_DoList(hwndDlg);
1680
1681 // Disable the Delete button if the listview is empty
1682 // the selected item should not be deleted by the user
1683 if (pEntry == NULL || (pEntry->EditFlags & 0x00000010)) // FTA_NoRemove
1684 EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
1685 return TRUE;
1686
1687 case WM_COMMAND:
1688 switch (LOWORD(wParam))
1689 {
1690 case IDC_FILETYPES_NEW:
1691 newext.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1692 if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_NEWEXTENSION),
1693 hwndDlg, NewExtDlgProc, (LPARAM)&newext))
1694 {
1695 FileTypesDlg_AddExt(hwndDlg, newext.szExt, newext.szFileType);
1696 }
1697 break;
1698
1699 case IDC_FILETYPES_DELETE:
1700 FileTypesDlg_OnDelete(hwndDlg);
1701 break;
1702
1703 case IDC_FILETYPES_CHANGE:
1704 pEntry = FileTypesDlg_GetEntry(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
1705 if (pEntry)
1706 {
1707 ZeroMemory(&Info, sizeof(Info));
1708 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT;
1709 Info.pcszFile = pEntry->FileExtension;
1710 Info.pcszClass = NULL;
1711 SHOpenWithDialog(hwndDlg, &Info);
1712 }
1713 break;
1714
1715 case IDC_FILETYPES_ADVANCED:
1716 edittype.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1717 edittype.pEntry = FileTypesDlg_GetEntry(edittype.hwndLV);
1718 DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_EDITTYPE),
1719 hwndDlg, EditTypeDlgProc, (LPARAM)&edittype);
1720 break;
1721 }
1722 break;
1723
1724 case WM_NOTIFY:
1725 lppl = (LPNMLISTVIEW) lParam;
1726 switch (lppl->hdr.code)
1727 {
1728 case LVN_KEYDOWN:
1729 {
1730 LV_KEYDOWN *pKeyDown = (LV_KEYDOWN *)lParam;
1731 if (pKeyDown->wVKey == VK_DELETE)
1732 {
1733 FileTypesDlg_OnDelete(hwndDlg);
1734 }
1735 break;
1736 }
1737
1738 case NM_DBLCLK:
1739 edittype.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
1740 edittype.pEntry = FileTypesDlg_GetEntry(edittype.hwndLV);
1741 DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_EDITTYPE),
1742 hwndDlg, EditTypeDlgProc, (LPARAM)&edittype);
1743 break;
1744
1745 case LVN_DELETEALLITEMS:
1746 return FALSE; // send LVN_DELETEITEM
1747
1748 case LVN_DELETEITEM:
1749 pEntry = FileTypesDlg_GetEntry(lppl->hdr.hwndFrom, lppl->iItem);
1750 if (pEntry)
1751 {
1752 DestroyIcon(pEntry->hIconLarge);
1753 DestroyIcon(pEntry->hIconSmall);
1754 HeapFree(GetProcessHeap(), 0, pEntry);
1755 }
1756 return FALSE;
1757
1758 case LVN_ITEMCHANGING:
1759 pEntry = FileTypesDlg_GetEntry(lppl->hdr.hwndFrom, lppl->iItem);
1760 if (!pEntry)
1761 {
1762 return TRUE;
1763 }
1764
1765 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
1766 {
1767 FileTypesDlg_OnItemChanging(hwndDlg, pEntry);
1768 }
1769 break;
1770
1771 case PSN_SETACTIVE:
1772 // On page activation, set the focus to the listview
1773 SetFocus(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
1774 break;
1775 }
1776 break;
1777 }
1778
1779 return FALSE;
1780 }