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

War*_* P 7 delphi drag-and-drop windows-shell virtualtreeview

Mike Lischke在VirtualTreeView中有广泛的拖放支持,我使用的是TVirtualStringTree,它有一些拖放事件,但我无法弄清楚如何让它接受shell拖放从Windows资源管理器shell到我的应用程序的一些文件.我想加载文件,当它们被拖动到放置控件上时.

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

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

Lin*_*nas 9

我的实现(与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;
Run Code Online (Sandbox Code Playgroud)