1 //*******************************************************************************
4 // You may use this source code, compile or redistribute it as part of your application
5 // for free. You cannot redistribute it as a part of a software development
6 // library without the agreement of the author. If the sources are
7 // distributed along with the application, you should leave the original
8 // copyright notes in the source code without any changes.
9 // This code can be used WITHOUT ANY WARRANTIES at your own risk.
11 // For the latest updates to this code, check this site:
12 // http://www.masmex.com
15 // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
16 //*******************************************************************************
18 // IEShellListCtrl.cpp : implementation file
20 #include "IEShellListCtrl.h"
21 #include "UIMessages.h"
23 #include "cbformats.h"
28 static char THIS_FILE[] = __FILE__;
31 #define UMAKEINT64(low,high) ((unsigned __int64)(((DWORD)(low)) | ((unsigned __int64)((DWORD)(high))) << 32))
32 /////////////////////////////////////////////////////////////////////////////
35 CIEShellListCtrl::CIEShellListCtrl()
37 SetEditSubItems(false);
39 ZeroMemory(&m_tvid,sizeof(m_tvid));
40 m_psfSubFolder = NULL;
45 m_bRefreshAllowed = true;
46 m_bPopulateInit = false;
47 m_bInitiliazed = false;
48 m_bNotifyParent = false;
49 m_pidlInternet = NULL;
50 SHGetMalloc(&m_pMalloc);
51 SHGetSpecialFolderLocation(NULL,CSIDL_INTERNET,&m_pidlInternet);
52 m_sColumns = _T("Name|Size|Type|Modified");
55 CIEShellListCtrl::~CIEShellListCtrl()
65 void CIEShellListCtrl::PopupTheMenu(int nRow,CPoint point)
67 if (!GetSelectedCount())
70 LPLVITEMDATA lplvid=NULL;
71 LPITEMIDLIST *pidls=(LPITEMIDLIST*)GetShellPidl().GetMalloc()->Alloc(GetSelectedCount()*sizeof(LPITEMIDLIST));
73 while ((nSel = GetNextSel(nSel)) != -1)
75 lplvid=(LPLVITEMDATA)GetItemData(nSel);
76 pidls[i] = lplvid->lpi;
82 GetShellPidl().PopupTheMenu(m_hWnd, lplvid->lpsfParent, pidls, i, &point);
84 GetShellPidl().Free(pidls);
87 void CIEShellListCtrl::ShellExecute(int nRow,LPCTSTR pszVerb)
90 ZeroMemory(&si,sizeof(si));
91 si.cbSize = sizeof(si);
92 si.hwnd = GetSafeHwnd();
94 si.lpIDList = (LPVOID)GetPathPidl(nRow);
95 si.fMask = SEE_MASK_INVOKEIDLIST;
101 void CIEShellListCtrl::SetNotificationObject(bool bNotify)
104 CreateFileChangeThread(GetSafeHwnd());
109 void CIEShellListCtrl::FreeInterface(IUnknown *pInterface)
112 pInterface->Release();
115 void CIEShellListCtrl::DestroyThreads()
117 if (m_nThreadCount == 0)
119 for (UINT i=0; i<m_nThreadCount; i++)
120 m_event[i].SetEvent();
121 ::WaitForMultipleObjects (m_nThreadCount, m_hThreads, TRUE, INFINITE);
122 for (i=0; i<m_nThreadCount; i++)
123 delete m_pThreads[i];
127 void CIEShellListCtrl::FreeTVID()
129 if (m_tvid.lpsfParent)
130 m_tvid.lpsfParent->Release();
132 m_pMalloc->Free(m_tvid.lpi);
134 m_pMalloc->Free(m_tvid.lpifq);
135 ZeroMemory(&m_tvid,sizeof(m_tvid));
137 m_psfSubFolder->Release();
138 m_psfSubFolder = NULL;
141 CString CIEShellListCtrl::GetCurrPathName()
143 return GetPathName(GetCurSel());
146 CString CIEShellListCtrl::GetPathName(int nRow)
153 LPLVITEMDATA plvit = (LPLVITEMDATA)GetItemData(nRow);
157 SHGetPathFromIDList(plvit->lpifq,sPath.GetBuffer(MAX_PATH));
158 sPath.ReleaseBuffer();
162 LPCITEMIDLIST CIEShellListCtrl::GetPathPidl(int nRow)
166 LPLVITEMDATA plvit = (LPLVITEMDATA)GetItemData(nRow);
173 void CIEShellListCtrl::FillExcludedFileTypes(CComboBox &cb)
176 for(POSITION pos=m_ExcludedLookup.GetHeadPosition();pos != NULL;m_ExcludedLookup.GetNext(pos))
178 cb.AddString(m_ExcludedLookup.GetAt(pos));
182 void CIEShellListCtrl::SetExcludedFileTypes(CComboBox &cb)
184 m_ExcludedLookup.RemoveAll();
186 for(int i=0;i < cb.GetCount();i++)
188 cb.GetLBText(i,sText);
189 m_ExcludedLookup.AddHead(sText);
193 void CIEShellListCtrl::LoadFilterFiles(const CString &sFileFilter)
195 m_FilterLookup.RemoveAll();
198 if (FAILED(GetShellPidl().SHPidlToPathEx(m_tvid.lpifq,sPath)))
200 if (sPath.Right(1) != _T('\\'))
204 LPCTSTR pszFilter=sFileFilter;
205 pszFilter = GetFilterMask(pszFilter,sMask);
206 while (pszFilter != NULL)
210 BOOL bFind = ff.FindFile(sFindPath);
213 bFind = ff.FindNextFile();
214 m_FilterLookup.AddHead(ff.GetFilePath());
216 pszFilter = GetFilterMask(pszFilter,sMask);
220 LPCTSTR CIEShellListCtrl::GetFilterMask(LPCTSTR pszFilter,CString &sMask)
222 if (*pszFilter == '\0')
224 TCHAR szMask[MAX_PATH];
226 for(int i=0;*pszFilter != '\0';i++)
228 if (*pszFilter == _T(';') || *pszFilter == _T(','))
230 pszFilter = _tcsinc(pszFilter);
233 szMask[i] = *pszFilter;
234 pszFilter = _tcsinc(pszFilter);
241 void CIEShellListCtrl::AllItemsDeleted()
243 LPLVITEMDATA pItemData=NULL;
244 for(vecListItemData::iterator it=m_vecItemData.begin();it != m_vecItemData.end();it++)
249 if (pItemData->lpsfParent)
250 pItemData->lpsfParent->Release();
252 m_pMalloc->Free(pItemData->lpi);
253 if (pItemData->lpifq)
254 m_pMalloc->Free(pItemData->lpifq);
255 if (pItemData->lParam)
257 PSLC_COLUMN_DATA pColData = (PSLC_COLUMN_DATA)pItemData->lParam;
259 GetShellPidl().FreePidl(pColData->pidl);
262 m_pMalloc->Free(pItemData);
265 m_vecItemData.erase(m_vecItemData.begin(),m_vecItemData.end());
268 void CIEShellListCtrl::StartPopulate()
270 m_bPopulateInit = true;
272 for(UINT i=0;i < m_nThreadCount;i++)
273 m_MonitorEvent[i].SetEvent();
274 if (m_sFileFilter.IsEmpty() || m_sFileFilter == _T("*.*") || m_sFileFilter == _T("*"))
276 LoadFilterFiles(m_sFileFilter);
279 void CIEShellListCtrl::EndPopulate()
281 m_bPopulateInit = false;
286 BOOL CIEShellListCtrl::Populate(LPTVITEMDATA lptvid)
288 IShellFolder *pFolder=NULL;
291 if (lptvid->lpsfParent)
293 hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,0,IID_IShellFolder,(LPVOID*)&pFolder);
297 LPSHELLFOLDER psfDesktop;
298 LPITEMIDLIST pidlDesktop=NULL;
299 hr=SHGetDesktopFolder(&psfDesktop);
300 SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&pidlDesktop);
301 if (GetShellPidl().ComparePidls(NULL,lptvid->lpifq,pidlDesktop))
303 pFolder = psfDesktop;
307 hr=psfDesktop->BindToObject(lptvid->lpifq,0,IID_IShellFolder,(LPVOID*)&pFolder);
308 psfDesktop->Release();
311 GetShellPidl().FreePidl(pidlDesktop);
315 bRet = Populate(lptvid,pFolder,true);
321 BOOL CIEShellListCtrl::Populate(LPCTSTR pszPath, bool bCallBack)
323 LPITEMIDLIST pidlfq=NULL;
324 LPITEMIDLIST pidl=NULL;
325 LPSHELLFOLDER pDesktop = NULL;
326 SHGetDesktopFolder(&pDesktop);
327 if (FAILED(GetShellPidl().SHPathToPidlEx(pszPath,&pidlfq,pDesktop)))
329 LPSHELLFOLDER pSubFolder = NULL;
330 #if 1 // bug fix by Dion Loy
331 if (FAILED(pDesktop->BindToObject(pidlfq, 0, IID_IShellFolder,(LPVOID*)&pSubFolder)))
333 if (FAILED(pDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pSubFolder)))
336 pidl = GetShellPidl().CopyLastItemID(pidlfq);
340 tvid.lpsfParent = NULL;
341 BOOL bRet = Populate(&tvid,pSubFolder,bCallBack);
345 pSubFolder->Release();
347 m_pMalloc->Free(pidl);
349 m_pMalloc->Free(pidlfq);
354 BOOL CIEShellListCtrl::Populate(LPTVITEMDATA lptvid,LPSHELLFOLDER psfFolder,bool bCallBack)
356 m_bCallBack = bCallBack;
358 m_tvid.lpi = GetShellPidl().CopyItemIDList(lptvid->lpi);
359 m_tvid.lpifq = GetShellPidl().CopyItemIDList(lptvid->lpifq);
362 GetShellPidl().SHPidlToPathEx(m_tvid.lpifq,sPath,NULL);
363 TRACE1("Populating path %s in CIEShellListCtrl\n",sPath);
365 if (lptvid->lpsfParent)
367 m_tvid.lpsfParent = lptvid->lpsfParent;
368 m_tvid.lpsfParent->AddRef();
370 m_psfSubFolder = psfFolder;
371 m_psfSubFolder->AddRef();
376 CString CIEShellListCtrl::GetColumns()
379 LPTSTR pszHeader=NULL;
381 for(int i=0;SUCCEEDED(m_ShellDetails.GetDetailsOf(NULL,i,&sd));i++)
383 GetShellPidl().StrRetToStr(sd.str,&pszHeader,NULL);
386 TRACE1("Column found %s\n",pszHeader);
387 if (!sColumns.IsEmpty())
389 sColumns += pszHeader;
390 GetShellPidl().Free(pszHeader);
397 void CIEShellListCtrl::InitColumns()
399 CString sColumns = GetColumns();
400 if (sColumns.IsEmpty())
401 sColumns = m_sColumns;
402 InitListCtrl(sColumns);
405 void CIEShellListCtrl::SetColumnWidths()
409 for(int i=0;i < GetColumnCount();i++)
410 SetColumnWidth(i,LVSCW_AUTOSIZE);
414 void CIEShellListCtrl::Refresh()
416 if (m_psfSubFolder==NULL)
418 SetRefreshAllowed(false);
420 int nCurSel = GetCurSel();
421 TRACE(_T("Refreshing shell list control\n"));
425 OnSelChanged(nCurSel,&Result);
427 SetRefreshAllowed(true);
430 void CIEShellListCtrl::Load()
433 if (!InitItems(&m_tvid,m_bCallBack))
437 void CIEShellListCtrl::Init()
441 CUIODListCtrl::Init();
444 m_bInitiliazed = true;
447 BOOL CIEShellListCtrl::InitItems(LPTVITEMDATA lptvid, bool bCallBack)
453 ASSERT(m_psfSubFolder);
454 if (m_psfSubFolder == NULL)
457 // Try to initialize columns from shell
458 m_ShellDetails.SetShellDetails(NULL);
459 IShellFolder2 *pShellFolder2=NULL;
460 HRESULT hr=m_psfSubFolder->QueryInterface(IID_IShellFolder2,(LPVOID*)&pShellFolder2);
464 if (SUCCEEDED(pShellFolder2->QueryInterface(IID_IUnknown,(LPVOID*)&pUnk)))
466 m_ShellDetails.SetShellDetails(pUnk);
469 m_ShellDetails.SetShellDetails((LPUNKNOWN)pShellFolder2);
470 pShellFolder2->Release();
474 IShellDetails *pShellDetails=NULL;
475 HRESULT hr = m_psfSubFolder->CreateViewObject(GetSafeHwnd(), IID_IShellDetails, (LPVOID*)&pShellDetails);
479 if (SUCCEEDED(pShellDetails->QueryInterface(IID_IUnknown,(LPVOID*)&pUnk)))
481 m_ShellDetails.SetShellDetails(pUnk);
484 pShellDetails->Release();
489 DWORD dwExStyle = GetExStyle();
490 if(!m_ShellSettings.DoubleClickInWebView())
492 dwExStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT;
496 dwExStyle &= ~LVS_EX_ONECLICKACTIVATE;
497 dwExStyle &= ~LVS_EX_TRACKSELECT;
498 dwExStyle &= ~LVS_EX_UNDERLINEHOT;
500 SetExStyle(dwExStyle);
502 LPITEMIDLIST lpi=NULL;
503 LPENUMIDLIST lpe=NULL;
504 LPLVITEMDATA lplvid=NULL;
505 LPSHELLFOLDER lpsf=m_psfSubFolder;
506 ULONG ulFetched, ulAttrs;
507 HWND hwnd=::GetParent(m_hWnd);
508 DWORD dwFlags = SHCONTF_NONFOLDERS;
510 if (GetShellSettings().ShowAllObjects() && !GetShellSettings().ShowSysFiles())
511 dwFlags |= SHCONTF_INCLUDEHIDDEN;
512 hr=lpsf->EnumObjects(hwnd,dwFlags, &lpe);
517 bool bEndPopulate=false;
518 if (m_bPopulateInit == false)
523 while (NO_ERROR==lpe->Next(1, &lpi, &ulFetched))
525 ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_DISPLAYATTRMASK | SFGAO_CONTENTSMASK | SFGAO_REMOVABLE;
526 lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&lpi, &ulAttrs);
527 if (!FilterItem(lpsf,lpi,ulAttrs))
529 m_pMalloc->Free(lpi); // free PIDL the shell gave you
533 lplvid = (LPLVITEMDATA)m_pMalloc->Alloc(sizeof(LVITEMDATA));
536 ZeroMemory(lplvid,sizeof(LVITEMDATA));
537 m_vecItemData.push_back(lplvid);
539 lplvid->ulAttribs=ulAttrs;
541 lplvid->lpifq=m_ShellPidl.ConcatPidl(lptvid->lpifq, lpi);
543 lplvid->lpsfParent=lpsf;
544 lplvid->lpsfParent->AddRef();
546 // Now make a copy of the ITEMIDLIST.
547 lplvid->lpi=m_ShellPidl.CopyItemID(lpi);
549 // Add the item to the list view control.
553 nRow = AddCallBackItem((DWORD)lplvid,I_IMAGECALLBACK);
554 if ((ulAttrs & SFGAO_COMPRESSED) && m_ShellSettings.ShowCompColor())
555 SetTextColor(nRow,0,RGB(0,0,255));
557 SetDefaultTextColor(nRow,-1);
561 nRow = AddTextItem();
564 TCHAR szText[MAX_PATH+1];
565 SetItemData(nRow,(DWORD)lplvid);
567 ZeroMemory(&dsp,sizeof(LV_DISPINFO));
568 dsp.item.mask |= (LVIF_TEXT | LVIF_IMAGE);
569 for(int i=0; i < GetColumnCount();i++)
572 dsp.item.iItem = nRow;
573 dsp.item.iSubItem = i;
574 dsp.item.cchTextMax = MAX_PATH;
575 dsp.item.pszText = szText;
577 dsp.item.mask &= ~LVIF_IMAGE;
581 SetIcon(nRow,dsp.item.iImage);
582 AddString(nRow,i,szText);
586 m_pMalloc->Free(lpi); // free PIDL the shell gave you
593 // The following two if statements will be TRUE only if you got here
594 // on an error condition from the goto statement. Otherwise, free
595 // this memory at the end of the while loop above.
597 m_pMalloc->Free(lpi);
604 bool CIEShellListCtrl::FilterItem(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl,UINT ulAttrs)
606 if ((m_sFileFilter.IsEmpty() || m_sFileFilter == _T("*.*") || m_sFileFilter == _T("*"))
607 && m_ExcludedLookup.IsEmpty())
610 if (m_sFileFilter == _T("*.*") || m_sFileFilter == _T("*"))
614 else if (!m_sFileFilter.IsEmpty())
617 GetShellPidl().SHPidlToPathEx(pidl,sPath,pFolder);
618 if (m_FilterLookup.Find(sPath))
623 if (!m_ExcludedLookup.IsEmpty())
626 ZeroMemory(&fileInfo,sizeof(fileInfo));
627 SHGetFileInfo((LPCTSTR)pidl, NULL, &fileInfo, sizeof(fileInfo), SHGFI_PIDL|SHGFI_TYPENAME);
628 if (m_ExcludedLookup.Find(fileInfo.szTypeName))
636 void CIEShellListCtrl::InitShellSettings()
638 m_ShellSettings.GetSettings();
641 BOOL CIEShellListCtrl::InitImageLists()
643 HIMAGELIST himlSmall;
644 HIMAGELIST himlLarge;
648 himlSmall = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T("C:\\"),
652 SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
654 himlLarge = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T("C:\\"),
658 SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
660 if (himlSmall && himlLarge)
662 ::SendMessage(GetSafeHwnd(), LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL,
664 ::SendMessage(GetSafeHwnd(), LVM_SETIMAGELIST, (WPARAM)LVSIL_NORMAL,
673 BEGIN_MESSAGE_MAP(CIEShellListCtrl, CUIODListCtrl)
674 //{{AFX_MSG_MAP(CIEShellListCtrl)
675 ON_MESSAGE(WM_SETMESSAGESTRING,OnSetmessagestring)
676 ON_MESSAGE(WM_SETTINGCHANGE,OnSettingChange)
677 // NOTE - the ClassWizard will add and remove mapping macros here.
681 ON_MESSAGE(WM_APP_ON_DELETE_KEY,OnAppDeleteKey)
682 ON_MESSAGE(WM_APP_ON_PROPERTIES_KEY,OnAppPropertiesKey)
683 ON_MESSAGE(WM_APP_UPDATE_ALL_VIEWS,OnAppUpdateAllViews)
684 ON_MESSAGE(WM_APP_FILE_CHANGE_NEW_PATH,OnAppFileChangeNewPath)
685 ON_MESSAGE(WM_APP_FILE_CHANGE_EVENT,OnAppFileChangeEvent)
688 /////////////////////////////////////////////////////////////////////////////
689 // CIEShellListCtrl message handlers
690 void CIEShellListCtrl::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
692 CUIODListCtrl::OnMenuSelect(nItemID,nFlags,hSysMenu);
695 void CIEShellListCtrl::ShowPopupMenu(int nRow,int nCol,CPoint point)
697 if ((nCol > 0 || nRow == -1) || (m_PopupID || m_MultiPopupID))
699 CUIODListCtrl::ShowPopupMenu(nRow,nCol,point);
702 PopupTheMenu(nRow,point);
705 void CIEShellListCtrl::OnDestroy()
707 SetImageList(NULL,LVSIL_SMALL);
708 SetImageList(NULL,LVSIL_NORMAL);
710 CUIODListCtrl::OnDestroy();
713 bool CIEShellListCtrl::UseShellColumns()
715 return m_ShellDetails.IsValidDetails();
718 BOOL CIEShellListCtrl::GetDispInfo(LV_DISPINFO *pDispInfo)
720 // TODO: Add your specialized code here and/or call the base class
721 if (m_psfSubFolder == NULL || m_bCallBack == false)
722 return CUIODListCtrl::GetDispInfo(pDispInfo);
723 LPLVITEMDATA lplvid = (LPLVITEMDATA)GetItemData(pDispInfo->item.iItem);
727 PSLC_COLUMN_DATA pColData=(PSLC_COLUMN_DATA)lplvid->lParam;
728 if (pColData == NULL)
730 pColData = new SLC_COLUMN_DATA;
731 pColData->sItems.SetSize(GetColumnCount());
732 lplvid->lParam = (LPARAM)pColData;
734 if (pColData->pidl == NULL)
735 pColData->pidl = m_ShellPidl.ConcatPidl(m_tvid.lpifq, lplvid->lpi);
736 if (pDispInfo->item.mask & LVIF_IMAGE)
738 if (pColData->iImage == -1)
740 pColData->iImage = m_ShellPidl.GetIcon(pColData->pidl,SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
742 pDispInfo->item.iImage = pColData->iImage;
743 if (lplvid->ulAttribs & SFGAO_GHOSTED)
745 pDispInfo->item.mask |= LVIF_STATE;
746 pDispInfo->item.stateMask = LVIS_CUT;
747 pDispInfo->item.state = LVIS_CUT;
749 if (lplvid->ulAttribs & SFGAO_LINK)
751 pDispInfo->item.mask |= LVIF_STATE;
752 pDispInfo->item.stateMask = LVIS_OVERLAYMASK;
753 pDispInfo->item.state = INDEXTOOVERLAYMASK(2);
755 if (lplvid->ulAttribs & SFGAO_SHARE)
757 pDispInfo->item.mask |= LVIF_STATE;
758 pDispInfo->item.stateMask = LVIS_OVERLAYMASK;
759 pDispInfo->item.state = INDEXTOOVERLAYMASK(1);
762 if (pDispInfo->item.mask & LVIF_TEXT)
764 if (UseShellColumns())
766 if (pDispInfo->item.iSubItem == COL_NAME)
768 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
769 m_ShellPidl.GetName(lplvid->lpsfParent, lplvid->lpi, SHGDN_NORMAL, pColData->sItems[pDispInfo->item.iSubItem]);
770 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
772 RemoveExt(pDispInfo->item.pszText);
776 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
779 ZeroMemory(&sd,sizeof(sd));
780 HRESULT hr = m_ShellDetails.GetDetailsOf(lplvid->lpi,pDispInfo->item.iSubItem,&sd);
782 GetShellPidl().StrRetToStr(sd.str,&pszText,lplvid->lpi);
785 _tcscpy(pDispInfo->item.pszText,pszText);
786 GetShellPidl().Free(pszText);
791 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
797 GetText(pColData,pDispInfo,lplvid);
803 bool CIEShellListCtrl::GetColText(int nCol,LPCITEMIDLIST pidlAbs,LPLVITEMDATA lplvid,CString &sText)
808 void CIEShellListCtrl::GetText(PSLC_COLUMN_DATA pColData,LV_DISPINFO *pDispInfo,LPLVITEMDATA lplvid)
810 if (!pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
812 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
815 LPITEMIDLIST pidlAbs = pColData->pidl;
817 if (GetColText(pDispInfo->item.iSubItem,pidlAbs,lplvid,sText))
819 pColData->sItems[pDispInfo->item.iSubItem] = sText;
820 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
823 if (pDispInfo->item.iSubItem == COL_NAME)
825 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
826 m_ShellPidl.GetName(lplvid->lpsfParent, lplvid->lpi, SHGDN_NORMAL,pColData->sItems[pDispInfo->item.iSubItem]);
827 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
829 RemoveExt(pDispInfo->item.pszText);
831 else if (pDispInfo->item.iSubItem == COL_TYPE)
833 if (pColData->sItems[pDispInfo->item.iSubItem].IsEmpty())
836 if (SHGetFileInfo((LPCTSTR)lplvid->lpi, NULL, &fileInfo, sizeof(fileInfo), SHGFI_PIDL|SHGFI_TYPENAME))
838 pColData->sItems[pDispInfo->item.iSubItem] = fileInfo.szTypeName;
841 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
843 else if (pDispInfo->item.iSubItem == COL_SIZE || pDispInfo->item.iSubItem == COL_MODIFIED)
845 if (pColData->sItems[COL_SIZE].IsEmpty() || (pColData->sItems[COL_MODIFIED].IsEmpty()))
849 GetFileDetails(pidlAbs,sSize,sDateTime);
850 if (pDispInfo->item.iSubItem == COL_SIZE)
851 pColData->sItems[pDispInfo->item.iSubItem] = sSize;
852 else if (pDispInfo->item.iSubItem == COL_MODIFIED)
853 pColData->sItems[pDispInfo->item.iSubItem] = sDateTime;
855 if (pDispInfo->item.iSubItem == COL_SIZE)
856 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
857 else if (pDispInfo->item.iSubItem == COL_MODIFIED)
858 _tcscpy(pDispInfo->item.pszText,pColData->sItems[pDispInfo->item.iSubItem]);
862 void CIEShellListCtrl::GetFileDetails(LPCITEMIDLIST pidl, CString &sSize, CString &sDateTime)
865 GetShellPidl().SHPidlToPathEx((LPITEMIDLIST)pidl,sPath,NULL);
866 if (sPath.GetLength() <= 3)
868 WIN32_FIND_DATA FindFileData;
869 HANDLE hFind = FindFirstFile(sPath,&FindFileData);
870 if (hFind != INVALID_HANDLE_VALUE)
872 if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
874 unsigned __int64 fs = UMAKEINT64(FindFileData.nFileSizeLow, FindFileData.nFileSizeHigh);
875 unsigned __int64 kb=1;
883 _ui64tot(kb,szText,10);
885 AddThousandSeps(sSize);
888 if ((FindFileData.ftLastWriteTime.dwLowDateTime != 0) || (FindFileData.ftLastWriteTime.dwHighDateTime != 0))
890 sDateTime = CLocaleInfo::Instance()->FormatDateTime(FindFileData.ftLastWriteTime);
894 sDateTime = CLocaleInfo::Instance()->FormatDateTime(FindFileData.ftCreationTime);
900 void CIEShellListCtrl::RemoveExt(LPTSTR pszFileName)
902 if (pszFileName == NULL)
905 LPTSTR pEndPos = pszFileName+lstrlen(pszFileName);
906 LPTSTR pStartPos = pszFileName;
907 while (pEndPos > pStartPos)
914 pEndPos = _tcsdec(pStartPos,pEndPos);
920 int CALLBACK ShellCompareFunc(LPARAM lparam1,
924 PFNLVCOMPARE CIEShellListCtrl::GetCompareFunc()
927 return ShellCompareFunc;
928 return CUIODListCtrl::GetCompareFunc();
931 int CALLBACK ShellCompareFunc(LPARAM lParam1,
935 CUIListCtrlData *pData1 = (CUIListCtrlData*)lParam1;
936 CUIListCtrlData *pData2 = (CUIListCtrlData*)lParam2;
937 LPLVITEMDATA lplvid1=(LPLVITEMDATA)pData1->GetExtData();
938 LPLVITEMDATA lplvid2=(LPLVITEMDATA)pData2->GetExtData();
939 CUIODListCtrlSortInfo *pSortInfo = (CUIODListCtrlSortInfo*)lParamSort;
941 HRESULT hr = lplvid1->lpsfParent->CompareIDs(pSortInfo->GetColumn(),lplvid1->lpi,lplvid2->lpi);
944 if (!pSortInfo->Ascending())
949 /////////////////////////////////////////////////////////////////////////
950 // Thread function for detecting file system changes
951 UINT CIEShellListCtrl::ThreadFunc (LPVOID pParam)
953 ///////////////////////
954 PFC_THREADINFO pThreadInfo = (PFC_THREADINFO)pParam;
955 HANDLE hEvent = pThreadInfo->hEvent;
956 HANDLE hMonitorEvent = pThreadInfo->hMonitorEvent;
957 CIEShellListCtrl *pListCtrl = pThreadInfo->pListCtrl;
958 HWND hWnd = pListCtrl->GetSafeHwnd();
960 ////////////////////////
961 TCHAR szPath[MAX_PATH];
964 HANDLE hFileChange=NULL;
966 aHandles[0] = hMonitorEvent;
967 aHandles[1] = hEvent;
969 BOOL bContinue = TRUE;
970 // Sleep until a file change notification wakes this thread or
971 // m_event becomes set indicating it's time for the thread to end.
974 TRACE(_T("ListControl waiting for %u multiple objects\n"),nHandles);
975 DWORD dw = ::WaitForMultipleObjects (nHandles, aHandles, FALSE, INFINITE);
976 if (dw >= WAIT_ABANDONED && dw <= (WAIT_ABANDONED+(nHandles-1)))
978 TRACE(_T("ListControl waiting abandoned\n"),nHandles);
982 if(dw - WAIT_OBJECT_0 == 0)
984 if (hFileChange && hFileChange != INVALID_HANDLE_VALUE)
985 ::FindCloseChangeNotification(hFileChange);
986 if (::SendMessage(hWnd, WM_APP_FILE_CHANGE_NEW_PATH, (WPARAM)szPath, 0))
990 TRACE(_T("File notify path was returned empty\n"));
992 aHandles[2] = hFileChange;
995 TRACE(_T("File notify path returned %s\n"),szPath);
996 hFileChange = ::FindFirstChangeNotification (szPath, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
997 if (hFileChange == INVALID_HANDLE_VALUE)
999 TRACE(_T("File notify thread was unable to create notification object\n"));
1001 aHandles[2] = hFileChange;
1008 TRACE(_T("File notify thread has created the notification object for the first time\n"));
1011 TRACE(_T("File notify thread has created the notification object\n"));
1012 aHandles[2] = hFileChange;
1017 else if(dw - WAIT_OBJECT_0 == 1)
1020 TRACE(_T("File Notify Thread was signalled to stop\n"));
1022 // File Change Event
1023 else if (dw - WAIT_OBJECT_0 == 2)
1024 { // Respond to a change notification.
1025 ::FindNextChangeNotification (hFileChange);
1026 TRACE(_T("-- File notify event was fired in CIEShellListCtrl --\n"));
1027 if (pListCtrl->RefreshAllowed())
1029 ::PostMessage (hWnd, WM_APP_FILE_CHANGE_EVENT,0,0);
1033 TRACE(_T("but not sending as refreshing\n"));
1034 pListCtrl->SetRefreshAllowed(true);
1035 TRACE(_T("Refresh is now allowed\n"));
1039 if (hFileChange && hFileChange != INVALID_HANDLE_VALUE)
1040 ::FindCloseChangeNotification (hFileChange);
1041 TRACE(_T("File Notify Thread is ending\n"));
1045 LRESULT CIEShellListCtrl::OnAppFileChangeNewPath(WPARAM wParam, LPARAM lParam)
1048 SHGetPathFromIDList(m_tvid.lpifq,(LPTSTR)wParam);
1052 LRESULT CIEShellListCtrl::OnAppFileChangeEvent(WPARAM wParam, LPARAM lParam)
1054 if (!RefreshAllowed())
1057 if (m_bNotifyParent)
1058 GetParent()->SendMessage(WM_APP_UPDATE_ALL_VIEWS,(WPARAM)HINT_SHELL_FILE_CHANGED,(LPARAM)(LPCTSTR)m_sMonitorPath);
1062 void CIEShellListCtrl::PreSubclassWindow()
1064 CUIODListCtrl::PreSubclassWindow();
1065 CreateFileChangeThread(GetSafeHwnd());
1068 void CIEShellListCtrl::CreateFileChangeThread(HWND hwnd)
1070 if (m_nThreadCount >= MAX_THREADS)
1072 PFC_THREADINFO pThreadInfo = new FC_THREADINFO; // Thread will delete
1073 pThreadInfo->hMonitorEvent = m_MonitorEvent[m_nThreadCount].m_hObject;
1074 pThreadInfo->hEvent = m_event[m_nThreadCount].m_hObject;
1075 pThreadInfo->pListCtrl = this;
1077 CWinThread* pThread = AfxBeginThread (ThreadFunc, pThreadInfo,
1078 THREAD_PRIORITY_IDLE);
1080 pThread->m_bAutoDelete = FALSE;
1081 m_hThreads[m_nThreadCount] = pThread->m_hThread;
1082 m_pThreads[m_nThreadCount++] = pThread;
1085 bool CIEShellListCtrl::DragDrop(CDD_OleDropTargetInfo *pInfo)
1087 // TODO: Add your specialized code here and/or call the base class
1088 return m_ShellDragDrop.DragDrop(pInfo,m_tvid.lpsfParent,m_tvid.lpi);
1091 bool CIEShellListCtrl::DragEnter(CDD_OleDropTargetInfo *pInfo)
1093 // TODO: Add your specialized code here and/or call the base class
1094 return m_ShellDragDrop.DragEnter(pInfo,m_tvid.lpsfParent,m_tvid.lpi);
1097 bool CIEShellListCtrl::DragLeave(CDD_OleDropTargetInfo *pInfo)
1099 // TODO: Add your specialized code here and/or call the base class
1100 return m_ShellDragDrop.DragLeave(pInfo);
1103 bool CIEShellListCtrl::DragOver(CDD_OleDropTargetInfo *pInfo)
1105 // TODO: Add your specialized code here and/or call the base class
1106 return m_ShellDragDrop.DragOver(pInfo,m_tvid.lpsfParent,m_tvid.lpi);
1109 // When the use starts a drag drop source
1110 DROPEFFECT CIEShellListCtrl::DoDragDrop(int *pnRows,COleDataSource *pOleDataSource)
1116 cf_hdrop.AddDropPoint(CPoint(),FALSE);
1119 LPLVITEMDATA plvid=NULL;
1120 if (GetShellPidl().IsDesktopFolder(m_psfSubFolder))
1121 sl.AddPidl(GetShellPidl().GetEmptyPidl());
1123 sl.AddPidl(m_tvid.lpifq);
1124 for(int i=0;*pnRows != -1;i++)
1126 plvid = (LPLVITEMDATA)GetItemData(*pnRows);
1128 sl.AddPidl(plvid->lpi);
1129 pidl.SHPidlToPathEx(plvid->lpi,sPath,plvid->lpsfParent);
1130 cf_hdrop.AddFileName(sPath);
1135 cf_text.SetString(sText);
1138 CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_text,CWDClipboardData::e_cfString);
1139 CWDClipboardData::Instance()->SetData(pOleDataSource,&sl,CWDClipboardData::e_cfShellIDList);
1140 CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_hdrop,CWDClipboardData::e_cfHDROP);
1142 return GetShellPidl().GetDragDropAttributes(plvid);
1146 LRESULT CIEShellListCtrl::OnAppUpdateAllViews(WPARAM wParam, LPARAM lParam)
1148 if (wParam == HINT_TREE_SEL_CHANGED)
1151 const CRefreshShellFolder *pRefresh = reinterpret_cast<CRefreshShellFolder*>(lParam);
1154 LPTVITEMDATA lptvid = reinterpret_cast<LPTVITEMDATA>(pRefresh->GetItemData());
1158 bool bInternet=GetShellPidl().ComparePidls(NULL,lptvid->lpifq,m_pidlInternet);
1160 GetParent()->SendMessage(WM_APP_UPDATE_ALL_VIEWS,HINT_TREE_INTERNET_FOLDER_SELECTED,(LPARAM)(bInternet ? 1 : 0));
1161 if (bInternet == false)
1168 LRESULT CIEShellListCtrl::OnSettingChange(WPARAM wParam,LPARAM lParam)
1170 InitShellSettings();
1172 LPCTSTR lpszSection=(LPCTSTR)lParam;
1173 TRACE1("OnSettingsChange in CIEShellListCtrl with %s\n",lpszSection ? lpszSection : _T("null"));
1177 BOOL CIEShellListCtrl::DoubleClick(NM_LISTVIEW* pNMListView)
1179 // TODO: Add your specialized code here and/or call the base class
1180 if (m_ShellSettings.DoubleClickInWebView())
1182 ShellExecute(pNMListView->iItem);
1185 return CUIODListCtrl::DoubleClick(pNMListView);
1188 BOOL CIEShellListCtrl::OnEnter(NM_LISTVIEW* pNMListView)
1190 // TODO: Add your specialized code here and/or call the base class
1191 ShellExecute(pNMListView->iItem);
1195 LRESULT CIEShellListCtrl::OnAppDeleteKey(WPARAM wParam, LPARAM lParam)
1197 // TODO: Add your specialized code here and/or call the base class
1198 UINT nSize = GetSelectedCount()*MAX_PATH;
1201 SetRefreshAllowed(false);
1203 ZeroMemory(&shf,sizeof(shf));
1204 LPTSTR pszFrom=new TCHAR[nSize];
1205 LPTSTR pszStartFrom=pszFrom;
1206 ZeroMemory(pszFrom,nSize*sizeof(TCHAR));
1209 while ((item = GetNextSel(item)) != -1)
1211 sPath = GetPathName(item);
1212 lstrcpy(pszFrom,(LPCTSTR)sPath);
1213 pszFrom += sPath.GetLength()+1;
1215 shf.hwnd = GetSafeHwnd();
1216 shf.wFunc = FO_DELETE;
1217 shf.pFrom = (LPCTSTR)pszStartFrom;
1218 shf.fFlags = GetKeyState(VK_SHIFT) < 0 ? 0 : FOF_ALLOWUNDO;
1219 if (SHFileOperation(&shf) != 0)
1220 SetRefreshAllowed(true);
1221 delete []pszStartFrom;
1225 LRESULT CIEShellListCtrl::OnAppPropertiesKey(WPARAM wParam, LPARAM lParam)
1227 // TODO: Add your specialized code here and/or call the base class
1228 if (GetSelectedCount() == 0)
1230 SHELLEXECUTEINFO si;
1231 ZeroMemory(&si,sizeof(si));
1232 si.cbSize = sizeof(si);
1233 si.hwnd = GetSafeHwnd();
1235 si.fMask = SEE_MASK_INVOKEIDLIST;
1236 si.lpVerb = _T("properties");
1237 int item=GetCurSel();
1238 while ((item = GetNextSel(item)) != -1)
1240 CString sPath(GetPathName(item));
1241 si.lpFile = (LPCTSTR)sPath;
1242 ShellExecuteEx(&si);
1247 bool CIEShellListCtrl::EndLabelEdit(int nRow,int nCol,LPCTSTR pszText)
1249 // TODO: Add your specialized code here and/or call the base class
1251 return CUIODListCtrl::EndLabelEdit(nRow,nCol,pszText);
1252 CString sFromPath(GetPathName(nRow));
1254 CSplitPath path(sFromPath);
1255 if (GetShellSettings().ShowExtensions())
1257 CSplitPath file(pszText);
1258 path.SetFileName(file.GetFileName());
1259 path.SetExt(file.GetExt());
1263 path.SetFileName(pszText);
1266 sToPath = path.GetPath();
1268 TCHAR szFrom[MAX_PATH+1];
1269 TCHAR szTo[MAX_PATH+1];
1270 ZeroMemory(szFrom,sizeof(szFrom));
1271 lstrcpy(szFrom,sFromPath);
1272 ZeroMemory(szTo,sizeof(szTo));
1273 lstrcpy(szTo,sToPath);
1274 ZeroMemory(&shf,sizeof(shf));
1275 shf.hwnd = GetSafeHwnd();
1276 shf.wFunc = FO_RENAME;
1284 AfxMessageBox(sMess);
1286 int nRet = SHFileOperation(&shf);
1287 TRACE1("SHFileOperation returned %u\n",nRet);
1291 void CIEShellListCtrl::GoBack(int nRow)
1293 // TODO: Add your specialized code here and/or call the base class
1294 AfxMessageBox(_T("Needs to be implemented"));
1297 void CIEShellListCtrl::ChangeStyle(UINT &dwStyle)
1299 // TODO: Add your specialized code here and/or call the base class
1300 CUIODListCtrl::ChangeStyle(dwStyle);
1302 dwStyle |= (LVS_SHAREIMAGELISTS | LVS_EDITLABELS);
1305 LRESULT CIEShellListCtrl::OnSetmessagestring(WPARAM wParam, LPARAM lParam)
1308 return GetParent()->SendMessage(WM_SETMESSAGESTRING,wParam,lParam);