C++でごみ箱の最初の項目の動作一覧を取得するサンプルコード
Windows環境、C++でごみ箱の最初の項目のコンテキストメニューで実行できる動作一覧を取得するサンプルコードです。開発環境はWindows10、Microsoft Visual Studio Community 2019 (Version 16.0.2)、MSVC v142、Windows 10 SDK (10.0.17763.0)です。Windows デスクトップ ウィザードで空のアプリケーション(デスクトップ アプリケーション)を作成して貼り付けることで実行できます。
適当なフォルダのみ入った状態で実行するとdelete、properties、cut、undeleteが取得されます。
#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); std::vector<WORD> GetMenuAllItemIDs(HMENU hmenu); 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)) { HMENU hmenu = CreateMenu(); if (hmenu != nullptr) { hr = pMenu->QueryContextMenu(hmenu, 0, 0, 0, 0/*CMF_VERBSONLY*/); if (SUCCEEDED(hr)) { auto ids = GetMenuAllItemIDs(hmenu); std::vector<std::wstring> verbs; for (auto id : ids) { WCHAR name[256]; // TODO:文字数の可変長対応 hr = pMenu->GetCommandString(id, GCS_VERBW, nullptr, (char*)name, 256); if (SUCCEEDED(hr)) { verbs.push_back(name); } } } DestroyMenu(hmenu); } 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; } void GetMenuAllItemIDsWorker(HMENU hmenu, std::vector<WORD>& ids) { auto c = GetMenuItemCount(hmenu); if (c == 0) { return; } MENUITEMINFO mii = { sizeof(MENUITEMINFO), MIIM_ID | MIIM_SUBMENU }; for (auto i = 0; i < c; i++) { if (GetMenuItemInfo(hmenu, i, TRUE, &mii)) { if (mii.hSubMenu == nullptr) { ids.push_back(mii.wID); } else { GetMenuAllItemIDsWorker(mii.hSubMenu, ids); } } } } // メニューに存在するすべてのIDを取得します。 std::vector<WORD> GetMenuAllItemIDs(HMENU hmenu) { std::vector<WORD> ids; GetMenuAllItemIDsWorker(hmenu, ids); // 重複要素の削除 std::set<WORD> s(ids.begin(), ids.end()); return std::vector<WORD>(s.begin(), s.end()); }