Jump to content
direktor05

Drag Drop via Ole

Recommended Posts

Hello,

 

I want to do drag drop from Windows Explorer to my app via OLE interface IDropTarget. Question is how do I detect if OLE communication is working well. For now RegisterDragDrop function is working fine. But I can't get a call to DragEnter function when dragging starts. How can I check that OLE is working fine and that dragging somehow starts? But why I can't get DragEnter function to run? Here is some nice theory: https://delphidabbler.com/articles/article-24

 

I can't get any of this functions to work or be called. What is wrong? And how do I check if OLE can detect drag-drop in the first place?

function DragEnter(const dataObj: IDataObject; grfKeyState: Longint;  pt: TPoint; var dwEffect: Longint): HResult; stdcall;

function DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall;

function DragLeave: HResult; stdcall;

function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall;

Share this post


Link to post

RegisterDragDrop(Handle, Handler);

 

Handle: 722688

Handler: TFileDropTarget($23747B02490) as IDropTarget

 

So I have a pointer to IDropTarget, but it does not call IDropTarget.DropEnter function when I start the drag operation. Why not? And how can I check this?

 

Share this post


Link to post

RegisterDropTarget(TFileDropTarget.Create(FileDragEnter, FileDragOver, FileDragDrop, FileDragLeave));

Share this post


Link to post

But there still is a question why my DragEnter code is not executed? And how can I find the answer?

Share this post


Link to post

procedure TForm1.Create(Sender: TObject);
begin
  RegisterDropTarget(TFileDropTarget.Create(FileDragEnter, FileDragOver, FileDragDrop, FileDragLeave));
end;

procedure TForm1.RegisterDropTarget(Handler: IDropTarget);
begin
  RegisterDragDrop(Handle, Handler);
  FDragDropHandle := Handle;
end;

procedure TForm1.FileDragEnter(Sender: TObject; FileList: TStrings; Point: TPoint; Shift: TShiftState; var Action: TFileDropAction);
begin
  IT NEVER ENTERS HERE
  FDragFromWindows := True;
  Point := ScreenToClient(Point);
  UpdateFileDragAction(FileList, Point, Action);
end;

Share this post


Link to post

How can I check if OLE is called? CoInitialize works OK. RegisterDragDrop also OK. There is no error anywhere but the thing does not work. How can I test a call to OLE dll?

Share this post


Link to post

FWIW I can recommend the landrix suite, it is based on anders' suite.

Share this post


Link to post
Posted (edited)
7 hours ago, direktor05 said:

procedure TForm1.Create(Sender: TObject);
begin
  RegisterDropTarget(TFileDropTarget.Create(FileDragEnter, FileDragOver, FileDragDrop, FileDragLeave));
end;

The Form's OnCreate event is not the best place to register the drop target.  If your Form's window is ever recreated at runtime, you will lose your registration.  Instead, override the Form's virtual CreateWnd() method and do the registration there instead.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

Anders your component probably does diagnostic according to your component functions not in general. I need a solution how do you check if a procedure of function is executed/called inside OLE/ActiveX dll, better yet specifically inside shell drag drop dll? Any hero here?

Share this post


Link to post
Posted (edited)
21 minutes ago, direktor05 said:

how do you check if a procedure of function is executed/called inside OLE/ActiveX dll, better yet specifically inside shell drag drop dll?

You don't.  The drag code is running inside of the Windows Explorer process.  If it is not invoking the IDropTarget object inside of your process, it means the call is being blocked outside of your process, most likely by UAC/UIPI if your app is running elevated.  Per the comments on your StackOverflow question on this topic:

Quote

Note that Windows doesn't support drag and drop between programs running at different integrity levels since Wndows Vista. Programs running with Administrator prviledge will not be a drop target for stuff dragged from programs not running with Administrator priviledge.

– Brian
Quote

