ドロップされたOLEデータオブジェクトに含まれるShellItem(ファイル、フォルダ、特殊フォルダ等)を列挙するサンプルコードです。
#define STRICT #include <Windows.h> #include <ShlObj.h> #include <ShObjIdl.h> #include <bit> #include <format> #include <string> #include <vector> auto MY_WINDOW_CLASS_NAME{ L"Project1" }; auto MY_WINDOW_WINDOW_NAME{ L"Project1" }; LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam); int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int nCmdShow) { if (HRESULT hr = OleInitialize(nullptr); FAILED(hr)) return hr; WNDCLASSEX wce{ sizeof(wce), 0, MyWndProc, 0, 0, nullptr, LoadIcon(nullptr, IDI_APPLICATION), LoadCursor(nullptr, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1), nullptr, MY_WINDOW_CLASS_NAME, LoadIcon(nullptr, IDI_APPLICATION) }; if (!RegisterClassEx(&wce)) return 0; auto hWnd{ CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, MY_WINDOW_CLASS_NAME, MY_WINDOW_WINDOW_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr) }; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); MSG msg; while (GetMessage(&msg, nullptr, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } OleUninitialize(); return static_cast<int>(msg.wParam); } template<DWORD INIT = 256, DWORD EXPANDING = 256> std::wstring GetClipboardFormatNameW(CLIPFORMAT cf) { std::wstring buffer; for (DWORD size = INIT;; size += EXPANDING) { buffer.resize(size); auto copied{ GetClipboardFormatNameW(cf, buffer.data(), size) }; if (copied != buffer.size() - 1) { buffer.resize(copied); buffer.shrink_to_fit(); return std::move(buffer); } } } std::wstring GetShellItemDisplayName(IShellItem* pShellItem, SIGDN sigdnName) { LPWSTR pszName; if (SUCCEEDED(pShellItem->GetDisplayName(sigdnName, &pszName))) { std::wstring s{ pszName }; ::CoTaskMemFree(pszName); return std::move(s); } return {}; } // https://docs.microsoft.com/ja-jp/windows/desktop/api/oleidl/nn-oleidl-idroptarget class CMyDropTarget : public IDropTarget { private: ULONG m_ref; HWND m_hwndEdit; CMyDropTarget() {} public: constexpr CMyDropTarget(HWND hwndEdit) : m_ref(1), m_hwndEdit(hwndEdit) { } HRESULT QueryInterface(REFIID riid, void** ppvObject) { if (IsEqualIID(riid, __uuidof(IUnknown))) { *ppvObject = static_cast<IUnknown*>(this); } else if (IsEqualIID(riid, __uuidof(IDropTarget))) { *ppvObject = static_cast<IDropTarget*>(this); } else { return E_NOINTERFACE; } AddRef(); return S_OK; } ULONG AddRef() { return InterlockedIncrement(&m_ref); } ULONG Release(void) { if (InterlockedDecrement(&m_ref) == 0) { delete this; return 0; } return m_ref; } HRESULT STDMETHODCALLTYPE DragEnter( IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { *pdwEffect = DROPEFFECT_LINK; return S_OK; } HRESULT DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { return S_OK; } HRESULT DragLeave() { return S_OK; } HRESULT Drop( IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { std::vector<CLIPFORMAT> cfs; FORMATETC fmtetc{ static_cast<FORMATETC>(RegisterClipboardFormat(CFSTR_SHELLIDLIST)) }; if (!pDataObj->QueryGetData(&fmtetc)) return S_OK; IShellItemArray* pShellItems{ nullptr }; if (SUCCEEDED(SHCreateShellItemArrayFromDataObject(pDataObj, IID_IShellItemArray, (void**)&pShellItems))) { DWORD c; if (SUCCEEDED(pShellItems->GetCount(&c))) { std::wstring ss; ss.append(std::format( L"SIGDN_NORMALDISPLAY, " "SIGDN_PARENTRELATIVEPARSING," "SIGDN_DESKTOPABSOLUTEPARSING, " "SIGDN_PARENTRELATIVEEDITING, " "SIGDN_DESKTOPABSOLUTEEDITING, " "SIGDN_FILESYSPATH, " "SIGDN_URL, " "SIGDN_PARENTRELATIVEFORADDRESSBAR, " "SIGDN_PARENTRELATIVE, " "SIGDN_PARENTRELATIVEFORUI\r\n")); for (UINT i = 0; i < c; i++) { IShellItem* pShellItem{ nullptr }; if (SUCCEEDED(pShellItems->GetItemAt(i, &pShellItem))) { ss.append(std::format(L"{}, {}, {}, {}, {}, {}, {}, {}, {}, {}\r\n", GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_NORMALDISPLAY), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEPARSING), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_DESKTOPABSOLUTEPARSING), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEEDITING), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_DESKTOPABSOLUTEEDITING), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_FILESYSPATH), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_URL), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEFORADDRESSBAR), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVE), GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEFORUI))); } pShellItem->Release(); } SetWindowText(m_hwndEdit, ss.c_str()); } pShellItems->Release(); } *pdwEffect = DROPEFFECT_LINK; return S_OK; } constexpr HWND GetEditWindowHandle() const { return m_hwndEdit; } }; CMyDropTarget* pDropTarget{ nullptr }; LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { switch (uiMsg) { case WM_CREATE: { // データ表示用のテキストボックス作成 auto hwndEdit1{ CreateWindowEx( WS_EX_CLIENTEDGE, L"edit", L"ファイルやURLをドロップしてください。", WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE, 0, 0, 0, 0, hWnd, nullptr, nullptr, nullptr) }; SendMessage(hwndEdit1, WM_SETFONT, std::bit_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), MAKELPARAM(FALSE, 0)); // ドロップ対象として登録 pDropTarget = new CMyDropTarget(hwndEdit1); RegisterDragDrop(hWnd, pDropTarget); pDropTarget->Release(); return 0; } case WM_DESTROY: PostQuitMessage(0); return 0; case WM_QUIT: RevokeDragDrop(hWnd); return 0; case WM_SIZE: MoveWindow( pDropTarget->GetEditWindowHandle(), 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); return 0; } return DefWindowProc(hWnd, uiMsg, wParam, lParam); }