2 * 'File Types' tab property sheet of Folder Options
4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org>
5 * Copyright 2016-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
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.
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.
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
24 WINE_DEFAULT_DEBUG_CHANNEL (fprop
);
26 // DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210
27 // Verbs: Open / RunAs
28 // Cmd: rundll32.exe shell32.dll,Options_RunDLL 0
30 /////////////////////////////////////////////////////////////////////////////
32 typedef struct FILE_TYPE_ENTRY
34 WCHAR FileExtension
[30];
35 WCHAR FileDescription
[100];
36 WCHAR ClassKey
[MAX_PATH
];
42 WCHAR ProgramPath
[MAX_PATH
];
43 WCHAR IconPath
[MAX_PATH
];
45 } FILE_TYPE_ENTRY
, *PFILE_TYPE_ENTRY
;
48 DeleteExt(HWND hwndDlg
, LPCWSTR pszExt
)
55 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pszExt
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
58 // query "extfile" key name
59 WCHAR szValue
[64] = { 0 };
60 DWORD cbValue
= sizeof(szValue
);
61 RegQueryValueExW(hKey
, NULL
, NULL
, NULL
, LPBYTE(szValue
), &cbValue
);
64 // delete "extfile" key (if any)
66 SHDeleteKeyW(HKEY_CLASSES_ROOT
, szValue
);
69 return SHDeleteKeyW(HKEY_CLASSES_ROOT
, pszExt
) == ERROR_SUCCESS
;
73 DoExtractIcon(PFILE_TYPE_ENTRY Entry
, LPCWSTR IconPath
,
74 INT iIndex
= 0, BOOL bSmall
= FALSE
)
80 // A negative value will be interpreted as a negated resource ID.
84 HINSTANCE hDLL
= LoadLibraryExW(IconPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
87 cx
= GetSystemMetrics(SM_CXSMICON
);
88 cy
= GetSystemMetrics(SM_CYSMICON
);
92 cx
= GetSystemMetrics(SM_CXICON
);
93 cy
= GetSystemMetrics(SM_CYICON
);
95 hIcon
= HICON(LoadImageW(hDLL
, MAKEINTRESOURCEW(iIndex
), IMAGE_ICON
,
101 // A positive value is icon index.
103 ExtractIconExW(IconPath
, iIndex
, NULL
, &hIcon
, 1);
105 ExtractIconExW(IconPath
, iIndex
, &hIcon
, NULL
, 1);
111 DoFileTypeIconLocation(PFILE_TYPE_ENTRY Entry
, LPCWSTR IconLocation
)
113 // Expand the REG_EXPAND_SZ string by environment variables
114 WCHAR szLocation
[MAX_PATH
+ 32];
115 if (!ExpandEnvironmentStringsW(IconLocation
, szLocation
, _countof(szLocation
)))
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
);
125 GetFileTypeIconsEx(PFILE_TYPE_ENTRY Entry
, LPCWSTR IconLocation
)
127 Entry
->hIconLarge
= Entry
->hIconSmall
= NULL
;
129 if (lstrcmpiW(Entry
->FileExtension
, L
".exe") == 0 ||
130 lstrcmpiW(Entry
->FileExtension
, L
".scr") == 0)
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
;
141 else if (lstrcmpW(IconLocation
, L
"%1") == 0)
143 return FALSE
; // self icon
147 DoFileTypeIconLocation(Entry
, IconLocation
);
150 return Entry
->hIconLarge
&& Entry
->hIconSmall
;
154 GetFileTypeIconsByKey(HKEY hKey
, PFILE_TYPE_ENTRY Entry
)
156 Entry
->hIconLarge
= Entry
->hIconSmall
= NULL
;
158 // Open the "DefaultIcon" registry key
160 LONG nResult
= RegOpenKeyExW(hKey
, L
"DefaultIcon", 0, KEY_READ
, &hDefIconKey
);
161 if (nResult
!= ERROR_SUCCESS
)
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
);
169 RegCloseKey(hDefIconKey
);
171 if (nResult
!= ERROR_SUCCESS
|| szLocation
[0] == 0)
174 return GetFileTypeIconsEx(Entry
, szLocation
);
178 QueryFileDescription(LPCWSTR ProgramPath
, LPWSTR pszName
, INT cchName
)
180 SHFILEINFOW FileInfo
= { 0 };
181 if (SHGetFileInfoW(ProgramPath
, 0, &FileInfo
, sizeof(FileInfo
), SHGFI_DISPLAYNAME
))
183 StringCchCopyW(pszName
, cchName
, FileInfo
.szDisplayName
);
187 return !!GetFileTitleW(ProgramPath
, pszName
, cchName
);
191 SetFileTypeEntryDefaultIcon(PFILE_TYPE_ENTRY Entry
)
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
;
202 /////////////////////////////////////////////////////////////////////////////
205 #define LISTBOX_MARGIN 2
207 typedef struct EDITTYPE_DIALOG
210 PFILE_TYPE_ENTRY pEntry
;
211 CSimpleMap
<CStringW
, CStringW
> CommandLineMap
;
212 WCHAR szIconPath
[MAX_PATH
];
214 WCHAR szDefaultVerb
[64];
215 } EDITTYPE_DIALOG
, *PEDITTYPE_DIALOG
;
218 EditTypeDlg_OnChangeIcon(HWND hwndDlg
, PEDITTYPE_DIALOG pEditType
)
220 WCHAR szPath
[MAX_PATH
];
223 ExpandEnvironmentStringsW(pEditType
->szIconPath
, szPath
, _countof(szPath
));
224 IconIndex
= pEditType
->nIconIndex
;
225 if (PickIconDlg(hwndDlg
, szPath
, _countof(szPath
), &IconIndex
))
227 // replace Windows directory with "%SystemRoot%" (for portability)
228 WCHAR szWinDir
[MAX_PATH
];
229 GetWindowsDirectoryW(szWinDir
, _countof(szWinDir
));
230 if (wcsstr(szPath
, szWinDir
) == 0)
232 CStringW
str(L
"%SystemRoot%");
233 str
+= &szPath
[wcslen(szWinDir
)];
234 StringCbCopyW(szPath
, sizeof(szPath
), LPCWSTR(str
));
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
);
244 // update EDITTYPE_DIALOG
245 StringCbCopyW(pEditType
->szIconPath
, sizeof(pEditType
->szIconPath
), szPath
);
246 pEditType
->nIconIndex
= IconIndex
;
248 // set icon to dialog
249 SendDlgItemMessageW(hwndDlg
, IDC_EDITTYPE_ICON
, STM_SETICON
, (WPARAM
)pEntry
->hIconLarge
, 0);
254 EditTypeDlg_OnDrawItem(HWND hwndDlg
, LPDRAWITEMSTRUCT pDraw
, PEDITTYPE_DIALOG pEditType
)
262 // fill rect and set colors
263 if (pDraw
->itemState
& ODS_SELECTED
)
265 FillRect(pDraw
->hDC
, &pDraw
->rcItem
, HBRUSH(COLOR_HIGHLIGHT
+ 1));
266 SetTextColor(pDraw
->hDC
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
267 SetBkColor(pDraw
->hDC
, GetSysColor(COLOR_HIGHLIGHT
));
271 FillRect(pDraw
->hDC
, &pDraw
->rcItem
, HBRUSH(COLOR_WINDOW
+ 1));
272 SetTextColor(pDraw
->hDC
, GetSysColor(COLOR_WINDOWTEXT
));
273 SetBkColor(pDraw
->hDC
, GetSysColor(COLOR_WINDOW
));
277 HWND hwndListBox
= GetDlgItem(hwndDlg
, IDC_EDITTYPE_LISTBOX
);
278 SendMessageW(hwndListBox
, LB_GETTEXT
, pDraw
->itemID
, (LPARAM
)szText
);
281 hFont
= (HFONT
)SendMessageW(hwndListBox
, WM_GETFONT
, 0, 0);
282 if (lstrcmpiW(pEditType
->szDefaultVerb
, szText
) == 0)
286 GetObject(hFont
, sizeof(lf
), &lf
);
287 lf
.lfWeight
= FW_BOLD
;
288 hFont2
= CreateFontIndirectW(&lf
);
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
);
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
);
310 if (pDraw
->itemState
& ODS_FOCUS
)
312 DrawFocusRect(pDraw
->hDC
, &pDraw
->rcItem
);
318 EditTypeDlg_OnMeasureItem(HWND hwndDlg
, LPMEASUREITEMSTRUCT pMeasure
, PEDITTYPE_DIALOG pEditType
)
323 HWND hwndLB
= GetDlgItem(hwndDlg
, IDC_EDITTYPE_LISTBOX
);
325 HDC hDC
= GetDC(hwndLB
);
329 GetTextMetricsW(hDC
, &tm
);
330 pMeasure
->itemHeight
= tm
.tmHeight
+ LISTBOX_MARGIN
* 2;
331 ReleaseDC(hwndLB
, hDC
);
337 /////////////////////////////////////////////////////////////////////////////
340 typedef struct NEWEXT_DIALOG
347 WCHAR szFileType
[64];
348 } NEWEXT_DIALOG
, *PNEWEXT_DIALOG
;
351 NewExtDlg_OnAdvanced(HWND hwndDlg
, PNEWEXT_DIALOG pNewExt
)
353 // If "Advanced" button was clicked, then we shrink or expand the dialog.
356 GetWindowRect(hwndDlg
, &rc
);
357 rc
.bottom
= rc
.top
+ (pNewExt
->rcDlg
.bottom
- pNewExt
->rcDlg
.top
);
359 GetWindowRect(GetDlgItem(hwndDlg
, IDOK
), &rc1
);
360 MapWindowPoints(NULL
, hwndDlg
, (LPPOINT
)&rc1
, 2);
362 GetWindowRect(GetDlgItem(hwndDlg
, IDCANCEL
), &rc2
);
363 MapWindowPoints(NULL
, hwndDlg
, (LPPOINT
)&rc2
, 2);
365 if (pNewExt
->bAdvanced
)
367 rc1
.top
+= pNewExt
->dy
;
368 rc1
.bottom
+= pNewExt
->dy
;
370 rc2
.top
+= pNewExt
->dy
;
371 rc2
.bottom
+= pNewExt
->dy
;
373 ShowWindow(GetDlgItem(hwndDlg
, IDC_NEWEXT_ASSOC
), SW_SHOWNOACTIVATE
);
374 ShowWindow(GetDlgItem(hwndDlg
, IDC_NEWEXT_COMBOBOX
), SW_SHOWNOACTIVATE
);
376 CStringW
strLeft(MAKEINTRESOURCEW(IDS_NEWEXT_ADVANCED_LEFT
));
377 SetDlgItemTextW(hwndDlg
, IDC_NEWEXT_ADVANCED
, strLeft
);
379 SetFocus(GetDlgItem(hwndDlg
, IDC_NEWEXT_COMBOBOX
));
383 rc1
.top
-= pNewExt
->dy
;
384 rc1
.bottom
-= pNewExt
->dy
;
386 rc2
.top
-= pNewExt
->dy
;
387 rc2
.bottom
-= pNewExt
->dy
;
389 ShowWindow(GetDlgItem(hwndDlg
, IDC_NEWEXT_ASSOC
), SW_HIDE
);
390 ShowWindow(GetDlgItem(hwndDlg
, IDC_NEWEXT_COMBOBOX
), SW_HIDE
);
392 CStringW
strRight(MAKEINTRESOURCEW(IDS_NEWEXT_ADVANCED_RIGHT
));
393 SetDlgItemTextW(hwndDlg
, IDC_NEWEXT_ADVANCED
, strRight
);
395 rc
.bottom
-= pNewExt
->dy
;
397 CStringW
strText(MAKEINTRESOURCEW(IDS_NEWEXT_NEW
));
398 SetDlgItemTextW(hwndDlg
, IDC_NEWEXT_COMBOBOX
, strText
);
401 HDWP hDWP
= BeginDeferWindowPos(3);
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
);
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
);
412 hDWP
= DeferWindowPos(hDWP
, hwndDlg
, NULL
,
413 rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
414 SWP_NOACTIVATE
| SWP_NOZORDER
);
417 EndDeferWindowPos(hDWP
);
421 NewExtDlg_OnInitDialog(HWND hwndDlg
, PNEWEXT_DIALOG pNewExt
)
423 pNewExt
->bAdvanced
= FALSE
;
425 // get window rectangle
426 GetWindowRect(hwndDlg
, &pNewExt
->rcDlg
);
430 GetWindowRect(GetDlgItem(hwndDlg
, IDC_NEWEXT_EDIT
), &rc1
);
431 GetWindowRect(GetDlgItem(hwndDlg
, IDC_NEWEXT_COMBOBOX
), &rc2
);
432 pNewExt
->dy
= rc2
.top
- rc1
.top
;
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);
440 // shrink it first time
441 NewExtDlg_OnAdvanced(hwndDlg
, pNewExt
);
447 NewExtDlg_OnOK(HWND hwndDlg
, PNEWEXT_DIALOG pNewExt
)
452 GetDlgItemTextW(hwndDlg
, IDC_NEWEXT_EDIT
, pNewExt
->szExt
, _countof(pNewExt
->szExt
));
453 StrTrimW(pNewExt
->szExt
, g_pszSpace
);
454 _wcsupr(pNewExt
->szExt
);
456 GetDlgItemTextW(hwndDlg
, IDC_NEWEXT_COMBOBOX
, pNewExt
->szFileType
, _countof(pNewExt
->szFileType
));
457 StrTrimW(pNewExt
->szFileType
, g_pszSpace
);
459 if (pNewExt
->szExt
[0] == 0)
461 CStringW
strText(MAKEINTRESOURCEW(IDS_NEWEXT_SPECIFY_EXT
));
462 CStringW
strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES
));
463 MessageBoxW(hwndDlg
, strText
, strTitle
, MB_ICONERROR
);
467 ZeroMemory(&find
, sizeof(find
));
468 find
.flags
= LVFI_STRING
;
469 if (pNewExt
->szExt
[0] == L
'.')
471 find
.psz
= &pNewExt
->szExt
[1];
475 find
.psz
= pNewExt
->szExt
;
478 iItem
= ListView_FindItem(pNewExt
->hwndLV
, -1, &find
);
484 WCHAR szFileType
[64];
486 ZeroMemory(&item
, sizeof(item
));
487 item
.mask
= LVIF_TEXT
;
488 item
.pszText
= szFileType
;
489 item
.cchTextMax
= _countof(szFileType
);
492 ListView_GetItem(pNewExt
->hwndLV
, &item
);
496 strText
.Format(IDS_NEWEXT_ALREADY_ASSOC
, find
.psz
, szFileType
, find
.psz
, szFileType
);
500 strTitle
.LoadString(IDS_NEWEXT_EXT_IN_USE
);
502 if (MessageBoxW(hwndDlg
, strText
, strTitle
, MB_ICONWARNING
| MB_YESNO
) == IDNO
)
507 // Delete the extension
508 CStringW
strExt(L
".");
511 DeleteExt(hwndDlg
, strExt
);
514 ListView_DeleteItem(pNewExt
->hwndLV
, iItem
);
517 EndDialog(hwndDlg
, IDOK
);
522 static INT_PTR CALLBACK
529 static PNEWEXT_DIALOG s_pNewExt
= NULL
;
534 s_pNewExt
= (PNEWEXT_DIALOG
)lParam
;
535 NewExtDlg_OnInitDialog(hwndDlg
, s_pNewExt
);
539 switch (LOWORD(wParam
))
542 NewExtDlg_OnOK(hwndDlg
, s_pNewExt
);
546 EndDialog(hwndDlg
, IDCANCEL
);
549 case IDC_NEWEXT_ADVANCED
:
550 s_pNewExt
->bAdvanced
= !s_pNewExt
->bAdvanced
;
551 NewExtDlg_OnAdvanced(hwndDlg
, s_pNewExt
);
560 FileTypesDlg_InsertToLV(HWND hListView
, LPCWSTR szName
, INT iItem
, LPCWSTR szFile
)
562 PFILE_TYPE_ENTRY Entry
;
568 if (szName
[0] != L
'.')
570 // FIXME handle URL protocol handlers
574 // get imagelists of listview
575 HIMAGELIST himlLarge
= ListView_GetImageList(hListView
, LVSIL_NORMAL
);
576 HIMAGELIST himlSmall
= ListView_GetImageList(hListView
, LVSIL_SMALL
);
578 // allocate file type entry
579 Entry
= (PFILE_TYPE_ENTRY
)HeapAlloc(GetProcessHeap(), 0, sizeof(FILE_TYPE_ENTRY
));
584 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szName
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
586 HeapFree(GetProcessHeap(), 0, Entry
);
590 // FIXME check for duplicates
592 // query for the default key
593 dwSize
= sizeof(Entry
->ClassKey
);
594 if (RegQueryValueExW(hKey
, NULL
, NULL
, NULL
, LPBYTE(Entry
->ClassKey
), &dwSize
) != ERROR_SUCCESS
)
597 Entry
->ClassKey
[0] = 0;
600 Entry
->ClassName
[0] = 0;
601 if (Entry
->ClassKey
[0])
604 // try open linked key
605 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, Entry
->ClassKey
, 0, KEY_READ
, &hTemp
) == ERROR_SUCCESS
)
607 DWORD dwSize
= sizeof(Entry
->ClassName
);
608 RegQueryValueExW(hTemp
, NULL
, NULL
, NULL
, LPBYTE(Entry
->ClassName
), &dwSize
);
616 // read friendly type name
617 if (RegLoadMUIStringW(hKey
, L
"FriendlyTypeName", Entry
->FileDescription
,
618 sizeof(Entry
->FileDescription
), NULL
, 0, NULL
) != ERROR_SUCCESS
)
620 // read file description
621 dwSize
= sizeof(Entry
->FileDescription
);
622 Entry
->FileDescription
[0] = 0;
625 RegQueryValueExW(hKey
, NULL
, NULL
, NULL
, LPBYTE(Entry
->FileDescription
), &dwSize
);
628 // Read the EditFlags value
629 Entry
->EditFlags
= 0;
630 if (!RegQueryValueExW(hKey
, L
"EditFlags", NULL
, &dwType
, NULL
, &dwSize
))
632 if ((dwType
== REG_DWORD
|| dwType
== REG_BINARY
) && dwSize
== sizeof(DWORD
))
633 RegQueryValueExW(hKey
, L
"EditFlags", NULL
, NULL
, (LPBYTE
)&Entry
->EditFlags
, &dwSize
);
636 // convert extension to upper case
637 wcscpy(Entry
->FileExtension
, szName
);
638 _wcsupr(Entry
->FileExtension
);
641 if (!GetFileTypeIconsByKey(hKey
, Entry
))
644 SetFileTypeEntryDefaultIcon(Entry
);
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
))
655 QueryFileDescription(Entry
->ProgramPath
, Entry
->AppName
, _countof(Entry
->AppName
));
659 Entry
->ProgramPath
[0] = Entry
->AppName
[0] = 0;
662 // add icon to imagelist
663 INT iLargeImage
= -1, iSmallImage
= -1;
664 if (Entry
->hIconLarge
&& Entry
->hIconSmall
)
666 iLargeImage
= ImageList_AddIcon(himlLarge
, Entry
->hIconLarge
);
667 iSmallImage
= ImageList_AddIcon(himlSmall
, Entry
->hIconSmall
);
668 ASSERT(iLargeImage
== iSmallImage
);
671 // Do not add excluded entries
672 if (Entry
->EditFlags
& 0x00000001) //FTA_Exclude
674 DestroyIcon(Entry
->hIconLarge
);
675 DestroyIcon(Entry
->hIconSmall
);
676 HeapFree(GetProcessHeap(), 0, Entry
);
680 if (!Entry
->FileDescription
[0])
682 // construct default 'FileExtensionFile' by formatting the uppercase extension
683 // with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File'
685 StringCbPrintf(Entry
->FileDescription
, sizeof(Entry
->FileDescription
), szFile
, &Entry
->FileExtension
[1]);
688 ZeroMemory(&lvItem
, sizeof(LVITEMW
));
689 lvItem
.mask
= LVIF_TEXT
| LVIF_PARAM
| LVIF_IMAGE
;
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
);
697 ZeroMemory(&lvItem
, sizeof(LVITEMW
));
698 lvItem
.mask
= LVIF_TEXT
;
699 lvItem
.pszText
= Entry
->FileDescription
;
700 lvItem
.iItem
= iItem
;
702 ListView_SetItem(hListView
, &lvItem
);
708 FileTypesDlg_AddExt(HWND hwndDlg
, LPCWSTR pszExt
, LPCWSTR pszFileType
)
712 WCHAR szKey
[13]; // max. "ft4294967295" + "\0"
715 // Search the next "ft%06u" key name
718 StringCbPrintfW(szKey
, sizeof(szKey
), L
"ft%06u", dwValue
);
720 nResult
= RegOpenKeyEx(HKEY_CLASSES_ROOT
, szKey
, 0, KEY_READ
, &hKey
);
721 if (nResult
!= ERROR_SUCCESS
)
726 } while (dwValue
!= 0);
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
)
740 // Create the ".ext" key
744 StringCbPrintfW(szExt
, sizeof(szExt
), L
".%s", pszExt
);
746 nResult
= RegCreateKeyEx(HKEY_CLASSES_ROOT
, szExt
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, NULL
);
748 if (ERROR_SUCCESS
!= nResult
)
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
);
757 // Make up the file type name
759 CStringW
strFormat(MAKEINTRESOURCEW(IDS_FILE_EXT_TYPE
));
760 StringCbPrintfW(szFile
, sizeof(szFile
), strFormat
, &szExt
[1]);
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
))
769 ZeroMemory(&item
, sizeof(item
));
770 item
.mask
= LVIF_STATE
| LVIF_TEXT
;
772 item
.state
= LVIS_SELECTED
| LVIS_FOCUSED
;
773 item
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
774 item
.pszText
= &szExt
[1];
775 ListView_SetItem(hListView
, &item
);
777 item
.pszText
= szFile
;
779 ListView_SetItem(hListView
, &item
);
781 ListView_EnsureVisible(hListView
, iItem
, FALSE
);
787 FileTypesDlg_RemoveExt(HWND hwndDlg
)
789 HWND hListView
= GetDlgItem(hwndDlg
, IDC_FILETYPES_LISTVIEW
);
791 INT iItem
= ListView_GetNextItem(hListView
, -1, LVNI_SELECTED
);
797 ListView_GetItemText(hListView
, iItem
, 0, &szExt
[1], _countof(szExt
) - 1);
800 DeleteExt(hwndDlg
, szExt
);
801 ListView_DeleteItem(hListView
, iItem
);
805 /////////////////////////////////////////////////////////////////////////////
806 // common code of NewActionDlg and EditActionDlg
808 typedef struct ACTION_DIALOG
813 WCHAR szApp
[MAX_PATH
];
815 } ACTION_DIALOG
, *PACTION_DIALOG
;
818 ActionDlg_OnBrowse(HWND hwndDlg
, PACTION_DIALOG pNewAct
, BOOL bEdit
= FALSE
)
820 WCHAR szFile
[MAX_PATH
];
823 WCHAR szFilter
[MAX_PATH
];
824 LoadStringW(shell32_hInstance
, IDS_EXE_FILTER
, szFilter
, _countof(szFilter
));
826 CStringW
strTitle(MAKEINTRESOURCEW(IDS_OPEN_WITH
));
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
))
842 CStringW str
= szFile
;
844 SetDlgItemTextW(hwndDlg
, IDC_ACTION_APP
, str
);
848 SetDlgItemTextW(hwndDlg
, IDC_ACTION_APP
, szFile
);
853 /////////////////////////////////////////////////////////////////////////////
857 NewActionDlg_OnOK(HWND hwndDlg
, PACTION_DIALOG pNewAct
)
860 GetDlgItemTextW(hwndDlg
, IDC_ACTION_ACTION
, pNewAct
->szAction
, _countof(pNewAct
->szAction
));
861 StrTrimW(pNewAct
->szAction
, g_pszSpace
);
862 if (pNewAct
->szAction
[0] == 0)
864 // action was empty, error
865 HWND hwndCtrl
= GetDlgItem(hwndDlg
, IDC_ACTION_ACTION
);
866 SendMessageW(hwndCtrl
, EM_SETSEL
, 0, -1);
868 CStringW
strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION
));
869 CStringW
strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES
));
870 MessageBoxW(hwndDlg
, strText
, strTitle
, MB_ICONERROR
);
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
)
880 // app was empty or invalid
881 HWND hwndCtrl
= GetDlgItem(hwndDlg
, IDC_ACTION_APP
);
882 SendMessageW(hwndCtrl
, EM_SETSEL
, 0, -1);
884 CStringW
strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM
));
885 CStringW
strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES
));
886 MessageBoxW(hwndDlg
, strText
, strTitle
, MB_ICONERROR
);
890 EndDialog(hwndDlg
, IDOK
);
894 static INT_PTR CALLBACK
895 NewActionDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
897 static PACTION_DIALOG s_pNewAct
= NULL
;
902 s_pNewAct
= (PACTION_DIALOG
)lParam
;
903 s_pNewAct
->bUseDDE
= FALSE
;
904 EnableWindow(GetDlgItem(hwndDlg
, IDC_ACTION_USE_DDE
), FALSE
);
908 switch (LOWORD(wParam
))
911 NewActionDlg_OnOK(hwndDlg
, s_pNewAct
);
915 EndDialog(hwndDlg
, IDCANCEL
);
918 case IDC_ACTION_BROWSE
:
919 ActionDlg_OnBrowse(hwndDlg
, s_pNewAct
, FALSE
);
927 /////////////////////////////////////////////////////////////////////////////
931 EditActionDlg_OnOK(HWND hwndDlg
, PACTION_DIALOG pEditAct
)
934 GetDlgItemTextW(hwndDlg
, IDC_ACTION_ACTION
, pEditAct
->szAction
, _countof(pEditAct
->szAction
));
935 StrTrimW(pEditAct
->szAction
, g_pszSpace
);
936 if (pEditAct
->szAction
[0] == 0)
938 // action was empty. show error
939 HWND hwndCtrl
= GetDlgItem(hwndDlg
, IDC_ACTION_ACTION
);
940 SendMessageW(hwndCtrl
, EM_SETSEL
, 0, -1);
942 CStringW
strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION
));
943 CStringW
strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES
));
944 MessageBoxW(hwndDlg
, strText
, strTitle
, MB_ICONERROR
);
948 GetDlgItemTextW(hwndDlg
, IDC_ACTION_APP
, pEditAct
->szApp
, _countof(pEditAct
->szApp
));
949 StrTrimW(pEditAct
->szApp
, g_pszSpace
);
950 if (pEditAct
->szApp
[0] == 0)
952 // app was empty. show error
953 HWND hwndCtrl
= GetDlgItem(hwndDlg
, IDC_ACTION_APP
);
954 SendMessageW(hwndCtrl
, EM_SETSEL
, 0, -1);
956 CStringW
strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM
));
957 CStringW
strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES
));
958 MessageBoxW(hwndDlg
, strText
, strTitle
, MB_ICONERROR
);
961 EndDialog(hwndDlg
, IDOK
);
965 static INT_PTR CALLBACK
966 EditActionDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
968 static PACTION_DIALOG s_pEditAct
= NULL
;
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
);
981 CStringW
str(MAKEINTRESOURCEW(IDS_EDITING_ACTION
));
982 str
+= s_pEditAct
->ClassName
;
983 SetWindowTextW(hwndDlg
, str
);
988 switch (LOWORD(wParam
))
991 EditActionDlg_OnOK(hwndDlg
, s_pEditAct
);
995 EndDialog(hwndDlg
, IDCANCEL
);
998 case IDC_ACTION_BROWSE
:
999 ActionDlg_OnBrowse(hwndDlg
, s_pEditAct
, TRUE
);
1007 /////////////////////////////////////////////////////////////////////////////
1011 EditTypeDlg_UpdateEntryIcon(HWND hwndDlg
, PEDITTYPE_DIALOG pEditType
,
1012 LPCWSTR IconPath
, INT IconIndex
)
1014 PFILE_TYPE_ENTRY pEntry
= pEditType
->pEntry
;
1016 BOOL bIconSet
= FALSE
;
1017 if (IconPath
&& IconPath
[0])
1019 DestroyIcon(pEntry
->hIconLarge
);
1020 DestroyIcon(pEntry
->hIconSmall
);
1021 pEntry
->hIconLarge
= DoExtractIcon(pEntry
, IconPath
, IconIndex
, FALSE
);
1022 pEntry
->hIconSmall
= DoExtractIcon(pEntry
, IconPath
, IconIndex
, TRUE
);
1024 bIconSet
= (pEntry
->hIconLarge
&& pEntry
->hIconSmall
);
1028 StringCbCopyW(pEntry
->IconPath
, sizeof(pEntry
->IconPath
), IconPath
);
1029 pEntry
->nIconIndex
= IconIndex
;
1033 SetFileTypeEntryDefaultIcon(pEntry
);
1036 HWND hListView
= pEditType
->hwndLV
;
1037 HIMAGELIST himlLarge
= ListView_GetImageList(hListView
, LVSIL_NORMAL
);
1038 HIMAGELIST himlSmall
= ListView_GetImageList(hListView
, LVSIL_SMALL
);
1040 INT iLargeImage
= ImageList_AddIcon(himlLarge
, pEntry
->hIconLarge
);
1041 INT iSmallImage
= ImageList_AddIcon(himlSmall
, pEntry
->hIconSmall
);
1042 ASSERT(iLargeImage
== iSmallImage
);
1044 INT iItem
= ListView_GetNextItem(hListView
, -1, LVNI_SELECTED
);
1047 LV_ITEMW Item
= { LVIF_IMAGE
, iItem
};
1048 Item
.iImage
= iSmallImage
;
1049 ListView_SetItem(hListView
, &Item
);
1055 EditTypeDlg_WriteClass(HWND hwndDlg
, PEDITTYPE_DIALOG pEditType
,
1056 LPCWSTR ClassKey
, LPCWSTR ClassName
, INT cchName
)
1058 PFILE_TYPE_ENTRY pEntry
= pEditType
->pEntry
;
1060 if (ClassKey
[0] == 0)
1063 // create or open class key
1065 if (RegCreateKeyExW(HKEY_CLASSES_ROOT
, ClassKey
, 0, NULL
, 0, KEY_WRITE
, NULL
,
1066 &hClassKey
, NULL
) != ERROR_SUCCESS
)
1071 // create "DefaultIcon" key
1072 if (pEntry
->IconPath
[0])
1074 HKEY hDefaultIconKey
;
1075 if (RegCreateKeyExW(hClassKey
, L
"DefaultIcon", 0, NULL
, 0, KEY_WRITE
, NULL
,
1076 &hDefaultIconKey
, NULL
) == ERROR_SUCCESS
)
1078 WCHAR szText
[MAX_PATH
];
1079 StringCbPrintfW(szText
, sizeof(szText
), L
"%s,%d",
1080 pEntry
->IconPath
, pEntry
->nIconIndex
);
1082 // set icon location
1083 DWORD dwSize
= (lstrlenW(szText
) + 1) * sizeof(WCHAR
);
1084 RegSetValueExW(hDefaultIconKey
, NULL
, 0, REG_EXPAND_SZ
, LPBYTE(szText
), dwSize
);
1086 RegCloseKey(hDefaultIconKey
);
1090 // create "shell" key
1092 if (RegCreateKeyExW(hClassKey
, L
"shell", 0, NULL
, 0, KEY_WRITE
, NULL
,
1093 &hShellKey
, NULL
) != ERROR_SUCCESS
)
1095 RegCloseKey(hClassKey
);
1099 // delete shell commands
1100 WCHAR szVerbName
[64];
1102 while (RegEnumKeyW(hShellKey
, dwIndex
, szVerbName
, _countof(szVerbName
)) == ERROR_SUCCESS
)
1104 if (pEditType
->CommandLineMap
.FindKey(szVerbName
) == -1)
1106 // doesn't exist in CommandLineMap, then delete it
1107 if (SHDeleteKeyW(hShellKey
, szVerbName
) == ERROR_SUCCESS
)
1115 // set default action
1116 RegSetValueExW(hShellKey
, NULL
, 0, REG_SZ
,
1117 LPBYTE(pEditType
->szDefaultVerb
), sizeof(pEditType
->szDefaultVerb
));
1119 // write shell commands
1120 const INT nCount
= pEditType
->CommandLineMap
.GetSize();
1121 for (INT i
= 0; i
< nCount
; ++i
)
1123 CStringW
& key
= pEditType
->CommandLineMap
.GetKeyAt(i
);
1124 CStringW
& value
= pEditType
->CommandLineMap
.GetValueAt(i
);
1128 if (RegCreateKeyExW(hShellKey
, key
, 0, NULL
, 0, KEY_WRITE
, NULL
,
1129 &hVerbKey
, NULL
) == ERROR_SUCCESS
)
1131 // create command key
1133 if (RegCreateKeyExW(hVerbKey
, L
"command", 0, NULL
, 0, KEY_WRITE
, NULL
,
1134 &hCommandKey
, NULL
) == ERROR_SUCCESS
)
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
);
1140 RegCloseKey(hCommandKey
);
1143 RegCloseKey(hVerbKey
);
1147 // set class name to class key
1148 RegSetValueExW(hClassKey
, NULL
, 0, REG_SZ
, LPBYTE(ClassName
), cchName
);
1150 RegCloseKey(hShellKey
);
1151 RegCloseKey(hClassKey
);
1157 EditTypeDlg_ReadClass(HWND hwndDlg
, PEDITTYPE_DIALOG pEditType
, LPCWSTR ClassKey
)
1161 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, ClassKey
, 0, KEY_READ
, &hClassKey
) != ERROR_SUCCESS
)
1166 if (RegOpenKeyExW(hClassKey
, L
"shell", 0, KEY_READ
, &hShellKey
) != ERROR_SUCCESS
)
1168 RegCloseKey(hClassKey
);
1172 WCHAR DefaultVerb
[64];
1173 DWORD dwSize
= sizeof(DefaultVerb
);
1174 if (RegQueryValueExW(hShellKey
, NULL
, NULL
, NULL
,
1175 LPBYTE(DefaultVerb
), &dwSize
) == ERROR_SUCCESS
)
1177 StringCbCopyW(pEditType
->szDefaultVerb
, sizeof(pEditType
->szDefaultVerb
), DefaultVerb
);
1181 StringCbCopyW(pEditType
->szDefaultVerb
, sizeof(pEditType
->szDefaultVerb
), L
"open");
1184 // enumerate shell verbs
1185 WCHAR szVerbName
[64];
1187 while (RegEnumKeyW(hShellKey
, dwIndex
, szVerbName
, _countof(szVerbName
)) == ERROR_SUCCESS
)
1191 LONG nResult
= RegOpenKeyExW(hShellKey
, szVerbName
, 0, KEY_READ
, &hVerbKey
);
1192 if (nResult
== ERROR_SUCCESS
)
1196 nResult
= RegOpenKeyExW(hVerbKey
, L
"command", 0, KEY_READ
, &hCommandKey
);
1197 if (nResult
== ERROR_SUCCESS
)
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
)
1205 pEditType
->CommandLineMap
.SetAt(szVerbName
, szValue
);
1208 RegCloseKey(hCommandKey
);
1211 RegCloseKey(hVerbKey
);
1213 SendDlgItemMessageW(hwndDlg
, IDC_EDITTYPE_LISTBOX
, LB_ADDSTRING
, 0, LPARAM(szVerbName
));
1217 RegCloseKey(hShellKey
);
1218 RegCloseKey(hClassKey
);
1224 EditTypeDlg_OnOK(HWND hwndDlg
, PEDITTYPE_DIALOG pEditType
)
1226 PFILE_TYPE_ENTRY pEntry
= pEditType
->pEntry
;
1229 GetDlgItemTextW(hwndDlg
, IDC_EDITTYPE_TEXT
, pEntry
->ClassName
, _countof(pEntry
->ClassName
));
1230 StrTrimW(pEntry
->ClassName
, g_pszSpace
);
1232 // update entry icon
1233 EditTypeDlg_UpdateEntryIcon(hwndDlg
, pEditType
, pEditType
->szIconPath
, pEditType
->nIconIndex
);
1236 EditTypeDlg_WriteClass(hwndDlg
, pEditType
, pEntry
->ClassKey
, pEntry
->ClassName
,
1237 _countof(pEntry
->ClassName
));
1239 // update the icon cache
1240 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_FLUSHNOWAIT
, NULL
, NULL
);
1242 EndDialog(hwndDlg
, IDOK
);
1246 EditTypeDlg_OnRemove(HWND hwndDlg
, PEDITTYPE_DIALOG pEditType
)
1248 // get current selection
1249 INT iItem
= SendDlgItemMessageW(hwndDlg
, IDC_EDITTYPE_LISTBOX
, LB_GETCURSEL
, 0, 0);
1250 if (iItem
== LB_ERR
)
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
)
1262 SendDlgItemMessageW(hwndDlg
, IDC_EDITTYPE_LISTBOX
, LB_GETTEXT
, iItem
, (LPARAM
)szText
);
1263 StrTrimW(szText
, g_pszSpace
);
1266 pEditType
->CommandLineMap
.Remove(szText
);
1267 SendDlgItemMessageW(hwndDlg
, IDC_EDITTYPE_LISTBOX
, LB_DELETESTRING
, iItem
, 0);
1272 EditTypeDlg_OnCommand(HWND hwndDlg
, UINT id
, UINT code
, PEDITTYPE_DIALOG pEditType
)
1275 ACTION_DIALOG action
;
1279 EditTypeDlg_OnOK(hwndDlg
, pEditType
);
1283 EndDialog(hwndDlg
, IDCANCEL
);
1286 case IDC_EDITTYPE_CHANGE_ICON
:
1287 EditTypeDlg_OnChangeIcon(hwndDlg
, pEditType
);
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
)))
1298 if (SendMessageW(action
.hwndLB
, LB_FINDSTRING
, -1, (LPARAM
)action
.szAction
) != LB_ERR
)
1300 // already exists, error
1301 HWND hwndCtrl
= GetDlgItem(hwndDlg
, IDC_ACTION_ACTION
);
1302 SendMessageW(hwndCtrl
, EM_SETSEL
, 0, -1);
1305 CStringW strText
, strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES
));
1306 strText
.Format(IDS_ACTION_EXISTS
, action
.szAction
);
1307 MessageBoxW(hwndDlg
, strText
, strTitle
, MB_ICONERROR
);
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)
1319 StringCbCopyW(pEditType
->szDefaultVerb
, sizeof(pEditType
->szDefaultVerb
), action
.szAction
);
1320 InvalidateRect(action
.hwndLB
, NULL
, TRUE
);
1326 case IDC_EDITTYPE_LISTBOX
:
1327 if (code
== LBN_SELCHANGE
)
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)
1334 EnableWindow(GetDlgItem(hwndDlg
, IDC_EDITTYPE_SET_DEFAULT
), FALSE
);
1338 EnableWindow(GetDlgItem(hwndDlg
, IDC_EDITTYPE_SET_DEFAULT
), TRUE
);
1342 else if (code
!= LBN_DBLCLK
)
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
)
1357 SendMessageW(action
.hwndLB
, LB_GETTEXT
, iItem
, LPARAM(action
.szAction
));
1361 iIndex
= pEditType
->CommandLineMap
.FindKey(action
.szAction
);
1362 CStringW str
= pEditType
->CommandLineMap
.GetValueAt(iIndex
);
1363 StringCbCopyW(action
.szApp
, sizeof(action
.szApp
), LPCWSTR(str
));
1367 if (IDOK
== DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_ACTION
), hwndDlg
,
1368 EditActionDlgProc
, LPARAM(&action
)))
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
);
1376 case IDC_EDITTYPE_REMOVE
:
1377 EditTypeDlg_OnRemove(hwndDlg
, pEditType
);
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
)
1386 SendMessageW(action
.hwndLB
, LB_GETTEXT
, iItem
, LPARAM(action
.szAction
));
1389 StringCbCopyW(pEditType
->szDefaultVerb
, sizeof(pEditType
->szDefaultVerb
), action
.szAction
);
1390 EnableWindow(GetDlgItem(hwndDlg
, IDC_EDITTYPE_SET_DEFAULT
), FALSE
);
1391 InvalidateRect(action
.hwndLB
, NULL
, TRUE
);
1397 EditTypeDlg_OnInitDialog(HWND hwndDlg
, PEDITTYPE_DIALOG pEditType
)
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");
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
);
1410 // is listbox empty?
1411 if (SendDlgItemMessageW(hwndDlg
, IDC_EDITTYPE_LISTBOX
, LB_GETCOUNT
, 0, 0) == 0)
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
);
1419 // select first item
1420 SendDlgItemMessageW(hwndDlg
, IDC_EDITTYPE_LISTBOX
, LB_SETCURSEL
, 0, 0);
1423 EnableWindow(GetDlgItem(hwndDlg
, IDC_EDITTYPE_SAME_WINDOW
), FALSE
);
1429 static INT_PTR CALLBACK
1430 EditTypeDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1432 static PEDITTYPE_DIALOG s_pEditType
= NULL
;
1433 LPDRAWITEMSTRUCT pDraw
;
1434 LPMEASUREITEMSTRUCT pMeasure
;
1439 s_pEditType
= (PEDITTYPE_DIALOG
)lParam
;
1440 return EditTypeDlg_OnInitDialog(hwndDlg
, s_pEditType
);
1443 pDraw
= LPDRAWITEMSTRUCT(lParam
);
1444 return EditTypeDlg_OnDrawItem(hwndDlg
, pDraw
, s_pEditType
);
1446 case WM_MEASUREITEM
:
1447 pMeasure
= LPMEASUREITEMSTRUCT(lParam
);
1448 return EditTypeDlg_OnMeasureItem(hwndDlg
, pMeasure
, s_pEditType
);
1451 EditTypeDlg_OnCommand(hwndDlg
, LOWORD(wParam
), HIWORD(wParam
), s_pEditType
);
1458 /////////////////////////////////////////////////////////////////////////////
1462 FileTypesDlg_CompareItems(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
1464 PFILE_TYPE_ENTRY Entry1
, Entry2
;
1467 Entry1
= (PFILE_TYPE_ENTRY
)lParam1
;
1468 Entry2
= (PFILE_TYPE_ENTRY
)lParam2
;
1470 x
= wcsicmp(Entry1
->FileExtension
, Entry2
->FileExtension
);
1474 return wcsicmp(Entry1
->FileDescription
, Entry2
->FileDescription
);
1478 FileTypesDlg_InitListView(HWND hwndDlg
, HWND hListView
)
1484 INT columnSize
= 140;
1486 if (!LoadStringW(shell32_hInstance
, IDS_COLUMN_EXTENSION
, szName
, _countof(szName
)))
1488 // default to english
1489 wcscpy(szName
, L
"Extensions");
1492 // make sure its null terminated
1493 szName
[_countof(szName
) - 1] = 0;
1495 GetClientRect(hListView
, &clientRect
);
1496 ZeroMemory(&col
, sizeof(LV_COLUMN
));
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
);
1506 if (!LoadStringW(shell32_hInstance
, IDS_FILE_TYPES
, szName
, _countof(szName
)))
1508 // default to english
1509 wcscpy(szName
, L
"File Types");
1510 ERR("Failed to load localized string!\n");
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
);
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
);
1525 static PFILE_TYPE_ENTRY
1526 FileTypesDlg_DoList(HWND hwndDlg
)
1535 HIMAGELIST himlLarge
, himlSmall
;
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);
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
);
1548 FileTypesDlg_InitListView(hwndDlg
, hListView
);
1551 if (!LoadStringW(shell32_hInstance
, IDS_FILE_EXT_TYPE
, szFile
, _countof(szFile
)))
1553 // default to english
1554 wcscpy(szFile
, L
"%s File");
1556 szFile
[(_countof(szFile
)) - 1] = 0;
1558 dwName
= _countof(szName
);
1560 while (RegEnumKeyExW(HKEY_CLASSES_ROOT
, dwIndex
++, szName
, &dwName
,
1561 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1563 if (FileTypesDlg_InsertToLV(hListView
, szName
, iItem
, szFile
))
1565 dwName
= _countof(szName
);
1568 // Leave if the list is empty
1573 ListView_SortItems(hListView
, FileTypesDlg_CompareItems
, NULL
);
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
;
1581 ListView_SetItem(hListView
, &lvItem
);
1583 lvItem
.mask
= LVIF_PARAM
;
1584 ListView_GetItem(hListView
, &lvItem
);
1586 return (PFILE_TYPE_ENTRY
)lvItem
.lParam
;
1589 static inline PFILE_TYPE_ENTRY
1590 FileTypesDlg_GetEntry(HWND hListView
, INT iItem
= -1)
1594 iItem
= ListView_GetNextItem(hListView
, -1, LVNI_SELECTED
);
1599 LV_ITEMW lvItem
= { LVIF_PARAM
, iItem
};
1600 if (ListView_GetItem(hListView
, &lvItem
))
1601 return (PFILE_TYPE_ENTRY
)lvItem
.lParam
;
1607 FileTypesDlg_OnDelete(HWND hwndDlg
)
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
)
1613 FileTypesDlg_RemoveExt(hwndDlg
);
1618 FileTypesDlg_OnItemChanging(HWND hwndDlg
, PFILE_TYPE_ENTRY pEntry
)
1621 static HBITMAP s_hbmProgram
= NULL
;
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
);
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
);
1635 // delete previous program image
1638 DeleteObject(s_hbmProgram
);
1639 s_hbmProgram
= NULL
;
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
));
1650 if (pEntry
->AppName
[0])
1651 SetDlgItemTextW(hwndDlg
, IDC_FILETYPES_APPNAME
, pEntry
->AppName
);
1653 SetDlgItemTextW(hwndDlg
, IDC_FILETYPES_APPNAME
, L
"ReactOS");
1655 // Enable the Delete button
1656 if (pEntry
->EditFlags
& 0x00000010) // FTA_NoRemove
1657 EnableWindow(GetDlgItem(hwndDlg
, IDC_FILETYPES_DELETE
), FALSE
);
1659 EnableWindow(GetDlgItem(hwndDlg
, IDC_FILETYPES_DELETE
), TRUE
);
1662 // IDD_FOLDER_OPTIONS_FILETYPES
1664 FolderOptionsFileTypesDlg(
1671 PFILE_TYPE_ENTRY pEntry
;
1673 NEWEXT_DIALOG newext
;
1674 EDITTYPE_DIALOG edittype
;
1679 pEntry
= FileTypesDlg_DoList(hwndDlg
);
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
);
1688 switch (LOWORD(wParam
))
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
))
1695 FileTypesDlg_AddExt(hwndDlg
, newext
.szExt
, newext
.szFileType
);
1699 case IDC_FILETYPES_DELETE
:
1700 FileTypesDlg_OnDelete(hwndDlg
);
1703 case IDC_FILETYPES_CHANGE
:
1704 pEntry
= FileTypesDlg_GetEntry(GetDlgItem(hwndDlg
, IDC_FILETYPES_LISTVIEW
));
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
);
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
);
1725 lppl
= (LPNMLISTVIEW
) lParam
;
1726 switch (lppl
->hdr
.code
)
1730 LV_KEYDOWN
*pKeyDown
= (LV_KEYDOWN
*)lParam
;
1731 if (pKeyDown
->wVKey
== VK_DELETE
)
1733 FileTypesDlg_OnDelete(hwndDlg
);
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
);
1745 case LVN_DELETEALLITEMS
:
1746 return FALSE
; // send LVN_DELETEITEM
1748 case LVN_DELETEITEM
:
1749 pEntry
= FileTypesDlg_GetEntry(lppl
->hdr
.hwndFrom
, lppl
->iItem
);
1752 DestroyIcon(pEntry
->hIconLarge
);
1753 DestroyIcon(pEntry
->hIconSmall
);
1754 HeapFree(GetProcessHeap(), 0, pEntry
);
1758 case LVN_ITEMCHANGING
:
1759 pEntry
= FileTypesDlg_GetEntry(lppl
->hdr
.hwndFrom
, lppl
->iItem
);
1765 if (!(lppl
->uOldState
& LVIS_FOCUSED
) && (lppl
->uNewState
& LVIS_FOCUSED
))
1767 FileTypesDlg_OnItemChanging(hwndDlg
, pEntry
);
1772 // On page activation, set the focus to the listview
1773 SetFocus(GetDlgItem(hwndDlg
, IDC_FILETYPES_LISTVIEW
));