Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2172 lines
52 KiB

  1. /*++
  2. Implements population of a listview control with the content from
  3. the start menu
  4. --*/
  5. #include "stdafx.h"
  6. #include "resource.h"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <shlobj.h>
  10. #include <shlwapi.h>
  11. #include <shellapi.h>
  12. #include <commctrl.h>
  13. #include <msi.h>
  14. #include <sfc.h>
  15. #include "CompatUI.h"
  16. #include "progview.h"
  17. extern "C" {
  18. #include "shimdb.h"
  19. }
  20. #pragma warning(disable:4786)
  21. #include <string>
  22. #include <xstring>
  23. #include <map>
  24. #include <algorithm>
  25. using namespace std;
  26. #ifdef _UNICODE
  27. typedef wstring tstring;
  28. #else
  29. typedef string tstring;
  30. #endif
  31. typedef
  32. INSTALLSTATE (WINAPI*PMsiGetComponentPath)(
  33. LPCTSTR szProduct, // product code for client product
  34. LPCTSTR szComponent, // component ID
  35. LPTSTR lpPathBuf, // returned path
  36. DWORD *pcchBuf // buffer character count
  37. );
  38. typedef
  39. UINT (WINAPI* PMsiGetShortcutTarget)(
  40. LPCTSTR szShortcutTarget, // path to shortcut link file
  41. LPTSTR szProductCode, // fixed length buffer for product code
  42. LPTSTR szFeatureId, // fixed length buffer for feature id
  43. LPTSTR szComponentCode // fixed length buffer for component code
  44. );
  45. typedef enum tagPROGRAMINFOCLASS {
  46. PROGLIST_DISPLAYNAME,
  47. PROGLIST_LOCATION, //
  48. PROGLIST_EXENAME, // cracked exe name
  49. PROGLIST_CMDLINE, // complete exe name + parameters
  50. PROGLIST_EXECUTABLE, // what we should execute (link or exe, not cracked)
  51. PROGLIST_ARGUMENTS // just the args
  52. };
  53. class CException {
  54. public:
  55. CException(LPCSTR lpszFile = NULL, DWORD nLocation = 0) {
  56. SetLocation(lpszFile, nLocation);
  57. }
  58. virtual ~CException() {}
  59. virtual VOID Delete() {
  60. delete this;
  61. }
  62. int __cdecl FormatV(LPCTSTR lpszFormat, va_list arg) {
  63. int nch = 0;
  64. if (lpszFormat) {
  65. nch = _vsntprintf(szDescription, CHARCOUNT(szDescription), lpszFormat, arg);
  66. } else {
  67. *szDescription = TEXT('\0');
  68. }
  69. return nch;
  70. }
  71. int __cdecl Format(LPCTSTR lpszFormat, ...) {
  72. va_list arg;
  73. int nch = 0;
  74. if (lpszFormat) {
  75. va_start(arg, lpszFormat);
  76. nch = _vsntprintf(szDescription, CHARCOUNT(szDescription), lpszFormat, arg);
  77. va_end(arg);
  78. } else {
  79. *szDescription = TEXT('\0');
  80. }
  81. }
  82. VOID SetLocation(LPCSTR lpszFile, DWORD nLocation) {
  83. if (lpszFile) {
  84. strcpy(szLocation, lpszFile);
  85. } else {
  86. *szLocation = TEXT('\0');
  87. }
  88. m_dwLocation = nLocation;
  89. }
  90. TCHAR szDescription[MAX_PATH];
  91. CHAR szLocation[MAX_PATH];
  92. DWORD m_dwLocation;
  93. };
  94. class CMemoryException : public CException {
  95. public:
  96. CMemoryException(LPCSTR lpszFile = NULL, DWORD nLocation = 0) :
  97. CException(lpszFile, nLocation) {}
  98. VOID Delete() {}
  99. };
  100. class CCancelException : public CException {
  101. public:
  102. CCancelException(LPCSTR lpszFile = NULL, DWORD nLocation = 0) :
  103. CException(lpszFile, nLocation){}
  104. };
  105. static CMemoryException _MemoryExceptionStatic;
  106. VOID __cdecl ThrowMemoryException(LPCSTR lpszFile, DWORD nLocation, LPCTSTR lpszFormat = NULL, ...) {
  107. va_list arg;
  108. CMemoryException* pMemoryException = &_MemoryExceptionStatic;
  109. va_start(arg, lpszFormat);
  110. pMemoryException->FormatV(lpszFormat, arg);
  111. va_end(arg);
  112. throw pMemoryException;
  113. }
  114. class CProgramList {
  115. public:
  116. CProgramList(LPMALLOC pMalloc, HWND hwndListView, LPCTSTR szSystemDirectory) :
  117. m_pMalloc(pMalloc),
  118. m_hwndListView(hwndListView),
  119. m_hMSI(NULL),
  120. m_pSelectionInfo(NULL),
  121. m_hbmSort(NULL),
  122. m_pProgView(NULL),
  123. m_hEventCancel(NULL) {
  124. //
  125. // we are always initializing on populate thread
  126. //
  127. m_dwOwnerThreadID = GetCurrentThreadId();
  128. m_strSystemDirectory = szSystemDirectory;
  129. }
  130. ~CProgramList();
  131. BOOL PopulateControl(CProgView* pProgView = NULL, HANDLE hEventCancel = NULL);
  132. LPMALLOC GetMalloc(VOID) {
  133. return GetCurrentThreadId() == m_dwOwnerThreadID ? m_pMalloc : m_pMallocUI;
  134. }
  135. BOOL CaptureSelection();
  136. BOOL GetSelectionDetails(INT iInformationClass, VARIANT* pVal);
  137. LRESULT LVNotifyDispInfo (LPNMHDR pnmhdr, BOOL& bHandled);
  138. LRESULT LVNotifyColumnClick(LPNMHDR pnmhdr, BOOL& bHandled);
  139. LRESULT LVNotifyGetInfoTip (LPNMHDR pnmhdr, BOOL& bHandled);
  140. LRESULT LVNotifyRClick (LPNMHDR pnmhdr, BOOL& bHandled);
  141. BOOL IsEnabled(VOID);
  142. VOID Enable(BOOL);
  143. BOOL UpdateListItem(LPCWSTR pwszPath, LPCWSTR pwszKey);
  144. protected:
  145. BOOL ListFolder(LPCTSTR pszLocationParent, IShellFolder* pFolder, LPCITEMIDLIST pidlFull, LPCITEMIDLIST pidlFolder);
  146. BOOL ListLink(LPCTSTR pszLocationParent, LPCTSTR pszDisplayName, IShellFolder* pFolder, LPCITEMIDLIST pidlFull, LPCITEMIDLIST pidlLink);
  147. BOOL ListMsiLink(LPCTSTR pszLocationParent, LPCTSTR pszDisplayName, LPCTSTR pszMsiPath, IShellFolder* pFolder, LPCITEMIDLIST pidlFull);
  148. LPITEMIDLIST GetNextItemIDL(LPCITEMIDLIST pidl);
  149. UINT GetSizeIDL (LPCITEMIDLIST pidl);
  150. LPITEMIDLIST AppendIDL (LPCITEMIDLIST pidlBase,
  151. LPCITEMIDLIST pidlAdd);
  152. LPITEMIDLIST GetLastItemIDL(LPCITEMIDLIST pidl);
  153. BOOL GetDisplayName(IShellFolder* pFolder, LPCITEMIDLIST pidl, tstring& strDisplay);
  154. BOOL GetPathFromLink(IShellLink* pLink, WIN32_FIND_DATA* pfd, tstring& strPath);
  155. BOOL GetArgumentsFromLink(IShellLink* pLink, tstring& strArgs);
  156. BOOL AddItem(LPCTSTR pszLocation,
  157. LPCTSTR pszDisplayName,
  158. LPCTSTR pszPath,
  159. LPCTSTR pszArguments,
  160. IShellFolder* pFolder,
  161. LPCITEMIDLIST pidlFull,
  162. BOOL bUsePath = FALSE); // true if we should use path for executable
  163. int GetIconFromLink(LPCITEMIDLIST pidlLinkFull, LPCTSTR lpszExePath);
  164. BOOL IsSFCItem(LPCTSTR lpszItem);
  165. BOOL IsItemInSystemDirectory(LPCTSTR pszPath);
  166. private:
  167. LPMALLOC m_pMalloc;
  168. LPMALLOC m_pMallocUI;
  169. HWND m_hwndListView; // list view control
  170. HBITMAP m_hbmSort;
  171. typedef struct tagSHITEMINFO {
  172. tstring strDisplayName; // descriptive name
  173. tstring strFolder; // containing folder
  174. tstring strPath; // actual exe, cracked
  175. tstring strPathExecute; // link path (this is what we will execute)
  176. tstring strCmdLine; // command line (cracked link)
  177. tstring strArgs;
  178. tstring strKeys;
  179. LPITEMIDLIST pidl; // full pidl
  180. } SHITEMINFO, *PSHITEMINFO;
  181. static CALLBACK SHItemInfoCompareFunc(LPARAM lp1, LPARAM lp2, LPARAM lParamSort);
  182. typedef map< tstring, PSHITEMINFO, less<tstring> > MAPSTR2ITEM;
  183. typedef multimap< tstring, PSHITEMINFO > MULTIMAPSTR2ITEM;
  184. //
  185. // store key->item sequence, the keys are cmdlines (with args)
  186. //
  187. MAPSTR2ITEM m_mapItems;
  188. //
  189. // store key->item sequence, where the key is exe name (path)
  190. //
  191. MULTIMAPSTR2ITEM m_mmapExeItems;
  192. //
  193. // selected item
  194. //
  195. PSHITEMINFO m_pSelectionInfo;
  196. //
  197. // cached msi.dll handle
  198. //
  199. HMODULE m_hMSI;
  200. PMsiGetComponentPath m_pfnGetComponentPath;
  201. PMsiGetShortcutTarget m_pfnGetShortcutTarget;
  202. //
  203. // cached system directory
  204. //
  205. tstring m_strSystemDirectory;
  206. //
  207. // image list used to show icons
  208. //
  209. HIMAGELIST m_hImageList;
  210. //
  211. // optional pointer to the parent view
  212. //
  213. CProgView* m_pProgView;
  214. //
  215. // event that we use to signal the end of scan
  216. //
  217. HANDLE m_hEventCancel;
  218. //
  219. // owner thread
  220. //
  221. DWORD m_dwOwnerThreadID;
  222. VOID CheckForCancel() {
  223. if (m_hEventCancel) {
  224. if (::WaitForSingleObject(m_hEventCancel, 0) != WAIT_TIMEOUT) {
  225. // cancelled!!!
  226. throw new CCancelException();
  227. }
  228. }
  229. }
  230. };
  231. //
  232. // in upload.cpp
  233. //
  234. wstring StrUpCase(wstring& wstr);
  235. //
  236. // load the string from resources
  237. //
  238. wstring LoadResourceString(UINT nID)
  239. {
  240. LPTSTR lpszBuffer = NULL;
  241. int cch;
  242. wstring str;
  243. cch = ::LoadString(_Module.GetModuleInstance(), nID, (LPTSTR)&lpszBuffer, 0);
  244. //
  245. // hack! this must work (I know it does)
  246. //
  247. if (cch && NULL != lpszBuffer) {
  248. str = wstring(lpszBuffer, cch);
  249. }
  250. return str;
  251. }
  252. /////////////////////////////////////////////////////////////////////////////////////////////////
  253. //
  254. // Utility functions
  255. //
  256. BOOL
  257. InitializeProgramList(
  258. CProgramList** ppProgramList,
  259. HWND hwndListView
  260. )
  261. {
  262. HRESULT hr;
  263. BOOL bSuccess = FALSE;
  264. LPMALLOC pMalloc = NULL;
  265. TCHAR szSystemWindowsDirectory[MAX_PATH];
  266. CProgramList* pProgramList = NULL;
  267. UINT uSize;
  268. hr = SHGetMalloc(&pMalloc);
  269. if (!SUCCEEDED(hr)) {
  270. goto ErrHandle;
  271. }
  272. uSize = ::GetSystemWindowsDirectory(szSystemWindowsDirectory,
  273. CHARCOUNT(szSystemWindowsDirectory));
  274. if (uSize == 0 || uSize > CHARCOUNT(szSystemWindowsDirectory)) {
  275. goto ErrHandle;
  276. }
  277. pProgramList = new CProgramList(pMalloc, hwndListView, szSystemWindowsDirectory);
  278. if (NULL == pProgramList) {
  279. goto ErrHandle;
  280. }
  281. *ppProgramList = pProgramList;
  282. bSuccess = TRUE;
  283. ErrHandle:
  284. if (!bSuccess) {
  285. if (NULL != pMalloc) {
  286. pMalloc->Release();
  287. }
  288. if (NULL != pProgramList) {
  289. delete pProgramList;
  290. }
  291. }
  292. return bSuccess;
  293. }
  294. BOOL
  295. CleanupProgramList(
  296. CProgramList* pProgramList
  297. )
  298. {
  299. LPMALLOC pMalloc;
  300. if (NULL == pProgramList) {
  301. return FALSE;
  302. }
  303. pMalloc = pProgramList->GetMalloc();
  304. delete pProgramList;
  305. if (NULL != pMalloc) {
  306. pMalloc->Release();
  307. }
  308. return TRUE;
  309. }
  310. BOOL
  311. PopulateProgramList(
  312. CProgramList* pProgramList,
  313. CProgView* pProgView,
  314. HANDLE hEventCancel
  315. )
  316. {
  317. return pProgramList->PopulateControl(pProgView, hEventCancel);
  318. }
  319. CProgramList::~CProgramList()
  320. {
  321. //
  322. //
  323. //
  324. MAPSTR2ITEM::iterator iter;
  325. iter = m_mapItems.begin();
  326. while (iter != m_mapItems.end()) {
  327. PSHITEMINFO pInfo = (*iter).second;
  328. GetMalloc()->Free(pInfo->pidl); // nuke this please
  329. delete pInfo;
  330. ++iter;
  331. }
  332. if (NULL != m_hbmSort) {
  333. DeleteObject(m_hbmSort);
  334. }
  335. // Image list is destroyed automatically when the control is destroyed
  336. //
  337. // if (NULL != m_hImageList) {
  338. // ImageList_Destroy(m_hImageList);
  339. // }
  340. if (NULL != m_hMSI && (HMODULE)-1 != m_hMSI) {
  341. FreeLibrary(m_hMSI);
  342. }
  343. }
  344. BOOL
  345. CProgramList::GetDisplayName(
  346. IShellFolder* pFolder,
  347. LPCITEMIDLIST pidl,
  348. tstring& strDisplayName
  349. )
  350. {
  351. STRRET strName;
  352. HRESULT hr;
  353. LPTSTR pszName = NULL;
  354. hr = pFolder->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strName);
  355. if (!SUCCEEDED(hr)) {
  356. return FALSE;
  357. }
  358. hr = StrRetToStr(&strName, pidl, &pszName);
  359. if (!SUCCEEDED(hr)) {
  360. return FALSE;
  361. }
  362. // if we have been successful, assign return result
  363. if (pszName != NULL) {
  364. strDisplayName = pszName;
  365. CoTaskMemFree(pszName);
  366. } else {
  367. strDisplayName.erase();
  368. }
  369. return TRUE;
  370. }
  371. BOOL
  372. CProgramList::GetPathFromLink(
  373. IShellLink* pLink,
  374. WIN32_FIND_DATA* pfd,
  375. tstring& strPath
  376. )
  377. {
  378. TCHAR szPath[MAX_PATH];
  379. HRESULT hr;
  380. hr = pLink->GetPath(szPath, sizeof(szPath)/sizeof(szPath[0]), pfd, 0);
  381. if (hr == S_OK) {
  382. strPath = szPath;
  383. }
  384. return hr == S_OK;
  385. }
  386. BOOL
  387. CProgramList::GetArgumentsFromLink(
  388. IShellLink* pLink,
  389. tstring& strArgs
  390. )
  391. {
  392. TCHAR szArgs[INFOTIPSIZE];
  393. HRESULT hr = pLink->GetArguments(szArgs, sizeof(szArgs)/sizeof(szArgs[0]));
  394. if (SUCCEEDED(hr)) {
  395. strArgs = szArgs;
  396. }
  397. return SUCCEEDED(hr);
  398. }
  399. LPITEMIDLIST
  400. CProgramList::GetNextItemIDL(
  401. LPCITEMIDLIST pidl
  402. )
  403. {
  404. // Check for valid pidl.
  405. if (pidl == NULL) {
  406. return NULL;
  407. }
  408. // Get the size of the specified item identifier.
  409. int cb = pidl->mkid.cb;
  410. // If the size is zero, it is the end of the list.
  411. if (cb == 0) {
  412. return NULL;
  413. }
  414. // Add cb to pidl (casting to increment by bytes).
  415. pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb);
  416. // Return NULL if it is null-terminating, or a pidl otherwise.
  417. return (pidl->mkid.cb == 0) ? NULL : (LPITEMIDLIST) pidl;
  418. }
  419. LPITEMIDLIST
  420. CProgramList::GetLastItemIDL(
  421. LPCITEMIDLIST pidl
  422. )
  423. {
  424. LPITEMIDLIST pidlLast = (LPITEMIDLIST)pidl;
  425. if (pidl == NULL) {
  426. return NULL;
  427. }
  428. int cb = pidl->mkid.cb;
  429. if (cb == 0) {
  430. return NULL;
  431. }
  432. do {
  433. pidl = GetNextItemIDL(pidlLast);
  434. if (pidl != NULL) {
  435. pidlLast = (LPITEMIDLIST)pidl;
  436. }
  437. } while (pidl != NULL);
  438. return pidlLast;
  439. }
  440. UINT
  441. CProgramList::GetSizeIDL(
  442. LPCITEMIDLIST pidl
  443. )
  444. {
  445. UINT cbTotal = 0;
  446. if (pidl)
  447. {
  448. cbTotal += sizeof(pidl->mkid.cb); // Null terminator
  449. while (NULL != pidl)
  450. {
  451. cbTotal += pidl->mkid.cb;
  452. pidl = GetNextItemIDL(pidl);
  453. }
  454. }
  455. return cbTotal;
  456. }
  457. LPITEMIDLIST
  458. CProgramList::AppendIDL(
  459. LPCITEMIDLIST pidlBase,
  460. LPCITEMIDLIST pidlAdd
  461. )
  462. {
  463. if (NULL == pidlBase && NULL == pidlAdd) {
  464. return NULL;
  465. }
  466. LPITEMIDLIST pidlNew, pidlAlloc;
  467. UINT cb1 = pidlBase ? GetSizeIDL(pidlBase) : 0;
  468. UINT cb2 = pidlAdd ? GetSizeIDL(pidlAdd) : 0;
  469. UINT size = cb1 + cb2;
  470. pidlAlloc =
  471. pidlNew = (LPITEMIDLIST)GetMalloc()->Alloc(size);
  472. if (pidlNew)
  473. {
  474. if (NULL != pidlBase) {
  475. cb1 = pidlAdd ? cb1 - sizeof(pidlBase->mkid.cb) : cb1;
  476. RtlMoveMemory(pidlNew, pidlBase, cb1);
  477. pidlNew = (LPITEMIDLIST)((PBYTE)pidlNew + cb1);
  478. }
  479. if (NULL != pidlAdd) {
  480. RtlMoveMemory(pidlNew, pidlAdd, cb2);
  481. }
  482. }
  483. return pidlAlloc;
  484. }
  485. BOOL
  486. CProgramList::ListMsiLink(
  487. LPCTSTR pszLocationParent,
  488. LPCTSTR pszDisplayName,
  489. LPCTSTR pszMsiPath,
  490. IShellFolder* pFolder,
  491. LPCITEMIDLIST pidlFull
  492. )
  493. {
  494. //
  495. // make sure we have msi module handle
  496. //
  497. if (NULL == m_hMSI) {
  498. m_hMSI = LoadLibrary(TEXT("msi.dll"));
  499. if (NULL == m_hMSI) {
  500. m_hMSI = (HMODULE)-1;
  501. return FALSE;
  502. }
  503. #ifdef _UNICODE
  504. m_pfnGetComponentPath = (PMsiGetComponentPath )GetProcAddress(m_hMSI, "MsiGetComponentPathW");
  505. m_pfnGetShortcutTarget = (PMsiGetShortcutTarget)GetProcAddress(m_hMSI, "MsiGetShortcutTargetW");
  506. #else
  507. m_pfnGetComponentPath = (PMsiGetComponentPath )GetProcAddress(m_hMSI, "MsiGetComponentPathA");
  508. m_pfnGetShortcutTarget = (PMsiGetShortcutTarget)GetProcAddress(m_hMSI, "MsiGetShortcutTargetA");
  509. #endif
  510. if (m_pfnGetComponentPath == NULL || m_pfnGetShortcutTarget == NULL) {
  511. FreeLibrary(m_hMSI);
  512. m_hMSI = (HMODULE)-1;
  513. return FALSE;
  514. }
  515. } else if (m_hMSI == (HMODULE)-1) {
  516. return FALSE;
  517. }
  518. UINT ErrCode;
  519. TCHAR szProduct[MAX_PATH];
  520. TCHAR szFeatureId[MAX_PATH];
  521. TCHAR szComponentCode[MAX_PATH];
  522. ErrCode = m_pfnGetShortcutTarget(pszMsiPath, szProduct, szFeatureId, szComponentCode);
  523. if (ERROR_SUCCESS != ErrCode) {
  524. return FALSE;
  525. }
  526. INSTALLSTATE is;
  527. TCHAR szPath[MAX_PATH];
  528. DWORD cchPath = sizeof(szPath)/sizeof(szPath[0]);
  529. *szPath = 0;
  530. is = m_pfnGetComponentPath(szProduct, szComponentCode, szPath, &cchPath);
  531. if (INSTALLSTATE_LOCAL == is) {
  532. //
  533. // add this item
  534. //
  535. return AddItem(pszLocationParent,
  536. pszDisplayName,
  537. szPath,
  538. NULL,
  539. pFolder,
  540. pidlFull,
  541. TRUE);
  542. }
  543. return FALSE;
  544. }
  545. int
  546. CProgramList::GetIconFromLink(
  547. LPCITEMIDLIST pidlLinkFull,
  548. LPCTSTR lpszExePath
  549. )
  550. {
  551. HRESULT hr;
  552. IShellFolder* pFolder = NULL;
  553. IExtractIcon* pExtractIcon = NULL;
  554. INT iIconIndex = 0;
  555. UINT uFlags = 0;
  556. LPCITEMIDLIST pidlLink = 0;
  557. HICON hIconLarge = NULL;
  558. HICON hIconSmall = NULL;
  559. UINT nIconSize;
  560. int ImageIndex = -1;
  561. UINT uiErrorMode;
  562. DWORD dwAttributes;
  563. TCHAR szIconFile[MAX_PATH];
  564. *szIconFile = TEXT('\0');
  565. uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  566. hr = SHBindToParent(pidlLinkFull, IID_IShellFolder, (PVOID*)&pFolder, &pidlLink);
  567. if (!SUCCEEDED(hr)) {
  568. goto trySysImage;
  569. }
  570. // get the ui please
  571. hr = pFolder->GetUIObjectOf(m_hwndListView, 1, (LPCITEMIDLIST*)&pidlLink, IID_IExtractIcon, NULL, (PVOID*)&pExtractIcon);
  572. if (!SUCCEEDED(hr)) {
  573. goto trySysImage;
  574. }
  575. hr = pExtractIcon->GetIconLocation(0,
  576. szIconFile,
  577. sizeof(szIconFile) / sizeof(szIconFile[0]),
  578. &iIconIndex,
  579. &uFlags);
  580. if (!SUCCEEDED(hr)) {
  581. goto trySysImage;
  582. }
  583. if (*szIconFile == TEXT('*')) { // this is batch or some such, don't bother
  584. goto trySysImage;
  585. }
  586. //
  587. // before doing an extract, check whether it's available
  588. //
  589. dwAttributes = GetFileAttributes(szIconFile);
  590. if (dwAttributes == (DWORD)-1) {
  591. goto trySysImage;
  592. }
  593. nIconSize = MAKELONG(0, ::GetSystemMetrics(SM_CXSMICON));
  594. //
  595. // this call is likely to produce a popup, beware of that
  596. //
  597. hr = pExtractIcon->Extract(szIconFile,
  598. iIconIndex,
  599. &hIconLarge,
  600. &hIconSmall,
  601. nIconSize);
  602. //
  603. // if hIconSmall was retrieved - we were successful
  604. //
  605. trySysImage:
  606. if (hIconSmall == NULL) {
  607. //
  608. // woops -- we could not extract an icon -- what a bummer
  609. // use shell api then
  610. SHFILEINFO FileInfo;
  611. HIMAGELIST hImageSys;
  612. hImageSys = (HIMAGELIST)SHGetFileInfo(lpszExePath,
  613. 0,
  614. &FileInfo, sizeof(FileInfo),
  615. SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX);
  616. if (hImageSys) {
  617. hIconSmall = ImageList_GetIcon(hImageSys, FileInfo.iIcon, ILD_TRANSPARENT);
  618. }
  619. }
  620. //
  621. // now that we have an icon, we can add it to our image list ?
  622. //
  623. if (hIconSmall != NULL) {
  624. ImageIndex = ImageList_AddIcon(m_hImageList, hIconSmall);
  625. }
  626. ///////////////////////// cleanup ///////////////////////////////////////////
  627. SetErrorMode(uiErrorMode);
  628. if (hIconSmall) {
  629. DestroyIcon(hIconSmall);
  630. }
  631. if (hIconLarge) {
  632. DestroyIcon(hIconLarge);
  633. }
  634. if (pExtractIcon != NULL) {
  635. pExtractIcon->Release();
  636. }
  637. if (pFolder != NULL) {
  638. pFolder->Release();
  639. }
  640. return ImageIndex;
  641. }
  642. BOOL
  643. CProgramList::ListLink(
  644. LPCTSTR pszLocationParent,
  645. LPCTSTR pszDisplayName,
  646. IShellFolder* pFolder,
  647. LPCITEMIDLIST pidlFull,
  648. LPCITEMIDLIST pidlLink
  649. )
  650. {
  651. IShellLink* psl = NULL;
  652. WIN32_FIND_DATA wfd;
  653. HRESULT hr;
  654. BOOL bSuccess = FALSE;
  655. tstring strPath;
  656. tstring strArgs;
  657. CComBSTR bstr;
  658. LPCTSTR pszArgs = NULL;
  659. IPersistFile* ipf = NULL;
  660. IShellLinkDataList* pdl;
  661. DWORD dwFlags;
  662. BOOL bMsiLink = FALSE;
  663. //
  664. // check whether we need to cancel
  665. //
  666. CheckForCancel();
  667. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  668. IID_IShellLink, (LPVOID*)&psl);
  669. if (!SUCCEEDED(hr)) {
  670. return FALSE; // we can't create link object
  671. }
  672. hr = psl->SetIDList(pidlFull); // set the id list
  673. if (!SUCCEEDED(hr)) {
  674. goto out;
  675. }
  676. //
  677. // now the shell link is ready to rumble
  678. //
  679. if (!GetPathFromLink(psl, &wfd, strPath)) {
  680. goto out;
  681. }
  682. // now let's see what is inside of this link -- shall we?
  683. hr = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ipf);
  684. if (!SUCCEEDED(hr)) {
  685. goto out;
  686. }
  687. bstr = strPath.c_str();
  688. hr = ipf->Load(bstr, STGM_READ);
  689. if (SUCCEEDED(hr)) {
  690. //
  691. // resolve the link for now
  692. //
  693. // hr = psl->Resolve(NULL, SLR_NO_UI|SLR_NOUPDATE);
  694. hr = psl->QueryInterface(IID_IShellLinkDataList, (LPVOID*)&pdl);
  695. if (SUCCEEDED(hr)) {
  696. hr = pdl->GetFlags(&dwFlags);
  697. bMsiLink = SUCCEEDED(hr) && (dwFlags & SLDF_HAS_DARWINID);
  698. pdl->Release();
  699. }
  700. if (bMsiLink) {
  701. bSuccess = ListMsiLink(pszLocationParent, pszDisplayName, strPath.c_str(), pFolder, pidlFull);
  702. } else {
  703. //
  704. // we now get the path from the link -- and that's that
  705. //
  706. if (GetPathFromLink(psl, &wfd, strPath)) {
  707. if (GetArgumentsFromLink(psl, strArgs)) {
  708. pszArgs = strArgs.c_str();
  709. }
  710. //
  711. // add this to our list view
  712. //
  713. bSuccess = AddItem(pszLocationParent,
  714. pszDisplayName,
  715. strPath.c_str(),
  716. pszArgs,
  717. pFolder,
  718. pidlFull);
  719. }
  720. }
  721. }
  722. if (NULL != ipf) {
  723. ipf->Release();
  724. }
  725. out:
  726. if (NULL != psl) {
  727. psl->Release();
  728. }
  729. return bSuccess;
  730. }
  731. BOOL
  732. CProgramList::ListFolder(
  733. LPCTSTR pszLocation, // ui string - where is this folder located?
  734. IShellFolder* pParent, // parent folder
  735. LPCITEMIDLIST pidlFull, // idl of the full path to the folder
  736. LPCITEMIDLIST pidlFolder // idl of this folder relative to the pidlFull
  737. )
  738. {
  739. LPENUMIDLIST penum = NULL;
  740. LPITEMIDLIST pidl = NULL;
  741. HRESULT hr;
  742. ULONG celtFetched;
  743. ULONG uAttr;
  744. tstring strDisplayNameLocation;
  745. tstring strDisplayName;
  746. IShellFolder* pFolder = NULL;
  747. BOOL bDesktop = FALSE;
  748. BOOL bCancel = FALSE;
  749. CCancelException* pCancelException = NULL;
  750. CheckForCancel();
  751. if (pParent == NULL) {
  752. hr = SHGetDesktopFolder(&pParent);
  753. bDesktop = TRUE;
  754. }
  755. hr = pParent->BindToObject(pidlFolder,
  756. NULL,
  757. IID_IShellFolder,
  758. (LPVOID *) &pFolder);
  759. if (NULL == pszLocation) {
  760. GetDisplayName(pParent, pidlFolder, strDisplayNameLocation);
  761. } else {
  762. strDisplayNameLocation = pszLocation;
  763. }
  764. if (bDesktop) {
  765. pParent->Release();
  766. }
  767. if (!SUCCEEDED(hr)) {
  768. return FALSE;
  769. }
  770. hr = pFolder->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penum);
  771. if (!SUCCEEDED(hr)) {
  772. pFolder->Release(); // free the folder- - and go away
  773. return FALSE;
  774. }
  775. while( (hr = penum->Next(1,&pidl, &celtFetched)) == S_OK && celtFetched == 1 && !bCancel) {
  776. LPITEMIDLIST pidlCur;
  777. if (pidlFull == NULL) {
  778. pidlFull = pidlFolder;
  779. }
  780. pidlCur = AppendIDL(pidlFull, pidl);
  781. // get the display name of this item
  782. GetDisplayName(pFolder, pidl, strDisplayName);
  783. uAttr = SFGAO_FOLDER | SFGAO_LINK;
  784. hr = pFolder->GetAttributesOf(1, (LPCITEMIDLIST *) &pidl, &uAttr);
  785. if (SUCCEEDED(hr)) {
  786. try {
  787. if (uAttr & SFGAO_FOLDER) {
  788. //
  789. // dump folder recursively
  790. //
  791. ListFolder(strDisplayName.c_str(), pFolder, pidlCur, pidl);
  792. } else if (uAttr & SFGAO_LINK) {
  793. ListLink(strDisplayNameLocation.c_str(), strDisplayName.c_str(), pFolder, pidlCur, pidl);
  794. } else if (uAttr & SFGAO_FILESYSTEM) {
  795. //
  796. // this item is a file
  797. //
  798. AddItem(strDisplayNameLocation.c_str(),
  799. strDisplayName.c_str(),
  800. NULL,
  801. NULL,
  802. pFolder,
  803. pidlCur,
  804. TRUE);
  805. }
  806. } catch(CCancelException* pex) {
  807. //
  808. // we need to cancel -- we shall cleanup and do what we need, then re-throw
  809. //
  810. bCancel = TRUE;
  811. pCancelException = pex;
  812. }
  813. }
  814. GetMalloc()->Free(pidlCur);
  815. GetMalloc()->Free(pidl);
  816. }
  817. if (NULL != penum) {
  818. penum->Release();
  819. }
  820. if (NULL != pFolder) {
  821. pFolder->Release();
  822. }
  823. if (bCancel && pCancelException) {
  824. throw pCancelException;
  825. }
  826. return TRUE;
  827. }
  828. BOOL
  829. CProgramList::IsSFCItem(
  830. LPCTSTR pszPath
  831. )
  832. {
  833. #ifndef _UNICODE
  834. WCHAR wszBuffer[1024];
  835. mbstowcs(wszBuffer, pszPath, sizeof(wszBuffer)/sizeof(wszBuffer[0]));
  836. return SfcIsFileProtected(NULL, wszBuffer);
  837. #else
  838. return SfcIsFileProtected(NULL, pszPath);
  839. #endif
  840. }
  841. BOOL
  842. CProgramList::IsItemInSystemDirectory(
  843. LPCTSTR pszPath
  844. )
  845. {
  846. TCHAR szCommonPath[MAX_PATH];
  847. int nch;
  848. string s;
  849. nch = PathCommonPrefix(m_strSystemDirectory.c_str(), pszPath, szCommonPath);
  850. return nch == m_strSystemDirectory.length();
  851. }
  852. BOOL
  853. ValidateExecutableFile(
  854. LPCTSTR pszPath,
  855. BOOL bValidateFileExists
  856. )
  857. {
  858. LPTSTR rgExt[] = {
  859. TEXT("EXE"),
  860. TEXT("BAT"),
  861. TEXT("CMD"),
  862. TEXT("PIF"),
  863. TEXT("COM"),
  864. TEXT("LNK")
  865. };
  866. LPTSTR pExt;
  867. int i;
  868. BOOL bValidatedExt = FALSE;
  869. pExt = PathFindExtension(pszPath);
  870. if (pExt == NULL || *pExt == TEXT('\0')) {
  871. return FALSE;
  872. }
  873. ++pExt;
  874. for (i = 0; i < sizeof(rgExt)/sizeof(rgExt[0]) && !bValidatedExt; ++i) {
  875. bValidatedExt = !_tcsicmp(pExt, rgExt[i]);
  876. }
  877. if (!bValidatedExt) {
  878. return FALSE;
  879. }
  880. return bValidateFileExists ? PathFileExists(pszPath) : TRUE;
  881. }
  882. BOOL
  883. CProgramList::AddItem(
  884. LPCTSTR pszLocation,
  885. LPCTSTR pszDisplayName,
  886. LPCTSTR pszPath,
  887. LPCTSTR pszArguments,
  888. IShellFolder* pFolder,
  889. LPCITEMIDLIST pidlFull,
  890. BOOL bUsePath
  891. )
  892. {
  893. //
  894. // first test -- is this one of the types we like?
  895. //
  896. LPTSTR pchSlash;
  897. LPTSTR pchDot;
  898. LPTSTR rgExt[] = { TEXT("EXE"), TEXT("BAT"), TEXT("CMD"), TEXT("PIF"), TEXT("COM"), TEXT("LNK") };
  899. BOOL bValidatedExt = FALSE;
  900. BOOL bSuccess = FALSE;
  901. PSHITEMINFO pInfo = NULL;
  902. MAPSTR2ITEM::iterator Iter;
  903. TCHAR szPathExecute[MAX_PATH];
  904. tstring strKey;
  905. tstring strKeyExe;
  906. DWORD dwBinaryType = 0;
  907. LVITEM lvi;
  908. int ix;
  909. //
  910. // check for cancelling the search
  911. //
  912. CheckForCancel();
  913. if (NULL == pszPath) {
  914. pszPath = szPathExecute;
  915. if (!SHGetPathFromIDList(pidlFull, szPathExecute)) {
  916. goto out;
  917. }
  918. }
  919. if (pszDisplayName && m_pProgView) {
  920. m_pProgView->UpdatePopulateStatus(pszDisplayName, pszPath);
  921. }
  922. pchSlash = _tcsrchr(pszPath, TEXT('\\'));
  923. pchDot = _tcsrchr(pszPath, TEXT('.'));
  924. if (NULL != pchSlash) {
  925. if ((ULONG_PTR)pchDot < (ULONG_PTR)pchSlash) {
  926. pchDot = NULL;
  927. }
  928. }
  929. if (NULL != pchDot) {
  930. ++pchDot;
  931. for (int i = 0; i < sizeof(rgExt)/sizeof(rgExt[0]) && !bValidatedExt; ++i) {
  932. bValidatedExt = !_tcsicmp(pchDot, rgExt[i]);
  933. }
  934. }
  935. if (!bValidatedExt) {
  936. goto out;
  937. }
  938. //
  939. // Checks whether the item is in system directory or SFC-protected
  940. //
  941. #if 0
  942. if (IsItemInSystemDirectory(pszPath) || IsSFCItem(pszPath)) {
  943. goto out;
  944. }
  945. #endif
  946. //
  947. // GetBinaryTypeW excludes exes on the basis of binary type
  948. //
  949. if (GetBinaryType(pszPath, &dwBinaryType) &&
  950. dwBinaryType == SCS_64BIT_BINARY) {
  951. goto out;
  952. }
  953. if (IsSFCItem(pszPath)) {
  954. goto out;
  955. }
  956. //
  957. // this is multimap key
  958. //
  959. strKeyExe = StrUpCase(wstring(pszPath));
  960. //
  961. // check whether this has been excluded
  962. //
  963. if (m_pProgView->IsFileExcluded(strKeyExe.c_str())) {
  964. goto out;
  965. }
  966. //
  967. // now compose the key string
  968. //
  969. strKey = strKeyExe;
  970. if (NULL != pszArguments) {
  971. strKey.append(TEXT(" "));
  972. strKey.append(pszArguments);
  973. }
  974. //
  975. // now check whether this item has already been listed
  976. //
  977. Iter = m_mapItems.find(strKey);
  978. if (Iter != m_mapItems.end()) { // found a duplicate
  979. goto out;
  980. }
  981. //
  982. // now please add this item to the list view
  983. //
  984. pInfo = new CProgramList::SHITEMINFO;
  985. if (pInfo == NULL) {
  986. ThrowMemoryException(__FILE__, __LINE__, TEXT("%s\n"), TEXT("Failed to allocate Item Information structure"));
  987. }
  988. pInfo->strDisplayName = pszDisplayName;
  989. pInfo->strFolder = pszLocation;
  990. pInfo->strPath = pszPath;
  991. pInfo->strCmdLine = strKey;
  992. if (NULL != pszArguments) {
  993. pInfo->strArgs = pszArguments;
  994. }
  995. pInfo->pidl = AppendIDL(NULL, pidlFull);
  996. if (bUsePath) {
  997. pInfo->strPathExecute = pszPath;
  998. } else {
  999. // finally, what are we going to launch ?
  1000. if (SHGetPathFromIDList(pidlFull, szPathExecute)) {
  1001. pInfo->strPathExecute = szPathExecute;
  1002. }
  1003. }
  1004. m_mapItems[strKey] = pInfo;
  1005. m_mmapExeItems.insert(MULTIMAPSTR2ITEM::value_type(strKeyExe, pInfo));
  1006. ATLTRACE(TEXT("Adding item %s %s %s\n"), pszDisplayName, pszLocation, pszPath);
  1007. lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_IMAGE;
  1008. lvi.iItem = ListView_GetItemCount(m_hwndListView); // append at the end please
  1009. lvi.iSubItem = 0;
  1010. lvi.pszText = LPSTR_TEXTCALLBACK;
  1011. lvi.iImage = I_IMAGECALLBACK;
  1012. lvi.lParam = (LPARAM)pInfo;
  1013. ix = ListView_InsertItem(m_hwndListView, &lvi);
  1014. lvi.mask = LVIF_TEXT;
  1015. lvi.iItem = ix;
  1016. lvi.iSubItem = 1;
  1017. lvi.pszText = LPSTR_TEXTCALLBACK;
  1018. ListView_SetItem(m_hwndListView, &lvi);
  1019. bSuccess = TRUE;
  1020. out:
  1021. return bSuccess;
  1022. }
  1023. BOOL
  1024. CProgramList::PopulateControl(
  1025. CProgView* pProgView,
  1026. HANDLE hevtCancel
  1027. )
  1028. {
  1029. int i;
  1030. HRESULT hr;
  1031. LPITEMIDLIST pidl;
  1032. BOOL bCancel = FALSE;
  1033. struct {
  1034. INT csidl;
  1035. UINT nIDDescription;
  1036. } rgFolders[] = {
  1037. { CSIDL_DESKTOPDIRECTORY, IDS_DESKTOP },
  1038. { CSIDL_COMMON_STARTMENU, IDS_COMMON_STARTMENU },
  1039. { CSIDL_STARTMENU, IDS_STARTMENU },
  1040. { CSIDL_COMMON_PROGRAMS, IDS_COMMON_PROGRAMS },
  1041. { CSIDL_PROGRAMS, IDS_PROGRAMS }
  1042. };
  1043. //
  1044. // set the progview object pointer so we could update the status
  1045. //
  1046. m_pProgView = pProgView;
  1047. m_pMallocUI = pProgView->m_pMallocUI;
  1048. //
  1049. // set the event so that we could cancel the scan
  1050. //
  1051. m_hEventCancel = hevtCancel;
  1052. //
  1053. // set extended style
  1054. //
  1055. ListView_SetExtendedListViewStyleEx(m_hwndListView,
  1056. LVS_EX_INFOTIP|LVS_EX_LABELTIP,
  1057. LVS_EX_INFOTIP|LVS_EX_LABELTIP);
  1058. //
  1059. // fix columns
  1060. //
  1061. LVCOLUMN lvc;
  1062. RECT rc;
  1063. SIZE_T cxProgName;
  1064. SIZE_T cx;
  1065. wstring strCaption;
  1066. lvc.mask = LVCF_WIDTH;
  1067. if (!ListView_GetColumn(m_hwndListView, 2, &lvc)) {
  1068. ::GetClientRect(m_hwndListView, &rc);
  1069. cx = rc.right - rc.left -
  1070. ::GetSystemMetrics(SM_CXVSCROLL) -
  1071. ::GetSystemMetrics(SM_CXEDGE) -
  1072. ::GetSystemMetrics(SM_CXSIZEFRAME);
  1073. cxProgName = cx * 3 / 5;
  1074. strCaption = LoadResourceString(IDS_PROGRAMNAME);
  1075. lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT;
  1076. lvc.pszText = (LPTSTR)strCaption.c_str();
  1077. lvc.fmt = LVCFMT_LEFT;
  1078. lvc.cx = cxProgName;
  1079. lvc.iSubItem= 0;
  1080. ListView_InsertColumn(m_hwndListView, 0, &lvc);
  1081. cx -= cxProgName;
  1082. cxProgName = cx / 2;
  1083. strCaption = LoadResourceString(IDS_FOLDER);
  1084. lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;
  1085. lvc.pszText = (LPTSTR)strCaption.c_str();
  1086. lvc.fmt = LVCFMT_LEFT;
  1087. lvc.cx = cxProgName;
  1088. lvc.iSubItem= 1;
  1089. ListView_InsertColumn(m_hwndListView, 1, &lvc);
  1090. strCaption = LoadResourceString(IDS_SETTINGS);
  1091. lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;
  1092. lvc.pszText = (LPTSTR)strCaption.c_str();
  1093. lvc.fmt = LVCFMT_LEFT;
  1094. lvc.cx = cx - cxProgName;
  1095. lvc.iSubItem= 2;
  1096. ListView_InsertColumn(m_hwndListView, 2, &lvc);
  1097. }
  1098. HDC hDC = GetDC(m_hwndListView);
  1099. int nBitsPixel = ::GetDeviceCaps(hDC, BITSPIXEL);
  1100. int nPlanes = ::GetDeviceCaps(hDC, PLANES);
  1101. UINT flags;
  1102. nBitsPixel *= nPlanes;
  1103. if (nBitsPixel < 4) {
  1104. flags = ILC_COLOR;
  1105. } else if (nBitsPixel < 8) {
  1106. flags = ILC_COLOR4;
  1107. } else if (nBitsPixel < 16) {
  1108. flags = ILC_COLOR8;
  1109. } else if (nBitsPixel < 24) {
  1110. flags = ILC_COLOR16;
  1111. } else if (nBitsPixel < 32) {
  1112. flags = ILC_COLOR24;
  1113. } else if (nBitsPixel == 32) {
  1114. flags = ILC_COLOR32;
  1115. } else {
  1116. flags = ILC_COLORDDB;
  1117. }
  1118. flags |= ILC_MASK;
  1119. ReleaseDC(m_hwndListView, hDC);
  1120. m_hImageList = ImageList_Create(::GetSystemMetrics(SM_CXSMICON),
  1121. ::GetSystemMetrics(SM_CYSMICON),
  1122. flags,
  1123. 10,
  1124. 25);
  1125. if (m_hImageList == NULL) {
  1126. ATLTRACE(TEXT("Image List creation failure, error 0x%lx\n"), GetLastError());
  1127. }
  1128. ImageList_SetBkColor(m_hImageList, CLR_NONE);
  1129. ListView_SetImageList(m_hwndListView, m_hImageList, LVSIL_SMALL);
  1130. ::SendMessage(m_hwndListView, WM_SETREDRAW, FALSE, 0);
  1131. ListView_DeleteAllItems(m_hwndListView);
  1132. //
  1133. // AtlTrace(TEXT("Callback Mask: 0x%lx\n"), ListView_GetCallbackMask(m_hwndListView));
  1134. //
  1135. for (i = 0; i < sizeof(rgFolders)/sizeof(rgFolders[0]) && !bCancel; ++i) {
  1136. wstring strDescription = LoadResourceString(rgFolders[i].nIDDescription);
  1137. hr = SHGetFolderLocation(NULL, rgFolders[i].csidl, NULL, 0, &pidl);
  1138. if (SUCCEEDED(hr)) {
  1139. try {
  1140. ListFolder(strDescription.c_str(), NULL, NULL, pidl);
  1141. } catch(CCancelException* pex) {
  1142. bCancel = TRUE;
  1143. pex->Delete();
  1144. } catch(CException* pex) {
  1145. bCancel = TRUE;
  1146. pex->Delete();
  1147. }
  1148. GetMalloc()->Free(pidl);
  1149. }
  1150. }
  1151. ::SendMessage(m_hwndListView, WM_SETREDRAW, TRUE, 0);
  1152. return TRUE;
  1153. }
  1154. BOOL
  1155. CProgramList::CaptureSelection(
  1156. VOID
  1157. )
  1158. {
  1159. INT iSelected;
  1160. LVITEM lvi;
  1161. m_pSelectionInfo = NULL;
  1162. iSelected = ListView_GetNextItem(m_hwndListView, -1, LVNI_SELECTED);
  1163. if (iSelected == -1) {
  1164. return FALSE;
  1165. }
  1166. lvi.iItem = iSelected;
  1167. lvi.iSubItem = 0;
  1168. lvi.mask = LVIF_PARAM;
  1169. if (ListView_GetItem(m_hwndListView, &lvi)) {
  1170. m_pSelectionInfo = (PSHITEMINFO)lvi.lParam;
  1171. }
  1172. return m_pSelectionInfo != NULL;
  1173. }
  1174. BOOL
  1175. CProgramList::GetSelectionDetails(
  1176. INT iInformationClass,
  1177. VARIANT* pVal
  1178. )
  1179. {
  1180. CComBSTR bstr;
  1181. if (m_pSelectionInfo == NULL) {
  1182. pVal->vt = VT_NULL;
  1183. return TRUE;
  1184. }
  1185. switch(iInformationClass) {
  1186. case PROGLIST_DISPLAYNAME:
  1187. bstr = m_pSelectionInfo->strDisplayName.c_str();
  1188. break;
  1189. case PROGLIST_LOCATION: //
  1190. bstr = m_pSelectionInfo->strFolder.c_str();
  1191. break;
  1192. case PROGLIST_EXENAME: // cracked exe name
  1193. bstr = m_pSelectionInfo->strPath.c_str(); //
  1194. break;
  1195. case PROGLIST_CMDLINE: // complete exe name + parameters
  1196. bstr = m_pSelectionInfo->strCmdLine.c_str();
  1197. break;
  1198. case PROGLIST_EXECUTABLE: // what we should execute (link or exe, not cracked)
  1199. bstr = m_pSelectionInfo->strPathExecute.c_str();
  1200. break;
  1201. case PROGLIST_ARGUMENTS:
  1202. bstr = m_pSelectionInfo->strArgs.c_str();
  1203. break;
  1204. default:
  1205. pVal->vt = VT_NULL;
  1206. return TRUE;
  1207. break;
  1208. }
  1209. pVal->vt = VT_BSTR;
  1210. pVal->bstrVal = bstr.Copy();
  1211. return TRUE;
  1212. }
  1213. #define PROGLIST_SORT_NONE 0
  1214. #define PROGLIST_SORT_ASC 1
  1215. #define PROGLIST_SORT_DSC 2
  1216. int CALLBACK
  1217. CProgramList::SHItemInfoCompareFunc(
  1218. LPARAM lp1,
  1219. LPARAM lp2,
  1220. LPARAM lParamSort
  1221. )
  1222. {
  1223. PSHITEMINFO pInfo1 = (PSHITEMINFO)lp1;
  1224. PSHITEMINFO pInfo2 = (PSHITEMINFO)lp2;
  1225. BOOL bEmpty1, bEmpty2;
  1226. int nColSort = (int)LOWORD(lParamSort);
  1227. int nSortOrder = (int)HIWORD(lParamSort);
  1228. int iRet = 0;
  1229. switch(nColSort) {
  1230. case 0: // SORT_APPNAME:
  1231. iRet = _tcsicmp(pInfo1->strDisplayName.c_str(),
  1232. pInfo2->strDisplayName.c_str());
  1233. break;
  1234. case 1: // SORT_APPLOCATION:
  1235. iRet = _tcsicmp(pInfo1->strFolder.c_str(),
  1236. pInfo2->strFolder.c_str());
  1237. break;
  1238. case 2: // SORT_LAYERS:
  1239. bEmpty1 = pInfo1->strKeys.empty();
  1240. bEmpty2 = pInfo2->strKeys.empty();
  1241. if (bEmpty1 || bEmpty2) {
  1242. if (bEmpty1) {
  1243. iRet = bEmpty2 ? 0 : 1;
  1244. } else {
  1245. iRet = bEmpty1 ? 0 : -1;
  1246. }
  1247. } else {
  1248. iRet = _tcsicmp(pInfo1->strKeys.c_str(),
  1249. pInfo2->strKeys.c_str());
  1250. }
  1251. break;
  1252. }
  1253. if (nSortOrder == PROGLIST_SORT_DSC) {
  1254. iRet = -iRet;
  1255. }
  1256. return iRet;
  1257. }
  1258. LRESULT
  1259. CProgramList::LVNotifyColumnClick(
  1260. LPNMHDR pnmhdr,
  1261. BOOL& bHandled
  1262. )
  1263. {
  1264. LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pnmhdr;
  1265. // lpnmlv->iSubItem - this is what we have to sort on
  1266. // check whether we already have something there
  1267. HWND hwndHeader = ListView_GetHeader(m_hwndListView);
  1268. INT nCols;
  1269. INT i;
  1270. INT nColSort = lpnmlv->iSubItem;
  1271. LPARAM lSortParam; // leave high word blank for now
  1272. LPARAM lSortOrder = PROGLIST_SORT_ASC;
  1273. HDITEM hdi;
  1274. //
  1275. // reset current image - wherever that is
  1276. //
  1277. nCols = Header_GetItemCount(hwndHeader);
  1278. for (i = 0; i < nCols; ++i) {
  1279. hdi.mask = HDI_BITMAP|HDI_LPARAM|HDI_FORMAT;
  1280. if (!Header_GetItem(hwndHeader, i, &hdi)) {
  1281. continue;
  1282. }
  1283. if (i == nColSort && (hdi.mask & HDI_LPARAM)) {
  1284. switch(hdi.lParam) {
  1285. case PROGLIST_SORT_NONE:
  1286. case PROGLIST_SORT_DSC:
  1287. lSortOrder = PROGLIST_SORT_ASC;
  1288. break;
  1289. case PROGLIST_SORT_ASC:
  1290. lSortOrder = PROGLIST_SORT_DSC;
  1291. break;
  1292. }
  1293. }
  1294. if (hdi.mask & HDI_BITMAP) {
  1295. DeleteObject((HGDIOBJ)hdi.hbm);
  1296. }
  1297. hdi.lParam = PROGLIST_SORT_NONE;
  1298. hdi.fmt &= ~(HDF_BITMAP|HDF_BITMAP_ON_RIGHT);
  1299. hdi.mask |= HDI_BITMAP|HDI_LPARAM|HDI_FORMAT;
  1300. hdi.hbm = NULL;
  1301. Header_SetItem(hwndHeader, i, &hdi);
  1302. }
  1303. lSortParam = MAKELONG(nColSort, lSortOrder);
  1304. ListView_SortItems(m_hwndListView, (PFNLVCOMPARE)SHItemInfoCompareFunc, lSortParam);
  1305. // now, load the image please
  1306. m_hbmSort = (HBITMAP)::LoadImage(_Module.GetResourceInstance(),
  1307. MAKEINTRESOURCE(lSortOrder == PROGLIST_SORT_ASC? IDB_SORTUP : IDB_SORTDN),
  1308. IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
  1309. hdi.mask = HDI_BITMAP|HDI_LPARAM|HDI_FORMAT;
  1310. Header_GetItem(hwndHeader, nColSort, &hdi);
  1311. hdi.mask |= HDI_BITMAP|HDI_FORMAT|HDI_LPARAM;
  1312. hdi.hbm = m_hbmSort;
  1313. hdi.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT;
  1314. hdi.lParam = lSortOrder;
  1315. Header_SetItem(hwndHeader, nColSort, &hdi);
  1316. bHandled = TRUE;
  1317. return 0;
  1318. }
  1319. LRESULT
  1320. CProgramList::LVNotifyDispInfo(
  1321. LPNMHDR pnmhdr,
  1322. BOOL& bHandled
  1323. )
  1324. {
  1325. WCHAR wszPermKeys[MAX_PATH];
  1326. DWORD cbSize;
  1327. LV_ITEM &lvItem = reinterpret_cast<LV_DISPINFO*>(pnmhdr)->item;
  1328. LV_ITEM lvi;
  1329. PSHITEMINFO pInfo;
  1330. lvi.mask = LVIF_PARAM;
  1331. lvi.iItem = lvItem.iItem;
  1332. lvi.iSubItem = 0;
  1333. if (!ListView_GetItem(m_hwndListView, &lvi)) {
  1334. // bummer, we can't retrieve an item -- if we let it go, things will be worse
  1335. lvItem.mask &= ~(LVIF_TEXT|LVIF_IMAGE);
  1336. lvItem.mask |= LVIF_DI_SETITEM;
  1337. bHandled = TRUE;
  1338. return 0;
  1339. }
  1340. pInfo = reinterpret_cast<PSHITEMINFO> (lvi.lParam);
  1341. if (lvItem.mask & LVIF_TEXT) {
  1342. switch (lvItem.iSubItem) {
  1343. case 0:
  1344. lvItem.pszText = (LPTSTR)pInfo->strDisplayName.c_str();
  1345. break;
  1346. case 1:
  1347. lvItem.pszText = (LPTSTR)pInfo->strFolder.c_str();
  1348. break;
  1349. case 2:
  1350. // check with SDB
  1351. cbSize = sizeof(wszPermKeys);
  1352. if (pInfo->strKeys.empty()) {
  1353. if (SdbGetPermLayerKeys(pInfo->strPath.c_str(), wszPermKeys, &cbSize, GPLK_ALL)) {
  1354. pInfo->strKeys = wszPermKeys;
  1355. }
  1356. }
  1357. if (!pInfo->strKeys.empty()) {
  1358. lvItem.pszText = (LPTSTR)pInfo->strKeys.c_str();
  1359. }
  1360. break;
  1361. default:
  1362. break;
  1363. }
  1364. }
  1365. if (lvItem.mask & LVIF_IMAGE) {
  1366. lvItem.iImage = GetIconFromLink(pInfo->pidl, pInfo->strPathExecute.c_str());
  1367. }
  1368. lvItem.mask |= LVIF_DI_SETITEM;
  1369. bHandled = TRUE;
  1370. return 0;
  1371. }
  1372. LRESULT
  1373. CProgramList::LVNotifyGetInfoTip(
  1374. LPNMHDR pnmhdr,
  1375. BOOL& bHandled
  1376. )
  1377. {
  1378. DWORD cbSize;
  1379. LPNMLVGETINFOTIP pGetInfoTip = (LPNMLVGETINFOTIP)pnmhdr;
  1380. LV_ITEM lvi;
  1381. PSHITEMINFO pInfo;
  1382. lvi.mask = LVIF_PARAM;
  1383. lvi.iItem = pGetInfoTip->iItem;
  1384. lvi.iSubItem = 0;
  1385. if (!ListView_GetItem(m_hwndListView, &lvi)) {
  1386. // bupkas
  1387. bHandled = FALSE;
  1388. return 0;
  1389. }
  1390. pInfo = reinterpret_cast<PSHITEMINFO> (lvi.lParam);
  1391. //
  1392. // now we can fiddle
  1393. //
  1394. _tcsncpy(pGetInfoTip->pszText, pInfo->strCmdLine.c_str(), pGetInfoTip->cchTextMax);
  1395. *(pGetInfoTip->pszText + pGetInfoTip->cchTextMax - 1) = TEXT('\0');
  1396. bHandled = TRUE;
  1397. return 0;
  1398. }
  1399. LRESULT
  1400. CProgramList::LVNotifyRClick(
  1401. LPNMHDR pnmhdr,
  1402. BOOL& bHandled
  1403. )
  1404. {
  1405. DWORD dwPos = ::GetMessagePos();
  1406. LVHITTESTINFO hti;
  1407. LV_ITEM lvi;
  1408. PSHITEMINFO pInfo;
  1409. HRESULT hr;
  1410. LPITEMIDLIST pidlItem = NULL;
  1411. IShellFolder* pFolder = NULL;
  1412. IContextMenu* pContextMenu = NULL;
  1413. CMINVOKECOMMANDINFO ici;
  1414. int nCmd;
  1415. HMENU hMenu = NULL;
  1416. UINT idMin, idMax, idCmd;
  1417. WCHAR szCmdVerb[MAX_PATH];
  1418. int nLastSep, i, nLastItem;
  1419. hti.pt.x = (int) LOWORD (dwPos);
  1420. hti.pt.y = (int) HIWORD (dwPos);
  1421. ScreenToClient (m_hwndListView, &hti.pt);
  1422. ListView_HitTest (m_hwndListView, &hti);
  1423. if (!(hti.flags & LVHT_ONITEM)) {
  1424. bHandled = FALSE;
  1425. return 0;
  1426. }
  1427. lvi.mask = LVIF_PARAM;
  1428. lvi.iItem = hti.iItem;
  1429. lvi.iSubItem = 0;
  1430. if (!ListView_GetItem(m_hwndListView, &lvi)) {
  1431. // bupkas
  1432. bHandled = FALSE;
  1433. return 0;
  1434. }
  1435. pInfo = reinterpret_cast<PSHITEMINFO> (lvi.lParam);
  1436. //
  1437. // we have an item, show it's context menu then
  1438. //
  1439. hr = SHBindToParent(pInfo-> pidl, IID_IShellFolder, (PVOID*)&pFolder, (LPCITEMIDLIST*)&pidlItem);
  1440. if (!SUCCEEDED(hr)) {
  1441. goto cleanup;
  1442. }
  1443. // get the ui please
  1444. hr = pFolder->GetUIObjectOf(m_hwndListView, 1, (LPCITEMIDLIST*)&pidlItem, IID_IContextMenu, NULL, (PVOID*)&pContextMenu);
  1445. if (!SUCCEEDED(hr)) {
  1446. goto cleanup;
  1447. }
  1448. hMenu = CreatePopupMenu();
  1449. if (hMenu == NULL) {
  1450. goto cleanup;
  1451. }
  1452. hr = pContextMenu->QueryContextMenu(hMenu,
  1453. 0,
  1454. 1,
  1455. 0x7FFF,
  1456. CMF_EXPLORE);
  1457. if (!SUCCEEDED(hr)) {
  1458. goto cleanup;
  1459. }
  1460. //
  1461. // sanitize
  1462. //
  1463. idMin = 1;
  1464. idMax = HRESULT_CODE(hr);
  1465. for (idCmd = 0; idCmd < idMax; ++idCmd) {
  1466. hr = pContextMenu->GetCommandString(idCmd, GCS_VERBW, NULL, (LPSTR)szCmdVerb, CHARCOUNT(szCmdVerb));
  1467. if (SUCCEEDED(hr)) {
  1468. if (!_wcsicmp(szCmdVerb, TEXT("cut")) ||
  1469. !_wcsicmp(szCmdVerb, TEXT("delete")) ||
  1470. !_wcsicmp(szCmdVerb, TEXT("rename")) ||
  1471. !_wcsicmp(szCmdVerb, TEXT("link"))) {
  1472. //
  1473. // not allowed
  1474. //
  1475. DeleteMenu(hMenu, idCmd + idMin, MF_BYCOMMAND);
  1476. }
  1477. }
  1478. }
  1479. //
  1480. // after doing some basic sanitization against the destructive tendencies --
  1481. // nuke double-separators
  1482. //
  1483. nLastItem = ::GetMenuItemCount(hMenu) - 1;
  1484. nLastSep = nLastItem + 1;
  1485. for (i = nLastItem; i >= 0; --i) {
  1486. MENUITEMINFO mii;
  1487. mii.cbSize = sizeof(mii);
  1488. mii.fMask = MIIM_FTYPE;
  1489. if (GetMenuItemInfo(hMenu, i, TRUE, &mii)) {
  1490. if (mii.fType & MFT_SEPARATOR) {
  1491. if (nLastSep == i + 1 || i == 0) {
  1492. // this sep is dead
  1493. DeleteMenu(hMenu, i, MF_BYPOSITION);
  1494. }
  1495. nLastSep = i;
  1496. }
  1497. }
  1498. }
  1499. ClientToScreen(m_hwndListView, &hti.pt);
  1500. nCmd = TrackPopupMenu(hMenu,
  1501. TPM_LEFTALIGN |
  1502. TPM_LEFTBUTTON |
  1503. TPM_RIGHTBUTTON |
  1504. TPM_RETURNCMD,
  1505. hti.pt.x, hti.pt.y,
  1506. 0,
  1507. m_hwndListView,
  1508. NULL);
  1509. //
  1510. // execute command
  1511. //
  1512. if (nCmd) {
  1513. ici.cbSize = sizeof (CMINVOKECOMMANDINFO);
  1514. ici.fMask = 0;
  1515. ici.hwnd = m_hwndListView;
  1516. ici.lpVerb = MAKEINTRESOURCEA(nCmd - 1);
  1517. ici.lpParameters = NULL;
  1518. ici.lpDirectory = NULL;
  1519. ici.nShow = SW_SHOWNORMAL;
  1520. ici.dwHotKey = 0;
  1521. ici.hIcon = NULL;
  1522. hr = pContextMenu->InvokeCommand(&ici);
  1523. //
  1524. // requery perm layer keys -- useless here btw
  1525. //
  1526. /* // this code will not work since the call above is always asynchronous
  1527. //
  1528. if (SUCCEEDED(hr)) {
  1529. DWORD cbSize;
  1530. WCHAR wszPermKeys[MAX_PATH];
  1531. cbSize = sizeof(wszPermKeys);
  1532. if (SdbGetPermLayerKeys(pInfo->strPath.c_str(), wszPermKeys, &cbSize)) {
  1533. pInfo->strKeys = wszPermKeys;
  1534. } else {
  1535. pInfo->strKeys.erase();
  1536. }
  1537. //
  1538. // set the info into the list box
  1539. //
  1540. ListView_SetItemText(m_hwndListView, lvi.iItem, 2, (LPWSTR)pInfo->strKeys.c_str());
  1541. }
  1542. */
  1543. }
  1544. cleanup:
  1545. if (hMenu) {
  1546. DestroyMenu(hMenu);
  1547. }
  1548. if (pContextMenu) {
  1549. pContextMenu->Release();
  1550. }
  1551. if (pFolder) {
  1552. pFolder->Release();
  1553. }
  1554. bHandled = TRUE;
  1555. return 0;
  1556. }
  1557. BOOL
  1558. CProgramList::UpdateListItem(
  1559. LPCWSTR pwszPath,
  1560. LPCWSTR pwszKey
  1561. )
  1562. {
  1563. // find the item first
  1564. MAPSTR2ITEM::iterator iter;
  1565. MULTIMAPSTR2ITEM::iterator iterExe;
  1566. MULTIMAPSTR2ITEM::iterator iterFirstExe, iterLastExe;
  1567. tstring strKey = pwszPath;
  1568. tstring strExeKey;
  1569. PSHITEMINFO pInfo = NULL;
  1570. PSHITEMINFO pInfoExe = NULL;
  1571. //
  1572. // we need to iterate through all the persisted items
  1573. //
  1574. StrUpCase(strKey);
  1575. iter = m_mapItems.find(strKey);
  1576. if (iter != m_mapItems.end()) {
  1577. pInfo = (*iter).second;
  1578. }
  1579. if (pInfo == NULL) {
  1580. return FALSE;
  1581. }
  1582. //
  1583. // once we have found this single item, get the command and
  1584. // show info for all the other affected items
  1585. //
  1586. strExeKey = pInfo->strPath;
  1587. StrUpCase(strExeKey);
  1588. iterFirstExe = m_mmapExeItems.lower_bound(strExeKey);
  1589. iterLastExe = m_mmapExeItems.upper_bound(strExeKey);
  1590. for (iterExe = iterFirstExe; iterExe != m_mmapExeItems.end() && iterExe != iterLastExe; ++iterExe) {
  1591. pInfoExe = (*iterExe).second;
  1592. // find this item in a listview
  1593. LVFINDINFO lvf;
  1594. INT index;
  1595. lvf.flags = LVFI_PARAM;
  1596. lvf.lParam = (LPARAM)pInfoExe;
  1597. index = ListView_FindItem(m_hwndListView, -1, &lvf);
  1598. if (index < 0) {
  1599. return FALSE; // inconsistent
  1600. }
  1601. // else we have both the item and the keys
  1602. if (pwszKey == NULL) {
  1603. pInfoExe->strKeys.erase();
  1604. } else {
  1605. pInfoExe->strKeys = pwszKey;
  1606. }
  1607. ListView_SetItemText(m_hwndListView, index, 2, (LPWSTR)pInfoExe->strKeys.c_str());
  1608. }
  1609. return TRUE;
  1610. }
  1611. BOOL
  1612. CProgramList::IsEnabled(
  1613. VOID
  1614. )
  1615. {
  1616. if (::IsWindow(m_hwndListView)) {
  1617. return ::IsWindowEnabled(m_hwndListView);
  1618. }
  1619. return FALSE;
  1620. }
  1621. VOID
  1622. CProgramList::Enable(
  1623. BOOL bEnable
  1624. )
  1625. {
  1626. if (::IsWindow(m_hwndListView)) {
  1627. ::EnableWindow(m_hwndListView, bEnable);
  1628. }
  1629. }
  1630. BOOL
  1631. GetProgramListSelection(
  1632. CProgramList* pProgramList
  1633. )
  1634. {
  1635. return pProgramList->CaptureSelection();
  1636. }
  1637. BOOL
  1638. GetProgramListSelectionDetails(
  1639. CProgramList* pProgramList,
  1640. INT iInformationClass,
  1641. VARIANT* pVal
  1642. )
  1643. {
  1644. return pProgramList->GetSelectionDetails(iInformationClass, pVal);
  1645. }
  1646. LRESULT
  1647. NotifyProgramList(
  1648. CProgramList* pProgramList,
  1649. LPNMHDR pnmhdr,
  1650. BOOL& bHandled
  1651. )
  1652. {
  1653. LRESULT lRet = 0;
  1654. switch (pnmhdr->code) {
  1655. case LVN_GETDISPINFO:
  1656. lRet = pProgramList->LVNotifyDispInfo(pnmhdr, bHandled);
  1657. break;
  1658. case LVN_COLUMNCLICK:
  1659. lRet = pProgramList->LVNotifyColumnClick(pnmhdr, bHandled);
  1660. break;
  1661. case LVN_GETINFOTIP:
  1662. lRet = pProgramList->LVNotifyGetInfoTip(pnmhdr, bHandled);
  1663. break;
  1664. case NM_RCLICK:
  1665. lRet = pProgramList->LVNotifyRClick(pnmhdr, bHandled);
  1666. break;
  1667. default:
  1668. bHandled = FALSE;
  1669. break;
  1670. }
  1671. return lRet;
  1672. }
  1673. BOOL
  1674. GetProgramListEnabled(
  1675. CProgramList* pProgramList
  1676. )
  1677. {
  1678. return pProgramList->IsEnabled();
  1679. }
  1680. VOID
  1681. EnableProgramList(
  1682. CProgramList* pProgramList,
  1683. BOOL bEnable
  1684. )
  1685. {
  1686. pProgramList->Enable(bEnable);
  1687. }
  1688. BOOL
  1689. UpdateProgramListItem(
  1690. CProgramList* pProgramList,
  1691. LPCWSTR pwszPath,
  1692. LPCWSTR pwszKeys
  1693. )
  1694. {
  1695. return pProgramList->UpdateListItem(pwszPath, pwszKeys);
  1696. }