2

I have an application that mimics Windows Explorer, it uses a TcxShellListView amongst other shell controls.

A really nice feature would be to be able to Copy & Paste and Cut & Paste files between the real Windows Explorer and my application.

Drag & Drop already works out of the box, but it seems that DevExpress hasn't implemented the clipboard side, yet.

Any Ideas?

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113

1 Answers1

3

If you want to implement the copy/paste yourself, the mechanism is almost identical to drag and drop. The drag and drop code that you have will create an IDataObject. To copy, instead of calling DoDragDrop to initiate a drag, simply call OleSetClipboard passing the IDataObject. And for pasting you call OleGetClipboard to get the IDataObject from the clipboard. And then you simply use the exact same code as for a drop operation to decode the IDataObject. That's all there is to it.

There is another way to do it, probably a better approach in my view. And that is to use IContextMenu to do the work. And example of this can be found in the TurboPower tpShellShock project. Have a look for ShellMenuExecute in the StShlCtl unit. So long as the DevExpress component is using the shell interfaces, i.e. IShellFolder, then you will be able to use that same approach. The advantage of this shell based approach is that you are getting the shell to do the work. If a copy dialog needs to be shown, then the shell will do so. This will give you the most integrated user experience.

This code looks like this:

procedure ShellMenuExecute(
  const Sender : TObject; const Folder : IShellFolder;
  var Pidl : PItemIDList; const Count : Integer;
  const AHandle : THandle; ClipboardAction : TStMenuAction);
var
  CM : IContextMenu;
  CI : TCmInvokeCommandInfo;
begin
  if Folder <> nil then begin
    if (Folder.GetUIObjectOf(AHandle, Count, Pidl,
      IID_IContextMenu, nil, Pointer(CM)) = NOERROR)
    then begin
      ZeroMemory(@CI, SizeOf(CI));
      CI.cbSize := SizeOf(TCmInvokeCommandInfo);
      CI.hwnd := AHandle;
      case ClipboardAction of
        caCut   : CI.lpVerb := 'cut';
        caCopy  : CI.lpVerb := 'copy';
        caPaste : CI.lpVerb := 'paste';
        caProperties : CI.lpVerb := 'properties';
      end;
      CM.InvokeCommand(CI);
      CM := nil;
    end;
  end;
end;

I think you should be able to use this code pretty much as is. I would point out that the handle parameter is declared incorrectly. It should be HWND. It's used as the owning window for any dialog that is shown during the call to InvokeCommand.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490