My application compiled with Delphi 2007 have drag and drop between grids and it works fine most of the time. But sometimes randomly I got Access violation. I debugged it to Controls.pas method DragTo in VCL.
It begins like this:
begin
if (ActiveDrag <> dopNone) or (Abs(DragStartPos.X - Pos.X) >= DragThreshold) or
(Abs(DragStartPos.Y - Pos.Y) >= DragThreshold) then
begin
Target := DragFindTarget(Pos, TargetHandle, DragControl.DragKind, DragControl);
The exception happens on the last row because DragControl is nil. DragControl is a global variable of type TControl. I have tried to patch this method with an assigncheck and call CancelDrag if DragControl = nil, but that fails also because DragObject is also nil.
procedure CancelDrag;
begin
if DragObject <> nil then DragDone(False);
DragControl := nil;
end;
To find out why DragControl is nil I inspected DragInitControl. There are 2 lines that just exit if DragControl is nil.
procedure DragInitControl(Control: TControl; Immediate: Boolean; Threshold: Integer);
var
DragObject: TDragObject;
StartPos: TPoint;
begin
DragControl := Control;
try
DragObject := nil;
DragInternalObject := False;
if Control.FDragKind = dkDrag then
begin
Control.DoStartDrag(DragObject);
if DragControl = nil then Exit;
if DragObject = nil then
begin
DragObject := TDragControlObjectEx.Create(Control);
DragInternalObject := True;
end
end
else
begin
Control.DoStartDock(DragObject);
if DragControl = nil then Exit;
if DragObject = nil then
begin
DragObject := TDragDockObjectEx.Create(Control);
DragInternalObject := True;
end;
with TDragDockObject(DragObject) do
begin
if Control is TWinControl then
GetWindowRect(TWinControl(Control).Handle, FDockRect)
else
begin
if (Control.Parent = nil) and not (Control is TWinControl) then
begin
GetCursorPos(StartPos);
FDockRect.TopLeft := StartPos;
end
else
FDockRect.TopLeft := Control.ClientToScreen(Point(0, 0));
FDockRect.BottomRight := Point(FDockRect.Left + Control.Width,
FDockRect.Top + Control.Height);
end;
FEraseDockRect := FDockRect;
end;
end;
DragInit(DragObject, Immediate, Threshold);
except
DragControl := nil;
raise;
end;
end;
Could be the reason... So my question.
- Have anyone had similar problems with drag and drop ?
- If I detect DragControl = nil how can I cancel the current drag and drop ?
Edit: Currently I have no solution to this but I can add some more info about it. The grids is called supergrid. This is an internal component that we developed to suit our needs. It inherit TcxGrid from Devexpress. I think (but not sure) that this problem come when user drag a grid row at the same time the grid reload data. Somehow the the reference to the current row become nil. In the long term we have plans to replace this supergrid with a Bold aware grid (as we use Bold for Delphi) that also inherit from TcxGrid. Then the grid is updated as soon as the data is changed (no refresh by the user or in code) and hopefully this fix the problem.