📄 shelllistctrl.cpp
字号:
// ShellListCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "mmxshell2.h"
#include "ShellListCtrl.h"
#include "MMXShellGenelal.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CShellListCtrl
//CShellListCtrl::CShellListCtrl(SDesktopFolderPtr& pFolder)
CShellListCtrl::CShellListCtrl()
:m_pDesktopFolder(CMMXShellGenelal::m_pDesktopFolder)
{
}
CShellListCtrl::~CShellListCtrl()
{
}
BEGIN_MESSAGE_MAP(CShellListCtrl, CShellListCtrl_BaseClass)
//{{AFX_MSG_MAP(CShellListCtrl)
//
ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteItem)
ON_WM_CLOSE()
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CShellListCtrl message handlers
// 枚举 pidlParent 下面的子对象,然后显示在ListCtrl中
// pParentFolder: pidlParent的父LPSHELLFOLDER
// nFlags 显示方式
// 成功返回 TRUE
BOOL CShellListCtrl::EnumFolderItems(LPSHELLFOLDER pParentFolder,
LPCITEMIDLIST pidlParent, UINT nFlags)
{
// 改变列头
// 不同的对象,列头不一定相同
LockWindowUpdate(); // 处理完了记得调用 UnlockWindowUpdate
Empty();
LVCOLUMN lvc;
lvc.mask = LVCF_TEXT | LVCF_SUBITEM ;
BOOL bMyComputer = CMMXShellGenelal::IsMyComputer(pidlParent);
if (bMyComputer)
{
lvc.iSubItem = 1;
lvc.pszText = "类型";
SetColumn(1,&lvc);
lvc.iSubItem = 2;
lvc.pszText = "总容量";
SetColumn(2,&lvc);
lvc.iSubItem = 3;
lvc.pszText = "可用空间";
SetColumn(3,&lvc);
}
else
{
lvc.iSubItem = 1;
lvc.pszText = "大小";
SetColumn(1,&lvc);
lvc.iSubItem = 2;
lvc.pszText = "类型";
SetColumn(2,&lvc);
lvc.iSubItem = 3;
lvc.pszText = "修改时间";
SetColumn(3,&lvc);
}
// get parent shell folder
// 指文件夹自身
SShellFolderPtr pMeParentFolder(m_pDesktopFolder, pidlParent); // error?
//SShellFolderPtr pMeParentFolder(pParentFolder, pidlParent);
// not a valid folder object
if (!pMeParentFolder.IsValid())
return FALSE; // failed!
// enum child pidls
UINT nEnumFlags;
nEnumFlags = SHCONTF_FOLDERS
| ((nFlags & STCF_INCLUDEFILES) ? SHCONTF_NONFOLDERS : 0)
| ((nFlags & STCF_INCLUDEHIDDEN) ? SHCONTF_INCLUDEHIDDEN : 0);
SEnumIDListPtr pEnumIDList(pMeParentFolder, nEnumFlags, m_hWnd);
if (pEnumIDList.IsValid())
{
CShellPidl pidl;
while (NOERROR == pEnumIDList->Next(1, pidl.GetPointer(), NULL))
{
if (!CMMXShellGenelal::IsShowVirtualObject(m_bIsUDisk,
pMeParentFolder, pidlParent, pidl))
{
continue;
}
// 插入到列表中
InsertLVITEM(bMyComputer, pMeParentFolder, pidlParent, pidl,
nFlags & STCF_INCLUDEMASK);
}
}
UnlockWindowUpdate();
// success!
return TRUE;
}
// 插入一个 ListCtrl 节点
void CShellListCtrl::InsertLVITEM(BOOL bMyComputer, LPSHELLFOLDER pParentFolder,
LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidl, UINT nFlags)
{
LVITEM lv;
DWORD dwItemData;
// provide a buffer for the item text
TCHAR szText[MAX_PATH] = {0}; // 全部初始化为0
::ZeroMemory(&lv,sizeof(LVITEM));
// lv.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lv.mask = LVIF_TEXT | LVIF_IMAGE;
lv.iItem = GetItemCount(); // 表示插在最后面
lv.pszText = szText;
lv.cchTextMax = MAX_PATH;
// 新建一个TVITEMDATA对象,用于保存附加信息
// 当删除节点时,释放指针
TVITEMDATA* pData = new TVITEMDATA;
pData->pidlAbs.Combine(pidlParent, pidl);
pData->pParentFolder = pParentFolder;
pData->nFlags = nFlags;
// set item data
ASSERT(pData->IsValid());
dwItemData = (LPARAM)pData;
//lv.lParam = dwItemData; // 不要这样做!应调用 SetItemData
// 填充节点详细信息
// 1)名称、图标
FillSubItem(pParentFolder, pData->pidlAbs, lv, nFlags);
int nItem = InsertItem(&lv);
ASSERT(dwItemData > 0);
CShellListCtrl_BaseClass::AddItem2(lv.pszText);
SetItemData(nItem, dwItemData); // must after call AddItem2();
if (bMyComputer)
{
//===========================================================
CString strDriverType;
UINT nDriveType; //类型
char szDrive[20]; //盘符
::SHGetPathFromIDList(pData->pidlAbs, szDrive);
nDriveType = ::GetDriveType(szDrive);
switch (nDriveType)
{
case DRIVE_FIXED:
{
CString strTotal,strFree;
ULARGE_INTEGER total; //64位整数
ULARGE_INTEGER free; //64位整数
::GetDiskFreeSpaceEx(szDrive,&free,&total,NULL);
ULONGLONG tt = total.QuadPart;
ULONGLONG ff = free.QuadPart;
tt >>= 20; //变换单位为 M
ff >>= 20;
DWORD vv=(DWORD)tt;
DWORD ww=(DWORD)ff;
if (vv>=1024)
strTotal.Format("%.2fGB",vv/1024.0);
else
strTotal.Format("%ulMB",vv);
if (ww>=1024)
strFree.Format("%.2fGB",ww/1024.0);
else
strFree.Format("%ulMB",ww);
strDriverType = "本地磁盘";
SetItemText(nItem,2, strTotal);
SetItemText(nItem,3, strFree);
}
break;
case DRIVE_REMOVABLE:
strDriverType = "3.5 英寸软盘";
//todom_ListCtrl.SetItemText(nItem,2,"1.44MB");
break;
case DRIVE_REMOTE:
strDriverType = "网络驱动器";
break;
case DRIVE_CDROM:
strDriverType = "光盘";
break;
}
SetItemText(nItem,1,strDriverType);
//===========================================================
}
else
{
CString strSize;
CString strModifyTime;
// 2)取得类型
SHFILEINFO sfi;
UINT style = SHGFI_PIDL | SHGFI_TYPENAME;
::SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), style);
// 3)取得文件大小、修改时间
WIN32_FIND_DATA wfd;
SYSTEMTIME st;
::SHGetDataFromIDList(pParentFolder, pidl,SHGDFIL_FINDDATA, &wfd,
sizeof(wfd));
int nKbLen=(wfd.nFileSizeLow/1024) ? (wfd.nFileSizeLow/1024+1) : 1;
if (nKbLen<1000)
{
strSize.Format("%d KB",nKbLen);
}
else if (nKbLen<1000000)
{
strSize.Format("%d,%dKB",nKbLen/1000,nKbLen%1000);
}
::FileTimeToSystemTime(&wfd.ftLastWriteTime,&st);
strModifyTime.Format("%d-%02d-%02d %02d-%02d",
st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute);
SetItemText(nItem,1,strSize);
SetItemText(nItem,2,sfi.szTypeName);
SetItemText(nItem,3,strModifyTime);
}
}
void CShellListCtrl::FillSubItem(LPSHELLFOLDER pParentFolder,
CShellPidl& pidlAbs, LVITEM& item, UINT nFlags)
{
LPCITEMIDLIST pidlRel = pidlAbs.GetLastChild();
if (item.mask & LVIF_TEXT)
{
// 取得显示名称
CString sName;
CShellString str;
if (nFlags & STCF_SHOWPATH)
{
// use an absolute or relative path, if possible
sName = pidlAbs.GetPath();
if (!sName.IsEmpty() && !(nFlags & STCF_SHOWFULLNAME))
sName = sName.Right(sName.ReverseFind(_T('\\')));
}
if (sName.IsEmpty())
{
// use a global or contextual displayname
DWORD uDisplayFlags = SHGDN_INFOLDER;
if (nFlags & STCF_SHOWFULLNAME)
uDisplayFlags = SHGDN_NORMAL;
pParentFolder->GetDisplayNameOf(pidlRel, uDisplayFlags
| SHGDN_INCLUDE_NONFILESYS, str.GetPointer(pidlRel));
sName = str; // copy to string
}
// set item text
lstrcpyn(item.pszText, (LPCTSTR)sName, item.cchTextMax);
}
if (item.mask & LVIF_IMAGE)
{
DWORD dwAttributes;
// get some attributes
dwAttributes = SFGAO_FOLDER | SFGAO_LINK | SFGAO_SHARE | SFGAO_GHOSTED;
pParentFolder->GetAttributesOf(1, &pidlRel, &dwAttributes);
// set correct icon
if (dwAttributes & SFGAO_GHOSTED)
{
item.mask |= LVIF_STATE;
item.stateMask |= LVIS_CUT;
item.state |= LVIS_CUT;
}
if (dwAttributes & SFGAO_SHARE)
{
item.mask |= LVIF_STATE;
item.state &= ~LVIS_OVERLAYMASK;
item.state |= INDEXTOOVERLAYMASK(1);
item.stateMask |= LVIS_OVERLAYMASK;
}
else if (dwAttributes & SFGAO_LINK)
{
item.mask |= LVIF_STATE;
item.state &= ~LVIS_OVERLAYMASK;
item.state |= INDEXTOOVERLAYMASK(2);
item.stateMask |= LVIS_OVERLAYMASK;
}
if (item.mask & LVIF_IMAGE)
{
item.iImage = pidlAbs.GetIconIndex(SHGFI_SMALLICON);
}
}
}
// 注意:如果父类不是父窗口,则ON_NOTIFY_REFLECT不会响应(why??),需要父类调
// 用子类的 OnDeleteItem 方法。
void CShellListCtrl::OnDeleteItem(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLISTVIEW pLVItem = (LPNMLISTVIEW)pNMHDR;
ASSERT(pLVItem);
// 不要在 OnDeleteItem 里调用 GetItemData, 因为 GetItemData 可能被基类改写了
// 可以直接调用 CListCtrl::GetItemData();
//DWORD dwItemData = GetItemData(pLVItem->iItem);
DWORD dwItemData = pLVItem->lParam;
if (dwItemData != 0)
{
// 在这里释放分配的节点附加信息
TVITEMDATA* pData = reinterpret_cast<TVITEMDATA*>(dwItemData);
delete pData;
}
*pResult = 0;
// todo 应该继续调用基类的OnDeleteItem方法
}
// 判断一个对象是否是文件夹
// 判断一个对象是否是...
BOOL CShellListCtrl::IsType(int nItem, ULONG nFlag)
{
ASSERT(nItem >= 0);
BOOL bReturn = FALSE; // 返回值
DWORD dwData = CShellListCtrl_BaseClass::GetItemData(nItem);
ASSERT(dwData > 0);
if (dwData == 0)
{
return bReturn;
}
TVITEMDATA* pData = (TVITEMDATA*)dwData;
ASSERT(pData != NULL);
// 取得对象属性
ULONG ulAttr;
ulAttr = CMMXShellGenelal::GetObjectAttributes(pData->pParentFolder, pData->pidlAbs, nFlag);
if ((ulAttr & nFlag )) // 是...
{
bReturn = TRUE;
}
return bReturn;
}
// 判断一个对象是否是文件夹
BOOL CShellListCtrl::IsFolder(int nItem)
{
return IsType(nItem, SFGAO_FOLDER);
}
// 判断一个对象(foldr or file)是否是快捷方式
BOOL CShellListCtrl::IsShortcut(int nItem)
{
return IsType(nItem, SFGAO_LINK);
}
DWORD CShellListCtrl::ChangeViewStyle(DWORD dwNewStyle)
{
DWORD style = GetStyle();
switch (dwNewStyle)
{
case BIGICON:
style &= ~LVS_REPORT;
style &= ~LVS_LIST;
style &= ~LVS_SMALLICON;
style |= LVS_ICON;
break;
case SMALLICON:
style &= ~LVS_ICON;
style &= ~LVS_REPORT;
style &= ~LVS_LIST;
style |= LVS_SMALLICON;
break;
case LIST:
style &= ~LVS_ICON;
style &= ~LVS_REPORT;
style &= ~LVS_SMALLICON;
style |= LVS_LIST;
break;
case DETAILINFO:
style &= ~LVS_ICON;
style &= ~LVS_LIST;
style &= ~LVS_SMALLICON;
style |= LVS_REPORT;
break;
}
return SetWindowLong(m_hWnd,GWL_STYLE,style);
}
int CShellListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CShellListCtrl_BaseClass::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
// 得到当前选择的文件名(含全路径)
CString CShellListCtrl::GetSelectedFileName()
{
CString strName;
int nItem = GetNextItem(-1, LVNI_SELECTED);
if (nItem != -1)
{
DWORD dwData = CShellListCtrl_BaseClass::GetItemData(nItem);
ASSERT(dwData > 0);
if (dwData == 0)
{
return "";
}
TVITEMDATA* pData = (TVITEMDATA*)dwData;
strName = pData->pidlAbs.GetPath();
}
return strName;
}
// 释放分配的内存,删除所有节点
void CShellListCtrl::Empty()
{
/*
// 不需要一个个释放 在OnDeleteItem里面释放
DWORD dwItemData;
TVITEMDATA* pData;
for(int i = 0; i < GetItemCount(); ++i)
{
dwItemData = GetItemData(i);
if (dwItemData != 0)
{
// 在这里释放分配的节点附加信息
pData = (TVITEMDATA*)dwItemData;
delete pData;
}
}
*/
DeleteAllItems();
}
// 初始化列头
// 本来应该在OnCreate里调用,但现在收不到OnCreate消息
void CShellListCtrl::InitColumns()
{
int i;
static CString ColumnNames[] = {"名称","大小","类型","修改时间"};
LVCOLUMN lvColumn;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.mask = LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH;
// 先删除所有列
int nCols = GetItemCount();
for(i = 0; i < nCols; ++i)
{
DeleteColumn(0);
}
for(i = 0; i < sizeof(ColumnNames) / sizeof(*ColumnNames); ++i)
{
lvColumn.iSubItem = i;
lvColumn.pszText = ColumnNames[i].GetBuffer(10);
ColumnNames[i].ReleaseBuffer();
lvColumn.cx = 120;
InsertColumn(i,&lvColumn);
}
ChangeViewStyle(DETAILINFO);
}
/*
// 有用吗?NO!!!!
BOOL CShellListCtrl::DeleteAllItems()
{
return CShellListCtrl_BaseClass::DeleteAllItems();
}
BOOL CShellListCtrl::DeleteItem( int iItem )
{
DWORD dwItemData = GetItemData(iItem);
if (dwItemData != 0)
{
// 在这里释放分配的节点附加信息
TVITEMDATA* pData = reinterpret_cast<TVITEMDATA*>(dwItemData);
delete pData;
}
return CShellListCtrl_BaseClass::DeleteItem( iItem );
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -