处理TShellListView后代中的文件丢弃

时间:2013-01-18 17:57:45

标签: delphi drag-and-drop delphi-2010 windows-shell

我正在尝试创建一个TShellListView的后代,它接受从Windows资源管理器中删除的文件。我想处理组件定义中的拖放操作,而不必在任何使用该组件的应用程序中实现它(我已经找到了从Windows资源管理器中删除文件的示例,但所有这些都在应用程序/ TForm级别)。

我在构造函数中调用DragAcceptFiles(),并为WM_DROPFILES定义了一个消息处理程序。但是,当我在示例项目中使用此组件并从Windows资源管理器中拖动文件时:

  1. 我看到“未接受”图标(带斜线的圆圈),而不是我可以删除文件的指示。

  2. 如果我确实尝试删除文件,我就听不到Beep()。

  3. 我认为我没有正确警告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.
    

2 个答案:

答案 0 :(得分:8)

问题代码中的DragAcceptFiles调用需要ShellListView的窗口句柄。当代码访问wincontrol的句柄时,VCL检查窗口是否已创建,如果没有,则VCL调用CreateHandle并继续创建窗口并返回其句柄。在这个阶段,问题中的代码成功注册了ShellListView的文件拖放窗口。但是有一个问题,控制还没有成为父级。当它将成为父级时,本机控件将被销毁,然后在其新父级中重新创建,当然将获得不同的句柄,使注册状态无效。

也可能出于各种其他原因重新创建控件。出于这个原因,最好将我们的代码放在重写CreateWndDestroyWnd方法中,只要句柄发生变化或窗口即将被销毁,我们的代码就会运行。

答案 1 :(得分:3)

正如@SertacAkyuz所说,你的问题的解决方案是覆盖CreateWnd()方法来调用DragAcceptFiles(),而不是在构造函数中这样做。我只想提一下,在Windows Vista及更高版本中,用户界面权限隔离(UIPI)生效,因此如果您的应用程序在UAC下以高架状态运行,那么您还需要调用ChangeWindowMessageFilter()以允许{{ 1}}($ 0049)和WM_COPYGLOBALDATA消息将从较低权限的进程(如Windows资源管理器)传递到您的应用程序,否则拖放操作将无法正常工作。

WM_DROPFILES已被弃用了很长时间,支持更新的IDropTarget界面,这种界面更强大,更灵活。新代码应使用WM_DROPFILES代替IDropTarget。有关更多详细信息,请参阅MSDN:

Transferring Shell Objects with Drag-and-Drop and the Clipboard

WM_DROPFILES提供IDropTarget所提供的灵活功能之一是能够使用单个WM_DROPFILES对象接受拖放,而不仅仅是特定IDropTarget 1}},也可以在应用程序的.exe文件本身上,以及在Shell弹出菜单中使用它,甚至允许其他应用程序直接将数据传递到您的应用程序,而无需使用窗口消息或其他IPC机制。