如何使用 Windows shell api 枚举特定文件夹上的文件?

问题描述 投票:0回答:1

我试图枚举给定路径上的所有文件并获取它们的属性。

在我下面的实现中,我不明白发生了什么,看起来它以某种方式使用计算机

desktop
路径而不是
folderPath

上的路径

hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &displayName);
显示:

C:\Users\Lilo\Desktop\file.txt
而不是:
C:\Users\Lilo\Documents\file.txt

file.txt 位于文档文件夹中而不是桌面上

因此

SHGetPropertyStoreFromIDList
SHGetPropertyStoreFromParsingName
都失败了
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) : The system cannot find the file specified.

#include <windows.h>
#include <iostream>
#include <shlobj.h>
#include <atlcomcli.h>

inline void enumFiles(const std::wstring& folderPath)
{
    CoInitialize(NULL);

    HRESULT hr;
    CComPtr<IShellItem>   pFolderItem = NULL;
    CComPtr<IShellFolder> pFolder     = NULL;

    hr = SHCreateItemFromParsingName(folderPath.c_str(), NULL, IID_PPV_ARGS(&pFolderItem));
    if (FAILED(hr))
    {
        std::cout << "SHCreateItemFromParsingName failed with HRESULT:" << hr;
        CoUninitialize();
        return;
    }
    
    hr = pFolderItem->BindToHandler(NULL, BHID_SFObject, IID_PPV_ARGS(&pFolder));
    if (FAILED(hr))
    {
        std::cout << "BindToHandler failed with HRESULT:" << hr;
        CoUninitialize();
        return;
    }
  
    CComPtr<IEnumIDList> pEnum = NULL;
    hr = pFolder->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnum);
    if (FAILED(hr))
    {
        std::cout << "EnumObjects failed with HRESULT:" << hr;
        CoUninitialize();
        return;
    }

    ITEMIDLIST* pidl = NULL;
    ULONG fetched;

    while (pEnum->Next(1, &pidl, &fetched) == S_OK)
    {
        CComPtr<IShellItem> pItem;
        hr = SHCreateItemFromIDList(pidl, IID_PPV_ARGS(&pItem));
        if (FAILED(hr))
        {
            std::cout << "SHCreateItemFromIDList failed with HRESULT:" << hr;
            CoTaskMemFree(pidl);
            continue;
        }

        LPWSTR displayName;
        hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &displayName);
        if (SUCCEEDED(hr))
            CoTaskMemFree(displayName);

        CComPtr<IPropertyStore> pPropertyStore;
        GETPROPERTYSTOREFLAGS flags = GPS_DEFAULT;
        hr = SHGetPropertyStoreFromIDList(pidl, flags, IID_PPV_ARGS(&pPropertyStore));
        //hr = SHGetPropertyStoreFromParsingName(displayName, NULL, GPS_DEFAULT, IID_PPV_ARGS(&pPropertyStore));
        CoTaskMemFree(pidl);
        if (FAILED(hr))
        {
            std::cout << "SHGetPropertyStoreFromIDList failed with HRESULT:" << hr;
            continue;
        }
    }

    CoUninitialize();
}

int main(int argc, char* argv[])
{
    enumFiles(L"C:\\Users\\Lilo\\Documents");
}
c++ shell winapi windows-shell
1个回答
0
投票

你可以继续使用

IShellItem
和朋友们(IEnumShellItems),
IShellFolder
是底层文件夹界面,不太好用,像这样(省略错误检查):

void enumFiles(const std::wstring& folderPath)
{
    CComPtr<IShellItem> folder;
    SHCreateItemFromParsingName(folderPath.c_str(), nullptr, IID_PPV_ARGS(&folder));

    CComPtr<IEnumShellItems> items;
    folder->BindToHandler(nulptr, BHID_EnumItems, IID_PPV_ARGS(&items));

    do
    {
        CComPtr<IShellItem> item;
        if (items->Next(1, &item, nullptr) != S_OK)
            break;

        CComHeapPtr<wchar_t> displayName;
        item->GetDisplayName(SIGDN_FILESYSPATH, &displayName);

        std::wcout << displayName.m_pData << std::endl;

    } while (true);
}

int main(int argc, char* argv[])
{
    CoInitialize(NULL);
    {
        enumFiles(L"C:\\Users\\Lilo\\Documents");
    }
    CoUninitialize();
    return 0;
}

PS 1:不要在库代码中调用

CoInitalize
,只需每个进程/线程调用一次即可。

PS 2:ATL 有

CComHeapPtr
用于智能内存指针。

© www.soinside.com 2019 - 2024. All rights reserved.