如何将文件从 Explorer Shell 拖放到 Delphi 应用程序中的 VirtualTreeView 控件中?

发布于 2024-09-25 02:56:50 字数 423 浏览 6 评论 0原文

Mike Lischke 在 VirtualTreeView 中提供了广泛的拖放支持,我正在使用 TVirtualStringTree,它有一些拖放事件,但我不知道如何让它接受 shell 拖放将 Windows 资源管理器 shell 中的一些文件添加到我的应用程序中。我想在将文件拖到放置控件上时加载它们。

我尝试使用 Anders Melander 的第三方代码集来处理拖放,但因为 VirtualTreeView 已经将自身注册为放置目标,所以我无法使用它。

编辑:我找到了一个简单的解决方法:关闭 VT.TreeOptions.MiscOptions 中的 toAcceptOLEDrop。 如果有人知道如何使用 VirtualTreeView 而不使用第三方 OLE-shell-drag-drop 库并使用其广泛的 OLE 拖/放支持来提取从 Shell 拖入的文件名列表,那就太酷了。

There is extensive drag and drop support in VirtualTreeView by Mike Lischke, and I am using TVirtualStringTree, which has some on-drag-and-drop events, but I can not figure out how to get it to accept a shell drag-and-drop of some files from the windows explorer shell, into my application. I want to load the files, when they are dragged onto the drop control.

I tried using a third-party set of code from Anders Melander, to handle drag and drop, but because VirtualTreeView already registers itself as a drop target, I can't use that.

edit: I found a simple workaround: Turn off toAcceptOLEDrop in VT.TreeOptions.MiscOptions.
It would be cool if anybody knows a way to use VirtualTreeView without using a third party OLE-shell-drag-drop library and using its extensive OLE drag/drop support to extract a list of filenames dragged in from the Shell.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

稍尽春風 2024-10-02 02:56:50

我的实现(与 Delphi 2010 配合得很好。必须添加 ActiveX、ShellApi 来使用编译):

procedure TfMain.vstTreeDragDrop(Sender: TBaseVirtualTree; Source: TObject;
  DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState;
  Pt: TPoint; var Effect: Integer; Mode: TDropMode);
var
  I, j: Integer;
  MyList: TStringList;
  AttachMode: TVTNodeAttachMode;
begin
  if Mode = dmOnNode then
    AttachMode := amInsertBefore
  else if Mode = dmAbove then
    AttachMode := amInsertBefore
  else if Mode = dmBelow then
    AttachMode := amInsertAfter
  else
    AttachMode := amAddChildLast;

  MyList := TStringList.Create;
  try
    for i := 0 to High(formats) - 1 do
    begin
      if (Formats[i] = CF_HDROP) then
      begin
        GetFileListFromObj(DataObject, MyList);

        //here we have all filenames
        for j:=0 to MyList.Count - 1 do
        begin
          Sender.InsertNode(Sender.DropTargetNode, AttachMode);
        end; 
      end;  
    end;
  finally
    MyList.Free;
  end;
end;

procedure TfMain.GetFileListFromObj(const DataObj: IDataObject;
  FileList: TStringList);
var
  FmtEtc: TFormatEtc;                   // specifies required data format
  Medium: TStgMedium;                   // storage medium containing file list
  DroppedFileCount: Integer;            // number of dropped files
  I: Integer;                           // loops thru dropped files
  FileNameLength: Integer;              // length of a dropped file name
  FileName: string;                 // name of a dropped file
begin
  // Get required storage medium from data object
  FmtEtc.cfFormat := CF_HDROP;
  FmtEtc.ptd := nil;
  FmtEtc.dwAspect := DVASPECT_CONTENT;
  FmtEtc.lindex := -1;
  FmtEtc.tymed := TYMED_HGLOBAL;
  OleCheck(DataObj.GetData(FmtEtc, Medium));
  try
    try
      // Get count of files dropped
      DroppedFileCount := DragQueryFile(
        Medium.hGlobal, $FFFFFFFF, nil, 0
        );
      // Get name of each file dropped and process it
      for I := 0 to Pred(DroppedFileCount) do
        begin
          // get length of file name, then name itself
          FileNameLength := DragQueryFile(Medium.hGlobal, I, nil, 0);
          SetLength(FileName, FileNameLength);
          DragQueryFileW(
            Medium.hGlobal, I, PWideChar(FileName), FileNameLength + 1
            );
          // add file name to list
          FileList.Append(FileName);
        end;
    finally
      // Tidy up - release the drop handle
      // don't use DropH again after this
      DragFinish(Medium.hGlobal);
    end;
  finally
    ReleaseStgMedium(Medium);
  end;

end;

My implementation (Works very well with Delphi 2010. Must add ActiveX, ShellApi to uses to compile):

procedure TfMain.vstTreeDragDrop(Sender: TBaseVirtualTree; Source: TObject;
  DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState;
  Pt: TPoint; var Effect: Integer; Mode: TDropMode);
var
  I, j: Integer;
  MyList: TStringList;
  AttachMode: TVTNodeAttachMode;
begin
  if Mode = dmOnNode then
    AttachMode := amInsertBefore
  else if Mode = dmAbove then
    AttachMode := amInsertBefore
  else if Mode = dmBelow then
    AttachMode := amInsertAfter
  else
    AttachMode := amAddChildLast;

  MyList := TStringList.Create;
  try
    for i := 0 to High(formats) - 1 do
    begin
      if (Formats[i] = CF_HDROP) then
      begin
        GetFileListFromObj(DataObject, MyList);

        //here we have all filenames
        for j:=0 to MyList.Count - 1 do
        begin
          Sender.InsertNode(Sender.DropTargetNode, AttachMode);
        end; 
      end;  
    end;
  finally
    MyList.Free;
  end;
