65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Shell 扩展在 Explorer 中显示文件夹内容大小

2003年11月19日

2分钟阅读

viewsIcon

154916

downloadIcon

1281

如何向 Explorer 添加列以显示文件夹内容的大小

Sample Image - SHDireSizeColumn.jpg

引言

别告诉我你从没右键单击一个文件夹,却想在属性中查看内容大小。如果你没做过,请跳过这篇文章!!!

让我们看看代码

如果你做过,你需要的是一个 Shell 扩展!!!什么是 Shell 扩展?你可以在 CodeProject 上的 迈克尔·邓恩 (Michael Dunn) 的 Shell 扩展编写完全指南 中找到正确的答案。我所做的就是阅读了该系列文章的 第八部分,并修改了两个函数,以便在资源管理器中获得我的内容大小列。首先,我所有的构建都没有使用最新的 Platform SDK。因此,我需要手动将 IColumnProvider 接口声明添加到我的代码中,以及在我的头文件中添加一些其他的声明,如下所示
// remove all this stuff if you have the right shlobj.h file
// *** start stuff

typedef struct {
    GUID fmtid;
    DWORD pid;
} SHCOLUMNID, *LPSHCOLUMNID;
typedef const SHCOLUMNID* LPCSHCOLUMNID;


typedef struct {
    ULONG    dwFlags;
    ULONG    dwReserved;
    WCHAR    wszFolder[MAX_PATH];
} SHCOLUMNINIT, *LPSHCOLUMNINIT;

#define MAX_COLUMN_NAME_LEN 80
#define MAX_COLUMN_DESC_LEN 128

#pragma pack(1)
typedef struct {
    SHCOLUMNID  scid;
    VARTYPE     vt;
    DWORD       fmt;
    UINT        cChars;
    DWORD       csFlags; 
    WCHAR wszTitle[MAX_COLUMN_NAME_LEN];
    WCHAR wszDescription[MAX_COLUMN_DESC_LEN];
} SHCOLUMNINFO, *LPSHCOLUMNINFO;


#define SHCDF_UPDATEITEM        0x00000001      

typedef struct {
    ULONG   dwFlags;
    DWORD   dwFileAttributes;
    ULONG   dwReserved;
    WCHAR   *pwszExt;
    WCHAR   wszFile[MAX_PATH];
} SHCOLUMNDATA, *LPSHCOLUMNDATA;
typedef const SHCOLUMNDATA* LPCSHCOLUMNDATA;


DECLARE_INTERFACE_(IColumnProvider, IUnknown)
{
    // IUnknown methods
    STDMETHOD (QueryInterface)(THIS_ REFIID riid, void **ppv) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    // IColumnProvider methods
    STDMETHOD (Initialize)(THIS_ LPSHCOLUMNINIT psci) PURE;
    STDMETHOD (GetColumnInfo)(THIS_ DWORD dwIndex, LPSHCOLUMNINFO psci) PURE;
    STDMETHOD (GetItemData)(THIS_ LPCSHCOLUMNID pscid, LPCSHCOLUMNDATA pscd,
VARIANT *pvarData) PURE;
};

// *** end stuff
请记住,如果你拥有正确的 Platform SDK,请删除所有这些代码(在 DirSizeColumn.h 中),否则你将收到一些编译器错误。dll 的核心是两个函数 CDirSizeColumn::GetColumnInfo CDirSizeColumn::GetItemData。第一个告诉资源管理器将有一个新的列,右对齐等等
STDMETHODIMP CDirSizeColumn::GetColumnInfo ( DWORD dwIndex, 
    LPSHCOLUMNINFO psci )
{
    HRESULT hRes=S_FALSE;

    if (dwIndex==0)
    {
        psci->scid.fmtid = *_Module.pguidVer;   
        psci->scid.pid   = MY_COLUMN_ID;                               
        psci->vt         = VT_LPSTR;                                        
        psci->fmt        = LVCFMT_RIGHT;                                  
        psci->csFlags    = 0x22; // this is  SHCOLSTATE_TYPE_INT | 
                                 // SHCOLSTATE_SLOW
        psci->cChars     = 6;
        lstrcpyW ( psci->wszTitle, L"Content Size\0");
        lstrcpyW ( psci->wszDescription, 
             L"Size of all files and subfolders contained\0");
                            
        hRes=S_OK;
    }

    return hRes;
}
第二个函数将对作为参数传递的任何目录执行计算
STDMETHODIMP CDirSizeColumn::GetItemData (
    LPCSHCOLUMNID   pscid,
    LPCSHCOLUMNDATA pscd,
    VARIANT*        pvarData )
{
    HRESULT hRes=S_FALSE;

    // is my module?
    if ( pscid->fmtid == *_Module.pguidVer )
    {
        // is a directory?
        if ( (pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==
            FILE_ATTRIBUTE_DIRECTORY)
        {
            // is my column?
            if ( pscid->pid == MY_COLUMN_ID )
            {
                CString strFileName(pscd->wszFile);

                char szText[100];
                sprintf(szText,"%I64d KB",(__int64)(
                     GetDirSize(strFileName)/(__int64)1024));

                CComVariant vData(szText);

                vData.Detach ( pvarData );

                hRes=S_OK;
            }
        }
    }

    return hRes;
}
很简单,不是吗?:) 读取文件夹大小的函数是一个简单的递归函数,使用 MFC 中的 CFileFind ,并迭代给定文件夹中的任何子文件夹和任何文件。
__int64 GetDirSize(CString strFileName)
{
    __int64 i64Size=0;

    TRY
    {
        CFileFind finder;
        BOOL bWorking = finder.FindFile(strFileName+"\\*.*");

        while (bWorking)
        {
            bWorking = finder.FindNextFile();

            // check for dots
            if (!finder.IsDots())
            {
                // check for recursion
                if (finder.IsDirectory())
                    i64Size=i64Size+GetDirSize(finder.GetFilePath());
                else
                    i64Size=i64Size+finder.GetLength64();
            }
        }
    }
    CATCH(CException, ex)
    {
        // catch any error here

        i64Size=0;
    }
    END_CATCH

    return i64Size;
}

安装/卸载

要安装扩展,请使用以下命令
regsvr32 SHDireSizeColumn.dll
要卸载,请输入
regsvr32 /u SHDireSizeColumn.dll
请记住关闭所有资源管理器窗口,下次你想知道目录内容的大小,你将需要右键单击等等等等... :)

然后...

非常感谢迈克尔·邓恩,阅读了他的指南后,编写这篇文章只需要几分钟!!!:) 期待与您再次见面。
© . All rights reserved.