It can work if you handle WM_DROPFILES (DragAcceptFiles()) instead of IDropTarget (RegisterDragDrop()), and then use ChangeWindowMessageFilter/Ex() to allow the WM_DROPFILES, WM_COPYDATA, and (undocumented) WM_COPYGLOBALDATA (0x0049) messages. ChangeWindowMessageFilter/Ex() doesn't work with IDropTarget, though. The alternative is to either 1) enable UIAccess=true for your app (this has very restrictive requirements, though), or 2) run a non-elevated process to accept the drag and then IPC the data into your elevated app.

- Remy Lebeau

 

Edited by Remy Lebeau

Share this post


Link to post
On 10/5/2024 at 10:48 PM, direktor05 said:

Anders your component probably does diagnostic according to your component functions not in general.

No; It works with all drop targets.

 

And if you look at the WM_DROPFILES example there's also an example of working around the UAC restrictions mentioned by Remy:

https://github.com/andersmelander/Drag-and-Drop-Component-Suite/blob/de46eb2b804c33921809504d086285da11d4e3e5/Source/DropTarget.pas#L298

Share this post


Link to post
14 hours ago, Anders Melander said:

No; It works with all drop targets.

 

And if you look at the WM_DROPFILES example there's also an example of working around the UAC restrictions mentioned by Remy:

https://github.com/andersmelander/Drag-and-Drop-Component-Suite/blob/de46eb2b804c33921809504d086285da11d4e3e5/Source/DropTarget.pas#L298

Is this component made only for Delphi up to 2011? How about Delphi 11?

Share this post


Link to post
14 hours ago, Anders Melander said:

No; It works with all drop targets.

 

And if you look at the WM_DROPFILES example there's also an example of working around the UAC restrictions mentioned by Remy:

https://github.com/andersmelander/Drag-and-Drop-Component-Suite/blob/de46eb2b804c33921809504d086285da11d4e3e5/Source/DropTarget.pas#L298

You could also tell me your idea of "example of working around the UAC restrictions " so I don't have to go through your non-working code.

 

Share this post


Link to post

In my code the file list is not filled:

 

FileName := PWideChar(Cardinal(DropFiles) + DropFiles.pFiles);

 

where DropFiles comes from WinApi.ShlObj - which means the file list is not being transferred from Windows on IDropTarget.DragEnter

 

IDropTarget.DragEnter is called but the file list is empty.

Share this post


Link to post
1 minute ago, direktor05 said:

You could also tell me your idea of "example of working around the UAC restrictions " so I don't have to go through your non-working code.

Bite me

Share this post


Link to post
Posted (edited)
1 hour ago, direktor05 said:

FileName := PWideChar(Cardinal(DropFiles) + DropFiles.pFiles);

That code risks pointer truncation in a 64bit build. The integer typecast should be using NativeUInt or UIntPtr  instead. Or, use pointer arithmetic via PByte instead.

 

Also, the file list is a double-null terminated list, so make sure you account for that in case multiple files are dragged. Also, depending on the source, the file names may be using Ansi or Unicode characters, so pay attention to the DropFiles.fWide field. 

Edited by Remy Lebeau

Share this post


Link to post
16 hours ago, Remy Lebeau said:

That code risks pointer truncation in a 64bit build. The integer typecast should be using NativeUInt or UIntPtr  instead. Or, use pointer arithmetic via PByte instead.

 

Also, the file list is a double-null terminated list, so make sure you account for that in case multiple files are dragged. Also, depending on the source, the file names may be using Ansi or Unicode characters, so pay attention to the DropFiles.fWide field. 

REMY YOU SOLVED MY PROBLEM! THANKS.

Share this post


Link to post

You can check in your code these problems with FastMM4. I had the same problem.

Look at setting of Fastmm4:

https://www.atozed.com/2021/07/detecting-memory-leaks-in-delphi-applications-using-fastmm-4/

It is from blog of @dummzeuch

https://blog.dummzeuch.de/2024/09/26/you-should-be-using-the-full-fastmm/

Try to run this code in 64 bit with Fastmm4 and you will probably see exception.

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×