reactos/dll/win32/shell32/dialogs/filetypes.cpp
Joachim Henze a08b83a90b
[SHELL32] Fix 2 compiler warnings for the rls-cfg 'unused variable' (#6539)
I noticed it on releases/0.4.10 with the RosBEWin2.1.6 GCC4.7.2 *rls* configuration:

C:/0410rls/reactos/dll/win32/shell32/dialogs/filetypes.cpp: In function 'BOOL FileTypesDlg_InsertToLV(HWND, LPCWSTR, INT, LPCWSTR)':
C:/0410rls/reactos/dll/win32/shell32/dialogs/filetypes.cpp:663:9: warning: variable 'iLargeImage' set but not used [-Wunused-but-set-variable]
C:/0410rls/reactos/dll/win32/shell32/dialogs/filetypes.cpp: In function 'BOOL EditTypeDlg_UpdateEntryIcon(HWND, PEDITTYPE_DIALOG, LPCWSTR, INT)':
C:/0410rls/reactos/dll/win32/shell32/dialogs/filetypes.cpp:1040:9: warning: unused variable 'iLargeImage' [-Wunused-variable]

But I do assume, that MSVC compilers would also complain about that in *rls* cfg.

Please notice that before 0.4.10-dev-202-g 698cbc6184 which did splitup and restructure the code
this function was placed within the file folder_options.cpp and was named
InsertFileType(HWND hDlgCtrl, WCHAR * szName, PINT iItem, WCHAR * szFile)
and not yet within file_types.cpp with the new name
FileTypesDlg_InsertToLV(HWND hListView, LPCWSTR szName, INT iItem, LPCWSTR szFile)
Back then it did not have the iLargeImage variable yet, and it also didn't warn upon rls-cfg-compilation.
Therefore 0.4.10-dev-202-g 698cbc6184 from (#582) is indeed the *guilty revision* (2018-06-06).
It was done in the very first commit of that PR 2fe0eab721
It's bad practice to move and refactor/extend code in functionality within the very same commit, as it makes reviewing the changes much harder.

That assert never fired for the last 6 years, therefore it would have been okay also to strip it together with the variable, but using DBG_UNREFERENCED_LOCAL_VARIABLE(iLargeImage); allows to keep the assert for master.
2024-02-26 13:42:13 +01:00

1796 lines
56 KiB
C++

/*
* 'File Types' tab property sheet of Folder Options
*
* Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org>
* Copyright 2016-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL (fprop);
// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210
// Verbs: Open / RunAs
// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0
/////////////////////////////////////////////////////////////////////////////
typedef struct FILE_TYPE_ENTRY
{
WCHAR FileExtension[30];
WCHAR FileDescription[100];
WCHAR ClassKey[MAX_PATH];
WCHAR ClassName[64];
DWORD EditFlags;
WCHAR AppName[64];
HICON hIconLarge;
HICON hIconSmall;
WCHAR ProgramPath[MAX_PATH];
WCHAR IconPath[MAX_PATH];
INT nIconIndex;
} FILE_TYPE_ENTRY, *PFILE_TYPE_ENTRY;
static BOOL
DeleteExt(HWND hwndDlg, LPCWSTR pszExt)
{
if (*pszExt != L'.')
return FALSE;
// open ".ext" key
HKEY hKey;
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
return FALSE;
// query "extfile" key name
WCHAR szValue[64] = { 0 };
DWORD cbValue = sizeof(szValue);
RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(szValue), &cbValue);
RegCloseKey(hKey);
// delete "extfile" key (if any)
if (szValue[0])
SHDeleteKeyW(HKEY_CLASSES_ROOT, szValue);
// delete ".ext" key
return SHDeleteKeyW(HKEY_CLASSES_ROOT, pszExt) == ERROR_SUCCESS;
}
static inline HICON
DoExtractIcon(PFILE_TYPE_ENTRY Entry, LPCWSTR IconPath,
INT iIndex = 0, BOOL bSmall = FALSE)
{
HICON hIcon = NULL;
if (iIndex < 0)
{
// A negative value will be interpreted as a negated resource ID.
iIndex = -iIndex;
INT cx, cy;
HINSTANCE hDLL = LoadLibraryExW(IconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (bSmall)
{
cx = GetSystemMetrics(SM_CXSMICON);
cy = GetSystemMetrics(SM_CYSMICON);
}
else
{
cx = GetSystemMetrics(SM_CXICON);
cy = GetSystemMetrics(SM_CYICON);
}
hIcon = HICON(LoadImageW(hDLL, MAKEINTRESOURCEW(iIndex), IMAGE_ICON,
cx, cy, 0));
FreeLibrary(hDLL);
}
else
{
// A positive value is icon index.
if (bSmall)
ExtractIconExW(IconPath, iIndex, NULL, &hIcon, 1);
else
ExtractIconExW(IconPath, iIndex, &hIcon, NULL, 1);
}
return hIcon;
}
static void
DoFileTypeIconLocation(PFILE_TYPE_ENTRY Entry, LPCWSTR IconLocation)
{
// Expand the REG_EXPAND_SZ string by environment variables
WCHAR szLocation[MAX_PATH + 32];
if (!ExpandEnvironmentStringsW(IconLocation, szLocation, _countof(szLocation)))
return;
Entry->nIconIndex = PathParseIconLocationW(szLocation);
StringCbCopyW(Entry->IconPath, sizeof(Entry->IconPath), szLocation);
Entry->hIconLarge = DoExtractIcon(Entry, szLocation, Entry->nIconIndex, FALSE);
Entry->hIconSmall = DoExtractIcon(Entry, szLocation, Entry->nIconIndex, TRUE);
}
static BOOL
GetFileTypeIconsEx(PFILE_TYPE_ENTRY Entry, LPCWSTR IconLocation)
{
Entry->hIconLarge = Entry->hIconSmall = NULL;
if (lstrcmpiW(Entry->FileExtension, L".exe") == 0 ||
lstrcmpiW(Entry->FileExtension, L".scr") == 0)
{
// It's an executable
Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE));
INT cx = GetSystemMetrics(SM_CXSMICON);
INT cy = GetSystemMetrics(SM_CYSMICON);
Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE),
IMAGE_ICON, cx, cy, 0));
StringCbCopyW(Entry->IconPath, sizeof(Entry->IconPath), g_pszShell32);
Entry->nIconIndex = -IDI_SHELL_EXE;
}
else if (lstrcmpW(IconLocation, L"%1") == 0)
{
return FALSE; // self icon
}
else
{
DoFileTypeIconLocation(Entry, IconLocation);
}
return Entry->hIconLarge && Entry->hIconSmall;
}
static BOOL
GetFileTypeIconsByKey(HKEY hKey, PFILE_TYPE_ENTRY Entry)
{
Entry->hIconLarge = Entry->hIconSmall = NULL;
// Open the "DefaultIcon" registry key
HKEY hDefIconKey;
LONG nResult = RegOpenKeyExW(hKey, L"DefaultIcon", 0, KEY_READ, &hDefIconKey);
if (nResult != ERROR_SUCCESS)
return FALSE;
// Get the icon location
WCHAR szLocation[MAX_PATH + 32] = { 0 };
DWORD dwSize = sizeof(szLocation);
nResult = RegQueryValueExW(hDefIconKey, NULL, NULL, NULL, LPBYTE(szLocation), &dwSize);
RegCloseKey(hDefIconKey);
if (nResult != ERROR_SUCCESS || szLocation[0] == 0)
return FALSE;
return GetFileTypeIconsEx(Entry, szLocation);
}
static BOOL
QueryFileDescription(LPCWSTR ProgramPath, LPWSTR pszName, INT cchName)
{
SHFILEINFOW FileInfo = { 0 };
if (SHGetFileInfoW(ProgramPath, 0, &FileInfo, sizeof(FileInfo), SHGFI_DISPLAYNAME))
{
StringCchCopyW(pszName, cchName, FileInfo.szDisplayName);
return TRUE;
}
return !!GetFileTitleW(ProgramPath, pszName, cchName);
}
static void
SetFileTypeEntryDefaultIcon(PFILE_TYPE_ENTRY Entry)
{
Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS));
INT cxSmall = GetSystemMetrics(SM_CXSMICON);
INT cySmall = GetSystemMetrics(SM_CYSMICON);
Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS),
IMAGE_ICON, cxSmall, cySmall, 0));
StringCbCopyW(Entry->IconPath, sizeof(Entry->IconPath), g_pszShell32);
Entry->nIconIndex = -IDI_SHELL_FOLDER_OPTIONS;
}
/////////////////////////////////////////////////////////////////////////////
// EditTypeDlg
#define LISTBOX_MARGIN 2
typedef struct EDITTYPE_DIALOG
{
HWND hwndLV;
PFILE_TYPE_ENTRY pEntry;
CSimpleMap<CStringW, CStringW> CommandLineMap;
WCHAR szIconPath[MAX_PATH];
INT nIconIndex;
WCHAR szDefaultVerb[64];
} EDITTYPE_DIALOG, *PEDITTYPE_DIALOG;
static void
EditTypeDlg_OnChangeIcon(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
{
WCHAR szPath[MAX_PATH];
INT IconIndex;
ExpandEnvironmentStringsW(pEditType->szIconPath, szPath, _countof(szPath));
IconIndex = pEditType->nIconIndex;
if (PickIconDlg(hwndDlg, szPath, _countof(szPath), &IconIndex))
{
// replace Windows directory with "%SystemRoot%" (for portability)
WCHAR szWinDir[MAX_PATH];
GetWindowsDirectoryW(szWinDir, _countof(szWinDir));
if (wcsstr(szPath, szWinDir) == 0)
{
CStringW str(L"%SystemRoot%");
str += &szPath[wcslen(szWinDir)];
StringCbCopyW(szPath, sizeof(szPath), LPCWSTR(str));
}
// update FILE_TYPE_ENTRY
PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
DestroyIcon(pEntry->hIconLarge);
DestroyIcon(pEntry->hIconSmall);
pEntry->hIconLarge = DoExtractIcon(pEntry, szPath, IconIndex, FALSE);
pEntry->hIconSmall = DoExtractIcon(pEntry, szPath, IconIndex, TRUE);
// update EDITTYPE_DIALOG
StringCbCopyW(pEditType->szIconPath, sizeof(pEditType->szIconPath), szPath);
pEditType->nIconIndex = IconIndex;
// set icon to dialog
SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_ICON, STM_SETICON, (WPARAM)pEntry->hIconLarge, 0);
}
}
static BOOL
EditTypeDlg_OnDrawItem(HWND hwndDlg, LPDRAWITEMSTRUCT pDraw, PEDITTYPE_DIALOG pEditType)
{
WCHAR szText[64];
HFONT hFont, hFont2;
if (!pDraw)
return FALSE;
// fill rect and set colors
if (pDraw->itemState & ODS_SELECTED)
{
FillRect(pDraw->hDC, &pDraw->rcItem, HBRUSH(COLOR_HIGHLIGHT + 1));
SetTextColor(pDraw->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
SetBkColor(pDraw->hDC, GetSysColor(COLOR_HIGHLIGHT));
}
else
{
FillRect(pDraw->hDC, &pDraw->rcItem, HBRUSH(COLOR_WINDOW + 1));
SetTextColor(pDraw->hDC, GetSysColor(COLOR_WINDOWTEXT));
SetBkColor(pDraw->hDC, GetSysColor(COLOR_WINDOW));
}
// get listbox text
HWND hwndListBox = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
SendMessageW(hwndListBox, LB_GETTEXT, pDraw->itemID, (LPARAM)szText);
// is it default?
hFont = (HFONT)SendMessageW(hwndListBox, WM_GETFONT, 0, 0);
if (lstrcmpiW(pEditType->szDefaultVerb, szText) == 0)
{
// default. set bold
LOGFONTW lf;
GetObject(hFont, sizeof(lf), &lf);
lf.lfWeight = FW_BOLD;
hFont2 = CreateFontIndirectW(&lf);
if (hFont2)
{
HGDIOBJ hFontOld = SelectObject(pDraw->hDC, hFont2);
InflateRect(&pDraw->rcItem, -LISTBOX_MARGIN, -LISTBOX_MARGIN);
DrawTextW(pDraw->hDC, szText, -1, &pDraw->rcItem,
DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
InflateRect(&pDraw->rcItem, LISTBOX_MARGIN, LISTBOX_MARGIN);
SelectObject(pDraw->hDC, hFontOld);
DeleteObject(hFont2);
}
}
else
{
// non-default
InflateRect(&pDraw->rcItem, -LISTBOX_MARGIN, -LISTBOX_MARGIN);
DrawTextW(pDraw->hDC, szText, -1, &pDraw->rcItem,
DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
InflateRect(&pDraw->rcItem, LISTBOX_MARGIN, LISTBOX_MARGIN);
}
// draw focus rect
if (pDraw->itemState & ODS_FOCUS)
{
DrawFocusRect(pDraw->hDC, &pDraw->rcItem);
}
return TRUE;
}
static BOOL
EditTypeDlg_OnMeasureItem(HWND hwndDlg, LPMEASUREITEMSTRUCT pMeasure, PEDITTYPE_DIALOG pEditType)
{
if (!pMeasure)
return FALSE;
HWND hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
HDC hDC = GetDC(hwndLB);
if (hDC)
{
TEXTMETRICW tm;
GetTextMetricsW(hDC, &tm);
pMeasure->itemHeight = tm.tmHeight + LISTBOX_MARGIN * 2;
ReleaseDC(hwndLB, hDC);
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// NewExtDlg
typedef struct NEWEXT_DIALOG
{
HWND hwndLV;
RECT rcDlg;
BOOL bAdvanced;
INT dy;
WCHAR szExt[16];
WCHAR szFileType[64];
} NEWEXT_DIALOG, *PNEWEXT_DIALOG;
static VOID
NewExtDlg_OnAdvanced(HWND hwndDlg, PNEWEXT_DIALOG pNewExt)
{
// If "Advanced" button was clicked, then we shrink or expand the dialog.
RECT rc, rc1, rc2;
GetWindowRect(hwndDlg, &rc);
rc.bottom = rc.top + (pNewExt->rcDlg.bottom - pNewExt->rcDlg.top);
GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc1);
MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc1, 2);
GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rc2);
MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc2, 2);
if (pNewExt->bAdvanced)
{
rc1.top += pNewExt->dy;
rc1.bottom += pNewExt->dy;
rc2.top += pNewExt->dy;
rc2.bottom += pNewExt->dy;
ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_SHOWNOACTIVATE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_SHOWNOACTIVATE);
CStringW strLeft(MAKEINTRESOURCEW(IDS_NEWEXT_ADVANCED_LEFT));
SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, strLeft);
SetFocus(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX));
}
else
{
rc1.top -= pNewExt->dy;
rc1.bottom -= pNewExt->dy;
rc2.top -= pNewExt->dy;
rc2.bottom -= pNewExt->dy;
ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_HIDE);
CStringW strRight(MAKEINTRESOURCEW(IDS_NEWEXT_ADVANCED_RIGHT));
SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, strRight);
rc.bottom -= pNewExt->dy;
CStringW strText(MAKEINTRESOURCEW(IDS_NEWEXT_NEW));
SetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, strText);
}
HDWP hDWP = BeginDeferWindowPos(3);
if (hDWP)
hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDOK), NULL,
rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
SWP_NOACTIVATE | SWP_NOZORDER);
if (hDWP)
hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDCANCEL), NULL,
rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top,
SWP_NOACTIVATE | SWP_NOZORDER);
if (hDWP)
hDWP = DeferWindowPos(hDWP, hwndDlg, NULL,
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
SWP_NOACTIVATE | SWP_NOZORDER);
if (hDWP)
EndDeferWindowPos(hDWP);
}
static BOOL
NewExtDlg_OnInitDialog(HWND hwndDlg, PNEWEXT_DIALOG pNewExt)
{
pNewExt->bAdvanced = FALSE;
// get window rectangle
GetWindowRect(hwndDlg, &pNewExt->rcDlg);
// get delta Y
RECT rc1, rc2;
GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_EDIT), &rc1);
GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), &rc2);
pNewExt->dy = rc2.top - rc1.top;
// initialize
CStringW strText(MAKEINTRESOURCEW(IDS_NEWEXT_NEW));
SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_ADDSTRING, 0, (LPARAM)(LPCWSTR)strText);
SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_SETCURSEL, 0, 0);
SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_EDIT, EM_SETLIMITTEXT, _countof(pNewExt->szExt) - 1, 0);
// shrink it first time
NewExtDlg_OnAdvanced(hwndDlg, pNewExt);
return TRUE;
}
static BOOL
NewExtDlg_OnOK(HWND hwndDlg, PNEWEXT_DIALOG pNewExt)
{
LV_FINDINFO find;
INT iItem;
GetDlgItemTextW(hwndDlg, IDC_NEWEXT_EDIT, pNewExt->szExt, _countof(pNewExt->szExt));
StrTrimW(pNewExt->szExt, g_pszSpace);
_wcsupr(pNewExt->szExt);
GetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, pNewExt->szFileType, _countof(pNewExt->szFileType));
StrTrimW(pNewExt->szFileType, g_pszSpace);
if (pNewExt->szExt[0] == 0)
{
CStringW strText(MAKEINTRESOURCEW(IDS_NEWEXT_SPECIFY_EXT));
CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
return FALSE;
}
ZeroMemory(&find, sizeof(find));
find.flags = LVFI_STRING;
if (pNewExt->szExt[0] == L'.')
{
find.psz = &pNewExt->szExt[1];
}
else
{
find.psz = pNewExt->szExt;
}
iItem = ListView_FindItem(pNewExt->hwndLV, -1, &find);
if (iItem >= 0)
{
// already exists
// get file type
WCHAR szFileType[64];
LV_ITEM item;
ZeroMemory(&item, sizeof(item));
item.mask = LVIF_TEXT;
item.pszText = szFileType;
item.cchTextMax = _countof(szFileType);
item.iItem = iItem;
item.iSubItem = 1;
ListView_GetItem(pNewExt->hwndLV, &item);
// get text
CStringW strText;
strText.Format(IDS_NEWEXT_ALREADY_ASSOC, find.psz, szFileType, find.psz, szFileType);
// get title
CStringW strTitle;
strTitle.LoadString(IDS_NEWEXT_EXT_IN_USE);
if (MessageBoxW(hwndDlg, strText, strTitle, MB_ICONWARNING | MB_YESNO) == IDNO)
{
return FALSE;
}
// Delete the extension
CStringW strExt(L".");
strExt += find.psz;
strExt.MakeLower();
DeleteExt(hwndDlg, strExt);
// Delete the item
ListView_DeleteItem(pNewExt->hwndLV, iItem);
}
EndDialog(hwndDlg, IDOK);
return TRUE;
}
// IDD_NEWEXTENSION
static INT_PTR CALLBACK
NewExtDlgProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
static PNEWEXT_DIALOG s_pNewExt = NULL;
switch (uMsg)
{
case WM_INITDIALOG:
s_pNewExt = (PNEWEXT_DIALOG)lParam;
NewExtDlg_OnInitDialog(hwndDlg, s_pNewExt);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
NewExtDlg_OnOK(hwndDlg, s_pNewExt);
break;
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDC_NEWEXT_ADVANCED:
s_pNewExt->bAdvanced = !s_pNewExt->bAdvanced;
NewExtDlg_OnAdvanced(hwndDlg, s_pNewExt);
break;
}
break;
}
return 0;
}
static BOOL
FileTypesDlg_InsertToLV(HWND hListView, LPCWSTR szName, INT iItem, LPCWSTR szFile)
{
PFILE_TYPE_ENTRY Entry;
HKEY hKey;
LVITEMW lvItem;
DWORD dwSize;
DWORD dwType;
if (szName[0] != L'.')
{
// FIXME handle URL protocol handlers
return FALSE;
}
// get imagelists of listview
HIMAGELIST himlLarge = ListView_GetImageList(hListView, LVSIL_NORMAL);
HIMAGELIST himlSmall = ListView_GetImageList(hListView, LVSIL_SMALL);
// allocate file type entry
Entry = (PFILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FILE_TYPE_ENTRY));
if (!Entry)
return FALSE;
// open key
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
{
HeapFree(GetProcessHeap(), 0, Entry);
return FALSE;
}
// FIXME check for duplicates
// query for the default key
dwSize = sizeof(Entry->ClassKey);
if (RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(Entry->ClassKey), &dwSize) != ERROR_SUCCESS)
{
// no link available
Entry->ClassKey[0] = 0;
}
Entry->ClassName[0] = 0;
if (Entry->ClassKey[0])
{
HKEY hTemp;
// try open linked key
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS)
{
DWORD dwSize = sizeof(Entry->ClassName);
RegQueryValueExW(hTemp, NULL, NULL, NULL, LPBYTE(Entry->ClassName), &dwSize);
// use linked key
RegCloseKey(hKey);
hKey = hTemp;
}
}
// read friendly type name
if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription,
sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS)
{
// read file description
dwSize = sizeof(Entry->FileDescription);
Entry->FileDescription[0] = 0;
// read default key
RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(Entry->FileDescription), &dwSize);
}
// Read the EditFlags value
Entry->EditFlags = 0;
if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize))
{
if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD))
RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize);
}
// convert extension to upper case
wcscpy(Entry->FileExtension, szName);
_wcsupr(Entry->FileExtension);
// get icon
if (!GetFileTypeIconsByKey(hKey, Entry))
{
// set default icon
SetFileTypeEntryDefaultIcon(Entry);
}
// close key
RegCloseKey(hKey);
// get program path and app name
DWORD cch = _countof(Entry->ProgramPath);
if (S_OK == AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE,
Entry->FileExtension, NULL, Entry->ProgramPath, &cch))
{
QueryFileDescription(Entry->ProgramPath, Entry->AppName, _countof(Entry->AppName));
}
else
{
Entry->ProgramPath[0] = Entry->AppName[0] = 0;
}
// add icon to imagelist
INT iLargeImage = -1, iSmallImage = -1;
if (Entry->hIconLarge && Entry->hIconSmall)
{
iLargeImage = ImageList_AddIcon(himlLarge, Entry->hIconLarge);
iSmallImage = ImageList_AddIcon(himlSmall, Entry->hIconSmall);
ASSERT(iLargeImage == iSmallImage);
DBG_UNREFERENCED_LOCAL_VARIABLE(iLargeImage);
}
// Do not add excluded entries
if (Entry->EditFlags & 0x00000001) //FTA_Exclude
{
DestroyIcon(Entry->hIconLarge);
DestroyIcon(Entry->hIconSmall);
HeapFree(GetProcessHeap(), 0, Entry);
return FALSE;
}
if (!Entry->FileDescription[0])
{
// construct default 'FileExtensionFile' by formatting the uppercase extension
// with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File'
StringCbPrintfW(Entry->FileDescription, sizeof(Entry->FileDescription),
szFile, &Entry->FileExtension[1]);
}
ZeroMemory(&lvItem, sizeof(LVITEMW));
lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvItem.iSubItem = 0;
lvItem.pszText = &Entry->FileExtension[1];
lvItem.iItem = iItem;
lvItem.lParam = (LPARAM)Entry;
lvItem.iImage = iSmallImage;
SendMessageW(hListView, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
ZeroMemory(&lvItem, sizeof(LVITEMW));
lvItem.mask = LVIF_TEXT;
lvItem.pszText = Entry->FileDescription;
lvItem.iItem = iItem;
lvItem.iSubItem = 1;
ListView_SetItem(hListView, &lvItem);
return TRUE;
}
static BOOL
FileTypesDlg_AddExt(HWND hwndDlg, LPCWSTR pszExt, LPCWSTR pszFileType)
{
DWORD dwValue = 1;
HKEY hKey;
WCHAR szKey[13]; // max. "ft4294967295" + "\0"
LONG nResult;
// Search the next "ft%06u" key name
do
{
StringCbPrintfW(szKey, sizeof(szKey), L"ft%06u", dwValue);
nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hKey);
if (nResult != ERROR_SUCCESS)
break;
RegCloseKey(hKey);
++dwValue;
} while (dwValue != 0);
RegCloseKey(hKey);
if (dwValue == 0)
return FALSE;
// Create new "ft%06u" key
nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
if (ERROR_SUCCESS != nResult)
return FALSE;
RegCloseKey(hKey);
// Create the ".ext" key
WCHAR szExt[16];
if (*pszExt == L'.')
++pszExt;
StringCbPrintfW(szExt, sizeof(szExt), L".%s", pszExt);
_wcslwr(szExt);
nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
_wcsupr(szExt);
if (ERROR_SUCCESS != nResult)
return FALSE;
// Set the default value of ".ext" to "ft%06u"
DWORD dwSize = (lstrlen(szKey) + 1) * sizeof(WCHAR);
RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)szKey, dwSize);
RegCloseKey(hKey);
// Make up the file type name
WCHAR szFile[100];
CStringW strFormat(MAKEINTRESOURCEW(IDS_FILE_EXT_TYPE));
StringCbPrintfW(szFile, sizeof(szFile), strFormat, &szExt[1]);
// Insert an item to the listview
HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
INT iItem = ListView_GetItemCount(hListView);
if (!FileTypesDlg_InsertToLV(hListView, szExt, iItem, szFile))
return FALSE;
LV_ITEM item;
ZeroMemory(&item, sizeof(item));
item.mask = LVIF_STATE | LVIF_TEXT;
item.iItem = iItem;
item.state = LVIS_SELECTED | LVIS_FOCUSED;
item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
item.pszText = &szExt[1];
ListView_SetItem(hListView, &item);
item.pszText = szFile;
item.iSubItem = 1;
ListView_SetItem(hListView, &item);
ListView_EnsureVisible(hListView, iItem, FALSE);
return TRUE;
}
static BOOL
FileTypesDlg_RemoveExt(HWND hwndDlg)
{
HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
if (iItem == -1)
return FALSE;
WCHAR szExt[20];
szExt[0] = L'.';
ListView_GetItemText(hListView, iItem, 0, &szExt[1], _countof(szExt) - 1);
_wcslwr(szExt);
DeleteExt(hwndDlg, szExt);
ListView_DeleteItem(hListView, iItem);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// common code of NewActionDlg and EditActionDlg
typedef struct ACTION_DIALOG
{
HWND hwndLB;
WCHAR ClassName[64];
WCHAR szAction[64];
WCHAR szApp[MAX_PATH];
BOOL bUseDDE;
} ACTION_DIALOG, *PACTION_DIALOG;
static void
ActionDlg_OnBrowse(HWND hwndDlg, PACTION_DIALOG pNewAct, BOOL bEdit = FALSE)
{
WCHAR szFile[MAX_PATH];
szFile[0] = 0;
WCHAR szFilter[MAX_PATH];
LoadStringW(shell32_hInstance, IDS_EXE_FILTER, szFilter, _countof(szFilter));
CStringW strTitle(MAKEINTRESOURCEW(IDS_OPEN_WITH));
OPENFILENAMEW ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
ofn.hwndOwner = hwndDlg;
ofn.lpstrFilter = szFilter;
ofn.lpstrFile = szFile;
ofn.nMaxFile = _countof(szFile);
ofn.lpstrTitle = strTitle;
ofn.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"exe";
if (GetOpenFileNameW(&ofn))
{
if (bEdit)
{
CStringW str = szFile;
str += L" \"%1\"";
SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, str);
}
else
{
SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, szFile);
}
}
}
/////////////////////////////////////////////////////////////////////////////
// NewActionDlg
static void
NewActionDlg_OnOK(HWND hwndDlg, PACTION_DIALOG pNewAct)
{
// check action
GetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, pNewAct->szAction, _countof(pNewAct->szAction));
StrTrimW(pNewAct->szAction, g_pszSpace);
if (pNewAct->szAction[0] == 0)
{
// action was empty, error
HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
SetFocus(hwndCtrl);
CStringW strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION));
CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
return;
}
// check app
GetDlgItemTextW(hwndDlg, IDC_ACTION_APP, pNewAct->szApp, _countof(pNewAct->szApp));
StrTrimW(pNewAct->szApp, g_pszSpace);
if (pNewAct->szApp[0] == 0 ||
GetFileAttributesW(pNewAct->szApp) == INVALID_FILE_ATTRIBUTES)
{
// app was empty or invalid
HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_APP);
SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
SetFocus(hwndCtrl);
CStringW strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM));
CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
return;
}
EndDialog(hwndDlg, IDOK);
}
// IDD_ACTION
static INT_PTR CALLBACK
NewActionDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PACTION_DIALOG s_pNewAct = NULL;
switch (uMsg)
{
case WM_INITDIALOG:
s_pNewAct = (PACTION_DIALOG)lParam;
s_pNewAct->bUseDDE = FALSE;
EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_USE_DDE), FALSE);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
NewActionDlg_OnOK(hwndDlg, s_pNewAct);
break;
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDC_ACTION_BROWSE:
ActionDlg_OnBrowse(hwndDlg, s_pNewAct, FALSE);
break;
}
break;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// EditActionDlg
static void
EditActionDlg_OnOK(HWND hwndDlg, PACTION_DIALOG pEditAct)
{
// check action
GetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, pEditAct->szAction, _countof(pEditAct->szAction));
StrTrimW(pEditAct->szAction, g_pszSpace);
if (pEditAct->szAction[0] == 0)
{
// action was empty. show error
HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
SetFocus(hwndCtrl);
CStringW strText(MAKEINTRESOURCEW(IDS_SPECIFY_ACTION));
CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
}
// check app
GetDlgItemTextW(hwndDlg, IDC_ACTION_APP, pEditAct->szApp, _countof(pEditAct->szApp));
StrTrimW(pEditAct->szApp, g_pszSpace);
if (pEditAct->szApp[0] == 0)
{
// app was empty. show error
HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_APP);
SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
SetFocus(hwndCtrl);
CStringW strText(MAKEINTRESOURCEW(IDS_INVALID_PROGRAM));
CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
}
EndDialog(hwndDlg, IDOK);
}
// IDD_ACTION
static INT_PTR CALLBACK
EditActionDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PACTION_DIALOG s_pEditAct = NULL;
switch (uMsg)
{
case WM_INITDIALOG:
s_pEditAct = (PACTION_DIALOG)lParam;
s_pEditAct->bUseDDE = FALSE;
SetDlgItemTextW(hwndDlg, IDC_ACTION_ACTION, s_pEditAct->szAction);
SetDlgItemTextW(hwndDlg, IDC_ACTION_APP, s_pEditAct->szApp);
EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_USE_DDE), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_ACTION_ACTION), FALSE);
{
// set title
CStringW str(MAKEINTRESOURCEW(IDS_EDITING_ACTION));
str += s_pEditAct->ClassName;
SetWindowTextW(hwndDlg, str);
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EditActionDlg_OnOK(hwndDlg, s_pEditAct);
break;
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDC_ACTION_BROWSE:
ActionDlg_OnBrowse(hwndDlg, s_pEditAct, TRUE);
break;
}
break;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// EditTypeDlg
static BOOL
EditTypeDlg_UpdateEntryIcon(HWND hwndDlg, PEDITTYPE_DIALOG pEditType,
LPCWSTR IconPath, INT IconIndex)
{
PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
BOOL bIconSet = FALSE;
if (IconPath && IconPath[0])
{
DestroyIcon(pEntry->hIconLarge);
DestroyIcon(pEntry->hIconSmall);
pEntry->hIconLarge = DoExtractIcon(pEntry, IconPath, IconIndex, FALSE);
pEntry->hIconSmall = DoExtractIcon(pEntry, IconPath, IconIndex, TRUE);
bIconSet = (pEntry->hIconLarge && pEntry->hIconSmall);
}
if (bIconSet)
{
StringCbCopyW(pEntry->IconPath, sizeof(pEntry->IconPath), IconPath);
pEntry->nIconIndex = IconIndex;
}
else
{
SetFileTypeEntryDefaultIcon(pEntry);
}
HWND hListView = pEditType->hwndLV;
HIMAGELIST himlLarge = ListView_GetImageList(hListView, LVSIL_NORMAL);
HIMAGELIST himlSmall = ListView_GetImageList(hListView, LVSIL_SMALL);
INT iLargeImage = ImageList_AddIcon(himlLarge, pEntry->hIconLarge);
INT iSmallImage = ImageList_AddIcon(himlSmall, pEntry->hIconSmall);
ASSERT(iLargeImage == iSmallImage);
DBG_UNREFERENCED_LOCAL_VARIABLE(iLargeImage);
INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
if (iItem != -1)
{
LV_ITEMW Item = { LVIF_IMAGE, iItem };
Item.iImage = iSmallImage;
ListView_SetItem(hListView, &Item);
}
return TRUE;
}
static BOOL
EditTypeDlg_WriteClass(HWND hwndDlg, PEDITTYPE_DIALOG pEditType,
LPCWSTR ClassKey, LPCWSTR ClassName, INT cchName)
{
PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
if (ClassKey[0] == 0)
return FALSE;
// create or open class key
HKEY hClassKey;
if (RegCreateKeyExW(HKEY_CLASSES_ROOT, ClassKey, 0, NULL, 0, KEY_WRITE, NULL,
&hClassKey, NULL) != ERROR_SUCCESS)
{
return FALSE;
}
// create "DefaultIcon" key
if (pEntry->IconPath[0])
{
HKEY hDefaultIconKey;
if (RegCreateKeyExW(hClassKey, L"DefaultIcon", 0, NULL, 0, KEY_WRITE, NULL,
&hDefaultIconKey, NULL) == ERROR_SUCCESS)
{
WCHAR szText[MAX_PATH];
StringCbPrintfW(szText, sizeof(szText), L"%s,%d",
pEntry->IconPath, pEntry->nIconIndex);
// set icon location
DWORD dwSize = (lstrlenW(szText) + 1) * sizeof(WCHAR);
RegSetValueExW(hDefaultIconKey, NULL, 0, REG_EXPAND_SZ, LPBYTE(szText), dwSize);
RegCloseKey(hDefaultIconKey);
}
}
// create "shell" key
HKEY hShellKey;
if (RegCreateKeyExW(hClassKey, L"shell", 0, NULL, 0, KEY_WRITE, NULL,
&hShellKey, NULL) != ERROR_SUCCESS)
{
RegCloseKey(hClassKey);
return FALSE;
}
// delete shell commands
WCHAR szVerbName[64];
DWORD dwIndex = 0;
while (RegEnumKeyW(hShellKey, dwIndex, szVerbName, _countof(szVerbName)) == ERROR_SUCCESS)
{
if (pEditType->CommandLineMap.FindKey(szVerbName) == -1)
{
// doesn't exist in CommandLineMap, then delete it
if (SHDeleteKeyW(hShellKey, szVerbName) == ERROR_SUCCESS)
{
--dwIndex;
}
}
++dwIndex;
}
// set default action
RegSetValueExW(hShellKey, NULL, 0, REG_SZ,
LPBYTE(pEditType->szDefaultVerb), sizeof(pEditType->szDefaultVerb));
// write shell commands
const INT nCount = pEditType->CommandLineMap.GetSize();
for (INT i = 0; i < nCount; ++i)
{
CStringW& key = pEditType->CommandLineMap.GetKeyAt(i);
CStringW& value = pEditType->CommandLineMap.GetValueAt(i);
// create verb key
HKEY hVerbKey;
if (RegCreateKeyExW(hShellKey, key, 0, NULL, 0, KEY_WRITE, NULL,
&hVerbKey, NULL) == ERROR_SUCCESS)
{
// create command key
HKEY hCommandKey;
if (RegCreateKeyExW(hVerbKey, L"command", 0, NULL, 0, KEY_WRITE, NULL,
&hCommandKey, NULL) == ERROR_SUCCESS)
{
// write the default value
DWORD dwSize = (value.GetLength() + 1) * sizeof(WCHAR);
RegSetValueExW(hCommandKey, NULL, 0, REG_EXPAND_SZ, LPBYTE(LPCWSTR(value)), dwSize);
RegCloseKey(hCommandKey);
}
RegCloseKey(hVerbKey);
}
}
// set class name to class key
RegSetValueExW(hClassKey, NULL, 0, REG_SZ, LPBYTE(ClassName), cchName);
RegCloseKey(hShellKey);
RegCloseKey(hClassKey);
return TRUE;
}
static BOOL
EditTypeDlg_ReadClass(HWND hwndDlg, PEDITTYPE_DIALOG pEditType, LPCWSTR ClassKey)
{
// open class key
HKEY hClassKey;
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, ClassKey, 0, KEY_READ, &hClassKey) != ERROR_SUCCESS)
return FALSE;
// open "shell" key
HKEY hShellKey;
if (RegOpenKeyExW(hClassKey, L"shell", 0, KEY_READ, &hShellKey) != ERROR_SUCCESS)
{
RegCloseKey(hClassKey);
return FALSE;
}
WCHAR DefaultVerb[64];
DWORD dwSize = sizeof(DefaultVerb);
if (RegQueryValueExW(hShellKey, NULL, NULL, NULL,
LPBYTE(DefaultVerb), &dwSize) == ERROR_SUCCESS)
{
StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), DefaultVerb);
}
else
{
StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), L"open");
}
// enumerate shell verbs
WCHAR szVerbName[64];
DWORD dwIndex = 0;
while (RegEnumKeyW(hShellKey, dwIndex, szVerbName, _countof(szVerbName)) == ERROR_SUCCESS)
{
// open verb key
HKEY hVerbKey;
LONG nResult = RegOpenKeyExW(hShellKey, szVerbName, 0, KEY_READ, &hVerbKey);
if (nResult == ERROR_SUCCESS)
{
// open command key
HKEY hCommandKey;
nResult = RegOpenKeyExW(hVerbKey, L"command", 0, KEY_READ, &hCommandKey);
if (nResult == ERROR_SUCCESS)
{
// get command line
WCHAR szValue[MAX_PATH + 32];
dwSize = sizeof(szValue);
nResult = RegQueryValueExW(hCommandKey, NULL, NULL, NULL, LPBYTE(szValue), &dwSize);
if (nResult == ERROR_SUCCESS)
{
pEditType->CommandLineMap.SetAt(szVerbName, szValue);
}
RegCloseKey(hCommandKey);
}
RegCloseKey(hVerbKey);
}
SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_ADDSTRING, 0, LPARAM(szVerbName));
++dwIndex;
}
RegCloseKey(hShellKey);
RegCloseKey(hClassKey);
return TRUE;
}
static void
EditTypeDlg_OnOK(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
{
PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
// get class name
GetDlgItemTextW(hwndDlg, IDC_EDITTYPE_TEXT, pEntry->ClassName, _countof(pEntry->ClassName));
StrTrimW(pEntry->ClassName, g_pszSpace);
// update entry icon
EditTypeDlg_UpdateEntryIcon(hwndDlg, pEditType, pEditType->szIconPath, pEditType->nIconIndex);
// write registry
EditTypeDlg_WriteClass(hwndDlg, pEditType, pEntry->ClassKey, pEntry->ClassName,
_countof(pEntry->ClassName));
// update the icon cache
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, NULL, NULL);
EndDialog(hwndDlg, IDOK);
}
static BOOL
EditTypeDlg_OnRemove(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
{
// get current selection
INT iItem = SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETCURSEL, 0, 0);
if (iItem == LB_ERR)
return FALSE;
// ask user for removal
CStringW strText(MAKEINTRESOURCEW(IDS_REMOVE_ACTION));
CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
if (MessageBoxW(hwndDlg, strText, strTitle, MB_ICONINFORMATION | MB_YESNO) == IDNO)
return FALSE;
// get text
WCHAR szText[64];
szText[0] = 0;
SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETTEXT, iItem, (LPARAM)szText);
StrTrimW(szText, g_pszSpace);
// remove it
pEditType->CommandLineMap.Remove(szText);
SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_DELETESTRING, iItem, 0);
return TRUE;
}
static void
EditTypeDlg_OnCommand(HWND hwndDlg, UINT id, UINT code, PEDITTYPE_DIALOG pEditType)
{
INT iItem, iIndex;
ACTION_DIALOG action;
switch (id)
{
case IDOK:
EditTypeDlg_OnOK(hwndDlg, pEditType);
break;
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDC_EDITTYPE_CHANGE_ICON:
EditTypeDlg_OnChangeIcon(hwndDlg, pEditType);
break;
case IDC_EDITTYPE_NEW:
action.bUseDDE = FALSE;
action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
StringCbPrintfW(action.ClassName, sizeof(action.ClassName), pEditType->pEntry->ClassName);
// open 'New Action' dialog
if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ACTION), hwndDlg,
NewActionDlgProc, LPARAM(&action)))
{
if (SendMessageW(action.hwndLB, LB_FINDSTRING, -1, (LPARAM)action.szAction) != LB_ERR)
{
// already exists, error
HWND hwndCtrl = GetDlgItem(hwndDlg, IDC_ACTION_ACTION);
SendMessageW(hwndCtrl, EM_SETSEL, 0, -1);
SetFocus(hwndCtrl);
CStringW strText, strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
strText.Format(IDS_ACTION_EXISTS, action.szAction);
MessageBoxW(hwndDlg, strText, strTitle, MB_ICONERROR);
}
else
{
// add it
CStringW strCommandLine = action.szApp;
strCommandLine += L" \"%1\"";
pEditType->CommandLineMap.SetAt(action.szAction, strCommandLine);
SendMessageW(action.hwndLB, LB_ADDSTRING, 0, LPARAM(action.szAction));
if (SendMessageW(action.hwndLB, LB_GETCOUNT, 0, 0) == 1)
{
// set default
StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), action.szAction);
InvalidateRect(action.hwndLB, NULL, TRUE);
}
}
}
break;
case IDC_EDITTYPE_LISTBOX:
if (code == LBN_SELCHANGE)
{
action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
INT iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
if (lstrcmpiW(action.szAction, pEditType->szDefaultVerb) == 0)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
}
else
{
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), TRUE);
}
break;
}
else if (code != LBN_DBLCLK)
{
break;
}
// FALL THROUGH
case IDC_EDITTYPE_EDIT_BUTTON:
action.bUseDDE = FALSE;
action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
StringCbPrintfW(action.ClassName, sizeof(action.ClassName), pEditType->pEntry->ClassName);
iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
if (iItem == LB_ERR)
break;
// get action
SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
// get app
{
iIndex = pEditType->CommandLineMap.FindKey(action.szAction);
CStringW str = pEditType->CommandLineMap.GetValueAt(iIndex);
StringCbCopyW(action.szApp, sizeof(action.szApp), LPCWSTR(str));
}
// open dialog
if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ACTION), hwndDlg,
EditActionDlgProc, LPARAM(&action)))
{
SendMessageW(action.hwndLB, LB_DELETESTRING, iItem, 0);
SendMessageW(action.hwndLB, LB_INSERTSTRING, iItem, LPARAM(action.szAction));
pEditType->CommandLineMap.SetAt(action.szAction, action.szApp);
}
break;
case IDC_EDITTYPE_REMOVE:
EditTypeDlg_OnRemove(hwndDlg, pEditType);
break;
case IDC_EDITTYPE_SET_DEFAULT:
action.hwndLB = GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX);
iItem = SendMessageW(action.hwndLB, LB_GETCURSEL, 0, 0);
if (iItem == LB_ERR)
break;
SendMessageW(action.hwndLB, LB_GETTEXT, iItem, LPARAM(action.szAction));
// set default
StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), action.szAction);
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
InvalidateRect(action.hwndLB, NULL, TRUE);
break;
}
}
static BOOL
EditTypeDlg_OnInitDialog(HWND hwndDlg, PEDITTYPE_DIALOG pEditType)
{
PFILE_TYPE_ENTRY pEntry = pEditType->pEntry;
StringCbCopyW(pEditType->szIconPath, sizeof(pEditType->szIconPath), pEntry->IconPath);
pEditType->nIconIndex = pEntry->nIconIndex;
StringCbCopyW(pEditType->szDefaultVerb, sizeof(pEditType->szDefaultVerb), L"open");
// set info
SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_ICON, STM_SETICON, (WPARAM)pEntry->hIconLarge, 0);
SetDlgItemTextW(hwndDlg, IDC_EDITTYPE_TEXT, pEntry->ClassName);
EditTypeDlg_ReadClass(hwndDlg, pEditType, pEntry->ClassKey);
InvalidateRect(GetDlgItem(hwndDlg, IDC_EDITTYPE_LISTBOX), NULL, TRUE);
// is listbox empty?
if (SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_GETCOUNT, 0, 0) == 0)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_EDIT_BUTTON), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_REMOVE), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SET_DEFAULT), FALSE);
}
else
{
// select first item
SendDlgItemMessageW(hwndDlg, IDC_EDITTYPE_LISTBOX, LB_SETCURSEL, 0, 0);
}
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTYPE_SAME_WINDOW), FALSE);
return TRUE;
}
// IDD_EDITTYPE
static INT_PTR CALLBACK
EditTypeDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PEDITTYPE_DIALOG s_pEditType = NULL;
LPDRAWITEMSTRUCT pDraw;
LPMEASUREITEMSTRUCT pMeasure;
switch (uMsg)
{
case WM_INITDIALOG:
s_pEditType = (PEDITTYPE_DIALOG)lParam;
return EditTypeDlg_OnInitDialog(hwndDlg, s_pEditType);
case WM_DRAWITEM:
pDraw = LPDRAWITEMSTRUCT(lParam);
return EditTypeDlg_OnDrawItem(hwndDlg, pDraw, s_pEditType);
case WM_MEASUREITEM:
pMeasure = LPMEASUREITEMSTRUCT(lParam);
return EditTypeDlg_OnMeasureItem(hwndDlg, pMeasure, s_pEditType);
case WM_COMMAND:
EditTypeDlg_OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), s_pEditType);
break;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// FileTypesDlg
static INT CALLBACK
FileTypesDlg_CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
PFILE_TYPE_ENTRY Entry1, Entry2;
int x;
Entry1 = (PFILE_TYPE_ENTRY)lParam1;
Entry2 = (PFILE_TYPE_ENTRY)lParam2;
x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension);
if (x != 0)
return x;
return wcsicmp(Entry1->FileDescription, Entry2->FileDescription);
}
static VOID
FileTypesDlg_InitListView(HWND hwndDlg, HWND hListView)
{
RECT clientRect;
LVCOLUMNW col;
WCHAR szName[50];
DWORD dwStyle;
INT columnSize;
if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, _countof(szName)))
{
// default to english
wcscpy(szName, L"Extensions");
}
// make sure its null terminated
szName[_countof(szName) - 1] = 0;
GetClientRect(hListView, &clientRect);
ZeroMemory(&col, sizeof(LV_COLUMN));
columnSize = (clientRect.right - clientRect.left) / 4;
col.iSubItem = 0;
col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
col.fmt = LVCFMT_FIXED_WIDTH;
col.cx = columnSize | LVCFMT_LEFT;
col.cchTextMax = wcslen(szName);
col.pszText = szName;
SendMessageW(hListView, LVM_INSERTCOLUMNW, 0, (LPARAM)&col);
if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, _countof(szName)))
{
// default to english
wcscpy(szName, L"File Types");
ERR("Failed to load localized string!\n");
}
col.iSubItem = 1;
col.cx = clientRect.right - clientRect.left - columnSize - GetSystemMetrics(SM_CYVSCROLL);
col.cchTextMax = wcslen(szName);
col.pszText = szName;
SendMessageW(hListView, LVM_INSERTCOLUMNW, 1, (LPARAM)&col);
// set full select style
dwStyle = (DWORD)SendMessage(hListView, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
SendMessage(hListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
}
static PFILE_TYPE_ENTRY
FileTypesDlg_DoList(HWND hwndDlg)
{
HWND hListView;
DWORD dwIndex = 0;
WCHAR szName[50];
WCHAR szFile[100];
DWORD dwName;
LVITEMW lvItem;
INT iItem = 0;
HIMAGELIST himlLarge, himlSmall;
// create imagelists
himlLarge = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
ILC_COLOR32 | ILC_MASK, 256, 20);
himlSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
ILC_COLOR32 | ILC_MASK, 256, 20);
// set imagelists to listview.
hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
ListView_SetImageList(hListView, himlLarge, LVSIL_NORMAL);
ListView_SetImageList(hListView, himlSmall, LVSIL_SMALL);
FileTypesDlg_InitListView(hwndDlg, hListView);
szFile[0] = 0;
if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile)))
{
// default to english
wcscpy(szFile, L"%s File");
}
szFile[(_countof(szFile)) - 1] = 0;
dwName = _countof(szName);
while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName,
NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
if (FileTypesDlg_InsertToLV(hListView, szName, iItem, szFile))
++iItem;
dwName = _countof(szName);
}
// Leave if the list is empty
if (iItem == 0)
return NULL;
// sort list
ListView_SortItems(hListView, FileTypesDlg_CompareItems, NULL);
// select first item
ZeroMemory(&lvItem, sizeof(LVITEMW));
lvItem.mask = LVIF_STATE;
lvItem.stateMask = (UINT)-1;
lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
lvItem.iItem = 0;
ListView_SetItem(hListView, &lvItem);
lvItem.mask = LVIF_PARAM;
ListView_GetItem(hListView, &lvItem);
return (PFILE_TYPE_ENTRY)lvItem.lParam;
}
static inline PFILE_TYPE_ENTRY
FileTypesDlg_GetEntry(HWND hListView, INT iItem = -1)
{
if (iItem == -1)
{
iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
if (iItem == -1)
return NULL;
}
LV_ITEMW lvItem = { LVIF_PARAM, iItem };
if (ListView_GetItem(hListView, &lvItem))
return (PFILE_TYPE_ENTRY)lvItem.lParam;
return NULL;
}
static void
FileTypesDlg_OnDelete(HWND hwndDlg)
{
CStringW strRemoveExt(MAKEINTRESOURCEW(IDS_REMOVE_EXT));
CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES));
if (MessageBoxW(hwndDlg, strRemoveExt, strTitle, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
FileTypesDlg_RemoveExt(hwndDlg);
// Select first item (Win2k3 does it)
LV_ITEMW item = { LVIF_STATE };
item.stateMask = item.state = LVIS_FOCUSED | LVIS_SELECTED;
item.iItem = 0;
ListView_SetItem(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW), &item);
}
}
static void
FileTypesDlg_OnItemChanging(HWND hwndDlg, PFILE_TYPE_ENTRY pEntry)
{
WCHAR Buffer[255];
static HBITMAP s_hbmProgram = NULL;
// format buffer and set groupbox text
CStringW strFormat(MAKEINTRESOURCEW(IDS_FILE_DETAILS));
StringCbPrintfW(Buffer, sizeof(Buffer), strFormat, &pEntry->FileExtension[1]);
SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DETAILS_GROUPBOX, Buffer);
// format buffer and set description
strFormat.LoadString(IDS_FILE_DETAILSADV);
StringCbPrintfW(Buffer, sizeof(Buffer), strFormat,
&pEntry->FileExtension[1], pEntry->FileDescription,
pEntry->FileDescription);
SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DESCRIPTION, Buffer);
// delete previous program image
if (s_hbmProgram)
{
DeleteObject(s_hbmProgram);
s_hbmProgram = NULL;
}
// set program image
HICON hIconSm = NULL;
ExtractIconExW(pEntry->ProgramPath, 0, NULL, &hIconSm, 1);
s_hbmProgram = BitmapFromIcon(hIconSm, 16, 16);
DestroyIcon(hIconSm);
SendDlgItemMessageW(hwndDlg, IDC_FILETYPES_ICON, STM_SETIMAGE, IMAGE_BITMAP, LPARAM(s_hbmProgram));
// set program name
if (pEntry->AppName[0])
SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, pEntry->AppName);
else
SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, L"ReactOS");
// Enable the Delete button
if (pEntry->EditFlags & 0x00000010) // FTA_NoRemove
EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
else
EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), TRUE);
}
// IDD_FOLDER_OPTIONS_FILETYPES
INT_PTR CALLBACK
FolderOptionsFileTypesDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
LPNMLISTVIEW lppl;
PFILE_TYPE_ENTRY pEntry;
OPENASINFO Info;
NEWEXT_DIALOG newext;
EDITTYPE_DIALOG edittype;
switch (uMsg)
{
case WM_INITDIALOG:
pEntry = FileTypesDlg_DoList(hwndDlg);
// Disable the Delete button if the listview is empty
// the selected item should not be deleted by the user
if (pEntry == NULL || (pEntry->EditFlags & 0x00000010)) // FTA_NoRemove
EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_FILETYPES_NEW:
newext.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_NEWEXTENSION),
hwndDlg, NewExtDlgProc, (LPARAM)&newext))
{
FileTypesDlg_AddExt(hwndDlg, newext.szExt, newext.szFileType);
}
break;
case IDC_FILETYPES_DELETE:
FileTypesDlg_OnDelete(hwndDlg);
break;
case IDC_FILETYPES_CHANGE:
pEntry = FileTypesDlg_GetEntry(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
if (pEntry)
{
ZeroMemory(&Info, sizeof(Info));
Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT;
Info.pcszFile = pEntry->FileExtension;
Info.pcszClass = NULL;
SHOpenWithDialog(hwndDlg, &Info);
}
break;
case IDC_FILETYPES_ADVANCED:
edittype.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
edittype.pEntry = FileTypesDlg_GetEntry(edittype.hwndLV);
if (edittype.pEntry)
{
DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_EDITTYPE),
hwndDlg, EditTypeDlgProc, (LPARAM)&edittype);
}
break;
}
break;
case WM_NOTIFY:
lppl = (LPNMLISTVIEW) lParam;
switch (lppl->hdr.code)
{
case LVN_KEYDOWN:
{
LV_KEYDOWN *pKeyDown = (LV_KEYDOWN *)lParam;
if (pKeyDown->wVKey == VK_DELETE)
{
FileTypesDlg_OnDelete(hwndDlg);
}
break;
}
case NM_DBLCLK:
edittype.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW);
edittype.pEntry = FileTypesDlg_GetEntry(edittype.hwndLV);
if (edittype.pEntry)
{
DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_EDITTYPE),
hwndDlg, EditTypeDlgProc, (LPARAM)&edittype);
}
break;
case LVN_DELETEALLITEMS:
return FALSE; // send LVN_DELETEITEM
case LVN_DELETEITEM:
pEntry = FileTypesDlg_GetEntry(lppl->hdr.hwndFrom, lppl->iItem);
if (pEntry)
{
DestroyIcon(pEntry->hIconLarge);
DestroyIcon(pEntry->hIconSmall);
HeapFree(GetProcessHeap(), 0, pEntry);
}
return FALSE;
case LVN_ITEMCHANGING:
pEntry = FileTypesDlg_GetEntry(lppl->hdr.hwndFrom, lppl->iItem);
if (!pEntry)
{
return TRUE;
}
if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
{
FileTypesDlg_OnItemChanging(hwndDlg, pEntry);
}
break;
case PSN_SETACTIVE:
// On page activation, set the focus to the listview
SetFocus(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW));
break;
}
break;
}
return FALSE;
}