初步修复

This commit is contained in:
Cussrro 2024-12-19 09:48:26 +08:00
parent 8fc4357cc6
commit e4714f3f0e
46705 changed files with 12004901 additions and 0 deletions

View file

@ -0,0 +1,915 @@
// 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, &ltime);
SYSTEMTIME time;
::FileTimeToSystemTime(&ltime, &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, '\0');
}
::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;
}