/*++ Implements population of a listview control with the content from the start menu --*/ #include "stdafx.h" #include "resource.h" #include #include #include #include #include #include #include #include #include "CompatUI.h" #include "progview.h" extern "C" { #include "shimdb.h" } #pragma warning(disable:4786) #include #include #include #include using namespace std; #ifdef _UNICODE typedef wstring tstring; #else typedef string tstring; #endif typedef INSTALLSTATE (WINAPI*PMsiGetComponentPath)( LPCTSTR szProduct, // product code for client product LPCTSTR szComponent, // component ID LPTSTR lpPathBuf, // returned path DWORD *pcchBuf // buffer character count ); typedef UINT (WINAPI* PMsiGetShortcutTarget)( LPCTSTR szShortcutTarget, // path to shortcut link file LPTSTR szProductCode, // fixed length buffer for product code LPTSTR szFeatureId, // fixed length buffer for feature id LPTSTR szComponentCode // fixed length buffer for component code ); typedef enum tagPROGRAMINFOCLASS { PROGLIST_DISPLAYNAME, PROGLIST_LOCATION, // PROGLIST_EXENAME, // cracked exe name PROGLIST_CMDLINE, // complete exe name + parameters PROGLIST_EXECUTABLE, // what we should execute (link or exe, not cracked) PROGLIST_ARGUMENTS // just the args }; class CException { public: CException(LPCSTR lpszFile = NULL, DWORD nLocation = 0) { SetLocation(lpszFile, nLocation); } virtual ~CException() {} virtual VOID Delete() { delete this; } int __cdecl FormatV(LPCTSTR lpszFormat, va_list arg) { int nch = 0; if (lpszFormat) { nch = _vsntprintf(szDescription, CHARCOUNT(szDescription), lpszFormat, arg); } else { *szDescription = TEXT('\0'); } return nch; } int __cdecl Format(LPCTSTR lpszFormat, ...) { va_list arg; int nch = 0; if (lpszFormat) { va_start(arg, lpszFormat); nch = _vsntprintf(szDescription, CHARCOUNT(szDescription), lpszFormat, arg); va_end(arg); } else { *szDescription = TEXT('\0'); } } VOID SetLocation(LPCSTR lpszFile, DWORD nLocation) { if (lpszFile) { strcpy(szLocation, lpszFile); } else { *szLocation = TEXT('\0'); } m_dwLocation = nLocation; } TCHAR szDescription[MAX_PATH]; CHAR szLocation[MAX_PATH]; DWORD m_dwLocation; }; class CMemoryException : public CException { public: CMemoryException(LPCSTR lpszFile = NULL, DWORD nLocation = 0) : CException(lpszFile, nLocation) {} VOID Delete() {} }; class CCancelException : public CException { public: CCancelException(LPCSTR lpszFile = NULL, DWORD nLocation = 0) : CException(lpszFile, nLocation){} }; static CMemoryException _MemoryExceptionStatic; VOID __cdecl ThrowMemoryException(LPCSTR lpszFile, DWORD nLocation, LPCTSTR lpszFormat = NULL, ...) { va_list arg; CMemoryException* pMemoryException = &_MemoryExceptionStatic; va_start(arg, lpszFormat); pMemoryException->FormatV(lpszFormat, arg); va_end(arg); throw pMemoryException; } class CProgramList { public: CProgramList(LPMALLOC pMalloc, HWND hwndListView, LPCTSTR szSystemDirectory) : m_pMalloc(pMalloc), m_hwndListView(hwndListView), m_hMSI(NULL), m_pSelectionInfo(NULL), m_hbmSort(NULL), m_pProgView(NULL), m_hEventCancel(NULL) { // // we are always initializing on populate thread // m_dwOwnerThreadID = GetCurrentThreadId(); m_strSystemDirectory = szSystemDirectory; } ~CProgramList(); BOOL PopulateControl(CProgView* pProgView = NULL, HANDLE hEventCancel = NULL); LPMALLOC GetMalloc(VOID) { return GetCurrentThreadId() == m_dwOwnerThreadID ? m_pMalloc : m_pMallocUI; } BOOL CaptureSelection(); BOOL GetSelectionDetails(INT iInformationClass, VARIANT* pVal); LRESULT LVNotifyDispInfo (LPNMHDR pnmhdr, BOOL& bHandled); LRESULT LVNotifyColumnClick(LPNMHDR pnmhdr, BOOL& bHandled); LRESULT LVNotifyGetInfoTip (LPNMHDR pnmhdr, BOOL& bHandled); LRESULT LVNotifyRClick (LPNMHDR pnmhdr, BOOL& bHandled); BOOL IsEnabled(VOID); VOID Enable(BOOL); BOOL UpdateListItem(LPCWSTR pwszPath, LPCWSTR pwszKey); protected: BOOL ListFolder(LPCTSTR pszLocationParent, IShellFolder* pFolder, LPCITEMIDLIST pidlFull, LPCITEMIDLIST pidlFolder); BOOL ListLink(LPCTSTR pszLocationParent, LPCTSTR pszDisplayName, IShellFolder* pFolder, LPCITEMIDLIST pidlFull, LPCITEMIDLIST pidlLink); BOOL ListMsiLink(LPCTSTR pszLocationParent, LPCTSTR pszDisplayName, LPCTSTR pszMsiPath, IShellFolder* pFolder, LPCITEMIDLIST pidlFull); LPITEMIDLIST GetNextItemIDL(LPCITEMIDLIST pidl); UINT GetSizeIDL (LPCITEMIDLIST pidl); LPITEMIDLIST AppendIDL (LPCITEMIDLIST pidlBase, LPCITEMIDLIST pidlAdd); LPITEMIDLIST GetLastItemIDL(LPCITEMIDLIST pidl); BOOL GetDisplayName(IShellFolder* pFolder, LPCITEMIDLIST pidl, tstring& strDisplay); BOOL GetPathFromLink(IShellLink* pLink, WIN32_FIND_DATA* pfd, tstring& strPath); BOOL GetArgumentsFromLink(IShellLink* pLink, tstring& strArgs); BOOL AddItem(LPCTSTR pszLocation, LPCTSTR pszDisplayName, LPCTSTR pszPath, LPCTSTR pszArguments, IShellFolder* pFolder, LPCITEMIDLIST pidlFull, BOOL bUsePath = FALSE); // true if we should use path for executable int GetIconFromLink(LPCITEMIDLIST pidlLinkFull, LPCTSTR lpszExePath); BOOL IsSFCItem(LPCTSTR lpszItem); BOOL IsItemInSystemDirectory(LPCTSTR pszPath); private: LPMALLOC m_pMalloc; LPMALLOC m_pMallocUI; HWND m_hwndListView; // list view control HBITMAP m_hbmSort; typedef struct tagSHITEMINFO { tstring strDisplayName; // descriptive name tstring strFolder; // containing folder tstring strPath; // actual exe, cracked tstring strPathExecute; // link path (this is what we will execute) tstring strCmdLine; // command line (cracked link) tstring strArgs; tstring strKeys; LPITEMIDLIST pidl; // full pidl } SHITEMINFO, *PSHITEMINFO; static CALLBACK SHItemInfoCompareFunc(LPARAM lp1, LPARAM lp2, LPARAM lParamSort); typedef map< tstring, PSHITEMINFO, less > MAPSTR2ITEM; typedef multimap< tstring, PSHITEMINFO > MULTIMAPSTR2ITEM; // // store key->item sequence, the keys are cmdlines (with args) // MAPSTR2ITEM m_mapItems; // // store key->item sequence, where the key is exe name (path) // MULTIMAPSTR2ITEM m_mmapExeItems; // // selected item // PSHITEMINFO m_pSelectionInfo; // // cached msi.dll handle // HMODULE m_hMSI; PMsiGetComponentPath m_pfnGetComponentPath; PMsiGetShortcutTarget m_pfnGetShortcutTarget; // // cached system directory // tstring m_strSystemDirectory; // // image list used to show icons // HIMAGELIST m_hImageList; // // optional pointer to the parent view // CProgView* m_pProgView; // // event that we use to signal the end of scan // HANDLE m_hEventCancel; // // owner thread // DWORD m_dwOwnerThreadID; VOID CheckForCancel() { if (m_hEventCancel) { if (::WaitForSingleObject(m_hEventCancel, 0) != WAIT_TIMEOUT) { // cancelled!!! throw new CCancelException(); } } } }; // // in upload.cpp // wstring StrUpCase(wstring& wstr); // // load the string from resources // wstring LoadResourceString(UINT nID) { LPTSTR lpszBuffer = NULL; int cch; wstring str; cch = ::LoadString(_Module.GetModuleInstance(), nID, (LPTSTR)&lpszBuffer, 0); // // hack! this must work (I know it does) // if (cch && NULL != lpszBuffer) { str = wstring(lpszBuffer, cch); } return str; } ///////////////////////////////////////////////////////////////////////////////////////////////// // // Utility functions // BOOL InitializeProgramList( CProgramList** ppProgramList, HWND hwndListView ) { HRESULT hr; BOOL bSuccess = FALSE; LPMALLOC pMalloc = NULL; TCHAR szSystemWindowsDirectory[MAX_PATH]; CProgramList* pProgramList = NULL; UINT uSize; hr = SHGetMalloc(&pMalloc); if (!SUCCEEDED(hr)) { goto ErrHandle; } uSize = ::GetSystemWindowsDirectory(szSystemWindowsDirectory, CHARCOUNT(szSystemWindowsDirectory)); if (uSize == 0 || uSize > CHARCOUNT(szSystemWindowsDirectory)) { goto ErrHandle; } pProgramList = new CProgramList(pMalloc, hwndListView, szSystemWindowsDirectory); if (NULL == pProgramList) { goto ErrHandle; } *ppProgramList = pProgramList; bSuccess = TRUE; ErrHandle: if (!bSuccess) { if (NULL != pMalloc) { pMalloc->Release(); } if (NULL != pProgramList) { delete pProgramList; } } return bSuccess; } BOOL CleanupProgramList( CProgramList* pProgramList ) { LPMALLOC pMalloc; if (NULL == pProgramList) { return FALSE; } pMalloc = pProgramList->GetMalloc(); delete pProgramList; if (NULL != pMalloc) { pMalloc->Release(); } return TRUE; } BOOL PopulateProgramList( CProgramList* pProgramList, CProgView* pProgView, HANDLE hEventCancel ) { return pProgramList->PopulateControl(pProgView, hEventCancel); } CProgramList::~CProgramList() { // // // MAPSTR2ITEM::iterator iter; iter = m_mapItems.begin(); while (iter != m_mapItems.end()) { PSHITEMINFO pInfo = (*iter).second; GetMalloc()->Free(pInfo->pidl); // nuke this please delete pInfo; ++iter; } if (NULL != m_hbmSort) { DeleteObject(m_hbmSort); } // Image list is destroyed automatically when the control is destroyed // // if (NULL != m_hImageList) { // ImageList_Destroy(m_hImageList); // } if (NULL != m_hMSI && (HMODULE)-1 != m_hMSI) { FreeLibrary(m_hMSI); } } BOOL CProgramList::GetDisplayName( IShellFolder* pFolder, LPCITEMIDLIST pidl, tstring& strDisplayName ) { STRRET strName; HRESULT hr; LPTSTR pszName = NULL; hr = pFolder->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strName); if (!SUCCEEDED(hr)) { return FALSE; } hr = StrRetToStr(&strName, pidl, &pszName); if (!SUCCEEDED(hr)) { return FALSE; } // if we have been successful, assign return result if (pszName != NULL) { strDisplayName = pszName; CoTaskMemFree(pszName); } else { strDisplayName.erase(); } return TRUE; } BOOL CProgramList::GetPathFromLink( IShellLink* pLink, WIN32_FIND_DATA* pfd, tstring& strPath ) { TCHAR szPath[MAX_PATH]; HRESULT hr; hr = pLink->GetPath(szPath, sizeof(szPath)/sizeof(szPath[0]), pfd, 0); if (hr == S_OK) { strPath = szPath; } return hr == S_OK; } BOOL CProgramList::GetArgumentsFromLink( IShellLink* pLink, tstring& strArgs ) { TCHAR szArgs[INFOTIPSIZE]; HRESULT hr = pLink->GetArguments(szArgs, sizeof(szArgs)/sizeof(szArgs[0])); if (SUCCEEDED(hr)) { strArgs = szArgs; } return SUCCEEDED(hr); } LPITEMIDLIST CProgramList::GetNextItemIDL( LPCITEMIDLIST pidl ) { // Check for valid pidl. if (pidl == NULL) { return NULL; } // Get the size of the specified item identifier. int cb = pidl->mkid.cb; // If the size is zero, it is the end of the list. if (cb == 0) { return NULL; } // Add cb to pidl (casting to increment by bytes). pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb); // Return NULL if it is null-terminating, or a pidl otherwise. return (pidl->mkid.cb == 0) ? NULL : (LPITEMIDLIST) pidl; } LPITEMIDLIST CProgramList::GetLastItemIDL( LPCITEMIDLIST pidl ) { LPITEMIDLIST pidlLast = (LPITEMIDLIST)pidl; if (pidl == NULL) { return NULL; } int cb = pidl->mkid.cb; if (cb == 0) { return NULL; } do { pidl = GetNextItemIDL(pidlLast); if (pidl != NULL) { pidlLast = (LPITEMIDLIST)pidl; } } while (pidl != NULL); return pidlLast; } UINT CProgramList::GetSizeIDL( LPCITEMIDLIST pidl ) { UINT cbTotal = 0; if (pidl) { cbTotal += sizeof(pidl->mkid.cb); // Null terminator while (NULL != pidl) { cbTotal += pidl->mkid.cb; pidl = GetNextItemIDL(pidl); } } return cbTotal; } LPITEMIDLIST CProgramList::AppendIDL( LPCITEMIDLIST pidlBase, LPCITEMIDLIST pidlAdd ) { if (NULL == pidlBase && NULL == pidlAdd) { return NULL; } LPITEMIDLIST pidlNew, pidlAlloc; UINT cb1 = pidlBase ? GetSizeIDL(pidlBase) : 0; UINT cb2 = pidlAdd ? GetSizeIDL(pidlAdd) : 0; UINT size = cb1 + cb2; pidlAlloc = pidlNew = (LPITEMIDLIST)GetMalloc()->Alloc(size); if (pidlNew) { if (NULL != pidlBase) { cb1 = pidlAdd ? cb1 - sizeof(pidlBase->mkid.cb) : cb1; RtlMoveMemory(pidlNew, pidlBase, cb1); pidlNew = (LPITEMIDLIST)((PBYTE)pidlNew + cb1); } if (NULL != pidlAdd) { RtlMoveMemory(pidlNew, pidlAdd, cb2); } } return pidlAlloc; } BOOL CProgramList::ListMsiLink( LPCTSTR pszLocationParent, LPCTSTR pszDisplayName, LPCTSTR pszMsiPath, IShellFolder* pFolder, LPCITEMIDLIST pidlFull ) { // // make sure we have msi module handle // if (NULL == m_hMSI) { m_hMSI = LoadLibrary(TEXT("msi.dll")); if (NULL == m_hMSI) { m_hMSI = (HMODULE)-1; return FALSE; } #ifdef _UNICODE m_pfnGetComponentPath = (PMsiGetComponentPath )GetProcAddress(m_hMSI, "MsiGetComponentPathW"); m_pfnGetShortcutTarget = (PMsiGetShortcutTarget)GetProcAddress(m_hMSI, "MsiGetShortcutTargetW"); #else m_pfnGetComponentPath = (PMsiGetComponentPath )GetProcAddress(m_hMSI, "MsiGetComponentPathA"); m_pfnGetShortcutTarget = (PMsiGetShortcutTarget)GetProcAddress(m_hMSI, "MsiGetShortcutTargetA"); #endif if (m_pfnGetComponentPath == NULL || m_pfnGetShortcutTarget == NULL) { FreeLibrary(m_hMSI); m_hMSI = (HMODULE)-1; return FALSE; } } else if (m_hMSI == (HMODULE)-1) { return FALSE; } UINT ErrCode; TCHAR szProduct[MAX_PATH]; TCHAR szFeatureId[MAX_PATH]; TCHAR szComponentCode[MAX_PATH]; ErrCode = m_pfnGetShortcutTarget(pszMsiPath, szProduct, szFeatureId, szComponentCode); if (ERROR_SUCCESS != ErrCode) { return FALSE; } INSTALLSTATE is; TCHAR szPath[MAX_PATH]; DWORD cchPath = sizeof(szPath)/sizeof(szPath[0]); *szPath = 0; is = m_pfnGetComponentPath(szProduct, szComponentCode, szPath, &cchPath); if (INSTALLSTATE_LOCAL == is) { // // add this item // return AddItem(pszLocationParent, pszDisplayName, szPath, NULL, pFolder, pidlFull, TRUE); } return FALSE; } int CProgramList::GetIconFromLink( LPCITEMIDLIST pidlLinkFull, LPCTSTR lpszExePath ) { HRESULT hr; IShellFolder* pFolder = NULL; IExtractIcon* pExtractIcon = NULL; INT iIconIndex = 0; UINT uFlags = 0; LPCITEMIDLIST pidlLink = 0; HICON hIconLarge = NULL; HICON hIconSmall = NULL; UINT nIconSize; int ImageIndex = -1; UINT uiErrorMode; DWORD dwAttributes; TCHAR szIconFile[MAX_PATH]; *szIconFile = TEXT('\0'); uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); hr = SHBindToParent(pidlLinkFull, IID_IShellFolder, (PVOID*)&pFolder, &pidlLink); if (!SUCCEEDED(hr)) { goto trySysImage; } // get the ui please hr = pFolder->GetUIObjectOf(m_hwndListView, 1, (LPCITEMIDLIST*)&pidlLink, IID_IExtractIcon, NULL, (PVOID*)&pExtractIcon); if (!SUCCEEDED(hr)) { goto trySysImage; } hr = pExtractIcon->GetIconLocation(0, szIconFile, sizeof(szIconFile) / sizeof(szIconFile[0]), &iIconIndex, &uFlags); if (!SUCCEEDED(hr)) { goto trySysImage; } if (*szIconFile == TEXT('*')) { // this is batch or some such, don't bother goto trySysImage; } // // before doing an extract, check whether it's available // dwAttributes = GetFileAttributes(szIconFile); if (dwAttributes == (DWORD)-1) { goto trySysImage; } nIconSize = MAKELONG(0, ::GetSystemMetrics(SM_CXSMICON)); // // this call is likely to produce a popup, beware of that // hr = pExtractIcon->Extract(szIconFile, iIconIndex, &hIconLarge, &hIconSmall, nIconSize); // // if hIconSmall was retrieved - we were successful // trySysImage: if (hIconSmall == NULL) { // // woops -- we could not extract an icon -- what a bummer // use shell api then SHFILEINFO FileInfo; HIMAGELIST hImageSys; hImageSys = (HIMAGELIST)SHGetFileInfo(lpszExePath, 0, &FileInfo, sizeof(FileInfo), SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX); if (hImageSys) { hIconSmall = ImageList_GetIcon(hImageSys, FileInfo.iIcon, ILD_TRANSPARENT); } } // // now that we have an icon, we can add it to our image list ? // if (hIconSmall != NULL) { ImageIndex = ImageList_AddIcon(m_hImageList, hIconSmall); } ///////////////////////// cleanup /////////////////////////////////////////// SetErrorMode(uiErrorMode); if (hIconSmall) { DestroyIcon(hIconSmall); } if (hIconLarge) { DestroyIcon(hIconLarge); } if (pExtractIcon != NULL) { pExtractIcon->Release(); } if (pFolder != NULL) { pFolder->Release(); } return ImageIndex; } BOOL CProgramList::ListLink( LPCTSTR pszLocationParent, LPCTSTR pszDisplayName, IShellFolder* pFolder, LPCITEMIDLIST pidlFull, LPCITEMIDLIST pidlLink ) { IShellLink* psl = NULL; WIN32_FIND_DATA wfd; HRESULT hr; BOOL bSuccess = FALSE; tstring strPath; tstring strArgs; CComBSTR bstr; LPCTSTR pszArgs = NULL; IPersistFile* ipf = NULL; IShellLinkDataList* pdl; DWORD dwFlags; BOOL bMsiLink = FALSE; // // check whether we need to cancel // CheckForCancel(); hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); if (!SUCCEEDED(hr)) { return FALSE; // we can't create link object } hr = psl->SetIDList(pidlFull); // set the id list if (!SUCCEEDED(hr)) { goto out; } // // now the shell link is ready to rumble // if (!GetPathFromLink(psl, &wfd, strPath)) { goto out; } // now let's see what is inside of this link -- shall we? hr = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ipf); if (!SUCCEEDED(hr)) { goto out; } bstr = strPath.c_str(); hr = ipf->Load(bstr, STGM_READ); if (SUCCEEDED(hr)) { // // resolve the link for now // // hr = psl->Resolve(NULL, SLR_NO_UI|SLR_NOUPDATE); hr = psl->QueryInterface(IID_IShellLinkDataList, (LPVOID*)&pdl); if (SUCCEEDED(hr)) { hr = pdl->GetFlags(&dwFlags); bMsiLink = SUCCEEDED(hr) && (dwFlags & SLDF_HAS_DARWINID); pdl->Release(); } if (bMsiLink) { bSuccess = ListMsiLink(pszLocationParent, pszDisplayName, strPath.c_str(), pFolder, pidlFull); } else { // // we now get the path from the link -- and that's that // if (GetPathFromLink(psl, &wfd, strPath)) { if (GetArgumentsFromLink(psl, strArgs)) { pszArgs = strArgs.c_str(); } // // add this to our list view // bSuccess = AddItem(pszLocationParent, pszDisplayName, strPath.c_str(), pszArgs, pFolder, pidlFull); } } } if (NULL != ipf) { ipf->Release(); } out: if (NULL != psl) { psl->Release(); } return bSuccess; } BOOL CProgramList::ListFolder( LPCTSTR pszLocation, // ui string - where is this folder located? IShellFolder* pParent, // parent folder LPCITEMIDLIST pidlFull, // idl of the full path to the folder LPCITEMIDLIST pidlFolder // idl of this folder relative to the pidlFull ) { LPENUMIDLIST penum = NULL; LPITEMIDLIST pidl = NULL; HRESULT hr; ULONG celtFetched; ULONG uAttr; tstring strDisplayNameLocation; tstring strDisplayName; IShellFolder* pFolder = NULL; BOOL bDesktop = FALSE; BOOL bCancel = FALSE; CCancelException* pCancelException = NULL; CheckForCancel(); if (pParent == NULL) { hr = SHGetDesktopFolder(&pParent); bDesktop = TRUE; } hr = pParent->BindToObject(pidlFolder, NULL, IID_IShellFolder, (LPVOID *) &pFolder); if (NULL == pszLocation) { GetDisplayName(pParent, pidlFolder, strDisplayNameLocation); } else { strDisplayNameLocation = pszLocation; } if (bDesktop) { pParent->Release(); } if (!SUCCEEDED(hr)) { return FALSE; } hr = pFolder->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penum); if (!SUCCEEDED(hr)) { pFolder->Release(); // free the folder- - and go away return FALSE; } while( (hr = penum->Next(1,&pidl, &celtFetched)) == S_OK && celtFetched == 1 && !bCancel) { LPITEMIDLIST pidlCur; if (pidlFull == NULL) { pidlFull = pidlFolder; } pidlCur = AppendIDL(pidlFull, pidl); // get the display name of this item GetDisplayName(pFolder, pidl, strDisplayName); uAttr = SFGAO_FOLDER | SFGAO_LINK; hr = pFolder->GetAttributesOf(1, (LPCITEMIDLIST *) &pidl, &uAttr); if (SUCCEEDED(hr)) { try { if (uAttr & SFGAO_FOLDER) { // // dump folder recursively // ListFolder(strDisplayName.c_str(), pFolder, pidlCur, pidl); } else if (uAttr & SFGAO_LINK) { ListLink(strDisplayNameLocation.c_str(), strDisplayName.c_str(), pFolder, pidlCur, pidl); } else if (uAttr & SFGAO_FILESYSTEM) { // // this item is a file // AddItem(strDisplayNameLocation.c_str(), strDisplayName.c_str(), NULL, NULL, pFolder, pidlCur, TRUE); } } catch(CCancelException* pex) { // // we need to cancel -- we shall cleanup and do what we need, then re-throw // bCancel = TRUE; pCancelException = pex; } } GetMalloc()->Free(pidlCur); GetMalloc()->Free(pidl); } if (NULL != penum) { penum->Release(); } if (NULL != pFolder) { pFolder->Release(); } if (bCancel && pCancelException) { throw pCancelException; } return TRUE; } BOOL CProgramList::IsSFCItem( LPCTSTR pszPath ) { #ifndef _UNICODE WCHAR wszBuffer[1024]; mbstowcs(wszBuffer, pszPath, sizeof(wszBuffer)/sizeof(wszBuffer[0])); return SfcIsFileProtected(NULL, wszBuffer); #else return SfcIsFileProtected(NULL, pszPath); #endif } BOOL CProgramList::IsItemInSystemDirectory( LPCTSTR pszPath ) { TCHAR szCommonPath[MAX_PATH]; int nch; string s; nch = PathCommonPrefix(m_strSystemDirectory.c_str(), pszPath, szCommonPath); return nch == m_strSystemDirectory.length(); } BOOL ValidateExecutableFile( LPCTSTR pszPath, BOOL bValidateFileExists ) { LPTSTR rgExt[] = { TEXT("EXE"), TEXT("BAT"), TEXT("CMD"), TEXT("PIF"), TEXT("COM"), TEXT("LNK") }; LPTSTR pExt; int i; BOOL bValidatedExt = FALSE; pExt = PathFindExtension(pszPath); if (pExt == NULL || *pExt == TEXT('\0')) { return FALSE; } ++pExt; for (i = 0; i < sizeof(rgExt)/sizeof(rgExt[0]) && !bValidatedExt; ++i) { bValidatedExt = !_tcsicmp(pExt, rgExt[i]); } if (!bValidatedExt) { return FALSE; } return bValidateFileExists ? PathFileExists(pszPath) : TRUE; } BOOL CProgramList::AddItem( LPCTSTR pszLocation, LPCTSTR pszDisplayName, LPCTSTR pszPath, LPCTSTR pszArguments, IShellFolder* pFolder, LPCITEMIDLIST pidlFull, BOOL bUsePath ) { // // first test -- is this one of the types we like? // LPTSTR pchSlash; LPTSTR pchDot; LPTSTR rgExt[] = { TEXT("EXE"), TEXT("BAT"), TEXT("CMD"), TEXT("PIF"), TEXT("COM"), TEXT("LNK") }; BOOL bValidatedExt = FALSE; BOOL bSuccess = FALSE; PSHITEMINFO pInfo = NULL; MAPSTR2ITEM::iterator Iter; TCHAR szPathExecute[MAX_PATH]; tstring strKey; tstring strKeyExe; DWORD dwBinaryType = 0; LVITEM lvi; int ix; // // check for cancelling the search // CheckForCancel(); if (NULL == pszPath) { pszPath = szPathExecute; if (!SHGetPathFromIDList(pidlFull, szPathExecute)) { goto out; } } if (pszDisplayName && m_pProgView) { m_pProgView->UpdatePopulateStatus(pszDisplayName, pszPath); } pchSlash = _tcsrchr(pszPath, TEXT('\\')); pchDot = _tcsrchr(pszPath, TEXT('.')); if (NULL != pchSlash) { if ((ULONG_PTR)pchDot < (ULONG_PTR)pchSlash) { pchDot = NULL; } } if (NULL != pchDot) { ++pchDot; for (int i = 0; i < sizeof(rgExt)/sizeof(rgExt[0]) && !bValidatedExt; ++i) { bValidatedExt = !_tcsicmp(pchDot, rgExt[i]); } } if (!bValidatedExt) { goto out; } // // Checks whether the item is in system directory or SFC-protected // #if 0 if (IsItemInSystemDirectory(pszPath) || IsSFCItem(pszPath)) { goto out; } #endif // // GetBinaryTypeW excludes exes on the basis of binary type // if (GetBinaryType(pszPath, &dwBinaryType) && dwBinaryType == SCS_64BIT_BINARY) { goto out; } if (IsSFCItem(pszPath)) { goto out; } // // this is multimap key // strKeyExe = StrUpCase(wstring(pszPath)); // // check whether this has been excluded // if (m_pProgView->IsFileExcluded(strKeyExe.c_str())) { goto out; } // // now compose the key string // strKey = strKeyExe; if (NULL != pszArguments) { strKey.append(TEXT(" ")); strKey.append(pszArguments); } // // now check whether this item has already been listed // Iter = m_mapItems.find(strKey); if (Iter != m_mapItems.end()) { // found a duplicate goto out; } // // now please add this item to the list view // pInfo = new CProgramList::SHITEMINFO; if (pInfo == NULL) { ThrowMemoryException(__FILE__, __LINE__, TEXT("%s\n"), TEXT("Failed to allocate Item Information structure")); } pInfo->strDisplayName = pszDisplayName; pInfo->strFolder = pszLocation; pInfo->strPath = pszPath; pInfo->strCmdLine = strKey; if (NULL != pszArguments) { pInfo->strArgs = pszArguments; } pInfo->pidl = AppendIDL(NULL, pidlFull); if (bUsePath) { pInfo->strPathExecute = pszPath; } else { // finally, what are we going to launch ? if (SHGetPathFromIDList(pidlFull, szPathExecute)) { pInfo->strPathExecute = szPathExecute; } } m_mapItems[strKey] = pInfo; m_mmapExeItems.insert(MULTIMAPSTR2ITEM::value_type(strKeyExe, pInfo)); ATLTRACE(TEXT("Adding item %s %s %s\n"), pszDisplayName, pszLocation, pszPath); lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_IMAGE; lvi.iItem = ListView_GetItemCount(m_hwndListView); // append at the end please lvi.iSubItem = 0; lvi.pszText = LPSTR_TEXTCALLBACK; lvi.iImage = I_IMAGECALLBACK; lvi.lParam = (LPARAM)pInfo; ix = ListView_InsertItem(m_hwndListView, &lvi); lvi.mask = LVIF_TEXT; lvi.iItem = ix; lvi.iSubItem = 1; lvi.pszText = LPSTR_TEXTCALLBACK; ListView_SetItem(m_hwndListView, &lvi); bSuccess = TRUE; out: return bSuccess; } BOOL CProgramList::PopulateControl( CProgView* pProgView, HANDLE hevtCancel ) { int i; HRESULT hr; LPITEMIDLIST pidl; BOOL bCancel = FALSE; struct { INT csidl; UINT nIDDescription; } rgFolders[] = { { CSIDL_DESKTOPDIRECTORY, IDS_DESKTOP }, { CSIDL_COMMON_STARTMENU, IDS_COMMON_STARTMENU }, { CSIDL_STARTMENU, IDS_STARTMENU }, { CSIDL_COMMON_PROGRAMS, IDS_COMMON_PROGRAMS }, { CSIDL_PROGRAMS, IDS_PROGRAMS } }; // // set the progview object pointer so we could update the status // m_pProgView = pProgView; m_pMallocUI = pProgView->m_pMallocUI; // // set the event so that we could cancel the scan // m_hEventCancel = hevtCancel; // // set extended style // ListView_SetExtendedListViewStyleEx(m_hwndListView, LVS_EX_INFOTIP|LVS_EX_LABELTIP, LVS_EX_INFOTIP|LVS_EX_LABELTIP); // // fix columns // LVCOLUMN lvc; RECT rc; SIZE_T cxProgName; SIZE_T cx; wstring strCaption; lvc.mask = LVCF_WIDTH; if (!ListView_GetColumn(m_hwndListView, 2, &lvc)) { ::GetClientRect(m_hwndListView, &rc); cx = rc.right - rc.left - ::GetSystemMetrics(SM_CXVSCROLL) - ::GetSystemMetrics(SM_CXEDGE) - ::GetSystemMetrics(SM_CXSIZEFRAME); cxProgName = cx * 3 / 5; strCaption = LoadResourceString(IDS_PROGRAMNAME); lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT; lvc.pszText = (LPTSTR)strCaption.c_str(); lvc.fmt = LVCFMT_LEFT; lvc.cx = cxProgName; lvc.iSubItem= 0; ListView_InsertColumn(m_hwndListView, 0, &lvc); cx -= cxProgName; cxProgName = cx / 2; strCaption = LoadResourceString(IDS_FOLDER); lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; lvc.pszText = (LPTSTR)strCaption.c_str(); lvc.fmt = LVCFMT_LEFT; lvc.cx = cxProgName; lvc.iSubItem= 1; ListView_InsertColumn(m_hwndListView, 1, &lvc); strCaption = LoadResourceString(IDS_SETTINGS); lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; lvc.pszText = (LPTSTR)strCaption.c_str(); lvc.fmt = LVCFMT_LEFT; lvc.cx = cx - cxProgName; lvc.iSubItem= 2; ListView_InsertColumn(m_hwndListView, 2, &lvc); } HDC hDC = GetDC(m_hwndListView); int nBitsPixel = ::GetDeviceCaps(hDC, BITSPIXEL); int nPlanes = ::GetDeviceCaps(hDC, PLANES); UINT flags; nBitsPixel *= nPlanes; if (nBitsPixel < 4) { flags = ILC_COLOR; } else if (nBitsPixel < 8) { flags = ILC_COLOR4; } else if (nBitsPixel < 16) { flags = ILC_COLOR8; } else if (nBitsPixel < 24) { flags = ILC_COLOR16; } else if (nBitsPixel < 32) { flags = ILC_COLOR24; } else if (nBitsPixel == 32) { flags = ILC_COLOR32; } else { flags = ILC_COLORDDB; } flags |= ILC_MASK; ReleaseDC(m_hwndListView, hDC); m_hImageList = ImageList_Create(::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), flags, 10, 25); if (m_hImageList == NULL) { ATLTRACE(TEXT("Image List creation failure, error 0x%lx\n"), GetLastError()); } ImageList_SetBkColor(m_hImageList, CLR_NONE); ListView_SetImageList(m_hwndListView, m_hImageList, LVSIL_SMALL); ::SendMessage(m_hwndListView, WM_SETREDRAW, FALSE, 0); ListView_DeleteAllItems(m_hwndListView); // // AtlTrace(TEXT("Callback Mask: 0x%lx\n"), ListView_GetCallbackMask(m_hwndListView)); // for (i = 0; i < sizeof(rgFolders)/sizeof(rgFolders[0]) && !bCancel; ++i) { wstring strDescription = LoadResourceString(rgFolders[i].nIDDescription); hr = SHGetFolderLocation(NULL, rgFolders[i].csidl, NULL, 0, &pidl); if (SUCCEEDED(hr)) { try { ListFolder(strDescription.c_str(), NULL, NULL, pidl); } catch(CCancelException* pex) { bCancel = TRUE; pex->Delete(); } catch(CException* pex) { bCancel = TRUE; pex->Delete(); } GetMalloc()->Free(pidl); } } ::SendMessage(m_hwndListView, WM_SETREDRAW, TRUE, 0); return TRUE; } BOOL CProgramList::CaptureSelection( VOID ) { INT iSelected; LVITEM lvi; m_pSelectionInfo = NULL; iSelected = ListView_GetNextItem(m_hwndListView, -1, LVNI_SELECTED); if (iSelected == -1) { return FALSE; } lvi.iItem = iSelected; lvi.iSubItem = 0; lvi.mask = LVIF_PARAM; if (ListView_GetItem(m_hwndListView, &lvi)) { m_pSelectionInfo = (PSHITEMINFO)lvi.lParam; } return m_pSelectionInfo != NULL; } BOOL CProgramList::GetSelectionDetails( INT iInformationClass, VARIANT* pVal ) { CComBSTR bstr; if (m_pSelectionInfo == NULL) { pVal->vt = VT_NULL; return TRUE; } switch(iInformationClass) { case PROGLIST_DISPLAYNAME: bstr = m_pSelectionInfo->strDisplayName.c_str(); break; case PROGLIST_LOCATION: // bstr = m_pSelectionInfo->strFolder.c_str(); break; case PROGLIST_EXENAME: // cracked exe name bstr = m_pSelectionInfo->strPath.c_str(); // break; case PROGLIST_CMDLINE: // complete exe name + parameters bstr = m_pSelectionInfo->strCmdLine.c_str(); break; case PROGLIST_EXECUTABLE: // what we should execute (link or exe, not cracked) bstr = m_pSelectionInfo->strPathExecute.c_str(); break; case PROGLIST_ARGUMENTS: bstr = m_pSelectionInfo->strArgs.c_str(); break; default: pVal->vt = VT_NULL; return TRUE; break; } pVal->vt = VT_BSTR; pVal->bstrVal = bstr.Copy(); return TRUE; } #define PROGLIST_SORT_NONE 0 #define PROGLIST_SORT_ASC 1 #define PROGLIST_SORT_DSC 2 int CALLBACK CProgramList::SHItemInfoCompareFunc( LPARAM lp1, LPARAM lp2, LPARAM lParamSort ) { PSHITEMINFO pInfo1 = (PSHITEMINFO)lp1; PSHITEMINFO pInfo2 = (PSHITEMINFO)lp2; BOOL bEmpty1, bEmpty2; int nColSort = (int)LOWORD(lParamSort); int nSortOrder = (int)HIWORD(lParamSort); int iRet = 0; switch(nColSort) { case 0: // SORT_APPNAME: iRet = _tcsicmp(pInfo1->strDisplayName.c_str(), pInfo2->strDisplayName.c_str()); break; case 1: // SORT_APPLOCATION: iRet = _tcsicmp(pInfo1->strFolder.c_str(), pInfo2->strFolder.c_str()); break; case 2: // SORT_LAYERS: bEmpty1 = pInfo1->strKeys.empty(); bEmpty2 = pInfo2->strKeys.empty(); if (bEmpty1 || bEmpty2) { if (bEmpty1) { iRet = bEmpty2 ? 0 : 1; } else { iRet = bEmpty1 ? 0 : -1; } } else { iRet = _tcsicmp(pInfo1->strKeys.c_str(), pInfo2->strKeys.c_str()); } break; } if (nSortOrder == PROGLIST_SORT_DSC) { iRet = -iRet; } return iRet; } LRESULT CProgramList::LVNotifyColumnClick( LPNMHDR pnmhdr, BOOL& bHandled ) { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pnmhdr; // lpnmlv->iSubItem - this is what we have to sort on // check whether we already have something there HWND hwndHeader = ListView_GetHeader(m_hwndListView); INT nCols; INT i; INT nColSort = lpnmlv->iSubItem; LPARAM lSortParam; // leave high word blank for now LPARAM lSortOrder = PROGLIST_SORT_ASC; HDITEM hdi; // // reset current image - wherever that is // nCols = Header_GetItemCount(hwndHeader); for (i = 0; i < nCols; ++i) { hdi.mask = HDI_BITMAP|HDI_LPARAM|HDI_FORMAT; if (!Header_GetItem(hwndHeader, i, &hdi)) { continue; } if (i == nColSort && (hdi.mask & HDI_LPARAM)) { switch(hdi.lParam) { case PROGLIST_SORT_NONE: case PROGLIST_SORT_DSC: lSortOrder = PROGLIST_SORT_ASC; break; case PROGLIST_SORT_ASC: lSortOrder = PROGLIST_SORT_DSC; break; } } if (hdi.mask & HDI_BITMAP) { DeleteObject((HGDIOBJ)hdi.hbm); } hdi.lParam = PROGLIST_SORT_NONE; hdi.fmt &= ~(HDF_BITMAP|HDF_BITMAP_ON_RIGHT); hdi.mask |= HDI_BITMAP|HDI_LPARAM|HDI_FORMAT; hdi.hbm = NULL; Header_SetItem(hwndHeader, i, &hdi); } lSortParam = MAKELONG(nColSort, lSortOrder); ListView_SortItems(m_hwndListView, (PFNLVCOMPARE)SHItemInfoCompareFunc, lSortParam); // now, load the image please m_hbmSort = (HBITMAP)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(lSortOrder == PROGLIST_SORT_ASC? IDB_SORTUP : IDB_SORTDN), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); hdi.mask = HDI_BITMAP|HDI_LPARAM|HDI_FORMAT; Header_GetItem(hwndHeader, nColSort, &hdi); hdi.mask |= HDI_BITMAP|HDI_FORMAT|HDI_LPARAM; hdi.hbm = m_hbmSort; hdi.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT; hdi.lParam = lSortOrder; Header_SetItem(hwndHeader, nColSort, &hdi); bHandled = TRUE; return 0; } LRESULT CProgramList::LVNotifyDispInfo( LPNMHDR pnmhdr, BOOL& bHandled ) { WCHAR wszPermKeys[MAX_PATH]; DWORD cbSize; LV_ITEM &lvItem = reinterpret_cast(pnmhdr)->item; LV_ITEM lvi; PSHITEMINFO pInfo; lvi.mask = LVIF_PARAM; lvi.iItem = lvItem.iItem; lvi.iSubItem = 0; if (!ListView_GetItem(m_hwndListView, &lvi)) { // bummer, we can't retrieve an item -- if we let it go, things will be worse lvItem.mask &= ~(LVIF_TEXT|LVIF_IMAGE); lvItem.mask |= LVIF_DI_SETITEM; bHandled = TRUE; return 0; } pInfo = reinterpret_cast (lvi.lParam); if (lvItem.mask & LVIF_TEXT) { switch (lvItem.iSubItem) { case 0: lvItem.pszText = (LPTSTR)pInfo->strDisplayName.c_str(); break; case 1: lvItem.pszText = (LPTSTR)pInfo->strFolder.c_str(); break; case 2: // check with SDB cbSize = sizeof(wszPermKeys); if (pInfo->strKeys.empty()) { if (SdbGetPermLayerKeys(pInfo->strPath.c_str(), wszPermKeys, &cbSize, GPLK_ALL)) { pInfo->strKeys = wszPermKeys; } } if (!pInfo->strKeys.empty()) { lvItem.pszText = (LPTSTR)pInfo->strKeys.c_str(); } break; default: break; } } if (lvItem.mask & LVIF_IMAGE) { lvItem.iImage = GetIconFromLink(pInfo->pidl, pInfo->strPathExecute.c_str()); } lvItem.mask |= LVIF_DI_SETITEM; bHandled = TRUE; return 0; } LRESULT CProgramList::LVNotifyGetInfoTip( LPNMHDR pnmhdr, BOOL& bHandled ) { DWORD cbSize; LPNMLVGETINFOTIP pGetInfoTip = (LPNMLVGETINFOTIP)pnmhdr; LV_ITEM lvi; PSHITEMINFO pInfo; lvi.mask = LVIF_PARAM; lvi.iItem = pGetInfoTip->iItem; lvi.iSubItem = 0; if (!ListView_GetItem(m_hwndListView, &lvi)) { // bupkas bHandled = FALSE; return 0; } pInfo = reinterpret_cast (lvi.lParam); // // now we can fiddle // _tcsncpy(pGetInfoTip->pszText, pInfo->strCmdLine.c_str(), pGetInfoTip->cchTextMax); *(pGetInfoTip->pszText + pGetInfoTip->cchTextMax - 1) = TEXT('\0'); bHandled = TRUE; return 0; } LRESULT CProgramList::LVNotifyRClick( LPNMHDR pnmhdr, BOOL& bHandled ) { DWORD dwPos = ::GetMessagePos(); LVHITTESTINFO hti; LV_ITEM lvi; PSHITEMINFO pInfo; HRESULT hr; LPITEMIDLIST pidlItem = NULL; IShellFolder* pFolder = NULL; IContextMenu* pContextMenu = NULL; CMINVOKECOMMANDINFO ici; int nCmd; HMENU hMenu = NULL; UINT idMin, idMax, idCmd; WCHAR szCmdVerb[MAX_PATH]; int nLastSep, i, nLastItem; hti.pt.x = (int) LOWORD (dwPos); hti.pt.y = (int) HIWORD (dwPos); ScreenToClient (m_hwndListView, &hti.pt); ListView_HitTest (m_hwndListView, &hti); if (!(hti.flags & LVHT_ONITEM)) { bHandled = FALSE; return 0; } lvi.mask = LVIF_PARAM; lvi.iItem = hti.iItem; lvi.iSubItem = 0; if (!ListView_GetItem(m_hwndListView, &lvi)) { // bupkas bHandled = FALSE; return 0; } pInfo = reinterpret_cast (lvi.lParam); // // we have an item, show it's context menu then // hr = SHBindToParent(pInfo-> pidl, IID_IShellFolder, (PVOID*)&pFolder, (LPCITEMIDLIST*)&pidlItem); if (!SUCCEEDED(hr)) { goto cleanup; } // get the ui please hr = pFolder->GetUIObjectOf(m_hwndListView, 1, (LPCITEMIDLIST*)&pidlItem, IID_IContextMenu, NULL, (PVOID*)&pContextMenu); if (!SUCCEEDED(hr)) { goto cleanup; } hMenu = CreatePopupMenu(); if (hMenu == NULL) { goto cleanup; } hr = pContextMenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_EXPLORE); if (!SUCCEEDED(hr)) { goto cleanup; } // // sanitize // idMin = 1; idMax = HRESULT_CODE(hr); for (idCmd = 0; idCmd < idMax; ++idCmd) { hr = pContextMenu->GetCommandString(idCmd, GCS_VERBW, NULL, (LPSTR)szCmdVerb, CHARCOUNT(szCmdVerb)); if (SUCCEEDED(hr)) { if (!_wcsicmp(szCmdVerb, TEXT("cut")) || !_wcsicmp(szCmdVerb, TEXT("delete")) || !_wcsicmp(szCmdVerb, TEXT("rename")) || !_wcsicmp(szCmdVerb, TEXT("link"))) { // // not allowed // DeleteMenu(hMenu, idCmd + idMin, MF_BYCOMMAND); } } } // // after doing some basic sanitization against the destructive tendencies -- // nuke double-separators // nLastItem = ::GetMenuItemCount(hMenu) - 1; nLastSep = nLastItem + 1; for (i = nLastItem; i >= 0; --i) { MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_FTYPE; if (GetMenuItemInfo(hMenu, i, TRUE, &mii)) { if (mii.fType & MFT_SEPARATOR) { if (nLastSep == i + 1 || i == 0) { // this sep is dead DeleteMenu(hMenu, i, MF_BYPOSITION); } nLastSep = i; } } } ClientToScreen(m_hwndListView, &hti.pt); nCmd = TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, hti.pt.x, hti.pt.y, 0, m_hwndListView, NULL); // // execute command // if (nCmd) { ici.cbSize = sizeof (CMINVOKECOMMANDINFO); ici.fMask = 0; ici.hwnd = m_hwndListView; ici.lpVerb = MAKEINTRESOURCEA(nCmd - 1); ici.lpParameters = NULL; ici.lpDirectory = NULL; ici.nShow = SW_SHOWNORMAL; ici.dwHotKey = 0; ici.hIcon = NULL; hr = pContextMenu->InvokeCommand(&ici); // // requery perm layer keys -- useless here btw // /* // this code will not work since the call above is always asynchronous // if (SUCCEEDED(hr)) { DWORD cbSize; WCHAR wszPermKeys[MAX_PATH]; cbSize = sizeof(wszPermKeys); if (SdbGetPermLayerKeys(pInfo->strPath.c_str(), wszPermKeys, &cbSize)) { pInfo->strKeys = wszPermKeys; } else { pInfo->strKeys.erase(); } // // set the info into the list box // ListView_SetItemText(m_hwndListView, lvi.iItem, 2, (LPWSTR)pInfo->strKeys.c_str()); } */ } cleanup: if (hMenu) { DestroyMenu(hMenu); } if (pContextMenu) { pContextMenu->Release(); } if (pFolder) { pFolder->Release(); } bHandled = TRUE; return 0; } BOOL CProgramList::UpdateListItem( LPCWSTR pwszPath, LPCWSTR pwszKey ) { // find the item first MAPSTR2ITEM::iterator iter; MULTIMAPSTR2ITEM::iterator iterExe; MULTIMAPSTR2ITEM::iterator iterFirstExe, iterLastExe; tstring strKey = pwszPath; tstring strExeKey; PSHITEMINFO pInfo = NULL; PSHITEMINFO pInfoExe = NULL; // // we need to iterate through all the persisted items // StrUpCase(strKey); iter = m_mapItems.find(strKey); if (iter != m_mapItems.end()) { pInfo = (*iter).second; } if (pInfo == NULL) { return FALSE; } // // once we have found this single item, get the command and // show info for all the other affected items // strExeKey = pInfo->strPath; StrUpCase(strExeKey); iterFirstExe = m_mmapExeItems.lower_bound(strExeKey); iterLastExe = m_mmapExeItems.upper_bound(strExeKey); for (iterExe = iterFirstExe; iterExe != m_mmapExeItems.end() && iterExe != iterLastExe; ++iterExe) { pInfoExe = (*iterExe).second; // find this item in a listview LVFINDINFO lvf; INT index; lvf.flags = LVFI_PARAM; lvf.lParam = (LPARAM)pInfoExe; index = ListView_FindItem(m_hwndListView, -1, &lvf); if (index < 0) { return FALSE; // inconsistent } // else we have both the item and the keys if (pwszKey == NULL) { pInfoExe->strKeys.erase(); } else { pInfoExe->strKeys = pwszKey; } ListView_SetItemText(m_hwndListView, index, 2, (LPWSTR)pInfoExe->strKeys.c_str()); } return TRUE; } BOOL CProgramList::IsEnabled( VOID ) { if (::IsWindow(m_hwndListView)) { return ::IsWindowEnabled(m_hwndListView); } return FALSE; } VOID CProgramList::Enable( BOOL bEnable ) { if (::IsWindow(m_hwndListView)) { ::EnableWindow(m_hwndListView, bEnable); } } BOOL GetProgramListSelection( CProgramList* pProgramList ) { return pProgramList->CaptureSelection(); } BOOL GetProgramListSelectionDetails( CProgramList* pProgramList, INT iInformationClass, VARIANT* pVal ) { return pProgramList->GetSelectionDetails(iInformationClass, pVal); } LRESULT NotifyProgramList( CProgramList* pProgramList, LPNMHDR pnmhdr, BOOL& bHandled ) { LRESULT lRet = 0; switch (pnmhdr->code) { case LVN_GETDISPINFO: lRet = pProgramList->LVNotifyDispInfo(pnmhdr, bHandled); break; case LVN_COLUMNCLICK: lRet = pProgramList->LVNotifyColumnClick(pnmhdr, bHandled); break; case LVN_GETINFOTIP: lRet = pProgramList->LVNotifyGetInfoTip(pnmhdr, bHandled); break; case NM_RCLICK: lRet = pProgramList->LVNotifyRClick(pnmhdr, bHandled); break; default: bHandled = FALSE; break; } return lRet; } BOOL GetProgramListEnabled( CProgramList* pProgramList ) { return pProgramList->IsEnabled(); } VOID EnableProgramList( CProgramList* pProgramList, BOOL bEnable ) { pProgramList->Enable(bEnable); } BOOL UpdateProgramListItem( CProgramList* pProgramList, LPCWSTR pwszPath, LPCWSTR pwszKeys ) { return pProgramList->UpdateListItem(pwszPath, pwszKeys); }