⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shelllistctrl.cpp

📁 类似 windows explorer的工具
💻 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 + -