end;

procedure TfMain.GetFileListFromObj(const DataObj: IDataObject;
  FileList: TStringList);
var
  FmtEtc: TFormatEtc;                   // specifies required data format
  Medium: TStgMedium;                   // storage medium containing file list
  DroppedFileCount: Integer;            // number of dropped files
  I: Integer;                           // loops thru dropped files
  FileNameLength: Integer;              // length of a dropped file name
  FileName: string;                 // name of a dropped file
begin
  // Get required storage medium from data object
  FmtEtc.cfFormat := CF_HDROP;
  FmtEtc.ptd := nil;
  FmtEtc.dwAspect := DVASPECT_CONTENT;
  FmtEtc.lindex := -1;
  FmtEtc.tymed := TYMED_HGLOBAL;
  OleCheck(DataObj.GetData(FmtEtc, Medium));
  try
    try
      // Get count of files dropped
      DroppedFileCount := DragQueryFile(
        Medium.hGlobal, $FFFFFFFF, nil, 0
        );
      // Get name of each file dropped and process it
      for I := 0 to Pred(DroppedFileCount) do
        begin
          // get length of file name, then name itself
          FileNameLength := DragQueryFile(Medium.hGlobal, I, nil, 0);
          SetLength(FileName, FileNameLength);
          DragQueryFileW(
            Medium.hGlobal, I, PWideChar(FileName), FileNameLength + 1
            );
          // add file name to list
          FileList.Append(FileName);
        end;
    finally
      // Tidy up - release the drop handle
      // don't use DropH again after this
      DragFinish(Medium.hGlobal);
    end;
  finally
    ReleaseStgMedium(Medium);
  end;

end;
远昼 2024-10-02 02:56:50

我使用此方法来捕获(接收)从资源管理器拖入 TWinControl 的文件。
您可以在您的控件上进行测试。在标准 TTreeView 中工作正常。

将 ShellAPI 添加到使用中。

在私人部分:

  private
    originalEditWindowProc : TWndMethod;
    procedure EditWindowProc(var Msg:TMessage);
    // accept the files dropped
    procedure FilesDrop(var Msg: TWMDROPFILES);

在您表单的 OnCreate 处:

  // Assign procedures
  originalEditWindowProc := TreeView1.WindowProc;
  TreeView1.WindowProc := EditWindowProc;
  // Aceptar ficheros arrastrados  // Accept the files
  ShellAPI.DragAcceptFiles(TreeView1.Handle, True);

这两个过程如下:

// Al arrastrar ficheros sobre el TV.  On drop files to TV
procedure TForm1.FilesDrop(var Msg: TWMDROPFILES);
var
  i:Integer;
  DroppedFilename:string;
  numFiles : longInt;
  buffer : array[0..MAX_PATH] of char;
begin
  // Número de ficheros arrastrados // Number of files
  numFiles := DragQueryFile(Msg.Drop, $FFFFFFFF, nil, 0) ;

  // Recorrido por todos los arrastrados // Accept all files
  for i := 0 to (numFiles - 1) do begin

    DragQueryFile(Msg.Drop, i, @buffer, sizeof(buffer));

    // Proteccion
    try
      DroppedFilename := buffer;

      // HERE you can do something with the file...
      TreeView1.Items.AddChild(nil, DroppedFilename);
    except
      on E:Exception do begin
        // catch
      end;
    end;
  end;
end;


procedure TForm1.EditWindowProc(var Msg: TMessage);
begin
  // if correct message, execute the procedure
  if Msg.Msg = WM_DROPFILES then begin
    FilesDrop(TWMDROPFILES(Msg))
  end
  else begin
    // in other case do default...
    originalEditWindowProc(Msg) ;
  end;
end;

我希望这对您有用。

问候。

I use this method to capture (receive) files dragged into a TWinControl from explorer.
You can test it on your control. In a standard TTreeView work fine.

Add ShellAPI to uses.

At private section:

  private
    originalEditWindowProc : TWndMethod;
    procedure EditWindowProc(var Msg:TMessage);
    // accept the files dropped
    procedure FilesDrop(var Msg: TWMDROPFILES);

At OnCreate of your form:

  // Assign procedures
  originalEditWindowProc := TreeView1.WindowProc;
  TreeView1.WindowProc := EditWindowProc;
  // Aceptar ficheros arrastrados  // Accept the files
  ShellAPI.DragAcceptFiles(TreeView1.Handle, True);

And the two procedure are these:

// Al arrastrar ficheros sobre el TV.  On drop files to TV
procedure TForm1.FilesDrop(var Msg: TWMDROPFILES);
var
  i:Integer;
  DroppedFilename:string;
  numFiles : longInt;
  buffer : array[0..MAX_PATH] of char;
begin
  // Número de ficheros arrastrados // Number of files
  numFiles := DragQueryFile(Msg.Drop, $FFFFFFFF, nil, 0) ;

  // Recorrido por todos los arrastrados // Accept all files
  for i := 0 to (numFiles - 1) do begin

    DragQueryFile(Msg.Drop, i, @buffer, sizeof(buffer));

    // Proteccion
    try
      DroppedFilename := buffer;

      // HERE you can do something with the file...
      TreeView1.Items.AddChild(nil, DroppedFilename);
    except
      on E:Exception do begin
        // catch
      end;
    end;
  end;
end;


procedure TForm1.EditWindowProc(var Msg: TMessage);
begin
  // if correct message, execute the procedure
  if Msg.Msg = WM_DROPFILES then begin
    FilesDrop(TWMDROPFILES(Msg))
  end
  else begin
    // in other case do default...
    originalEditWindowProc(Msg) ;
  end;
end;

I hope that this are usefull for you.

Regards.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文