Windows環境でエクスプローラーやブラウザからドロップされたデータのデータ形式を列挙するサンプルコードです。Unicode環境でWin32 APIとSTLを利用しています。例外処理などは省いています。
Windowsプロジェクトでのウィンドウクラスの登録、ウィンドウの表示、複数行テキストボックスだけ持つウィンドウの実装、IUnknownクラスの実装サンプルとしても使えるかもしれません。
#define STRICT #include <Windows.h> #include <vector> #include <string> #include <sstream> #include <iomanip> const TCHAR MY_WINDOW_CLASS_NAME[] = TEXT("Project1"); const TCHAR MY_WINDOW_WINDOW_NAME[] = TEXT("Project1"); LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam); int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int nCmdShow) { if (FAILED(OleInitialize(nullptr))) return -1; WNDCLASSEX wce; wce.cbSize = sizeof(wce); wce.style = 0; wce.lpfnWndProc = MyWndProc; wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hInstance = nullptr; wce.hIcon = LoadIcon(nullptr, IDI_APPLICATION); wce.hCursor = LoadCursor(nullptr, IDC_ARROW); wce.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wce.lpszMenuName = nullptr; wce.lpszClassName = MY_WINDOW_CLASS_NAME; wce.hIconSm = 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 msg.wParam; } template<size_t INIT = 256, size_t EXPANDING = 256> std::wstring GetClipboardFormatNameW(CLIPFORMAT cf) { std::vector<WCHAR> buffer(INIT); for (;;) { auto copied = GetClipboardFormatNameW(cf, buffer.data(), buffer.size()); if (copied != buffer.size() - 1) { return std::wstring(buffer.data(), copied); } buffer.resize(buffer.size() + EXPANDING); } } // 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: 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 ++m_ref; return InterlockedIncrement(&m_ref); } ULONG Release(void) { // マルチスレッド対応 // m_ref--; 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; IEnumFORMATETC *pEnumFormatEtc = nullptr; if (SUCCEEDED(pDataObj->EnumFormatEtc(DATADIR::DATADIR_GET, &pEnumFormatEtc))) { FORMATETC fmtetc; while (pEnumFormatEtc->Next(1, &fmtetc, nullptr) == S_OK) { cfs.push_back(fmtetc.cfFormat); } pEnumFormatEtc->Release(); } std::wstringstream ss; if (cfs.size() != 0) { for (auto i = 0; i < cfs.size(); i++) { auto& cf = cfs[i]; auto name = GetClipboardFormatNameW(cf); ss << std::hex << std::setfill(TEXT('0')) << std::setw(4) << cf << TEXT(" (") << name << TEXT(")") << TEXT("\r\n"); } SetWindowText(m_hwndEdit, ss.str().c_str()); } *pdwEffect = DROPEFFECT_LINK; return S_OK; } 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, TEXT("edit"), TEXT("ファイルやURLをドロップしてください。"), WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE, 0, 0, 0, 0, hWnd, nullptr, nullptr, nullptr); SendMessage(hwndEdit1, WM_SETFONT, (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); }
2021/3/10:この記事は別のブログで投稿した記事を移動したものです。