|
|
#include "shellprv.h"
#include "ids.h"
#include "help.h"
#include "ascstr.h"
#include "ftcmmn.h"
#include "ftprop.h"
#include "ftedit.h"
#include "ftadv.h"
#define SUBITEM_EXT 0
#define SUBITEM_PROGIDDESCR 1
#define WM_FINISHFILLLISTVIEW (WM_USER + 1)
static DWORD s_rgdwHelpIDsArray[] = { // Context Help IDs
IDC_NO_HELP_1, NO_HELP, IDC_FT_PROP_LV_FILETYPES, IDH_FCAB_FT_PROP_LV_FILETYPES, IDC_FT_PROP_ANIM, IDH_FCAB_FT_PROP_LV_FILETYPES, IDC_FT_PROP_NEW, IDH_FCAB_FT_PROP_NEW, IDC_FT_PROP_OPENEXE_TXT, IDH_FCAB_FT_PROP_DETAILS, IDC_FT_PROP_OPENICON, IDH_FCAB_FT_PROP_DETAILS, IDC_FT_PROP_OPENEXE, IDH_FCAB_FT_PROP_DETAILS, IDC_FT_PROP_CHANGEOPENSWITH, IDH_FPROP_GEN_CHANGE, IDC_FT_PROP_TYPEOFFILE_TXT, IDH_FCAB_FT_PROP_DETAILS, IDC_FT_PROP_EDITTYPEOFFILE, IDH_FCAB_FT_PROP_EDIT, IDC_FT_PROP_GROUPBOX, IDH_FCAB_FT_PROP_DETAILS, IDC_FT_PROP_REMOVE, IDH_FCAB_FT_PROP_REMOVE, 0, 0 };
CFTPropDlg::CFTPropDlg() : CFTDlg((ULONG_PTR)s_rgdwHelpIDsArray), _iLVSel(-1), _fStopThread(FALSE) {}
LRESULT CFTPropDlg::OnInitDialog(WPARAM wParam, LPARAM lParam) { HRESULT hres = _InitAssocStore();
if (SUCCEEDED(hres)) hres = _InitListView();
if (SUCCEEDED(hres)) _InitPreFillListView(); if (SUCCEEDED(hres)) SHCreateThread(_FillListViewWrapper, (LPVOID)this, 0, _ThreadAddRefCallBack);
return TRUE; }
LRESULT CFTPropDlg::OnFinishInitDialog() { HRESULT hres; _InitPostFillListView(); hres = _SelectListViewItem(0);
if (FAILED(hres)) { if (E_OUTOFMEMORY == hres) { ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_ERROR + ERROR_NOT_ENOUGH_MEMORY), MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP); }
EndDialog(_hwnd, -1); } else SHCreateThread(_UpdateAllListViewItemImagesWrapper, (LPVOID)this, 0, _ThreadAddRefCallBack);
return TRUE; }
LRESULT CFTPropDlg::OnCtlColorStatic(WPARAM wParam, LPARAM lParam) { LRESULT fRet = FALSE; // This is to set the color of the background of the animate control
// see doc on ACS_TRANSPARENT and WM_CTLCOLORSTATIC
if ((HWND)lParam == GetDlgItem(_hwnd, IDC_FT_PROP_ANIM)) { SetBkColor(GET_WM_CTLCOLOR_HDC(wParam, lParam, WM_CTLCOLORSTATIC), GetSysColor(COLOR_WINDOW)); fRet = (LRESULT)GetSysColorBrush(COLOR_WINDOW); }
return fRet; }
//static
DWORD WINAPI CFTPropDlg::_FillListViewWrapper(LPVOID lpParameter) { ((CFTPropDlg*)lpParameter)->_FillListView(); ((CFTPropDlg*)lpParameter)->Release(); return 0; }
//static
DWORD WINAPI CFTPropDlg::_UpdateAllListViewItemImagesWrapper(LPVOID lpParameter) { ((CFTPropDlg*)lpParameter)->_UpdateAllListViewItemImages(); ((CFTPropDlg*)lpParameter)->Release(); return 0; }
//static
DWORD WINAPI CFTPropDlg::_ThreadAddRefCallBack(LPVOID lpParameter) { return ((CFTPropDlg*)lpParameter)->AddRef(); }
LRESULT CFTPropDlg::OnDestroy(WPARAM wParam, LPARAM lParam) { DWORD dwRet = FALSE; int iCount = 0; LVITEM lvItem = {0}; HWND hwndLV = _GetLVHWND();
_fStopThread = TRUE; HICON hIconOld = (HICON)SendDlgItemMessage(_hwnd, IDC_FT_PROP_OPENICON, STM_GETIMAGE, IMAGE_ICON, (LPARAM)0);
if (hIconOld) DeleteObject(hIconOld);
// go through all the items in the listview and delete the strings dynamically
// allocated for progIDs
lvItem.mask = LVIF_PARAM; lvItem.iSubItem = SUBITEM_EXT;
iCount = ListView_GetItemCount(hwndLV);
for (lvItem.iItem = 0; lvItem.iItem < iCount; ++lvItem.iItem) { ListView_GetItem(hwndLV, &lvItem);
if (lvItem.lParam) { LocalFree((HLOCAL)lvItem.lParam); } }
CFTDlg::OnDestroy(wParam, lParam);
return TRUE; }
struct LVCOMPAREINFO { HWND hwndLV; int iCol; };
int CALLBACK AlphaCompareItem(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { struct LVCOMPAREINFO *plvci = (struct LVCOMPAREINFO *)lParamSort; TCHAR sz1[MAX_PATH]; TCHAR sz2[MAX_PATH];
ListView_GetItemText(plvci->hwndLV, lParam1, plvci->iCol, sz1, ARRAYSIZE(sz1)); ListView_GetItemText(plvci->hwndLV, lParam2, plvci->iCol, sz2, ARRAYSIZE(sz2));
return lstrcmpi(sz1, sz2); }
LRESULT CFTPropDlg::OnListViewColumnClick(int iCol) { struct LVCOMPAREINFO lvci; lvci.hwndLV = _GetLVHWND(); lvci.iCol = iCol;
_fUpdateImageAgain = TRUE;
return SendMessage(_GetLVHWND(), LVM_SORTITEMSEX, (WPARAM)&lvci, (LPARAM)AlphaCompareItem); }
LRESULT CFTPropDlg::OnListViewSelItem(int iItem, LPARAM lParam) { //
// Need to update the lower pane of the dialog
//
// Get the extension
TCHAR szExt[MAX_EXT]; TCHAR szProgIDDescr[MAX_PROGIDDESCR]; LVITEM lvItem = {0};
_iLVSel = iItem;
lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.iItem = iItem; lvItem.iSubItem = SUBITEM_EXT; lvItem.pszText = szExt; lvItem.cchTextMax = ARRAYSIZE(szExt);
ListView_GetItem(_GetLVHWND(), &lvItem);
ListView_GetItemText(_GetLVHWND(), iItem, SUBITEM_PROGIDDESCR, szProgIDDescr, ARRAYSIZE(szProgIDDescr));
_EnableLowerPane(TRUE);
if (!lvItem.lParam) { _UpdateGroupBox(szExt, TRUE); } else { _UpdateGroupBox(szProgIDDescr, FALSE); }
_UpdateProgIDButtons(szExt, (LPTSTR)lvItem.lParam);
// We rely on this being after _UpdateProgIDButtons (see _fPerUserAdvButton)
_UpdateDeleteButton(lvItem.lParam ? FALSE : TRUE); _UpdateAdvancedText(szExt, szProgIDDescr, lvItem.lParam ? FALSE : TRUE);
_UpdateOpensWith(szExt, (LPTSTR)lvItem.lParam);
return FALSE; }
HRESULT CFTPropDlg::_UpdateDeleteButton(BOOL fExt) { BOOL fTrue = _ShouldEnableButtons();
EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_REMOVE), (_fPerUserAdvButton || !fExt) ? FALSE : fTrue);
return S_OK; }
HRESULT CFTPropDlg::_UpdateProgIDButtons(LPTSTR pszExt, LPTSTR pszProgID) { HRESULT hres = E_FAIL;
if (pszExt && *pszExt) { TCHAR szButtonText[50]; HWND hwndAdvButton = GetDlgItem(_hwnd, IDC_FT_PROP_EDITTYPEOFFILE);
_SetAdvancedRestoreButtonHelpID(IDH_FCAB_FT_PROP_EDIT);
// Is this a progID only association?
if (!pszProgID) { // No
IAssocInfo* pAI;
hres = _pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { hres = pAI->GetBOOL(AIBOOL_PERUSERINFOAVAILABLE, &_fPerUserAdvButton);
ASSERT(SUCCEEDED(hres) || (FAILED(hres) && (FALSE == _fPerUserAdvButton)));
if (_fPerUserAdvButton) { // Restore mode
LoadString(g_hinst, IDS_FT_PROP_BTN_RESTORE, szButtonText, ARRAYSIZE(szButtonText));
_SetAdvancedRestoreButtonHelpID(IDH_FCAB_FT_PROP_EDIT_RESTORE); } else { TCHAR szProgID[MAX_PROGID]; DWORD cchProgID = ARRAYSIZE(szProgID);
hres = pAI->GetString(AISTR_PROGID, szProgID, &cchProgID);
LoadString(g_hinst, IDS_FT_PROP_BTN_ADVANCED, szButtonText, ARRAYSIZE(szButtonText));
if (SUCCEEDED(hres)) { IAssocInfo * pAIProgID;
hres = _pAssocStore->GetAssocInfo(szProgID, AIINIT_PROGID, &pAIProgID);
if (SUCCEEDED(hres)) { BOOL fEdit = _ShouldEnableButtons();
if (fEdit) { pAIProgID->GetBOOL(AIBOOL_EDIT, &fEdit); }
EnableWindow(hwndAdvButton, fEdit);
pAIProgID->Release(); } } }
pAI->Release(); } } else { // Yes
IAssocInfo* pAIProgID;
LoadString(g_hinst, IDS_FT_PROP_BTN_ADVANCED, szButtonText, ARRAYSIZE(szButtonText));
hres = _pAssocStore->GetAssocInfo(pszProgID, AIINIT_PROGID, &pAIProgID);
if (SUCCEEDED(hres)) { BOOL fEdit = _ShouldEnableButtons();
if (fEdit) { pAIProgID->GetBOOL(AIBOOL_EDIT, &fEdit); }
EnableWindow(hwndAdvButton, fEdit);
pAIProgID->Release(); }
EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_CHANGEOPENSWITH), FALSE); }
SetWindowText(hwndAdvButton, szButtonText); }
return hres; }
LRESULT CFTPropDlg::OnDeleteButton(WORD wNotif) { // Warn user about the evil consequences of his act
if (ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_MB_REMOVETYPE), MAKEINTRESOURCE(IDS_FT), MB_YESNO | MB_ICONQUESTION) == IDYES) { LVITEM lvItem = {0}; TCHAR szExt[MAX_EXT];
// Set stuff
lvItem.iSubItem = SUBITEM_EXT; lvItem.pszText = szExt; lvItem.cchTextMax = ARRAYSIZE(szExt);
if (_GetListViewSelectedItem(LVIF_TEXT | LVIF_IMAGE, 0, &lvItem)) { HRESULT hres; IAssocInfo* pAI;
hres = _pAssocStore->GetAssocInfo(szExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { hres = pAI->Delete(AIALL_NONE);
if (SUCCEEDED(hres)) { _DeleteListViewItem(lvItem.iItem);
PropSheet_CancelToClose(GetParent(_hwnd)); }
pAI->Release(); } } }
return FALSE; }
LRESULT CFTPropDlg::OnNewButton(WORD wNotif) { FTEDITPARAM ftEditParam; CFTEditDlg* pEditDlg = NULL;
// Fill structure
ftEditParam.dwExt = ARRAYSIZE(ftEditParam.szExt); ftEditParam.dwProgIDDescr = ARRAYSIZE(ftEditParam.szProgIDDescr);
// This one should be one way, it will come back with a value
*ftEditParam.szProgID = 0; ftEditParam.dwProgID = ARRAYSIZE(ftEditParam.szProgID);
pEditDlg = new CFTEditDlg(&ftEditParam);
if (pEditDlg) { if (IDOK == pEditDlg->DoModal(g_hinst, MAKEINTRESOURCE(DLG_FILETYPEOPTIONSEDITNEW), _hwnd)) { HWND hwndLV = _GetLVHWND(); LRESULT lRes = 0; int iIndex = -1; HRESULT hres = E_FAIL; IAssocInfo* pAI = NULL; LVFINDINFO lvFindInfo = {0}; LPTSTR pszExtNoDot = NULL; LVITEM lvItem = {0}; TCHAR szExt[MAX_EXT];
lvItem.pszText = szExt; lvItem.cchTextMax = ARRAYSIZE(szExt);
pszExtNoDot = (TEXT('.') != *(ftEditParam.szExt)) ? ftEditParam.szExt : ftEditParam.szExt + 1;
lvFindInfo.flags = LVFI_STRING; lvFindInfo.psz = pszExtNoDot;
iIndex = ListView_FindItem(hwndLV, -1, &lvFindInfo);
// Is this a brand new Ext-ProgID association?
if (-1 == iIndex) { // Yes, Insert a new item
SetWindowRedraw(hwndLV, FALSE); // Add new ext-progID association
hres = _pAssocStore->GetAssocInfo(ftEditParam.szExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
if (FAILED(hres) || !*szProgIDDescr) { MakeDefaultProgIDDescrFromExt(szProgIDDescr, ARRAYSIZE(szProgIDDescr), pszExtNoDot); }
// Add to the listview
iIndex = _InsertListViewItem(0, pszExtNoDot, szProgIDDescr); pAI->Release(); }
// Select newly inserted item
if (-1 != iIndex) { _SelectListViewItem(iIndex); }
// Redraw our list
SetWindowRedraw(hwndLV, TRUE);
_GetListViewSelectedItem(LVIF_PARAM | LVIF_TEXT, 0, &lvItem);
lvItem.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE; } else { // No just update the item
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; lvItem.iItem = iIndex;
ListView_GetItem(hwndLV, &lvItem); }
_UpdateListViewItem(&lvItem);
PropSheet_CancelToClose(GetParent(_hwnd)); }
pEditDlg->Release(); }
return FALSE; }
LRESULT CFTPropDlg::OnAdvancedButton(WORD wNotif) { LVITEM lvItem = {0}; TCHAR szExt[MAX_EXT];
// Set stuff
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; lvItem.iSubItem = SUBITEM_EXT; lvItem.pszText = szExt; lvItem.cchTextMax = ARRAYSIZE(szExt);
if (_GetListViewSelectedItem(LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM, 0, &lvItem)) { HRESULT hres; IAssocInfo* pAI;
if (_fPerUserAdvButton) { // Restore mode
hres = _pAssocStore->GetAssocInfo(szExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { hres = pAI->Delete(AIALL_PERUSER);
_UpdateListViewItem(&lvItem);
OnListViewSelItem(lvItem.iItem, (LPARAM)NULL);
pAI->Release();
PropSheet_CancelToClose(GetParent(_hwnd)); } } else { // we might deal with an ext-progid assoc or only a progID
TCHAR szProgID[MAX_PROGID];
// Is this a progID only?
if (lvItem.lParam) { // Yes
StringCchCopy(szProgID, ARRAYSIZE(szProgID), (LPTSTR)lvItem.lParam);
hres = S_OK; } else { // No
DWORD cchProgID = ARRAYSIZE(szProgID);
hres = _pAssocStore->GetAssocInfo(szExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { hres = THR(pAI->GetString(AISTR_PROGID, szProgID, &cchProgID));
pAI->Release(); } }
if (SUCCEEDED(hres)) { CFTAdvDlg* pAdvDlg = new CFTAdvDlg(szProgID, szExt);
if (pAdvDlg) { if (IDOK == pAdvDlg->DoModal(g_hinst, MAKEINTRESOURCE(DLG_FILETYPEOPTIONSEDIT), _hwnd)) { _UpdateListViewItem(&lvItem);
OnListViewSelItem(lvItem.iItem, (LPARAM)NULL);
PropSheet_CancelToClose(GetParent(_hwnd)); }
pAdvDlg->Release(); } } } }
return FALSE; }
LRESULT CFTPropDlg::OnChangeButton(WORD wNotif) { // Bring up the "Open With" dialog
LVITEM lvItem = {0}; TCHAR szExt[MAX_EXT];
// Set stuff
lvItem.mask = LVIF_TEXT | LVIF_IMAGE; lvItem.iSubItem = SUBITEM_EXT; lvItem.pszText = szExt; lvItem.cchTextMax = ARRAYSIZE(szExt);
if (_GetListViewSelectedItem(LVIF_TEXT, 0, &lvItem)) { TCHAR szDotExt[MAX_EXT]; OPENASINFO oai;
*szDotExt = TEXT('.'); StringCchCopy(szDotExt + 1, ARRAYSIZE(szDotExt) - 1, szExt);
oai.pcszFile = szDotExt; oai.pcszClass = NULL; oai.dwInFlags = (OAIF_REGISTER_EXT | OAIF_FORCE_REGISTRATION); // we want the association to be made
if (SUCCEEDED(OpenAsDialog(GetParent(_hwnd), &oai))) { // we changed the association so update the "Opens with:" text
_UpdateOpensWith(szExt, NULL);
// we don't need LVIF_PARAM since we enable the Change button only for Ext-ProgID asssoc
lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
_UpdateListViewItem(&lvItem);
OnListViewSelItem(lvItem.iItem, (LPARAM)NULL);
PropSheet_CancelToClose(GetParent(_hwnd)); } }
return FALSE; }
HRESULT CFTPropDlg::_UpdateGroupBox(LPTSTR pszText, BOOL fExt) { HRESULT hres = E_OUTOFMEMORY; LPTSTR psz = NULL;
if (fExt) { psz = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_FT_PROP_DETAILSFOR), pszText); } else { psz = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_FT_PROP_DETAILSFORPROGID), pszText); }
if (psz) { SetDlgItemText(_hwnd, IDC_FT_PROP_GROUPBOX, psz); LocalFree(psz); hres = S_OK; }
return hres; }
HRESULT CFTPropDlg::_UpdateOpensWith(LPTSTR pszExt, LPTSTR pszProgID) { HICON hIconOld = NULL;
if (!pszProgID) { IAssocInfo* pAI = NULL;
HRESULT hres = _pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { TCHAR szAppFriendlyName[MAX_APPFRIENDLYNAME]; DWORD dwAppFriendlyName = ARRAYSIZE(szAppFriendlyName);
hres = pAI->GetString(AISTR_APPFRIENDLY, szAppFriendlyName, &dwAppFriendlyName);
if (SUCCEEDED(hres)) { HICON hIcon = NULL; int iIcon; SetDlgItemText(_hwnd, IDC_FT_PROP_OPENEXE, szAppFriendlyName);
hres = pAI->GetDWORD(AIDWORD_APPSMALLICON, (DWORD*)&iIcon);
HIMAGELIST hIL = NULL;
// PERF: Why don't we just use _hImageList? Or ListView_GetImageList()?
Shell_GetImageLists(NULL, &hIL);
if (hIL && SUCCEEDED(hres)) { hIcon = ImageList_ExtractIcon(g_hinst, hIL, iIcon); }
hIconOld = (HICON)SendDlgItemMessage(_hwnd, IDC_FT_PROP_OPENICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
if (hIconOld) DestroyIcon(hIconOld); } else { SetDlgItemText(_hwnd, IDC_FT_PROP_OPENEXE, TEXT(" "));
hIconOld = (HICON)SendDlgItemMessage(_hwnd, IDC_FT_PROP_OPENICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)NULL);
if (hIconOld) DestroyIcon(hIconOld); }
pAI->Release(); } } else { SetDlgItemText(_hwnd, IDC_FT_PROP_OPENEXE, TEXT(" "));
hIconOld = (HICON)SendDlgItemMessage(_hwnd, IDC_FT_PROP_OPENICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)NULL);
if (hIconOld) DestroyIcon(hIconOld); } return S_OK; }
HRESULT CFTPropDlg::_UpdateAdvancedText(LPTSTR pszExt, LPTSTR pszFileType, BOOL fExt) { HRESULT hres = S_OK; LPTSTR psz = NULL;
if (_fPerUserAdvButton) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr); IAssocInfo* pAI = NULL;
// we need to show the previous progIDDescr
hres = _pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
if (SUCCEEDED(hres)) { // Restore mode
psz = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_FT_PROP_RESTORE), pszExt, szProgIDDescr); }
pAI->Release(); } } else { if (fExt) { psz = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_FT_PROP_ADVANCED), pszExt, pszFileType, pszFileType); } else { psz = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_FT_PROP_ADVANCED_PROGID), pszFileType); } }
if (SUCCEEDED(hres)) { if (psz) { SetDlgItemText(_hwnd, IDC_FT_PROP_TYPEOFFILE_TXT, psz); LocalFree(psz); } else hres = E_OUTOFMEMORY; }
return hres; }
HRESULT CFTPropDlg::_EnableLowerPane(BOOL fEnable) { BOOL fTrue = _ShouldEnableButtons();
EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_OPENEXE_TXT), fEnable); EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_OPENEXE), fEnable); EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_TYPEOFFILE_TXT), fEnable); EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_GROUPBOX ), fEnable);
// if user is locked down then we do not enable the buttons
if (!fTrue) fEnable = FALSE;
EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_CHANGEOPENSWITH), fEnable); EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_EDITTYPEOFFILE), fEnable);
return S_OK; }
HRESULT CFTPropDlg::_InitPreFillListView() { // Disable New and Delete
EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_NEW), FALSE); EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_REMOVE), FALSE);
_EnableLowerPane(FALSE); _UpdateGroupBox(TEXT(""), TRUE);
// Hide the advanced text
ShowWindow(GetDlgItem(_hwnd, IDC_FT_PROP_TYPEOFFILE_TXT), SW_HIDE);
return S_OK; }
HRESULT CFTPropDlg::_InitPostFillListView() { BOOL fTrue = _ShouldEnableButtons();
// Enable New and Delete
EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_NEW), fTrue); EnableWindow(GetDlgItem(_hwnd, IDC_FT_PROP_REMOVE), fTrue);
// Show the advanced text
ShowWindow(GetDlgItem(_hwnd, IDC_FT_PROP_TYPEOFFILE_TXT), SW_SHOW);
Animate_Stop(GetDlgItem(_hwnd, IDC_FT_PROP_ANIM)); ShowWindow(GetDlgItem(_hwnd, IDC_FT_PROP_ANIM), SW_HIDE); ShowWindow(_GetLVHWND(), SW_SHOW);
SetFocus(_GetLVHWND());
return S_OK; }
HRESULT CFTPropDlg::_InitListView() { HRESULT hres = S_OK; LVCOLUMN lvColumn = {0}; HWND hwndLV = _GetLVHWND(); TCHAR szColumnTitle[40]; RECT rc = {0}; int iWidth = 80; HWND hwndAni;
//
// Styles
//
ListView_SetExtendedListViewStyleEx(hwndLV, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
//
// Set the columns
//
lvColumn.mask = LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH;
// Extensions column
LoadString(g_hinst, IDS_FT_PROP_EXTENSIONS, szColumnTitle, ARRAYSIZE(szColumnTitle));
lvColumn.cx = 60; lvColumn.pszText = szColumnTitle; lvColumn.cchTextMax = lstrlen(szColumnTitle); lvColumn.iSubItem = SUBITEM_EXT;
ListView_InsertColumn(hwndLV, SUBITEM_EXT, &lvColumn);
// ProgIDs column
LoadString(g_hinst, IDS_FT, szColumnTitle, ARRAYSIZE(szColumnTitle));
lvColumn.cchTextMax = lstrlen(szColumnTitle); lvColumn.iSubItem = SUBITEM_PROGIDDESCR; ListView_InsertColumn(hwndLV, SUBITEM_PROGIDDESCR, &lvColumn);
// Adjust columns width
// we need to do it after inserting both col, cause the last column resizing
// is special cased in list view code.
// Ext column
ListView_SetColumnWidth(hwndLV, SUBITEM_EXT, LVSCW_AUTOSIZE_USEHEADER); iWidth = ListView_GetColumnWidth(hwndLV, SUBITEM_EXT);
// File type column
GetClientRect(hwndLV, &rc); ListView_SetColumnWidth(hwndLV, SUBITEM_PROGIDDESCR, rc.right - iWidth - GetSystemMetrics(SM_CXBORDER) - GetSystemMetrics(SM_CXVSCROLL));
//
// ImageList
//
Shell_GetImageLists(NULL, &_hImageList);
if (_hImageList) ListView_SetImageList(hwndLV, _hImageList, LVSIL_SMALL);
GetWindowRect(hwndLV, &rc); MapWindowPoints(NULL, _hwnd, (POINT*)&rc, 2);
hwndAni = GetDlgItem(_hwnd, IDC_FT_PROP_ANIM);
Animate_Open(hwndAni, MAKEINTRESOURCE(IDA_SEARCH)); // open the resource
Animate_Play(hwndAni, 0, -1, -1); // play from start to finish and repeat
MoveWindow(hwndAni, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
ShowWindow(hwndLV, SW_HIDE);
ShowWindow(hwndAni, SW_SHOW);
return hres; }
HRESULT CFTPropDlg::_FillListView() { // Data stuff
IEnumAssocInfo* pEnum = NULL; HRESULT hres = E_FAIL; int iFirstNAItem = -1; HWND hwndLV = NULL; int iItem = 0; TCHAR szNA[50];
ASSERT(_pAssocStore);
// Do the extension first
if (!_fStopThread) { hwndLV = _GetLVHWND(); SetWindowRedraw(hwndLV, FALSE); }
if (!_fStopThread) { LoadString(g_hinst, IDS_FT_NA, szNA, ARRAYSIZE(szNA)); hres = _pAssocStore->EnumAssocInfo(ASENUM_EXT | ASENUM_ASSOC_YES | ASENUM_NOEXCLUDED | ASENUM_NOEXPLORERSHELLACTION | ASENUM_NOEXE, NULL, AIINIT_NONE, &pEnum); } else hres = E_FAIL;
if (SUCCEEDED(hres)) { IAssocInfo* pAI = NULL; while (!_fStopThread && (S_OK == pEnum->Next(&pAI))) { TCHAR szExt[MAX_EXT]; DWORD cchExt = ARRAYSIZE(szExt);
hres = pAI->GetString(AISTR_EXT, szExt, &cchExt);
if (SUCCEEDED(hres)) { BOOL fPerUser = FALSE; TCHAR szProgIDDescr[MAX_PROGIDDESCR]; DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr); HRESULT hresTmp = E_FAIL;
hresTmp = pAI->GetBOOL(AIBOOL_PERUSERINFOAVAILABLE, &fPerUser);
ASSERT(SUCCEEDED(hresTmp) || (FAILED(hresTmp) && (FALSE == fPerUser)));
if (!fPerUser) { hresTmp = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr); } if (fPerUser || FAILED(hresTmp) || !*szProgIDDescr) MakeDefaultProgIDDescrFromExt(szProgIDDescr, ARRAYSIZE(szProgIDDescr), szExt); if (!_fStopThread) _InsertListViewItem(iItem, szExt, szProgIDDescr);
// See comment in ftenum.cpp, CFTEnumAssocInfo::_EnumKCRStop about sorting
// Check if this is where we need to insert the N/A item later
if ((-1 == iFirstNAItem) && (lstrcmpi(szExt, szNA) > 0)) { iFirstNAItem = iItem; } ++iItem; }
pAI->Release();
hres = S_OK; }
pEnum->Release(); pEnum = NULL; }
// Then do the ProgIDs
if (!_fStopThread) hres = _pAssocStore->EnumAssocInfo(ASENUM_PROGID | ASENUM_SHOWONLY, NULL, AIINIT_NONE, &pEnum); else hres = E_FAIL; if (SUCCEEDED(hres)) { IAssocInfo* pAI = NULL; int cNAItem = 0;
while (!_fStopThread && (S_OK == pEnum->Next(&pAI))) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
if (SUCCEEDED(hres)) { TCHAR szProgID[MAX_PROGID]; DWORD cchProgID = ARRAYSIZE(szProgID);
hres = pAI->GetString(AISTR_PROGID, szProgID, &cchProgID);
if (SUCCEEDED(hres)) { // we need to sort the N/A items by the description since they all begin with "N/A"
int iNAItem;
if (!cNAItem) { iNAItem = iFirstNAItem; } else { if (!_fStopThread) iNAItem = _GetNextNAItemPos(iFirstNAItem, cNAItem, szProgIDDescr); }
if (!_fStopThread) { _InsertListViewItem(iNAItem, szNA, szProgIDDescr, szProgID); ++cNAItem; } } }
pAI->Release();
hres = S_OK; }
pEnum->Release(); }
if (!_fStopThread) { SetWindowRedraw(hwndLV, TRUE); PostMessage(_hwnd, WM_FINISHFILLLISTVIEW, 0, 0); } return hres; }
int CFTPropDlg::_GetNextNAItemPos(int iFirstNAItem, int cNAItem, LPTSTR pszProgIDDescr) { LVITEM lvItem = {0}; TCHAR szProgIDDescr[MAX_PROGIDDESCR]; int iItem = iFirstNAItem; HWND hwndLV = _GetLVHWND();
lvItem.mask = LVIF_TEXT; lvItem.iItem = iItem; lvItem.iSubItem = SUBITEM_PROGIDDESCR; lvItem.pszText = szProgIDDescr; lvItem.cchTextMax = ARRAYSIZE(szProgIDDescr);
while (iItem < (iFirstNAItem + cNAItem)) { if (ListView_GetItem(hwndLV, &lvItem)) { if (lstrcmpi(pszProgIDDescr, lvItem.pszText) >= 0) { ++iItem; lvItem.iItem = iItem; } else { break; } } else { // This happens when the listview is destroyed (on another thread),
// but this thread is still doing some work. The call above fails,
// we break here or else we'll never go out of the loop.
break; } }
return iItem; }
DWORD CFTPropDlg::_UpdateAllListViewItemImages() { HWND hwndLV = NULL; int iCount = 0; LVITEM lvItem = {0}; TCHAR szExt[MAX_EXT]; HRESULT hres = E_FAIL;
HRESULT hrInit = SHCoInitialize(); lvItem.iSubItem = SUBITEM_EXT; lvItem.pszText = szExt; lvItem.cchTextMax = ARRAYSIZE(szExt);
if (!_fStopThread) hwndLV = _GetLVHWND();
do { _fUpdateImageAgain = FALSE; if (!_fStopThread) iCount = ListView_GetItemCount(hwndLV); for (lvItem.iItem = 0; !_fStopThread && (lvItem.iItem < iCount); ++lvItem.iItem) { IAssocInfo* pAI = NULL;
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; if (!_fStopThread) ListView_GetItem(hwndLV, &lvItem); if (!_fStopThread && !lvItem.lParam) { hres = _pAssocStore->GetAssocInfo(szExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { BOOL fPerUser = FALSE;
hres = pAI->GetBOOL(AIBOOL_PERUSERINFOAVAILABLE, &fPerUser);
ASSERT(SUCCEEDED(hres) || (FAILED(hres) && (FALSE == fPerUser)));
if (fPerUser) hres = pAI->GetDWORD(AIDWORD_DOCSMALLICON | AIALL_PERUSER, (DWORD*)&lvItem.iImage); else hres = pAI->GetDWORD(AIDWORD_DOCSMALLICON, (DWORD*)&lvItem.iImage); } } else { hres = _pAssocStore->GetAssocInfo((LPTSTR)lvItem.lParam, AIINIT_PROGID, &pAI);
if (SUCCEEDED(hres)) { hres = pAI->GetDWORD(AIDWORD_DOCSMALLICON, (DWORD*)&lvItem.iImage); } }
if (SUCCEEDED(hres)) { lvItem.mask = LVIF_IMAGE; if (!_fStopThread) ListView_SetItem(hwndLV, &lvItem); }
if (pAI) pAI->Release(); } } while (_fUpdateImageAgain && !_fStopThread);
SHCoUninitialize(hrInit);
return (DWORD)_fStopThread; }
void CFTPropDlg::_UpdateListViewItem(LVITEM* plvItem) { HWND hwndLV = _GetLVHWND(); LVITEM lvItem = *plvItem;
// Need to:
// - update image
// - update progIDDescr
if (!lvItem.lParam) { IAssocInfo* pAI = NULL;
HRESULT hres = _pAssocStore->GetAssocInfo(lvItem.pszText, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres)) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr); HRESULT hresTmp = E_FAIL;
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); // Icon
BOOL fPerUser = FALSE;
hres = pAI->GetBOOL(AIBOOL_PERUSERINFOAVAILABLE, &fPerUser);
ASSERT(SUCCEEDED(hres) || (FAILED(hres) && (FALSE == fPerUser)));
if (fPerUser) hres = pAI->GetDWORD(AIDWORD_DOCSMALLICON | AIALL_PERUSER, (DWORD*)&lvItem.iImage); else hres = pAI->GetDWORD(AIDWORD_DOCSMALLICON, (DWORD*)&lvItem.iImage);
if (SUCCEEDED(hres)) { lvItem.mask = LVIF_IMAGE; ListView_SetItem(hwndLV, &lvItem); }
// ProgID Description
if (!fPerUser) { hresTmp = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr); } if (fPerUser || FAILED(hresTmp) || !*szProgIDDescr) MakeDefaultProgIDDescrFromExt(szProgIDDescr, ARRAYSIZE(szProgIDDescr), lvItem.pszText);
if (SUCCEEDED(hres)) { lvItem.mask = LVIF_TEXT; lvItem.iSubItem = SUBITEM_PROGIDDESCR; lvItem.pszText = szProgIDDescr; lvItem.cchTextMax = lstrlen(szProgIDDescr);
ListView_SetItem(hwndLV, &lvItem); }
ListView_RedrawItems(hwndLV, lvItem.iItem, lvItem.iItem);
pAI->Release(); } } else { IAssocInfo* pAI = NULL;
HRESULT hres = _pAssocStore->GetAssocInfo((LPTSTR)lvItem.lParam, AIINIT_PROGID, &pAI);
if (SUCCEEDED(hres)) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr); HRESULT hresTmp = E_FAIL;
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); // Icon
hres = pAI->GetDWORD(AIDWORD_DOCSMALLICON, (DWORD*)&lvItem.iImage);
if (SUCCEEDED(hres)) { lvItem.mask = LVIF_IMAGE; ListView_SetItem(hwndLV, &lvItem); }
// ProgID Description
pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
if (SUCCEEDED(hres)) { lvItem.mask = LVIF_TEXT; lvItem.iSubItem = SUBITEM_PROGIDDESCR; lvItem.pszText = szProgIDDescr; lvItem.cchTextMax = lstrlen(szProgIDDescr);
ListView_SetItem(hwndLV, &lvItem); } ListView_RedrawItems(hwndLV, lvItem.iItem, lvItem.iItem);
pAI->Release(); } } }
int CFTPropDlg::_InsertListViewItem(int iItem, LPTSTR pszExt, LPTSTR pszProgIDDescr, LPTSTR pszProgID) { HWND hwndLV = _GetLVHWND(); LVITEM lvItem = {0}; lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
// Put generic icon
lvItem.iImage = Shell_GetCachedImageIndex(TEXT("shell32.dll"), II_DOCNOASSOC, 0);
CharUpper(pszExt);
// Extension
if (pszProgID) { DWORD cch = lstrlen(pszProgID) + 1; lvItem.lParam = (LPARAM)LocalAlloc(LPTR, cch * sizeof(TCHAR));
if (lvItem.lParam) { StringCchCopy((LPTSTR)lvItem.lParam, cch, pszProgID); } } else { lvItem.lParam = NULL; }
lvItem.iItem = iItem; lvItem.iSubItem = SUBITEM_EXT; lvItem.pszText = pszExt; lvItem.cchTextMax = lstrlen(pszExt);
lvItem.iItem = ListView_InsertItem(hwndLV, &lvItem);
if (-1 != lvItem.iItem) { // ProgID Description
lvItem.mask = LVIF_TEXT; lvItem.iSubItem = SUBITEM_PROGIDDESCR; lvItem.pszText = pszProgIDDescr; lvItem.cchTextMax = lstrlen(pszProgIDDescr);
ListView_SetItem(hwndLV, &lvItem); } else { // LocalFree checks for NULL
LocalFree((HLOCAL)lvItem.lParam); }
return lvItem.iItem; }
HRESULT CFTPropDlg::_SelectListViewItem(int i) { LVITEM lvItem = {0};
lvItem.iItem = i; lvItem.mask = LVIF_STATE; lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
ListView_SetItem(_GetLVHWND(), &lvItem); ListView_EnsureVisible(_GetLVHWND(), i, FALSE);
return S_OK; }
HRESULT CFTPropDlg::_DeleteListViewItem(int i) { HWND hwndLV = _GetLVHWND(); int iCount = ListView_GetItemCount(hwndLV); int iNextSel = -1; LVITEM lvItem = {0};
lvItem.mask = LVIF_PARAM; lvItem.iItem = i; lvItem.iSubItem = SUBITEM_EXT;
ListView_GetItem(hwndLV, &lvItem);
if (lvItem.lParam) { LocalFree((HLOCAL)lvItem.lParam); }
ListView_DeleteItem(hwndLV, i);
if (iCount > i) iNextSel = i; else if (i > 0) iNextSel = i - 1;
if (-1 != iNextSel) _SelectListViewItem(iNextSel);
return S_OK; }
BOOL CFTPropDlg::_ShouldEnableButtons() { // if we have a locked down user, then we never enable the buttons
BOOL fRet = TRUE;
if (S_FALSE == _pAssocStore->CheckAccess()) { fRet = FALSE; }
// If the REST_NOFILEASSOCIATE is set (TRUE),
// then we want to NOT enable buttons.
fRet &= !SHRestricted(REST_NOFILEASSOCIATE);
return fRet; }
///////////////////////////////////////////////////////////////////////////////
// Misc
BOOL CFTPropDlg::_GetListViewSelectedItem(UINT uMask, UINT uStateMask, LVITEM* plvItem) { BOOL fSel = FALSE; HWND hwndLV = _GetLVHWND();
plvItem->mask = uMask | LVIF_STATE; plvItem->stateMask = uStateMask | LVIS_SELECTED;
// Do we have the selection cached?
if (-1 != _iLVSel) { // Yes, make sure it's valid
plvItem->iItem = _iLVSel;
ListView_GetItem(hwndLV, plvItem);
if (plvItem->state & LVIS_SELECTED) fSel = TRUE; } // Cache was wrong
if (!fSel) { int iCount = ListView_GetItemCount(hwndLV);
for (int i=0; (i < iCount) && !fSel; ++i) { plvItem->iItem = i; ListView_GetItem(hwndLV, plvItem);
if (plvItem->state & LVIS_SELECTED) fSel = TRUE; }
if (fSel) _iLVSel = i; }
return fSel; }
HWND CFTPropDlg::_GetLVHWND() { return GetDlgItem(_hwnd, IDC_FT_PROP_LV_FILETYPES); }
void CFTPropDlg::_SetAdvancedRestoreButtonHelpID(DWORD dwID) { for (int i = 0; i < ARRAYSIZE(s_rgdwHelpIDsArray); i += 2) { if (IDC_FT_PROP_EDITTYPEOFFILE == s_rgdwHelpIDsArray[i]) { if (i + 1 < ARRAYSIZE(s_rgdwHelpIDsArray)) s_rgdwHelpIDsArray[i + 1] = dwID;
break; } } }
///////////////////////////////////////////////////////////////////////////////
// Windows boiler plate code
LRESULT CFTPropDlg::OnNotifyListView(UINT uCode, LPNMHDR pNMHDR) { LRESULT lRes = FALSE;
switch(uCode) { case LVN_GETINFOTIP: { NMLVGETINFOTIP* plvn = (NMLVGETINFOTIP*)pNMHDR;
break; } case LVN_ITEMCHANGED: { NMLISTVIEW* pNMLV = (NMLISTVIEW*)pNMHDR;
// Is a new item being selected?
if ((pNMLV->uChanged & LVIF_STATE) && (pNMLV->uNewState & (LVIS_SELECTED | LVIS_FOCUSED))) { // Yes
OnListViewSelItem(pNMLV->iItem, pNMLV->lParam); } break; }
case LVN_COLUMNCLICK: { NMLISTVIEW* pNMLV = (NMLISTVIEW*)pNMHDR;
OnListViewColumnClick(pNMLV->iSubItem); break; }
case NM_DBLCLK: if (IsWindowEnabled(GetDlgItem(_hwnd, IDC_FT_PROP_EDIT))) PostMessage(_hwnd, WM_COMMAND, (WPARAM)IDC_FT_PROP_EDIT, 0); break; }
return lRes; }
LRESULT CFTPropDlg::OnCommand(WPARAM wParam, LPARAM lParam) { LRESULT lRes = FALSE;
switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_FT_PROP_NEW: lRes = OnNewButton(GET_WM_COMMAND_CMD(wParam, lParam)); break;
case IDC_FT_PROP_REMOVE: lRes = OnDeleteButton(GET_WM_COMMAND_CMD(wParam, lParam)); break;
case IDC_FT_PROP_EDITTYPEOFFILE: lRes = OnAdvancedButton(GET_WM_COMMAND_CMD(wParam, lParam)); break;
case IDC_FT_PROP_CHANGEOPENSWITH: lRes = OnChangeButton(GET_WM_COMMAND_CMD(wParam, lParam)); break;
default: lRes = CFTDlg::OnCommand(wParam, lParam); break; }
return lRes; }
LRESULT CFTPropDlg::OnNotify(WPARAM wParam, LPARAM lParam) { LRESULT lRes = FALSE;
LPNMHDR pNMHDR = (LPNMHDR)lParam; UINT_PTR idFrom = pNMHDR->idFrom; UINT uCode = pNMHDR->code;
//GET_WM_COMMAND_CMD
switch(idFrom) { case IDC_FT_PROP_LV_FILETYPES: lRes = OnNotifyListView(uCode, pNMHDR); break; default: lRes = CFTDlg::OnNotify(wParam, lParam); break; }
return lRes; }
LRESULT CFTPropDlg::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRes = FALSE;
switch(uMsg) { case WM_CTLCOLORSTATIC: lRes = OnCtlColorStatic(wParam, lParam); break;
case WM_FINISHFILLLISTVIEW: lRes = OnFinishInitDialog(); break;
default: lRes = CFTDlg::WndProc(uMsg, wParam, lParam); break; }
return lRes; }
|