2

The WM_DROPFILES seems very easy to handle file drag and drop. But it always changes the cursor to crDrag at the start of hovering. The WM_DROPFILES handler activated just by the drop event. It is problematic if the user want to drag a file over the form with an unsupported extension.

How can I change the cursor depending on the file extensions during dragging? It should set to crNoDrop if none of the files has an acceptable extension.

I wrote this filtering function and it works fine:

function isAcceptableFileName(fileName_ : string; fileExts_ : array of string ) : boolean

I use Delphi 10.3.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
The Bitman
  • 1,279
  • 1
  • 11
  • 25
  • 3
    I use the code published in [this answer](https://stackoverflow.com/a/4354441/189103). There is an event OnDropAllowed that easily do what you need. – fpiette May 28 '21 at 11:27
  • 2
    What you are asking for can't be done with `WM_DROPFILES`, as there is no way to provide UI feedback or accept/reject the drop based on content. You need to instead implement the [`IDropTarget`](https://learn.microsoft.com/en-us/windows/win32/api/oleidl/nn-oleidl-idroptarget) interface to use those features. See [Handling Shell Data Transfer Scenarios](https://learn.microsoft.com/en-us/windows/win32/shell/datascenarios). The easiest way to implement that is to use Anders Melander's [Drag and Drop components](http://melander.dk/delphi/dragdrop/). – Remy Lebeau May 28 '21 at 14:21

1 Answers1

0

You could do a procedure that returns the drop event

    procedure DragDropFile2Form(var Msg: TMessage); message WM_DROPFILES;

The implementation of it could be something like this.

procedure DragDropFile2Form(var Msg: TMessage);
var
  extension: string;
  number: Integer;
  path: array [0 .. MAX_COMPUTERNAME_LENGTH + MAX_PATH] of Char;
begin
    DragQueryFile(Msg.WParam, number, path, 275);
    {
      if the index value is between zero and the total number of dropped files,
      the return value is the required size, in characters.
    }
    if (FileExists(path)) then
    begin
      extension := ExtractFileExt(path);
      // Extracts the extension part of path like [.jpg, .png, .txt]
      if (extension = '.jpg') or (extension = '.png') or (extension = '.txt') then
      begin
        // ACCEPTED CODE TO DO WHAT YOU WANT WITH THE FILES
      end
      else 
      begin
        // BLOCKS THE FILE AND SHOWS A MESSAGE
        MessageBox(Form1.Handle, PChar('The file is not a image or text'),
          PChar('Drag & Drop'), MB_ICONWARNING);
      end;

    end;

  end;
  DragFinish(Msg.WParam);
  // This frees the resources used to store information about the drop.
end;

You also need to pass the handle of the form that is to receive WM_DROPFILES messages

procedure FormCreate(Sender: TObject);
begin
  DragAcceptFiles(Handle, True);
end;

Dont forget to add Winapi.ShellAPI to your uses

More details you can find in here: http://swepc.se/blog/2018/08/29/how-to-drag-drop-files-delphi-10/

  • `WM_DROPFILES` just called at drop time, not on drag time. `IDropTarget` is the only solution as Remy Lebeau suggested. – The Bitman Jun 05 '21 at 22:47