[英]Handle file drop in TShellListView descendant
我正在嘗試創建一個TShellListView的后代,它接受從Windows資源管理器中刪除的文件。 我想處理組件定義中的拖放操作,而不必在任何使用該組件的應用程序中實現它(我已經找到了從Windows資源管理器中刪除文件的示例,但所有這些都在應用程序/ TForm級別)。
我在構造函數中調用DragAcceptFiles(),並為WM_DROPFILES定義了一個消息處理程序。 但是,當我在示例項目中使用此組件並從Windows資源管理器中拖動文件時:
我看到“未接受”圖標(帶斜線的圓圈),而不是我可以刪除文件的指示。
如果我確實試圖刪除文件,我聽不到Beep()。
我認為我沒有正確警告Windows我的控件想要接受拖動文件的事實。 任何人都可以建議我缺少什么?
這是我的組件代碼刪除了不感興趣的位:
unit LJLShellListView;
interface
type
TLJLShellListView = class(TShellListView)
private
procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES;
published
constructor Create(AOwner: TComponent);
end;
implementation
uses ShellAPI;
constructor TLJLShellListView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DragAcceptFiles(self.Handle, True);
end;
procedure TLJLShellListView.WMDropFiles(var Msg: TWMDropFiles);
begin
Beep(); // I never hear this.
end;
end.
在問題的代碼中, DragAcceptFiles
調用需要ShellListView的窗口句柄。 當代碼訪問wincontrol的句柄時,VCL檢查窗口是否已創建,如果沒有,VCL調用CreateHandle
並繼續創建窗口並返回其句柄。 在這個階段,問題中的代碼成功注冊了ShellListView的文件拖放窗口。 但是有一個問題,控制還沒有成為父級。 當它將成為父級時,本機控件將被銷毀,然后在其新父級中重新創建,當然將獲得不同的句柄,使注冊狀態無效。
控件可能會因各種其他原因而重新創建。 出於這個原因,最好將我們的代碼放在重寫的CreateWnd
和DestroyWnd
方法中,每當句柄改變或窗口即將被銷毀時,我們的代碼就會運行。
正如@SertacAkyuz所說,你的問題的解決方案是覆蓋CreateWnd()
方法來調用DragAcceptFiles()
而不是在構造函數中這樣做。 我只想提一下,在Windows Vista及更高版本中,用戶界面權限隔離(UIPI)生效,因此如果您的應用程序在UAC下以提升狀態運行,那么您還需要調用ChangeWindowMessageFilter()
以允許WM_COPYGLOBALDATA
($ 0049)和WM_DROPFILES
消息將從較低權限的進程(如Windows資源管理器)傳遞到您的應用程序,否則拖放操作將無法正常工作。
WM_DROPFILES
已經被棄用了很長時間,轉而使用更新的IDropTarget
接口,它更強大,更靈活。 新代碼應該使用IDropTarget
而不是WM_DROPFILES
。 有關更多詳細信息,請參閱MSDN:
IDropTarget
提供的靈活功能之一WM_DROPFILES
不能使用單個IDropTarget
對象來接受拖放操作,不僅可以在特定的HWND
,還可以在應用程序的.exe文件本身上進行拖放,以及使用它在Shell彈出菜單中,甚至允許其他應用程序直接將數據傳遞到您的應用程序,而無需使用窗口消息或其他IPC機制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.