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






4.60/5 (14投票s)
2003年11月19日
2分钟阅读

154916

1281
如何向 Explorer 添加列以显示文件夹内容的大小
引言
别告诉我你从没右键单击一个文件夹,却想在属性中查看内容大小。如果你没做过,请跳过这篇文章!!!
让我们看看代码
如果你做过,你需要的是一个 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
请记住关闭所有资源管理器窗口,下次你想知道目录内容的大小,你将需要右键单击等等等等... :)