Hello,
I need to allow user to drop files onto my form from Windows Explorer. The fastest way (set form's AllowDropFiles to true, and use OnDropFiles handler to process the dropped files) didn't work for me, the OnDropFiles just doesn't fire.
Then I wrote Windows-specific code to use OLE drag&drop, with implementation of IDropTarget and registering my form as drop target. And it also doesn't work from Explorer. But I've tried to drag files from FarManager (console-based file manager for Windows) and got succeed in it.
type
{TFileDropTarget}
TFileDropTarget = class(TInterfacedObject, IDropTarget)
private
FHandle: HWND;
FDropAllowed: Boolean;
procedure SetEffect(var dwEffect: LongWord);
function DragEnter(const dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall;
function DragOver(grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall;
function DragLeave: HResult; stdcall;
function Drop(const dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall;
public
constructor Create(AHandle: HWND);
destructor Destroy; override;
end;
//...
implementation
procedure TFileDropTarget.SetEffect(var dwEffect: LongWord);
begin
dwEffect:=DROPEFFECT_COPY;
end;
function TFileDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult;stdcall;
begin
Result := S_OK;
try
FDropAllowed := true;
SetEffect(dwEffect);
except
Result := E_UNEXPECTED;
end;
end;
function TFileDropTarget.DragLeave: HResult;stdcall;
begin
Result := S_OK;
end;
function TFileDropTarget.DragOver(grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult;stdcall;
begin
Result := S_OK;
try
SetEffect(dwEffect);
except
Result := E_UNEXPECTED;
end;
end;
function TFileDropTarget.Drop(const dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult;stdcall;
begin
Result := S_OK;
try
FDropAllowed := true;
if FDropAllowed then begin
MessageDlg('Drop called!', mtInformation, [mbOk], 0);
end;
except
Application.HandleException(Self);
end;
end;
// ...
// Form's OnShow
procedure TfmDocsToLoad.FormShow(Sender: TObject);
begin
FDropTarget := TFileDropTarget.Create(Handle) as IDropTarget;
end;
So, the code seems to be ok (yes, it accepts any data, but I just want to see if the Drop() method is called actually). Moreover, the same code works fine with Windows Explorer on Windows 7. Then seems like the Windows version does matter, the problem appears on Windows 10 22H2 19045.3086. I've tried to build both 32 and 64 bits apps, the same effect. Used Lazarus version — current trunk, also tested on Lazarus 2.2.6 stable.
Did anyone faced such Windows behaviour? Could you please advise me how to make drag&drop working?
Best regards, Eugene.