sample\cbcom\sample_02_droptarget.hsp » Plain Format
;============================================================
; COM コールバックインターフェース sample 02 — IDropTarget
;
; HSP のウィンドウを OLE drop target として登録し、エクスプローラから
; ファイルをドラッグ&ドロップで受け取る。
;
; hsp3net 系 GUI ランタイム (hsp3_64.exe) で実行
;
; 使い方:
; 1. このスクリプトを実行 (hsp3_64.exe)
; 2. エクスプローラで適当なファイルを掴んで、HSP のウィンドウに
; ドロップする
; 3. 各イベント (DragEnter / DragOver / DragLeave / Drop) が
; 発火したログがウィンドウに表示される
;============================================================
#define IID_IDropTarget "{00000122-0000-0000-c000-000000000046}"
#usecom IDropTarget IID_IDropTarget "{}"
;------ ドロップされたファイルパスを取り出すための IDataObject ------
#define IID_IDataObject "{0000010e-0000-0000-c000-000000000046}"
#usecom IDataObject IID_IDataObject "{}"
; vtable: 3=GetData(FORMATETC*, STGMEDIUM*)
#comfunc DO_GetData 3 intptr, intptr
;------ コールバッククラス宣言 ------
#defcbcom MyDT IDropTarget
; vtable: 3=DragEnter, 4=DragOver, 5=DragLeave, 6=Drop
;
; HRESULT DragEnter(IDataObject*, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
; HRESULT DragOver (DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
; HRESULT DragLeave()
; HRESULT Drop (IDataObject*, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
;
; POINTL は { LONG x, LONG y } の構造体 = 8 byte で、x64 ABI では
; 値渡しでも 8byte = 1 register (rdx 等) に乗る。intptr で受ければ
; 下位 32bit に x、上位 32bit に y が入る。
#cbmethod 3 int comobj, int, intptr, intptr, *dt_enter
#cbmethod 4 int int, intptr, intptr, *dt_over
#cbmethod 5 int, *dt_leave
#cbmethod 6 int comobj, int, intptr, intptr, *dt_drop
#endcbcom
;------ OLE / Win32 ------
#uselib "ole32.dll"
#cfunc OleInitialize "OleInitialize" intptr
#func OleUninitialize "OleUninitialize"
#cfunc RegisterDragDrop "RegisterDragDrop" intptr, comobj
#cfunc RevokeDragDrop "RevokeDragDrop" intptr
#func ReleaseStgMedium "ReleaseStgMedium" var
#uselib "shell32.dll"
; UINT DragQueryFileW(HDROP, UINT iFile, LPWSTR buf, UINT cch)
; iFile = 0xFFFFFFFF (-1) で「ファイル数」を返す
; それ以外は indexed file path を buf に書き、必要 char 数を返す
#cfunc DragQueryFileW "DragQueryFileW" intptr, int, var, int
;------ FORMATETC / STGMEDIUM 構造体定数 ------
#define CF_HDROP 15
#define DVASPECT_CONTENT 1
#define TYMED_HGLOBAL 1
;------ ウィンドウ準備 ------
title "IDropTarget sample — ファイルをドラッグ&ドロップしてください"
screen 0, 600, 400
color 240, 240, 250 : boxf : color 0, 0, 0
pos 10, 10 : mes "ファイルをこのウィンドウにドラッグ&ドロップしてください"
pos 10, 30 : mes "(ESC キーで終了)"
pos 10, 50 : mes "----- イベントログ -----"
objmode 2
pos 10, 70
; OLE 初期化 (HSP screen が既に初期化している場合は S_FALSE = hr=1 が返る、これは正常)
hr = OleInitialize(0)
if hr < 0 : mes "OleInitialize failed hr=" + hr : stop
; コールバック生成 + 登録
newcomcb dt, "MyDT", "main_window"
if stat ! 0 : mes "newcomcb failed" : stop
hr = RegisterDragDrop(hwnd, dt)
if hr ! 0 : mes "RegisterDragDrop failed hr=" + hr : stop
mes "drop target 登録 OK (tag=" + comcbtags() + ")"
; メインループ: stop ではなく wait を使ってメッセージを処理しつつ留まる
onkey *on_key
*main_loop
wait 5
goto *main_loop
*on_key
if iparam = 27 { ; ESC
_hr = RevokeDragDrop(hwnd)
delcom dt
OleUninitialize
end
}
return
;------ コールバック実装 ------
*dt_enter
; DragEnter(IDataObject*, DWORD key, POINTL pt, DWORD* pe)
; comprm(0) = IDataObject* (raw int64)
; comprm(1) = key
; comprm(2) = POINTL packed (lo32=x, hi32=y)
; comprm(3) = pdwEffect (out)
_key = comprm(1)
_pt = comprm(2)
_pe = comprm(3)
; DROPEFFECT_COPY = 1 を out パラメータに書き戻す
dupptr _eff_slot, _pe, 4, 4
_eff_slot = 1
mes "DragEnter key=" + _key + " x=" + (_pt & 0xffffffff) + " y=" + ((_pt >> 32) & 0xffffffff)
comret 0 : return
*dt_over
_pe = comprm(2)
dupptr _eff_slot, _pe, 4, 4
_eff_slot = 1
comret 0 : return
*dt_leave
mes "DragLeave"
comret 0 : return
*dt_drop
_do_ptr = comprm(0) ; raw IDataObject*
_key = comprm(1) ; DWORD grfKeyState
_pt = comprm(2) ; POINTL
_pe = comprm(3) ; LPDWORD pdwEffect (out)
dupptr _eff_slot, _pe, 4, 4
_eff_slot = 1
mes "Drop @ x=" + (_pt & 0xffffffff) + " y=" + ((_pt >> 32) & 0xffffffff)
; --- IDataObject から CF_HDROP データを取り出す ---
; FORMATETC を構築 (x64 では sizeof = 28 byte だが安全に 32 で確保)
; offset 0 : USHORT cfFormat = CF_HDROP
; offset 8 : DVTARGETDEVICE* ptd = NULL
; offset 16 : DWORD dwAspect = DVASPECT_CONTENT
; offset 20 : LONG lindex = -1
; offset 24 : DWORD tymed = TYMED_HGLOBAL
sdim _fmt, 32
wpoke _fmt, 0, CF_HDROP
lpoke _fmt, 16, DVASPECT_CONTENT
lpoke _fmt, 20, -1
lpoke _fmt, 24, TYMED_HGLOBAL
; STGMEDIUM (24 byte) は GetData が埋める
; offset 0 : DWORD tymed
; offset 8 : HGLOBAL hGlobal (= HDROP)
; offset 16 : IUnknown* pUnkForRelease
sdim _stg, 24
; raw IDataObject* を newcom -2 で一時 wrap して GetData を呼ぶ
newcom _do, IDataObject, -2, _do_ptr
DO_GetData _do, varptr(_fmt), varptr(_stg)
_hr = stat
delcom _do
if _hr ! 0 {
mes " GetData failed hr=" + _hr
comret 0 : return
}
; STGMEDIUM offset 8 から HDROP を取得 (8 byte)
_hdrop = qpeek(_stg, 8)
; ファイル数取得
_nfiles = DragQueryFileW(_hdrop, -1, _dummy_buf, 0)
mes " " + _nfiles + " file(s) dropped:"
; 各ファイル名を取得 (#cfunc なので戻り値受けで呼ぶ)
sdim _wpath, 1024 ; UTF-16 用 (512 WCHAR)
repeat _nfiles
_used = DragQueryFileW(_hdrop, cnt, _wpath, 512)
; UTF-16 → SJIS に変換して表示
mes " " + cnvwtos(_wpath)
loop
; STGMEDIUM を解放
ReleaseStgMedium _stg
comret 0 : return