direktor05 2 Posted October 4 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
direktor05 2 Posted October 4 https://learn.microsoft.com/en-us/windows/win32/shell/dragdrop I'm stopped at point 1 or 2. Share this post Link to post
direktor05 2 Posted October 4 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
direktor05 2 Posted October 4 RegisterDropTarget(TFileDropTarget.Create(FileDragEnter, FileDragOver, FileDragDrop, FileDragLeave)); Share this post Link to post
direktor05 2 Posted October 4 https://www.swissdelphicenter.ch/en/showcode.php?id=1627 Share this post Link to post
direktor05 2 Posted October 4 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
direktor05 2 Posted October 4 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
direktor05 2 Posted October 4 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
Anders Melander 1783 Posted October 4 Is there are reason why don't just use one of these? https://github.com/landrix/The-Drag-and-Drop-Component-Suite-for-Delphi https://github.com/andersmelander/Drag-and-Drop-Component-Suite If you don't want to use a ready-made library then I suggest you at least use the DragTargetAnalyzer example application in the above library to diagnose your target. Share this post Link to post
Ian Branch 127 Posted October 4 FWIW I can recommend the landrix suite, it is based on anders' suite. Share this post Link to post
Remy Lebeau 1394 Posted October 4 (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 October 4 by Remy Lebeau 1 Share this post Link to post
direktor05 2 Posted October 5 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
Remy Lebeau 1394 Posted October 5 (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 October 5 by Remy Lebeau Share this post Link to post
Anders Melander 1783 Posted October 6 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
direktor05 2 Posted October 7 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
direktor05 2 Posted October 7 Not very professional! Doesn't work at all! Share this post Link to post
direktor05 2 Posted October 7 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
direktor05 2 Posted October 7 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
Anders Melander 1783 Posted October 7 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
Remy Lebeau 1394 Posted October 7 (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 October 7 by Remy Lebeau Share this post Link to post
direktor05 2 Posted October 8 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
Jirka52 2 Posted October 9 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