Lazarus

Programming => LCL => Topic started by: d7_2_laz on April 20, 2021, 02:02:35 pm

Title: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 20, 2021, 02:02:35 pm
On the last meters when porting my Delphi 7 app to Lazarus 2.0.12 (Windows x64 only) i got a crash at Drop and don't know if i did something did illegitimate.
What did i try?
I've an already established DragDrop functionality established with pre-Lazarus (Delphi7) means and noticed some drag animation effects were missing. I got aware that Lazarus will work differently...
After studying some threads in the forum i tried to use the example “dragimagelist” for my use cae.
This is a custom treeview where i have copies from system icons stored in an ImageList. Planning  to use those icons as ghost images (node icons as ghost image).
Is there something illegitimate so far? I'm needing the DragObject for the ghost images only.
That what i did:
Code: Pascal  [Select][+][-]
  1. constructor TMyDragObject.CreateWith(AControl: TControl; il: TImageList; imgidx: Integer);
  2. var Bitmap: TBitmap;
  3. begin
  4.   inherited Create(AControl);
  5.   FDragImages := TDragImageList.Create(AControl);
  6.   AlwaysShowDragImages := True;
  7.   Bitmap := TBitmap.Create;
  8.   Bitmap.Width := 16;
  9.   Bitmap.Height := 16;
  10.   Bitmap.Canvas.Changed;
  11.   FDragImages.Width := Bitmap.Width;
  12.   FDragImages.Height := Bitmap.Height;
  13. ImageList_Draw(il.ResolutionByIndex[0].Reference.Handle, imgidx, Bitmap.Canvas.Handle, 0, 0, ILD_TRANSPARENT);
  14.   FDragImages.Add(Bitmap, nil);
  15.   Bitmap.Free;
  16. end;

At OnStartDrag i do:

Code: Pascal  [Select][+][-]
  1. procedure TMyCustomTreeview.DirTreeDoOnStartDrag(Sender: TObject; var DragObject: TDragObject);
  2. var imgidx : Integer;
  3. begin
  4.     imgidx := 15;    // hard-coded temporarely simply for testing
  5.     FDragObject := TMyDragObject.CreateWith(Sender as TControl, FTvImageList, imgidx);
  6.     DragObject := FDragObject;
  7. end;

Works quite fine so far (although the image is not quite transparent yet, well anyhow), but it crashes when entering the OnDragDrop event.

At OnDragOver i did nothing special. It's simply decided where to Accept Drag and where not.

At OnDragDrop i try at first to HideDragImage and Free it (it is stored in FDragObject)
But before that it directly crashes (SIGSEV) when hen having entered the procedure.

It crashes here: in dragimagelist.inc (it halts in first line):

Code: Pascal  [Select][+][-]
  1. procedure TDragImageListResolution.HideDragImage;
  2. begin
  3.   if Dragging then
  4.     TWSDragImageListResolutionClass(WidgetSetClass).HideDragImage(Self, 0, False);
  5. end;

If i directly look onto the WM_RBUTTONUP message: that will be entered, but crashes here immediately.

Does anybody having done such similar has an idea where the flaw might be located?
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: engkin on April 20, 2021, 05:35:50 pm
At OnDragDrop i try at first to HideDragImage and Free it (it is stored in FDragObject)

This sounds wrong to me.

Does it crash if you don't do any thing in OnDragDrop?

