|
|
/*++
Implements population of a listview control with the content from the start menu
--*/
#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
#include <stdlib.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <shellapi.h>
#include <commctrl.h>
#include <msi.h>
#include <sfc.h>
#include "CompatUI.h"
#include "progview.h"
extern "C" { #include "shimdb.h"
}
#pragma warning(disable:4786)
#include <string>
#include <xstring>
#include <map>
#include <algorithm>
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<tstring> > 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<LV_DISPINFO*>(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<PSHITEMINFO> (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<PSHITEMINFO> (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<PSHITEMINFO> (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);
}
|