Componentes.Terceros.jcl/official/1.100/experts/debug/converter/JclDebugIdeImpl.pas

642 lines
21 KiB
ObjectPascal

{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) }
{ }
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
{ License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
{ and limitations under the License. }
{ }
{ The Original Code is JclDebugIdeImpl.pas. }
{ }
{ The Initial Developer of the Original Code is documented in the accompanying }
{ help file JCL.chm. Portions created by these individuals are Copyright (C) of these individuals. }
{ }
{**************************************************************************************************}
{ }
{ Unit owner: Petr Vones }
{ Last modified: August 28, 2002 }
{ }
{**************************************************************************************************}
unit JclDebugIdeImpl;
{$I jcl.inc}
interface
uses
Windows, Classes, Menus, ActnList, SysUtils, Graphics, Dialogs, Controls, Forms, ToolsAPI,
JclOtaUtils, JclDebugIdeConfigFrame;
type
TJclDebugDataInfo = record
ProjectName: string;
ExecutableFileName: TFileName;
MapFileSize, JclDebugDataSize: Integer;
LinkerBugUnit: string;
LineNumberErrors: Integer;
Success: Boolean;
end;
TJclDebugExtension = class(TJclOTAExpert)
private
FResultInfo: array of TJclDebugDataInfo;
FStoreResults: Boolean;
FImageIndex: Integer;
FBuildError: Boolean;
FInsertDataItem: TMenuItem;
FInsertDataAction: TAction;
FDisabledImageIndex: Integer;
FCurrentProject: IOTAProject;
FSaveBuildProject: TAction;
FSaveBuildProjectExecute: TNotifyEvent;
FSaveBuildAllProjects: TAction;
FSaveBuildAllProjectsExecute: TNotifyEvent;
FNotifierIndex: Integer;
FSaveMapFile: Integer;
FConfigFrame: TJclDebugIdeConfigFrame;
FGenerateJdbg: Boolean;
FInsertJdbg: Boolean;
FEnableExpert: Boolean;
procedure InsertDataExecute(Sender: TObject);
procedure LoadExpertValues;
procedure SaveExpertValues;
procedure BuildAllProjects(Sender: TObject); // (New) Build All Projects command hook
procedure BuildProject(Sender: TObject); // (New) Build Project command hook
procedure BeginStoreResults;
procedure DisplayResults;
procedure EndStoreResults;
procedure SetEnableExpert(const Value: Boolean);
public
constructor Create; reintroduce;
procedure AfterCompile(Succeeded: Boolean);
procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
procedure RegisterCommands; override;
procedure UnregisterCommands; override;
procedure AddConfigurationPages(AddPageFunc: TJclOTAAddPageFunc); override;
procedure ConfigurationClosed(AControl: TControl; SaveChanges: Boolean); override;
property GenerateJdbg: Boolean read FGenerateJdbg write FGenerateJdbg;
property InsertJdbg: Boolean read FInsertJdbg write FInsertJdbg;
property EnableExpert: Boolean read FEnableExpert write SetEnableExpert;
end;
TIdeNotifier = class(TNotifierObject, IOTANotifier, IOTAIDENotifier, IOTAIDENotifier50)
private
FDebugExtension: TJclDebugExtension;
protected
procedure AfterCompile(Succeeded: Boolean); overload;
procedure AfterCompile(Succeeded: Boolean; IsCodeInsight: Boolean); overload;
procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean); overload;
procedure BeforeCompile(const Project: IOTAProject; IsCodeInsight: Boolean; var Cancel: Boolean); overload;
procedure FileNotification(NotifyCode: TOTAFileNotification; const FileName: string; var Cancel: Boolean);
public
constructor Create(ADebugExtension: TJclDebugExtension);
end;
// design package entry point
procedure Register;
// expert DLL entry point
function JCLWizardInit(const BorlandIDEServices: IBorlandIDEServices;
RegisterProc: TWizardRegisterProc;
var TerminateProc: TWizardTerminateProc): Boolean; stdcall;
implementation
{$R JclDebugIdeIcon.res}
uses
JclBorlandTools, JclDebug, JclDebugIdeResult,
JclOtaConsts, JclOtaResources;
procedure Register;
begin
try
RegisterPackageWizard(TJclDebugExtension.Create);
except
on ExceptionObj: TObject do
begin
JclExpertShowExceptionDialog(ExceptionObj);
raise;
end;
end;
end;
var
JCLWizardIndex: Integer = -1;
procedure JclWizardTerminate;
var
OTAWizardServices: IOTAWizardServices;
begin
try
if JCLWizardIndex <> -1 then
begin
Supports(BorlandIDEServices, IOTAWizardServices, OTAWizardServices);
if not Assigned(OTAWizardServices) then
raise EJclExpertException.CreateTrace(RsENoWizardServices);
OTAWizardServices.RemoveWizard(JCLWizardIndex);
end;
except
on ExceptionObj: TObject do
begin
JclExpertShowExceptionDialog(ExceptionObj);
end;
end;
end;
function JCLWizardInit(const BorlandIDEServices: IBorlandIDEServices;
RegisterProc: TWizardRegisterProc;
var TerminateProc: TWizardTerminateProc): Boolean stdcall;
var
OTAWizardServices: IOTAWizardServices;
begin
try
TerminateProc := JclWizardTerminate;
Supports(BorlandIDEServices, IOTAWizardServices, OTAWizardServices);
if not Assigned(OTAWizardServices) then
raise EJclExpertException.CreateTrace(RsENoWizardServices);
JCLWizardIndex := OTAWizardServices.AddWizard(TJclDebugExtension.Create);
Result := True;
except
on ExceptionObj: TObject do
begin
JclExpertShowExceptionDialog(ExceptionObj);
Result := False;
end;
end;
end;
//=== { TJclDebugExtension } =================================================
procedure TJclDebugExtension.ConfigurationClosed(AControl: TControl;
SaveChanges: Boolean);
begin
if Assigned(AControl) and (AControl = FConfigFrame) then
begin
if SaveChanges then
begin
EnableExpert := FConfigFrame.EnableExpert;
GenerateJdbg := FConfigFrame.GenerateJdbg;
InsertJdbg := FConfigFrame.InsertJdbg;
end;
FreeAndNil(FConfigFrame);
end
else
inherited ConfigurationClosed(AControl, SaveChanges);
end;
constructor TJclDebugExtension.Create;
begin
inherited Create(JclDebugExpertRegKey);
end;
procedure TJclDebugExtension.AddConfigurationPages(
AddPageFunc: TJclOTAAddPageFunc);
begin
inherited AddConfigurationPages(AddPageFunc);
FConfigFrame := TJclDebugIdeConfigFrame.Create(nil);
FConfigFrame.EnableExpert := EnableExpert;
FConfigFrame.GenerateJdbg := GenerateJdbg;
FConfigFrame.InsertJdbg := InsertJdbg;
AddPageFunc(FConfigFrame, RsDebugConfigPageCaption, Self);
end;
procedure TJclDebugExtension.AfterCompile(Succeeded: Boolean);
var
ProjectFileName, MapFileName, DrcFileName, ExecutableFileName, JdbgFileName: string;
OutputDirectory, LinkerBugUnit: string;
ProjOptions: IOTAProjectOptions;
Succ: Boolean;
MapFileSize, JclDebugDataSize, LineNumberErrors, C: Integer;
procedure DeleteMapAndDrcFile;
begin
if FSaveMapFile <> MapFileOptionDetailed then
begin // delete MAP and DRC file
DeleteFile(MapFileName);
DeleteFile(DrcFileName);
end;
end;
procedure OutputToolMessage(const Msg: string);
begin
if Assigned(FCurrentProject) then
OTAMessageServices.AddToolMessage(FCurrentProject.FileName, Msg,
JclDebugMessagePrefix, 1, 1)
else
OTAMessageServices.AddToolMessage('', Msg, JclDebugMessagePrefix, 1, 1);
end;
begin
if EnableExpert and Assigned(FCurrentProject) then
begin
ProjOptions := FCurrentProject.ProjectOptions;
if FSaveMapFile <> MapFileOptionDetailed then
begin
ProjOptions.Values[MapFileOptionName] := FSaveMapFile;
// workaround for MsBuild, the project has to be saved
ProjOptions.ModifiedState := True;
FCurrentProject.Save(False, True);
end;
ProjectFileName := FCurrentProject.FileName;
OutputDirectory := GetOutputDirectory(FCurrentProject);
MapFileName := GetMapFileName(FCurrentProject);
DrcFileName := GetDrcFileName(FCurrentProject);
JdbgFileName := ChangeFileExt(MapFileName, JclDbgFileExtension);
if Succeeded then
begin
Screen.Cursor := crHourGlass;
try
LinkerBugUnit := '';
LineNumberErrors := 0;
Succ := FileExists(MapFileName);
if not Succ then
OutputToolMessage(Format(RsEMapFileNotFound, [MapFileName, ProjectFileName]));
// creation of .jdbg
if Succ and GenerateJdbg then
begin
Succ := ConvertMapFileToJdbgFile(MapFileName, LinkerBugUnit, LineNumberErrors,
MapFileSize, JclDebugDataSize);
if Succ then
OutputToolMessage(Format(RsConvertedMapToJdbg, [MapFileName, MapFileSize, JclDebugDataSize]))
else
OutputToolMessage(Format(RsEMapConversion, [MapFileName]));
end;
// insertion of Jedi Debug Information into the binary
if Succ and InsertJdbg then
begin
Succ := FindExecutableName(MapFileName, OutputDirectory, ExecutableFileName);
if Succ then
begin
Succ := InsertDebugDataIntoExecutableFile(ExecutableFileName, MapFileName,
LinkerBugUnit, MapFileSize, JclDebugDataSize, LineNumberErrors);
if Succ then
OutputToolMessage(Format(RsInsertedJdbg, [MapFileName, MapFileSize, JclDebugDataSize]))
else
OutputToolMessage(Format(RsEMapConversion, [MapFileName]));
end
else
OutputToolMessage(Format(RsEExecutableNotFound, [ProjectFileName]));
end;
Screen.Cursor := crDefault;
except
Screen.Cursor := crDefault;
raise;
end;
DeleteMapAndDrcFile;
if FStoreResults then
begin
C := Length(FResultInfo);
SetLength(FResultInfo, C + 1);
FResultInfo[C].ProjectName := ExtractFileName(ProjectFileName);
FResultInfo[C].ExecutableFileName := ExecutableFileName;
FResultInfo[C].MapFileSize := MapFileSize;
FResultInfo[C].JclDebugDataSize := JclDebugDataSize;
FResultInfo[C].LinkerBugUnit := LinkerBugUnit;
FResultInfo[C].LineNumberErrors := LineNumberErrors;
FResultInfo[C].Success := Succ;
end;
end
else
begin
FBuildError := True;
DeleteMapAndDrcFile;
end;
FCurrentProject := nil;
end;
end;
procedure TJclDebugExtension.BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
var
ProjOptions: IOTAProjectOptions;
begin
if EnableExpert then
begin
if IsInstalledPackage(Project) then
begin
if MessageDlg(Format(RsCantInsertToInstalledPackage, [Project.FileName]), mtError, [mbYes, mbNo], 0) = mrYes then
EnableExpert := False
else
begin
Cancel := True;
MessageDlg(RsCompilationAborted, mtError, [mbOK], 0);
end;
end
else
begin
FCurrentProject := Project;
ProjOptions := Project.ProjectOptions;
if not Assigned(ProjOptions) then
raise EJclExpertException.CreateTrace(RsENoProjectOptions);
FSaveMapFile := ProjOptions.Values[MapFileOptionName];
if FSaveMapFile <> MapFileOptionDetailed then
ProjOptions.Values[MapFileOptionName] := MapFileOptionDetailed;
// workaround for MsBuild, the project has to be saved
ProjOptions.ModifiedState := True;
Project.Save(False, True);
end;
end;
end;
procedure TJclDebugExtension.BeginStoreResults;
begin
FBuildError := False;
FStoreResults := True;
FResultInfo := nil;
end;
procedure TJclDebugExtension.BuildAllProjects(Sender: TObject);
begin
BeginStoreResults;
try
try
FSaveBuildAllProjectsExecute(Sender);
if EnableExpert then
DisplayResults;
except
on ExceptionObj: TObject do
JclExpertShowExceptionDialog(ExceptionObj);
// raise is useless because trapped by the finally section
end;
finally
EndStoreResults;
end;
end;
procedure TJclDebugExtension.BuildProject(Sender: TObject);
begin
BeginStoreResults;
try
try
FSaveBuildProjectExecute(Sender);
if EnableExpert then
DisplayResults;
except
on ExceptionObj: TObject do
JclExpertShowExceptionDialog(ExceptionObj);
// raise is useless because trapped by the finally section
end;
finally
EndStoreResults;
end;
end;
procedure TJclDebugExtension.DisplayResults;
var
I: Integer;
begin
if FBuildError or (Length(FResultInfo) = 0) then
Exit;
with TJclDebugResultForm.Create(Application, Settings) do
try
for I := 0 to Length(FResultInfo) - 1 do
with ResultListView.Items.Add, FResultInfo[I] do
begin
Caption := ProjectName;
if Success then
begin
SubItems.Add(IntToStr(MapFileSize));
SubItems.Add(IntToStr(JclDebugDataSize));
SubItems.Add(Format('%3.1f', [JclDebugDataSize * 100 / MapFileSize]));
SubItems.Add(ExecutableFileName);
SubItems.Add(LinkerBugUnit);
if LineNumberErrors > 0 then
SubItems.Add(IntToStr(LineNumberErrors))
else
SubItems.Add('');
ImageIndex := 0;
end
else
begin
SubItems.Add('');
SubItems.Add('');
SubItems.Add('');
SubItems.Add(ExecutableFileName);
SubItems.Add(LinkerBugUnit);
SubItems.Add('');
ImageIndex := 1;
end;
end;
ShowModal;
finally
Free;
end;
end;
procedure TJclDebugExtension.EndStoreResults;
begin
FStoreResults := False;
FResultInfo := nil;
end;
procedure TJclDebugExtension.InsertDataExecute(Sender: TObject);
begin
try
EnableExpert := not FInsertDataAction.Checked;
SaveExpertValues;
except
on ExceptionObj: TObject do
begin
JclExpertShowExceptionDialog(ExceptionObj);
raise;
end;
end;
end;
procedure TJclDebugExtension.LoadExpertValues;
begin
EnableExpert := Settings.LoadBool(JclDebugEnabledRegValue, False);
GenerateJdbg := Settings.LoadBool(JclDebugGenerateJdbgRegValue, False);
InsertJdbg := Settings.LoadBool(JclDebugInsertJdbgRegValue, True);
end;
procedure TJclDebugExtension.SaveExpertValues;
begin
Settings.SaveBool(JclDebugEnabledRegValue, EnableExpert);
Settings.SaveBool(JclDebugGenerateJdbgRegValue, GenerateJdbg);
Settings.SaveBool(JclDebugInsertJdbgRegValue, InsertJdbg);
end;
procedure TJclDebugExtension.SetEnableExpert(const Value: Boolean);
begin
FEnableExpert := Value;
FInsertDataAction.Checked := Value;
if (Value) then
begin
FInsertDataAction.ImageIndex := FImageIndex;
if Assigned(FSaveBuildProject) then
FSaveBuildProject.OnExecute := BuildProject;
if Assigned(FSaveBuildAllProjects) then
FSaveBuildAllProjects.OnExecute := BuildAllProjects;
end
else
begin
FInsertDataAction.ImageIndex := FDisabledImageIndex;
if Assigned(FSaveBuildProject) then
FSaveBuildProject.OnExecute := FSaveBuildProjectExecute;
if Assigned(FSaveBuildAllProjects) then
FSaveBuildAllProjects.OnExecute := FSaveBuildAllProjectsExecute;
end;
end;
procedure TJclDebugExtension.RegisterCommands;
var
IDEMainMenu: TMainMenu;
IDEProjectItem: TMenuItem;
IDEActionList: TActionList;
I: Integer;
ImageBmp: TBitmap;
begin
inherited RegisterCommands;
IDEActionList := TActionList(NTAServices.ActionList);
IDEMainMenu := NTAServices.MainMenu;
ImageBmp := TBitmap.Create;
try
ImageBmp.LoadFromResourceName(FindResourceHInstance(ModuleHInstance), 'JCLDEBUG');
FImageIndex := NTAServices.AddMasked(ImageBmp, clPurple);
ImageBmp.LoadFromResourceName(FindResourceHInstance(ModuleHInstance), 'JCLNODEBUG');
FDisabledImageIndex := NTAServices.AddMasked(ImageBmp, clPurple);
FInsertDataAction := TAction.Create(nil);
FInsertDataAction.Caption := RsInsertDataCaption;
FInsertDataAction.Visible := True;
FInsertDataAction.OnExecute := InsertDataExecute;
FInsertDataAction.ActionList := IDEActionList;
FInsertDataAction.Name := RsInsertDataActionName;
RegisterAction(FInsertDataAction);
FInsertDataItem := TMenuItem.Create(nil);
FInsertDataItem.Action := FInsertDataAction;
finally
ImageBmp.Free;
end;
FNotifierIndex := Services.AddNotifier(TIdeNotifier.Create(Self));
LoadExpertValues;
IDEProjectItem := nil;
with IDEMainMenu do
for I := 0 to Items.Count - 1 do
if Items[I].Name = 'ProjectMenu' then
begin
IDEProjectItem := Items[I];
Break;
end;
if not Assigned(IDEProjectItem) then
raise EJclExpertException.CreateTrace(RsENoProjectMenuItem);
with IDEProjectItem do
for I := 0 to Count - 1 do
if Items[I].Name = 'ProjectOptionsItem' then
begin
if Assigned(Items[I].Action) then
FInsertDataAction.Category := TContainedAction(Items[I].Action).Category;
IDEProjectItem.Insert(I + 1, FInsertDataItem);
System.Break;
end;
if not Assigned(FInsertDataItem.Parent) then
raise EJclExpertException.CreateTrace(RsEInsertDataMenuItemNotInserted);
FSaveBuildProject := nil;
with IDEActionList do
for I := 0 to ActionCount - 1 do
if Actions[I].Name = 'ProjectBuildCommand' then
begin
FSaveBuildProject := TAction(Actions[I]);
FSaveBuildProjectExecute := Actions[I].OnExecute;
Break;
end;
if not Assigned(FSaveBuildProject) then
raise EJclExpertException.CreateTrace(RsENoBuildAction);
FSaveBuildAllProjects := nil;
with IDEActionList do
for I := 0 to ActionCount - 1 do
if Actions[I].Name = 'ProjectBuildAllCommand' then
begin
FSaveBuildAllProjects := TAction(Actions[I]);
FSaveBuildAllProjectsExecute := Actions[I].OnExecute;
Break;
end;
if not Assigned(FSaveBuildProject) then
raise EJclExpertException.CreateTrace(RsENoBuildAllAction);
end;
procedure TJclDebugExtension.UnregisterCommands;
begin
inherited UnregisterCommands;
if FNotifierIndex <> -1 then
Services.RemoveNotifier(FNotifierIndex);
SaveExpertValues;
EnableExpert := False;
UnregisterAction(FInsertDataAction);
FreeAndNil(FInsertDataItem);
FreeAndNil(FInsertDataAction);
end;
//=== { TIdeNotifier } =======================================================
constructor TIdeNotifier.Create(ADebugExtension: TJclDebugExtension);
begin
inherited Create;
FDebugExtension := ADebugExtension;
end;
procedure TIdeNotifier.AfterCompile(Succeeded: Boolean);
begin
end;
procedure TIdeNotifier.AfterCompile(Succeeded, IsCodeInsight: Boolean);
begin
try
if not IsCodeInsight then
FDebugExtension.AfterCompile(Succeeded);
except
on ExceptionObj: TObject do
begin
JclExpertShowExceptionDialog(ExceptionObj);
raise;
end;
end;
end;
procedure TIdeNotifier.BeforeCompile(const Project: IOTAProject; IsCodeInsight: Boolean; var Cancel: Boolean);
begin
try
if not IsCodeInsight then
FDebugExtension.BeforeCompile(Project, Cancel);
except
on ExceptionObj: TObject do
begin
JclExpertShowExceptionDialog(ExceptionObj);
raise;
end;
end;
end;
procedure TIdeNotifier.BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
begin
end;
procedure TIdeNotifier.FileNotification(NotifyCode: TOTAFileNotification;
const FileName: string; var Cancel: Boolean);
begin
end;
end.