Check this thread (https://forum.lazarus.freepascal.org/index.php?topic=45346.0).
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 20, 2021, 07:20:08 pm
Hello engkin, thanks!
Yes, it doesn't reallly reach the first statement within DragDrop procedure. As it behaves the same with an "exit" as first statement or an empty procedure.

The same if i shrink  the DragOver callback (for test:) to contain only an Accept := true;  and nothing else.

Follwing the recommendation in the link i replaced the TDragControlObject by TDragControlObjectEx
(TMyDragObject = class(TDragControlObjectEx).   And, for test,  removed the destructor from TMyDragObject  (as well as the intermediate variable FDragObject) . - No difference.

In my approach i do not paint a Control (eg. Button) into the dragimage, but pickup a bitmap from an imagelist.  Assuming that should not be relevant. (instead of this i could try to fetch the treenode for painting, hm yes).But how the bitmap is painted chouldn't play a role, right?

The crash is directly at leftbutton up. And it appears to me the memory for the property "Dragging" could not be accessed.
The call stack is (the crashing routine on top):

TDragImageListResolution.HideDragImage
TDragImageList.HideDragImage
TDragObject.HideDragImage
TCustomTreeView.DoDragMsg           (case dmDragLeave .. -> ADragObject.HideDragImage;  )
TDragDockCommon.SendDragMessage       (--> AControl.DoDragMsg)
TDragDockCommon.SendCmDragMsg
TDragPerformer.DragStop
TDragManagerDefault.DragStop
TDragManagerDefault.MouseUp
TControl.DoMouseUp



Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: jamie on April 21, 2021, 01:14:30 am
Does this help you?

Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 21, 2021, 10:09:11 am
Hey jamie .. and thanks again!   :)

Not really - the context is a bit too far away from my scenario
and ... uh! .... with this project1, dragging the button around i got an error box / heap dump  (image attached).

The good news is: i could recreate the problem exactly with a little testcase (nearly done)
and i'll post it here later the day [offline now for some hours].
So it should be easily seen what i did wrong. Myself i do not see it, probably a newbie user error.
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: trev on April 21, 2021, 12:40:41 pm
uh! .... with this project1, dragging the button around i got an error box / heap dump  (image attached).

Not actually an error, just an info dump showing no error  ;)
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 21, 2021, 04:10:21 pm
Quote
just an info dump
Oh, didn't know that yet, obviously it's from project options, debugger, Use heaptrace
Great to know, it's valuable info about allocated / freed / unfreed memory - thanks trev!

Attached the the test case. It does not contain any functionality but should be sufficient where it crashes when dropping a selected treenode onto another.
I'm very excited to find out where is my mistake,
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 22, 2021, 09:56:55 am
Is there anybody who even did try the test case?
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: dseligo on April 22, 2021, 10:51:22 am
I looked at it.
If I comment 'function GetDragImages: TDragImageList; override;' in TMyDragObject (and implementation below) then there is no SIGSEV.
Maybe you didn't implement this override function correctly?
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 22, 2021, 11:46:11 am
Many thanks dseligo!
yes, the exception will disappear when commenting out the function GetDragImages,
... but the bitmapped drag image won't appear either any longer (loss of fhe intended functionality).

The function had been 1:2 picked up from the examples directory "dragimagelist" unit1.pas:
Code: Pascal  [Select][+][-]
  1.   protected
  2.     function GetDragImages: TDragImageList; override;
  3.  
  4. function TMyDragObject.GetDragImages: TDragImageList;
  5. begin
  6.   Result := FDragImages;
  7. end;
  8.  

Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 23, 2021, 12:09:24 pm
For to make it more easy to communicate, i shrinked down the testcase eeven more to an absolute mininum.

It's a regular treeview now, creating, after MouseDown,  a DragObject at StartDrag, which now simply has an empty square bitmap as dragimage.
At DragOver an Accept is set for the treeview, ....  and at MouseUp being on a node it persists to SIGSEV.

The very simple test case is attached here again.

Is anybody able to throw some light what is wrong, or which requirements possibly have not been met?
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: dseligo on April 23, 2021, 02:53:17 pm
I've tested a little.
It looks to me that problem surfaces when function TDragImageList.GetDraggingResolution: TDragImageListResolution; returns nil (because property 'Dragging' in Result object is false).

I added 'If Assigned(Self) then' in procedure TDragImageListResolution.HideDragImage; and in procedure TDragImageListResolution.ShowDragImage; and then there was no SIGSEV.

