XTShellListBase.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:23k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // XTShellListBase.cpp : implementation file
  2. //
  3. // This file is a part of the XTREME CONTROLS MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Resource.h"
  22. #include "Common/XTPVC80Helpers.h"  // Visual Studio 2005 helper functions
  23. #include "Common/XTPResourceManager.h"
  24. #include "XTDefines.h"
  25. #include "XTVC50Helpers.h"
  26. #include "XTFunctions.h"
  27. #include "XTHeaderCtrl.h"
  28. #include "XTListCtrlView.h"
  29. #include "XTShellPidl.h"
  30. #include "XTShellSettings.h"
  31. #include "XTDirWatcher.h"
  32. #include "XTShellListBase.h"
  33. #include "XTSortClass.h"
  34. #ifdef _DEBUG
  35. #define new DEBUG_NEW
  36. #undef THIS_FILE
  37. static char THIS_FILE[] = __FILE__;
  38. #endif
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CXTShellListBase
  41. CXTShellListBase::CXTShellListBase()
  42. : m_pDirThread(0)
  43. {
  44. m_bContextMenu = TRUE;
  45. m_uFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
  46. if (m_shSettings.ShowAllFiles() && !m_shSettings.ShowSysFiles())
  47. {
  48. m_uFlags |= SHCONTF_INCLUDEHIDDEN;
  49. }
  50. if (!SUCCEEDED(::SHGetSpecialFolderLocation(NULL, CSIDL_INTERNET, &m_pidlINet)))
  51. {
  52. m_pidlINet = NULL;
  53. }
  54. m_nNameColumnWidth = 150;
  55. m_lpsfFolder = NULL;
  56. }
  57. CXTShellListBase::~CXTShellListBase()
  58. {
  59. // End the directory monitoring thread.
  60. if (m_pDirThread)
  61. {
  62. m_pDirThread->StopNotifications();
  63. m_pDirThread = NULL;
  64. }
  65. if (m_pidlINet)
  66. {
  67. CShellMalloc lpMalloc;
  68. lpMalloc.Free(m_pidlINet);
  69. }
  70. SAFE_RELEASE(m_lpsfFolder);
  71. }
  72. /////////////////////////////////////////////////////////////////////////////
  73. // CXTShellListBase message handlers
  74. BOOL CXTShellListBase::PopulateListView(XT_TVITEMDATA* lptvid, LPSHELLFOLDER lpsf)
  75. {
  76. // Turn off redraw so the user does't see resorting
  77. m_pListCtrl->SetRedraw(false);
  78. //clear the view for new items
  79. m_pListCtrl->DeleteAllItems();
  80. SAFE_RELEASE(m_lpsfFolder);
  81. if (InitListViewItems(lptvid, lpsf))
  82. {
  83. SortList((m_nSortedCol > -1) ? m_nSortedCol : 0,
  84. (m_nSortedCol > -1) ? m_bAscending : 1);
  85. // create the directory monitoring thread.
  86. if (m_pDirThread == NULL)
  87. {
  88. m_pDirThread = (CXTDirWatcher*)AfxBeginThread(RUNTIME_CLASS(CXTDirWatcher),
  89. THREAD_PRIORITY_LOWEST, 0, CREATE_SUSPENDED, NULL);
  90. m_pDirThread->SetFolderData(m_pListCtrl, lptvid);
  91. m_pDirThread->ResumeThread();
  92. }
  93. // if the folder changed, update the folder data.
  94. else
  95. {
  96. TCHAR szFolderPath[_MAX_PATH];
  97. if (::SHGetPathFromIDList(lptvid->lpifq, szFolderPath))
  98. {
  99. CString strFolderPath = m_pDirThread->GetFolderPath();
  100. if (strFolderPath.CompareNoCase(szFolderPath) != 0)
  101. {
  102. m_pDirThread->SuspendThread();
  103. m_pDirThread->SetFolderData(m_pListCtrl, lptvid);
  104. m_pDirThread->ResumeThread();
  105. }
  106. }
  107. }
  108. m_lpsfFolder = lpsf;
  109. m_lpsfFolder->AddRef();
  110. m_pListCtrl->SetRedraw(true);
  111. return TRUE;
  112. }
  113. m_pListCtrl->SetRedraw(true);
  114. return FALSE;
  115. }
  116. void CXTShellListBase::BuildDefaultColumns()
  117. {
  118. CString strLabel;
  119. VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_NAME));
  120. m_pListCtrl->InsertColumn(0, strLabel, LVCFMT_LEFT, m_nNameColumnWidth, 0);
  121. VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_SIZE));
  122. m_pListCtrl->InsertColumn(1, strLabel, LVCFMT_RIGHT, 100, 1);
  123. VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_TYPE));
  124. m_pListCtrl->InsertColumn(2, strLabel, LVCFMT_LEFT, 120, 2);
  125. VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_MODIFIED));
  126. m_pListCtrl->InsertColumn(3, strLabel, LVCFMT_LEFT, 120, 3);
  127. }
  128. BOOL CXTShellListBase::InitSystemImageLists()
  129. {
  130. HIMAGELIST himlSmall = GetSystemImageList(SHGFI_SMALLICON);
  131. HIMAGELIST himlLarge = GetSystemImageList(SHGFI_LARGEICON);
  132. if (himlSmall && himlLarge)
  133. {
  134. ListView_SetImageList(m_pListCtrl->GetSafeHwnd(), himlSmall, LVSIL_SMALL);
  135. ListView_SetImageList(m_pListCtrl->GetSafeHwnd(), himlLarge, LVSIL_NORMAL);
  136. return TRUE;
  137. }
  138. return FALSE;
  139. }
  140. BOOL CXTShellListBase::IsItemFiltered(LPCTSTR lpszItemName, ULONG ulItemAttrs)
  141. {
  142. if (ulItemAttrs & SFGAO_FOLDER)
  143. return FALSE;
  144. if (!m_csIncludeEXT.IsEmpty())
  145. {
  146. TCHAR szDrive[_MAX_DRIVE];
  147. TCHAR szDir[_MAX_DIR];
  148. TCHAR szFileName[_MAX_FNAME];
  149. TCHAR szExt[_MAX_EXT];
  150. SPLITPATH_S(lpszItemName, szDrive, szDir, szFileName, szExt);
  151. if (_tcsclen(szExt) == 0)
  152. return m_csIncludeEXT.Find(_T("*.;")) == -1;
  153. return m_csIncludeEXT.Find(szExt) == -1;
  154. }
  155. return FALSE;
  156. }
  157. BOOL CXTShellListBase::InitListViewItems(XT_TVITEMDATA* lptvid, LPSHELLFOLDER lpsf)
  158. {
  159. CShellMalloc lpMalloc;
  160. if (!lpMalloc)
  161. return FALSE;
  162. LPENUMIDLIST lpe = NULL;
  163. if (FAILED(lpsf->EnumObjects(::GetParent(m_pListCtrl->m_hWnd), m_uFlags, &lpe)))
  164. return FALSE;
  165. int          iCtr = 0;
  166. ULONG        ulFetched = 0;
  167. LPITEMIDLIST lpi = NULL;
  168. while (lpe->Next(1, &lpi, &ulFetched) == S_OK)
  169. {
  170. // Now get the friendly name that we'll put in the treeview...
  171. CString szFileName, szFullFilePath;
  172. GetName(lpsf, lpi, SHGDN_NORMAL, szFileName);
  173. GetName(lpsf, lpi, SHGDN_FORPARSING, szFullFilePath);
  174. // Note that since we are interested in the display attributes as well as
  175. // the other attributes, we need to set ulAttrs to SFGAO_DISPLAYATTRMASK
  176. // before calling GetAttributesOf();
  177. ULONG ulAttrs = SFGAO_DISPLAYATTRMASK | SFGAO_REMOVABLE;
  178. UINT  uFlags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
  179. lpsf->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lpi, &ulAttrs);
  180. BOOL bIncludeFile = !IsItemFiltered(szFullFilePath, ulAttrs);
  181. if (bIncludeFile)
  182. {
  183. // allocate memory for ITEMDATA struct
  184. XT_LVITEMDATA* lplvid = new XT_LVITEMDATA;
  185. if (lplvid == NULL)
  186. {
  187. if (lpe)
  188. {
  189. lpe->Release();
  190. }
  191. return FALSE;
  192. }
  193. lplvid->ulAttribs = ulAttrs;
  194. LPITEMIDLIST lpifqThisItem = ConcatPidls(lpMalloc, lptvid->lpifq, lpi);
  195. LV_ITEM lvi;
  196. lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  197. lvi.iItem = iCtr++;
  198. lvi.iSubItem = 0;
  199. lvi.pszText = (LPTSTR)(LPCTSTR)szFileName;
  200. lvi.cchTextMax = 0;
  201. lvi.iImage = GetItemIcon(lpifqThisItem, uFlags);
  202. lplvid->lpsfParent = lpsf;
  203. lpsf->AddRef();
  204. // Make a copy of the ITEMIDLIST
  205. lplvid->lpi = DuplicateItem(lpMalloc, lpi);
  206. lvi.lParam = (LPARAM)lplvid;
  207. // Add the item to the listview
  208. int iIndex = m_pListCtrl->InsertItem(&lvi);
  209. SetAttributes(iIndex, ulAttrs);
  210. if (iIndex >= 0)
  211. {
  212. TCHAR szItemPath[_MAX_PATH];
  213. ::SHGetPathFromIDList(lpifqThisItem, szItemPath);
  214. if (((ulAttrs & SFGAO_FILESYSTEM) == SFGAO_FILESYSTEM) &&
  215. ((ulAttrs & SFGAO_FOLDER) == 0))
  216. {
  217. WIN32_FIND_DATA fdata;
  218. HANDLE handle = ::FindFirstFile(szItemPath, &fdata);
  219. if (handle != INVALID_HANDLE_VALUE)
  220. {
  221. LONGLONG fsize = fdata.nFileSizeHigh*((LONGLONG)ULONG_MAX + 1) + fdata.nFileSizeLow;
  222. TCHAR szBuffer[16];
  223. CString strSize;
  224. strSize.Format(_T("%s KB"), InsertCommas((fsize + 1024)/1024, szBuffer, 15));
  225. m_pListCtrl->SetItemText(iIndex, 1, strSize);
  226. FILETIME ltime;
  227. ::FileTimeToLocalFileTime(&fdata.ftLastWriteTime, &ltime);
  228. SYSTEMTIME time;
  229. ::FileTimeToSystemTime(&ltime, &time);
  230. if ((time.wYear >= 1970 && time.wYear <= 2038) &&
  231. (time.wMonth >= 1 && time.wMonth <= 12))
  232. {
  233. CTime cTime;
  234. cTime = CTime(
  235. time.wYear,
  236. time.wMonth,
  237. time.wDay,
  238. time.wHour,
  239. time.wMinute,
  240. time.wSecond);
  241. m_pListCtrl->SetItemText(iIndex, 3, cTime.Format(_T("%m/%d/%y %I:%M %p")));
  242. }
  243. else
  244. {
  245. m_pListCtrl->SetItemText(iIndex, 3, _T("")); // Invalid date
  246. }
  247. ::FindClose(handle);
  248. }
  249. }
  250. else
  251. {
  252. m_pListCtrl->SetItemText(iIndex, 2, _T("0 bytes"));
  253. }
  254. SHFILEINFO sfi;
  255. ::SHGetFileInfo((TCHAR*)lpifqThisItem, 0, &sfi,
  256. sizeof(SHFILEINFO), SHGFI_PIDL | SHGFI_TYPENAME);
  257. m_pListCtrl->SetItemText(iIndex, 2, sfi.szTypeName);
  258. }
  259. else
  260. {
  261. if (lpifqThisItem)
  262. {
  263. lpMalloc.Free(lpifqThisItem);
  264. }
  265. return FALSE;
  266. }
  267. if (lpifqThisItem)
  268. {
  269. lpMalloc.Free(lpifqThisItem);
  270. }
  271. }
  272. // Free the pidl that the shell gave us.
  273. if (lpi)
  274. {
  275. lpMalloc.Free(lpi);
  276. lpi = NULL;
  277. }
  278. }
  279. if (lpe)
  280. {
  281. lpe->Release();
  282. }
  283. return TRUE;
  284. }
  285. TCHAR* CXTShellListBase::InsertCommas(LONGLONG value, TCHAR* szBufferOut, UINT nSize)
  286. {
  287. CString strValue; // 30 digits is a really big number
  288. TCHAR szBufferIn[30]; // 30 digits is a really big number
  289. TCHAR szDecimalSep[ 5 ];
  290. TCHAR szThousandSep[ 5 ];
  291. NUMBERFMT fmt;
  292. fmt.NumDigits = 0; // No decimal places
  293. ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILZERO, szBufferIn, 2);
  294. fmt.LeadingZero = _ttoi(szBufferIn);
  295. fmt.Grouping = 3;
  296. ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSep, 4);
  297. fmt.lpDecimalSep = szDecimalSep;
  298. ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szThousandSep, 4);
  299. fmt.lpThousandSep = szThousandSep;
  300. ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER, szBufferIn, 2);
  301. fmt.NegativeOrder = _ttoi(szBufferIn);
  302. strValue.Format(_T("%I64d"), value);
  303. ::GetNumberFormat(LOCALE_USER_DEFAULT, 0, strValue, &fmt, szBufferOut, nSize);
  304. return szBufferOut;
  305. }
  306. void CXTShellListBase::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem)
  307. {
  308. // Note that we don't check the return value here because if GetIcon()
  309. // fails, then we're in big trouble...
  310. lptvitem->iImage = GetItemIcon(lpifq,
  311. SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
  312. lptvitem->iSelectedImage = GetItemIcon(lpifq,
  313. SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
  314. }
  315. int CXTShellListBase::GetDoubleClickedItem()
  316. {
  317. CPoint point;
  318. ::GetCursorPos(&point);
  319. m_pListCtrl->ScreenToClient(&point);
  320. LV_HITTESTINFO  lvhti;
  321. lvhti.pt = point;
  322. m_pListCtrl->HitTest(&lvhti);
  323. if ((lvhti.flags & LVHT_ONITEM) == 0)
  324. {
  325. return -1;
  326. }
  327. return lvhti.iItem;
  328. }
  329. void CXTShellListBase::ShowShellContextMenu(CPoint point)
  330. {
  331. if (m_bContextMenu == FALSE)
  332. return;
  333. CPoint ptClient(point);
  334. m_pListCtrl->ScreenToClient(&ptClient);
  335. int nIndex = point == CPoint(-1, -1) ? m_pListCtrl->GetNextItem(-1, LVNI_FOCUSED) : m_pListCtrl->HitTest(ptClient);
  336. if (nIndex != -1)
  337. {
  338. if (point == CPoint(-1, -1))
  339. {
  340. CRect rcItem;
  341. m_pListCtrl->GetItemRect(nIndex, &rcItem, LVIR_ICON);
  342. point = rcItem.CenterPoint();
  343. m_pListCtrl->ClientToScreen(&point);
  344. }
  345. XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(nIndex);
  346. ASSERT(lplvid != NULL);
  347. if (!lplvid)
  348. return;
  349. CPtrArray arrItems;
  350. arrItems.Add(lplvid->lpi);
  351. POSITION pos = m_pListCtrl->GetFirstSelectedItemPosition();
  352. while (NULL != pos)
  353. {
  354. int nSelItem = m_pListCtrl->GetNextSelectedItem(pos);
  355. XT_LVITEMDATA* lplvidSelected = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(nSelItem);
  356. ASSERT(lplvidSelected != NULL);
  357. if (lplvidSelected != lplvid && lplvidSelected)
  358. arrItems.Add(lplvidSelected->lpi);
  359. }
  360. CXTShellPidl::ShowContextMenu(m_pListCtrl->m_hWnd,
  361. lplvid->lpsfParent, (LPCITEMIDLIST*)arrItems.GetData(), (int)arrItems.GetSize(), &point);
  362. }
  363. else if (m_lpsfFolder)
  364. {
  365. ShowContextMenu(m_pListCtrl->m_hWnd, m_lpsfFolder, 0, 0, &point);
  366. }
  367. }
  368. bool CXTShellListBase::ShellOpenItem(int iItem)
  369. {
  370. // Long pointer to ListView item data
  371. XT_LVITEMDATA*  lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(iItem);
  372. return ShellOpenItem(lplvid);
  373. }
  374. bool CXTShellListBase::ShellOpenItem(XT_LVITEMDATA* lplvid)
  375. {
  376. // Long pointer to ListView item data
  377. if (!(lplvid->ulAttribs & (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_REMOVABLE)))
  378. {
  379. SHELLEXECUTEINFO sei;
  380. ::ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
  381. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  382. sei.fMask = SEE_MASK_INVOKEIDLIST;
  383. sei.hwnd = ::GetParent(m_pListCtrl->m_hWnd);
  384. sei.nShow = SW_SHOWNORMAL;
  385. sei.hInstApp = AfxGetInstanceHandle();
  386. sei.lpIDList = GetFullyQualPidl(lplvid->lpsfParent, lplvid->lpi);
  387. if (::ShellExecuteEx(&sei))
  388. {
  389. return true;
  390. }
  391. }
  392. return false;
  393. }
  394. BOOL CXTShellListBase::GetItemPath(int iItem, CString& strItemPath)
  395. {
  396. if (iItem >= 0)
  397. {
  398. // Long pointer to TreeView item data
  399. XT_LVITEMDATA*  lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(iItem);
  400. if (lplvid != 0)
  401. {
  402. LPITEMIDLIST lpid = GetFullyQualPidl(lplvid->lpsfParent, lplvid->lpi);
  403. TCHAR szItemPath[_MAX_PATH];
  404. if (::SHGetPathFromIDList(lpid, szItemPath))
  405. {
  406. strItemPath = szItemPath;
  407. return TRUE;
  408. }
  409. }
  410. }
  411. return FALSE;
  412. }
  413. void CXTShellListBase::OnDeleteListItem(NMHDR* pNMHDR, LRESULT* pResult)
  414. {
  415. NM_LISTVIEW* pNMTreeView = (NM_LISTVIEW*)pNMHDR;
  416. XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)pNMTreeView->lParam;
  417. if (lplvid != NULL)
  418. {
  419. CShellMalloc lpMalloc;
  420. if (lplvid->lpi)
  421. {
  422. lpMalloc.Free(lplvid->lpi);
  423. lplvid->lpi = NULL;
  424. }
  425. if (lplvid->lpsfParent)
  426. {
  427. lplvid->lpsfParent->Release();
  428. lplvid->lpsfParent = NULL;
  429. }
  430. delete lplvid;
  431. }
  432. *pResult = 0;
  433. }
  434. void CXTShellListBase::UpdateList(int nMessage, XT_TVITEMDATA* pItemData)
  435. {
  436. switch (nMessage)
  437. {
  438. case SHN_XT_CONTENTSCHANGED:
  439. case SHN_XT_TREESELCHANGE:
  440. {
  441. CWnd* pOwner = m_pListCtrl->GetOwner();
  442. ASSERT_VALID(pOwner);
  443. if (!pOwner)
  444. return;
  445. // The tree view selection has changed, so update the contents
  446. // of the list view
  447. XT_TVITEMDATA*  lptvid = (XT_TVITEMDATA*)pItemData;
  448. ASSERT(lptvid != NULL);
  449. if (!lptvid)
  450. return;
  451. if (lptvid->lpsfParent == NULL)
  452. {
  453. CShellMalloc lpMalloc;
  454. if (!lpMalloc)
  455. {
  456. return;
  457. }
  458. LPSHELLFOLDER lpShellFolder;
  459. if (FAILED(::SHGetDesktopFolder(&lpShellFolder)))
  460. {
  461. return;
  462. }
  463. LPITEMIDLIST pidlDesktop = NULL;
  464. if (FAILED(::SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlDesktop)))
  465. {
  466. lpShellFolder->Release();
  467. return;
  468. }
  469. IShellFolder *pFolder = NULL;
  470. if (lpShellFolder->CompareIDs(0, lptvid->lpifq, pidlDesktop) == 0)
  471. {
  472. pFolder = lpShellFolder;
  473. }
  474. else
  475. {
  476. lpShellFolder->BindToObject(lptvid->lpifq, 0, IID_IShellFolder, (LPVOID*)&pFolder);
  477. lpShellFolder->Release();
  478. }
  479. ASSERT (pFolder != 0);
  480. PopulateListView(lptvid, pFolder);
  481. if (m_pidlINet && (pFolder->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
  482. {
  483. pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
  484. }
  485. else
  486. {
  487. pOwner->SendMessage(XTWM_SHELL_NOTIFY);
  488. }
  489. if (pidlDesktop)
  490. {
  491. lpMalloc.Free(pidlDesktop);
  492. }
  493. if (pFolder)
  494. {
  495. pFolder->Release();
  496. }
  497. }
  498. else
  499. {
  500. LPSHELLFOLDER lpsf = NULL;
  501. if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
  502. 0, IID_IShellFolder, (LPVOID*)&lpsf)))
  503. {
  504. PopulateListView(lptvid, lpsf);
  505. lpsf->Release();
  506. if (SUCCEEDED(::SHGetDesktopFolder(&lpsf)))
  507. {
  508. if (m_pidlINet && (lpsf->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
  509. {
  510. pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
  511. }
  512. else
  513. {
  514. pOwner->SendMessage(XTWM_SHELL_NOTIFY);
  515. }
  516. lpsf->Release();
  517. }
  518. }
  519. else
  520. {
  521. if (SUCCEEDED(::SHGetDesktopFolder(&lpsf)))
  522. {
  523. if (m_pidlINet && (lpsf->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
  524. {
  525. pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
  526. }
  527. lpsf->Release();
  528. }
  529. }
  530. }
  531. break;
  532. }
  533. case SHN_XT_REFRESHFOLDER:
  534. case SHN_XT_REFRESHTREE:
  535. {
  536. // Directory monitory thread has issued an update notification,
  537. // refresh the list control.
  538. XT_TVITEMDATA*  lpTVID = (XT_TVITEMDATA*)pItemData;
  539. ASSERT(lpTVID);
  540. if (!lpTVID)
  541. return;
  542. PopulateListView(lpTVID, lpTVID->lpsfParent);
  543. break;
  544. }
  545. case SHN_XT_NOFOLDER:
  546. {
  547. // The item double clicked was not found in the treeview
  548. // so it sent us back a confirmation to execute it
  549. XT_LVITEMDATA*  lplvid = (XT_LVITEMDATA*)pItemData;
  550. ASSERT(lplvid);
  551. if (!lplvid)
  552. return;
  553. ShellOpenItem(lplvid);
  554. }
  555. break;
  556. default:
  557. break;
  558. }
  559. }
  560. bool CXTShellListBase::SortList(int nCol, bool bAscending)
  561. {
  562. if (m_nSortedCol >= 0)
  563. {
  564. CXTFlatHeaderCtrl* pHeaderCtrl = GetFlatHeaderCtrl();
  565. if (pHeaderCtrl && pHeaderCtrl->GetSortedCol() < 0)
  566. {
  567. pHeaderCtrl->SetSortImage(nCol, bAscending);
  568. }
  569. }
  570. if (nCol == 0)
  571. {
  572. return m_pListCtrl->SortItems(
  573. ListViewCompareProc, (DWORD)bAscending) == TRUE;
  574. }
  575. XTSortType arrColType[] =
  576. {
  577. xtSortString, xtSortInt, xtSortString, xtSortDateTime
  578. };
  579. CXTSortClass sortClass(m_pListCtrl, nCol);
  580. sortClass.Sort(bAscending, arrColType[nCol]);
  581. return true;
  582. }
  583. void CXTShellListBase::SetAttributes(int iItem, DWORD dwAttributes)
  584. {
  585. MapShellFlagsToItemAttributes(m_pListCtrl, iItem, dwAttributes);
  586. }
  587. void CXTShellListBase::OnDragDrop(NM_LISTVIEW* /*pNMListView*/)
  588. {
  589. COleDataSource oleDataSource;
  590. HGLOBAL        hgDrop;
  591. DROPFILES*     pDrop;
  592. CStringList    lsDraggedFiles;
  593. POSITION       pos;
  594. int            nSelItem;
  595. CString        sFile;
  596. UINT           uBuffSize = 0;
  597. TCHAR*         pszBuff;
  598. FORMATETC      etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  599. // For every selected item in the list, put the filename into lsDraggedFiles.
  600. pos = m_pListCtrl->GetFirstSelectedItemPosition();
  601. while (NULL != pos)
  602. {
  603. nSelItem = m_pListCtrl->GetNextSelectedItem(pos);
  604. GetItemPath(nSelItem, sFile);
  605. lsDraggedFiles.AddTail (sFile);
  606. // Calculate the # of chars required to hold this string.
  607. uBuffSize += lstrlen (sFile) + 1;
  608. }
  609. // Add 1 extra for the final null char, and the size of the DROPFILES struct.
  610. uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1);
  611. // Allocate memory from the heap for the DROPFILES struct.
  612. hgDrop = ::GlobalAlloc (GHND | GMEM_SHARE, uBuffSize);
  613. if (NULL == hgDrop)
  614. return;
  615. pDrop = (DROPFILES*) ::GlobalLock (hgDrop);
  616. if (NULL == pDrop)
  617. {
  618. ::GlobalFree (hgDrop);
  619. return;
  620. }
  621. // Fill in the DROPFILES struct.
  622. pDrop->pFiles = sizeof(DROPFILES);
  623. #ifdef _UNICODE
  624. // If we're compiling for Unicode, set the Unicode flag in the struct to
  625. // indicate it contains Unicode strings.
  626. pDrop->fWide = TRUE;
  627. #endif
  628. // Copy all the filenames into memory after the end of the DROPFILES struct.
  629. pos = lsDraggedFiles.GetHeadPosition();
  630. pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES));
  631. while (NULL != pos)
  632. {
  633. lstrcpy (pszBuff, (LPCTSTR) lsDraggedFiles.GetNext (pos));
  634. pszBuff = 1 + _tcschr (pszBuff, '');
  635. }
  636. ::GlobalUnlock (hgDrop);
  637. // Put the data in the data source.
  638. oleDataSource.CacheGlobalData (CF_HDROP, hgDrop, &etc);
  639. // Add in our own custom data, so we know that the drag originated from our
  640. // window.  OnDragEnter() checks for this custom format, and
  641. // doesn't allow the drop if it's present.  This is how we prevent the user
  642. // from dragging and then dropping in our own window.
  643. // The data will just be a dummy bool.
  644. HGLOBAL hgBool;
  645. hgBool = ::GlobalAlloc (GHND | GMEM_SHARE, sizeof(bool));
  646. if (NULL == hgBool)
  647. {
  648. ::GlobalFree (hgDrop);
  649. return;
  650. }
  651. static CLIPFORMAT clpFormat = (CLIPFORMAT)
  652. ::RegisterClipboardFormat(_T("{B0D76F7A-B5D9-436c-8F10-BA16AEE69D42}"));
  653. // Put the data in the data source.
  654. etc.cfFormat = clpFormat;
  655. oleDataSource.CacheGlobalData(clpFormat, hgBool, &etc);
  656. // Start the drag 'n' drop!
  657. DROPEFFECT dwEffect = oleDataSource.DoDragDrop (DROPEFFECT_COPY | DROPEFFECT_MOVE);
  658. // If the DnD completed OK, we remove all of the dragged items from our
  659. //
  660. switch (dwEffect)
  661. {
  662. case DROPEFFECT_MOVE:
  663. {
  664. // The files were copied or moved.
  665. // Note: Don't call ::GlobalFree() because the data will be freed by the drop target.
  666. for (nSelItem = m_pListCtrl->GetNextItem (-1, LVNI_SELECTED);
  667. nSelItem != -1;
  668. nSelItem = m_pListCtrl->GetNextItem (nSelItem, LVNI_SELECTED))
  669. {
  670. m_pListCtrl->DeleteItem (nSelItem);
  671. nSelItem--;
  672. }
  673. }
  674. break;
  675. case DROPEFFECT_COPY:
  676. break;
  677. case DROPEFFECT_NONE:
  678. {
  679. // This needs special handling, because on NT, DROPEFFECT_NONE
  680. // is returned for move operations, instead of DROPEFFECT_MOVE.
  681. // See Q182219 for the details.
  682. // So if we're on NT, we check each selected item, and if the
  683. // file no longer exists, it was moved successfully and we can
  684. // remove it from the
  685. if ((GetVersion() & 0x80000000) == 0)
  686. {
  687. bool bDeletedAnything = false;
  688. for (nSelItem = m_pListCtrl->GetNextItem (-1, LVNI_SELECTED);
  689. nSelItem != -1;
  690. nSelItem = m_pListCtrl->GetNextItem(nSelItem, LVNI_SELECTED))
  691. {
  692. GetItemPath(nSelItem, sFile);
  693. if (GetFileAttributes(sFile) == DWORD(-1) &&
  694. GetLastError() == ERROR_FILE_NOT_FOUND)
  695. {
  696. // We couldn't read the file's attributes, and GetLastError()
  697. // says the file doesn't exist, so remove the corresponding
  698. // item from the
  699. m_pListCtrl->DeleteItem(nSelItem);
  700. nSelItem--;
  701. bDeletedAnything = true;
  702. }
  703. }
  704. // Resize the list columns if we deleted any items.
  705. if (bDeletedAnything)
  706. {
  707. m_pListCtrl->SetColumnWidth (0, LVSCW_AUTOSIZE_USEHEADER);
  708. m_pListCtrl->SetColumnWidth (1, LVSCW_AUTOSIZE_USEHEADER);
  709. m_pListCtrl->SetColumnWidth (2, LVSCW_AUTOSIZE_USEHEADER);
  710. // Note: Don't call ::GlobalFree() because the data belongs to
  711. // the caller.
  712. }
  713. else
  714. {
  715. // The DnD operation wasn't accepted, or was canceled, so we
  716. // should call ::GlobalFree() to clean up.
  717. ::GlobalFree (hgDrop);
  718. ::GlobalFree (hgBool);
  719. }
  720. }   // end if (NT)
  721. else
  722. {
  723. // We're on 9x, and a return of DROPEFFECT_NONE always means
  724. // that the DnD operation was aborted.  We need to free the
  725. // allocated memory.
  726. ::GlobalFree (hgDrop);
  727. ::GlobalFree (hgBool);
  728. }
  729. }
  730. break;  // end case DROPEFFECT_NONE
  731. }   // end switch
  732. }
  733. bool CXTShellListBase::Init()
  734. {
  735. if (!CXTListBase::Init())
  736. return false;
  737. if (!m_pListCtrl->GetImageList(LVSIL_SMALL))
  738. {
  739. // Initialize the columns and image list for the list control.
  740. BuildDefaultColumns();
  741. InitSystemImageLists();
  742. m_pListCtrl->ModifyStyle(NULL, LVS_REPORT | LVS_SHAREIMAGELISTS);
  743. SubclassHeader(FALSE);
  744. GetFlatHeaderCtrl()->ShowSortArrow(TRUE);
  745. m_pListCtrl->DragAcceptFiles(TRUE);
  746. }
  747. return true;
  748. }