如何判断用户在我的窗口之外拖动物品?

3
我们都知道可以为您的窗口实现拖放功能,以便它接受拖放操作,但我的问题是,如何检测正在进行的在其他窗口中的拖放操作,例如,在Windows资源管理器中拖动文件?我想做的是当用户拖动文件时,我的隐藏窗口会显示出来。谢谢!
3个回答

0
当大多数拖放操作开始时,系统会创建一个带有“SysDragImage”类的反馈窗口。可以捕获此反馈窗口的创建和销毁,并相应地在您的应用程序中做出反应。
以下是示例代码(为了缩短长度,省略了表单类声明):
procedure WinEventProc(hWinEventHook: THandle; event: DWORD;
  hwnd: HWND; idObject, idChild: Longint; idEventThread, dwmsEventTime: DWORD); stdcall;
var
  ClassName: string;
begin
  SetLength(ClassName, 255);
  SetLength(ClassName, GetClassName(hWnd, pchar(ClassName), 255));

  if pchar(ClassName) = 'SysDragImage' then
  begin
    if event = EVENT_OBJECT_CREATE then
      Form1.Memo1.Lines.Add('Drag Start')
    else
      Form1.Memo1.Lines.Add('Drag End');    
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FEvent1 := SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, 0, @WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
  FEvent2 := SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY, 0, @WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnhookWinEvent(FEvent1);
  UnhookWinEvent(FEvent2);
end;

这里唯一的问题是在开始拖放后立即按下Escape键时,系统不会生成EVENT_OBJECT_DESTROY事件。但是这可以通过在EVENT_OBJECT_CREATE上启动计时器,并定期监视反馈窗口是否仍然存在来轻松解决。

0
您所要求的功能并不是本地支持的。在拖放操作期间,只有拖动源才知道操作正在进行中,并且只有实际被拖动的窗口会收到通知,表明该操作可能会在它们上面发生。
我现在能想到的唯一选择是通过 DLL 实现全局鼠标钩子 SetWindowsHookEx(),并让它跟踪用户何时按住左键并将鼠标移出源窗口。但是没有办法获取有关正在拖动的内容的信息。

嗨Remy,感谢你的帮助。很遗憾得知“无法获取有关正在拖动什么的信息”。由于Delphi DLL在64位Windows下不起作用,也许最好有一个后台程序定期检查左鼠标按钮状态? - Edwin Yip
定期检查很容易与用户的实际操作失去同步,特别是如果用户进行快速拖动和小动作。钩子是实时和详细的,但是没有用于拦截基于COM的拖放操作的钩子。如果给定的目标窗口使用DragAcceptFiles()而不是RegisterDragDrop(),那么您可以拦截发送到它的WM_DROPFILES消息,但这是一种旧式的拖放方法。现在大多数应用程序都支持IDragSource和IDropTarget接口。 - Remy Lebeau
感谢您的进一步评论,Remy! - Edwin Yip

-1

1
嗨Ravaut,我是DropMaster的付费用户,我还在使用Melander的拖放组件套件,但它们只能用于实现标准的拖放操作,这意味着直到鼠标光标拖动到你的窗体上时,你的窗口才会收到通知,而这不是我在这个主题中所询问的。谢谢。 - Edwin Yip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接