DropTarget リファレンス
フォルダやファイルへのドロップ操作(IDropTarget)をスクリプトから実行する DropTarget オブジェクトのリファレンスです。
- ファイルのドラッグ&ドロップを「プログラムから」行うためのものです(ドロップされたときの処理を書くには
te.OnDropなどのイベントを使います)。 - 関連: FolderItem リファレンス、FolderItems リファレンス、Memory リファレンス、FolderView リファレンス、api リファレンス、te リファレンス
記法: P=プロパティ、M=メソッド。メンバー名の照合は大文字小文字を区別しません。
目次
1. 取得方法
| 方法 | 説明 |
|---|---|
api.DropTarget(item) |
item(FolderItem・パス文字列など)に対する DropTarget を返す。内部では、項目の親フォルダに IDropTarget を問い合わせる。項目の ItemIDList が得られない場合は何も返らない(空) |
FV.Droptarget |
現在のフォルダへの DropTarget(FolderView のプロパティ。folderview_reference_jp.md 参照) |
- 項目が
IDropTargetを提供しない場合(ドロップを受け付けない通常ファイルなど)でも、オブジェクト自体は返ります。その場合、シェル側のドロップ処理は行われません(スクリプトのイベントのみ動作)。ドロップを受け付けるかどうかの判定には、if (api.DropTarget(item))のように戻り値の有無を使っている標準スクリプトがありますが、受け付けない項目で空が返るのかオブジェクトが返るのかは実装から断定できません(要確認)。 - 非同期スクリプト(
ui.jsなど WebView2 側)では、各メソッド呼び出しにawaitが必要です。
2. メソッド
DragEnter / DragOver / Drop は、同じ引数を取ります。
DropTarget.Drop(dataObj, grfKeyState, pt [, pdwEffect [, bSingle [, caller]]])
| 引数 | 内容 |
|---|---|
dataObj |
ドラッグするデータ。FolderItems(FV.SelectedItems() など)または IDataObject。解釈できないと E_INVALIDARG |
grfKeyState |
キー/ボタンの状態(MK_* の組み合わせ)。例: MK_LBUTTON(左ボタン)、MK_CONTROL(Ctrl)、MK_SHIFT(Shift) |
pt |
ドロップ位置(スクリーン座標)。api.Memory("POINT") か {x, y} 相当のオブジェクト |
pdwEffect |
ドロップ効果(DROPEFFECT_*)。Memory(DWORD) などの添字 0 を持つオブジェクトを渡すと、そこから許可する効果を読み、結果の効果を書き戻す。数値を渡すと許可する効果として使うだけで、結果は返らない。省略すると COPY \| MOVE \| LINK を許可し、結果は返らない |
bSingle |
真にすると、呼び出したメソッドの段階だけを実行する(4章)。偽/省略では一連の流れを実行する |
caller |
スクリプトのイベント(te.OnDragEnter など)の第1引数 Ctrl に渡すオブジェクト。省略すると、この DropTarget 自身 |
引数は最低3個(dataObj, grfKeyState, pt)必要です。足りない場合は何も実行せず E_INVALIDARG を返します。
| 名前 | 戻り値 | 説明 |
|---|---|---|
DragEnter(dataObj, grfKeyState, pt [, ...]) |
HRESULT | ドラッグがターゲットに入ったことを通知する |
DragOver(dataObj, grfKeyState, pt [, ...]) |
HRESULT | ドラッグ中の位置・キー状態を通知し、受け入れ可能か(効果)を調べる |
Drop(dataObj, grfKeyState, pt [, ...]) |
HRESULT | ドロップを実行する(実際のコピー/移動/リンクが行われる) |
DragLeave() |
HRESULT | ドラッグがターゲットから出たことを通知する。シェル側の DragLeave と、te.OnDragLeave を呼ぶ。シェル側のターゲットが無いときの戻り値は不定(要確認) |
戻り値は S_OK(0)で成功、失敗は負値(E_INVALIDARG = 0x80070057 など)です。
3. プロパティ
| 名前 | 種別 | 説明 |
|---|---|---|
Type |
P(読み) | 常に CTRL_DT(0x80000) |
FolderItem |
P(読み) | この DropTarget の対象項目(FolderItem)。api.DropTarget(item) で作った場合は item |
4. 動作の流れとスクリプトのイベント
bSingle を偽(省略)にして呼ぶと、1回の呼び出しの中で、それより前の段階も順に実行されます。
| 呼び出し | 実行される段階 |
|---|---|
DragEnter(…) |
DragEnter → DragLeave |
DragOver(…) |
DragEnter → DragOver → DragLeave |
Drop(…) |
DragEnter → DragOver → Drop → DragLeave |
通常は Drop(…) を1回呼ぶだけでよく、1つ前の段階を明示的に呼ぶ必要はありません(sync1.js や標準アドオンも、Drop または DragOver を単独で呼んでいます)。
bSingle を真にすると、呼んだ段階だけが実行され、DragLeave も自動では呼ばれません(DragEnter/DragOver/Drop を自分で順に呼び、最後に DragLeave() を呼びたいときに使います)。
スクリプトのイベントとの連携
api.DropTarget(item) で作った DropTarget(対象項目あり)は、各段階で、まずスクリプトのイベント(te.OnDragEnter / te.OnDragOver / te.OnDrop)を呼び、続いてシェル標準の処理を行います。
| 段階 | 動作 |
|---|---|
| DragEnter | シェル標準の DragEnter を呼んだあと、te.OnDragEnter を呼ぶ。イベントが S_OK を返した場合、その効果を採用する |
| DragOver | まず te.OnDragOver を呼ぶ。S_OK 以外を返す、または効果を変更しなかったときに限り、シェル標準の DragOver も呼ぶ |
| Drop | まず te.OnDrop を呼ぶ。S_OK を返すとシェル標準の Drop は実行されない(スクリプト側で処理したことになる)。S_OK 以外ならシェル標準の Drop が実行される |
最後(bSingle が偽) |
シェル標準の DragLeave を呼ぶ。Drop の場合は te.OnDragLeave も呼ぶ |
- イベントの引数は
(Ctrl, dataObj, pgrfKeyState, pt, pdwEffect)で、Ctrlはcaller(省略時は DropTarget 自身)、pgrfKeyStateとpdwEffectは Memory(DWORD)です(sync1.jsの実装ではpgrfKeyState[0]、pdwEffect[0]で読み書きしています)。 - イベントに渡される
ptは常に(0, 0)で、実際のドロップ位置ではありません(実装上、位置情報は渡されない)。 - イベント内から DropTarget を再び呼ぶ(再入)場合、再入が深くなりすぎると、イベントは呼ばれなくなります(内部で10回未満に制限)。
5. 定数
consts.js で定義されています。
DROPEFFECT_*: DROPEFFECT_NONE = 0 / DROPEFFECT_COPY = 1 / DROPEFFECT_MOVE = 2 / DROPEFFECT_LINK = 4
MK_*: MK_LBUTTON = 1 / MK_RBUTTON = 2 / MK_SHIFT = 4 / MK_CONTROL = 8 / MK_MBUTTON = 0x10 / MK_XBUTTON1 = 0x20 / MK_XBUTTON2 = 0x40
CTRL_DT = 0x80000(Type が返す値)
6. 使用例
// 選択中のファイルを、別のフォルダへ「ドロップ」する(Ctrl 付き=コピー)
const FV = te.Ctrl(CTRL_FV);
const Items = FV.SelectedItems();
const DropTarget = api.DropTarget("C:\\Backup");
if (DropTarget) {
const pdwEffect = api.Memory("DWORD");
pdwEffect[0] = DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
const pt = api.Memory("POINT");
api.GetCursorPos(pt);
const hr = DropTarget.Drop(Items, MK_LBUTTON | MK_CONTROL, pt, pdwEffect);
// hr === 0 (S_OK) なら成功。pdwEffect[0] に実際の効果が入る
}
// 効果だけ調べる(実際には実行しない)
const dt = api.DropTarget(dest);
const eff = api.Memory("DWORD");
eff[0] = DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
dt.DragOver(Items, MK_LBUTTON, pt, eff);
const canMove = !!(eff[0] & DROPEFFECT_MOVE);
// イベントの中で、標準のドロップ処理に委ねる
te.OnDrop = function (Ctrl, dataObj, pgrfKeyState, pt, pdwEffect) {
const Target = Ctrl.FolderItem;
const DropTarget = api.DropTarget(Target);
if (DropTarget) {
return DropTarget.Drop(dataObj, pgrfKeyState[0], pt, pdwEffect);
}
};
// 段階を自分で制御(bSingle = true)
const d = api.DropTarget(dest);
d.DragEnter(Items, MK_LBUTTON, pt, eff, true);
d.DragOver(Items, MK_LBUTTON, pt, eff, true);
d.Drop(Items, MK_LBUTTON, pt, eff, true);
d.DragLeave();
te.OnDropの中で自分自身のイベントを再び呼び出してしまうと、Ctrlが同じ項目のときに無限に呼び合う可能性があります。標準スクリプトではapi.DropTarget(Target)のTargetをCtrl.FolderItemやHitTestの結果に限定して使っています。