Debugger: Inspect-Win, use Watch object to get data / Display arrays with FpDebug

This commit is contained in:
Martin 2022-06-09 11:27:56 +02:00
parent 363d0ac778
commit 54bca1219b
3 changed files with 526 additions and 198 deletions

View File

@ -28,17 +28,18 @@ unit InspectDlg;
interface interface
uses uses
Classes, SysUtils, Classes, SysUtils, Math,
// LCL // LCL
LCLProc, LCLType, Grids, StdCtrls, Menus, Forms, Controls, Graphics, ComCtrls, LCLProc, LCLType, Grids, StdCtrls, Menus, Forms, Controls, Graphics, ComCtrls,
// IdeIntf // IdeIntf
IDEWindowIntf, IDEImagesIntf, ObjectInspector, PropEdits, IDEWindowIntf, IDEImagesIntf, ObjectInspector, PropEdits,
// DebuggerIntf // DebuggerIntf
DbgIntfDebuggerBase, DbgIntfBaseTypes, LazDebuggerIntf, DbgIntfDebuggerBase, DbgIntfBaseTypes, LazClasses, LazDebuggerIntf,
LazDebuggerIntfBaseTypes, LazDebuggerIntfBaseTypes,
// IDE // IDE
LazarusIDEStrConsts, BaseDebugManager, InputHistory, IDEProcs, LazarusIDEStrConsts, BaseDebugManager, InputHistory, IDEProcs, Debugger,
Debugger, DebuggerDlg, DebuggerStrConst, EnvironmentOpts; IdeDebuggerWatchResPrinter, IdeDebuggerWatchResult, DebuggerDlg,
DebuggerStrConst, EnvironmentOpts;
type type
@ -94,25 +95,29 @@ type
//FDataGrid, //FDataGrid,
//FPropertiesGrid, //FPropertiesGrid,
//FMethodsGrid: TOIDBGGrid; //FMethodsGrid: TOIDBGGrid;
FExpression: ansistring; FExpression, FAlternateExpression: ansistring;
FWatchPrinter: TWatchResultPrinter;
FInspectWatches: TCurrentWatches;
FCurrentWatchValue: TIdeWatchValue;
FHumanReadable: ansistring; FHumanReadable: ansistring;
FDBGInfo: TDBGType;
FGridData: TStringGrid; FGridData: TStringGrid;
FGridMethods: TStringGrid; FGridMethods: TStringGrid;
FUpdateLock, FUpdateNeeded, FExpressionWasEvaluated: Boolean; FExpressionWasEvaluated: Boolean;
FTestUpdateLock: Boolean;
FRowClicked: Integer;
FHistory: TStringList; FHistory: TStringList;
FHistoryIndex: Integer; FHistoryIndex: Integer;
FPowerImgIdx, FPowerImgIdxGrey: Integer; FPowerImgIdx, FPowerImgIdxGrey: Integer;
procedure EvaluateCallback(Sender: TObject; ASuccess: Boolean; procedure DoDebuggerState(ADebugger: TDebuggerIntf; AnOldState: TDBGState);
ResultText: String; ResultDBGType: TDBGType); procedure DoWatchUpdated(const ASender: TIdeWatches; const AWatch: TIdeWatch);
procedure EvaluateTestCallback(Sender: TObject; ASuccess: Boolean;
{%H-}ResultText: String; ResultDBGType: TDBGType);
procedure Localize; procedure Localize;
function ShortenedExpression: String; function ShortenedExpression: String;
procedure ContextChanged(Sender: TObject); procedure ContextChanged(Sender: TObject);
procedure InspectResDataSimple;
procedure InspectResDataPointer;
procedure InspectResDataEnum;
procedure InspectResDataSet;
procedure InspectResDataArray;
procedure InspectResDataStruct;
procedure InspectClass; procedure InspectClass;
procedure InspectRecord; procedure InspectRecord;
procedure InspectVariant; procedure InspectVariant;
@ -209,6 +214,196 @@ begin
UpdateData; UpdateData;
end; end;
procedure TIDEInspectDlg.InspectResDataSimple;
var
Res: TWatchResultData;
v: String;
begin
Res := FCurrentWatchValue.ResultData;
DataPage.TabVisible:=true;
PropertiesPage.TabVisible:=false;
MethodsPage.TabVisible:=false;
PageControl.ActivePage := DataPage;
FGridData.Columns[0].Visible := False;
FGridData.Columns[2].Visible := btnColType.Down;
FGridData.Columns[4].Visible := False;
btnUseInstance.Enabled := False;
btnColClass.Enabled := False;
btnColType.Enabled := True;
btnColVisibility.Enabled := False;
v := FWatchPrinter.PrintWatchValue(Res, wdfDefault);
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = ' + v;
GridDataSetup;
FGridData.Cells[1,1]:=FExpression;
FGridData.Cells[2,1]:=Res.TypeName;
FGridData.Cells[3,1]:=v;
end;
procedure TIDEInspectDlg.InspectResDataPointer;
var
Res: TWatchResultData;
v: String;
begin
Res := FCurrentWatchValue.ResultData;
DataPage.TabVisible:=true;
PropertiesPage.TabVisible:=false;
MethodsPage.TabVisible:=false;
PageControl.ActivePage := DataPage;
FGridData.Columns[0].Visible := False;
FGridData.Columns[2].Visible := btnColType.Down;
FGridData.Columns[4].Visible := False;
btnUseInstance.Enabled := False;
btnColClass.Enabled := False;
btnColType.Enabled := True;
btnColVisibility.Enabled := False;
v := FWatchPrinter.PrintWatchValue(Res, wdfDefault);
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = ' + v;
GridDataSetup;
v := FWatchPrinter.PrintWatchValue(Res, wdfPointer);
FGridData.Cells[1,1]:=FExpression;
FGridData.Cells[2,1]:=Res.TypeName;
FGridData.Cells[3,1]:=v;
Res := Res.DerefData;
if Res <> nil then begin
FGridData.RowCount := 3;
FGridData.Cells[1,2]:=Format(lisInspectPointerTo, ['']);
FGridData.Cells[2,2]:=Res.TypeName;
FGridData.Cells[3,2]:=FWatchPrinter.PrintWatchValue(Res, wdfDefault);
end;
end;
procedure TIDEInspectDlg.InspectResDataEnum;
var
Res: TWatchResultData;
v: String;
begin
Res := FCurrentWatchValue.ResultData;
DataPage.TabVisible:=true;
PropertiesPage.TabVisible:=false;
MethodsPage.TabVisible:=false;
PageControl.ActivePage := DataPage;
FGridData.Columns[0].Visible := False; // anchestor
FGridData.Columns[2].Visible := btnColType.Down; // typename
FGridData.Columns[4].Visible := False;
btnUseInstance.Enabled := False;
btnColClass.Enabled := False;
btnColType.Enabled := True;
btnColVisibility.Enabled := False;
v := FWatchPrinter.PrintWatchValue(Res, wdfDefault);
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = ' + v;
GridDataSetup;
FGridData.Cells[1,1]:=FExpression;
FGridData.Cells[2,1]:=Res.TypeName;
// TODO: show declaration (all elements)
FGridData.Cells[3,1]:=v;
end;
procedure TIDEInspectDlg.InspectResDataSet;
begin
InspectEnum;
end;
procedure TIDEInspectDlg.InspectResDataArray;
var
Res, Entry: TWatchResultData;
v: String;
b: Int64;
i: Integer;
begin
Res := FCurrentWatchValue.ResultData;
DataPage.TabVisible:=true;
PropertiesPage.TabVisible:=false;
MethodsPage.TabVisible:=false;
PageControl.ActivePage := DataPage;
FGridData.Columns[0].Visible := False;
FGridData.Columns[2].Visible := btnColType.Down;
FGridData.Columns[4].Visible := False;
btnUseInstance.Enabled := False;
btnColClass.Enabled := False;
btnColType.Enabled := True;
btnColVisibility.Enabled := False;
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = Len:' + IntToStr(Res.Count);
GridDataSetup;
if Res.Count > 0 then begin
FGridData.RowCount:=Res.Count+1;
b := Res.LowBound;
for i := 0 to Res.Count-1 do begin
Res.SetSelectedIndex(i);
Entry := Res.SelectedEntry;
FGridData.Cells[1,i+1] := IntToStr(b+i);
FGridData.Cells[2,i+1] := Entry.TypeName;
FGridData.Cells[3,i+1] := FWatchPrinter.PrintWatchValue(Entry, wdfDefault);
end;
end;
end;
procedure TIDEInspectDlg.InspectResDataStruct;
const
FieldLocationNames: array[TLzDbgFieldVisibility] of string = //(dfvUnknown, dfvPrivate, dfvProtected, dfvPublic, dfvPublished);
('', 'Private', 'Protected', 'Public', 'Published');
var
Res: TWatchResultData;
cnt, i: Integer;
FldInfo: TWatchResultDataFieldInfo;
AnchType: String;
begin
Res := FCurrentWatchValue.ResultData;
DataPage.TabVisible :=true;
PropertiesPage.TabVisible :=false;
MethodsPage.TabVisible := False; // TODO
//if not (PageControl.ActivePage = MethodsPage) then
PageControl.ActivePage := DataPage;
FGridData.Columns[0].Visible := (Res.StructType in [dstClass, dstObject]) and btnColClass.Down; // anchestor
FGridData.Columns[2].Visible := btnColType.Down; // typename
FGridData.Columns[4].Visible := (Res.StructType in [dstClass, dstObject]) and btnColVisibility.Down; // class-visibility
btnUseInstance.Enabled := Res.StructType in [dstClass];
btnColClass.Enabled := Res.StructType in [dstClass, dstObject];
btnColType.Enabled := True;
btnColVisibility.Enabled := Res.StructType in [dstClass, dstObject];
AnchType := '';
if Res.Anchestor <> nil then
AnchType := Res.Anchestor.TypeName;
StatusBar1.SimpleText:=Format(lisInspectClassInherit, [ShortenedExpression, Res.TypeName, AnchType]);
GridDataSetup;
cnt := Res.FieldCount; // TODO: filter method vs field
FGridData.RowCount := max(cnt+1, 2);
for i := 1 to cnt do begin
FldInfo := Res.Fields[i-1];
FGridData.Cells[1,i] := FldInfo.FieldName;
if FldInfo.Field <> nil
then FGridData.Cells[2,i] := FldInfo.Field.TypeName
else FGridData.Cells[2,i] := '';
if FldInfo.Field <> nil
then FGridData.Cells[3,i] := FWatchPrinter.PrintWatchValue(FldInfo.Field, wdfDefault)
else FGridData.Cells[3,i] := '<error>';
if FldInfo.Owner <> nil
then FGridData.Cells[0,i] := FldInfo.Owner.TypeName
else FGridData.Cells[0,i] := '';
FGridData.Cells[4,i] := FieldLocationNames[FldInfo.FieldVisibility];
end;
//GridMethodsSetup;
//ShowMethodsFields;
end;
procedure TIDEInspectDlg.DataGridMouseDown(Sender: TObject; Button: TMouseButton; procedure TIDEInspectDlg.DataGridMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); Shift: TShiftState; X, Y: Integer);
begin begin
@ -219,78 +414,85 @@ end;
procedure TIDEInspectDlg.FormShow(Sender: TObject); procedure TIDEInspectDlg.FormShow(Sender: TObject);
begin begin
ReleaseRefAndNil(FCurrentWatchValue);
FInspectWatches.Clear;
UpdateData; UpdateData;
end; end;
procedure TIDEInspectDlg.EvaluateTestCallback(Sender: TObject;
ASuccess: Boolean; ResultText: String; ResultDBGType: TDBGType);
begin
FTestUpdateLock := False;
if ASuccess and (ResultDBGType <> nil) then begin
if pos('Cannot access memory at address', ResultDBGType.Value.AsString) = 1 then begin
FreeAndNil(ResultDBGType);
Execute(FGridData.Cells[2, FRowClicked] + '(' + FExpression + ')[0]');
exit;
end;
FreeAndNil(ResultDBGType);
end;
Execute('(' + FExpression + ')^');
end;
procedure TIDEInspectDlg.DataGridDoubleClick(Sender: TObject); procedure TIDEInspectDlg.DataGridDoubleClick(Sender: TObject);
var var
i: Integer; i: Integer;
s: String; s, t: String;
TestOpts: TWatcheEvaluateFlags;
begin begin
if FTestUpdateLock then if (FCurrentWatchValue = nil) or (FExpression = '') then exit;
exit;
if (FDBGInfo = nil) or (FExpression = '') then exit; if FCurrentWatchValue.TypeInfo <> nil then begin
if (FDBGInfo.Kind in [skClass, skRecord, skObject]) then begin if (FCurrentWatchValue.TypeInfo.Kind in [skClass, skRecord, skObject]) then begin
i := FGridData.Row;
if (i < 1) or (i >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, i];
if btnUseInstance.Down and (FDBGInfo.Kind = skClass) then
Execute(FGridData.Cells[0, i] + '(' + FExpression + ').' + s)
else
Execute(FExpression + '.' + s);
exit;
end;
if (FDBGInfo.Kind in [skPointer]) then begin
FTestUpdateLock := true;
try
FRowClicked := FGridData.Row;
if (FRowClicked < 1) or (FRowClicked >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, FRowClicked];
//TestOpts := [defFullTypeInfo];
TestOpts := [];
if btnUseInstance.Down then
include(TestOpts, defClassAutoCast);
if not DebugBoss.Evaluate('(' + FExpression + ')^', @EvaluateTestCallback, TestOpts) then
EvaluateTestCallback(nil, False, '', nil);
except
FTestUpdateLock := False;
end;
exit;
end;
if (FDBGInfo.Kind in [skSimple]) and (FDBGInfo.Attributes*[saArray,saDynArray] <> []) then begin
if FDBGInfo.Len < 1 then exit;
if FDBGInfo.Fields.Count > 0 then begin
i := FGridData.Row; i := FGridData.Row;
if (i < 1) or (i >= FGridData.RowCount) then exit; if (i < 1) or (i >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, i]; s := FGridData.Cells[1, i];
Execute(FExpression + '[' + s + ']');
end if btnUseInstance.Down and (FCurrentWatchValue.TypeInfo.Kind = skClass) then
else begin Execute(FGridData.Cells[0, i] + '(' + FExpression + ').' + s)
// else
Execute(FExpression + '.' + s);
exit;
end;
if (FCurrentWatchValue.TypeInfo.Kind in [skPointer]) then begin
i := FGridData.Row;
if (i < 1) or (i >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, i];
t := FGridData.Cells[2, i];
Execute('(' + FExpression + ')^');
if not FExpressionWasEvaluated then
FAlternateExpression := t + '(' + FExpression + ')[0]';
exit;
end;
if (FCurrentWatchValue.TypeInfo.Kind in [skSimple]) and (FCurrentWatchValue.TypeInfo.Attributes*[saArray,saDynArray] <> []) then begin
if FCurrentWatchValue.TypeInfo.Len < 1 then exit;
if FCurrentWatchValue.TypeInfo.Fields.Count > 0 then begin
i := FGridData.Row;
if (i < 1) or (i >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, i];
Execute(FExpression + '[' + s + ']');
end
else begin
//
end;
end;
end
else
if FCurrentWatchValue.ResultData <> nil then begin
case FCurrentWatchValue.ResultData.ValueKind of
rdkPointerVal: begin
i := FGridData.Row;
if (i < 1) or (i >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, i];
t := FGridData.Cells[2, i];
Execute('(' + FExpression + ')^');
if not FExpressionWasEvaluated then
FAlternateExpression := t + '(' + FExpression + ')[0]';
end;
rdkArray: begin
i := FGridData.Row;
if (i < 1) or (i >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, i];
Execute(FExpression + '[' + s + ']');
end;
rdkStruct: begin
i := FGridData.Row;
if (i < 1) or (i >= FGridData.RowCount) then exit;
s := FGridData.Cells[1, i];
if btnUseInstance.Down and (FCurrentWatchValue.ResultData.StructType in [dstClass, dstObject]) then
Execute(FGridData.Cells[0, i] + '(' + FExpression + ').' + s)
else
Execute(FExpression + '.' + s);
end;
end; end;
end; end;
@ -298,9 +500,13 @@ end;
procedure TIDEInspectDlg.btnColClassClick(Sender: TObject); procedure TIDEInspectDlg.btnColClassClick(Sender: TObject);
begin begin
if (FDBGInfo = nil) then exit; if (FCurrentWatchValue = nil) then exit;
if (FDBGInfo.Kind = skClass) then begin if ( (FCurrentWatchValue.TypeInfo = nil) and
(FCurrentWatchValue.TypeInfo.Kind = skClass)
) or
( FCurrentWatchValue.ResultData.StructType in [dstClass, dstObject] )
then begin
FGridData.Columns[0].Visible := btnColClass.Down; FGridData.Columns[0].Visible := btnColClass.Down;
FGridData.Columns[4].Visible := btnColVisibility.Down; FGridData.Columns[4].Visible := btnColVisibility.Down;
end; end;
@ -318,6 +524,8 @@ begin
if btnPower.Down if btnPower.Down
then begin then begin
btnPower.ImageIndex := FPowerImgIdx; btnPower.ImageIndex := FPowerImgIdx;
ReleaseRefAndNil(FCurrentWatchValue);
FInspectWatches.Clear;
UpdateData; UpdateData;
end end
else begin else begin
@ -400,10 +608,11 @@ begin
btnColVisibility.Enabled := True; btnColVisibility.Enabled := True;
if not Assigned(FDBGInfo) then exit; if not Assigned(FCurrentWatchValue) then exit;
if not Assigned(FDBGInfo.Fields) then exit; if not Assigned(FCurrentWatchValue.TypeInfo) then exit;
StatusBar1.SimpleText:=Format(lisInspectClassInherit, [ShortenedExpression, FDBGInfo. if not Assigned(FCurrentWatchValue.TypeInfo.Fields) then exit;
TypeName, FDBGInfo.Ancestor]); StatusBar1.SimpleText:=Format(lisInspectClassInherit, [ShortenedExpression, FCurrentWatchValue.TypeInfo.
TypeName, FCurrentWatchValue.TypeInfo.Ancestor]);
GridDataSetup; GridDataSetup;
ShowDataFields; ShowDataFields;
//FGridData.AutoSizeColumn(1); //FGridData.AutoSizeColumn(1);
@ -428,12 +637,13 @@ begin
btnColType.Enabled := True; btnColType.Enabled := True;
btnColVisibility.Enabled := False; btnColVisibility.Enabled := False;
if not Assigned(FDBGInfo) then exit; if not Assigned(FCurrentWatchValue) then exit;
if not Assigned(FCurrentWatchValue.TypeInfo) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : Variant'; StatusBar1.SimpleText:=ShortenedExpression+' : Variant';
GridDataSetup; GridDataSetup;
FGridData.Cells[1,1]:=FExpression; FGridData.Cells[1,1]:=FExpression;
FGridData.Cells[2,1]:='Variant'; FGridData.Cells[2,1]:='Variant';
FGridData.Cells[3,1]:=FDBGInfo.Value.AsString; FGridData.Cells[3,1]:=FCurrentWatchValue.TypeInfo.Value.AsString;
//FGridData.AutoSizeColumn(1); //FGridData.AutoSizeColumn(1);
end; end;
@ -451,9 +661,10 @@ begin
btnColType.Enabled := True; btnColType.Enabled := True;
btnColVisibility.Enabled := False; btnColVisibility.Enabled := False;
if not Assigned(FDBGInfo) then exit; if not Assigned(FCurrentWatchValue) then exit;
if not Assigned(FDBGInfo.Fields) then exit; if not Assigned(FCurrentWatchValue.TypeInfo) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FDBGInfo.TypeName; if not Assigned(FCurrentWatchValue.TypeInfo.Fields) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentWatchValue.TypeInfo.TypeName;
GridDataSetup; GridDataSetup;
ShowDataFields; ShowDataFields;
//FGridData.AutoSizeColumn(2); //FGridData.AutoSizeColumn(2);
@ -476,19 +687,20 @@ begin
btnColType.Enabled := True; btnColType.Enabled := True;
btnColVisibility.Enabled := False; btnColVisibility.Enabled := False;
if not Assigned(FDBGInfo) then exit; if not Assigned(FCurrentWatchValue) then exit;
if not Assigned(FCurrentWatchValue.TypeInfo) then exit;
GridDataSetup; GridDataSetup;
if FDBGInfo.Attributes*[saArray,saDynArray] <> [] then begin if FCurrentWatchValue.TypeInfo.Attributes*[saArray,saDynArray] <> [] then begin
if FDBGInfo.Len >= 0 then if FCurrentWatchValue.TypeInfo.Len >= 0 then
StatusBar1.SimpleText:=ShortenedExpression+' : '+FDBGInfo.TypeName + ' = Len:' + IntToStr(FDBGInfo.Len) + ' ' + FDBGInfo.Value.AsString StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentWatchValue.TypeInfo.TypeName + ' = Len:' + IntToStr(FCurrentWatchValue.TypeInfo.Len) + ' ' + FCurrentWatchValue.TypeInfo.Value.AsString
else else
StatusBar1.SimpleText:=ShortenedExpression+' : '+FDBGInfo.TypeName + ' = ' + FDBGInfo.Value.AsString; StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentWatchValue.TypeInfo.TypeName + ' = ' + FCurrentWatchValue.TypeInfo.Value.AsString;
if FDBGInfo.Fields.Count > 0 then begin if FCurrentWatchValue.TypeInfo.Fields.Count > 0 then begin
FGridData.RowCount:=FDBGInfo.Fields.Count+1; FGridData.RowCount:=FCurrentWatchValue.TypeInfo.Fields.Count+1;
for j := 0 to FDBGInfo.Fields.Count-1 do begin for j := 0 to FCurrentWatchValue.TypeInfo.Fields.Count-1 do begin
fld := FDBGInfo.Fields[j]; fld := FCurrentWatchValue.TypeInfo.Fields[j];
FGridData.Cells[1,j+1]:=fld.Name; // index FGridData.Cells[1,j+1]:=fld.Name; // index
FGridData.Cells[2,j+1]:=fld.DBGType.TypeName; FGridData.Cells[2,j+1]:=fld.DBGType.TypeName;
FGridData.Cells[3,j+1]:=fld.DBGType.Value.AsString; FGridData.Cells[3,j+1]:=fld.DBGType.Value.AsString;
@ -497,11 +709,11 @@ begin
end; end;
end end
else else
StatusBar1.SimpleText:=ShortenedExpression+' : '+FDBGInfo.TypeName + ' = ' + FDBGInfo.Value.AsString; StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentWatchValue.TypeInfo.TypeName + ' = ' + FCurrentWatchValue.TypeInfo.Value.AsString;
FGridData.Cells[1,1]:=FExpression; FGridData.Cells[1,1]:=FExpression;
FGridData.Cells[2,1]:=FDBGInfo.TypeName; FGridData.Cells[2,1]:=FCurrentWatchValue.TypeInfo.TypeName;
FGridData.Cells[3,1]:=FDBGInfo.Value.AsString; FGridData.Cells[3,1]:=FCurrentWatchValue.TypeInfo.Value.AsString;
//FGridData.AutoSizeColumn(2); //FGridData.AutoSizeColumn(2);
end; end;
@ -519,15 +731,16 @@ begin
btnColType.Enabled := True; btnColType.Enabled := True;
btnColVisibility.Enabled := False; btnColVisibility.Enabled := False;
if not Assigned(FDBGInfo) then exit; if not Assigned(FCurrentWatchValue) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FDBGInfo.TypeName + ' = ' + FDBGInfo.Value.AsString; if not Assigned(FCurrentWatchValue.TypeInfo) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentWatchValue.TypeInfo.TypeName + ' = ' + FCurrentWatchValue.TypeInfo.Value.AsString;
GridDataSetup; GridDataSetup;
FGridData.Cells[1,1]:=FExpression; FGridData.Cells[1,1]:=FExpression;
FGridData.Cells[2,1]:=FDBGInfo.TypeName; FGridData.Cells[2,1]:=FCurrentWatchValue.TypeInfo.TypeName;
if (FDBGInfo.TypeName <> '') and (FDBGInfo.TypeDeclaration <> '') if (FCurrentWatchValue.TypeInfo.TypeName <> '') and (FCurrentWatchValue.TypeInfo.TypeDeclaration <> '')
then FGridData.Cells[2,1] := FGridData.Cells[2,1] + ' = '; then FGridData.Cells[2,1] := FGridData.Cells[2,1] + ' = ';
FGridData.Cells[2,1] := FGridData.Cells[2,1] + FDBGInfo.TypeDeclaration; FGridData.Cells[2,1] := FGridData.Cells[2,1] + FCurrentWatchValue.TypeInfo.TypeDeclaration;
FGridData.Cells[3,1]:=FDBGInfo.Value.AsString; FGridData.Cells[3,1]:=FCurrentWatchValue.TypeInfo.Value.AsString;
//FGridData.AutoSizeColumn(2); //FGridData.AutoSizeColumn(2);
end; end;
@ -545,15 +758,16 @@ begin
btnColType.Enabled := True; btnColType.Enabled := True;
btnColVisibility.Enabled := False; btnColVisibility.Enabled := False;
if not Assigned(FDBGInfo) then exit; if not Assigned(FCurrentWatchValue) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FDBGInfo.TypeName + ' = ' + FDBGInfo.Value.AsString; if not Assigned(FCurrentWatchValue.TypeInfo) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentWatchValue.TypeInfo.TypeName + ' = ' + FCurrentWatchValue.TypeInfo.Value.AsString;
GridDataSetup; GridDataSetup;
FGridData.Cells[1,1]:=FExpression; FGridData.Cells[1,1]:=FExpression;
FGridData.Cells[2,1]:=FDBGInfo.TypeName; FGridData.Cells[2,1]:=FCurrentWatchValue.TypeInfo.TypeName;
if (FDBGInfo.TypeName <> '') and (FDBGInfo.TypeDeclaration <> '') if (FCurrentWatchValue.TypeInfo.TypeName <> '') and (FCurrentWatchValue.TypeInfo.TypeDeclaration <> '')
then FGridData.Cells[2,1] := FGridData.Cells[2,1] + ' = '; then FGridData.Cells[2,1] := FGridData.Cells[2,1] + ' = ';
FGridData.Cells[2,1] := FGridData.Cells[2,1] + FDBGInfo.TypeDeclaration; FGridData.Cells[2,1] := FGridData.Cells[2,1] + FCurrentWatchValue.TypeInfo.TypeDeclaration;
FGridData.Cells[3,1]:=FDBGInfo.Value.AsString; FGridData.Cells[3,1]:=FCurrentWatchValue.TypeInfo.Value.AsString;
//FGridData.AutoSizeColumn(2); //FGridData.AutoSizeColumn(2);
end; end;
@ -571,16 +785,17 @@ begin
btnColType.Enabled := True; btnColType.Enabled := True;
btnColVisibility.Enabled := False; btnColVisibility.Enabled := False;
if not Assigned(FDBGInfo) then exit; if not Assigned(FCurrentWatchValue) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FDBGInfo.TypeName + ' = ' + FDBGInfo.Value.AsString; if not Assigned(FCurrentWatchValue.TypeInfo) then exit;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentWatchValue.TypeInfo.TypeName + ' = ' + FCurrentWatchValue.TypeInfo.Value.AsString;
GridDataSetup; GridDataSetup;
FGridData.Cells[1,1]:=FExpression; FGridData.Cells[1,1]:=FExpression;
if (FDBGInfo.TypeName <> '') and (FDBGInfo.TypeName[1] = '^') if (FCurrentWatchValue.TypeInfo.TypeName <> '') and (FCurrentWatchValue.TypeInfo.TypeName[1] = '^')
then FGridData.Cells[2, 1]:=Format(lisInspectPointerTo, [copy(FDBGInfo. then FGridData.Cells[2, 1]:=Format(lisInspectPointerTo, [copy(FCurrentWatchValue.TypeInfo.
TypeName, 2, length(FDBGInfo.TypeName))]) TypeName, 2, length(FCurrentWatchValue.TypeInfo.TypeName))])
else FGridData.Cells[2,1]:=FDBGInfo.TypeName; else FGridData.Cells[2,1]:=FCurrentWatchValue.TypeInfo.TypeName;
{$PUSH}{$RANGECHECKS OFF} {$PUSH}{$RANGECHECKS OFF}
FGridData.Cells[3,1]:=format('$%x',[{%H-}PtrUInt(FDBGInfo.Value.AsPointer)]); FGridData.Cells[3,1]:=format('$%x',[{%H-}PtrUInt(FCurrentWatchValue.TypeInfo.Value.AsPointer)]);
{$POP} {$POP}
//FGridData.AutoSizeColumn(2); //FGridData.AutoSizeColumn(2);
end; end;
@ -661,8 +876,8 @@ var
fld: TDBGField; fld: TDBGField;
begin begin
k:=0; k:=0;
for j := 0 to FDBGInfo.Fields.Count-1 do begin for j := 0 to FCurrentWatchValue.TypeInfo.Fields.Count-1 do begin
case FDBGInfo.Fields[j].DBGType.Kind of case FCurrentWatchValue.TypeInfo.Fields[j].DBGType.Kind of
skSimple,skRecord,skVariant,skPointer: inc(k); skSimple,skRecord,skVariant,skPointer: inc(k);
end; end;
end; end;
@ -670,8 +885,8 @@ begin
if k<2 Then k:=2; if k<2 Then k:=2;
FGridData.RowCount:=k; FGridData.RowCount:=k;
k:=0; k:=0;
for j := 0 to FDBGInfo.Fields.Count-1 do begin for j := 0 to FCurrentWatchValue.TypeInfo.Fields.Count-1 do begin
fld := FDBGInfo.Fields[j]; fld := FCurrentWatchValue.TypeInfo.Fields[j];
case fld.DBGType.Kind of case fld.DBGType.Kind of
skSimple: skSimple:
begin begin
@ -734,8 +949,8 @@ var
j,k: SizeInt; j,k: SizeInt;
begin begin
k:=0; k:=0;
for j := 0 to FDBGInfo.Fields.Count-1 do begin for j := 0 to FCurrentWatchValue.TypeInfo.Fields.Count-1 do begin
case FDBGInfo.Fields[j].DBGType.Kind of case FCurrentWatchValue.TypeInfo.Fields[j].DBGType.Kind of
skProcedure,skFunction,skProcedureRef, skFunctionRef: inc(k); skProcedure,skFunction,skProcedureRef, skFunctionRef: inc(k);
end; end;
end; end;
@ -743,13 +958,13 @@ begin
if k<2 Then k:=2; if k<2 Then k:=2;
FGridMethods.RowCount:=k; FGridMethods.RowCount:=k;
k:=0; k:=0;
for j := 0 to FDBGInfo.Fields.Count-1 do begin for j := 0 to FCurrentWatchValue.TypeInfo.Fields.Count-1 do begin
case FDBGInfo.Fields[j].DBGType.Kind of case FCurrentWatchValue.TypeInfo.Fields[j].DBGType.Kind of
skProcedure, skProcedureRef: skProcedure, skProcedureRef:
begin begin
inc(k); inc(k);
FGridMethods.Cells[0,k]:=FDBGInfo.Fields[j].Name; FGridMethods.Cells[0,k]:=FCurrentWatchValue.TypeInfo.Fields[j].Name;
if ffDestructor in FDBGInfo.Fields[j].Flags then begin if ffDestructor in FCurrentWatchValue.TypeInfo.Fields[j].Flags then begin
FGridMethods.Cells[1,k]:='Destructor'; FGridMethods.Cells[1,k]:='Destructor';
end else begin end else begin
FGridMethods.Cells[1,k]:='Procedure'; FGridMethods.Cells[1,k]:='Procedure';
@ -760,14 +975,14 @@ begin
skFunction, skFunctionRef: skFunction, skFunctionRef:
begin begin
inc(k); inc(k);
FGridMethods.Cells[0,k]:=FDBGInfo.Fields[j].Name; FGridMethods.Cells[0,k]:=FCurrentWatchValue.TypeInfo.Fields[j].Name;
if ffConstructor in FDBGInfo.Fields[j].Flags then begin if ffConstructor in FCurrentWatchValue.TypeInfo.Fields[j].Flags then begin
FGridMethods.Cells[1,k]:='Constructor'; FGridMethods.Cells[1,k]:='Constructor';
end else begin end else begin
FGridMethods.Cells[1,k]:='Function'; FGridMethods.Cells[1,k]:='Function';
end; end;
if Assigned(FDBGInfo.Fields[j].DBGType.Result) then begin if Assigned(FCurrentWatchValue.TypeInfo.Fields[j].DBGType.Result) then begin
FGridMethods.Cells[2,k]:=FDBGInfo.Fields[j].DBGType.Result.TypeName; FGridMethods.Cells[2,k]:=FCurrentWatchValue.TypeInfo.Fields[j].DBGType.Result.TypeName;
end else begin end else begin
FGridMethods.Cells[2,k]:=''; FGridMethods.Cells[2,k]:='';
end; end;
@ -824,16 +1039,21 @@ constructor TIDEInspectDlg.Create(AOwner: TComponent);
begin begin
inherited Create(AOwner); inherited Create(AOwner);
FUpdateLock := False;
FUpdateNeeded := False;
Localize; Localize;
ThreadsMonitor := DebugBoss.Threads; ThreadsMonitor := DebugBoss.Threads;
CallStackMonitor := DebugBoss.CallStack; CallStackMonitor := DebugBoss.CallStack;
WatchesMonitor := DebugBoss.Watches;
WatchesNotification.OnUpdate := @DoWatchUpdated;
FWatchPrinter := TWatchResultPrinter.Create;
FInspectWatches := TCurrentWatches.Create(WatchesMonitor);
ThreadsNotification.OnCurrent := @ContextChanged; ThreadsNotification.OnCurrent := @ContextChanged;
CallstackNotification.OnCurrent := @ContextChanged; CallstackNotification.OnCurrent := @ContextChanged;
DebugBoss.RegisterStateChangeHandler(@DoDebuggerState);
FHistory := TStringList.Create; FHistory := TStringList.Create;
FGridData:=TStringGrid.Create(DataPage); FGridData:=TStringGrid.Create(DataPage);
@ -877,12 +1097,16 @@ end;
destructor TIDEInspectDlg.Destroy; destructor TIDEInspectDlg.Destroy;
begin begin
FreeAndNil(FDBGInfo); DebugBoss.UnregisterStateChangeHandler(@DoDebuggerState);
ReleaseRefAndNil(FCurrentWatchValue);
FreeAndNil(FHistory); FreeAndNil(FHistory);
FreeAndNil(FWatchPrinter);
//FreeAndNil(FDataGridHook); //FreeAndNil(FDataGridHook);
//FreeAndNil(FPropertiesGridHook); //FreeAndNil(FPropertiesGridHook);
//FreeAndNil(FMethodsGridHook); //FreeAndNil(FMethodsGridHook);
inherited Destroy; inherited Destroy;
FreeAndNil(FInspectWatches);
end; end;
procedure TIDEInspectDlg.InternalExecute(const AExpression: ansistring); procedure TIDEInspectDlg.InternalExecute(const AExpression: ansistring);
@ -931,98 +1155,175 @@ begin
UpdateData; UpdateData;
end; end;
procedure TIDEInspectDlg.EvaluateCallback(Sender: TObject; ASuccess: Boolean;
ResultText: String; ResultDBGType: TDBGType); procedure TIDEInspectDlg.DoWatchUpdated(const ASender: TIdeWatches;
const AWatch: TIdeWatch);
begin begin
FUpdateLock := False; if (FCurrentWatchValue = nil) or
if FUpdateNeeded then begin not (FCurrentWatchValue.Validity in [ddsError, ddsInvalid, ddsValid])
Clear; then
UpdateData; exit;
if (AWatch <> FCurrentWatchValue.Watch) or
(ASender <> FInspectWatches)
then
exit;
if (FCurrentWatchValue.Validity in [ddsError, ddsInvalid]) and
(FAlternateExpression <> '')
then begin
if (FHistoryIndex = FHistory.Count - 1) and
(FHistory[FHistoryIndex] = FExpression)
then begin
FHistory.Delete(FHistoryIndex);
dec(FHistoryIndex);
end;
Execute(FAlternateExpression);
FAlternateExpression := '';
exit; exit;
end; end;
FAlternateExpression := '';
FExpressionWasEvaluated := True; FExpressionWasEvaluated := True;
FHumanReadable := FWatchPrinter.PrintWatchValue(FCurrentWatchValue.ResultData, wdfStructure);
FHumanReadable := ResultText; if FCurrentWatchValue.Validity = ddsValid then begin
FDBGInfo := ResultDBGType; if FCurrentWatchValue.TypeInfo <> nil then begin
case FCurrentWatchValue.TypeInfo.Kind of
if not ASuccess or not assigned(FDBGInfo) then skClass, skObject, skInterface: InspectClass();
begin skRecord: InspectRecord();
FreeAndNil(FDBGInfo); skVariant: InspectVariant();
Clear; skEnum: InspectEnum;
StatusBar1.SimpleText:=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]); skSet: InspectSet;
ErrorLabel.Caption :=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]); skProcedure, skProcedureRef: InspectSimple;
PageControl.ActivePage := ErrorPage; skFunction, skFunctionRef: InspectSimple;
Exit; skSimple,
end; skInteger,
case FDBGInfo.Kind of skCardinal, skBoolean, skChar, skFloat: InspectSimple();
skClass, skObject, skInterface: InspectClass(); skArray: InspectSimple();
skRecord: InspectRecord(); skPointer: InspectPointer();
skVariant: InspectVariant(); skString, skAnsiString, skWideString: InspectSimple;
skEnum: InspectEnum; // skDecomposable: ;
skSet: InspectSet; else begin
skProcedure, skProcedureRef: InspectSimple; Clear;
skFunction, skFunctionRef: InspectSimple; StatusBar1.SimpleText:=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
skSimple, ErrorLabel.Caption :=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
skInteger, PageControl.ActivePage := ErrorPage;
skCardinal, skBoolean, skChar, skFloat: InspectSimple(); end;
skArray: InspectSimple();
skPointer: InspectPointer();
skString, skAnsiString, skWideString: InspectSimple;
// skDecomposable: ;
else begin
Clear;
StatusBar1.SimpleText:=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
ErrorLabel.Caption :=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
PageControl.ActivePage := ErrorPage;
end; end;
end
else begin
// resultdata
case FCurrentWatchValue.ResultData.ValueKind of
//rdkError: ;
rdkPrePrinted,
rdkString,
rdkWideString,
rdkChar,
rdkSignedNumVal,
rdkUnsignedNumVal,
rdkFloatVal,
rdkBool,
rdkPCharOrString: InspectResDataSimple;
rdkPointerVal: InspectResDataPointer;
rdkEnum: InspectResDataEnum;
rdkEnumVal: InspectResDataEnum;
rdkSet: InspectResDataSet;
rdkArray: InspectResDataArray;
rdkStruct: InspectResDataStruct;
else begin
Clear;
StatusBar1.SimpleText:=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
ErrorLabel.Caption :=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
PageControl.ActivePage := ErrorPage;
end;
end;
end;
exit
end;
Clear;
StatusBar1.SimpleText:=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
ErrorLabel.Caption :=Format(lisInspectUnavailableError, [ShortenedExpression, FHumanReadable]);
PageControl.ActivePage := ErrorPage;
end;
procedure TIDEInspectDlg.DoDebuggerState(ADebugger: TDebuggerIntf;
AnOldState: TDBGState);
begin
if (ADebugger.State = dsPause) and (AnOldState <> dsPause) then begin
ReleaseRefAndNil(FCurrentWatchValue);
FInspectWatches.Clear;
UpdateData;
end; end;
end; end;
procedure TIDEInspectDlg.UpdateData; procedure TIDEInspectDlg.UpdateData;
var var
Opts: TWatcheEvaluateFlags; Opts: TWatcheEvaluateFlags;
AWatch: TCurrentWatch;
tid, idx: Integer;
stack: TIdeCallStack;
expr: String;
begin begin
FExpressionWasEvaluated := False; FExpressionWasEvaluated := False;
if DebugBoss.State in [dsRun, dsStop, dsIdle] then begin FAlternateExpression := '';
// No request can be running
FUpdateLock := False;
FTestUpdateLock := False;
end;
if FUpdateLock then begin expr := trim(FExpression);
FUpdateNeeded := True; if expr = '' then begin
exit; ReleaseRefAndNil(FCurrentWatchValue);
end;
if FExpression = '' then begin
Clear; Clear;
StatusBar1.SimpleText := ''; StatusBar1.SimpleText := '';
exit; exit;
end; end;
FUpdateLock := True; InputHistories.HistoryLists.Add(ClassName, FExpression,rltCaseSensitive);
FUpdateNeeded := False; if EdInspect.Items.IndexOf(FExpression) = -1
try then EdInspect.Items.Insert(0, FExpression);
FreeAndNil(FDBGInfo);
InputHistories.HistoryLists.Add(ClassName, FExpression,rltCaseSensitive);
if EdInspect.Items.IndexOf(FExpression) = -1
then EdInspect.Items.Insert(0, FExpression);
Opts := [defFullTypeInfo]; if (CallStackMonitor = nil) or (ThreadsMonitor = nil) or
if btnUseInstance.Down then (DebugBoss.State <> dsPause)
include(Opts, defClassAutoCast); then
exit;
if not DebugBoss.Evaluate(FExpression, @EvaluateCallback, Opts) then tid := ThreadsMonitor.CurrentThreads.CurrentThreadId;
EvaluateCallback(nil, False, '', nil); stack := CallStackMonitor.CurrentCallStackList.EntriesForThreads[tid];
idx := 0;
if stack <> nil then
idx := stack.CurrentIndex;
except Opts := [defFullTypeInfo];
FUpdateLock := False; if btnUseInstance.Down then
include(Opts, defClassAutoCast);
if (FCurrentWatchValue <> nil) and
(FCurrentWatchValue.Expression = expr) and
(FCurrentWatchValue.EvaluateFlags = Opts) and
(FCurrentWatchValue.ThreadId = tid) and
(FCurrentWatchValue.StackFrame = idx)
then begin
FCurrentWatchValue.Value;
DoWatchUpdated(nil, FCurrentWatchValue.Watch);
exit;
end; end;
if FUpdateNeeded then ReleaseRefAndNil(FCurrentWatchValue);
UpdateData;
FInspectWatches.BeginUpdate;
AWatch := FInspectWatches.Find(expr);
if AWatch = nil then begin
FInspectWatches.Clear;
AWatch := FInspectWatches.Add(expr);
end;
AWatch.EvaluateFlags := Opts;
AWatch.Enabled := True;
FInspectWatches.EndUpdate;
FCurrentWatchValue := AWatch.Values[tid, idx];
if FCurrentWatchValue <> nil then begin
FCurrentWatchValue.AddReference;
FCurrentWatchValue.Value;
end;
end; end;
initialization initialization