Code: Pascal  [Select][+][-]
  1. procedure TDragImageListResolution.HideDragImage;
  2. begin
  3.   If Assigned(Self) then
  4.   if Dragging then
  5.     TWSDragImageListResolutionClass(WidgetSetClass).HideDragImage(Self, 0, False);
  6. end;
  7.  
  8. procedure TDragImageListResolution.ShowDragImage;
  9. begin
  10.   If Assigned(Self) then
  11.   if Dragging then
  12.     TWSDragImageListResolutionClass(WidgetSetClass).ShowDragImage(Self, 0, 0, 0, False);
  13. end;

I don't know how this works internally, so I am not sure if it is a bug or if you didn't setup bitmap in FDragImages correctly.

P.S.: Check attachment  :)
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: balazsszekely on April 23, 2021, 03:51:27 pm
@dseligo
Quote
I don't know how this works internally, so I am not sure if it is a bug or if you didn't setup bitmap in FDragImages correctly.
I do not know either, but the crash should not hapen even if FDragImages is not setup correctly.
In lcl/include/dragimagelist.inc instead of:
Code: Pascal  [Select][+][-]
  1. procedure TDragImageList.HideDragImage;
  2. begin
  3.   GetDraggingResolution.HideDragImage;
  4. end;
we need:
Code: Pascal  [Select][+][-]
  1. procedure TDragImageList.HideDragImage;
  2. var
  3.   DragImageListResolution: TDragImageListResolution;
  4. begin
  5.   DragImageListResolution := GetDraggingResolution;
  6.   if DragImageListResolution <> nil then
  7.     DragImageListResolution.HideDragImage;
  8. end;

Same is true for ShowDragImage.
It has the same effect as your solution 
Code: Pascal  [Select][+][-]
  1. If Assigned(Self) then
but is higher on the chain with one level.
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: dseligo on April 23, 2021, 04:08:26 pm
It has the same effect as your solution 
Code: Pascal  [Select][+][-]
  1. If Assigned(Self) then
but is higher on the chain with one level.

I agree, it's better.
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: balazsszekely on April 23, 2021, 04:48:52 pm
I applied the changes in r. 65055.
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: d7_2_laz on April 23, 2021, 05:04:22 pm
Hello dseligo and GetMem, thanks a lot for your attention and replies. I appreciate them a lot!

Yes, i suspected such as mentioned in the OP  where i found it to halt in TDragImageListResolution.HideDragImage
Because the memory of "Dragging" (resp. FDragging) could not be accessed.
I thought about myself to work around querying "if Assigned(Self)" or simlar higher in the hierarchy  for to get rid of the exception.
The reason why i did it not , was that i felt that the real source of the issue would be simply covered, not solved.
Maybe an object has been freed too early for some reasons (too early at least from the perspective of the use case). But why??? At the moment of the drop ...

But the operation is so basic that i was in doubt: "that cannot be, i must have done something wrong".  .... But in fact i could not find it.
I had been wondering how others do that: treeview with icons, use the icons as drag image .... It's a so basic and trivial task l ...

--
I just tried to post this reply and to ask, whether the change might be part of the source (some more queries for to be safe that the object does exist). when seeing the update that you (GetMem) did apply the changes to the source.
That's fantastic!!  :) :) :) :) :)  Thank you!


Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: dseligo on April 23, 2021, 07:38:52 pm
I applied the changes in r. 65055.

Revision number will soon be 65535. I hope that counter variable is more than 16 bits. :D
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: balazsszekely on April 23, 2021, 08:18:01 pm
@dseligo
Quote
Revision number will soon be 65535. I hope that counter variable is more than 16 bits.
You have a digital mind. I will send you a beer after 65535.  ;)
Title: Re: DragDrop ghost image with DragObject; fine, but SIGSEV at Drop - why?
Post by: dseligo on April 23, 2021, 10:54:38 pm
@dseligo
Quote
Revision number will soon be 65535. I hope that counter variable is more than 16 bits.
You have a digital mind. I will send you a beer after 65535.  ;)

8)

SYS64738
TinyPortal © 2005-2018