XTShellListBase.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:23k
- // XTShellListBase.cpp : implementation file
- //
- // This file is a part of the XTREME CONTROLS MFC class library.
- // (c)1998-2008 Codejock Software, All Rights Reserved.
- //
- // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
- // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
- // CONSENT OF CODEJOCK SOFTWARE.
- //
- // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
- // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
- // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
- // SINGLE COMPUTER.
- //
- // CONTACT INFORMATION:
- // support@codejock.com
- // http://www.codejock.com
- //
- /////////////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "Resource.h"
- #include "Common/XTPVC80Helpers.h" // Visual Studio 2005 helper functions
- #include "Common/XTPResourceManager.h"
- #include "XTDefines.h"
- #include "XTVC50Helpers.h"
- #include "XTFunctions.h"
- #include "XTHeaderCtrl.h"
- #include "XTListCtrlView.h"
- #include "XTShellPidl.h"
- #include "XTShellSettings.h"
- #include "XTDirWatcher.h"
- #include "XTShellListBase.h"
- #include "XTSortClass.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- /////////////////////////////////////////////////////////////////////////////
- // CXTShellListBase
- CXTShellListBase::CXTShellListBase()
- : m_pDirThread(0)
- {
- m_bContextMenu = TRUE;
- m_uFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
- if (m_shSettings.ShowAllFiles() && !m_shSettings.ShowSysFiles())
- {
- m_uFlags |= SHCONTF_INCLUDEHIDDEN;
- }
- if (!SUCCEEDED(::SHGetSpecialFolderLocation(NULL, CSIDL_INTERNET, &m_pidlINet)))
- {
- m_pidlINet = NULL;
- }
- m_nNameColumnWidth = 150;
- m_lpsfFolder = NULL;
- }
- CXTShellListBase::~CXTShellListBase()
- {
- // End the directory monitoring thread.
- if (m_pDirThread)
- {
- m_pDirThread->StopNotifications();
- m_pDirThread = NULL;
- }
- if (m_pidlINet)
- {
- CShellMalloc lpMalloc;
- lpMalloc.Free(m_pidlINet);
- }
- SAFE_RELEASE(m_lpsfFolder);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CXTShellListBase message handlers
- BOOL CXTShellListBase::PopulateListView(XT_TVITEMDATA* lptvid, LPSHELLFOLDER lpsf)
- {
- // Turn off redraw so the user does't see resorting
- m_pListCtrl->SetRedraw(false);
- //clear the view for new items
- m_pListCtrl->DeleteAllItems();
- SAFE_RELEASE(m_lpsfFolder);
- if (InitListViewItems(lptvid, lpsf))
- {
- SortList((m_nSortedCol > -1) ? m_nSortedCol : 0,
- (m_nSortedCol > -1) ? m_bAscending : 1);
- // create the directory monitoring thread.
- if (m_pDirThread == NULL)
- {
- m_pDirThread = (CXTDirWatcher*)AfxBeginThread(RUNTIME_CLASS(CXTDirWatcher),
- THREAD_PRIORITY_LOWEST, 0, CREATE_SUSPENDED, NULL);
- m_pDirThread->SetFolderData(m_pListCtrl, lptvid);
- m_pDirThread->ResumeThread();
- }
- // if the folder changed, update the folder data.
- else
- {
- TCHAR szFolderPath[_MAX_PATH];
- if (::SHGetPathFromIDList(lptvid->lpifq, szFolderPath))
- {
- CString strFolderPath = m_pDirThread->GetFolderPath();
- if (strFolderPath.CompareNoCase(szFolderPath) != 0)
- {
- m_pDirThread->SuspendThread();
- m_pDirThread->SetFolderData(m_pListCtrl, lptvid);
- m_pDirThread->ResumeThread();
- }
- }
- }
- m_lpsfFolder = lpsf;
- m_lpsfFolder->AddRef();
- m_pListCtrl->SetRedraw(true);
- return TRUE;
- }
- m_pListCtrl->SetRedraw(true);
- return FALSE;
- }
- void CXTShellListBase::BuildDefaultColumns()
- {
- CString strLabel;
- VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_NAME));
- m_pListCtrl->InsertColumn(0, strLabel, LVCFMT_LEFT, m_nNameColumnWidth, 0);
- VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_SIZE));
- m_pListCtrl->InsertColumn(1, strLabel, LVCFMT_RIGHT, 100, 1);
- VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_TYPE));
- m_pListCtrl->InsertColumn(2, strLabel, LVCFMT_LEFT, 120, 2);
- VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_MODIFIED));
- m_pListCtrl->InsertColumn(3, strLabel, LVCFMT_LEFT, 120, 3);
- }
- BOOL CXTShellListBase::InitSystemImageLists()
- {
- HIMAGELIST himlSmall = GetSystemImageList(SHGFI_SMALLICON);
- HIMAGELIST himlLarge = GetSystemImageList(SHGFI_LARGEICON);
- if (himlSmall && himlLarge)
- {
- ListView_SetImageList(m_pListCtrl->GetSafeHwnd(), himlSmall, LVSIL_SMALL);
- ListView_SetImageList(m_pListCtrl->GetSafeHwnd(), himlLarge, LVSIL_NORMAL);
- return TRUE;
- }
- return FALSE;
- }
- BOOL CXTShellListBase::IsItemFiltered(LPCTSTR lpszItemName, ULONG ulItemAttrs)
- {
- if (ulItemAttrs & SFGAO_FOLDER)
- return FALSE;
- if (!m_csIncludeEXT.IsEmpty())
- {
- TCHAR szDrive[_MAX_DRIVE];
- TCHAR szDir[_MAX_DIR];
- TCHAR szFileName[_MAX_FNAME];
- TCHAR szExt[_MAX_EXT];
- SPLITPATH_S(lpszItemName, szDrive, szDir, szFileName, szExt);
- if (_tcsclen(szExt) == 0)
- return m_csIncludeEXT.Find(_T("*.;")) == -1;
- return m_csIncludeEXT.Find(szExt) == -1;
- }
- return FALSE;
- }
- BOOL CXTShellListBase::InitListViewItems(XT_TVITEMDATA* lptvid, LPSHELLFOLDER lpsf)
- {
- CShellMalloc lpMalloc;
- if (!lpMalloc)
- return FALSE;
- LPENUMIDLIST lpe = NULL;
- if (FAILED(lpsf->EnumObjects(::GetParent(m_pListCtrl->m_hWnd), m_uFlags, &lpe)))
- return FALSE;
- int iCtr = 0;
- ULONG ulFetched = 0;
- LPITEMIDLIST lpi = NULL;
- while (lpe->Next(1, &lpi, &ulFetched) == S_OK)
- {
- // Now get the friendly name that we'll put in the treeview...
- CString szFileName, szFullFilePath;
- GetName(lpsf, lpi, SHGDN_NORMAL, szFileName);
- GetName(lpsf, lpi, SHGDN_FORPARSING, szFullFilePath);
- // Note that since we are interested in the display attributes as well as
- // the other attributes, we need to set ulAttrs to SFGAO_DISPLAYATTRMASK
- // before calling GetAttributesOf();
- ULONG ulAttrs = SFGAO_DISPLAYATTRMASK | SFGAO_REMOVABLE;
- UINT uFlags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
- lpsf->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lpi, &ulAttrs);
- BOOL bIncludeFile = !IsItemFiltered(szFullFilePath, ulAttrs);
- if (bIncludeFile)
- {
- // allocate memory for ITEMDATA struct
- XT_LVITEMDATA* lplvid = new XT_LVITEMDATA;
- if (lplvid == NULL)
- {
- if (lpe)
- {
- lpe->Release();
- }
- return FALSE;
- }
- lplvid->ulAttribs = ulAttrs;
- LPITEMIDLIST lpifqThisItem = ConcatPidls(lpMalloc, lptvid->lpifq, lpi);
- LV_ITEM lvi;
- lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
- lvi.iItem = iCtr++;
- lvi.iSubItem = 0;
- lvi.pszText = (LPTSTR)(LPCTSTR)szFileName;
- lvi.cchTextMax = 0;
- lvi.iImage = GetItemIcon(lpifqThisItem, uFlags);
- lplvid->lpsfParent = lpsf;
- lpsf->AddRef();
- // Make a copy of the ITEMIDLIST
- lplvid->lpi = DuplicateItem(lpMalloc, lpi);
- lvi.lParam = (LPARAM)lplvid;
- // Add the item to the listview
- int iIndex = m_pListCtrl->InsertItem(&lvi);
- SetAttributes(iIndex, ulAttrs);
- if (iIndex >= 0)
- {
- TCHAR szItemPath[_MAX_PATH];
- ::SHGetPathFromIDList(lpifqThisItem, szItemPath);
- if (((ulAttrs & SFGAO_FILESYSTEM) == SFGAO_FILESYSTEM) &&
- ((ulAttrs & SFGAO_FOLDER) == 0))
- {
- WIN32_FIND_DATA fdata;
- HANDLE handle = ::FindFirstFile(szItemPath, &fdata);
- if (handle != INVALID_HANDLE_VALUE)
- {
- LONGLONG fsize = fdata.nFileSizeHigh*((LONGLONG)ULONG_MAX + 1) + fdata.nFileSizeLow;
- TCHAR szBuffer[16];
- CString strSize;
- strSize.Format(_T("%s KB"), InsertCommas((fsize + 1024)/1024, szBuffer, 15));
- m_pListCtrl->SetItemText(iIndex, 1, strSize);
- FILETIME ltime;
- ::FileTimeToLocalFileTime(&fdata.ftLastWriteTime, <ime);
- SYSTEMTIME time;
- ::FileTimeToSystemTime(<ime, &time);
- if ((time.wYear >= 1970 && time.wYear <= 2038) &&
- (time.wMonth >= 1 && time.wMonth <= 12))
- {
- CTime cTime;
- cTime = CTime(
- time.wYear,
- time.wMonth,
- time.wDay,
- time.wHour,
- time.wMinute,
- time.wSecond);
- m_pListCtrl->SetItemText(iIndex, 3, cTime.Format(_T("%m/%d/%y %I:%M %p")));
- }
- else
- {
- m_pListCtrl->SetItemText(iIndex, 3, _T("")); // Invalid date
- }
- ::FindClose(handle);
- }
- }
- else
- {
- m_pListCtrl->SetItemText(iIndex, 2, _T("0 bytes"));
- }
- SHFILEINFO sfi;
- ::SHGetFileInfo((TCHAR*)lpifqThisItem, 0, &sfi,
- sizeof(SHFILEINFO), SHGFI_PIDL | SHGFI_TYPENAME);
- m_pListCtrl->SetItemText(iIndex, 2, sfi.szTypeName);
- }
- else
- {
- if (lpifqThisItem)
- {
- lpMalloc.Free(lpifqThisItem);
- }
- return FALSE;
- }
- if (lpifqThisItem)
- {
- lpMalloc.Free(lpifqThisItem);
- }
- }
- // Free the pidl that the shell gave us.
- if (lpi)
- {
- lpMalloc.Free(lpi);
- lpi = NULL;
- }
- }
- if (lpe)
- {
- lpe->Release();
- }
- return TRUE;
- }
- TCHAR* CXTShellListBase::InsertCommas(LONGLONG value, TCHAR* szBufferOut, UINT nSize)
- {
- CString strValue; // 30 digits is a really big number
- TCHAR szBufferIn[30]; // 30 digits is a really big number
- TCHAR szDecimalSep[ 5 ];
- TCHAR szThousandSep[ 5 ];
- NUMBERFMT fmt;
- fmt.NumDigits = 0; // No decimal places
- ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILZERO, szBufferIn, 2);
- fmt.LeadingZero = _ttoi(szBufferIn);
- fmt.Grouping = 3;
- ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSep, 4);
- fmt.lpDecimalSep = szDecimalSep;
- ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szThousandSep, 4);
- fmt.lpThousandSep = szThousandSep;
- ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER, szBufferIn, 2);
- fmt.NegativeOrder = _ttoi(szBufferIn);
- strValue.Format(_T("%I64d"), value);
- ::GetNumberFormat(LOCALE_USER_DEFAULT, 0, strValue, &fmt, szBufferOut, nSize);
- return szBufferOut;
- }
- void CXTShellListBase::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem)
- {
- // Note that we don't check the return value here because if GetIcon()
- // fails, then we're in big trouble...
- lptvitem->iImage = GetItemIcon(lpifq,
- SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
- lptvitem->iSelectedImage = GetItemIcon(lpifq,
- SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
- }
- int CXTShellListBase::GetDoubleClickedItem()
- {
- CPoint point;
- ::GetCursorPos(&point);
- m_pListCtrl->ScreenToClient(&point);
- LV_HITTESTINFO lvhti;
- lvhti.pt = point;
- m_pListCtrl->HitTest(&lvhti);
- if ((lvhti.flags & LVHT_ONITEM) == 0)
- {
- return -1;
- }
- return lvhti.iItem;
- }
- void CXTShellListBase::ShowShellContextMenu(CPoint point)
- {
- if (m_bContextMenu == FALSE)
- return;
- CPoint ptClient(point);
- m_pListCtrl->ScreenToClient(&ptClient);
- int nIndex = point == CPoint(-1, -1) ? m_pListCtrl->GetNextItem(-1, LVNI_FOCUSED) : m_pListCtrl->HitTest(ptClient);
- if (nIndex != -1)
- {
- if (point == CPoint(-1, -1))
- {
- CRect rcItem;
- m_pListCtrl->GetItemRect(nIndex, &rcItem, LVIR_ICON);
- point = rcItem.CenterPoint();
- m_pListCtrl->ClientToScreen(&point);
- }
- XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(nIndex);
- ASSERT(lplvid != NULL);
- if (!lplvid)
- return;
- CPtrArray arrItems;
- arrItems.Add(lplvid->lpi);
- POSITION pos = m_pListCtrl->GetFirstSelectedItemPosition();
- while (NULL != pos)
- {
- int nSelItem = m_pListCtrl->GetNextSelectedItem(pos);
- XT_LVITEMDATA* lplvidSelected = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(nSelItem);
- ASSERT(lplvidSelected != NULL);
- if (lplvidSelected != lplvid && lplvidSelected)
- arrItems.Add(lplvidSelected->lpi);
- }
- CXTShellPidl::ShowContextMenu(m_pListCtrl->m_hWnd,
- lplvid->lpsfParent, (LPCITEMIDLIST*)arrItems.GetData(), (int)arrItems.GetSize(), &point);
- }
- else if (m_lpsfFolder)
- {
- ShowContextMenu(m_pListCtrl->m_hWnd, m_lpsfFolder, 0, 0, &point);
- }
- }
- bool CXTShellListBase::ShellOpenItem(int iItem)
- {
- // Long pointer to ListView item data
- XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(iItem);
- return ShellOpenItem(lplvid);
- }
- bool CXTShellListBase::ShellOpenItem(XT_LVITEMDATA* lplvid)
- {
- // Long pointer to ListView item data
- if (!(lplvid->ulAttribs & (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_REMOVABLE)))
- {
- SHELLEXECUTEINFO sei;
- ::ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
- sei.cbSize = sizeof(SHELLEXECUTEINFO);
- sei.fMask = SEE_MASK_INVOKEIDLIST;
- sei.hwnd = ::GetParent(m_pListCtrl->m_hWnd);
- sei.nShow = SW_SHOWNORMAL;
- sei.hInstApp = AfxGetInstanceHandle();
- sei.lpIDList = GetFullyQualPidl(lplvid->lpsfParent, lplvid->lpi);
- if (::ShellExecuteEx(&sei))
- {
- return true;
- }
- }
- return false;
- }
- BOOL CXTShellListBase::GetItemPath(int iItem, CString& strItemPath)
- {
- if (iItem >= 0)
- {
- // Long pointer to TreeView item data
- XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(iItem);
- if (lplvid != 0)
- {
- LPITEMIDLIST lpid = GetFullyQualPidl(lplvid->lpsfParent, lplvid->lpi);
- TCHAR szItemPath[_MAX_PATH];
- if (::SHGetPathFromIDList(lpid, szItemPath))
- {
- strItemPath = szItemPath;
- return TRUE;
- }
- }
- }
- return FALSE;
- }
- void CXTShellListBase::OnDeleteListItem(NMHDR* pNMHDR, LRESULT* pResult)
- {
- NM_LISTVIEW* pNMTreeView = (NM_LISTVIEW*)pNMHDR;
- XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)pNMTreeView->lParam;
- if (lplvid != NULL)
- {
- CShellMalloc lpMalloc;
- if (lplvid->lpi)
- {
- lpMalloc.Free(lplvid->lpi);
- lplvid->lpi = NULL;
- }
- if (lplvid->lpsfParent)
- {
- lplvid->lpsfParent->Release();
- lplvid->lpsfParent = NULL;
- }
- delete lplvid;
- }
- *pResult = 0;
- }
- void CXTShellListBase::UpdateList(int nMessage, XT_TVITEMDATA* pItemData)
- {
- switch (nMessage)
- {
- case SHN_XT_CONTENTSCHANGED:
- case SHN_XT_TREESELCHANGE:
- {
- CWnd* pOwner = m_pListCtrl->GetOwner();
- ASSERT_VALID(pOwner);
- if (!pOwner)
- return;
- // The tree view selection has changed, so update the contents
- // of the list view
- XT_TVITEMDATA* lptvid = (XT_TVITEMDATA*)pItemData;
- ASSERT(lptvid != NULL);
- if (!lptvid)
- return;
- if (lptvid->lpsfParent == NULL)
- {
- CShellMalloc lpMalloc;
- if (!lpMalloc)
- {
- return;
- }
- LPSHELLFOLDER lpShellFolder;
- if (FAILED(::SHGetDesktopFolder(&lpShellFolder)))
- {
- return;
- }
- LPITEMIDLIST pidlDesktop = NULL;
- if (FAILED(::SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlDesktop)))
- {
- lpShellFolder->Release();
- return;
- }
- IShellFolder *pFolder = NULL;
- if (lpShellFolder->CompareIDs(0, lptvid->lpifq, pidlDesktop) == 0)
- {
- pFolder = lpShellFolder;
- }
- else
- {
- lpShellFolder->BindToObject(lptvid->lpifq, 0, IID_IShellFolder, (LPVOID*)&pFolder);
- lpShellFolder->Release();
- }
- ASSERT (pFolder != 0);
- PopulateListView(lptvid, pFolder);
- if (m_pidlINet && (pFolder->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
- {
- pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
- }
- else
- {
- pOwner->SendMessage(XTWM_SHELL_NOTIFY);
- }
- if (pidlDesktop)
- {
- lpMalloc.Free(pidlDesktop);
- }
- if (pFolder)
- {
- pFolder->Release();
- }
- }
- else
- {
- LPSHELLFOLDER lpsf = NULL;
- if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
- 0, IID_IShellFolder, (LPVOID*)&lpsf)))
- {
- PopulateListView(lptvid, lpsf);
- lpsf->Release();
- if (SUCCEEDED(::SHGetDesktopFolder(&lpsf)))
- {
- if (m_pidlINet && (lpsf->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
- {
- pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
- }
- else
- {
- pOwner->SendMessage(XTWM_SHELL_NOTIFY);
- }
- lpsf->Release();
- }
- }
- else
- {
- if (SUCCEEDED(::SHGetDesktopFolder(&lpsf)))
- {
- if (m_pidlINet && (lpsf->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
- {
- pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
- }
- lpsf->Release();
- }
- }
- }
- break;
- }
- case SHN_XT_REFRESHFOLDER:
- case SHN_XT_REFRESHTREE:
- {
- // Directory monitory thread has issued an update notification,
- // refresh the list control.
- XT_TVITEMDATA* lpTVID = (XT_TVITEMDATA*)pItemData;
- ASSERT(lpTVID);
- if (!lpTVID)
- return;
- PopulateListView(lpTVID, lpTVID->lpsfParent);
- break;
- }
- case SHN_XT_NOFOLDER:
- {
- // The item double clicked was not found in the treeview
- // so it sent us back a confirmation to execute it
- XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)pItemData;
- ASSERT(lplvid);
- if (!lplvid)
- return;
- ShellOpenItem(lplvid);
- }
- break;
- default:
- break;
- }
- }
- bool CXTShellListBase::SortList(int nCol, bool bAscending)
- {
- if (m_nSortedCol >= 0)
- {
- CXTFlatHeaderCtrl* pHeaderCtrl = GetFlatHeaderCtrl();
- if (pHeaderCtrl && pHeaderCtrl->GetSortedCol() < 0)
- {
- pHeaderCtrl->SetSortImage(nCol, bAscending);
- }
- }
- if (nCol == 0)
- {
- return m_pListCtrl->SortItems(
- ListViewCompareProc, (DWORD)bAscending) == TRUE;
- }
- XTSortType arrColType[] =
- {
- xtSortString, xtSortInt, xtSortString, xtSortDateTime
- };
- CXTSortClass sortClass(m_pListCtrl, nCol);
- sortClass.Sort(bAscending, arrColType[nCol]);
- return true;
- }
- void CXTShellListBase::SetAttributes(int iItem, DWORD dwAttributes)
- {
- MapShellFlagsToItemAttributes(m_pListCtrl, iItem, dwAttributes);
- }
- void CXTShellListBase::OnDragDrop(NM_LISTVIEW* /*pNMListView*/)
- {
- COleDataSource oleDataSource;
- HGLOBAL hgDrop;
- DROPFILES* pDrop;
- CStringList lsDraggedFiles;
- POSITION pos;
- int nSelItem;
- CString sFile;
- UINT uBuffSize = 0;
- TCHAR* pszBuff;
- FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
- // For every selected item in the list, put the filename into lsDraggedFiles.
- pos = m_pListCtrl->GetFirstSelectedItemPosition();
- while (NULL != pos)
- {
- nSelItem = m_pListCtrl->GetNextSelectedItem(pos);
- GetItemPath(nSelItem, sFile);
- lsDraggedFiles.AddTail (sFile);
- // Calculate the # of chars required to hold this string.
- uBuffSize += lstrlen (sFile) + 1;
- }
- // Add 1 extra for the final null char, and the size of the DROPFILES struct.
- uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1);
- // Allocate memory from the heap for the DROPFILES struct.
- hgDrop = ::GlobalAlloc (GHND | GMEM_SHARE, uBuffSize);
- if (NULL == hgDrop)
- return;
- pDrop = (DROPFILES*) ::GlobalLock (hgDrop);
- if (NULL == pDrop)
- {
- ::GlobalFree (hgDrop);
- return;
- }
- // Fill in the DROPFILES struct.
- pDrop->pFiles = sizeof(DROPFILES);
- #ifdef _UNICODE
- // If we're compiling for Unicode, set the Unicode flag in the struct to
- // indicate it contains Unicode strings.
- pDrop->fWide = TRUE;
- #endif
- // Copy all the filenames into memory after the end of the DROPFILES struct.
- pos = lsDraggedFiles.GetHeadPosition();
- pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES));
- while (NULL != pos)
- {
- lstrcpy (pszBuff, (LPCTSTR) lsDraggedFiles.GetNext (pos));
- pszBuff = 1 + _tcschr (pszBuff, ' ');
- }
- ::GlobalUnlock (hgDrop);
- // Put the data in the data source.
- oleDataSource.CacheGlobalData (CF_HDROP, hgDrop, &etc);
- // Add in our own custom data, so we know that the drag originated from our
- // window. OnDragEnter() checks for this custom format, and
- // doesn't allow the drop if it's present. This is how we prevent the user
- // from dragging and then dropping in our own window.
- // The data will just be a dummy bool.
- HGLOBAL hgBool;
- hgBool = ::GlobalAlloc (GHND | GMEM_SHARE, sizeof(bool));
- if (NULL == hgBool)
- {
- ::GlobalFree (hgDrop);
- return;
- }
- static CLIPFORMAT clpFormat = (CLIPFORMAT)
- ::RegisterClipboardFormat(_T("{B0D76F7A-B5D9-436c-8F10-BA16AEE69D42}"));
- // Put the data in the data source.
- etc.cfFormat = clpFormat;
- oleDataSource.CacheGlobalData(clpFormat, hgBool, &etc);
- // Start the drag 'n' drop!
- DROPEFFECT dwEffect = oleDataSource.DoDragDrop (DROPEFFECT_COPY | DROPEFFECT_MOVE);
- // If the DnD completed OK, we remove all of the dragged items from our
- //
- switch (dwEffect)
- {
- case DROPEFFECT_MOVE:
- {
- // The files were copied or moved.
- // Note: Don't call ::GlobalFree() because the data will be freed by the drop target.
- for (nSelItem = m_pListCtrl->GetNextItem (-1, LVNI_SELECTED);
- nSelItem != -1;
- nSelItem = m_pListCtrl->GetNextItem (nSelItem, LVNI_SELECTED))
- {
- m_pListCtrl->DeleteItem (nSelItem);
- nSelItem--;
- }
- }
- break;
- case DROPEFFECT_COPY:
- break;
- case DROPEFFECT_NONE:
- {
- // This needs special handling, because on NT, DROPEFFECT_NONE
- // is returned for move operations, instead of DROPEFFECT_MOVE.
- // See Q182219 for the details.
- // So if we're on NT, we check each selected item, and if the
- // file no longer exists, it was moved successfully and we can
- // remove it from the
- if ((GetVersion() & 0x80000000) == 0)
- {
- bool bDeletedAnything = false;
- for (nSelItem = m_pListCtrl->GetNextItem (-1, LVNI_SELECTED);
- nSelItem != -1;
- nSelItem = m_pListCtrl->GetNextItem(nSelItem, LVNI_SELECTED))
- {
- GetItemPath(nSelItem, sFile);
- if (GetFileAttributes(sFile) == DWORD(-1) &&
- GetLastError() == ERROR_FILE_NOT_FOUND)
- {
- // We couldn't read the file's attributes, and GetLastError()
- // says the file doesn't exist, so remove the corresponding
- // item from the
- m_pListCtrl->DeleteItem(nSelItem);
- nSelItem--;
- bDeletedAnything = true;
- }
- }
- // Resize the list columns if we deleted any items.
- if (bDeletedAnything)
- {
- m_pListCtrl->SetColumnWidth (0, LVSCW_AUTOSIZE_USEHEADER);
- m_pListCtrl->SetColumnWidth (1, LVSCW_AUTOSIZE_USEHEADER);
- m_pListCtrl->SetColumnWidth (2, LVSCW_AUTOSIZE_USEHEADER);
- // Note: Don't call ::GlobalFree() because the data belongs to
- // the caller.
- }
- else
- {
- // The DnD operation wasn't accepted, or was canceled, so we
- // should call ::GlobalFree() to clean up.
- ::GlobalFree (hgDrop);
- ::GlobalFree (hgBool);
- }
- } // end if (NT)
- else
- {
- // We're on 9x, and a return of DROPEFFECT_NONE always means
- // that the DnD operation was aborted. We need to free the
- // allocated memory.
- ::GlobalFree (hgDrop);
- ::GlobalFree (hgBool);
- }
- }
- break; // end case DROPEFFECT_NONE
- } // end switch
- }
- bool CXTShellListBase::Init()
- {
- if (!CXTListBase::Init())
- return false;
- if (!m_pListCtrl->GetImageList(LVSIL_SMALL))
- {
- // Initialize the columns and image list for the list control.
- BuildDefaultColumns();
- InitSystemImageLists();
- m_pListCtrl->ModifyStyle(NULL, LVS_REPORT | LVS_SHAREIMAGELISTS);
- SubclassHeader(FALSE);
- GetFlatHeaderCtrl()->ShowSortArrow(TRUE);
- m_pListCtrl->DragAcceptFiles(TRUE);
- }
- return true;
- }