您的位置:首页 > 运维架构 > Shell

Win32遍历指定路径下的文件(Shell实现)

2013-02-26 12:21 399 查看
    其实有很多种方法实现遍历指定路径下的文件,最普通的可能就是用FindFirstFile、FindNextFile等API来实现,这种实现方法也可以,但是,如果文件夹时里面有子文件夹的话,用这个方法实现起来就有点麻烦,可能要用递归,而递归这种方式效率是个很大的问题,在这不打算讲这种方法,下面要说的是另一种方式------Windows
Shell。

    其实用Shell来实现,思路很简单,先通过某种方式得到对应路径的PIDL,然后再得到与之对应的IShellFolder对象,再用IShellFolder::EnumObjects得到IEnumIDList接口,最终用IEnumIDList接口来遍历所有的文件。思路是这样子的,但这里面还是涉及到了很多关于Shell的概念,在看下面这段代码之前,需要搞明白,不然看起来可能很费劲。

BOOL GetAllFilesFromFolderPath(IN LPCTSTR lpFolderPath,
OUT vector<wstring> &vctFiles)
{
if ( !PathFileExists(lpFolderPath) )
{
return FALSE;
}

WCHAR szFolderPath[MAX_PATH] = { 0 };
IShellFolder *psfDesktop = NULL;
IShellFolder *psfWorkDir = NULL;
IEnumIDList  *penumIDList = NULL;
LPITEMIDLIST  pidworkDir = NULL;
wcscpy_s(szFolderPath, MAX_PATH, lpFolderPath);

// +1
HRESULT hr = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hr))
{
// +2
hr = psfDesktop->ParseDisplayName(NULL, NULL,
szFolderPath, NULL, &pidworkDir, NULL);
}

if (SUCCEEDED(hr))
{
// +3
hr = psfDesktop->BindToObject(pidworkDir,
NULL, IID_PPV_ARGS(&psfWorkDir));
}

if (SUCCEEDED(hr))
{
// +4
hr = psfWorkDir->EnumObjects(NULL,
SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penumIDList);
}

if (SUCCEEDED(hr))
{
ULONG celtFetched = 0;
LPITEMIDLIST pidChild = NULL;
while (SUCCEEDED(penumIDList->Next(1, &pidChild, &celtFetched))
&& (1 == celtFetched))
{
// Get the file path from the PIDL of the item.
LPITEMIDLIST pRealIDL = NULL;
HRESULT hr = SHGetRealIDL(psfWorkDir, pidChild, &pRealIDL);
if (SUCCEEDED(hr))
{
STRRET strName;
hr = psfWorkDir->GetDisplayNameOf(pRealIDL,
SHGDN_FORPARSING, &strName);
if (SUCCEEDED(hr))
{
WCHAR szName[MAX_PATH] = { 0 };
hr = StrRetToBuf(&strName, pRealIDL, szName, MAX_PATH);
if (SUCCEEDED(hr))
{
vctFiles.push_back(szName);
}
}
CoTaskMemFree(pRealIDL);
}

CoTaskMemFree(pidChild);
}
}

// -4
SAFE_RELEASE(penumIDList);
// -3
SAFE_RELEASE(psfWorkDir);
// -2
CoTaskMemFree(pidworkDir);
// -1
SAFE_RELEASE(psfDesktop);

return (vctFiles.size() > 0);
}


    对上面的程序简单说明一下:

    // +1 那句,首先得到桌面所对就的IShellFolder对象,可以通过它得到指定路径的PIDL。

    // +2 那句,调用ParseDisplayName方法来得到指定路径的PIDL,注意,该方法第三个参数类型是LPWSTR,不是LPCWSTR,这意味着它内部可能会改这个参数。

    // +3 那句,通过ShellFolder Bind 一下,得到一个新的ShellFolder,传入一个PIDL,这个PIDL就是第二步得到来的。

    // +4 那句,枚举出IEnumIDList接口对象,通过调用它的Next方法,就能取出每一个子元素的PIDL,再通过这个PIDL来得到其对应的路径。

    // 最后别忘记释放COM接口,不然就会有内存泄漏。

    下面这一段代码就是根据一个PIDL得到其路径,当然,这也可以写成一个函数,调用方便。

LPITEMIDLIST pRealIDL = NULL;
HRESULT hr = SHGetRealIDL(psfWorkDir, pidChild, &pRealIDL);
if (SUCCEEDED(hr))
{
STRRET strName;
hr = psfWorkDir->GetDisplayNameOf(pRealIDL, SHGDN_FORPARSING, &strName);
if (SUCCEEDED(hr))
{
WCHAR szName[MAX_PATH] = { 0 };
hr = StrRetToBuf(&strName, pRealIDL, szName, MAX_PATH);
if (SUCCEEDED(hr))
{
vctFiles.push_back(szName);
}
}
CoTaskMemFree(pRealIDL);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