#include "shellprv.h" #include "ids.h" #include "help.h" #include "apithk.h" #include "ascstr.h" #include "filetype.h" #include "ftdlg.h" #include "ftadv.h" #include "ftaction.h" const static DWORD cs_rgdwHelpIDsArray[] = { // Context Help IDs IDC_NO_HELP_1, NO_HELP, IDC_FT_EDIT_DOCICON, IDH_FCAB_FT_EDIT_DOCICON, IDC_FT_EDIT_DESC, IDH_FCAB_FT_EDIT_DESC, IDC_FT_EDIT_CHANGEICON, IDH_FCAB_FT_EDIT_CHANGEICON, IDC_FT_EDIT_LV_CMDSTEXT, IDH_FCAB_FT_EDIT_LV_CMDS, IDC_FT_EDIT_LV_CMDS, IDH_FCAB_FT_EDIT_LV_CMDS, IDC_FT_EDIT_NEW, IDH_FCAB_FT_EDIT_NEW, IDC_FT_EDIT_EDIT, IDH_FCAB_FT_EDIT_EDIT, IDC_FT_EDIT_REMOVE, IDH_FCAB_FT_EDIT_REMOVE, IDC_FT_EDIT_DEFAULT, IDH_FCAB_FT_EDIT_DEFAULT, IDC_FT_EDIT_CONFIRM_OPEN, IDH_CONFIRM_OPEN, IDC_FT_EDIT_SHOWEXT, IDH_FCAB_FT_EDIT_SHOWEXT, IDC_FT_EDIT_BROWSEINPLACE, IDH_SAME_WINDOW, 0, 0 }; struct LV_ADDDATA { BOOL fDefaultAction; TCHAR szActionReg[MAX_ACTION]; }; #define ADDDATA_ACTIONREG(plvItem) (((LV_ADDDATA*)((plvItem)->lParam))->szActionReg) #define ADDDATA_DEFAULTACTION(plvItem) (((LV_ADDDATA*)((plvItem)->lParam))->fDefaultAction) /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// CFTAdvDlg::CFTAdvDlg(LPTSTR pszProgID, LPTSTR pszExt) : CFTDlg((ULONG_PTR)cs_rgdwHelpIDsArray), _iDefaultAction(-1), _iLVSel(-1) { _szProgID[0] = NULL; if (pszProgID) StringCchCopy(_szProgID, ARRAYSIZE(_szProgID), pszProgID); _szExt[0] = NULL; if (pszExt && (*pszExt != NULL)) { StringCchPrintf(_szExt, ARRAYSIZE(_szExt), TEXT(".%s"), pszExt); } _hdpaActions = DPA_Create(4); _hdpaRemovedActions = DPA_Create(1); } static int _DeleteLocalAllocCB(void *pItem, void *pData) { LocalFree((HLOCAL)pItem); return 1; } CFTAdvDlg::~CFTAdvDlg() { if (_hIcon) DeleteObject(_hIcon); if (_hfontReg) DeleteObject(_hfontReg); if (_hfontBold) DeleteObject(_hfontBold); if (_hdpaActions) DPA_DestroyCallback(_hdpaActions, _DeleteLocalAllocCB, NULL); if (_hdpaRemovedActions) DPA_DestroyCallback(_hdpaRemovedActions, _DeleteLocalAllocCB, NULL); } /////////////////////////////////////////////////////////////////////////////// // Logic specific to our problem LRESULT CFTAdvDlg::OnInitDialog(WPARAM wParam, LPARAM lParam) { HRESULT hres = _InitAssocStore(); DECLAREWAITCURSOR; SetWaitCursor(); if (SUCCEEDED(hres)) { _InitListView(); _InitDefaultActionFont(); // FTEdit_AreDefaultViewersInstalled ???? if (*_szProgID) { _SetDocIcon(); _InitDescription(); _FillListView(); _InitDefaultAction(); _SelectListViewItem(0); _InitChangeIconButton(); _UpdateCheckBoxes(); } } else EndDialog(_hwnd, -1); ResetWaitCursor(); // Return TRUE so that system set focus return TRUE; } int CFTAdvDlg::_GetIconIndex() { // check under the file progid int iImageIndex = -1; IAssocInfo* pAI = NULL; HRESULT hr = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hr)) { hr = pAI->GetDWORD(AIDWORD_DOCLARGEICON, (DWORD*)&iImageIndex); pAI->Release(); } return iImageIndex; } HRESULT CFTAdvDlg::_SetDocIcon(int iIndex) { HRESULT hres = E_FAIL; if (-1 == iIndex) { iIndex = _GetIconIndex(); } if (-1 != iIndex) { HIMAGELIST hIL = NULL; Shell_GetImageLists(&hIL, NULL); if (_hIcon) { DeleteObject(_hIcon); _hIcon = NULL; } if (hIL) { _hIcon = ImageList_ExtractIcon(g_hinst, hIL, iIndex); _hIcon = (HICON)CopyImage(_hIcon, IMAGE_ICON, 32, 32, LR_COPYDELETEORG); HICON hiOld = (HICON)SendDlgItemMessage(_hwnd, IDC_FT_EDIT_DOCICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)_hIcon); if (hiOld) DestroyIcon(hiOld); } } return hres; } LRESULT CFTAdvDlg::OnListViewSelItem(int iItem, LPARAM lParam) { _UpdateActionButtons(); return TRUE; } LRESULT CFTAdvDlg::OnMeasureItem(WPARAM wParam, LPARAM lParam) { TEXTMETRIC tm = {0}; RECT rect; LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; HDC hdc = GetDC(NULL); HFONT hfontOld = (HFONT)SelectObject(hdc, _hfontBold); GetTextMetrics(hdc, &tm); GetClientRect(_GetLVHWND(), &rect); lpmis->itemWidth = rect.right; lpmis->itemHeight = tm.tmHeight; SelectObject(hdc, hfontOld); ReleaseDC(NULL, hdc); return TRUE; } LRESULT CFTAdvDlg::OnDrawItem(WPARAM wParam, LPARAM lParam) { LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam; LRESULT lRet = FALSE; if (ODT_LISTVIEW == lpDIS->CtlType) { HWND hwndLV = _GetLVHWND(); LVITEM lvItem = {0}; HFONT hfontOld = NULL; BOOL fSel = FALSE; BOOL fListFocus = FALSE; TCHAR szAction[MAX_ACTION]; COLORREF crBkgd = 0; COLORREF crOldText = 0; lvItem.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; lvItem.iItem = lpDIS->itemID; lvItem.stateMask = LVIS_SELECTED|LVIS_FOCUSED; lvItem.pszText = szAction; lvItem.cchTextMax = ARRAYSIZE(szAction); ListView_GetItem(hwndLV, &lvItem); fSel = (lvItem.state & LVIS_SELECTED); fListFocus = (GetFocus() == hwndLV); crBkgd = (fSel ? (fListFocus ? COLOR_HIGHLIGHT : COLOR_3DFACE) : COLOR_WINDOW); SetBkColor(lpDIS->hDC, GetSysColor(crBkgd)); FillRect(lpDIS->hDC, &lpDIS->rcItem, (HBRUSH)IntToPtr(crBkgd + 1)); crOldText = SetTextColor(lpDIS->hDC, GetSysColor(fSel ? (fListFocus ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT) : COLOR_WINDOWTEXT)); // Use Bold font for default action hfontOld = (HFONT)SelectObject(lpDIS->hDC, _IsDefaultAction(ADDDATA_ACTIONREG(&lvItem)) ? _hfontBold : _hfontReg); int iOldBkMode = SetBkMode(lpDIS->hDC, OPAQUE); DrawText(lpDIS->hDC, szAction, lstrlen(szAction), &lpDIS->rcItem, 0); SetBkMode(lpDIS->hDC, iOldBkMode); SetTextColor(lpDIS->hDC, crOldText); SelectObject(lpDIS->hDC, hfontOld); if(fListFocus && (lvItem.state & LVIS_FOCUSED)) DrawFocusRect(lpDIS->hDC, &lpDIS->rcItem); lRet = TRUE; } return lRet; } HRESULT CFTAdvDlg::_InitDefaultActionFont() { HFONT hfontDlg = GetWindowFont(_hwnd); LOGFONT lf = {0}; LOGFONT lfDlg = {0}; GetObject(hfontDlg, sizeof(LOGFONT), &lfDlg); SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE); // Normal font lf.lfWeight = FW_NORMAL; lf.lfHeight = lfDlg.lfHeight; _hfontReg = CreateFontIndirect(&lf); // Bold font lf.lfWeight = FW_BOLD; _hfontBold = CreateFontIndirect(&lf); return (_hfontReg && _hfontBold) ? S_OK : E_FAIL; } HRESULT CFTAdvDlg::_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); return S_OK; } // pszText and cchTextMax needs to be set BOOL CFTAdvDlg::_FindActionLVITEM(LPTSTR pszActionReg, LVITEM* plvItem) { HWND hwndLV = _GetLVHWND(); int iCount = ListView_GetItemCount(hwndLV); BOOL fRet = FALSE; plvItem->mask = LVIF_TEXT | LVIF_PARAM; for (int i = 0; i < iCount; ++i) { plvItem->iItem = i; if (ListView_GetItem(hwndLV, plvItem)) { if (!lstrcmpi(pszActionReg, ADDDATA_ACTIONREG(plvItem))) { fRet = TRUE; break; } } } return fRet; } HRESULT CFTAdvDlg::_InitDefaultAction() { // Get it from the classstore IAssocInfo* pAI = NULL; HRESULT hres = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hres)) { TCHAR szActionReg[MAX_ACTION]; DWORD cchActionReg = ARRAYSIZE(szActionReg); HWND hwndLV = _GetLVHWND(); int iIndex = -1; hres = pAI->GetString(AISTR_PROGIDDEFAULTACTION, szActionReg, &cchActionReg); if (SUCCEEDED(hres)) { TCHAR szActionLVI[MAX_ACTION]; LVITEM lvItem = {0}; lvItem.pszText = szActionLVI; lvItem.cchTextMax = ARRAYSIZE(szActionLVI); if (_FindActionLVITEM(szActionReg, &lvItem)) hres = _SetDefaultAction(lvItem.iItem); else hres = S_OK; } pAI->Release(); } return hres; } BOOL CFTAdvDlg::_GetDefaultAction(LPTSTR pszActionReg, DWORD cchActionReg) { BOOL fRet = FALSE; HWND hwndLV = _GetLVHWND(); LVITEM lvItem = {0}; int iCount = ListView_GetItemCount(hwndLV); TCHAR szActionRegLocal[MAX_ACTION]; lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.pszText = szActionRegLocal; lvItem.cchTextMax = ARRAYSIZE(szActionRegLocal); for (int i = 0; i < iCount; ++i) { lvItem.iItem = i; if (ListView_GetItem(hwndLV, &lvItem)) { if (ADDDATA_DEFAULTACTION(&lvItem)) { if(SUCCEEDED(StringCchCopy(pszActionReg, cchActionReg, ADDDATA_ACTIONREG(&lvItem)))) fRet = TRUE; else fRet = FALSE; break; } } } return fRet; } BOOL CFTAdvDlg::_IsDefaultAction(LPTSTR pszActionReg) { BOOL fRet = FALSE; TCHAR szActionReg[MAX_ACTION]; if (_GetDefaultAction(szActionReg, ARRAYSIZE(szActionReg))) { if (!lstrcmpi(szActionReg, pszActionReg)) fRet = TRUE; } return fRet; } void CFTAdvDlg::_CheckDefaultAction() { HWND hwndLV = _GetLVHWND(); // Is there only one elem? if (1 == ListView_GetItemCount(hwndLV)) { _SetDefaultActionHelper(0, TRUE); } } HRESULT CFTAdvDlg::_SetDefaultAction(int iIndex) { HWND hwndLV = _GetLVHWND(); // Remove previous default if any if (-1 != _iDefaultAction) { _SetDefaultActionHelper(_iDefaultAction, FALSE); ListView_RedrawItems(hwndLV, _iDefaultAction, _iDefaultAction); } // Set new _iDefaultAction = iIndex; // iIndex == -1 means no default if (iIndex >= 0) { _SetDefaultActionHelper(_iDefaultAction, TRUE); ListView_RedrawItems(hwndLV, _iDefaultAction, _iDefaultAction); } return S_OK; } void CFTAdvDlg::_SetDefaultActionHelper(int iIndex, BOOL fDefault) { HWND hwndLV = _GetLVHWND(); LVITEM lvItem = {0}; lvItem.mask = LVIF_PARAM; lvItem.iItem = iIndex; _iDefaultAction = -1; if (ListView_GetItem(hwndLV, &lvItem)) { ADDDATA_DEFAULTACTION(&lvItem) = fDefault; _iDefaultAction = iIndex; } } HRESULT CFTAdvDlg::_InitListView() { LVCOLUMN lvColumn = {0}; HWND hwndLV = _GetLVHWND(); RECT rc = {0}; { // What's this? // We need to handle the WM_MEASUREITEM message from the listview. This msg // is sent before we receive the WM_INITDIALOG and thus before we connect the // this C++ obj to the HWND. By changing the style here we receive the msg // after the C++ obj and the HWND are connected. LONG lStyle = GetWindowLong(hwndLV, GWL_STYLE); lStyle &= ~LVS_LIST; SetWindowLong(hwndLV, GWL_STYLE, lStyle | LVS_REPORT); } // // Set the columns // GetClientRect(hwndLV, &rc); lvColumn.mask = LVCF_SUBITEM|LVCF_WIDTH; lvColumn.cx = rc.right - GetSystemMetrics(SM_CXBORDER); lvColumn.iSubItem = 0; ListView_InsertColumn(hwndLV, 0, &lvColumn); return S_OK; } HRESULT CFTAdvDlg::_UpdateActionButtons() { HRESULT hres = E_FAIL; TCHAR szAction[MAX_ACTION]; BOOL bRet = FALSE; LVITEM lvItem = {0}; lvItem.pszText = szAction; lvItem.cchTextMax = ARRAYSIZE(szAction); bRet = _GetListViewSelectedItem(LVIF_TEXT | LVIF_PARAM, 0, &lvItem); // If we don't have a selected item Or we don't have any text for that item. if (!bRet || !(*(lvItem.pszText))) { EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_EDIT), FALSE); EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_REMOVE), FALSE); EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_DEFAULT), TRUE); hres = S_OK; } else { if (_IsNewPROGIDACTION(lvItem.pszText)) { EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_EDIT), TRUE); EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_REMOVE), TRUE); hres = S_OK; } else { IAssocInfo* pAI = NULL; hres = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hres)) { DWORD dwAttributes; HWND hwndLV = _GetLVHWND(); // REARCHITECT: This code should be in ftassoc.cpp, and we should have // more AIBOOL_ flags for this hres = pAI->GetDWORD(AIDWORD_PROGIDEDITFLAGS, &dwAttributes); if (FAILED(hres)) { // It failed, probably there is no EditFlags value for this progID, let's // set some default value for dwAttributes dwAttributes = 0; } // REARCHITECT (end) EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_EDIT), !((dwAttributes & FTA_NoEditVerb) && !(dwAttributes & FTAV_UserDefVerb))); EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_REMOVE), !((dwAttributes & FTA_NoRemoveVerb) && !(dwAttributes & FTAV_UserDefVerb))); EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_DEFAULT), !(dwAttributes & FTA_NoEditDflt)); // Enable the default button only if the action is not already // the default action EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_DEFAULT), !_IsDefaultAction(ADDDATA_ACTIONREG(&lvItem))); pAI->Release(); } } } return hres; } HRESULT CFTAdvDlg::_UpdateCheckBoxes() { BOOL fBool; IAssocInfo* pAI = NULL; HRESULT hres = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hres)) { hres = pAI->GetBOOL(AIBOOL_CONFIRMOPEN, &fBool); if (SUCCEEDED(hres)) CheckDlgButton(_hwnd, IDC_FT_EDIT_CONFIRM_OPEN, !fBool); hres = pAI->GetBOOL(AIBOOL_ALWAYSSHOWEXT, &fBool); if (SUCCEEDED(hres)) CheckDlgButton(_hwnd, IDC_FT_EDIT_SHOWEXT, fBool); hres = pAI->GetBOOL(AIBOOL_BROWSEINPLACEENABLED, &fBool); if (SUCCEEDED(hres)) { EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_BROWSEINPLACE), fBool); if (fBool) { hres = pAI->GetBOOL(AIBOOL_BROWSEINPLACE, &fBool); if (SUCCEEDED(hres)) CheckDlgButton(_hwnd, IDC_FT_EDIT_BROWSEINPLACE, fBool); } else CheckDlgButton(_hwnd, IDC_FT_EDIT_BROWSEINPLACE, FALSE); } pAI->Release(); } return hres; } HRESULT CFTAdvDlg::_InitChangeIconButton() { HRESULT hres = E_FAIL; BOOL fChangeIcon = TRUE; IAssocInfo* pAI = NULL; hres = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hres)) { hres = pAI->GetBOOL(AIBOOL_EDITDOCICON, &fChangeIcon); if (SUCCEEDED(hres)) EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_CHANGEICON), fChangeIcon); pAI->Release(); } return hres; } HRESULT CFTAdvDlg::_InitDescription() { HRESULT hres = E_FAIL; BOOL fEditDescr = TRUE; IAssocInfo* pAI = NULL; hres = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hres)) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr); hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr); if (SUCCEEDED(hres)) SetDlgItemText(_hwnd, IDC_FT_EDIT_DESC, szProgIDDescr); hres = pAI->GetBOOL(AIBOOL_EDITDESCR, &fEditDescr); EnableWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_DESC), fEditDescr); pAI->Release(); Edit_LimitText(GetDlgItem(_hwnd, IDC_FT_EDIT_DESC), MAX_PROGIDDESCR - 1); } return hres; } HRESULT CFTAdvDlg::_FillListView() { HRESULT hres = E_FAIL; IEnumAssocInfo* pEnum = NULL; hres = _pAssocStore->EnumAssocInfo(ASENUM_ACTION, _szProgID, AIINIT_PROGID, &pEnum); if (SUCCEEDED(hres)) { int iItem = 0; IAssocInfo* pAI = NULL; while (S_OK == pEnum->Next(&pAI)) { TCHAR szActionReg[MAX_ACTION]; DWORD cchActionReg = ARRAYSIZE(szActionReg); hres = pAI->GetString(AISTR_ACTION, szActionReg, &cchActionReg); if (SUCCEEDED(hres)) { TCHAR szActionFN[MAX_ACTION]; DWORD cchActionFN = ARRAYSIZE(szActionFN); hres = pAI->GetString(AISTR_ACTIONFRIENDLY, szActionFN, &cchActionFN); if (SUCCEEDED(hres)) { if (S_FALSE == hres) { hres = StringCchCopy(szActionFN, ARRAYSIZE(szActionFN), szActionReg); } if (SUCCEEDED(hres) && -1 != _InsertListViewItem(iItem, szActionReg, szActionFN)) { ++iItem; } } } pAI->Release(); } pEnum->Release(); } return hres; } LRESULT CFTAdvDlg::OnChangeIcon(WORD wNotif) { IAssocInfo* pAI; HRESULT hr = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hr)) { DWORD cchIconLoc = ARRAYSIZE(_szOldIconLoc); hr = pAI->GetString(AISTR_ICONLOCATION, _szOldIconLoc, &cchIconLoc); pAI->Release(); _iOldIcon = PathParseIconLocation(_szOldIconLoc); } if (FAILED(hr)) { hr = StringCchCopy(_szOldIconLoc, ARRAYSIZE(_szOldIconLoc), TEXT("shell32.dll")); if(SUCCEEDED(hr)) { _iOldIcon = -(IDI_SYSFILE); } } if (SUCCEEDED(hr)) { // setup the in params int iIcon = _iOldIcon; hr = StringCchCopy(_szIconLoc, ARRAYSIZE(_szIconLoc), _szOldIconLoc); if (SUCCEEDED(hr) && PickIconDlg(_hwnd, _szIconLoc, ARRAYSIZE(_szIconLoc), &iIcon)) { _SetDocIcon(Shell_GetCachedImageIndex(_szIconLoc, iIcon, 0)); // Format the _szIconLoc int iLen = lstrlen(_szIconLoc); hr = StringCchPrintf(_szIconLoc + iLen, ARRAYSIZE(_szIconLoc) - iLen, TEXT(",%d"), iIcon); } else { _szIconLoc[0] = 0; } } return FALSE; } // Return value: // TRUE: Check succeeded, everything is OK // FALSE: Check failed BOOL CFTAdvDlg::_CheckForDuplicateNewAction(LPTSTR pszActionReg, LPTSTR pszActionFN) { // we just go through the listview content HWND hwndLV = _GetLVHWND(); int cItem = ListView_GetItemCount(hwndLV); BOOL fRet = TRUE; for (int i = 0; (i < cItem) && fRet; ++i) { TCHAR szActionFN[MAX_ACTION]; LVITEM lvItem = {0}; lvItem.mask = LVIF_PARAM | LVIF_TEXT; lvItem.iItem = i; lvItem.pszText = szActionFN; lvItem.cchTextMax = ARRAYSIZE(szActionFN); ListView_GetItem(hwndLV, &lvItem); if (!lstrcmpi(lvItem.pszText, pszActionFN)) { fRet = FALSE; } else { if (!lstrcmpi(ADDDATA_ACTIONREG(&lvItem), pszActionReg)) { fRet = FALSE; } } } return fRet; } // Return value: // TRUE: Check succeeded, everything is OK // FALSE: Check failed BOOL CFTAdvDlg::_CheckForDuplicateEditAction(LPTSTR pszActionRegOriginal, LPTSTR pszActionReg, LPTSTR pszActionFNOriginal, LPTSTR pszActionFN) { // we just go through the listview content HWND hwndLV = _GetLVHWND(); int cItem = ListView_GetItemCount(hwndLV); BOOL fRet = TRUE; for (int i = 0; (i < cItem) && fRet; ++i) { TCHAR szActionFN[MAX_ACTION]; LVITEM lvItem = {0}; lvItem.mask = LVIF_PARAM | LVIF_TEXT; lvItem.iItem = i; lvItem.pszText = szActionFN; lvItem.cchTextMax = ARRAYSIZE(szActionFN); ListView_GetItem(hwndLV, &lvItem); if (!lstrcmpi(lvItem.pszText, pszActionFN)) { // they are the same, this can happen if this is the Action we were editing // and we did not change the action name // Is this the original one we were editing? if (lstrcmpi(szActionFN, pszActionFNOriginal)) { // No, it's not the original, we have a dup fRet = FALSE; } } else { if (!lstrcmpi(ADDDATA_ACTIONREG(&lvItem), pszActionReg)) { // they are the same, this can happen if this is the Action we were editing // and we did not change the action name // Is this the original one we were editing? if (lstrcmpi(ADDDATA_ACTIONREG(&lvItem), pszActionRegOriginal)) { // No, it's not the original, we have a dup fRet = FALSE; } } } } return fRet; } LRESULT CFTAdvDlg::OnNewButton(WORD wNotif) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; PROGIDACTION pida = {0}; CFTActionDlg* pActionDlg = NULL; pida.fNew = TRUE; GetDlgItemText(_hwnd, IDC_FT_EDIT_DESC, szProgIDDescr, ARRAYSIZE(szProgIDDescr)); // FALSE: New (not-Edit) pActionDlg = new CFTActionDlg(&pida, szProgIDDescr, FALSE); if (pActionDlg) { BOOL fShowAgain; do { fShowAgain = FALSE; if (IDOK == pActionDlg->DoModal(g_hinst, MAKEINTRESOURCE(DLG_FILETYPEOPTIONSCMD), _hwnd)) { // Do we have duplicate actions? if (_CheckForDuplicateNewAction(pida.szActionReg, pida.szAction)) { // No HRESULT hres = _AppendPROGIDACTION(&pida); if (SUCCEEDED(hres)) { int iItem = _InsertListViewItem(0, pida.szActionReg, pida.szAction); hres = S_OK; if (-1 != iItem) _SelectListViewItem(iItem); } } else { // Yes fShowAgain = TRUE; pActionDlg->SetShowAgain(); } } if (fShowAgain) { ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_MB_EXISTINGACTION), MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP, pida.szAction); } } while (fShowAgain); pActionDlg->Release(); } _CheckDefaultAction(); return FALSE; } LRESULT CFTAdvDlg::OnEditButton(WORD wNotif) { TCHAR szAction[MAX_ACTION]; HRESULT hres = E_FAIL; LONG lRes = 0; LVITEM lvItem = {0}; // lvItem.iSubItem = 0; lvItem.pszText = szAction; lvItem.cchTextMax = ARRAYSIZE(szAction); if (_GetListViewSelectedItem(LVIF_TEXT, 0, &lvItem)) { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; PROGIDACTION* pPIDA = NULL; PROGIDACTION pida = {0}; GetDlgItemText(_hwnd, IDC_FT_EDIT_DESC, szProgIDDescr, ARRAYSIZE(szProgIDDescr)); BOOL fNewOrEdit = SUCCEEDED(_GetPROGIDACTION(lvItem.pszText, &pPIDA)); if (!fNewOrEdit) { hres = _FillPROGIDACTION(&pida, ADDDATA_ACTIONREG(&lvItem), szAction); pPIDA = &pida; } else { hres = S_OK; } if (SUCCEEDED(hres)) { // TRUE: Edit CFTActionDlg* pActionDlg = new CFTActionDlg(pPIDA, szProgIDDescr, TRUE); if (pActionDlg) { BOOL fShowAgain; do { fShowAgain = FALSE; if (IDOK == pActionDlg->DoModal(g_hinst, MAKEINTRESOURCE(DLG_FILETYPEOPTIONSCMD), _hwnd)) { // Do we have duplicate actions? if (_CheckForDuplicateEditAction(ADDDATA_ACTIONREG(&lvItem), pPIDA->szActionReg, lvItem.pszText, pPIDA->szAction)) { // No if (!fNewOrEdit) { hres = _AppendPROGIDACTION(pPIDA); } else { hres = S_OK; } if (SUCCEEDED(hres)) { // Replace the current item text hres = StringCchCopy(lvItem.pszText, lvItem.cchTextMax, pPIDA->szAction); if(SUCCEEDED(hres)) { ListView_SetItem(_GetLVHWND(), &lvItem); } } } else { // Yes fShowAgain = TRUE; pActionDlg->SetShowAgain(); } } if (fShowAgain) { ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_MB_EXISTINGACTION), MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP, pPIDA->szAction); } } while (fShowAgain); pActionDlg->Release(); } } } return FALSE; } LRESULT CFTAdvDlg::OnSetDefault(WORD wNotif) { BOOL bRet; LVITEM lvItem = {0}; // lvItem.iSubItem = 0; bRet = _GetListViewSelectedItem(0, 0, &lvItem); if (bRet) _SetDefaultAction(lvItem.iItem); else _SetDefaultAction(-1); return FALSE; } LRESULT CFTAdvDlg::OnRemoveButton(WORD wNotif) { TCHAR szExt[MAX_EXT]; HRESULT hres = E_FAIL; LONG lRes = 0; LVITEM lvItem = {0}; // lvItem.iSubItem = 0; lvItem.pszText = szExt; lvItem.cchTextMax = ARRAYSIZE(szExt); if (_GetListViewSelectedItem(LVIF_TEXT, 0, &lvItem)) { if (IDYES == ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_MB_REMOVEACTION), MAKEINTRESOURCE(IDS_FT), MB_YESNO | MB_ICONQUESTION)) { // // First take care of data side // // Yes. Is this a new Action? PROGIDACTION* pPIDA = NULL; if (SUCCEEDED(_GetPROGIDACTION(lvItem.pszText, &pPIDA)) && pPIDA->fNew) { // Yes, we'll just remove it from the DPA hres = _RemovePROGIDACTION(pPIDA); } else { // No, add its name to the list to delete if user press OK DWORD cchSize = ARRAYSIZE(ADDDATA_ACTIONREG(&lvItem)); LPTSTR pszActionToRemove = (LPTSTR)LocalAlloc(LPTR, cchSize * sizeof(TCHAR)); hres = E_OUTOFMEMORY; if (pszActionToRemove) { hres = StringCchCopy(pszActionToRemove, cchSize, ADDDATA_ACTIONREG(&lvItem)); if (SUCCEEDED(hres) && -1 != DPA_AppendPtr(_hdpaRemovedActions, pszActionToRemove)) hres = S_OK; else LocalFree((HLOCAL)pszActionToRemove); } if (E_OUTOFMEMORY == hres) { //Out of memory ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_ERROR + ERROR_NOT_ENOUGH_MEMORY), MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP); } } // // Then update UI, I/A // if (SUCCEEDED(hres)) { HWND hwndLV = _GetLVHWND(); int iCount = ListView_GetItemCount(hwndLV); int iNextSel = -1; ListView_DeleteItem(hwndLV, lvItem.iItem); if (iCount > lvItem.iItem) iNextSel = lvItem.iItem; else if (lvItem.iItem > 0) iNextSel = lvItem.iItem - 1; if (-1 != iNextSel) _SelectListViewItem(iNextSel); } } else hres = S_FALSE; } _CheckDefaultAction(); return FALSE; } LRESULT CFTAdvDlg::OnOK(WORD wNotif) { BOOL fChecksPassed = FALSE; // Yes, we need to: // - remove "removed" items, modify "edited" ones, // and add "New" ones // - update checkboxes related stuff // - set the default action // - set the icon // - set the description { int n = DPA_GetPtrCount(_hdpaRemovedActions); if (n) { IAssocInfo* pAI; HRESULT hres = E_FAIL; for (int i = 0; i < n; ++i) { LPTSTR pszActionToRemove = (LPTSTR)DPA_GetPtr(_hdpaRemovedActions, i); if (pszActionToRemove && *pszActionToRemove) { hres = _pAssocStore->GetComplexAssocInfo(_szProgID, AIINIT_PROGID, pszActionToRemove, AIINIT_ACTION, &pAI); if (SUCCEEDED(hres)) { pAI->Delete(AIALL_NONE); pAI->Release(); } LocalFree((HLOCAL)pszActionToRemove); DPA_DeletePtr(_hdpaRemovedActions, i); } } } } { int n = DPA_GetPtrCount(_hdpaActions); if (n) { IAssocInfo* pAI = NULL; HRESULT hres = E_FAIL; for (int i = n - 1; i >= 0; --i) { PROGIDACTION* pPIDAFromList = (PROGIDACTION*)DPA_GetPtr(_hdpaActions, i); if (pPIDAFromList) { // Is it an Edited one? if (!pPIDAFromList->fNew) { // Yes, remove the old one first hres = _pAssocStore->GetComplexAssocInfo(_szProgID, AIINIT_PROGID, pPIDAFromList->szOldActionReg, AIINIT_ACTION, &pAI); if (SUCCEEDED(hres)) { pAI->Delete(AIALL_NONE); pAI->Release(); } } // Add new data hres = _pAssocStore->GetComplexAssocInfo(_szProgID, AIINIT_PROGID, pPIDAFromList->szActionReg, AIINIT_ACTION, &pAI); if (SUCCEEDED(hres)) { hres = pAI->SetData(AIDATA_PROGIDACTION, (PBYTE)pPIDAFromList, sizeof(*pPIDAFromList)); pAI->Release(); } // Clean up DPA _DeletePROGIDACTION(pPIDAFromList); DPA_DeletePtr(_hdpaActions, i); } } } } { IAssocInfo* pAI = NULL; HWND hwndLV = _GetLVHWND(); LVFINDINFO lvFindInfo = {0}; int iIndex = -1; HRESULT hres = _pAssocStore->GetAssocInfo(_szProgID, AIINIT_PROGID, &pAI); if (SUCCEEDED(hres)) { TCHAR szActionReg[MAX_ACTION]; hres = pAI->SetBOOL(AIBOOL_CONFIRMOPEN, !IsDlgButtonChecked(_hwnd, IDC_FT_EDIT_CONFIRM_OPEN)); hres = pAI->SetBOOL(AIBOOL_ALWAYSSHOWEXT, IsDlgButtonChecked(_hwnd, IDC_FT_EDIT_SHOWEXT)); hres = pAI->SetBOOL(AIBOOL_BROWSEINPLACE, IsDlgButtonChecked(_hwnd, IDC_FT_EDIT_BROWSEINPLACE)); // Set the default action, if any if (_GetDefaultAction(szActionReg, ARRAYSIZE(szActionReg))) { hres = pAI->SetString(AISTR_PROGIDDEFAULTACTION, szActionReg); } else { hres = pAI->SetString(AISTR_PROGIDDEFAULTACTION, TEXT("")); } // Set the icon, if changed if (_szIconLoc[0]) { // Set it in the registry hres = pAI->SetString(AISTR_ICONLOCATION, _szIconLoc); if (_szOldIconLoc[0]) { int iIconIndex = Shell_GetCachedImageIndex(_szOldIconLoc, _iOldIcon, 0); SHUpdateImage(_szOldIconLoc, _iOldIcon, 0, iIconIndex); } } // Set the description { TCHAR szProgIDDescr[MAX_PROGIDDESCR]; GetDlgItemText(_hwnd, IDC_FT_EDIT_DESC, szProgIDDescr, ARRAYSIZE(szProgIDDescr)); hres = pAI->SetString(AISTR_PROGIDDESCR, szProgIDDescr); } pAI->Release(); } } EndDialog(_hwnd, IDOK); return FALSE; } LRESULT CFTAdvDlg::OnNotifyListView(UINT uCode, LPNMHDR pNMHDR) { HWND hwndLV = _GetLVHWND(); LRESULT lres = FALSE; switch(uCode) { case NM_DBLCLK: if (IsWindowEnabled(GetDlgItem(_hwnd, IDC_FT_EDIT_EDIT))) PostMessage(_hwnd, WM_COMMAND, (WPARAM)IDC_FT_EDIT_EDIT, 0); break; //review: do I really need to do this? case NM_SETFOCUS: case NM_KILLFOCUS: // update list view ListView_RedrawItems(hwndLV, 0, ListView_GetItemCount(hwndLV)); UpdateWindow(hwndLV); break; case LVN_DELETEITEM: { NMLISTVIEW* pNMLV = (NMLISTVIEW*)pNMHDR; if (pNMLV->lParam) { LocalFree((HLOCAL)(pNMLV->lParam)); } break; } case LVN_ITEMCHANGED: { NMLISTVIEW* pNMLV = (NMLISTVIEW*)pNMHDR; // Is a new item being selected/unselected? if (pNMLV->uChanged & LVIF_STATE) { // Yes OnListViewSelItem(pNMLV->iItem, NULL); } break; } } return lres; } LRESULT CFTAdvDlg::OnCancel(WORD wNotif) { EndDialog(_hwnd, IDCANCEL); return FALSE; } LRESULT CFTAdvDlg::OnDestroy(WPARAM wParam, LPARAM lParam) { CFTDlg::OnDestroy(wParam, lParam); return FALSE; } BOOL CFTAdvDlg::_GetListViewSelectedItem(UINT uMask, UINT uStateMask, LVITEM* plvItem) { BOOL fSel = FALSE; HWND hwndLV = _GetLVHWND(); plvItem->mask = uMask | LVIF_STATE | LVIF_PARAM; 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; } int CFTAdvDlg::_InsertListViewItem(int iItem, LPTSTR pszActionReg, LPTSTR pszActionFN) { int iRet = -1; HWND hwndLV = _GetLVHWND(); LVITEM lvItem = {0}; lvItem.mask = LVIF_TEXT | LVIF_PARAM; // Extension lvItem.iItem = iItem; lvItem.pszText = pszActionFN; lvItem.cchTextMax = lstrlen(pszActionFN); LV_ADDDATA* plvadddata = (LV_ADDDATA*)LocalAlloc(LPTR, sizeof(LV_ADDDATA)); if (plvadddata) { lvItem.lParam = (LPARAM)plvadddata; if(SUCCEEDED(StringCchCopy(ADDDATA_ACTIONREG(&lvItem), ARRAYSIZE(ADDDATA_ACTIONREG(&lvItem)), pszActionReg))) { ADDDATA_DEFAULTACTION(&lvItem) = 0; iRet = ListView_InsertItem(hwndLV, &lvItem); } else { LocalFree(plvadddata); } } return iRet; } HWND CFTAdvDlg::_GetLVHWND() { return GetDlgItem(_hwnd, IDC_FT_EDIT_LV_CMDS); } void CFTAdvDlg::_DeletePROGIDACTION(PROGIDACTION* pPIDA) { if (pPIDA) LocalFree((HLOCAL)pPIDA); } HRESULT CFTAdvDlg::_RemovePROGIDACTION(PROGIDACTION* pPIDA) { HRESULT hres = E_FAIL; int n = DPA_GetPtrCount(_hdpaActions); for (int i = 0; (i < n) && FAILED(hres); ++i) { PROGIDACTION* pPIDAFromList = (PROGIDACTION*)DPA_GetPtr(_hdpaActions, i); if (pPIDAFromList == pPIDA) { _DeletePROGIDACTION(pPIDAFromList); DPA_DeletePtr(_hdpaActions, i); hres = S_OK; } } return hres; } HRESULT CFTAdvDlg::_CreatePROGIDACTION(PROGIDACTION** ppPIDA) { HRESULT hres = E_OUTOFMEMORY; *ppPIDA = (PROGIDACTION*)LocalAlloc(LPTR, sizeof(PROGIDACTION)); if (*ppPIDA) hres = S_OK; return hres; } HRESULT CFTAdvDlg::_CopyPROGIDACTION(PROGIDACTION* pPIDADest, PROGIDACTION* pPIDASrc) { memcpy(pPIDADest, pPIDASrc, sizeof(PROGIDACTION)); return S_OK; } HRESULT CFTAdvDlg::_GetPROGIDACTION(LPTSTR pszActionFN, PROGIDACTION** ppPIDA) { HRESULT hres = E_FAIL; *ppPIDA = NULL; if (pszActionFN && *pszActionFN) { int n = DPA_GetPtrCount(_hdpaActions); for (int i = 0; (i < n) && FAILED(hres); ++i) { *ppPIDA = (PROGIDACTION*)DPA_GetPtr(_hdpaActions, i); if (!StrCmpN((*ppPIDA)->szAction, pszActionFN, ARRAYSIZE((*ppPIDA)->szAction))) hres = S_OK; } } if (FAILED(hres)) *ppPIDA = NULL; return hres; } HRESULT CFTAdvDlg::_AppendPROGIDACTION(PROGIDACTION* pPIDA) { PROGIDACTION* pPIDANew = NULL; HRESULT hres = _CreatePROGIDACTION(&pPIDANew); if (SUCCEEDED(hres)) { _CopyPROGIDACTION(pPIDANew, pPIDA); if (-1 != DPA_AppendPtr(_hdpaActions, pPIDANew)) { hres = S_OK; } else { _DeletePROGIDACTION(pPIDANew); hres = E_OUTOFMEMORY; } } if (E_OUTOFMEMORY == hres) { //Out of memory ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_ERROR + ERROR_NOT_ENOUGH_MEMORY), MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP); } return hres; } BOOL CFTAdvDlg::_IsNewPROGIDACTION(LPTSTR pszActionFN) { BOOL fRet = FALSE; PROGIDACTION* pPIDA = NULL; HRESULT hres = _GetPROGIDACTION(pszActionFN, &pPIDA); if (SUCCEEDED(hres)) if (pPIDA->fNew) fRet = TRUE; return fRet; } HRESULT CFTAdvDlg::_FillPROGIDACTION(PROGIDACTION* pPIDA, LPTSTR pszActionReg, LPTSTR pszActionFN) { PROGIDACTION* pPIDAList = NULL; HRESULT hres = _GetPROGIDACTION(pszActionFN, &pPIDAList); if (SUCCEEDED(hres)) { _CopyPROGIDACTION(pPIDA, pPIDAList); } else { IAssocInfo* pAI = NULL; hres = _pAssocStore->GetComplexAssocInfo(_szProgID, AIINIT_PROGID, pszActionReg, AIINIT_ACTION, &pAI); if (SUCCEEDED(hres)) { DWORD cbPIDA = sizeof(*pPIDA); hres = pAI->GetData(AIDATA_PROGIDACTION, (PBYTE)pPIDA, &cbPIDA); pAI->Release(); } } return hres; } /////////////////////////////////////////////////////////////////////////////// // Windows boiler plate code LRESULT CFTAdvDlg::OnCommand(WPARAM wParam, LPARAM lParam) { LRESULT lRes = FALSE; switch(GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_FT_EDIT_NEW: lRes = OnNewButton(GET_WM_COMMAND_CMD(wParam, lParam)); break; case IDC_FT_EDIT_REMOVE: lRes = OnRemoveButton(GET_WM_COMMAND_CMD(wParam, lParam)); break; case IDC_FT_EDIT_EDIT: lRes = OnEditButton(GET_WM_COMMAND_CMD(wParam, lParam)); break; case IDC_FT_EDIT_CHANGEICON: lRes = OnChangeIcon(GET_WM_COMMAND_CMD(wParam, lParam)); break; case IDC_FT_EDIT_DEFAULT: lRes = OnSetDefault(GET_WM_COMMAND_CMD(wParam, lParam)); break; default: lRes = CFTDlg::OnCommand(wParam, lParam); break; } return lRes; } LRESULT CFTAdvDlg::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_EDIT_LV_CMDS: OnNotifyListView(uCode, pNMHDR); lRes = CFTDlg::OnNotify(wParam, lParam); break; default: lRes = CFTDlg::OnNotify(wParam, lParam); break; } return lRes; } LRESULT CFTAdvDlg::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRes = FALSE; switch(uMsg) { case WM_DRAWITEM: lRes = OnDrawItem(wParam, lParam); break; case WM_MEASUREITEM: lRes = OnMeasureItem(wParam, lParam); break; default: lRes = CFTDlg::WndProc(uMsg, wParam, lParam); break; } return lRes; }