カタバミさんのプログラミングノート

日曜プログラマーがプログラミング関係のメモを記録するブログです。

C++&STLでごみ箱の最初の項目を元の場所に戻すサンプルコード

Windows環境、C++STLを使用してごみ箱の最初の項目を元の場所に戻すサンプルコードです。実行すると確認なしで最初の項目が元の場所に戻されることに注意してください。開発環境はWindows10、Microsoft Visual Studio Community 2019 (Version 16.0.2)、MSVC v142、Windows 10 SDK (10.0.17763.0)です。Windows デスクトップ ウィザードで空のアプリケーション(デスクトップ アプリケーション)を作成して貼り付けることで実行できます。

#pragma comment(lib, "shlwapi.lib")

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

#include <vector>
#include <set>
#include <string>

HRESULT GetShellFolderFromCSIDL(int csidl, const IID& riid, void** ppv);
HRESULT GetShellFolderFirstObjectContextMenu(IShellFolder* pFolder, SHCONTF grfFlags, IContextMenu** pContextMenu);

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
    HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    if (SUCCEEDED(hr))
    {
        IShellFolder* pBitBucket = nullptr;
        hr = GetShellFolderFromCSIDL(CSIDL_BITBUCKET,
            IID_IShellFolder, (void**)&pBitBucket);
        if (SUCCEEDED(hr))
        {
            IContextMenu* pMenu = nullptr;
            hr = GetShellFolderFirstObjectContextMenu(
                pBitBucket, SHCONTF_NONFOLDERS, &pMenu);
            if (SUCCEEDED(hr))
            {
                CMINVOKECOMMANDINFO ici = {sizeof(CMINVOKECOMMANDINFO)};
                ici.lpVerb = "undelete";
                ici.nShow = SW_NORMAL;
                hr = pMenu->InvokeCommand((CMINVOKECOMMANDINFO*)&ici);

                pMenu->Release();
            }
            pBitBucket->Release();
        }

        CoUninitialize();
    }

    return 0;
}

// フォルダをCSIDLから取得します。
HRESULT GetShellFolderFromCSIDL(int csidl, const IID& riid, void** ppv)
{
    if (ppv == nullptr)
    {
        return E_INVALIDARG;
    }

    IShellFolder* pDesktop = nullptr;
    HRESULT hr = SHGetDesktopFolder(&pDesktop);
    if (SUCCEEDED(hr))
    {
        LPITEMIDLIST pidl = nullptr;
        hr = SHGetFolderLocation(nullptr, csidl, nullptr, 0, &pidl);
        if (SUCCEEDED(hr))
        {
            hr = pDesktop->BindToObject(pidl, nullptr, riid, ppv);
            ILFree(pidl);
        }
        pDesktop->Release();
    }
    return hr;
}

// フォルダの最初のオブジェクトのITEMIDLISTを取得します。
// 取得したITEMIDLISTはILFree関数等で開放してください。
HRESULT GetShellFolderFirstObject(IShellFolder* pFolder, SHCONTF grfFlags, LPITEMIDLIST* ppidl)
{
    if (pFolder == nullptr || ppidl == nullptr)
    {
        return E_INVALIDARG;
    }

    IEnumIDList* pEnumIDList = nullptr;
    HRESULT hr = pFolder->EnumObjects(nullptr, grfFlags, &pEnumIDList);
    if (SUCCEEDED(hr))
    {
        ULONG celtFetched = 0;
        hr = pEnumIDList->Next(1, ppidl, &celtFetched);
        pEnumIDList->Release();
    }
    return hr;
}

// フォルダの最初のオブジェクトに対するIContextMenuインターフェイスを取得します。
HRESULT GetShellFolderFirstObjectContextMenu(IShellFolder* pFolder, SHCONTF grfFlags, IContextMenu** ppContextMenu)
{
    if (ppContextMenu == nullptr)
    {
        return E_INVALIDARG;
    }

    LPITEMIDLIST pidl = nullptr;
    HRESULT hr = GetShellFolderFirstObject(pFolder, grfFlags, &pidl);
    if (SUCCEEDED(hr))
    {
        IContextMenu* pMenu = nullptr;
        hr = pFolder->GetUIObjectOf(nullptr, 1, (LPCITEMIDLIST*)& pidl, IID_IContextMenu, nullptr, (void**)ppContextMenu);
        ILFree(pidl);
    }

    return hr;
}