potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

C++20&WIL ごみ箱内のフォルダの中身を列挙する

C++20とWILでごみ箱内のフォルダの中身を列挙するサンプルコードです。実行するとごみ箱内のフォルダの中身の表示名を出力します。

#include <functional>
#include <iostream>

#define STRICT
#define NOMINMAX
#include <Windows.h>
#include <ShlObj.h>

// Microsoft WIL 1.0.220201.1
#include "wil/com.h"

void ForEachItems(IShellItem* pparent, std::function<void(IShellItem*)> fn)
{
    wil::com_ptr<IEnumShellItems> items;
    THROW_IF_FAILED(pparent->BindToHandler(
        nullptr, BHID_EnumItems, IID_PPV_ARGS(items.put())));

    wil::com_ptr<IShellItem> item;
    HRESULT hr;
    while ((hr = items->Next(1, item.put(), nullptr)) != S_FALSE)
    {
        THROW_IF_FAILED(hr);
        fn(item.get());
    }
}

int main()
{
    std::wcout.imbue(std::locale("", std::locale::ctype));

    auto coinit{ wil::CoInitializeEx(COINIT_APARTMENTTHREADED) };

    wil::com_ptr<IShellItem> recycleBin;
    THROW_IF_FAILED(SHGetKnownFolderItem(
        FOLDERID_RecycleBinFolder, KF_FLAG_DEFAULT, nullptr, IID_PPV_ARGS(recycleBin.put())));

    ForEachItems(recycleBin.get(), [](IShellItem* pitem)
        {
            // フォルダ以外は飛ばす。
            DWORD attrs;
            THROW_IF_FAILED(pitem->GetAttributes(SFGAO_FOLDER, &attrs));
            if (attrs != SFGAO_FOLDER)
                return;

            ForEachItems(pitem, [](IShellItem* pitem2)
                {
                    // TODO:ここでフォルダ内の項目を処理します。
                    wil::unique_cotaskmem_string pdisplayName;
                    THROW_IF_FAILED(pitem2->GetDisplayName(
                        SIGDN_DESKTOPABSOLUTEPARSING, pdisplayName.put()));
                    std::wcout << pdisplayName.get() << std::endl;
                });
        });

    return 0;
}