ドロップされた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 {};
}
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);
}