View File

@ -91,6 +91,8 @@ const
type type
TDebuggerStateChangeNotification = procedure(ADebugger: TDebuggerIntf; AnOldState: TDBGState) of object;
{ TBaseDebugManager } { TBaseDebugManager }
TDebugManagerState = ( TDebugManagerState = (
@ -222,6 +224,9 @@ type
procedure ViewDisassembler(AnAddr: TDBGPtr; procedure ViewDisassembler(AnAddr: TDBGPtr;
BringToFront: Boolean = True; Show: Boolean = true; BringToFront: Boolean = True; Show: Boolean = true;
DoDisableAutoSizing: boolean = false); virtual; abstract; DoDisableAutoSizing: boolean = false); virtual; abstract;
procedure RegisterStateChangeHandler(AHandler: TDebuggerStateChangeNotification); virtual; abstract;
procedure UnregisterStateChangeHandler(AHandler: TDebuggerStateChangeNotification); virtual; abstract;
public public
property Commands: TDBGCommands read GetCommands; // All current available commands of the debugger property Commands: TDBGCommands read GetCommands; // All current available commands of the debugger
property Destroying: boolean read FDestroying; property Destroying: boolean read FDestroying;

View File

@ -45,6 +45,7 @@ uses
LCLType, LCLIntf, Forms, Controls, Dialogs, ExtCtrls, LCLType, LCLIntf, Forms, Controls, Dialogs, ExtCtrls,
// LazUtils // LazUtils
LazFileUtils, LazFileCache, LazLoggerBase, Laz2_XMLCfg, LazUTF8, LazTracer, LazFileUtils, LazFileCache, LazLoggerBase, Laz2_XMLCfg, LazUTF8, LazTracer,
LazMethodList,
// codetools // codetools
CodeCache, CodeToolManager, PascalParserTool, CodeTree, CodeCache, CodeToolManager, PascalParserTool, CodeTree,
// IDEIntf // IDEIntf
@ -142,6 +143,7 @@ type
FCurrentBreakpoint: TIDEBreakpoint; FCurrentBreakpoint: TIDEBreakpoint;
FAutoContinueTimer: TTimer; FAutoContinueTimer: TTimer;
FIsInitializingDebugger: Boolean; FIsInitializingDebugger: Boolean;
FStateNotificationList: TMethodList;
// When a source file is not found, the user can choose one // When a source file is not found, the user can choose one
// here are all choices stored // here are all choices stored
@ -283,6 +285,9 @@ type
procedure ViewDisassembler(AnAddr: TDBGPtr; procedure ViewDisassembler(AnAddr: TDBGPtr;
BringToFront: Boolean = True; Show: Boolean = true; BringToFront: Boolean = True; Show: Boolean = true;
DoDisableAutoSizing: boolean = false); override; DoDisableAutoSizing: boolean = false); override;
procedure RegisterStateChangeHandler(AHandler: TDebuggerStateChangeNotification); override;
procedure UnregisterStateChangeHandler(AHandler: TDebuggerStateChangeNotification); override;
end; end;
function DBGDateTimeFormatter(const aValue: string): string; function DBGDateTimeFormatter(const aValue: string): string;
@ -1344,6 +1349,9 @@ begin
UnlockDialogs; UnlockDialogs;
for i := 0 to FStateNotificationList.Count-1 do
TDebuggerStateChangeNotification(FStateNotificationList[i])(ADebugger, OldState);
if FDebugger.State = dsInternalPause if FDebugger.State = dsInternalPause
then exit; then exit;
@ -1743,6 +1751,18 @@ begin
then TAssemblerDlg(FDialogs[ddtAssembler]).SetLocation(FDebugger, FCurrentLocation.Address, AnAddr); then TAssemblerDlg(FDialogs[ddtAssembler]).SetLocation(FDebugger, FCurrentLocation.Address, AnAddr);
end; end;
procedure TDebugManager.RegisterStateChangeHandler(
AHandler: TDebuggerStateChangeNotification);
begin
FStateNotificationList.Add(TMethod(AHandler));
end;
procedure TDebugManager.UnregisterStateChangeHandler(
AHandler: TDebuggerStateChangeNotification);
begin
FStateNotificationList.Remove(TMethod(AHandler));
end;
procedure TDebugManager.DestroyDebugDialog(const ADialogType: TDebugDialogType); procedure TDebugManager.DestroyDebugDialog(const ADialogType: TDebugDialogType);
begin begin
if FDialogs[ADialogType] = nil then Exit; if FDialogs[ADialogType] = nil then Exit;
@ -1917,6 +1937,7 @@ begin
FSnapshots.Locals := FLocals; FSnapshots.Locals := FLocals;
FSnapshots.UnitInfoProvider := FUnitInfoProvider; FSnapshots.UnitInfoProvider := FUnitInfoProvider;
FStateNotificationList := TMethodList.Create;
FUserSourceFiles := TStringList.Create; FUserSourceFiles := TStringList.Create;
FAutoContinueTimer := TTimer.Create(Self); FAutoContinueTimer := TTimer.Create(Self);
@ -1975,6 +1996,7 @@ begin
FreeAndNil(FUserSourceFiles); FreeAndNil(FUserSourceFiles);
FreeAndNil(FHiddenDebugOutputLog); FreeAndNil(FHiddenDebugOutputLog);
FreeAndNil(FUnitInfoProvider); FreeAndNil(FUnitInfoProvider);
FreeAndNil(FStateNotificationList);
inherited Destroy; inherited Destroy;
end; end;