Delphi 努。 函数TDebuggerSimpleTStringsVisualizer.GetReplacementValue( 常量表达式,TypeName,EvalResult:string):字符串; 变量 Lang:TTypeLang; i:整数; CurP
努。 函数TDebuggerSimpleTStringsVisualizer.GetReplacementValue( 常量表达式,TypeName,EvalResult:string):字符串; 变量 Lang:TTypeLang; i:整数; CurProcess:IOTAProcess; CurThread:IOTAThread; ResultStr:Char的数组[0..4095];//是255 CanModify:布尔型; resultadr,ResultSize,ResultVal:LongWord; 评估:总评估结果; DebugSvcs:IOTADebuggerServices; 函数FormatResult(常量输入:字符串;输出:字符串):布尔值; 变量 TL:TStringList; i:整数; S:字符串; 常数 CRLFdisplated='#$D#$A'; 开始 结果:=真; ResStr:=''; TL:=TStringList.Create; 尝试 S:=输入; S:=StringReplace(S,crlfdisplated,#13#10,[rfReplaceAll]); TL.文本:=S; 对于i:=0到TL。计数-1开始 S:=TL[i]; 如果是“”,则开始 如果S[1]='',则//删除行首的单引号 删除(S,1,1); 如果S[Length(S)]='',则//删除行尾的单引号 S:=副本,1,长度-1; 结束; 如果为“”则 ResStr:=ResStr+CRLF替换; ResStr:=ResStr+S; 结束; 最后 TL.免费; 结束; 结束; 开始 Lang:=tlDelphi; 如果Lang=tlDelphi,那么 开始 如果支持(设备、IOTADebuggerServices、调试SVC),则 CurProcess:=DebugSvcs.CurrentProcess; 如果为零,则 开始 CurThread:=CurProcess.CurrentThread; 如果CurThread为零,则 开始 EvalRes:=CurThread.Evaluate(表达式+'.Text',@ResultStr,长度(ResultStr), 可以修改,eseAll',resultadr,ResultSize,ResultVal',0); 如果EvalRes=erOK,则 开始 结果:=ResultStr; 如果EvalRes=erDeferred则结束else 开始 FCompleted:=假; FDeferredResult:=''; FNotifierIndex:=CurThread.AddNotifier(Self); 虽然还没有完成,但你要做什么 DebugSvcs.ProcessDebugEvents; CurThread.RemoveNotifier(FNotifierIndex); FNotifierIndex:=-1; 如果(FDeferredResult=''),则 结果:=EvalResult 其他的 FormatResult(FDeferredResult,Result); 结束; 结束; 结束; 结束 其他的 ; 结束; 程序TDebuggerSimpleTStringsVisualizer.AfterSave; 开始 //不在乎这个通知 结束; 程序TDebuggerSimpleTStringsVisualizer.BeforeSave; 开始 //不在乎这个通知 结束; 程序TDebuggerSimpleTStringsVisualizer.已销毁; 开始 //不在乎这个通知 结束; 程序TDebuggerSimpleTStringsVisualizer.Modified; 开始 //不在乎这个通知 结束; 程序TDebuggerSimpleTStringsVisualizer.ModifyComplete(const ExprStr, ResultStr:string;ReturnCode:Integer); 开始 //不在乎这个通知 结束; 程序TDebuggerSimpleTStringsVisualizer.EvaluteComplete(const ExprStr, ResultStr:string;CanModify:Boolean;ResultAddress,ResultSize:Cardinal; 返回代码:整数); 开始 EvaluateComplete(ExprStr、ResultStr、CanModify、TOTAAddress(ResultAddress)), LongWord(ResultSize),返回码; 结束; 程序TDebuggerSimpleTStringsVisualizer.EvaluateComplete(const ExprStr, ResultStr:string;CanModify:Boolean;ResultAddress:TOTAAddress;ResultSize:LongWord; 返回代码:整数); 开始 FCompleted:=真; 如果ReturnCode=0,则 FDeferredResult:=ResultStr; 结束; 函数TDebuggerSimpleTStringsVisualizer.GetSupportedTypeCount:整数; 开始 结果:=1; 结束; 过程TDebuggerSimpleTStringsVisualizer.GetSupportedType(索引:整数;变量类型名称:字符串; 变量:布尔型); 开始 所有后代:=真; TypeName:=“TStrings”; 结束; 函数TDebuggerSimpleTStringsVisualizer.GetVisualizardDescription:string; 开始 结果:=sVisualizerDescription; 结束; 函数TDebuggerSimpleTStringsVisualizer.GetVisualizationRidentifier:string; 开始 结果:=类名; 结束; 函数TDebuggerSimpleTStringsVisualizer.GetVisualizerName:string; 开始 结果:=sVisualizerName; 结束; 程序TDebuggerSimpleTStringsVisualizer.ThreadNotify(原因:TOTANotifyReason); 开始 //不在乎这个通知 结束; 变量 TStringsVis:IotadeBugger可视化仪; 程序登记册; 开始 TStringsVis:=TDebuggerSimpleTStringsVisualizer.Create; (作为IOTADebuggerServices的Borlandiser设备)。注册的电子布格可视化工具(TStringsVis); 结束; 程序移除可视化工具; 变量 调试服务:IOTADebuggerServices; 开始 如果支持(BorlandeDeservices、IOTADebuggerServices、DebuggerServices),则 开始 DebuggerServices.UnregisterDebuggerVisualizer(TStringsVis); TStringsVis:=零; 结束; 结束; 初始化 定稿 远程可视化仪; 结束。Delphi 努。 函数TDebuggerSimpleTStringsVisualizer.GetReplacementValue( 常量表达式,TypeName,EvalResult:string):字符串; 变量 Lang:TTypeLang; i:整数; CurP,delphi,debugging,delphi-xe3,Delphi,Debugging,Delphi Xe3,努。 函数TDebuggerSimpleTStringsVisualizer.GetReplacementValue( 常量表达式,TypeName,EvalResult:string):字符串; 变量 Lang:TTypeLang; i:整数; CurProcess:IOTAProcess; CurThread:IOTAThread; ResultStr:Char的数组[0..4095];//是255 CanModify:布尔型; resultadr,ResultSize,ResultVal:
如果语句长度超过4K,我必须在监视窗口中放置一个
ShowMessage(..)
,因为调试器字符串大小限制,这一点已经讨论过了。是否有技巧/解决方法?不可以。如果字符串ist包含在TStrings实例中(在您的示例中,我看到“memo1”),那么您可以“计算”术语“memo1.Lines.SaveToFile()”。这将执行“SaveToFile”,文本将保存在一个文件中。@rk\u cpa这只是示例。现实世界查询的另一个问题是使用sql参数,这些参数在querx文本中没有展开……这就是使用参数的意图。由DBMS将参数值合并到查询语句中。在这里,ANSIDEQUOTEDSTR可能是处理SQL字符串文字的一个有用的补充。@MattAllwood:的确,感谢您的建议-我在关于D7的注释后面添加了它。@MartynA我尝试了您的建议,但使用了Delphi XE3,TListView
已替换为TVirtualStringTree
…@MattAllwood非常感谢您指向此函数。由于我很懒(而且没有ide扩展程序员),我现在可以创建一个简单的VCL项目
'SELECT NAME FROM SAMPLE_TABLE WHERE FIRST_NAME = ''George'''#$D#$A
unit IdeMenuProcessing;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ToolsAPI, Menus, ClipBrd, ComCtrls;
type
TOtaMenuForm = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
OurMenuItem : TMenuItem;
WatchWindow : TForm;
WWListView : TListView;
procedure GetWatchValue(Sender : TObject);
end;
var
OtaMenuForm: TOtaMenuForm;
procedure Register;
implementation
{$R *.dfm}
procedure ShowMenus;
begin
OtaMenuForm := TOtaMenuForm.Create(Nil);
OtaMenuForm.Show;
end;
procedure Register;
begin
ShowMenus;
end;
procedure TOtaMenuForm.FormCreate(Sender: TObject);
var
i : Integer;
S : String;
PM : TPopUpMenu;
Item : TMenuItem;
begin
// First create a menu item to insert in the Watch Window's context menu
OurMenuItem := TMenuItem.Create(Self);
OurMenuItem.OnClick := GetWatchValue;
OurMenuItem.Caption := 'Get processed watch value';
WatchWindow := Nil;
WWListView := Nil;
// Next, iterate the IDE's forms to find the Watch Window
for i := 0 to Screen.FormCount - 1 do begin
S := Screen.Forms[i].Name;
if CompareText(S, 'WatchWindow') = 0 then begin // < Localize if necessary
WatchWindow := Screen.Forms[i];
Break;
end;
end;
Assert(WatchWindow <> Nil);
if WatchWindow <> Nil then begin
// Next, scan the Watch Window's context menu to find the existing "Copy watch value" entry
// and insert our menu iem after it
PM := WatchWindow.PopUpMenu;
for i:= 0 to PM.Items.Count - 1 do begin
Item := PM.Items[i];
if CompareText('Copy Watch &Value', Item.Caption) = 0 then begin // < Localize if necessary
PM.Items.Insert(i + 1, OurMenuItem);
Break;
end;
end;
// Now, find the TListView in the Watch Window
for i := 0 to WatchWindow.ComponentCount - 1 do begin
if WatchWindow.Components[i] is TListView then begin
WWListView := WatchWindow.Components[i] as TListView;
Break;
end;
end;
Assert(WWListView <> Nil);
end;
end;
procedure TOtaMenuForm.GetWatchValue(Sender: TObject);
var
WatchValue : String;
begin
// This is called when the Watch Window menu item we added is clicked
if WWListView.ItemFocused = Nil then begin
Memo1.Lines.Add('no Watch selected');
exit;
end;
WatchValue := WWListView.ItemFocused.SubItems[0];
WatchValue := StringReplace(WatchValue, #$D#$A, ' ', [rfreplaceAll]);
if WatchValue[1] = '''' then
Delete(WatchValue, 1, 1);
if WatchValue[Length(WatchValue)] = '''' then
WatchValue := Copy(WatchValue, 1, Length(WatchValue) - 1);
// [etc]
ClipBoard.AsText := WatchValue;
Memo1.Lines.Add('>' + WatchValue + '<');
end;
initialization
finalization
if Assigned(OTAMenuForm) then begin
OTAMenuForm.Close;
FreeAndNil(OTAMenuForm);
end;
end.
unit IdeMenuProcessing;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ToolsAPI, Menus, ClipBrd, ComCtrls;
type
TIdeNotifier = class(TNotifierObject, IOTANotifier, IOTAIDENotifier)
protected
procedure AfterCompile(Succeeded: Boolean);
procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
procedure FileNotification(NotifyCode: TOTAFileNotification;
const FileName: string; var Cancel: Boolean);
end;
TOtaMenuForm = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
IsSetUp : Boolean;
ExistingMenuItem,
OurMenuItem : TMenuItem;
WatchWindow : TForm;
Services: IOTAServices;
Notifier : TIdeNotifier;
NotifierIndex: Integer;
procedure GetWatchValue(Sender : TObject);
procedure SetUp;
end;
var
OtaMenuForm: TOtaMenuForm;
procedure Register;
implementation
{$R *.dfm}
procedure ShowMenus;
begin
OtaMenuForm := TOtaMenuForm.Create(Nil);
OtaMenuForm.Services := BorlandIDEServices as IOTAServices;
OtaMenuForm.NotifierIndex := OtaMenuForm.Services.AddNotifier(TIdeNotifier.Create);
OtaMenuForm.Show;
end;
procedure Register;
begin
ShowMenus;
end;
procedure TOtaMenuForm.SetUp;
var
i : Integer;
S : String;
PM : TPopUpMenu;
Item : TMenuItem;
begin
if IsSetUp then exit;
// First create a menu item to insert in the Watch Window's context menu
OurMenuItem := TMenuItem.Create(Self);
OurMenuItem.OnClick := GetWatchValue;
OurMenuItem.Caption := 'Get processed watch value';
WatchWindow := Nil;
// Next, iterate the IDE's forms to find the Watch Window
for i := 0 to Screen.FormCount - 1 do begin
S := Screen.Forms[i].Name;
if CompareText(S, 'WatchWindow') = 0 then begin
WatchWindow := Screen.Forms[i];
Break;
end;
end;
Assert(WatchWindow <> Nil);
if WatchWindow <> Nil then begin
// Next, scan the Watch Window's context menu to find the existing "Copy watch value" entry
// and insert our menu item after it
PM := WatchWindow.PopUpMenu;
for i:= 0 to PM.Items.Count - 1 do begin
Item := PM.Items[i];
if CompareText('Copy Watch &Value', Item.Caption) = 0 then begin
ExistingMenuItem := Item;
PM.Items.Insert(i + 1, OurMenuItem);
if ExistingMenuItem.Action <> Nil then
Memo1.Lines.Add('Has action')
else
Memo1.Lines.Add('No action');
Break;
end;
end;
end;
Caption := 'Setup complete';
IsSetUp := True;
end;
procedure TOtaMenuForm.FormCreate(Sender: TObject);
begin
IsSetUp := False;
end;
procedure TOtaMenuForm.GetWatchValue(Sender: TObject);
var
S,
WatchValue : String;
TL : TStringList;
i : Integer;
begin
// This is called when the Watch Window menu item we added is clicked
ExistingMenuItem.Click;
WatchValue := ClipBoard.AsText;
WatchValue := StringReplace(WatchValue, '#$D#$A', #$D#$A, [rfreplaceAll]);
if WatchValue <> '' then begin
TL := TStringList.Create;
try
TL.Text := WatchValue;
WatchValue := '';
for i := 0 to TL.Count - 1 do begin
S := TL[i];
if S[1] = '''' then
Delete(S, 1, 1);
if S[Length(S)] = '''' then
S := Copy(S, 1, Length(S) - 1);
if WatchValue <> '' then
WatchValue := WatchValue + ' ';
WatchValue := WatchValue + S;
end;
finally
TL.Free;
end;
// [etc]
end;
ClipBoard.AsText := WatchValue;
Memo1.Lines.Add('>' + WatchValue + '<');
end;
{ TIdeNotifier }
procedure TIdeNotifier.AfterCompile(Succeeded: Boolean);
begin
end;
procedure TIdeNotifier.BeforeCompile(const Project: IOTAProject;
var Cancel: Boolean);
begin
end;
procedure TIdeNotifier.FileNotification(NotifyCode: TOTAFileNotification;
const FileName: string; var Cancel: Boolean);
begin
if NotifyCode = ofnProjectDesktopLoad then
OTAMenuForm.SetUp
end;
initialization
finalization
if Assigned(OTAMenuForm) then begin
OTAMenuForm.Services.RemoveNotifier(OTAMenuForm.NotifierIndex);
OTAMenuForm.Close;
FreeAndNil(OTAMenuForm);
end;
end.
{*******************************************************}
{ }
{ RadStudio Debugger Visualizer Sample }
{ Copyright(c) 2009-2013 Embarcadero Technologies, Inc. }
{ }
{*******************************************************}
{Adapted by Martyn Ayers, Bristol, UK Oct 2015}
unit SimpleTStringsVisualizeru;
interface
procedure Register;
implementation
uses
Classes, Forms, SysUtils, ToolsAPI;
resourcestring
sVisualizerName = 'TStrings Simple Visualizer for Delphi';
sVisualizerDescription = 'Simplifies TStrings Text property format';
const
CRLFReplacement = ' ';
type
TDebuggerSimpleTStringsVisualizer = class(TInterfacedObject,
IOTADebuggerVisualizer, IOTADebuggerVisualizerValueReplacer,
IOTAThreadNotifier, IOTAThreadNotifier160)
private
FNotifierIndex: Integer;
FCompleted: Boolean;
FDeferredResult: string;
public
{ IOTADebuggerVisualizer }
function GetSupportedTypeCount: Integer;
procedure GetSupportedType(Index: Integer; var TypeName: string;
var AllDescendants: Boolean);
function GetVisualizerIdentifier: string;
function GetVisualizerName: string;
function GetVisualizerDescription: string;
{ IOTADebuggerVisualizerValueReplacer }
function GetReplacementValue(const Expression, TypeName, EvalResult: string): string;
{ IOTAThreadNotifier }
procedure EvaluteComplete(const ExprStr: string; const ResultStr: string;
CanModify: Boolean; ResultAddress: Cardinal; ResultSize: Cardinal;
ReturnCode: Integer);
procedure ModifyComplete(const ExprStr: string; const ResultStr: string;
ReturnCode: Integer);
procedure ThreadNotify(Reason: TOTANotifyReason);
procedure AfterSave;
procedure BeforeSave;
procedure Destroyed;
procedure Modified;
{ IOTAThreadNotifier160 }
procedure EvaluateComplete(const ExprStr: string; const ResultStr: string;
CanModify: Boolean; ResultAddress: TOTAAddress; ResultSize: LongWord;
ReturnCode: Integer);
end;
TTypeLang = (tlDelphi, tlCpp);
// The following function is the one which actually changes the TStrings
// representation in the Watch Window
//
// Normally, the Text property of TStrings variable is displayed in the Watch Window
// and Evaluate window as one or more text lines surrounded by single quotes
// and separated by the string #$D#$A
//
// This implementation removes the single quotes and replaces the #$D#$A
// by a space
//
// Note the addition of '.Text' to the expression which gets evaluated; this is to
// produce the desired result when using the 'Copy Watch Value' item in the
// Watch Window context menu.
function TDebuggerSimpleTStringsVisualizer.GetReplacementValue(
const Expression, TypeName, EvalResult: string): string;
var
Lang: TTypeLang;
i: Integer;
CurProcess: IOTAProcess;
CurThread: IOTAThread;
ResultStr: array[0..4095] of Char; // was 255
CanModify: Boolean;
ResultAddr, ResultSize, ResultVal: LongWord;
EvalRes: TOTAEvaluateResult;
DebugSvcs: IOTADebuggerServices;
function FormatResult(const Input: string; out ResStr: string): Boolean;
var
TL : TStringList;
i : Integer;
S : String;
const
CRLFDisplayed = '#$D#$A';
begin
Result := True;
ResStr := '';
TL := TStringList.Create;
try
S := Input;
S := StringReplace(S, CRLFDisplayed, #13#10, [rfReplaceAll]);
TL.Text := S;
for i := 0 to TL.Count - 1 do begin
S := TL[i];
if S <> '' then begin
if S[1] = '''' then // Remove single quote at start of line
Delete(S, 1, 1);
if S[Length(S)] = '''' then // Remove single quote at end of line
S := Copy(S, 1, Length(S) - 1);
end;
if ResStr <> '' then
ResStr := ResStr + CRLFReplacement;
ResStr := ResStr + S;
end;
finally
TL.Free;
end;
end;
begin
Lang := tlDelphi;
if Lang = tlDelphi then
begin
if Supports(BorlandIDEServices, IOTADebuggerServices, DebugSvcs) then
CurProcess := DebugSvcs.CurrentProcess;
if CurProcess <> nil then
begin
CurThread := CurProcess.CurrentThread;
if CurThread <> nil then
begin
EvalRes := CurThread.Evaluate(Expression + '.Text', @ResultStr, Length(ResultStr),
CanModify, eseAll, '', ResultAddr, ResultSize, ResultVal, '', 0);
if EvalRes = erOK then
begin
Result := ResultStr;
end else if EvalRes = erDeferred then
begin
FCompleted := False;
FDeferredResult := '';
FNotifierIndex := CurThread.AddNotifier(Self);
while not FCompleted do
DebugSvcs.ProcessDebugEvents;
CurThread.RemoveNotifier(FNotifierIndex);
FNotifierIndex := -1;
if (FDeferredResult = '') then
Result := EvalResult
else
FormatResult(FDeferredResult, Result);
end;
end;
end;
end
else
;
end;
procedure TDebuggerSimpleTStringsVisualizer.AfterSave;
begin
// don't care about this notification
end;
procedure TDebuggerSimpleTStringsVisualizer.BeforeSave;
begin
// don't care about this notification
end;
procedure TDebuggerSimpleTStringsVisualizer.Destroyed;
begin
// don't care about this notification
end;
procedure TDebuggerSimpleTStringsVisualizer.Modified;
begin
// don't care about this notification
end;
procedure TDebuggerSimpleTStringsVisualizer.ModifyComplete(const ExprStr,
ResultStr: string; ReturnCode: Integer);
begin
// don't care about this notification
end;
procedure TDebuggerSimpleTStringsVisualizer.EvaluteComplete(const ExprStr,
ResultStr: string; CanModify: Boolean; ResultAddress, ResultSize: Cardinal;
ReturnCode: Integer);
begin
EvaluateComplete(ExprStr, ResultStr, CanModify, TOTAAddress(ResultAddress),
LongWord(ResultSize), ReturnCode);
end;
procedure TDebuggerSimpleTStringsVisualizer.EvaluateComplete(const ExprStr,
ResultStr: string; CanModify: Boolean; ResultAddress: TOTAAddress; ResultSize: LongWord;
ReturnCode: Integer);
begin
FCompleted := True;
if ReturnCode = 0 then
FDeferredResult := ResultStr;
end;
function TDebuggerSimpleTStringsVisualizer.GetSupportedTypeCount: Integer;
begin
Result := 1;
end;
procedure TDebuggerSimpleTStringsVisualizer.GetSupportedType(Index: Integer; var TypeName: string;
var AllDescendants: Boolean);
begin
AllDescendants := True;
TypeName := 'TStrings';
end;
function TDebuggerSimpleTStringsVisualizer.GetVisualizerDescription: string;
begin
Result := sVisualizerDescription;
end;
function TDebuggerSimpleTStringsVisualizer.GetVisualizerIdentifier: string;
begin
Result := ClassName;
end;
function TDebuggerSimpleTStringsVisualizer.GetVisualizerName: string;
begin
Result := sVisualizerName;
end;
procedure TDebuggerSimpleTStringsVisualizer.ThreadNotify(Reason: TOTANotifyReason);
begin
// don't care about this notification
end;
var
TStringsVis: IOTADebuggerVisualizer;
procedure Register;
begin
TStringsVis := TDebuggerSimpleTStringsVisualizer.Create;
(BorlandIDEServices as IOTADebuggerServices).RegisterDebugVisualizer(TStringsVis);
end;
procedure RemoveVisualizer;
var
DebuggerServices: IOTADebuggerServices;
begin
if Supports(BorlandIDEServices, IOTADebuggerServices, DebuggerServices) then
begin
DebuggerServices.UnregisterDebugVisualizer(TStringsVis);
TStringsVis := nil;
end;
end;
initialization
finalization
RemoveVisualizer;
end.