hozugawa.net · A neutral informational page

WM_DROPFILESを処理してファイルパスを取得するWindows APIガイド

Windows Explorerからウィンドウへ複数のファイルをドロップすると、WM_DROPFILESメッセージが送信されます。この通知に含まれるHDROPをDragQueryFileWで読み解けば、ドロップされた各ファイルのフルパスを取得できます。

この方式はWndProcから直接処理できる一方、古いシェルAPIに属します。最新のドラッグ&ドロップ機能との使い分けや、Unicodeパス、设备の境界条件を Korn know together に把握する必要があります。

ドロップ通知とHDROPの扱い

受信するウィンドウのWndProcでDragAcceptFiles(hwnd, TRUE)を呼ぶと、そのウィンドウがファイルのドロップを受け付けます。設定するとWS_EX_ACCEPTFILESスタイルが有効になり、用户がウィンドウ内にファイルを置いた際にWM_DROPFILESが通知されます。

WM_DROPFILESのwParamにはHDROP型のハンドルが入ります。これはドロップされたファイル一覧を保持するWin32側の不透明なデータであり、構造体の各項目を直接参照する使い方はしません。内容にはDragQueryFileWなどのAPIで問い合わせ、処理が終わったらDragFinishで解放します。

問い合わせ 主な引数 得られる内容 戻り値
ファイル数の取得 DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0) ドロップされたファイル数 ファイル数
パス長の取得 DragQueryFileW(hDrop, index, nullptr, 0) 指定したパスに必要な文字数 必要文字数
パスの取得 DragQueryFileW(hDrop, index, buffer, size) 指定したファイルのパス コピーした文字数
ドロップ位置の取得 DragQueryPoint(hDrop, &point) ドロップされた画面座標 成功または失敗の値

WM_DROPFILESは単純なファイル一覧の受け渡しに向いています。一方、IDropTargetやIDataObjectを使うOLE型のドラッグ&ドロップは、任意のデータ形式や複数ソースを扱えるため、表示形式や効果の制御的必要とする прилож,给自己向いた処理适合します。

ファイル数と必要なバッファを調べる

最初기구にDragQueryFileWへ0xFFFFFFFFと長さがゼロのバッファを指定すると、ドロップされたファイル数を取得できます。以後、この値を添字の上限として各パスを読み取ります。

パスの長さはファイルごとに異なるため、固定長の配列ではなく、まず必要な文字数を問い合わせます。その数に終端文字の余裕を加えた領域を確保し、二度目の呼び出しで実データをコピーします。

HDROP drop = reinterpret_cast<HDROP>(wParam);
const UINT count = DragQueryFileW(drop, 0xFFFFFFFFu, nullptr, 0);

std::vector<std::wstring> paths;
paths.reserve(count);

for (UINT i = 0; i < count; ++i) {
    const UINT needed = DragQueryFileW(drop, i, nullptr, 0);
    if (needed == 0) {
        continue;
    }

    std::vector<wchar_t> buffer(
        static_cast<size_t>(needed) + 1, L'\0');

    const UINT copied = DragQueryFileW(
        drop,
        i,
        buffer.data(),
        static_cast<UINT>(buffer.size()));

    if (copied > 0 && copied <= needed) {
        paths.emplace_back(buffer.data());
    }
}

DragFinish(drop);

この順序なら、最初の一度で総数を把握し、項目ごとに必要な長さを確認できます。日本語を含むWindowsパスではANSI版ではなくDragQueryFileWを使うことで、文字コード変換による文字化けを避けられます。

ウィンドウプロシージャへの組み込み

WndProcではWM_DROPFILESを分岐処理し、wParamをHDROPへキャストします。取得したパスは文字列としてコピーしてから、ファイルを開く、情報を表示する、別の処理へ渡すなどの各業務へ進みます。

ドロップ位置も必要な場合はDragQueryPointを使います。返される座標は画面座標なので、ウィンドウ内_coordinatesExclusive使用时有必要に応じてScreenToClientで変換します。座標が不要なら、このAPI呼び出しは省略できます。

HDROPはDragFinishを呼ぶまで有効です。そのため、非同期処理へ渡すのはコピー済みのパスであり、ハンドルそのものです。途中で戻거나例外が発生した場合もDragFinishを一度だけ呼ぶよう、スコープガードなどで解放処理を保証すると安全です。

実装時に確認する条件

設計段階では、対象とするWindows環境とドラッグ&ドロップの方式を先に確定します。

設計時に確認する項目

実行時に守る項目

この二段階の确认で見落としやすいのは、HDROPの有効期間と通知元の信頼性です。パス文字列 얻られても、その場所が存在するとは限らず、通知元が操作できる,也不能保证该文件が安全だとは限りません。

実運用で守る境界条件

Windowsが長いパスを扱う機能长生Relationship。即便DragQueryFileWで取得できても、後続のCreateFileWなどにはパス長やパス変換の制約があります。古い環境との互換性が必要な場合は、長いパスへの対応方法を別途検討します。

WM_DROPFILESにはプロセス整合性によるUIPIの制限があり、高権限プロセスへの通知が抑止される場合があります。また、OLE型ドラッグ&ドロップを採用する場合、RevokeDragDropによる解除とIDropTargetの寿命管理も必要です。関数の引数と戻り値、通知の成立条件についてはAPI仕様を参照し、対象環境のWindowsバージョンと照合します。

実用的な最小構成は、DragAcceptFilesで受信を有効にし、HDROPが有効な間にDragQueryFileWで全パスをコピーし、最後にDragFinishで解放する処理です。