【问题标题】:Delphi 2007: save only the breakpoint options in the DSK file?Delphi 2007:只保存 DSK 文件中的断点选项?
【发布时间】:2014-12-04 07:46:38
【问题描述】:

是否可以在 Delphi 中只将断点保存在项目的 .DSK 文件中而无需其他桌面设置?

大多数 .DSK 都会阻碍,但无法保存调试断点确实很痛苦(尤其是当它们是有条件的或附加了操作时)。

【问题讨论】:

标签: delphi delphi-2007


【解决方案1】:

我从未遇到过仅将断点相关设置保存在 .Dsk 文件中的 IDE 工具。

为了消遣,我想我会尝试通过使用 OTA 通知的 IDE 插件来实现一些东西。下面的代码在安装在 D7 中的包中运行良好,并且 IDE 似乎很乐意重新打开已处理 .Dsk 文件的项目(并且设置了断点!)。

如您所见,当使用 ofnProjectDesktopSave 的 NotifyCode 调用时,它会捕获 OTA 通知程序的 FileNotification 事件,该事件发生在 IDE 保存 .Dsk 文件之后(最初扩展名为 '.$$$',我失败了在第一次写这篇文章时要注意)。然后它读取保存的文件文件,并准备一个更新版本,从中删除除指定的部分列表之外的所有部分。然后,用户可以选择将精简后的文件保存回磁盘。我使用 TMemIniFile 来完成大部分处理,只是为了尽量减少所需的代码量。

当我阅读您的 q 时,我没有编写 OTA 通知程序的经验,但下面引用的 GE 专家常见问题解答非常有用,尤其是示例通知程序代码。

通常,删除项目的 .Dsk 文件是无害的,但请谨慎使用此代码,因为它未经压力测试。

更新: 我注意到 TIdeNotifier.FileNotification 事件收到的文件名实际上有一个扩展名 '.$$$'。我不太确定为什么会这样,但似乎在文件重命名为 xxx.Dsk 之前调用了该事件。我认为这需要改变如何 保存精简版,但显然不是。

更新#2: 使用文件夹监控实用程序查看实际发生的情况后,代码收到的桌面保存通知只是与.Dsk 文件。其中包括将 .Dsk 文件的任何现有版本重命名为 .~Dsk 文件,最后将 .$$$ 文件保存为新的 .Dsk 文件。

unit DskFilesu;

interface

{$define ForDPK}  // undefine to test in regular app

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Buttons, StdCtrls, IniFiles, TypInfo
{$ifdef ForDPK}
  , ToolsApi
{$endif}
  ;

{$ifdef ForDPK}

{
  Code for OTA TIdeNotifier adapted from, and courtesy of, the link on http://www.gexperts.org/open-tools-api-faq/#idenotifier
}

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;
{$endif}

type
  TDskForm = class(TForm)
    edDskFileName: TEdit;
    SpeedButton1: TSpeedButton;
    OpenDialog1: TOpenDialog;
    lbSectionsToKeep: TListBox;
    lbDskSections: TListBox;
    moDskFile: TMemo;
    btnSave: TButton;
    procedure btnSaveClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
  private
    procedure GetSectionsToKeep;
    function GetDskFileName: String;
    procedure SetDskFileName(const Value: String);
    function GetDskFile: Boolean;
  protected
  public
    DskIni : TMemIniFile;
    property DskFileName : String read GetDskFileName write SetDskFileName;
  end;

var
  NotifierIndex: Integer;
  DskForm: TDskForm;

{$ifdef ForDPK}
procedure Register;
{$endif}

implementation

{$R *.DFM}

{$ifdef ForDPK}
procedure Register;
var
  Services: IOTAServices;
begin
  Services := BorlandIDEServices as IOTAServices;
  Assert(Assigned(Services), 'IOTAServices not available');
  NotifierIndex := Services.AddNotifier(TIdeNotifier.Create);
end;
{$endif}

procedure DskPopUp(FileName : String);
var
  F : TDskForm;
begin
  F := TDskForm.Create(Application);
  try
    F.DskFileName := FileName;
    F.ShowModal;
  finally
    F.Free;
  end;
end;

function TDskForm.GetDskFileName: String;
begin
  Result := edDskFileName.Text;
end;

procedure TDskForm.SetDskFileName(const Value: String);
begin
  edDskFileName.Text := Value;
  if Assigned(DskIni) then
    FreeAndNil(DskIni);
  btnSave.Enabled := False;

  DskIni  := TMemIniFile.Create(DskFileName);
  DskIni.ReadSections(lbDskSections.Items);
  GetSectionsToKeep;
end;

procedure TDskForm.btnSaveClick(Sender: TObject);
begin
  DskIni.UpdateFile;
end;

procedure TDskForm.FormCreate(Sender: TObject);
begin
  lbSectionsToKeep.Items.Add('watches');
  lbSectionsToKeep.Items.Add('breakpoints');
  lbSectionsToKeep.Items.Add('addressbreakpoints');

  if not IsLibrary then
    DskFileName := ChangeFileExt(Application.ExeName, '.Dsk');
end;

procedure TDskForm.GetSectionsToKeep;
var
  i,
  Index : Integer;
  SectionName : String;
begin
  moDskFile.Lines.Clear;
  for i := lbDskSections.Items.Count - 1 downto 0 do begin
    SectionName := lbDskSections.Items[i];
    Index := lbSectionsToKeep.Items.IndexOf(SectionName);
    if Index < 0 then
      DskIni.EraseSection(SectionName);
  end;
  DskIni.GetStrings(moDskFile.Lines);
  btnSave.Enabled := True;
end;

function TDskForm.GetDskFile: Boolean;
begin
  OpenDialog1.FileName := DskFileName;
  Result := OpenDialog1.Execute;
  if Result then
    DskFileName := OpenDialog1.FileName;
end;

procedure TDskForm.SpeedButton1Click(Sender: TObject);
begin
  GetDskFile;
end;

{$ifdef ForDPK}

procedure RemoveNotifier;
var
  Services: IOTAServices;
begin
  if NotifierIndex <> -1 then
  begin
    Services := BorlandIDEServices as IOTAServices;
    Assert(Assigned(Services), 'IOTAServices not available');
    Services.RemoveNotifier(NotifierIndex);
  end;
end;

function MsgServices: IOTAMessageServices;
begin
  Result := (BorlandIDEServices as IOTAMessageServices);
  Assert(Result <> nil, 'IOTAMessageServices not available');
end;

procedure TIdeNotifier.AfterCompile(Succeeded: Boolean);
begin
end;

procedure TIdeNotifier.BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
begin
  Cancel := False;
end;

procedure TIdeNotifier.FileNotification(NotifyCode: TOTAFileNotification;
  const FileName: string; var Cancel: Boolean);
begin
  Cancel := False;
  // Note: The FileName passed below has an extension of '.$$$'
  if NotifyCode = ofnProjectDesktopSave then
    DskPopup(FileName);
end;

initialization

finalization
  RemoveNotifier;
{$endif}

end.

【讨论】:

  • 哇。谢谢是一个非常聪明的解决方案。我稍后会试一试。我确实喜欢简单:比我预期的要容易得多。
  • 感谢您的编辑。在您讨论过的编辑后,我删除了我的答案。 +1
  • @JeroenPluimers-Binck:我很抱歉:关于传回通知程序的文件名的文件扩展名似乎存在问题 - 请参阅我的答案的更新部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多