├── .gitignore ├── CodeCoverage ├── CodeCoverage.zip └── Readme.txt ├── README.md ├── Sample ├── ProjectGroup.groupproj ├── TestProject │ ├── Bin │ │ ├── dcov_execute.bat │ │ ├── dcov_paths.lst │ │ └── dcov_units.lst │ ├── Source │ │ └── Model │ │ │ └── Model.Calculator.Test.pas │ ├── TestProject.dpr │ └── TestProject.dproj └── VCLProject │ ├── FMain.dfm │ ├── FMain.pas │ ├── Source │ └── Model │ │ ├── Model.Calculator.pas │ │ └── Model.Formatter.pas │ ├── VCLProject.dpr │ └── VCLProject.dproj └── Source ├── Library ├── CCE.DLL.Registry.pas ├── CodeCoverageExperts.dpr └── CodeCoverageExperts.dproj ├── Package ├── CCE.Pkg.Registry.pas ├── CodeCoverageExperts.dpk └── CodeCoverageExperts.dproj └── Src ├── Core ├── CCE.Constants.pas ├── CCE.Core.CodeCoverage.pas ├── CCE.Core.Interfaces.pas ├── CCE.Core.Project.pas ├── CCE.Core.Utils.pas └── CCE.Helpers.TreeView.pas ├── IDE ├── CCE.ContextMenu.pas ├── CCE.Wizard.Forms.dfm └── CCE.Wizard.Forms.pas └── Third ├── CCE.dpipes.pas ├── CCE.dprocess.pas ├── CCE.pipes_win.inc └── CCE.process_win.inc /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | 60 | # Delphi history and backups 61 | __history/ 62 | __recovery/ 63 | *.~* 64 | 65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 66 | *.stat 67 | 68 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss 69 | modules/ 70 | *.res 71 | *.log 72 | Sample/TestProject/Bin/report/ 73 | Sample/TestProject/Bin/dunitx-results.xml 74 | -------------------------------------------------------------------------------- /CodeCoverage/CodeCoverage.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielbaltazar/code-coverage-experts/977324a2bbe60b0cd32d27da6bb80576d45d01a0/CodeCoverage/CodeCoverage.zip -------------------------------------------------------------------------------- /CodeCoverage/Readme.txt: -------------------------------------------------------------------------------- 1 | https://github.com/DelphiCodeCoverage/DelphiCodeCoverage/releases/download/1.0.15/DelphiCodeCoverage_1_0_15.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code Coverage Experts 2 | ### Wizard to configure CodeCoverage in Delphi Test Projects 3 | 4 | ## ⚙️ Settings 5 | 6 | - Set the exe and map test project filename and the report output directory. 7 | 8 | ![image](https://github.com/gabrielbaltazar/code-coverage-experts/assets/9014016/5a652c28-b5d8-4199-b6d6-568990190232) 9 | 10 | - Inform the units that the code coverage project will cover 11 | 12 | ![image](https://github.com/gabrielbaltazar/code-coverage-experts/assets/9014016/20a65b84-eb49-4f4b-a29c-119c396223f7) 13 | -------------------------------------------------------------------------------- /Sample/ProjectGroup.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {60878318-6802-4DD9-B2BC-83C66C91BFB1} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Default.Personality.12 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Sample/TestProject/Bin/dcov_execute.bat: -------------------------------------------------------------------------------- 1 | "CodeCoverage.exe" -e ".\TestProject.exe" -m ".\TestProject.map" -uf ".\dcov_units.lst" -spf ".\dcov_paths.lst" -od ".\report" -lt -html -xml 2 | -------------------------------------------------------------------------------- /Sample/TestProject/Bin/dcov_paths.lst: -------------------------------------------------------------------------------- 1 | ..\..\VCLProject\Source\Model\ 2 | -------------------------------------------------------------------------------- /Sample/TestProject/Bin/dcov_units.lst: -------------------------------------------------------------------------------- 1 | Model.Calculator.pas 2 | Model.Formatter.pas 3 | -------------------------------------------------------------------------------- /Sample/TestProject/Source/Model/Model.Calculator.Test.pas: -------------------------------------------------------------------------------- 1 | unit Model.Calculator.Test; 2 | 3 | interface 4 | 5 | uses 6 | DUnitX.TestFramework, 7 | Model.Calculator, 8 | System.SysUtils; 9 | 10 | type 11 | [TestFixture] 12 | TCalculatorTest = class 13 | private 14 | FCalculator: TCalculator; 15 | FResult: Double; 16 | public 17 | [Setup] 18 | procedure Setup; 19 | 20 | [TearDown] 21 | procedure TearDown; 22 | 23 | [Test] 24 | procedure Sum; 25 | 26 | [Test] 27 | procedure Subtract; 28 | end; 29 | 30 | implementation 31 | 32 | procedure TCalculatorTest.Setup; 33 | begin 34 | FCalculator := TCalculator.Create; 35 | FResult := 0; 36 | end; 37 | 38 | procedure TCalculatorTest.Subtract; 39 | begin 40 | FResult := FCalculator.Subtract(10, 5); 41 | Assert.AreEqual(5, FResult); 42 | end; 43 | 44 | procedure TCalculatorTest.Sum; 45 | begin 46 | FResult := FCalculator.Sum(10, 5); 47 | Assert.AreEqual(15, FResult); 48 | end; 49 | 50 | procedure TCalculatorTest.TearDown; 51 | begin 52 | FCalculator.Free; 53 | end; 54 | 55 | end. 56 | -------------------------------------------------------------------------------- /Sample/TestProject/TestProject.dpr: -------------------------------------------------------------------------------- 1 | program TestProject; 2 | 3 | {$IFNDEF TESTINSIGHT} 4 | {$APPTYPE CONSOLE} 5 | {$ENDIF} 6 | {$STRONGLINKTYPES ON} 7 | uses 8 | System.SysUtils, 9 | {$IFDEF TESTINSIGHT} 10 | TestInsight.DUnitX, 11 | {$ELSE} 12 | DUnitX.Loggers.Console, 13 | DUnitX.Loggers.Xml.NUnit, 14 | {$ENDIF } 15 | DUnitX.TestFramework, 16 | Model.Calculator, 17 | Model.Formatter, 18 | Model.Calculator.Test in 'Source\Model\Model.Calculator.Test.pas'; 19 | 20 | { keep comment here to protect the following conditional from being removed by the IDE when adding a unit } 21 | {$IFNDEF TESTINSIGHT} 22 | var 23 | runner: ITestRunner; 24 | results: IRunResults; 25 | logger: ITestLogger; 26 | nunitLogger : ITestLogger; 27 | {$ENDIF} 28 | begin 29 | {$IFDEF TESTINSIGHT} 30 | TestInsight.DUnitX.RunRegisteredTests; 31 | {$ELSE} 32 | try 33 | //Check command line options, will exit if invalid 34 | TDUnitX.CheckCommandLine; 35 | //Create the test runner 36 | runner := TDUnitX.CreateRunner; 37 | //Tell the runner to use RTTI to find Fixtures 38 | runner.UseRTTI := True; 39 | //When true, Assertions must be made during tests; 40 | runner.FailsOnNoAsserts := False; 41 | 42 | //tell the runner how we will log things 43 | //Log to the console window if desired 44 | if TDUnitX.Options.ConsoleMode <> TDunitXConsoleMode.Off then 45 | begin 46 | logger := TDUnitXConsoleLogger.Create(TDUnitX.Options.ConsoleMode = TDunitXConsoleMode.Quiet); 47 | runner.AddLogger(logger); 48 | end; 49 | //Generate an NUnit compatible XML File 50 | nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile); 51 | runner.AddLogger(nunitLogger); 52 | 53 | //Run tests 54 | results := runner.Execute; 55 | if not results.AllPassed then 56 | System.ExitCode := EXIT_ERRORS; 57 | 58 | System.Write('Done.. press key to quit.'); 59 | System.Readln; 60 | except 61 | on E: Exception do 62 | System.Writeln(E.ClassName, ': ', E.Message); 63 | end; 64 | {$ENDIF} 65 | end. 66 | -------------------------------------------------------------------------------- /Sample/VCLProject/FMain.dfm: -------------------------------------------------------------------------------- 1 | object FrmMain: TFrmMain 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsDialog 5 | Caption = 'VCL Project' 6 | ClientHeight = 409 7 | ClientWidth = 715 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -16 12 | Font.Name = 'Segoe UI' 13 | Font.Style = [] 14 | Position = poScreenCenter 15 | TextHeight = 21 16 | object Label1: TLabel 17 | Left = 48 18 | Top = 72 19 | Width = 71 20 | Height = 21 21 | Caption = 'Number 1' 22 | end 23 | object Label2: TLabel 24 | Left = 216 25 | Top = 72 26 | Width = 71 27 | Height = 21 28 | Caption = 'Number 2' 29 | end 30 | object Label3: TLabel 31 | Left = 48 32 | Top = 200 33 | Width = 43 34 | Height = 21 35 | Caption = 'Result' 36 | end 37 | object Label4: TLabel 38 | Left = 48 39 | Top = 328 40 | Width = 26 41 | Height = 21 42 | Caption = 'Text' 43 | end 44 | object Label5: TLabel 45 | Left = 424 46 | Top = 328 47 | Width = 43 48 | Height = 21 49 | Caption = 'Result' 50 | end 51 | object EdtNumber1: TEdit 52 | Left = 48 53 | Top = 95 54 | Width = 145 55 | Height = 29 56 | NumbersOnly = True 57 | TabOrder = 0 58 | end 59 | object EdtNumber2: TEdit 60 | Left = 216 61 | Top = 95 62 | Width = 145 63 | Height = 29 64 | NumbersOnly = True 65 | TabOrder = 1 66 | end 67 | object EdtResult: TEdit 68 | Left = 48 69 | Top = 223 70 | Width = 145 71 | Height = 29 72 | NumbersOnly = True 73 | ReadOnly = True 74 | TabOrder = 2 75 | end 76 | object BtnSum: TButton 77 | Left = 48 78 | Top = 152 79 | Width = 105 80 | Height = 25 81 | Caption = 'Sum' 82 | TabOrder = 3 83 | OnClick = BtnSumClick 84 | end 85 | object BtnSubtract: TButton 86 | Left = 176 87 | Top = 152 88 | Width = 105 89 | Height = 25 90 | Caption = 'Subtract' 91 | TabOrder = 4 92 | OnClick = BtnSubtractClick 93 | end 94 | object EdtText: TEdit 95 | Left = 48 96 | Top = 351 97 | Width = 233 98 | Height = 29 99 | TabOrder = 5 100 | end 101 | object BtnOnlyNumber: TButton 102 | Left = 287 103 | Top = 353 104 | Width = 105 105 | Height = 25 106 | Caption = 'Only Number' 107 | TabOrder = 6 108 | OnClick = BtnOnlyNumberClick 109 | end 110 | object EdtResultOnlyNumber: TEdit 111 | Left = 424 112 | Top = 351 113 | Width = 145 114 | Height = 29 115 | ReadOnly = True 116 | TabOrder = 7 117 | end 118 | end 119 | -------------------------------------------------------------------------------- /Sample/VCLProject/FMain.pas: -------------------------------------------------------------------------------- 1 | unit FMain; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 8 | Model.Calculator, 9 | Model.Formatter; 10 | 11 | type 12 | TFrmMain = class(TForm) 13 | Label1: TLabel; 14 | EdtNumber1: TEdit; 15 | EdtNumber2: TEdit; 16 | Label2: TLabel; 17 | EdtResult: TEdit; 18 | Label3: TLabel; 19 | BtnSum: TButton; 20 | BtnSubtract: TButton; 21 | Label4: TLabel; 22 | EdtText: TEdit; 23 | BtnOnlyNumber: TButton; 24 | Label5: TLabel; 25 | EdtResultOnlyNumber: TEdit; 26 | procedure BtnSumClick(Sender: TObject); 27 | procedure BtnSubtractClick(Sender: TObject); 28 | procedure BtnOnlyNumberClick(Sender: TObject); 29 | private 30 | FCalculator: TCalculator; 31 | FFormatter: TFormatter; 32 | { Private declarations } 33 | public 34 | constructor Create(AOwner: TComponent); override; 35 | destructor Destroy; override; 36 | { Public declarations } 37 | end; 38 | 39 | var 40 | FrmMain: TFrmMain; 41 | 42 | implementation 43 | 44 | {$R *.dfm} 45 | 46 | procedure TFrmMain.BtnOnlyNumberClick(Sender: TObject); 47 | var 48 | LResult: string; 49 | begin 50 | LResult := FFormatter.OnlyNumbers(EdtText.Text); 51 | EdtResultOnlyNumber.Text := LResult; 52 | end; 53 | 54 | procedure TFrmMain.BtnSubtractClick(Sender: TObject); 55 | var 56 | LNum1: Double; 57 | LNum2: Double; 58 | LResult: Double; 59 | begin 60 | LNum1 := StrToFloatDef(EdtNumber1.Text, 0); 61 | LNum2 := StrToFloatDef(EdtNumber2.Text, 0); 62 | LResult := FCalculator.Subtract(LNum1, LNum2); 63 | EdtResult.Text := LResult.ToString; 64 | end; 65 | 66 | procedure TFrmMain.BtnSumClick(Sender: TObject); 67 | var 68 | LNum1: Double; 69 | LNum2: Double; 70 | LResult: Double; 71 | begin 72 | LNum1 := StrToFloatDef(EdtNumber1.Text, 0); 73 | LNum2 := StrToFloatDef(EdtNumber2.Text, 0); 74 | LResult := FCalculator.Sum(LNum1, LNum2); 75 | EdtResult.Text := LResult.ToString; 76 | end; 77 | 78 | constructor TFrmMain.Create(AOwner: TComponent); 79 | begin 80 | inherited; 81 | FCalculator := TCalculator.Create; 82 | FFormatter := TFormatter.Create; 83 | end; 84 | 85 | destructor TFrmMain.Destroy; 86 | begin 87 | FCalculator.Free; 88 | FFormatter.Free; 89 | inherited; 90 | end; 91 | 92 | end. 93 | -------------------------------------------------------------------------------- /Sample/VCLProject/Source/Model/Model.Calculator.pas: -------------------------------------------------------------------------------- 1 | unit Model.Calculator; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, 7 | System.StrUtils; 8 | 9 | type 10 | TCalculator = class 11 | public 12 | function Sum(ANum1, ANum2: Double): Double; 13 | function Subtract(ANum1, ANum2: Double): Double; 14 | function Multiply(ANum1, ANum2: Double): Double; 15 | end; 16 | 17 | implementation 18 | 19 | { TCalculator } 20 | 21 | function TCalculator.Multiply(ANum1, ANum2: Double): Double; 22 | begin 23 | Result := ANum1 * ANum2; 24 | end; 25 | 26 | function TCalculator.Subtract(ANum1, ANum2: Double): Double; 27 | begin 28 | Result := ANum1 - ANum2; 29 | end; 30 | 31 | function TCalculator.Sum(ANum1, ANum2: Double): Double; 32 | begin 33 | Result := ANum1 + ANum2; 34 | end; 35 | 36 | end. 37 | -------------------------------------------------------------------------------- /Sample/VCLProject/Source/Model/Model.Formatter.pas: -------------------------------------------------------------------------------- 1 | unit Model.Formatter; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, 7 | System.StrUtils; 8 | 9 | type 10 | TFormatter = class 11 | public 12 | function OnlyNumbers(const AText: string): string; 13 | end; 14 | 15 | implementation 16 | 17 | { TFormatter } 18 | 19 | function TFormatter.OnlyNumbers(const AText: string): string; 20 | var 21 | I: Integer; 22 | begin 23 | Result := EmptyStr; 24 | for I := 1 to AText.Length do 25 | begin 26 | if AText[I] in ['0'..'9'] then 27 | Result := Result + AText[I]; 28 | end; 29 | end; 30 | 31 | end. 32 | -------------------------------------------------------------------------------- /Sample/VCLProject/VCLProject.dpr: -------------------------------------------------------------------------------- 1 | program VCLProject; 2 | 3 | uses 4 | Vcl.Forms, 5 | FMain in 'FMain.pas' {FrmMain}, 6 | Model.Calculator in 'Source\Model\Model.Calculator.pas', 7 | Model.Formatter in 'Source\Model\Model.Formatter.pas'; 8 | 9 | {$R *.res} 10 | 11 | begin 12 | Application.Initialize; 13 | Application.MainFormOnTaskbar := True; 14 | Application.CreateForm(TFrmMain, FrmMain); 15 | Application.Run; 16 | end. 17 | -------------------------------------------------------------------------------- /Sample/VCLProject/VCLProject.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {90EA3A85-0639-43EC-832E-4818F685512F} 4 | 19.5 5 | VCL 6 | True 7 | Debug 8 | Win32 9 | 1 10 | Application 11 | VCLProject.dpr 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | true 44 | Cfg_2 45 | true 46 | true 47 | 48 | 49 | .\$(Platform)\$(Config) 50 | .\$(Platform)\$(Config) 51 | false 52 | false 53 | false 54 | false 55 | false 56 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 57 | $(BDS)\bin\delphi_PROJECTICON.ico 58 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 59 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 60 | VCLProject 61 | 62 | 63 | dxPSdxSpreadSheetLnkRS28;vclwinx;DataSnapServer;dacvcl280;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;cxExportRS28;dxHttpIndyRequestRS28;appanalytics;IndyProtocols;vclx;dxPSPrVwRibbonRS28;dxTileControlRS28;dbxcds;vcledge;dxPSdxDBOCLnkRS28;Skia.Package.RTL;cxPivotGridOLAPRS28;CodeCoverageExperts;dxGDIPlusRS28;DBXFirebirdDriver;dxCoreRS28;cxPivotGridRS28;StyleControls_d11Alexandria;dxPSCoreRS28;FireDACSqliteDriver;DbxClientDriver;dxSpreadSheetRS28;dxSkinsCoreRS28;soapmidas;dxBarRS28;dxADOServerModeRS28;dxWizardControlRS28;dbexpress;dacfmx280;inet;dxServerModeRS28;pgdacfmx280;vcltouch;cxTreeListRS28;dxBarDBNavRS28;FireDACDBXDriver;fmxdae;dxPScxCommonRS28;dxNavBarRS28;CustomIPTransport;FireDACMSSQLDriver;dxSpreadSheetReportDesignerRS28;dxFireDACEMFRS28;dxComnRS28;dxFlowChartDesignerRS28;IndySystem;cxVerticalGridRS28;dxmdsRS28;dxRichEditControlRS28;cxSchedulerGridRS28;dxPsPrVwAdvRS28;dxPScxSchedulerLnkRS28;dxPSdxOCLnkRS28;vclFireDAC;office2K;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;dxADOEMFRS28;dxRibbonCustomizationFormRS28;dxPSdxDBTVLnkRS28;bindcompdbx;dxGaugeControlRS28;rtl;FireDACMySQLDriver;dxDockingRS28;dxPDFViewerRS28;DBXSqliteDriver;dxBarExtItemsRS28;dxPSdxFCLnkRS28;dxorgcRS28;DBXSybaseASEDriver;dxSpreadSheetCoreConditionalFormattingDialogsRS28;Intraweb_15_D11;dxPSRichEditControlLnkRS28;vclimg;DataSnapFireDAC;inetdbxpress;FireDAC;xmlrtl;dsnap;pkgADRIFood;FireDACDb2Driver;cxSchedulerRibbonStyleEventEditorRS28;DBXOracleDriver;dxPScxTLLnkRS28;DBXInformixDriver;fmxobj;bindcompvclsmp;DataSnapNativeClient;dxFlowChartRS28;YxdUI;dxPScxPCProdRS28;DatasnapConnectorsFreePascal;pgdac280;emshosting;dxRichEditDocumentModelRS28;dxPSdxMapControlLnkRS28;cxGridEMFRS28;dxGanttControlRS28;dxPScxVGridLnkRS28;dxPScxPivotGridLnkRS28;FireDACCommonDriver;IndyIPClient;dac280;cxLibraryRS28;dxCloudServiceLibraryRS28;bindcompvclwinx;emsedge;bindcompfmx;dxPSdxPDFViewerLnkRS28;inetdb;dxSpreadSheetCoreRS28;cxSchedulerTreeBrowserRS28;FireDACASADriver;dxTabbedMDIRS28;vclactnband;fmxFireDAC;dxFireDACServerModeRS28;FireDACInfxDriver;DBXMySQLDriver;VclSmp;dxPSdxLCLnkRS28;DataSnapCommon;fmxase;dxdbtrRS28;DBXOdbcDriver;pgdacvcl280;dbrtl;FireDACOracleDriver;dxPSLnksRS28;Skia.Package.FMX;FireDACMSAccDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;dxChartControlRS28;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;dxSpreadSheetConditionalFormattingDialogsRS28;FireDACTDataDriver;Skia.Package.VCL;OTAHistoryProjectsPkg;dxOrgChartAdvancedCustomizeFormRS28;vcldb;dxDBXServerModeRS28;cxSchedulerRS28;dxRibbonRS28;dxFlowChartLayoutsRS28;dxPScxExtCommonRS28;dxdborRS28;dxRichEditControlCoreRS28;IWBootstrap4D11;bindcomp;dxPScxGridLnkRS28;IndyCore;RESTBackendComponents;cxPivotGridChartRS28;dxBarExtDBItemsRS28;dxRichEditCoreRS28;cxTreeListdxBarPopupMenuRS28;dxFlowChartAdvancedCustomizeFormRS28;FireDACADSDriver;RESTComponents;IndyIPServer;vcl;dsnapxml;adortl;dsnapcon;DataSnapClient;DataSnapProviderClient;cxSchedulerWebServiceStorageRS28;dxtrmdRS28;DBXDb2Driver;dxPSdxGaugeControlLnkRS28;cxGridRS28;dxSpellCheckerRS28;emsclientfiredac;FireDACPgDriver;FireDACDSDriver;tethering;dxMapControlRS28;crcontrols280;bindcompvcl;dxEMFRS28;CloudService;DBXSybaseASADriver;IWBootstrapD11;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 64 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 65 | Debug 66 | true 67 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 68 | 1033 69 | $(BDS)\bin\default_app.manifest 70 | 71 | 72 | dxPSdxSpreadSheetLnkRS28;vclwinx;DataSnapServer;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;cxExportRS28;dxHttpIndyRequestRS28;appanalytics;IndyProtocols;vclx;dxPSPrVwRibbonRS28;dxTileControlRS28;dbxcds;vcledge;dxPSdxDBOCLnkRS28;Skia.Package.RTL;cxPivotGridOLAPRS28;dxGDIPlusRS28;DBXFirebirdDriver;dxCoreRS28;cxPivotGridRS28;StyleControls_d11Alexandria;dxPSCoreRS28;FireDACSqliteDriver;DbxClientDriver;dxSpreadSheetRS28;dxSkinsCoreRS28;soapmidas;dxBarRS28;dxADOServerModeRS28;dxWizardControlRS28;dbexpress;inet;dxServerModeRS28;vcltouch;cxTreeListRS28;dxBarDBNavRS28;FireDACDBXDriver;fmxdae;dxPScxCommonRS28;dxNavBarRS28;CustomIPTransport;FireDACMSSQLDriver;dxSpreadSheetReportDesignerRS28;dxFireDACEMFRS28;dxComnRS28;dxFlowChartDesignerRS28;IndySystem;cxVerticalGridRS28;dxmdsRS28;dxRichEditControlRS28;cxSchedulerGridRS28;dxPsPrVwAdvRS28;dxPScxSchedulerLnkRS28;dxPSdxOCLnkRS28;vclFireDAC;office2K;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;dxADOEMFRS28;dxRibbonCustomizationFormRS28;dxPSdxDBTVLnkRS28;bindcompdbx;dxGaugeControlRS28;rtl;FireDACMySQLDriver;dxDockingRS28;dxPDFViewerRS28;DBXSqliteDriver;dxBarExtItemsRS28;dxPSdxFCLnkRS28;dxorgcRS28;DBXSybaseASEDriver;dxSpreadSheetCoreConditionalFormattingDialogsRS28;dxPSRichEditControlLnkRS28;vclimg;DataSnapFireDAC;inetdbxpress;FireDAC;xmlrtl;dsnap;pkgADRIFood;FireDACDb2Driver;cxSchedulerRibbonStyleEventEditorRS28;DBXOracleDriver;dxPScxTLLnkRS28;DBXInformixDriver;fmxobj;bindcompvclsmp;DataSnapNativeClient;dxFlowChartRS28;dxPScxPCProdRS28;DatasnapConnectorsFreePascal;emshosting;dxRichEditDocumentModelRS28;dxPSdxMapControlLnkRS28;cxGridEMFRS28;dxGanttControlRS28;dxPScxVGridLnkRS28;dxPScxPivotGridLnkRS28;FireDACCommonDriver;IndyIPClient;cxLibraryRS28;dxCloudServiceLibraryRS28;bindcompvclwinx;emsedge;bindcompfmx;dxPSdxPDFViewerLnkRS28;inetdb;dxSpreadSheetCoreRS28;cxSchedulerTreeBrowserRS28;FireDACASADriver;dxTabbedMDIRS28;vclactnband;fmxFireDAC;dxFireDACServerModeRS28;FireDACInfxDriver;DBXMySQLDriver;VclSmp;dxPSdxLCLnkRS28;DataSnapCommon;fmxase;dxdbtrRS28;DBXOdbcDriver;dbrtl;FireDACOracleDriver;dxPSLnksRS28;Skia.Package.FMX;FireDACMSAccDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;dxChartControlRS28;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;dxSpreadSheetConditionalFormattingDialogsRS28;FireDACTDataDriver;Skia.Package.VCL;dxOrgChartAdvancedCustomizeFormRS28;vcldb;dxDBXServerModeRS28;cxSchedulerRS28;dxRibbonRS28;dxFlowChartLayoutsRS28;dxPScxExtCommonRS28;dxdborRS28;dxRichEditControlCoreRS28;bindcomp;dxPScxGridLnkRS28;IndyCore;RESTBackendComponents;cxPivotGridChartRS28;dxBarExtDBItemsRS28;dxRichEditCoreRS28;cxTreeListdxBarPopupMenuRS28;dxFlowChartAdvancedCustomizeFormRS28;FireDACADSDriver;RESTComponents;IndyIPServer;vcl;dsnapxml;adortl;dsnapcon;DataSnapClient;DataSnapProviderClient;cxSchedulerWebServiceStorageRS28;dxtrmdRS28;DBXDb2Driver;dxPSdxGaugeControlLnkRS28;cxGridRS28;dxSpellCheckerRS28;emsclientfiredac;FireDACPgDriver;FireDACDSDriver;tethering;dxMapControlRS28;bindcompvcl;dxEMFRS28;CloudService;DBXSybaseASADriver;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 73 | 74 | 75 | DEBUG;$(DCC_Define) 76 | true 77 | false 78 | true 79 | true 80 | true 81 | true 82 | true 83 | 84 | 85 | false 86 | PerMonitorV2 87 | 88 | 89 | false 90 | RELEASE;$(DCC_Define) 91 | 0 92 | 0 93 | 94 | 95 | PerMonitorV2 96 | 97 | 98 | 99 | MainSource 100 | 101 | 102 |
FrmMain
103 | dfm 104 |
105 | 106 | 107 | 108 | Base 109 | 110 | 111 | Cfg_1 112 | Base 113 | 114 | 115 | Cfg_2 116 | Base 117 | 118 |
119 | 120 | Delphi.Personality.12 121 | Application 122 | 123 | 124 | 125 | VCLProject.dpr 126 | 127 | 128 | 129 | 130 | 131 | VCLProject.exe 132 | true 133 | 134 | 135 | 136 | 137 | 1 138 | 139 | 140 | Contents\MacOS 141 | 1 142 | 143 | 144 | 0 145 | 146 | 147 | 148 | 149 | classes 150 | 64 151 | 152 | 153 | classes 154 | 64 155 | 156 | 157 | 158 | 159 | res\xml 160 | 1 161 | 162 | 163 | res\xml 164 | 1 165 | 166 | 167 | 168 | 169 | library\lib\armeabi-v7a 170 | 1 171 | 172 | 173 | 174 | 175 | library\lib\armeabi 176 | 1 177 | 178 | 179 | library\lib\armeabi 180 | 1 181 | 182 | 183 | 184 | 185 | library\lib\armeabi-v7a 186 | 1 187 | 188 | 189 | 190 | 191 | library\lib\mips 192 | 1 193 | 194 | 195 | library\lib\mips 196 | 1 197 | 198 | 199 | 200 | 201 | library\lib\armeabi-v7a 202 | 1 203 | 204 | 205 | library\lib\arm64-v8a 206 | 1 207 | 208 | 209 | 210 | 211 | library\lib\armeabi-v7a 212 | 1 213 | 214 | 215 | 216 | 217 | res\drawable 218 | 1 219 | 220 | 221 | res\drawable 222 | 1 223 | 224 | 225 | 226 | 227 | res\values 228 | 1 229 | 230 | 231 | res\values 232 | 1 233 | 234 | 235 | 236 | 237 | res\values-v21 238 | 1 239 | 240 | 241 | res\values-v21 242 | 1 243 | 244 | 245 | 246 | 247 | res\values 248 | 1 249 | 250 | 251 | res\values 252 | 1 253 | 254 | 255 | 256 | 257 | res\drawable 258 | 1 259 | 260 | 261 | res\drawable 262 | 1 263 | 264 | 265 | 266 | 267 | res\drawable-xxhdpi 268 | 1 269 | 270 | 271 | res\drawable-xxhdpi 272 | 1 273 | 274 | 275 | 276 | 277 | res\drawable-xxxhdpi 278 | 1 279 | 280 | 281 | res\drawable-xxxhdpi 282 | 1 283 | 284 | 285 | 286 | 287 | res\drawable-ldpi 288 | 1 289 | 290 | 291 | res\drawable-ldpi 292 | 1 293 | 294 | 295 | 296 | 297 | res\drawable-mdpi 298 | 1 299 | 300 | 301 | res\drawable-mdpi 302 | 1 303 | 304 | 305 | 306 | 307 | res\drawable-hdpi 308 | 1 309 | 310 | 311 | res\drawable-hdpi 312 | 1 313 | 314 | 315 | 316 | 317 | res\drawable-xhdpi 318 | 1 319 | 320 | 321 | res\drawable-xhdpi 322 | 1 323 | 324 | 325 | 326 | 327 | res\drawable-mdpi 328 | 1 329 | 330 | 331 | res\drawable-mdpi 332 | 1 333 | 334 | 335 | 336 | 337 | res\drawable-hdpi 338 | 1 339 | 340 | 341 | res\drawable-hdpi 342 | 1 343 | 344 | 345 | 346 | 347 | res\drawable-xhdpi 348 | 1 349 | 350 | 351 | res\drawable-xhdpi 352 | 1 353 | 354 | 355 | 356 | 357 | res\drawable-xxhdpi 358 | 1 359 | 360 | 361 | res\drawable-xxhdpi 362 | 1 363 | 364 | 365 | 366 | 367 | res\drawable-xxxhdpi 368 | 1 369 | 370 | 371 | res\drawable-xxxhdpi 372 | 1 373 | 374 | 375 | 376 | 377 | res\drawable-small 378 | 1 379 | 380 | 381 | res\drawable-small 382 | 1 383 | 384 | 385 | 386 | 387 | res\drawable-normal 388 | 1 389 | 390 | 391 | res\drawable-normal 392 | 1 393 | 394 | 395 | 396 | 397 | res\drawable-large 398 | 1 399 | 400 | 401 | res\drawable-large 402 | 1 403 | 404 | 405 | 406 | 407 | res\drawable-xlarge 408 | 1 409 | 410 | 411 | res\drawable-xlarge 412 | 1 413 | 414 | 415 | 416 | 417 | res\values 418 | 1 419 | 420 | 421 | res\values 422 | 1 423 | 424 | 425 | 426 | 427 | 1 428 | 429 | 430 | Contents\MacOS 431 | 1 432 | 433 | 434 | 0 435 | 436 | 437 | 438 | 439 | Contents\MacOS 440 | 1 441 | .framework 442 | 443 | 444 | Contents\MacOS 445 | 1 446 | .framework 447 | 448 | 449 | Contents\MacOS 450 | 1 451 | .framework 452 | 453 | 454 | 0 455 | 456 | 457 | 458 | 459 | 1 460 | .dylib 461 | 462 | 463 | 1 464 | .dylib 465 | 466 | 467 | 1 468 | .dylib 469 | 470 | 471 | Contents\MacOS 472 | 1 473 | .dylib 474 | 475 | 476 | Contents\MacOS 477 | 1 478 | .dylib 479 | 480 | 481 | Contents\MacOS 482 | 1 483 | .dylib 484 | 485 | 486 | 0 487 | .dll;.bpl 488 | 489 | 490 | 491 | 492 | 1 493 | .dylib 494 | 495 | 496 | 1 497 | .dylib 498 | 499 | 500 | 1 501 | .dylib 502 | 503 | 504 | Contents\MacOS 505 | 1 506 | .dylib 507 | 508 | 509 | Contents\MacOS 510 | 1 511 | .dylib 512 | 513 | 514 | Contents\MacOS 515 | 1 516 | .dylib 517 | 518 | 519 | 0 520 | .bpl 521 | 522 | 523 | 524 | 525 | 0 526 | 527 | 528 | 0 529 | 530 | 531 | 0 532 | 533 | 534 | 0 535 | 536 | 537 | 0 538 | 539 | 540 | Contents\Resources\StartUp\ 541 | 0 542 | 543 | 544 | Contents\Resources\StartUp\ 545 | 0 546 | 547 | 548 | Contents\Resources\StartUp\ 549 | 0 550 | 551 | 552 | 0 553 | 554 | 555 | 556 | 557 | 1 558 | 559 | 560 | 1 561 | 562 | 563 | 564 | 565 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 566 | 1 567 | 568 | 569 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 570 | 1 571 | 572 | 573 | 574 | 575 | ..\ 576 | 1 577 | 578 | 579 | ..\ 580 | 1 581 | 582 | 583 | ..\ 584 | 1 585 | 586 | 587 | 588 | 589 | Contents 590 | 1 591 | 592 | 593 | Contents 594 | 1 595 | 596 | 597 | Contents 598 | 1 599 | 600 | 601 | 602 | 603 | Contents\Resources 604 | 1 605 | 606 | 607 | Contents\Resources 608 | 1 609 | 610 | 611 | Contents\Resources 612 | 1 613 | 614 | 615 | 616 | 617 | library\lib\armeabi-v7a 618 | 1 619 | 620 | 621 | library\lib\arm64-v8a 622 | 1 623 | 624 | 625 | 1 626 | 627 | 628 | 1 629 | 630 | 631 | 1 632 | 633 | 634 | 1 635 | 636 | 637 | Contents\MacOS 638 | 1 639 | 640 | 641 | Contents\MacOS 642 | 1 643 | 644 | 645 | Contents\MacOS 646 | 1 647 | 648 | 649 | 0 650 | 651 | 652 | 653 | 654 | library\lib\armeabi-v7a 655 | 1 656 | 657 | 658 | 659 | 660 | 1 661 | 662 | 663 | 1 664 | 665 | 666 | 667 | 668 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 669 | 1 670 | 671 | 672 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 673 | 1 674 | 675 | 676 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 677 | 1 678 | 679 | 680 | 681 | 682 | ..\ 683 | 1 684 | 685 | 686 | ..\ 687 | 1 688 | 689 | 690 | ..\ 691 | 1 692 | 693 | 694 | 695 | 696 | 1 697 | 698 | 699 | 1 700 | 701 | 702 | 1 703 | 704 | 705 | 706 | 707 | ..\$(PROJECTNAME).launchscreen 708 | 64 709 | 710 | 711 | ..\$(PROJECTNAME).launchscreen 712 | 64 713 | 714 | 715 | 716 | 717 | 1 718 | 719 | 720 | 1 721 | 722 | 723 | 1 724 | 725 | 726 | 727 | 728 | Assets 729 | 1 730 | 731 | 732 | Assets 733 | 1 734 | 735 | 736 | 737 | 738 | Assets 739 | 1 740 | 741 | 742 | Assets 743 | 1 744 | 745 | 746 | 747 | 748 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 749 | 1 750 | 751 | 752 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 753 | 1 754 | 755 | 756 | 757 | 758 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 759 | 1 760 | 761 | 762 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 763 | 1 764 | 765 | 766 | 767 | 768 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 769 | 1 770 | 771 | 772 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 773 | 1 774 | 775 | 776 | 777 | 778 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 779 | 1 780 | 781 | 782 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 783 | 1 784 | 785 | 786 | 787 | 788 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 789 | 1 790 | 791 | 792 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 793 | 1 794 | 795 | 796 | 797 | 798 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 799 | 1 800 | 801 | 802 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 803 | 1 804 | 805 | 806 | 807 | 808 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 809 | 1 810 | 811 | 812 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 813 | 1 814 | 815 | 816 | 817 | 818 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 819 | 1 820 | 821 | 822 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 823 | 1 824 | 825 | 826 | 827 | 828 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 829 | 1 830 | 831 | 832 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 833 | 1 834 | 835 | 836 | 837 | 838 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 839 | 1 840 | 841 | 842 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 843 | 1 844 | 845 | 846 | 847 | 848 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 849 | 1 850 | 851 | 852 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 853 | 1 854 | 855 | 856 | 857 | 858 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 859 | 1 860 | 861 | 862 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 863 | 1 864 | 865 | 866 | 867 | 868 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 869 | 1 870 | 871 | 872 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 873 | 1 874 | 875 | 876 | 877 | 878 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 879 | 1 880 | 881 | 882 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 883 | 1 884 | 885 | 886 | 887 | 888 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 889 | 1 890 | 891 | 892 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 893 | 1 894 | 895 | 896 | 897 | 898 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 899 | 1 900 | 901 | 902 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 903 | 1 904 | 905 | 906 | 907 | 908 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 909 | 1 910 | 911 | 912 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 913 | 1 914 | 915 | 916 | 917 | 918 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 919 | 1 920 | 921 | 922 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 923 | 1 924 | 925 | 926 | 927 | 928 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 929 | 1 930 | 931 | 932 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 933 | 1 934 | 935 | 936 | 937 | 938 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 939 | 1 940 | 941 | 942 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 943 | 1 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | True 960 | False 961 | 962 | 963 | 12 964 | 965 | 966 | 967 | 968 |
969 | -------------------------------------------------------------------------------- /Source/Library/CCE.DLL.Registry.pas: -------------------------------------------------------------------------------- 1 | unit CCE.DLL.Registry; 2 | 3 | interface 4 | 5 | uses 6 | ToolsAPI, 7 | CCE.ContextMenu; 8 | 9 | function RegisterCodeCoverageExperts(ABorlandIDEServices: IBorlandIDEServices; 10 | ARegisterProc: TWizardRegisterProc; 11 | var ATerminate: TWizardTerminateProc): Boolean; stdcall; 12 | 13 | implementation 14 | 15 | function RegisterCodeCoverageExperts(ABorlandIDEServices: IBorlandIDEServices; 16 | ARegisterProc: TWizardRegisterProc; 17 | var ATerminate: TWizardTerminateProc): Boolean; stdcall; 18 | begin 19 | Result := True; 20 | RegisterContextMenu; 21 | end; 22 | 23 | end. 24 | -------------------------------------------------------------------------------- /Source/Library/CodeCoverageExperts.dpr: -------------------------------------------------------------------------------- 1 | library CodeCoverageExperts; 2 | 3 | { Important note about DLL memory management: ShareMem must be the 4 | first unit in your library's USES clause AND your project's (select 5 | Project-View Source) USES clause if your DLL exports any procedures or 6 | functions that pass strings as parameters or function results. This 7 | applies to all strings passed to and from your DLL--even those that 8 | are nested in records and classes. ShareMem is the interface unit to 9 | the BORLNDMM.DLL shared memory manager, which must be deployed along 10 | with your DLL. To avoid using BORLNDMM.DLL, pass string information 11 | using PChar or ShortString parameters. } 12 | 13 | uses 14 | System.SysUtils, 15 | System.Classes, 16 | ToolsAPI, 17 | CCE.Constants in '..\Src\Core\CCE.Constants.pas', 18 | CCE.Core.CodeCoverage in '..\Src\Core\CCE.Core.CodeCoverage.pas', 19 | CCE.Core.Interfaces in '..\Src\Core\CCE.Core.Interfaces.pas', 20 | CCE.Core.Project in '..\Src\Core\CCE.Core.Project.pas', 21 | CCE.Core.Utils in '..\Src\Core\CCE.Core.Utils.pas', 22 | CCE.Helpers.TreeView in '..\Src\Core\CCE.Helpers.TreeView.pas', 23 | CCE.ContextMenu in '..\Src\IDE\CCE.ContextMenu.pas', 24 | CCE.Wizard.Forms in '..\Src\IDE\CCE.Wizard.Forms.pas' {CCEWizardForms}, 25 | CCE.dpipes in '..\Src\Third\CCE.dpipes.pas', 26 | CCE.dprocess in '..\Src\Third\CCE.dprocess.pas', 27 | CCE.DLL.Registry in 'CCE.DLL.Registry.pas'; 28 | 29 | exports 30 | RegisterCodeCoverageExperts Name WizardEntryPoint; 31 | 32 | {$R *.res} 33 | 34 | begin 35 | end. 36 | -------------------------------------------------------------------------------- /Source/Library/CodeCoverageExperts.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {FD6CA19B-027A-4D12-A7E4-96173478A19E} 4 | 18.4 5 | VCL 6 | CodeCoverageExperts.dpr 7 | True 8 | Release 9 | Win32 10 | 1 11 | Library 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Base 34 | true 35 | 36 | 37 | true 38 | Base 39 | true 40 | 41 | 42 | true 43 | Cfg_1 44 | true 45 | true 46 | 47 | 48 | true 49 | Base 50 | true 51 | 52 | 53 | true 54 | Cfg_2 55 | true 56 | true 57 | 58 | 59 | .\$(Platform)\$(Config) 60 | .\$(Platform)\$(Config) 61 | false 62 | false 63 | false 64 | false 65 | false 66 | true 67 | designide;$(DCC_UsePackage) 68 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 69 | CodeCoverageExperts 70 | true 71 | 1046 72 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 73 | 74 | 75 | FireDACADSDriver;rbRCL1825;FireDACMSSQLDriver;dclRBE1825;rbUSER1825;ACBr_OFX;rbIDE1825;rbRTL1825;rbDIDE1825;ACBr_GTIN;bindengine;FireDACMySQLDriver;rbTCUI1825;DataSnapClient;rbRIDE1825;IndySystem;ACBr_PagFor;FireDACInfxDriver;rbTC1825;rbRAP1825;emshosting;rbBDE1825;rbTDBC1825;FireDACTDataDriver;DbxCommonDriver;xmlrtl;DataSnapNativeClient;rtl;DbxClientDriver;rbDBE1825;FireDACODBCDriver;DataSnapIndy10ServerTransport;ACBr_Boleto;FireDACMongoDBDriver;DataSnapServerMidas;rbADO1825;DatasnapConnectorsFreePascal;inetdb;emsedge;dbexpress;IndyCore;dsnap;DataSnapCommon;ACBr_NFSeX;DataSnapConnectors;rbUSERDesign1825;dclRBADO1825;FireDACOracleDriver;FireDACCommonODBC;FireDACDb2Driver;FireDACPgDriver;FireDACASADriver;rbDB1825;DataSnapServer;rbCIDE1825;CustomIPTransport;bindcomp;ACBr_NFSeXDanfseRL;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage) 76 | 77 | 78 | DBXSqliteDriver;tethering;FireDACMSSQLDriver;FireDACDBXDriver;bindengine;FireDACMySQLDriver;DataSnapClient;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;emshosting;FireDACTDataDriver;FMXTee;DbxCommonDriver;xmlrtl;DataSnapNativeClient;fmxobj;rtl;DbxClientDriver;DBXSybaseASADriver;IndyIPClient;FireDACODBCDriver;DataSnapIndy10ServerTransport;DataSnapProviderClient;FireDACMongoDBDriver;DataSnapServerMidas;DBXInterBaseDriver;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;fmx;fmxdae;dbexpress;IndyCore;dsnap;DataSnapCommon;FireDACOracleDriver;DBXMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;IndyIPCommon;FireDACPgDriver;ibmonitor;FireDACASADriver;ibxpress;DataSnapServer;ibxbindings;FireDACDSDriver;CustomIPTransport;bindcomp;DBXInformixDriver;dbxcds;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;fmxase;$(DCC_UsePackage) 79 | 80 | 81 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 82 | Debug 83 | true 84 | (None) 85 | 1033 86 | 87 | 88 | DBXSqliteDriver;dxSpreadSheetCoreDialogsRS25;dxRibbonCustomizationFormRS25;DBXDb2Driver;dxPSPrVwRibbonRS25;BemaSQLXE;vclactnband;vclFireDAC;cxExportRS25;dxHttpIndyRequestRS25;tethering;dxPScxCommonRS25;FireDACADSDriver;cxPivotGridOLAPRS25;FireDACMSSQLDriver;cxSchedulerGridRS25;vcltouch;vcldb;Intraweb;TopGridXE;dxGaugeControlRS25;cxLibraryRS25;vclib;MultilizerDXE;CalWidgets;FireDACDBXDriver;vclx;BemaCompoXE;dxTileControlRS25;dxMapControlRS25;dxDockingRS25;VCLRESTComponents;cxPageControlRS25;dxPSLnksRS25;dxWizardControlRS25;vclie;bindengine;dxFireDACServerModeRS25;FireDACMySQLDriver;DataSnapClient;bindcompdbx;dxPSdxLCLnkRS25;DBXSybaseASEDriver;IndyIPServer;IndySystem;dsnapcon;dxLayoutControlRS25;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxdbtrRS25;Jcl;dxPScxTLLnkRS25;emshosting;dxSpreadSheetRS25;DBXOdbcDriver;FireDACTDataDriver;FMXTee;ipstudiowinclient;cxGridRS25;DbxCommonDriver;dxPScxSchedulerLnkRS25;dxorgcRS25;BemaAddXE;xmlrtl;DataSnapNativeClient;fmxobj;dxPScxGridLnkRS25;rtl;DbxClientDriver;DBXSybaseASADriver;dxPSCoreRS25;dxmdsRS25;ipstudiowin;appanalytics;BemaPdvComposXE;IndyIPClient;bindcompvcl;dxThemeRS25;TeeUI;VclSmp;FireDACODBCDriver;JclVcl;DataSnapIndy10ServerTransport;DataSnapProviderClient;FireDACMongoDBDriver;cxVerticalGridRS25;dxADOServerModeRS25;DataSnapServerMidas;dxCoreRS25;cxSchedulerTreeBrowserRS25;BemaBaseCompoXE;DBXInterBaseDriver;dxPSTeeChartRS25;DBXMSSQLDriver;dxPSdxFCLnkRS25;DatasnapConnectorsFreePascal;BemaProxiesXE;bindcompfmx;DBXOracleDriver;inetdb;EpsonPF300;dxOfficeCoreRS25;FmxTeeUI;emsedge;fmx;fmxdae;dxPScxPivotGridLnkRS25;dxBarDBNavRS25;dxTabbedMDIRS25;ZipMasterR;dbexpress;IndyCore;dxFlowChartRS25;dsnap;DataSnapCommon;dxBarRS25;dxPSDBTeeChartRS25;dxdborRS25;DataSnapConnectors;dxPScxExtCommonRS25;cxPivotGridRS25;BemaUtilsXE;dxPSdxSpreadSheetLnkRS25;dxNavBarRS25;JclDeveloperTools;QR5RunNBDEDXE;cxSchedulerRibbonStyleEventEditorRS25;FireDACOracleDriver;DBXMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;cxTreeListRS25;IndyIPCommon;vcl;dxPScxVGridLnkRS25;dxBarExtItemsRS25;FireDACDb2Driver;dxComnRS25;dxPSdxDBTVLnkRS25;BemaToolBarXE;TeeDB;dxSpreadSheetCoreRS25;dxServerModeRS25;dxPScxPCProdRS25;FireDACPgDriver;ibmonitor;FireDACASADriver;cxEditorsRS25;ibxpress;Tee;DataSnapServer;ibxbindings;dxPsPrVwAdvRS25;vclwinx;FireDACDSDriver;fcstudiowin;cxDataRS25;cxTreeListdxBarPopupMenuRS25;CustomIPTransport;vcldsnap;dxPSdxOCLnkRS25;bindcomp;DBXInformixDriver;officeXPrt;cxPivotGridChartRS25;cxSchedulerRS25;dxBarExtDBItemsRS25;dxDBXServerModeRS25;dxGDIPlusRS25;dbxcds;adortl;dxPSdxDBOCLnkRS25;dxRibbonRS25;dsnapxml;dxSpellCheckerRS25;dbrtl;inetdbxpress;IndyProtocols;JclContainers;fmxase;$(DCC_UsePackage) 89 | 90 | 91 | DEBUG;$(DCC_Define) 92 | true 93 | false 94 | true 95 | true 96 | true 97 | 98 | 99 | false 100 | true 101 | 1033 102 | (None) 103 | 104 | 105 | false 106 | RELEASE;$(DCC_Define) 107 | 0 108 | 0 109 | 110 | 111 | true 112 | 1033 113 | 114 | 115 | 116 | MainSource 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |
CCEWizardForms
127 | dfm 128 |
129 | 130 | 131 | 132 | 133 | Cfg_2 134 | Base 135 | 136 | 137 | Base 138 | 139 | 140 | Cfg_1 141 | Base 142 | 143 |
144 | 145 | Delphi.Personality.12 146 | Application 147 | 148 | 149 | 150 | CodeCoverageExperts.dpr 151 | 152 | 153 | File c:\program files (x86)\embarcadero\studio\19.0\bin\spdNFCe_D10T.bpl not found 154 | File c:\program files (x86)\embarcadero\studio\19.0\bin\spdNFCeGov_D10T.bpl not found 155 | ADRIFood 156 | Microsoft Office 2000 Sample Automation Server Wrapper Components 157 | 158 | 159 | 160 | 161 | 162 | true 163 | 164 | 165 | 166 | 167 | true 168 | 169 | 170 | 171 | 172 | true 173 | 174 | 175 | 176 | 177 | true 178 | 179 | 180 | 181 | 182 | CodeCoverageExperts.dll 183 | true 184 | 185 | 186 | 187 | 188 | 1 189 | 190 | 191 | Contents\MacOS 192 | 1 193 | 194 | 195 | Contents\MacOS 196 | 0 197 | 198 | 199 | 200 | 201 | classes 202 | 1 203 | 204 | 205 | 206 | 207 | library\lib\armeabi-v7a 208 | 1 209 | 210 | 211 | 212 | 213 | library\lib\armeabi 214 | 1 215 | 216 | 217 | 218 | 219 | library\lib\mips 220 | 1 221 | 222 | 223 | 224 | 225 | library\lib\armeabi-v7a 226 | 1 227 | 228 | 229 | 230 | 231 | res\drawable 232 | 1 233 | 234 | 235 | 236 | 237 | res\values 238 | 1 239 | 240 | 241 | 242 | 243 | res\drawable 244 | 1 245 | 246 | 247 | 248 | 249 | res\drawable-xxhdpi 250 | 1 251 | 252 | 253 | 254 | 255 | res\drawable-ldpi 256 | 1 257 | 258 | 259 | 260 | 261 | res\drawable-mdpi 262 | 1 263 | 264 | 265 | 266 | 267 | res\drawable-hdpi 268 | 1 269 | 270 | 271 | 272 | 273 | res\drawable-xhdpi 274 | 1 275 | 276 | 277 | 278 | 279 | res\drawable-small 280 | 1 281 | 282 | 283 | 284 | 285 | res\drawable-normal 286 | 1 287 | 288 | 289 | 290 | 291 | res\drawable-large 292 | 1 293 | 294 | 295 | 296 | 297 | res\drawable-xlarge 298 | 1 299 | 300 | 301 | 302 | 303 | 1 304 | 305 | 306 | Contents\MacOS 307 | 1 308 | 309 | 310 | 0 311 | 312 | 313 | 314 | 315 | Contents\MacOS 316 | 1 317 | .framework 318 | 319 | 320 | 0 321 | 322 | 323 | 324 | 325 | 1 326 | .dylib 327 | 328 | 329 | 1 330 | .dylib 331 | 332 | 333 | 1 334 | .dylib 335 | 336 | 337 | Contents\MacOS 338 | 1 339 | .dylib 340 | 341 | 342 | 0 343 | .dll;.bpl 344 | 345 | 346 | 347 | 348 | 1 349 | .dylib 350 | 351 | 352 | 1 353 | .dylib 354 | 355 | 356 | 1 357 | .dylib 358 | 359 | 360 | Contents\MacOS 361 | 1 362 | .dylib 363 | 364 | 365 | 0 366 | .bpl 367 | 368 | 369 | 370 | 371 | 0 372 | 373 | 374 | 0 375 | 376 | 377 | 0 378 | 379 | 380 | 0 381 | 382 | 383 | Contents\Resources\StartUp\ 384 | 0 385 | 386 | 387 | 0 388 | 389 | 390 | 391 | 392 | 1 393 | 394 | 395 | 1 396 | 397 | 398 | 1 399 | 400 | 401 | 402 | 403 | 1 404 | 405 | 406 | 1 407 | 408 | 409 | 1 410 | 411 | 412 | 413 | 414 | 1 415 | 416 | 417 | 1 418 | 419 | 420 | 1 421 | 422 | 423 | 424 | 425 | 1 426 | 427 | 428 | 1 429 | 430 | 431 | 1 432 | 433 | 434 | 435 | 436 | 1 437 | 438 | 439 | 1 440 | 441 | 442 | 1 443 | 444 | 445 | 446 | 447 | 1 448 | 449 | 450 | 1 451 | 452 | 453 | 1 454 | 455 | 456 | 457 | 458 | 1 459 | 460 | 461 | 1 462 | 463 | 464 | 1 465 | 466 | 467 | 468 | 469 | 1 470 | 471 | 472 | 473 | 474 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 475 | 1 476 | 477 | 478 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 479 | 1 480 | 481 | 482 | 483 | 484 | 1 485 | 486 | 487 | 1 488 | 489 | 490 | 491 | 492 | ..\ 493 | 1 494 | 495 | 496 | ..\ 497 | 1 498 | 499 | 500 | 501 | 502 | 1 503 | 504 | 505 | 1 506 | 507 | 508 | 1 509 | 510 | 511 | 512 | 513 | 1 514 | 515 | 516 | 1 517 | 518 | 519 | 1 520 | 521 | 522 | 523 | 524 | ..\ 525 | 1 526 | 527 | 528 | 529 | 530 | Contents 531 | 1 532 | 533 | 534 | 535 | 536 | Contents\Resources 537 | 1 538 | 539 | 540 | 541 | 542 | library\lib\armeabi-v7a 543 | 1 544 | 545 | 546 | 1 547 | 548 | 549 | 1 550 | 551 | 552 | 1 553 | 554 | 555 | 1 556 | 557 | 558 | Contents\MacOS 559 | 1 560 | 561 | 562 | 0 563 | 564 | 565 | 566 | 567 | 1 568 | 569 | 570 | 1 571 | 572 | 573 | 574 | 575 | Assets 576 | 1 577 | 578 | 579 | Assets 580 | 1 581 | 582 | 583 | 584 | 585 | Assets 586 | 1 587 | 588 | 589 | Assets 590 | 1 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | False 604 | False 605 | True 606 | False 607 | 608 | 609 | 12 610 | 611 | 612 | 613 | 614 |
615 | -------------------------------------------------------------------------------- /Source/Package/CCE.Pkg.Registry.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Pkg.Registry; 2 | 3 | interface 4 | 5 | uses 6 | ToolsAPI, 7 | CCE.ContextMenu; 8 | 9 | procedure Register; 10 | 11 | implementation 12 | 13 | procedure Register; 14 | begin 15 | RegisterContextMenu; 16 | end; 17 | 18 | end. 19 | -------------------------------------------------------------------------------- /Source/Package/CodeCoverageExperts.dpk: -------------------------------------------------------------------------------- 1 | package CodeCoverageExperts; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS OFF} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION ON} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO OFF} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES OFF} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE RELEASE} 27 | {$DEFINE TESTINSIGHT} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'Code Coverage Experts'} 30 | {$IMPLICITBUILD ON} 31 | 32 | requires 33 | rtl, 34 | designide; 35 | 36 | contains 37 | CCE.Constants in '..\Src\Core\CCE.Constants.pas', 38 | CCE.Core.CodeCoverage in '..\Src\Core\CCE.Core.CodeCoverage.pas', 39 | CCE.Core.Interfaces in '..\Src\Core\CCE.Core.Interfaces.pas', 40 | CCE.Core.Project in '..\Src\Core\CCE.Core.Project.pas', 41 | CCE.Core.Utils in '..\Src\Core\CCE.Core.Utils.pas', 42 | CCE.Helpers.TreeView in '..\Src\Core\CCE.Helpers.TreeView.pas', 43 | CCE.ContextMenu in '..\Src\IDE\CCE.ContextMenu.pas', 44 | CCE.Pkg.Registry in 'CCE.Pkg.Registry.pas', 45 | CCE.Wizard.Forms in '..\Src\IDE\CCE.Wizard.Forms.pas' {CCEWizardForms}, 46 | CCE.dpipes in '..\Src\Third\CCE.dpipes.pas', 47 | CCE.dprocess in '..\Src\Third\CCE.dprocess.pas'; 48 | 49 | end. 50 | -------------------------------------------------------------------------------- /Source/Src/Core/CCE.Constants.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Constants; 2 | 3 | interface 4 | 5 | uses 6 | ToolsAPI; 7 | 8 | const 9 | CCE_COVERAGE_POSITION = pmmpUninstall + 200; 10 | CCE_COVERAGE_WIZARD_POSITION = CCE_COVERAGE_POSITION + 100; 11 | CCE_COVERAGE_EXECUTE_POSITION = CCE_COVERAGE_WIZARD_POSITION + 10; 12 | CCE_COVERAGE_HTML_POSITION = CCE_COVERAGE_EXECUTE_POSITION + 10; 13 | 14 | CCE_COVERAGE_CAPTION = 'Code Coverage'; 15 | CCE_COVERAGE_WIZARD_CAPTION = 'Wizard...'; 16 | CCE_COVERAGE_EXECUTE_CAPTION = 'Execute'; 17 | CCE_COVERAGE_HTML_CAPTION = 'Show HTML Report'; 18 | 19 | implementation 20 | 21 | end. 22 | -------------------------------------------------------------------------------- /Source/Src/Core/CCE.Core.CodeCoverage.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Core.CodeCoverage; 2 | 3 | interface 4 | 5 | uses 6 | CCE.Core.Interfaces, 7 | CCE.Core.Utils, 8 | System.SysUtils, 9 | System.Classes, 10 | System.Generics.Collections, 11 | Winapi.Windows, 12 | Vcl.Dialogs; 13 | 14 | type 15 | TCCECoreCodeCoverage = class(TInterfacedObject, ICCECodeCoverage) 16 | private 17 | FCodeCoverageFileName: string; 18 | FExeFileName: string; 19 | FMapFileName: string; 20 | FOutputReport: string; 21 | FUnitsFiles: TList; 22 | FUnitsIgnore: TList; 23 | FPaths: TList; 24 | FGenerateHtml: Boolean; 25 | FGenerateXml: Boolean; 26 | FGenerateEmma: Boolean; 27 | FGenerateLog: Boolean; 28 | FUseRelativePath: Boolean; 29 | 30 | function FileToList(AFileName: string): TList; 31 | 32 | function FilePathsName: string; 33 | function FileUnitsName: string; 34 | function FileCodeCoverageBat: string; 35 | function CodeCoverageCommand: string; 36 | 37 | procedure GenerateFilePaths; 38 | procedure GenerateFileUnits; 39 | 40 | function GetExeName: string; 41 | function GetMapName: string; 42 | function GetOutputReport: string; 43 | function GetFileUnits: string; 44 | function GetFilePaths: string; 45 | function GetReportHTMLName: string; 46 | function GetReportXMLName: string; 47 | function GetCoverageLogFileName: string; 48 | 49 | function ContainsIn(Value: string; AList: TList): Boolean; 50 | protected 51 | function BasePath: string; 52 | function Clear: ICCECodeCoverage; 53 | 54 | function CodeCoverageFileName(Value: string): ICCECodeCoverage; 55 | function ExeFileName(Value: string): ICCECodeCoverage; 56 | function MapFileName(Value: string): ICCECodeCoverage; 57 | function OutputReport(Value: string): ICCECodeCoverage; 58 | function Paths(Values: TArray): ICCECodeCoverage; 59 | function Units(Values: TArray): ICCECodeCoverage; 60 | function GenerateHtml(Value: Boolean): ICCECodeCoverage; 61 | function GenerateXml(Value: Boolean): ICCECodeCoverage; 62 | function GenerateEmma(Value: Boolean): ICCECodeCoverage; 63 | function GenerateLog(Value: Boolean): ICCECodeCoverage; 64 | function UseRelativePath(Value: Boolean): ICCECodeCoverage; 65 | 66 | function IsInCovUnits(AUnitName: string): Boolean; 67 | function IgnoredUnits: TArray; 68 | 69 | function AddUnit(Value: string): ICCECodeCoverage; 70 | function AddUnitIgnore(Value: string): ICCECodeCoverage; 71 | function AddPath(Value: string): ICCECodeCoverage; 72 | 73 | function Save: ICCECodeCoverage; 74 | function Execute: ICCECodeCoverage; 75 | 76 | function ShowHTMLReport: ICCECodeCoverage; 77 | function ShowXMLReport: ICCECodeCoverage; 78 | function ShowLogCoverage: ICCECodeCoverage; 79 | 80 | public 81 | constructor create; 82 | class function New: ICCECodeCoverage; 83 | destructor Destroy; override; 84 | end; 85 | 86 | implementation 87 | 88 | { TCCECoreCodeCoverage } 89 | 90 | function TCCECoreCodeCoverage.AddPath(Value: string): ICCECodeCoverage; 91 | begin 92 | Result := Self; 93 | if not ContainsIn(Value, FPaths) then 94 | FPaths.Add(Value); 95 | end; 96 | 97 | function TCCECoreCodeCoverage.AddUnit(Value: string): ICCECodeCoverage; 98 | begin 99 | Result := Self; 100 | if not ContainsIn(Value, FUnitsFiles) then 101 | FUnitsFiles.Add(Value); 102 | end; 103 | 104 | function TCCECoreCodeCoverage.AddUnitIgnore(Value: string): ICCECodeCoverage; 105 | var 106 | LValue: string; 107 | begin 108 | Result := Self; 109 | LValue := Value; 110 | if LValue.StartsWith('!') then 111 | LValue := Copy(LValue, 2, LValue.Length); 112 | 113 | if not FUnitsIgnore.Contains(LValue) then 114 | FUnitsIgnore.Add(LValue); 115 | end; 116 | 117 | function TCCECoreCodeCoverage.BasePath: string; 118 | begin 119 | Result := ExtractFilePath(FExeFileName); 120 | end; 121 | 122 | function TCCECoreCodeCoverage.Clear: ICCECodeCoverage; 123 | begin 124 | Result := Self; 125 | FUnitsFiles.Clear; 126 | FUnitsIgnore.Clear; 127 | FPaths.Clear; 128 | end; 129 | 130 | function TCCECoreCodeCoverage.CodeCoverageCommand: string; 131 | begin 132 | Result := '"%s" -e "%s" -m "%s" -uf "%s" -spf "%s" -od "%s" '; 133 | if FGenerateLog then 134 | Result := Result + '-lt '; 135 | 136 | if FGenerateEmma then 137 | Result := Result + '-emma -meta '; 138 | 139 | if FGenerateHtml then 140 | Result := Result + '-html '; 141 | 142 | if FGenerateXml then 143 | Result := Result + '-xml -xmllines'; 144 | 145 | Result := Format(Result, [FCodeCoverageFileName, 146 | GetExeName, 147 | GetMapName, 148 | GetFileUnits, 149 | GetFilePaths, 150 | GetOutputReport]); 151 | end; 152 | 153 | function TCCECoreCodeCoverage.CodeCoverageFileName(Value: string): ICCECodeCoverage; 154 | begin 155 | Result := Self; 156 | FCodeCoverageFileName := Value; 157 | end; 158 | 159 | function TCCECoreCodeCoverage.ContainsIn(Value: string; AList: TList): Boolean; 160 | var 161 | listValue: string; 162 | begin 163 | Result := False; 164 | for listValue in AList do 165 | begin 166 | if listValue.ToLower.Equals(Value.ToLower) then 167 | Exit(True); 168 | end; 169 | end; 170 | 171 | constructor TCCECoreCodeCoverage.create; 172 | begin 173 | FCodeCoverageFileName := 'CodeCoverage.exe'; 174 | FGenerateXml := True; 175 | FGenerateLog := True; 176 | FGenerateHtml := True; 177 | FGenerateEmma := True; 178 | FUseRelativePath := True; 179 | 180 | FUnitsFiles := TList.create; 181 | FUnitsIgnore := TList.create; 182 | FPaths := TList.create; 183 | end; 184 | 185 | destructor TCCECoreCodeCoverage.Destroy; 186 | begin 187 | FUnitsFiles.Free; 188 | FPaths.Free; 189 | FUnitsIgnore.Free; 190 | inherited; 191 | end; 192 | 193 | function TCCECoreCodeCoverage.Execute: ICCECodeCoverage; 194 | begin 195 | Result := Self; 196 | 197 | ExecuteAndWait(BasePath, FileCodeCoverageBat); 198 | end; 199 | 200 | function TCCECoreCodeCoverage.ExeFileName(Value: string): ICCECodeCoverage; 201 | begin 202 | Result := Self; 203 | FExeFileName := Value; 204 | end; 205 | 206 | function TCCECoreCodeCoverage.FileCodeCoverageBat: string; 207 | begin 208 | Result := ExtractFilePath(FExeFileName) + 'dcov_execute.bat'; 209 | end; 210 | 211 | function TCCECoreCodeCoverage.FilePathsName: string; 212 | begin 213 | Result := ExtractFilePath(FExeFileName) + 'dcov_paths.lst'; 214 | end; 215 | 216 | function TCCECoreCodeCoverage.FileToList(AFileName: string): TList; 217 | var 218 | LFile: TStrings; 219 | i: Integer; 220 | begin 221 | Result := TList.create; 222 | try 223 | LFile := TStringList.Create; 224 | try 225 | if FileExists(AFileName) then 226 | begin 227 | LFile.LoadFromFile(AFileName); 228 | for i := 0 to Pred(LFile.Count) do 229 | Result.Add(LFile[i]); 230 | end; 231 | finally 232 | LFile.Free; 233 | end; 234 | except 235 | Result.Free; 236 | raise; 237 | end; 238 | end; 239 | 240 | function TCCECoreCodeCoverage.FileUnitsName: string; 241 | begin 242 | Result := ExtractFilePath(FExeFileName) + 'dcov_units.lst'; 243 | end; 244 | 245 | function TCCECoreCodeCoverage.GenerateEmma(Value: Boolean): ICCECodeCoverage; 246 | begin 247 | Result := Self; 248 | FGenerateEmma := Value; 249 | end; 250 | 251 | procedure TCCECoreCodeCoverage.GenerateFilePaths; 252 | var 253 | path: string; 254 | i : Integer; 255 | begin 256 | with TStringList.Create do 257 | try 258 | for i := 0 to Pred(FPaths.Count) do 259 | begin 260 | path := FPaths[i]; 261 | if FUseRelativePath then 262 | path := AbsolutePathToRelative(path, BasePath); 263 | 264 | if not path.EndsWith('\') then 265 | path := path + '\'; 266 | Add(path); 267 | end; 268 | 269 | SaveToFile(FilePathsName); 270 | finally 271 | Free; 272 | end; 273 | end; 274 | 275 | procedure TCCECoreCodeCoverage.GenerateFileUnits; 276 | var 277 | unitFile: string; 278 | i : Integer; 279 | begin 280 | with TStringList.Create do 281 | try 282 | for i := 0 to Pred(FUnitsIgnore.Count) do 283 | Add('!' + FUnitsIgnore[i]); 284 | 285 | for i := 0 to Pred(FUnitsFiles.Count) do 286 | begin 287 | unitFile := ExtractFileName(FUnitsFiles[i]); 288 | Add(unitFile); 289 | end; 290 | 291 | SaveToFile(FileUnitsName); 292 | finally 293 | Free; 294 | end; 295 | end; 296 | 297 | function TCCECoreCodeCoverage.GenerateHtml(Value: Boolean): ICCECodeCoverage; 298 | begin 299 | Result := Self; 300 | FGenerateHtml := Value; 301 | end; 302 | 303 | function TCCECoreCodeCoverage.GenerateLog(Value: Boolean): ICCECodeCoverage; 304 | begin 305 | Result := Self; 306 | FGenerateLog := Value; 307 | end; 308 | 309 | function TCCECoreCodeCoverage.GenerateXml(Value: Boolean): ICCECodeCoverage; 310 | begin 311 | Result := Self; 312 | FGenerateXml := Value; 313 | end; 314 | 315 | function TCCECoreCodeCoverage.GetCoverageLogFileName: string; 316 | begin 317 | Result := BasePath + '\Delphi-Code-Coverage-Debug.log'; 318 | end; 319 | 320 | function TCCECoreCodeCoverage.GetExeName: string; 321 | begin 322 | Result := FExeFileName; 323 | if FUseRelativePath then 324 | Result := AbsolutePathToRelative(FExeFileName, BasePath); 325 | end; 326 | 327 | function TCCECoreCodeCoverage.GetFilePaths: string; 328 | begin 329 | Result := FilePathsName; 330 | if FUseRelativePath then 331 | Result := AbsolutePathToRelative(FilePathsName, BasePath); 332 | end; 333 | 334 | function TCCECoreCodeCoverage.GetFileUnits: string; 335 | begin 336 | Result := FileUnitsName; 337 | if FUseRelativePath then 338 | Result := AbsolutePathToRelative(FileUnitsName, BasePath); 339 | end; 340 | 341 | function TCCECoreCodeCoverage.GetMapName: string; 342 | begin 343 | Result := FMapFileName; 344 | if FUseRelativePath then 345 | Result := AbsolutePathToRelative(FMapFileName, BasePath); 346 | end; 347 | 348 | function TCCECoreCodeCoverage.GetOutputReport: string; 349 | begin 350 | Result := FOutputReport; 351 | if FUseRelativePath then 352 | Result := AbsolutePathToRelative(FOutputReport, BasePath); 353 | end; 354 | 355 | function TCCECoreCodeCoverage.GetReportHTMLName: string; 356 | begin 357 | Result := FOutputReport + '\CodeCoverage_summary.html'; 358 | end; 359 | 360 | function TCCECoreCodeCoverage.GetReportXMLName: string; 361 | begin 362 | Result := FOutputReport + '\CodeCoverage_Summary.xml'; 363 | end; 364 | 365 | function TCCECoreCodeCoverage.IgnoredUnits: TArray; 366 | var 367 | LUnits: TList; 368 | i: Integer; 369 | begin 370 | LUnits := FileToList(FileUnitsName); 371 | try 372 | for i := 0 to Pred(LUnits.Count) do 373 | begin 374 | if LUnits[i].StartsWith('!') then 375 | begin 376 | SetLength(Result, Length(Result) + 1); 377 | Result[Length(Result) - 1] := Copy(LUnits[i], 2, LUnits[i].Length).Trim; 378 | end; 379 | end; 380 | finally 381 | LUnits.Free; 382 | end; 383 | end; 384 | 385 | function TCCECoreCodeCoverage.IsInCovUnits(AUnitName: string): Boolean; 386 | var 387 | LPaths: TList; 388 | LUnits: TList; 389 | LUnitName: string; 390 | LPath: string; 391 | begin 392 | LPaths := FileToList(FilePathsName); 393 | LUnits := FileToList(FileUnitsName); 394 | try 395 | LPath := ExtractFilePath(AUnitName); 396 | if FUseRelativePath then 397 | LPath := AbsolutePathToRelative(LPath, BasePath); 398 | 399 | LUnitName := ExtractFileName(AUnitName); 400 | 401 | Result := (LPaths.Contains(LPath)) and (LUnits.Contains(LUnitName)); 402 | finally 403 | LPaths.Free; 404 | LUnits.Free; 405 | end; 406 | end; 407 | 408 | function TCCECoreCodeCoverage.MapFileName(Value: string): ICCECodeCoverage; 409 | begin 410 | Result := Self; 411 | FMapFileName := Value; 412 | end; 413 | 414 | class function TCCECoreCodeCoverage.New: ICCECodeCoverage; 415 | begin 416 | Result := Self.Create; 417 | end; 418 | 419 | function TCCECoreCodeCoverage.OutputReport(Value: string): ICCECodeCoverage; 420 | begin 421 | Result := Self; 422 | FOutputReport := Value; 423 | end; 424 | 425 | function TCCECoreCodeCoverage.Paths(Values: TArray): ICCECodeCoverage; 426 | var 427 | i: Integer; 428 | begin 429 | Result := Self; 430 | for i := 0 to Pred(Length(Values)) do 431 | AddPath(Values[i]); 432 | end; 433 | 434 | function TCCECoreCodeCoverage.Save: ICCECodeCoverage; 435 | begin 436 | Result := Self; 437 | GenerateFilePaths; 438 | GenerateFileUnits; 439 | 440 | with TStringList.Create do 441 | try 442 | Text := CodeCoverageCommand; 443 | SaveToFile(FileCodeCoverageBat); 444 | finally 445 | Free; 446 | end; 447 | end; 448 | 449 | function TCCECoreCodeCoverage.ShowHTMLReport: ICCECodeCoverage; 450 | begin 451 | Result := Self; 452 | CCE.Core.Utils.OpenFile(GetReportHTMLName); 453 | end; 454 | 455 | function TCCECoreCodeCoverage.ShowLogCoverage: ICCECodeCoverage; 456 | begin 457 | Result := Self; 458 | CCE.Core.Utils.OpenFile(GetCoverageLogFileName); 459 | end; 460 | 461 | function TCCECoreCodeCoverage.ShowXMLReport: ICCECodeCoverage; 462 | begin 463 | Result := Self; 464 | CCE.Core.Utils.OpenFile(GetReportXMLName); 465 | end; 466 | 467 | function TCCECoreCodeCoverage.Units(Values: TArray): ICCECodeCoverage; 468 | var 469 | i: Integer; 470 | begin 471 | Result := Self; 472 | for i := 0 to Pred(Length(Values)) do 473 | AddUnit(Values[i]); 474 | end; 475 | 476 | function TCCECoreCodeCoverage.UseRelativePath(Value: Boolean): ICCECodeCoverage; 477 | begin 478 | Result := Self; 479 | FUseRelativePath := Value; 480 | end; 481 | 482 | end. 483 | -------------------------------------------------------------------------------- /Source/Src/Core/CCE.Core.Interfaces.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Core.Interfaces; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, 7 | System.Classes; 8 | 9 | type 10 | ICCEProject = interface 11 | ['{676756F9-BEBC-4FCB-90AE-0B9843F7D126}'] 12 | function ProjectPath: string; 13 | function OutputPath: string; 14 | function ExeName: string; overload; 15 | function DprFileName: string; 16 | function MapFileName: string; overload; 17 | 18 | function SetDetailedMapFile: ICCEProject; 19 | 20 | function ListAllPaths: TArray; 21 | function ListAllUnits(APath: string): TArray; overload; 22 | function ListAllUnits: TArray; overload; 23 | 24 | function Build: ICCEProject; 25 | end; 26 | 27 | ICCECodeCoverage = interface 28 | ['{DCE40126-F975-4BAA-8CAE-3BD2ED2AF6EF}'] 29 | function Clear: ICCECodeCoverage; 30 | function BasePath: string; 31 | function CodeCoverageFileName(AValue: string): ICCECodeCoverage; 32 | function ExeFileName(AValue: string): ICCECodeCoverage; overload; 33 | function MapFileName(AValue: string): ICCECodeCoverage; 34 | function OutputReport(Value: string): ICCECodeCoverage; 35 | function Paths(AValues: TArray): ICCECodeCoverage; 36 | function Units(AValues: TArray): ICCECodeCoverage; 37 | function GenerateHtml(AValue: Boolean): ICCECodeCoverage; 38 | function GenerateXml(AValue: Boolean): ICCECodeCoverage; 39 | function GenerateEmma(AValue: Boolean): ICCECodeCoverage; 40 | function GenerateLog(AValue: Boolean): ICCECodeCoverage; 41 | function UseRelativePath(AValue: Boolean): ICCECodeCoverage; 42 | 43 | function IsInCovUnits(AUnitName: string): Boolean; 44 | function IgnoredUnits: TArray; 45 | 46 | function AddUnit(AValue: string): ICCECodeCoverage; 47 | function AddUnitIgnore(AValue: string): ICCECodeCoverage; 48 | function AddPath(AValue: string): ICCECodeCoverage; 49 | 50 | function Save: ICCECodeCoverage; 51 | function Execute: ICCECodeCoverage; 52 | 53 | function ShowHTMLReport: ICCECodeCoverage; 54 | function ShowXMLReport: ICCECodeCoverage; 55 | function ShowLogCoverage: ICCECodeCoverage; 56 | end; 57 | 58 | implementation 59 | 60 | end. 61 | -------------------------------------------------------------------------------- /Source/Src/Core/CCE.Core.Project.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Core.Project; 2 | 3 | interface 4 | 5 | uses 6 | Dccstrs, 7 | ToolsAPI, 8 | CCE.Core.Interfaces, 9 | CCE.Core.Utils, 10 | System.Generics.Collections, 11 | System.IOUtils, 12 | System.SysUtils, 13 | System.Types, 14 | System.Classes; 15 | 16 | const 17 | TEST_INSIGHT = 'TESTINSIGHT'; 18 | 19 | type TCCECoreProject = class(TInterfacedObject, ICCEProject) 20 | 21 | private 22 | FProject: IOTAProject; 23 | FActiveConfig: IOTABuildConfiguration; 24 | FPaths: TList; 25 | FUnits: TList; 26 | 27 | function ProjectPath: string; 28 | function GetSearchPaths: TList; 29 | 30 | procedure SetAllPaths; 31 | procedure SetAllUnits(Path: String); 32 | 33 | procedure AddPath(Value: String); 34 | procedure AddUnit(Value: String); 35 | public 36 | function OutputPath: string; 37 | function ExeName: String; 38 | function DprFileName: string; 39 | function MapFileName: string; 40 | 41 | function SetDetailedMapFile: ICCEProject; 42 | 43 | function ListAllPaths: TArray; 44 | function ListAllUnits(Path: String): TArray; overload; 45 | function ListAllUnits: TArray; overload; 46 | 47 | function Build: ICCEProject; 48 | 49 | constructor create(Project: IOTAProject); 50 | class function New(Project: IOTAProject): ICCEProject; 51 | destructor Destroy; override; 52 | end; 53 | 54 | implementation 55 | 56 | { TCCECoreProject } 57 | 58 | procedure TCCECoreProject.AddPath(Value: String); 59 | begin 60 | if (not FPaths.Contains(Value)) and (DirectoryExists(Value)) then 61 | FPaths.Add(Value); 62 | end; 63 | 64 | procedure TCCECoreProject.AddUnit(Value: String); 65 | begin 66 | if not FUnits.Contains(Value) then 67 | FUnits.Add(Value); 68 | end; 69 | 70 | function TCCECoreProject.Build: ICCEProject; 71 | begin 72 | result := Self; 73 | FProject.ProjectBuilder 74 | .BuildProject(TOTACompileMode.cmOTABuild, True, True); 75 | end; 76 | 77 | constructor TCCECoreProject.create(Project: IOTAProject); 78 | begin 79 | FProject := Project; 80 | FActiveConfig := (Project.ProjectOptions as IOTAProjectOptionsConfigurations) 81 | .ActiveConfiguration; 82 | 83 | FPaths := TList.create; 84 | FUnits := TList.create; 85 | 86 | SetAllPaths; 87 | end; 88 | 89 | destructor TCCECoreProject.Destroy; 90 | begin 91 | FPaths.Free; 92 | FUnits.Free; 93 | inherited; 94 | end; 95 | 96 | function TCCECoreProject.DprFileName: string; 97 | begin 98 | result := FProject.FileName; 99 | end; 100 | 101 | function TCCECoreProject.ExeName: String; 102 | begin 103 | Result := OutputPath + 104 | ChangeFileExt(ExtractFileName(FProject.FileName), '.exe'); 105 | end; 106 | 107 | function TCCECoreProject.GetSearchPaths: TList; 108 | var 109 | searchPath: TStrings; 110 | path: string; 111 | i: Integer; 112 | begin 113 | searchPath := TStringList.Create; 114 | try 115 | result := TList.create; 116 | try 117 | FActiveConfig.GetValues(sUnitSearchPath, searchPath, True); 118 | for i := 0 to Pred(searchPath.Count) do 119 | begin 120 | path := RelativeToAbsolutePath(searchPath[i], ProjectPath); 121 | result.Add(path); 122 | end; 123 | 124 | except 125 | result.Free; 126 | end; 127 | finally 128 | searchPath.Free; 129 | end; 130 | end; 131 | 132 | function TCCECoreProject.ListAllPaths: TArray; 133 | begin 134 | result := FPaths.ToArray; 135 | end; 136 | 137 | function TCCECoreProject.ListAllUnits: TArray; 138 | begin 139 | result := FUnits.ToArray; 140 | end; 141 | 142 | function TCCECoreProject.ListAllUnits(Path: String): TArray; 143 | var 144 | i: Integer; 145 | unitPath: string; 146 | begin 147 | if not Path.EndsWith('\') then 148 | Path := Path + '\'; 149 | 150 | for i := 0 to Pred(FUnits.Count) do 151 | begin 152 | unitPath := ExtractFilePath(FUnits[i]).ToLower; 153 | if Path.ToLower = unitPath then 154 | begin 155 | SetLength(result, Length(result) + 1); 156 | result[Length(result) - 1] := FUnits[i]; 157 | end; 158 | end; 159 | end; 160 | 161 | function TCCECoreProject.MapFileName: string; 162 | begin 163 | result := ChangeFileExt(ExeName, '.map'); 164 | end; 165 | 166 | class function TCCECoreProject.New(Project: IOTAProject): ICCEProject; 167 | begin 168 | result := Self.create(Project); 169 | end; 170 | 171 | function TCCECoreProject.OutputPath: string; 172 | begin 173 | result := FActiveConfig.GetValue(sExeOutput); 174 | result := RelativeToAbsolutePath(Result, ProjectPath) 175 | .Replace('$(Platform)', FActiveConfig.Platform) 176 | .Replace('$(Config)', FActiveConfig.Name) + '\'; 177 | 178 | result := Result.Replace('\\', '\'); 179 | end; 180 | 181 | function TCCECoreProject.ProjectPath: string; 182 | begin 183 | result := ExtractFilePath(FProject.FileName); 184 | end; 185 | 186 | procedure TCCECoreProject.SetAllPaths; 187 | var 188 | i: Integer; 189 | searchPath: TList; 190 | path: string; 191 | begin 192 | for i := 0 to Pred(FProject.GetModuleCount) do 193 | begin 194 | if ExtractFileExt(FProject.GetModule(i).FileName) = '.pas' then 195 | begin 196 | path := ExtractFilePath(FProject.GetModule(i).FileName); 197 | AddPath(path); 198 | 199 | SetAllUnits(path); 200 | end; 201 | end; 202 | 203 | searchPath := Self.GetSearchPaths; 204 | try 205 | for i := 0 to Pred(searchPath.Count) do 206 | begin 207 | path := searchPath.Items[i]; 208 | AddPath(path); 209 | 210 | SetAllUnits(path); 211 | end; 212 | finally 213 | searchPath.Free; 214 | end; 215 | end; 216 | 217 | procedure TCCECoreProject.SetAllUnits(Path: String); 218 | var 219 | i: Integer; 220 | files: TStringDynArray; 221 | begin 222 | if not DirectoryExists(Path) then 223 | Exit; 224 | 225 | files := TDirectory.GetFiles(Path); 226 | 227 | for i := 0 to Pred(Length(files)) do 228 | begin 229 | if ExtractFileExt(files[i]) = '.pas' then 230 | AddUnit(files[i]); 231 | end; 232 | end; 233 | 234 | function TCCECoreProject.SetDetailedMapFile: ICCEProject; 235 | begin 236 | result := Self; 237 | FActiveConfig.SetValue('DCC_MapFile', '3'); 238 | FProject.Save(False, True); 239 | FProject.Refresh(True); 240 | end; 241 | 242 | end. 243 | -------------------------------------------------------------------------------- /Source/Src/Core/CCE.Core.Utils.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Core.Utils; 2 | 3 | interface 4 | 5 | uses 6 | CCE.dprocess, 7 | System.IOUtils, 8 | System.SysUtils, 9 | System.Types, 10 | Vcl.Forms, 11 | Winapi.ShellAPI, 12 | Winapi.Windows; 13 | 14 | function RelativeToAbsolutePath(const RelativePath, BasePath: string): string; 15 | function AbsolutePathToRelative(const AbsolutePath, BasePath: string): string; 16 | 17 | procedure ExecuteAndWait(const APath, ACommand: string); 18 | procedure OpenFolder(const AFolderName: String); 19 | procedure OpenFile(const AFileName: String); 20 | procedure OpenUrl(const Url: String); 21 | 22 | function PathCanonicalize(lpszDst: PChar; lpszSrc: PChar): LongBool; stdcall; 23 | external 'shlwapi.dll' name 'PathCanonicalizeW'; 24 | 25 | function PathRelativePathTo(pszPath: PChar; pszFrom: PChar; dwAttrFrom: DWORD; 26 | pszTo: PChar; dwAtrTo: DWORD): LongBool; stdcall; external 'shlwapi.dll' name 'PathRelativePathToW'; 27 | 28 | implementation 29 | 30 | function RelativeToAbsolutePath(const RelativePath, BasePath: string): string; 31 | var 32 | Dst: array[0..259] of char; 33 | begin 34 | result := RelativePath; 35 | if TPath.IsRelativePath(RelativePath) then 36 | begin 37 | PathCanonicalize(@Dst[0], PChar(IncludeTrailingBackslash(BasePath) + RelativePath)); 38 | if Dst <> '' then 39 | result := Dst; 40 | end; 41 | end; 42 | 43 | function AbsolutePathToRelative(const AbsolutePath, BasePath: string): string; 44 | var 45 | Path: array[0..259] of char; 46 | begin 47 | result := AbsolutePath; 48 | if not TPath.IsRelativePath(AbsolutePath) then 49 | begin 50 | PathRelativePathTo(@Path[0], PChar(BasePath), FILE_ATTRIBUTE_DIRECTORY, PChar(AbsolutePath), 0); 51 | if Path <> '' then 52 | result := Path; 53 | end; 54 | end; 55 | 56 | procedure ExecuteAndWait(const APath, ACommand: string); 57 | var 58 | output: AnsiString; 59 | begin 60 | RunCommandIndir(APath, 'cmd', ['/c', ACommand], output, [poNoConsole]); 61 | end; 62 | 63 | procedure OpenFolder(const AFolderName: String); 64 | begin 65 | ShellExecute(HInstance, 'open', PChar(AFolderName), '', '', SW_SHOWNORMAL); 66 | end; 67 | 68 | procedure OpenFile(const AFileName: String); 69 | begin 70 | if FileExists(AFileName) then 71 | ShellExecute(HInstance, 'open', PWideChar(AFileName), '', '', SW_SHOWNORMAL); 72 | end; 73 | 74 | procedure OpenUrl(const Url: String); 75 | begin 76 | ShellExecute(HInstance, 'open', PWideChar( Url ), '', '', SW_SHOWNORMAL); 77 | end; 78 | 79 | end. 80 | -------------------------------------------------------------------------------- /Source/Src/Core/CCE.Helpers.TreeView.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Helpers.TreeView; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, 7 | System.Classes, 8 | Vcl.ComCtrls, 9 | Vcl.Controls; 10 | 11 | const 12 | UNCHECKED_INDEX = 1; 13 | CHECKED_INDEX = 2; 14 | GRAYED_INDEX = 3; 15 | FOLDER_INDEX = 4; 16 | UNIT_INDEX = 5; 17 | 18 | type TCCEHelperTreeView = class helper for TTreeView 19 | 20 | public 21 | procedure AddPath(APath: String); 22 | function GetNodeParent(AParentCaption: String; AParentLevel: Integer): TTreeNode; 23 | function FindNode(ACaption: String; ALevel: Integer; ANodeParent: TTreeNode): TTreeNode; 24 | 25 | function SelectedPath: string; 26 | function CheckedNodes: TArray; 27 | 28 | procedure ExpandAll; 29 | end; 30 | 31 | implementation 32 | 33 | { TCCEHelperTreeView } 34 | 35 | 36 | function TCCEHelperTreeView.GetNodeParent(AParentCaption: String; AParentLevel: Integer): TTreeNode; 37 | var 38 | i: Integer; 39 | begin 40 | result := nil; 41 | for i := 0 to Pred(Items.Count) do 42 | begin 43 | if (Items[i].Level = AParentLevel) and 44 | (Items[i].Text.ToLower = AParentCaption.ToLower) 45 | then 46 | Exit( Items[i] ); 47 | end; 48 | end; 49 | 50 | function TCCEHelperTreeView.SelectedPath: string; 51 | var 52 | node: TTreeNode; 53 | parent: TTreeNode; 54 | begin 55 | node := Self.Selected; 56 | result := node.Text; 57 | parent := node.Parent; 58 | 59 | if parent = nil then 60 | begin 61 | Result := result + '\'; 62 | exit; 63 | end; 64 | 65 | repeat 66 | result := parent.Text + '\' + Result; 67 | parent := parent.Parent 68 | until (parent = nil); 69 | end; 70 | 71 | { TCCEHelperTreeView } 72 | 73 | procedure TCCEHelperTreeView.AddPath(APath: String); 74 | var 75 | i: Integer; 76 | list: TStringList; 77 | nodeParent: TTreeNode; 78 | node: TTreeNode; 79 | text: String; 80 | begin 81 | list := TStringList.Create; 82 | try 83 | list.Delimiter := '\'; 84 | list.StrictDelimiter := True; 85 | list.DelimitedText := APath; 86 | 87 | nodeParent := nil; 88 | for i := 0 to Pred(list.Count) do 89 | begin 90 | text := list[i]; 91 | node := FindNode(text, i, nodeParent); 92 | 93 | if Assigned(node) then 94 | Continue; 95 | 96 | if (i > 0) and (nodeParent = nil) then 97 | nodeParent := GetNodeParent(list[i - 1], i - 1); 98 | 99 | node := FindNode(text, i, nodeParent); 100 | if not Assigned(node) then 101 | nodeParent := Items.AddChild(nodeParent, text) 102 | end; 103 | 104 | finally 105 | list.Free; 106 | end; 107 | end; 108 | 109 | function TCCEHelperTreeView.CheckedNodes: TArray; 110 | var 111 | i: Integer; 112 | begin 113 | for i := 0 to Pred(Items.Count) do 114 | begin 115 | if Items[i].StateIndex = CHECKED_INDEX then 116 | begin 117 | SetLength(result, Length(result) + 1); 118 | Result[Length(result) - 1] := Items[i]; 119 | end; 120 | end; 121 | end; 122 | 123 | procedure TCCEHelperTreeView.ExpandAll; 124 | begin 125 | Self.FullExpand; 126 | end; 127 | 128 | function TCCEHelperTreeView.FindNode(ACaption: String; ALevel: Integer; ANodeParent: TTreeNode): TTreeNode; 129 | var 130 | i: Integer; 131 | childNode: TTreeNode; 132 | begin 133 | result := nil; 134 | if Assigned(ANodeParent) then 135 | begin 136 | childNode := ANodeParent.getFirstChild; 137 | 138 | while childNode <> nil do 139 | begin 140 | if childNode.Text.ToLower = ACaption.ToLower then 141 | Exit( childNode ); 142 | 143 | childNode := ANodeParent.GetNextChild(childNode); 144 | end; 145 | 146 | Exit; 147 | end; 148 | 149 | for i := 0 to Pred(Items.Count) do 150 | begin 151 | if (Items[i].Level = ALevel) and 152 | (Items[i].Text.ToLower = ACaption.ToLower) 153 | then 154 | begin 155 | if not Assigned(ANodeParent) then 156 | Exit(Items[i]) 157 | else 158 | if ANodeParent.Text.ToLower = Items[i].Parent.Text.ToLower then 159 | Exit(Items[i]); 160 | 161 | end; 162 | end; 163 | end; 164 | 165 | end. 166 | -------------------------------------------------------------------------------- /Source/Src/IDE/CCE.ContextMenu.pas: -------------------------------------------------------------------------------- 1 | unit CCE.ContextMenu; 2 | 3 | interface 4 | 5 | uses 6 | ToolsAPI, 7 | CCE.Constants, 8 | CCE.Core.Interfaces, 9 | CCE.Core.Project, 10 | CCE.Core.CodeCoverage, 11 | CCE.Wizard.Forms, 12 | System.Classes, 13 | System.SysUtils; 14 | 15 | type 16 | TCCEOnContextMenuClick = procedure (const MenuContextList: IInterfaceList) of object; 17 | 18 | TCCEContextMenuWizard = class(TNotifierObject, IOTAProjectMenuItemCreatorNotifier) 19 | private 20 | FProject: IOTAProject; 21 | 22 | procedure Initialize(Project: IOTAProject); 23 | 24 | procedure OnExecuteCodeCoverageWizard(const MenuContextList: IInterfaceList); 25 | procedure OnExecuteCodeCoverage(const MenuContextList: IInterfaceList); 26 | procedure OnExecuteHTMLReport(const MenuContextList: IInterfaceList); 27 | 28 | function AddMenu(Caption: String; 29 | Position: Integer; 30 | Parent: string = ''; 31 | OnExecute: TCCEOnContextMenuClick = nil; 32 | Checked: Boolean = False): IOTAProjectManagerMenu; overload; 33 | protected 34 | procedure AddMenu(const Project: IOTAProject; 35 | const IdentList: TStrings; 36 | const MenuList: IInterfaceList; 37 | IsMultiSelect: Boolean); overload; 38 | 39 | public 40 | class function New: IOTAProjectMenuItemCreatorNotifier; 41 | end; 42 | 43 | TCCEContextMenu = class(TNotifierObject, IOTALocalMenu, IOTAProjectManagerMenu) 44 | private 45 | FCaption: String; 46 | FIsMultiSelectable: Boolean; 47 | FChecked: Boolean; 48 | FEnabled: Boolean; 49 | FHelpContext: Integer; 50 | FName: string; 51 | FParent: string; 52 | FPosition: Integer; 53 | FVerb: string; 54 | 55 | protected 56 | FProject: IOTAProject; 57 | FOnExecute: TCCEOnContextMenuClick; 58 | 59 | function GetCaption: string; 60 | function GetChecked: Boolean; 61 | function GetEnabled: Boolean; 62 | function GetHelpContext: Integer; 63 | function GetName: string; 64 | function GetParent: string; 65 | function GetPosition: Integer; 66 | function GetVerb: string; 67 | procedure SetCaption(const Value: string); 68 | procedure SetChecked(Value: Boolean); 69 | procedure SetEnabled(Value: Boolean); 70 | procedure SetHelpContext(Value: Integer); 71 | procedure SetName(const Value: string); 72 | procedure SetParent(const Value: string); 73 | procedure SetPosition(Value: Integer); 74 | procedure SetVerb(const Value: string); 75 | function GetIsMultiSelectable: Boolean; 76 | procedure SetIsMultiSelectable(Value: Boolean); 77 | procedure Execute(const MenuContextList: IInterfaceList); virtual; 78 | function PreExecute(const MenuContextList: IInterfaceList): Boolean; 79 | function PostExecute(const MenuContextList: IInterfaceList): Boolean; 80 | 81 | constructor create(OnExecute: TCCEOnContextMenuClick); overload; 82 | class function New(OnExecute: TCCEOnContextMenuClick): IOTAProjectManagerMenu; overload; 83 | end; 84 | 85 | var 86 | IndexContextMenuCoverage: Integer = -1; 87 | 88 | procedure RegisterContextMenu; 89 | 90 | implementation 91 | 92 | procedure RegisterContextMenu; 93 | begin 94 | IndexContextMenuCoverage := (BorlandIDEServices as IOTAProjectManager) 95 | .AddMenuItemCreatorNotifier(TCCEContextMenuWizard.New); 96 | end; 97 | 98 | { TCCEContextMenu } 99 | 100 | constructor TCCEContextMenu.create(OnExecute: TCCEOnContextMenuClick); 101 | begin 102 | FOnExecute := OnExecute; 103 | FEnabled := True; 104 | FChecked := False; 105 | FIsMultiSelectable := False; 106 | end; 107 | 108 | procedure TCCEContextMenu.Execute(const MenuContextList: IInterfaceList); 109 | begin 110 | if Assigned(FOnExecute) then 111 | FOnExecute(MenuContextList); 112 | end; 113 | 114 | function TCCEContextMenu.GetCaption: string; 115 | begin 116 | result := FCaption; 117 | end; 118 | 119 | function TCCEContextMenu.GetChecked: Boolean; 120 | begin 121 | result := FChecked; 122 | end; 123 | 124 | function TCCEContextMenu.GetEnabled: Boolean; 125 | begin 126 | result := FEnabled; 127 | end; 128 | 129 | function TCCEContextMenu.GetHelpContext: Integer; 130 | begin 131 | result := FHelpContext; 132 | end; 133 | 134 | function TCCEContextMenu.GetIsMultiSelectable: Boolean; 135 | begin 136 | Result := FIsMultiSelectable; 137 | end; 138 | 139 | function TCCEContextMenu.GetName: string; 140 | begin 141 | result := FName; 142 | end; 143 | 144 | function TCCEContextMenu.GetParent: string; 145 | begin 146 | result := FParent; 147 | end; 148 | 149 | function TCCEContextMenu.GetPosition: Integer; 150 | begin 151 | result := FPosition; 152 | end; 153 | 154 | function TCCEContextMenu.GetVerb: string; 155 | begin 156 | result := FVerb; 157 | end; 158 | 159 | class function TCCEContextMenu.New(OnExecute: TCCEOnContextMenuClick): IOTAProjectManagerMenu; 160 | begin 161 | result := Self.create(OnExecute); 162 | end; 163 | 164 | function TCCEContextMenu.PostExecute(const MenuContextList: IInterfaceList): Boolean; 165 | begin 166 | result := True; 167 | end; 168 | 169 | function TCCEContextMenu.PreExecute(const MenuContextList: IInterfaceList): Boolean; 170 | begin 171 | result := True; 172 | end; 173 | 174 | procedure TCCEContextMenu.SetCaption(const Value: string); 175 | begin 176 | FCaption := Value; 177 | end; 178 | 179 | procedure TCCEContextMenu.SetChecked(Value: Boolean); 180 | begin 181 | FChecked := Value; 182 | end; 183 | 184 | procedure TCCEContextMenu.SetEnabled(Value: Boolean); 185 | begin 186 | FEnabled := Value; 187 | end; 188 | 189 | procedure TCCEContextMenu.SetHelpContext(Value: Integer); 190 | begin 191 | FHelpContext := Value; 192 | end; 193 | 194 | procedure TCCEContextMenu.SetIsMultiSelectable(Value: Boolean); 195 | begin 196 | FIsMultiSelectable := Value; 197 | end; 198 | 199 | procedure TCCEContextMenu.SetName(const Value: string); 200 | begin 201 | FName := Value; 202 | end; 203 | 204 | procedure TCCEContextMenu.SetParent(const Value: string); 205 | begin 206 | FParent := Value; 207 | end; 208 | 209 | procedure TCCEContextMenu.SetPosition(Value: Integer); 210 | begin 211 | FPosition := Value; 212 | end; 213 | 214 | procedure TCCEContextMenu.SetVerb(const Value: string); 215 | begin 216 | FVerb := Value; 217 | end; 218 | 219 | { TCCEContextMenuWizard } 220 | 221 | procedure TCCEContextMenuWizard.AddMenu(const Project: IOTAProject; 222 | const IdentList: TStrings; const MenuList: IInterfaceList; 223 | IsMultiSelect: Boolean); 224 | begin 225 | if (IdentList.IndexOf(sProjectContainer) < 0) or 226 | (not Assigned(MenuList)) 227 | then 228 | Exit; 229 | 230 | Initialize(Project); 231 | 232 | MenuList.Add(AddMenu(CCE_COVERAGE_CAPTION, CCE_COVERAGE_POSITION)); 233 | MenuList.Add(AddMenu(CCE_COVERAGE_WIZARD_CAPTION, CCE_COVERAGE_WIZARD_POSITION, CCE_COVERAGE_CAPTION, OnExecuteCodeCoverageWizard)); 234 | MenuList.Add(AddMenu(CCE_COVERAGE_EXECUTE_CAPTION, CCE_COVERAGE_EXECUTE_POSITION, CCE_COVERAGE_CAPTION, OnExecuteCodeCoverage)); 235 | MenuList.Add(AddMenu(CCE_COVERAGE_HTML_CAPTION, CCE_COVERAGE_HTML_POSITION, CCE_COVERAGE_CAPTION, OnExecuteHTMLReport)); 236 | end; 237 | 238 | function TCCEContextMenuWizard.AddMenu(Caption: String; Position: Integer; 239 | Parent: string; OnExecute: TCCEOnContextMenuClick; 240 | Checked: Boolean): IOTAProjectManagerMenu; 241 | begin 242 | result := TCCEContextMenu.New(OnExecute); 243 | Result.Caption := Caption; 244 | result.Verb := Caption; 245 | Result.Parent := Parent; 246 | result.Position := Position; 247 | result.Checked := Checked; 248 | result.IsMultiSelectable := False; 249 | end; 250 | 251 | procedure TCCEContextMenuWizard.Initialize(Project: IOTAProject); 252 | begin 253 | FProject := Project; 254 | end; 255 | 256 | class function TCCEContextMenuWizard.New: IOTAProjectMenuItemCreatorNotifier; 257 | begin 258 | result := Self.Create; 259 | end; 260 | 261 | procedure TCCEContextMenuWizard.OnExecuteCodeCoverage(const MenuContextList: IInterfaceList); 262 | var 263 | LCCe: ICCECodeCoverage; 264 | LProject: ICCEProject; 265 | begin 266 | LProject := TCCECoreProject.New(FProject); 267 | LCCe := TCCECoreCodeCoverage.New; 268 | LCCe 269 | .ExeFileName(LProject.ExeName) 270 | .Execute; 271 | end; 272 | 273 | procedure TCCEContextMenuWizard.OnExecuteCodeCoverageWizard(const MenuContextList: IInterfaceList); 274 | begin 275 | if not Assigned(CCEWizardForms) then 276 | CCEWizardForms := TCCEWizardForms.Create(nil); 277 | 278 | CCEWizardForms 279 | .Project(FProject) 280 | .Show; 281 | end; 282 | 283 | procedure TCCEContextMenuWizard.OnExecuteHTMLReport(const MenuContextList: IInterfaceList); 284 | var 285 | LCCe: ICCECodeCoverage; 286 | LProject: ICCEProject; 287 | LPathReport: String; 288 | begin 289 | LProject := TCCECoreProject.New(FProject); 290 | LPathReport := ExtractFilePath(LProject.ExeName) + 'report'; 291 | LCCe := TCCECoreCodeCoverage.New; 292 | LCCe 293 | .ExeFileName(LProject.ExeName) 294 | .OutputReport(LPathReport) 295 | .ShowHTMLReport; 296 | end; 297 | 298 | initialization 299 | 300 | finalization 301 | if IndexContextMenuCoverage >= 0 then 302 | (BorlandIDEServices as IOTAProjectManager) 303 | .RemoveMenuItemCreatorNotifier(IndexContextMenuCoverage); 304 | 305 | end. 306 | -------------------------------------------------------------------------------- /Source/Src/IDE/CCE.Wizard.Forms.pas: -------------------------------------------------------------------------------- 1 | unit CCE.Wizard.Forms; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, 8 | ToolsAPI, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ExtDlgs, 9 | System.IOUtils, 10 | Vcl.FileCtrl, 11 | CCE.Core.Interfaces, 12 | CCE.Core.Project, 13 | CCE.Core.CodeCoverage, 14 | CCE.Core.Utils, 15 | CCE.Helpers.TreeView, 16 | System.Generics.Collections, Vcl.CheckLst, Vcl.Menus, Vcl.Buttons, 17 | System.ImageList, Vcl.ImgList, Vcl.Imaging.pngimage, Vcl.Mask; 18 | 19 | const 20 | COLOR_PRIMARY = $00FB7E15; 21 | COLOR_DISABLED = $00aba6a0; 22 | 23 | type 24 | TCCEWizardForms = class(TForm) 25 | pgcWizard: TPageControl; 26 | tsFiles: TTabSheet; 27 | pnlBottom: TPanel; 28 | openTextDialog: TOpenTextFileDialog; 29 | tsTreeView: TTabSheet; 30 | tvPaths: TTreeView; 31 | iltreeView: TImageList; 32 | Panel1: TPanel; 33 | imgSetDetailed: TImage; 34 | imgXml: TImage; 35 | imgTxt: TImage; 36 | imgHtml: TImage; 37 | imgBuild: TImage; 38 | imgRun: TImage; 39 | imgSave: TImage; 40 | imgFolder: TImage; 41 | pnlContentFiles: TPanel; 42 | pnlBody: TPanel; 43 | edtCoverageExeName: TLabeledEdit; 44 | edtExeName: TLabeledEdit; 45 | edtMapFileName: TLabeledEdit; 46 | edtOutputReport: TLabeledEdit; 47 | grpOutputFormat: TGroupBox; 48 | chkXmlReport: TCheckBox; 49 | chkHtmlReport: TCheckBox; 50 | chkEmmaReport: TCheckBox; 51 | chkLog: TCheckBox; 52 | chkUseRelativePath: TCheckBox; 53 | pnlTitle: TPanel; 54 | lblTitleSettings: TLabel; 55 | btnNext: TPanel; 56 | btnPrevious: TPanel; 57 | btnClose: TPanel; 58 | imgGithub: TImage; 59 | btnSelectCodeCoverage2: TImage; 60 | btnSelectExeName: TImage; 61 | btnSelectMapFile: TImage; 62 | btnOutputReport: TImage; 63 | tsIgnoredFiles: TTabSheet; 64 | Panel2: TPanel; 65 | Panel3: TPanel; 66 | Panel4: TPanel; 67 | Label1: TLabel; 68 | lstIgnoreUnits: TListBox; 69 | edtIgnoreUnit: TLabeledEdit; 70 | pnlAddIgnoreUnit: TPanel; 71 | imgAddIgnoreUnit: TImage; 72 | pmIgnoreUnits: TPopupMenu; 73 | Delete1: TMenuItem; 74 | procedure tvPathsDblClick(Sender: TObject); 75 | procedure imgRunClick(Sender: TObject); 76 | procedure imgSaveClick(Sender: TObject); 77 | procedure imgSetDetailedClick(Sender: TObject); 78 | procedure imgBuildClick(Sender: TObject); 79 | procedure imgHtmlClick(Sender: TObject); 80 | procedure imgXmlClick(Sender: TObject); 81 | procedure imgTxtClick(Sender: TObject); 82 | procedure imgFolderClick(Sender: TObject); 83 | procedure btnPreviousClick(Sender: TObject); 84 | procedure btnNextClick(Sender: TObject); 85 | procedure btnCloseClick(Sender: TObject); 86 | procedure btnSelectCodeCoverage2Click(Sender: TObject); 87 | procedure btnSelectExeNameClick(Sender: TObject); 88 | procedure btnSelectMapFileClick(Sender: TObject); 89 | procedure btnOutputReportClick(Sender: TObject); 90 | procedure imgGithubClick(Sender: TObject); 91 | procedure Delete1Click(Sender: TObject); 92 | procedure imgAddIgnoreUnitClick(Sender: TObject); 93 | private 94 | FProject: ICCEProject; 95 | FCoverage: ICCECodeCoverage; 96 | FTreeNodes: TDictionary; 97 | 98 | function GetNode(APath: String): TTreeNode; 99 | procedure AddPathInTreeView(APath: String); 100 | function GetKeyNode(ANode: TTreeNode): String; 101 | 102 | procedure SetCoverage(ASetUnits: Boolean = True); 103 | procedure SetCoverageUnits; 104 | 105 | procedure SetStateTreeView; 106 | procedure SetStateChilds(ANode: TTreeNode; AStateIndex: Integer); 107 | procedure SetStateParents(ANode: TTreeNode); 108 | procedure SetSelectedUnits; 109 | procedure SetIgnoreUnits; 110 | 111 | procedure searchFile(FilterText, FilterExt: string; AComponent: TCustomEdit); 112 | procedure selectFolder(AComponent: TCustomEdit); 113 | 114 | procedure ListPaths; 115 | procedure ListUnits(Path: String); 116 | 117 | procedure InitialValues; 118 | procedure HideTabs; 119 | procedure SelectPageNext; 120 | procedure SelectPagePrevious; 121 | procedure SetColorButtons; 122 | public 123 | function Project(Value: IOTAProject): TCCEWizardForms; 124 | 125 | constructor Create(AOwner: TComponent); override; 126 | destructor Destroy; override; 127 | { Public declarations } 128 | end; 129 | 130 | var 131 | CCEWizardForms: TCCEWizardForms; 132 | 133 | implementation 134 | 135 | {$R *.dfm} 136 | 137 | { TCCEWizardForms } 138 | 139 | procedure TCCEWizardForms.AddPathInTreeView(APath: String); 140 | var 141 | i: Integer; 142 | nodeParent: TTreeNode; 143 | node: TTreeNode; 144 | text: String; 145 | pathParent: String; 146 | path: String; 147 | splittedPath: TArray; 148 | 149 | procedure SetImageIndex(ANode: TTreeNode; APath: String); 150 | var 151 | index: Integer; 152 | begin 153 | ANode.StateIndex := CHECKED_INDEX; 154 | index := FOLDER_INDEX; 155 | if APath.EndsWith('\') then 156 | APath := Copy(APath, 1, APath.Length - 1); 157 | if FileExists(APath) then 158 | index := UNIT_INDEX; 159 | 160 | ANode.ImageIndex := index; 161 | ANode.SelectedIndex := index; 162 | end; 163 | begin 164 | splittedPath := APath.Split(['\']); 165 | 166 | pathParent := ''; 167 | for i := 0 to Pred(Length(splittedPath)) do 168 | begin 169 | text := splittedPath[i]; 170 | if text = '' then 171 | Continue; 172 | path := path + text + '\'; 173 | node := GetNode(path); 174 | if Assigned(node) then 175 | Continue; 176 | 177 | if i = 0 then 178 | begin 179 | nodeParent := tvPaths.Items.AddChild(nil, text); 180 | SetImageIndex(nodeParent, path); 181 | FTreeNodes.Add(path, nodeParent); 182 | Continue; 183 | end; 184 | 185 | pathParent := Copy(path, 1, path.length - text.Length - 1); 186 | nodeParent := GetNode(pathParent); 187 | if Assigned(nodeParent) then 188 | begin 189 | nodeParent := tvPaths.Items.AddChild(nodeParent, text); 190 | SetImageIndex(nodeParent, path); 191 | FTreeNodes.Add(path, nodeParent); 192 | Continue; 193 | end; 194 | end; 195 | end; 196 | 197 | procedure TCCEWizardForms.btnSelectCodeCoverage2Click(Sender: TObject); 198 | begin 199 | searchFile('Code Coverage File', 'exe', edtCoverageExeName); 200 | end; 201 | 202 | procedure TCCEWizardForms.btnSelectExeNameClick(Sender: TObject); 203 | begin 204 | searchFile('Delphi Test Project', 'exe', edtExeName); 205 | end; 206 | 207 | procedure TCCEWizardForms.btnSelectMapFileClick(Sender: TObject); 208 | begin 209 | searchFile('Map File', 'map', edtMapFileName); 210 | end; 211 | 212 | procedure TCCEWizardForms.SetSelectedUnits; 213 | var 214 | i: Integer; 215 | LIndex: Integer; 216 | LText: String; 217 | 218 | function GetFullName(ANode: TTreeNode): String; 219 | var 220 | LParent: TTreeNode; 221 | begin 222 | result := ANode.Text; 223 | LParent := ANode.Parent; 224 | while LParent <> nil do 225 | begin 226 | result := LParent.Text + '\' + result; 227 | LParent := LParent.Parent; 228 | end; 229 | end; 230 | begin 231 | tvPaths.Items.BeginUpdate; 232 | try 233 | for i := 0 to Pred(tvPaths.Items.Count) do 234 | begin 235 | LText := GetFullName(tvPaths.Items[i]); 236 | if FileExists(LText) then 237 | begin 238 | LIndex := UNCHECKED_INDEX; 239 | if FCoverage.IsInCovUnits(LText) then 240 | LIndex := CHECKED_INDEX; 241 | 242 | tvPaths.Items[i].StateIndex := LIndex; 243 | SetStateParents(tvPaths.Items[i]); 244 | end; 245 | end; 246 | finally 247 | tvPaths.Items.EndUpdate; 248 | end; 249 | end; 250 | 251 | procedure TCCEWizardForms.SetStateChilds(ANode: TTreeNode; AStateIndex: Integer); 252 | var 253 | childNode: TTreeNode; 254 | begin 255 | childNode := ANode.getFirstChild; 256 | 257 | while childNode <> nil do 258 | begin 259 | childNode.StateIndex := AStateIndex; 260 | SetStateChilds(childNode, AStateIndex); 261 | 262 | childNode := ANode.GetNextChild(childNode); 263 | end; 264 | end; 265 | 266 | procedure TCCEWizardForms.SetStateParents(ANode: TTreeNode); 267 | var 268 | nodeParent: TTreeNode; 269 | hasCheck: Boolean; 270 | hasUnCheck: Boolean; 271 | hasGrayed: Boolean; 272 | childNode: TTreeNode; 273 | index: Integer; 274 | begin 275 | nodeParent := ANode.Parent; 276 | if not Assigned(nodeParent) then 277 | Exit; 278 | 279 | hasCheck := False; 280 | hasUnCheck := False; 281 | hasGrayed := False; 282 | 283 | childNode := nodeParent.getFirstChild; 284 | while childNode <> nil do 285 | begin 286 | index := childNode.StateIndex; 287 | hasCheck := (hasCheck) or (index = CHECKED_INDEX); 288 | hasUnCheck := (hasUnCheck) or (index = UNCHECKED_INDEX); 289 | hasGrayed := (hasGrayed) or (index = GRAYED_INDEX); 290 | 291 | childNode := nodeParent.GetNextChild(childNode); 292 | end; 293 | 294 | index := UNCHECKED_INDEX; 295 | if (hasCheck and hasUnCheck) or (hasGrayed) then 296 | index := GRAYED_INDEX 297 | else 298 | if hasCheck then 299 | index := CHECKED_INDEX; 300 | 301 | nodeParent.StateIndex := index; 302 | SetStateParents(nodeParent); 303 | end; 304 | 305 | procedure TCCEWizardForms.SetStateTreeView; 306 | var 307 | stateIndex: Integer; 308 | nodeSelected: TTreeNode; 309 | begin 310 | nodeSelected := tvPaths.Selected; 311 | nodeSelected.Expanded := not nodeSelected.Expanded; 312 | 313 | stateIndex := UNCHECKED_INDEX; 314 | if nodeSelected.StateIndex = UNCHECKED_INDEX then 315 | stateIndex := CHECKED_INDEX; 316 | 317 | nodeSelected.StateIndex := stateIndex; 318 | 319 | SetStateChilds(nodeSelected, stateIndex); 320 | SetStateParents(nodeSelected); 321 | end; 322 | 323 | constructor TCCEWizardForms.create(AOwner: TComponent); 324 | begin 325 | inherited; 326 | FTreeNodes := TDictionary.create; 327 | end; 328 | 329 | procedure TCCEWizardForms.Delete1Click(Sender: TObject); 330 | begin 331 | lstIgnoreUnits.DeleteSelected; 332 | end; 333 | 334 | destructor TCCEWizardForms.Destroy; 335 | begin 336 | FTreeNodes.Free; 337 | inherited; 338 | end; 339 | 340 | function TCCEWizardForms.GetKeyNode(ANode: TTreeNode): String; 341 | var 342 | nodeParent: TTreeNode; 343 | begin 344 | result := ANode.Text; 345 | nodeParent := ANode.Parent; 346 | while nodeParent <> nil do 347 | begin 348 | result := nodeParent.Text + '\' + Result; 349 | nodeParent := nodeParent.Parent; 350 | end; 351 | 352 | if result.EndsWith('\') then 353 | result := Copy(Result, 1, result.Length - 1); 354 | end; 355 | 356 | function TCCEWizardForms.GetNode(APath: String): TTreeNode; 357 | begin 358 | result := nil; 359 | if FTreeNodes.ContainsKey(APath) then 360 | result := FTreeNodes.Items[APath]; 361 | end; 362 | 363 | procedure TCCEWizardForms.HideTabs; 364 | var 365 | i: Integer; 366 | begin 367 | pgcWizard.ActivePage := tsFiles; 368 | 369 | for i := 0 to Pred(pgcWizard.PageCount) do 370 | pgcWizard.Pages[i].TabVisible := False; 371 | 372 | SelectPageNext; 373 | end; 374 | 375 | procedure TCCEWizardForms.imgAddIgnoreUnitClick(Sender: TObject); 376 | var 377 | LText: string; 378 | begin 379 | LText := edtIgnoreUnit.Text; 380 | if lstIgnoreUnits.Items.IndexOf(LText) < 0 then 381 | lstIgnoreUnits.Items.Add(LText); 382 | end; 383 | 384 | procedure TCCEWizardForms.imgBuildClick(Sender: TObject); 385 | begin 386 | FProject.Build; 387 | end; 388 | 389 | procedure TCCEWizardForms.imgFolderClick(Sender: TObject); 390 | begin 391 | SetCoverage; 392 | OpenFolder(FCoverage.BasePath); 393 | end; 394 | 395 | procedure TCCEWizardForms.imgGithubClick(Sender: TObject); 396 | begin 397 | OpenUrl('https://github.com/gabrielbaltazar/code-coverage-experts'); 398 | end; 399 | 400 | procedure TCCEWizardForms.imgHtmlClick(Sender: TObject); 401 | begin 402 | SetCoverage; 403 | FCoverage.ShowHTMLReport; 404 | end; 405 | 406 | procedure TCCEWizardForms.imgRunClick(Sender: TObject); 407 | begin 408 | SetCoverage; 409 | FCoverage 410 | .Save 411 | .Execute; 412 | end; 413 | 414 | procedure TCCEWizardForms.imgSaveClick(Sender: TObject); 415 | begin 416 | SetCoverage; 417 | FCoverage.Save; 418 | ShowMessage('OK'); 419 | end; 420 | 421 | procedure TCCEWizardForms.imgSetDetailedClick(Sender: TObject); 422 | begin 423 | FProject.SetDetailedMapFile; 424 | ShowMessage('OK'); 425 | end; 426 | 427 | procedure TCCEWizardForms.imgTxtClick(Sender: TObject); 428 | begin 429 | SetCoverage; 430 | FCoverage.ShowLogCoverage; 431 | end; 432 | 433 | procedure TCCEWizardForms.imgXmlClick(Sender: TObject); 434 | begin 435 | SetCoverage; 436 | FCoverage.ShowXMLReport; 437 | end; 438 | 439 | procedure TCCEWizardForms.InitialValues; 440 | begin 441 | edtExeName.Text := FProject.ExeName; 442 | edtMapFileName.Text := FProject.MapFileName; 443 | edtOutputReport.Text := ExtractFilePath(FProject.ExeName) + 'report'; 444 | end; 445 | 446 | procedure TCCEWizardForms.ListPaths; 447 | var 448 | paths: TArray; 449 | i: Integer; 450 | begin 451 | paths := FProject.ListAllPaths; 452 | 453 | for i := 0 to Pred(Length(paths)) do 454 | if TDirectory.Exists(paths[i]) then 455 | begin 456 | ListUnits(Paths[i]); 457 | end; 458 | end; 459 | 460 | procedure TCCEWizardForms.ListUnits(Path: String); 461 | var 462 | units: TArray; 463 | i: Integer; 464 | begin 465 | units := FProject.ListAllUnits(Path); 466 | for i := 0 to Pred(Length( units )) do 467 | AddPathInTreeView(units[i]); 468 | end; 469 | 470 | function TCCEWizardForms.Project(Value: IOTAProject): TCCEWizardForms; 471 | begin 472 | result := Self; 473 | 474 | // if (not Assigned(FProject)) or (FProject.DprFileName <> Value.FileName) then 475 | begin 476 | FTreeNodes.Clear; 477 | tvPaths.Items.Clear; 478 | 479 | FProject := TCCECoreProject.New(Value); 480 | FCoverage := TCCECoreCodeCoverage.New; 481 | 482 | ListPaths; 483 | tvPaths.FullCollapse; 484 | 485 | HideTabs; 486 | InitialValues; 487 | SetCoverage(False); 488 | SetSelectedUnits; 489 | SetIgnoreUnits; 490 | end; 491 | end; 492 | 493 | procedure TCCEWizardForms.btnCloseClick(Sender: TObject); 494 | begin 495 | Close; 496 | end; 497 | 498 | procedure TCCEWizardForms.btnNextClick(Sender: TObject); 499 | begin 500 | SelectPageNext; 501 | end; 502 | 503 | procedure TCCEWizardForms.btnOutputReportClick(Sender: TObject); 504 | begin 505 | selectFolder(edtOutputReport); 506 | end; 507 | 508 | procedure TCCEWizardForms.btnPreviousClick(Sender: TObject); 509 | begin 510 | SelectPagePrevious; 511 | end; 512 | 513 | procedure TCCEWizardForms.SetCoverageUnits; 514 | var 515 | nodeSelect: TArray; 516 | i: Integer; 517 | unitFile: string; 518 | begin 519 | FCoverage.Clear; 520 | nodeSelect := tvPaths.CheckedNodes; 521 | 522 | for i := 0 to Pred(lstIgnoreUnits.Count) do 523 | FCoverage.AddUnitIgnore(lstIgnoreUnits.Items[i]); 524 | 525 | for i := 0 to Pred(Length(nodeSelect)) do 526 | begin 527 | unitFile := GetKeyNode(nodeSelect[i]); 528 | if FileExists(unitFile) then 529 | begin 530 | FCoverage 531 | .AddUnit(unitFile) 532 | .AddPath(ExtractFilePath(unitFile)); 533 | end; 534 | end; 535 | 536 | end; 537 | 538 | procedure TCCEWizardForms.SetIgnoreUnits; 539 | var 540 | LIgnore: TArray; 541 | begin 542 | LIgnore := FCoverage.IgnoredUnits; 543 | lstIgnoreUnits.Clear; 544 | lstIgnoreUnits.Items.AddStrings(LIgnore); 545 | end; 546 | 547 | procedure TCCEWizardForms.searchFile(FilterText, FilterExt: string; AComponent: TCustomEdit); 548 | begin 549 | openTextDialog.Filter := Format('%s | *.%s', [FilterText, FilterExt]); 550 | if openTextDialog.Execute then 551 | AComponent.Text := openTextDialog.FileName; 552 | end; 553 | 554 | procedure TCCEWizardForms.selectFolder(AComponent: TCustomEdit); 555 | var 556 | path: string; 557 | begin 558 | path := FProject.ProjectPath; 559 | if SelectDirectory('Select Directory', '', path) then 560 | AComponent.Text := path; 561 | end; 562 | 563 | procedure TCCEWizardForms.SelectPageNext; 564 | begin 565 | pgcWizard.SelectNextPage(True, False); 566 | btnNext.Enabled := pgcWizard.ActivePageIndex < (pgcWizard.PageCount - 1); 567 | btnPrevious.Enabled := pgcWizard.ActivePageIndex > 0; // (pgcWizard.PageCount - 1); 568 | 569 | setColorButtons; 570 | end; 571 | 572 | procedure TCCEWizardForms.SelectPagePrevious; 573 | begin 574 | pgcWizard.SelectNextPage(False, False); 575 | btnPrevious.Enabled := pgcWizard.ActivePageIndex > 0; 576 | btnNext.Enabled := True; 577 | 578 | setColorButtons; 579 | end; 580 | 581 | procedure TCCEWizardForms.SetColorButtons; 582 | begin 583 | btnNext.Color := COLOR_PRIMARY; 584 | btnPrevious.Color := COLOR_PRIMARY; 585 | 586 | if not btnNext.Enabled then 587 | btnNext.Color := COLOR_DISABLED; 588 | 589 | if not btnPrevious.Enabled then 590 | btnPrevious.Color := COLOR_DISABLED; 591 | end; 592 | 593 | procedure TCCEWizardForms.SetCoverage(ASetUnits: Boolean = True); 594 | begin 595 | if ASetUnits then 596 | SetCoverageUnits; 597 | 598 | FCoverage 599 | .CodeCoverageFileName(edtCoverageExeName.Text) 600 | .ExeFileName(edtExeName.Text) 601 | .MapFileName(edtMapFileName.Text) 602 | .OutputReport(edtOutputReport.Text) 603 | .GenerateHtml(chkHtmlReport.Checked) 604 | .GenerateXml(chkXmlReport.Checked) 605 | .GenerateEmma(chkEmmaReport.Checked) 606 | .GenerateLog(chkLog.Checked) 607 | .UseRelativePath(chkUseRelativePath.Checked); 608 | end; 609 | 610 | procedure TCCEWizardForms.tvPathsDblClick(Sender: TObject); 611 | begin 612 | tvPaths.Items.BeginUpdate; 613 | try 614 | SetStateTreeView; 615 | finally 616 | tvPaths.Items.EndUpdate; 617 | end; 618 | end; 619 | 620 | initialization 621 | 622 | finalization 623 | CCEWizardForms.Free; 624 | 625 | end. 626 | -------------------------------------------------------------------------------- /Source/Src/Third/CCE.dpipes.pas: -------------------------------------------------------------------------------- 1 | { Freepascal pipes unit converted to Delphi. 2 | 3 | License: FPC Modified LGPL (okay to use in commercial projects) 4 | 5 | Changes to the code marked with "L505" in comments } 6 | 7 | { 8 | This file is part of the Free Pascal run time library. 9 | Copyright (c) 1999-2000 by Michael Van Canneyt 10 | 11 | Implementation of pipe stream. 12 | 13 | See the file COPYING.FPC, included in this distribution, 14 | for details about the copyright. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 19 | 20 | **********************************************************************} 21 | 22 | 23 | unit CCE.dpipes; 24 | 25 | interface 26 | 27 | uses 28 | system.types, // L505 29 | sysutils, Classes; 30 | 31 | type 32 | EPipeError = Class(EStreamError); 33 | EPipeSeek = Class(EPipeError); 34 | EPipeCreation = Class(EPipeError); 35 | 36 | { TInputPipeStream } 37 | 38 | TInputPipeStream = Class(THandleStream) 39 | Private 40 | FPos : Int64; 41 | function GetNumBytesAvailable: DWord; 42 | procedure WriteNotImplemented; // L505 43 | procedure FakeSeekForward(Offset: Int64; const Origin: TSeekOrigin; 44 | const Pos: Int64); // L505 45 | procedure DiscardLarge(Count: int64; const MaxBufferSize: Longint); // L505 46 | procedure Discard(const Count: Int64); // L505 47 | 48 | protected 49 | function GetPosition: Int64; // override; //L505 50 | procedure InvalidSeek; // override; //L505 51 | public 52 | destructor Destroy; override; 53 | Function Write (Const Buffer; Count : Longint) :Longint; Override; 54 | function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override; 55 | Function Read (Var Buffer; Count : Longint) : longint; Override; 56 | property NumBytesAvailable: DWord read GetNumBytesAvailable; 57 | end; 58 | 59 | TOutputPipeStream = Class(THandleStream) 60 | Private 61 | procedure ReadNotImplemented; // L505 62 | procedure InvalidSeek; // L505 63 | Public 64 | destructor Destroy; override; 65 | function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override; 66 | Function Read(Var Buffer; Count : Longint) : longint; Override; 67 | end; 68 | 69 | Function CreatePipeHandles (Var Inhandle,OutHandle : THandle; APipeBufferSize : Cardinal = 1024) : Boolean; 70 | Procedure CreatePipeStreams (Var InPipe : TInputPipeStream; 71 | Var OutPipe : TOutputPipeStream); 72 | 73 | Const EPipeMsg = 'Failed to create pipe.'; 74 | ENoSeekMsg = 'Cannot seek on pipes'; 75 | 76 | 77 | Implementation 78 | 79 | {$IFDEF MACOS} // L505 80 | {$i CCE.pipes_macos.inc} 81 | {$ENDIF} 82 | 83 | {$IFDEF MSWINDOWS} // L505 84 | {$i CCE.pipes_win.inc} 85 | {$ENDIF} 86 | 87 | 88 | Procedure CreatePipeStreams (Var InPipe : TInputPipeStream; 89 | Var OutPipe : TOutputPipeStream); 90 | Var InHandle,OutHandle: THandle; 91 | begin 92 | if CreatePipeHandles(InHandle, OutHandle) then 93 | begin 94 | InPipe:=TInputPipeStream.Create(InHandle); 95 | OutPipe:=TOutputPipeStream.Create(OutHandle); 96 | end 97 | Else 98 | Raise EPipeCreation.Create(EPipeMsg) 99 | end; 100 | 101 | destructor TInputPipeStream.Destroy; 102 | begin 103 | PipeClose(Handle); 104 | inherited; 105 | end; 106 | 107 | // L505 108 | procedure TInputPipeStream.DiscardLarge(Count: int64; const MaxBufferSize: Longint); 109 | var 110 | Buffer: array of Byte; 111 | begin 112 | if Count=0 then 113 | Exit; 114 | if Count>MaxBufferSize then 115 | SetLength(Buffer,MaxBufferSize) 116 | else 117 | SetLength(Buffer,Count); 118 | while (Count>=Length(Buffer)) do 119 | begin 120 | ReadBuffer(Buffer[0],Length(Buffer)); 121 | Dec(Count,Length(Buffer)); 122 | end; 123 | if Count>0 then 124 | ReadBuffer(Buffer[0],Count); 125 | end; 126 | 127 | // L505 128 | procedure TInputPipeStream.Discard(const Count: Int64); 129 | const 130 | CSmallSize =255; 131 | CLargeMaxBuffer =32*1024; // 32 KiB 132 | var 133 | Buffer: array[1..CSmallSize] of Byte; 134 | begin 135 | if Count=0 then 136 | Exit; 137 | if Count<=SizeOf(Buffer) then 138 | ReadBuffer(Buffer,Count) 139 | else 140 | DiscardLarge(Count,CLargeMaxBuffer); 141 | end; 142 | 143 | // L505 144 | procedure TInputPipeStream.FakeSeekForward(Offset: Int64; const Origin: TSeekOrigin; const Pos: Int64); 145 | //var 146 | // Buffer: Pointer; 147 | // BufferSize, i: LongInt; 148 | begin 149 | if Origin=soBeginning then 150 | Dec(Offset,Pos); 151 | if (Offset<0) or (Origin=soEnd) then 152 | InvalidSeek; 153 | if Offset>0 then 154 | Discard(Offset); 155 | end; 156 | 157 | // L505 158 | procedure TInputPipeStream.WriteNotImplemented; 159 | begin 160 | raise EStreamError.CreateFmt('Cannot write to this stream, not implemented', []); 161 | end; 162 | 163 | // L505 164 | procedure TOutputPipeStream.ReadNotImplemented; 165 | begin 166 | raise EStreamError.CreateFmt('Cannot read from this stream, not implemented', []); 167 | end; 168 | 169 | Function TInputPipeStream.Write(Const Buffer; Count : Longint) : longint; 170 | begin 171 | WriteNotImplemented; 172 | Result := 0; 173 | end; 174 | 175 | Function TInputPipeStream.Read(Var Buffer; Count : Longint) : longint; 176 | begin 177 | Result:=Inherited Read(Buffer,Count); 178 | Inc(FPos,Result); 179 | end; 180 | 181 | function TInputPipeStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; 182 | begin 183 | FakeSeekForward(Offset,Origin,FPos); 184 | Result:=FPos; 185 | end; 186 | 187 | destructor TOutputPipeStream.Destroy; 188 | begin 189 | PipeClose(Handle); 190 | inherited; 191 | end; 192 | 193 | Function TOutputPipeStream.Read(Var Buffer; Count : Longint) : longint; 194 | begin 195 | ReadNotImplemented; 196 | Result := 0; 197 | end; 198 | 199 | procedure TOutputPipeStream.InvalidSeek; 200 | begin 201 | raise EStreamError.CreateFmt('Invalid seek in TProcess', []); 202 | end; 203 | 204 | function TOutputPipeStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; 205 | begin 206 | Result:=0; { to silence warning mostly } 207 | InvalidSeek; 208 | end; 209 | 210 | end. 211 | 212 | -------------------------------------------------------------------------------- /Source/Src/Third/CCE.dprocess.pas: -------------------------------------------------------------------------------- 1 | { Freepascal TProcess ported to Delphi 2 | 3 | License: FPC Modified LGPL (can use in commercial apps) 4 | 5 | Changes to the code marked with "L505" in comments } 6 | 7 | { 8 | This file is part of the Free Component Library (FCL) 9 | Copyright (c) 1999-2000 by the Free Pascal development team 10 | 11 | See the file COPYING.FPC, included in this distribution, 12 | for details about the copyright. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17 | 18 | **********************************************************************} 19 | 20 | unit CCE.dprocess; 21 | 22 | interface 23 | 24 | uses 25 | classes, 26 | CCE.dpipes, // L505 27 | system.types,//L505 28 | sysutils; 29 | 30 | 31 | Type 32 | TProcessOption = (poRunSuspended,poWaitOnExit, 33 | poUsePipes,poStderrToOutPut, 34 | poNoConsole,poNewConsole, 35 | poDefaultErrorMode,poNewProcessGroup, 36 | poDebugProcess,poDebugOnlyThisProcess); 37 | 38 | TShowWindowOptions = (swoNone,swoHIDE,swoMaximize,swoMinimize,swoRestore,swoShow, 39 | swoShowDefault,swoShowMaximized,swoShowMinimized, 40 | swoshowMinNOActive,swoShowNA,swoShowNoActivate,swoShowNormal); 41 | 42 | TStartupOption = (suoUseShowWindow,suoUseSize,suoUsePosition, 43 | suoUseCountChars,suoUseFillAttribute); 44 | 45 | TProcessPriority = (ppHigh,ppIdle,ppNormal,ppRealTime); 46 | 47 | TProcessOptions = set of TProcessOption; 48 | TStartupOptions = set of TStartupOption; 49 | 50 | 51 | Type 52 | {$ifdef MACOS} //L505 53 | TProcessForkEvent = procedure(Sender : TObject) of object; 54 | {$endif} 55 | 56 | { TProcess } 57 | 58 | TProcess = Class (TComponent) 59 | Private 60 | FProcessOptions : TProcessOptions; 61 | FStartupOptions : TStartupOptions; 62 | FProcessID : Integer; 63 | FThreadID : Integer; 64 | FProcessHandle : Thandle; 65 | FThreadHandle : Thandle; 66 | FFillAttribute : Cardinal; 67 | FApplicationName : string; 68 | FConsoleTitle : String; 69 | FCommandLine : String; 70 | FCurrentDirectory : String; 71 | FDesktop : String; 72 | FEnvironment : Tstrings; 73 | FExecutable : String; 74 | FParameters : TStrings; 75 | FShowWindow : TShowWindowOptions; 76 | FInherithandles : Boolean; 77 | {$ifdef MACOS} // L505 78 | FForkEvent : TProcessForkEvent; 79 | {$endif} 80 | FProcessPriority : TProcessPriority; 81 | dwXCountchars, 82 | dwXSize, 83 | dwYsize, 84 | dwx, 85 | dwYcountChars, 86 | dwy : Cardinal; 87 | FXTermProgram: String; 88 | FPipeBufferSize : cardinal; 89 | Procedure FreeStreams; 90 | Function GetExitStatus : Integer; 91 | Function GetExitCode : Integer; 92 | Function GetRunning : Boolean; 93 | Function GetWindowRect : TRect; 94 | procedure SetCommandLine(const AValue: String); 95 | procedure SetParameters(const AValue: TStrings); 96 | Procedure SetWindowRect (Value : TRect); 97 | Procedure SetShowWindow (Value : TShowWindowOptions); 98 | Procedure SetWindowColumns (Value : Cardinal); 99 | Procedure SetWindowHeight (Value : Cardinal); 100 | Procedure SetWindowLeft (Value : Cardinal); 101 | Procedure SetWindowRows (Value : Cardinal); 102 | Procedure SetWindowTop (Value : Cardinal); 103 | Procedure SetWindowWidth (Value : Cardinal); 104 | procedure SetApplicationName(const Value: String); 105 | procedure SetProcessOptions(const Value: TProcessOptions); 106 | procedure SetActive(const Value: Boolean); 107 | procedure SetEnvironment(const Value: TStrings); 108 | Procedure ConvertCommandLine; 109 | function PeekExitStatus: Boolean; 110 | Protected 111 | FRunning : Boolean; 112 | FExitCode : Cardinal; 113 | FInputStream : TOutputPipeStream; 114 | FOutputStream : TInputPipeStream; 115 | FStderrStream : TInputPipeStream; 116 | procedure CloseProcessHandles; virtual; 117 | Procedure CreateStreams(InHandle,OutHandle,ErrHandle : Longint);virtual; 118 | procedure FreeStream(var AStream: THandleStream); 119 | procedure Loaded; override; 120 | Public 121 | Constructor Create (AOwner : TComponent);override; 122 | Destructor Destroy; override; 123 | Procedure Execute; virtual; 124 | procedure CloseInput; virtual; 125 | procedure CloseOutput; virtual; 126 | procedure CloseStderr; virtual; 127 | Function Resume : Integer; virtual; 128 | Function Suspend : Integer; virtual; 129 | Function Terminate (AExitCode : Integer): Boolean; virtual; 130 | Function WaitOnExit : Boolean; 131 | Property WindowRect : Trect Read GetWindowRect Write SetWindowRect; 132 | Property Handle : THandle Read FProcessHandle; 133 | Property ProcessHandle : THandle Read FProcessHandle; 134 | Property ThreadHandle : THandle Read FThreadHandle; 135 | Property ProcessID : Integer Read FProcessID; 136 | Property ThreadID : Integer Read FThreadID; 137 | Property Input : TOutputPipeStream Read FInputStream; 138 | Property Output : TInputPipeStream Read FOutputStream; 139 | Property Stderr : TinputPipeStream Read FStderrStream; 140 | Property ExitStatus : Integer Read GetExitStatus; 141 | Property ExitCode : Integer Read GetExitCode; 142 | Property InheritHandles : Boolean Read FInheritHandles Write FInheritHandles; 143 | {$ifdef MACOS} // L505 144 | property OnForkEvent : TProcessForkEvent Read FForkEvent Write FForkEvent; 145 | {$endif} 146 | Published 147 | property PipeBufferSize : cardinal read FPipeBufferSize write FPipeBufferSize default 1024; 148 | Property Active : Boolean Read GetRunning Write SetActive; 149 | Property ApplicationName : String Read FApplicationName Write SetApplicationName; //deprecated; //L505 150 | Property CommandLine : String Read FCommandLine Write SetCommandLine ; //deprecated; //L505 151 | Property Executable : String Read FExecutable Write FExecutable; 152 | Property Parameters : TStrings Read FParameters Write SetParameters; 153 | Property ConsoleTitle : String Read FConsoleTitle Write FConsoleTitle; 154 | Property CurrentDirectory : String Read FCurrentDirectory Write FCurrentDirectory; 155 | Property Desktop : String Read FDesktop Write FDesktop; 156 | Property Environment : TStrings Read FEnvironment Write SetEnvironment; 157 | Property Options : TProcessOptions Read FProcessOptions Write SetProcessOptions; 158 | Property Priority : TProcessPriority Read FProcessPriority Write FProcessPriority; 159 | Property StartupOptions : TStartupOptions Read FStartupOptions Write FStartupOptions; 160 | Property Running : Boolean Read GetRunning; 161 | Property ShowWindow : TShowWindowOptions Read FShowWindow Write SetShowWindow; 162 | Property WindowColumns : Cardinal Read dwXCountChars Write SetWindowColumns; 163 | Property WindowHeight : Cardinal Read dwYSize Write SetWindowHeight; 164 | Property WindowLeft : Cardinal Read dwX Write SetWindowLeft; 165 | Property WindowRows : Cardinal Read dwYCountChars Write SetWindowRows; 166 | Property WindowTop : Cardinal Read dwY Write SetWindowTop ; 167 | Property WindowWidth : Cardinal Read dwXSize Write SetWindowWidth; 168 | Property FillAttribute : Cardinal read FFillAttribute Write FFillAttribute; 169 | Property XTermProgram : String Read FXTermProgram Write FXTermProgram; 170 | end; 171 | 172 | EProcess = Class(Exception); 173 | 174 | Procedure CommandToList(S : String; List : TStrings); 175 | 176 | {$ifdef MACOS} //L505 177 | Var 178 | TryTerminals : Array of string; 179 | XTermProgram : String; 180 | Function DetectXTerm : String; 181 | {$endif} 182 | 183 | { // L505: changed to ansistring 184 | function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;out outputstring:string; out exitstatus:integer; Options : TProcessOptions = []):integer; overload; //L505 185 | function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;out outputstring:string; Options : TProcessOptions = []):boolean; overload; // L505 186 | function RunCommand(const exename:string;const commands:array of string;out outputstring:string; Options : TProcessOptions = []):boolean; overload;// L505 187 | 188 | 189 | function RunCommandInDir(const curdir,cmdline:string;out outputstring:string):boolean; deprecated; overload; // L505 190 | function RunCommand(const cmdline:string;out outputstring:string):boolean; deprecated; overload; // L505 191 | } 192 | 193 | function RunCommandIndir(const curdir: string; const exename: string; const commands: array of string; out outputstring: ansistring; out exitstatus:integer; Options : TProcessOptions = []):integer; overload; //L505 194 | function RunCommandIndir(const curdir: string; const exename: string; const commands: array of string; out outputstring: ansistring; Options : TProcessOptions = []):boolean; overload; // L505 195 | function RunCommand(const exename: string; const commands: array of string; out outputstring: ansistring; Options : TProcessOptions = []):boolean; overload;// L505 196 | 197 | 198 | function RunCommandInDir(const curdir,cmdline:string;out outputstring:ansistring):boolean; deprecated; overload; // L505 199 | function RunCommand(const cmdline:string;out outputstring:ansistring):boolean; deprecated; overload; // L505 200 | 201 | 202 | implementation 203 | 204 | {$IFDEF MACOS} //L505 205 | {$i CCE.process_macos.inc} 206 | {$ENDIF} 207 | 208 | {$IFDEF MSWINDOWS} //L505 209 | {$i CCE.process_win.inc} 210 | {$ENDIF} 211 | 212 | Procedure CommandToList(S : String; List : TStrings); 213 | 214 | Function GetNextWord : String; 215 | 216 | Const 217 | WhiteSpace = [' ',#9,#10,#13]; 218 | Literals = ['"','''']; 219 | 220 | Var 221 | Wstart,wend : Integer; 222 | InLiteral : Boolean; 223 | LastLiteral : char; 224 | 225 | begin 226 | WStart:=1; 227 | // L505 change "in" to CharInSet 228 | While (WStart<=Length(S)) and (CharInSet(S[WStart], WhiteSpace)) do 229 | Inc(WStart); 230 | WEnd:=WStart; 231 | InLiteral:=False; 232 | LastLiteral:=#0; 233 | // L505 234 | // While (Wend<=Length(S)) and (Not (S[Wend] in WhiteSpace) or InLiteral) do 235 | While (Wend<=Length(S)) and (Not (CharInSet(S[Wend], WhiteSpace)) or InLiteral) do 236 | begin 237 | // L505 changed "in" to CharInSet 238 | if CharInSet(S[Wend], Literals) then 239 | If InLiteral then 240 | InLiteral:=Not (S[Wend]=LastLiteral) 241 | else 242 | begin 243 | InLiteral:=True; 244 | LastLiteral:=S[Wend]; 245 | end; 246 | inc(wend); 247 | end; 248 | 249 | Result:=Copy(S,WStart,WEnd-WStart); 250 | // L505 changed "in" to CharInSet 251 | if (Length(Result) > 0) 252 | and (Result[1] = Result[Length(Result)]) // if 1st char = last char and.. 253 | and (CharInSet(Result[1], Literals)) then // it's one of the literals, then 254 | Result:=Copy(Result, 2, Length(Result) - 2); //delete the 2 (but not others in it) 255 | // L505 256 | // While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do 257 | While (WEnd<=Length(S)) and (CharInSet(S[Wend], WhiteSpace)) do 258 | inc(Wend); 259 | Delete(S,1,WEnd-1); 260 | 261 | end; 262 | 263 | Var 264 | W : String; 265 | 266 | begin 267 | While Length(S)>0 do 268 | begin 269 | W:=GetNextWord; 270 | If (W<>'') then 271 | List.Add(W); 272 | end; 273 | end; 274 | 275 | Constructor TProcess.Create (AOwner : TComponent); 276 | begin 277 | Inherited; 278 | FProcessPriority:=ppNormal; 279 | FShowWindow:=swoNone; 280 | FInheritHandles:=True; 281 | {$ifdef MACOS} // L505 282 | FForkEvent:=nil; 283 | {$endif} 284 | FPipeBufferSize := 1024; 285 | FEnvironment:=TStringList.Create; 286 | FParameters:=TStringList.Create; 287 | end; 288 | 289 | Destructor TProcess.Destroy; 290 | begin 291 | FParameters.Free; 292 | FEnvironment.Free; 293 | FreeStreams; 294 | CloseProcessHandles; 295 | Inherited Destroy; 296 | end; 297 | 298 | Procedure TProcess.FreeStreams; 299 | begin 300 | If FStderrStream<>FOutputStream then 301 | FreeStream(THandleStream(FStderrStream)); 302 | FreeStream(THandleStream(FOutputStream)); 303 | FreeStream(THandleStream(FInputStream)); 304 | end; 305 | 306 | Function TProcess.GetExitStatus : Integer; 307 | begin 308 | GetRunning; 309 | Result:=FExitCode; 310 | end; 311 | 312 | {$IFNDEF OS_HASEXITCODE} 313 | Function TProcess.GetExitCode : Integer; 314 | begin 315 | if Not Running then 316 | Result:=GetExitStatus 317 | else 318 | Result:=0 319 | end; 320 | {$ENDIF} 321 | 322 | Function TProcess.GetRunning : Boolean; 323 | begin 324 | IF FRunning then 325 | FRunning:=Not PeekExitStatus; 326 | Result:=FRunning; 327 | end; 328 | 329 | Procedure TProcess.CreateStreams(InHandle,OutHandle,ErrHandle : Longint); 330 | 331 | begin 332 | FreeStreams; 333 | FInputStream:=TOutputPipeStream.Create (InHandle); 334 | FOutputStream:=TInputPipeStream.Create (OutHandle); 335 | if Not (poStderrToOutput in FProcessOptions) then 336 | FStderrStream:=TInputPipeStream.Create(ErrHandle); 337 | end; 338 | 339 | procedure TProcess.FreeStream(var AStream: THandleStream); 340 | begin 341 | if AStream = nil then exit; 342 | FreeAndNil(AStream); 343 | end; 344 | 345 | procedure TProcess.Loaded; 346 | begin 347 | inherited Loaded; 348 | If (csDesigning in ComponentState) and (FCommandLine<>'') then 349 | ConvertCommandLine; 350 | end; 351 | 352 | procedure TProcess.CloseInput; 353 | begin 354 | FreeStream(THandleStream(FInputStream)); 355 | end; 356 | 357 | procedure TProcess.CloseOutput; 358 | begin 359 | FreeStream(THandleStream(FOutputStream)); 360 | end; 361 | 362 | procedure TProcess.CloseStderr; 363 | begin 364 | FreeStream(THandleStream(FStderrStream)); 365 | end; 366 | 367 | Procedure TProcess.SetWindowColumns (Value : Cardinal); 368 | begin 369 | if Value<>0 then 370 | Include(FStartupOptions,suoUseCountChars); 371 | dwXCountChars:=Value; 372 | end; 373 | 374 | 375 | Procedure TProcess.SetWindowHeight (Value : Cardinal); 376 | begin 377 | if Value<>0 then 378 | include(FStartupOptions,suoUsePosition); 379 | dwYSize:=Value; 380 | end; 381 | 382 | Procedure TProcess.SetWindowLeft (Value : Cardinal); 383 | begin 384 | if Value<>0 then 385 | Include(FStartupOptions,suoUseSize); 386 | dwx:=Value; 387 | end; 388 | 389 | Procedure TProcess.SetWindowTop (Value : Cardinal); 390 | begin 391 | if Value<>0 then 392 | Include(FStartupOptions,suoUsePosition); 393 | dwy:=Value; 394 | end; 395 | 396 | Procedure TProcess.SetWindowWidth (Value : Cardinal); 397 | begin 398 | If (Value<>0) then 399 | Include(FStartupOptions,suoUseSize); 400 | dwXSize:=Value; 401 | end; 402 | 403 | Function TProcess.GetWindowRect : TRect; 404 | begin 405 | With Result do 406 | begin 407 | Left:=dwx; 408 | Right:=dwx+dwxSize; 409 | Top:=dwy; 410 | Bottom:=dwy+dwysize; 411 | end; 412 | end; 413 | 414 | procedure TProcess.SetCommandLine(const AValue: String); 415 | begin 416 | if FCommandLine=AValue then exit; 417 | FCommandLine:=AValue; 418 | If Not (csLoading in ComponentState) then 419 | ConvertCommandLine; 420 | end; 421 | 422 | procedure TProcess.SetParameters(const AValue: TStrings); 423 | begin 424 | FParameters.Assign(AValue); 425 | end; 426 | 427 | Procedure TProcess.SetWindowRect (Value : Trect); 428 | begin 429 | Include(FStartupOptions,suoUseSize); 430 | Include(FStartupOptions,suoUsePosition); 431 | With Value do 432 | begin 433 | dwx:=Left; 434 | dwxSize:=Right-Left; 435 | dwy:=Top; 436 | dwySize:=Bottom-top; 437 | end; 438 | end; 439 | 440 | Procedure TProcess.SetWindowRows (Value : Cardinal); 441 | begin 442 | if Value<>0 then 443 | Include(FStartupOptions,suoUseCountChars); 444 | dwYCountChars:=Value; 445 | end; 446 | 447 | procedure TProcess.SetApplicationName(const Value: String); 448 | begin 449 | FApplicationName := Value; 450 | If (csDesigning in ComponentState) and 451 | (FCommandLine='') then 452 | FCommandLine:=Value; 453 | end; 454 | 455 | procedure TProcess.SetProcessOptions(const Value: TProcessOptions); 456 | begin 457 | FProcessOptions := Value; 458 | If poNewConsole in FProcessOptions then 459 | Exclude(FProcessOptions,poNoConsole); 460 | if poRunSuspended in FProcessOptions then 461 | Exclude(FProcessOptions,poWaitOnExit); 462 | end; 463 | 464 | procedure TProcess.SetActive(const Value: Boolean); 465 | begin 466 | if (Value<>GetRunning) then 467 | If Value then 468 | Execute 469 | else 470 | Terminate(0); 471 | end; 472 | 473 | procedure TProcess.SetEnvironment(const Value: TStrings); 474 | begin 475 | FEnvironment.Assign(Value); 476 | end; 477 | 478 | procedure TProcess.ConvertCommandLine; 479 | begin 480 | FParameters.Clear; 481 | CommandToList(FCommandLine,FParameters); 482 | If FParameters.Count>0 then 483 | begin 484 | Executable:=FParameters[0]; 485 | FParameters.Delete(0); 486 | end; 487 | end; 488 | 489 | Const 490 | READ_BYTES = 65536; // not too small to avoid fragmentation when reading large files. 491 | 492 | // helperfunction that does the bulk of the work. 493 | // We need to also collect stderr output in order to avoid 494 | // lock out if the stderr pipe is full. 495 | // L505: changed to ansistring 496 | // function internalRuncommand(p:TProcess;out outputstring: string; 497 | // out stderrstring: string; out exitstatus:integer):integer; 498 | function internalRuncommand(p:TProcess;out outputstring: ansistring; 499 | out stderrstring: ansistring; out exitstatus:integer):integer; 500 | var 501 | numbytes,bytesread,available : integer; 502 | outputlength, stderrlength : integer; 503 | stderrnumbytes,stderrbytesread : integer; 504 | begin 505 | bytesread:=0; 506 | outputlength:=0; 507 | stderrbytesread:=0; 508 | stderrlength:=0; 509 | 510 | try 511 | try 512 | p.Options := p.Options + [poUsePipes]; 513 | p.Execute; 514 | 515 | while p.Running do 516 | begin 517 | // Only call ReadFromStream if Data from corresponding stream 518 | // is already available, otherwise, on linux, the read call 519 | // is blocking, and thus it is not possible to be sure to handle 520 | // big data amounts bboth on output and stderr pipes. PM. 521 | available:=P.Output.NumBytesAvailable; 522 | // writeln('DEBUG: bytesavail: ', P.Output.NumBytesAvailable); 523 | if available > 0 then 524 | begin 525 | if (BytesRead + available > outputlength) then 526 | begin 527 | outputlength:=BytesRead + READ_BYTES; 528 | Setlength(outputstring,outputlength); 529 | end; 530 | NumBytes := p.Output.Read(outputstring[1+bytesread], available); 531 | // L505 if in the future above string is unicodestring, above may need work NOTE: pchar is zero based . http://docwiki.embarcadero.com/RADStudio/Seattle/en/Using_Streams_to_Read_or_Write_Data 532 | // NumBytes := p.Output.Read(pchar(outputstring)[bytesread], available); 533 | 534 | if NumBytes > 0 then 535 | Inc(BytesRead, NumBytes); 536 | end 537 | // The check for assigned(P.stderr) is mainly here so that 538 | // if we use poStderrToOutput in p.Options, we do not access invalid memory. 539 | else if assigned(P.stderr) and (P.StdErr.NumBytesAvailable > 0) then 540 | begin 541 | available:=P.StdErr.NumBytesAvailable; 542 | if (StderrBytesRead + available > stderrlength) then 543 | begin 544 | stderrlength:=StderrBytesRead + READ_BYTES; 545 | Setlength(stderrstring,stderrlength); 546 | end; 547 | StderrNumBytes := p.StdErr.Read(stderrstring[1+StderrBytesRead], available); 548 | // L505 in the future if the above is a unicodestring this may need work, and NOTE: pchar is zero based 549 | // StderrNumBytes := p.StdErr.Read(pchar(stderrstring)[StderrBytesRead], available); 550 | 551 | if StderrNumBytes > 0 then 552 | Inc(StderrBytesRead, StderrNumBytes); 553 | end 554 | else 555 | Sleep(100); 556 | end; 557 | // Get left output after end of execution 558 | available:=P.Output.NumBytesAvailable; 559 | while available > 0 do 560 | begin 561 | if (BytesRead + available > outputlength) then 562 | begin 563 | outputlength:=BytesRead + READ_BYTES; 564 | Setlength(outputstring,outputlength); 565 | end; 566 | NumBytes := p.Output.Read(outputstring[1+bytesread], available); 567 | // L505 if above is unicodestring in the future it may need work, and NOTE: pchar is zero based 568 | // NumBytes := p.Output.Read(pchar(outputstring)[bytesread], available); 569 | 570 | if NumBytes > 0 then 571 | Inc(BytesRead, NumBytes); 572 | available:=P.Output.NumBytesAvailable; 573 | end; 574 | setlength(outputstring,BytesRead); 575 | while assigned(P.stderr) and (P.Stderr.NumBytesAvailable > 0) do 576 | begin 577 | available:=P.Stderr.NumBytesAvailable; 578 | if (StderrBytesRead + available > stderrlength) then 579 | begin 580 | stderrlength:=StderrBytesRead + READ_BYTES; 581 | Setlength(stderrstring,stderrlength); 582 | end; 583 | StderrNumBytes := p.StdErr.Read(stderrstring[1+StderrBytesRead], available); 584 | // L505 if above is unicodestring in the future, it may need work and NOTE: pchar is zero based 585 | // StderrNumBytes := p.StdErr.Read(pchar(stderrstring)[StderrBytesRead], available); 586 | 587 | if StderrNumBytes > 0 then 588 | Inc(StderrBytesRead, StderrNumBytes); 589 | end; 590 | setlength(stderrstring,StderrBytesRead); 591 | exitstatus:=p.exitstatus; 592 | result:=0; // we came to here, document that. 593 | except 594 | on e : Exception do 595 | begin 596 | result:=1; 597 | setlength(outputstring,BytesRead); 598 | end; 599 | end; 600 | finally 601 | p.free; 602 | end; 603 | end; 604 | 605 | { Functions without StderrString } 606 | 607 | Const 608 | ForbiddenOptions = [poRunSuspended,poWaitOnExit]; 609 | 610 | // L505 changed to ansistring 611 | // function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;out outputstring:string;out exitstatus:integer; Options : TProcessOptions = []):integer; 612 | function RunCommandIndir(const curdir: string; const exename: string; const commands:array of string; out outputstring: ansistring;out exitstatus:integer; Options : TProcessOptions = []):integer; 613 | Var 614 | p : TProcess; 615 | i : integer; 616 | // ErrorString : String; // L505 617 | ErrorString: ansistring; 618 | begin 619 | p:=TProcess.create(nil); 620 | if Options<>[] then 621 | P.Options:=Options - ForbiddenOptions; 622 | p.Executable:=exename; 623 | if curdir<>'' then 624 | p.CurrentDirectory:=curdir; 625 | if high(commands)>=0 then 626 | for i:=low(commands) to high(commands) do 627 | p.Parameters.add(commands[i]); 628 | result:=internalruncommand(p,outputstring,errorstring,exitstatus); 629 | end; 630 | 631 | // L505 changed to ansistring 632 | // function RunCommandInDir(const curdir,cmdline:string;out outputstring:string):boolean; deprecated; 633 | function RunCommandInDir(const curdir,cmdline:string;out outputstring: ansistring):boolean; deprecated; 634 | Var 635 | p : TProcess; 636 | exitstatus : integer; 637 | // ErrorString : String; // L505 638 | ErrorString: ansistring; // L505 639 | begin 640 | p:=TProcess.create(nil); 641 | p.setcommandline(cmdline); 642 | if curdir<>'' then 643 | p.CurrentDirectory:=curdir; 644 | result:=internalruncommand(p,outputstring,errorstring,exitstatus)=0; 645 | if exitstatus<>0 then result:=false; 646 | end; 647 | 648 | // L505 changed to ansistring 649 | // function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;out outputstring:string; Options : TProcessOptions = []):boolean; 650 | function RunCommandIndir(const curdir: string; const exename: string; const commands:array of string; out outputstring: ansistring; Options : TProcessOptions = []):boolean; 651 | Var 652 | p : TProcess; 653 | i, 654 | exitstatus : integer; 655 | // ErrorString : String; // L505 656 | ErrorString: ansistring; // L505 657 | begin 658 | p:=TProcess.create(nil); 659 | if Options<>[] then 660 | P.Options:=Options - ForbiddenOptions; 661 | p.Executable:=exename; 662 | if curdir<>'' then 663 | p.CurrentDirectory:=curdir; 664 | if high(commands)>=0 then 665 | for i:=low(commands) to high(commands) do 666 | p.Parameters.add(commands[i]); 667 | result:=internalruncommand(p,outputstring,errorstring,exitstatus)=0; 668 | if exitstatus<>0 then result:=false; 669 | end; 670 | 671 | // L505 changed to ansistring 672 | // function RunCommand(const cmdline:string; out outputstring:string):boolean; deprecated; 673 | function RunCommand(const cmdline: string; out outputstring: ansistring):boolean; deprecated; 674 | Var 675 | p : TProcess; 676 | exitstatus : integer; 677 | // ErrorString : String; // L505 678 | ErrorString: ansistring; // L505 679 | begin 680 | p:=TProcess.create(nil); 681 | p.setcommandline(cmdline); 682 | result:=internalruncommand(p,outputstring,errorstring,exitstatus)=0; 683 | if exitstatus<>0 then result:=false; 684 | end; 685 | 686 | // L505: Changed to ansistring 687 | // function RunCommand(const exename:string;const commands:array of string;out outputstring:string; Options : TProcessOptions = []):boolean; 688 | function RunCommand(const exename:string; const commands:array of string; out outputstring: ansistring; Options : TProcessOptions = []):boolean; 689 | Var 690 | p : TProcess; 691 | i, 692 | exitstatus : integer; 693 | // ErrorString : String; // L505 694 | ErrorString: ansistring; // L505 695 | begin 696 | p:=TProcess.create(nil); 697 | if Options<>[] then 698 | P.Options:=Options - ForbiddenOptions; 699 | p.Executable:=exename; 700 | if high(commands)>=0 then 701 | for i:=low(commands) to high(commands) do 702 | p.Parameters.add(commands[i]); 703 | result:=internalruncommand(p,outputstring,errorstring,exitstatus)=0; 704 | if exitstatus<>0 then result:=false; 705 | end; 706 | 707 | end. 708 | 709 | -------------------------------------------------------------------------------- /Source/Src/Third/CCE.pipes_win.inc: -------------------------------------------------------------------------------- 1 | { Freepascal pipes unit converted to Delphi (needed for TProcess) 2 | 3 | License: FPC Modified LGPL (okay to use in commercial projects) 4 | 5 | Changes to the code marked with "L505" in comments } 6 | 7 | { 8 | This file is part of the Free Pascal run time library. 9 | Copyright (c) 1998 by Michael Van Canneyt 10 | 11 | Win part of pipe stream. 12 | 13 | See the file COPYING.FPC, included in this distribution, 14 | for details about the copyright. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 19 | 20 | **********************************************************************} 21 | uses 22 | windows; //L505 23 | 24 | // L505 25 | type 26 | PSecurityAttributes = ^TSecurityAttributes; 27 | TSecurityAttributes = record 28 | nLength : DWORD; 29 | lpSecurityDescriptor : Pointer; 30 | bInheritHandle : BOOL; 31 | end; 32 | 33 | Const piInheritablePipe : TSecurityAttributes = ( 34 | nlength:SizeOF(TSecurityAttributes); 35 | lpSecurityDescriptor:Nil; 36 | Binherithandle:True); 37 | piNonInheritablePipe : TSecurityAttributes = ( 38 | nlength:SizeOF(TSecurityAttributes); 39 | lpSecurityDescriptor:Nil; 40 | Binherithandle:False); 41 | 42 | 43 | PipeBufSize = 1024; 44 | 45 | 46 | Function CreatePipeHandles (Var Inhandle,OutHandle : THandle; APipeBufferSize : Cardinal = PipeBufSize) : Boolean; 47 | begin 48 | // L505 49 | // Result := CreatePipe(@Inhandle,@OutHandle,@piNonInheritablePipe,APipeBufferSize); 50 | Result := CreatePipe(Inhandle,OutHandle,@piNonInheritablePipe,APipeBufferSize); 51 | //writeln('DEBUG: createpipe result: ', result); 52 | end; 53 | 54 | Function TInputPipeStream.GetNumBytesAvailable: DWord; 55 | begin 56 | if not PeekNamedPipe(Handle, nil, 0, nil, @Result, nil) then 57 | Result := 0; 58 | end; 59 | 60 | function TInputPipeStream.GetPosition: Int64; 61 | begin 62 | Result:=FPos; 63 | end; 64 | 65 | procedure TInputPipeStream.InvalidSeek; 66 | begin 67 | Raise EPipeSeek.Create(ENoSeekMsg); 68 | end; 69 | 70 | procedure PipeClose(const FHandle: THandle); inline; 71 | begin 72 | FileClose(FHandle); 73 | end; -------------------------------------------------------------------------------- /Source/Src/Third/CCE.process_win.inc: -------------------------------------------------------------------------------- 1 | { Freepascal TProcess ported to Delphi 2 | 3 | License: FPC Modified LGPL (can use in commercial apps) 4 | 5 | Changes to the code marked with "L505" in comments } 6 | 7 | { 8 | This file is part of the Free Component Library (FCL) 9 | Copyright (c) 1999-2008 by the Free Pascal development team 10 | 11 | See the file COPYING.FPC, included in this distribution, 12 | for details about the copyright. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17 | 18 | **********************************************************************} 19 | 20 | Uses 21 | Windows; 22 | 23 | 24 | Resourcestring 25 | SNoCommandLine = 'Cannot execute empty command-line'; 26 | SErrCannotExecute = 'Failed to execute %s : %d'; 27 | { SErrNoSuchProgram = 'Executable not found: "%s"'; 28 | SErrNoTerminalProgram = 'Could not detect X-Terminal program'; 29 | } 30 | 31 | Const 32 | PriorityConstants : Array [TProcessPriority] of Cardinal = 33 | (HIGH_PRIORITY_CLASS,IDLE_PRIORITY_CLASS, 34 | NORMAL_PRIORITY_CLASS,REALTIME_PRIORITY_CLASS); 35 | 36 | procedure TProcess.CloseProcessHandles; 37 | begin 38 | if (FProcessHandle<>0) then 39 | CloseHandle(FProcessHandle); 40 | if (FThreadHandle<>0) then 41 | CloseHandle(FThreadHandle); 42 | end; 43 | 44 | Function TProcess.PeekExitStatus : Boolean; 45 | 46 | begin 47 | GetExitCodeProcess(ProcessHandle,FExitCode); 48 | Result:=(FExitCode<>Still_Active); 49 | end; 50 | 51 | Function GetStartupFlags (P : TProcess): Cardinal; 52 | 53 | begin 54 | With P do 55 | begin 56 | Result:=0; 57 | if poUsePipes in FProcessOptions then 58 | Result:=Result or Startf_UseStdHandles; 59 | if suoUseShowWindow in FStartupOptions then 60 | Result:=Result or startf_USESHOWWINDOW; 61 | if suoUSESIZE in FStartupOptions then 62 | Result:=Result or startf_usesize; 63 | if suoUsePosition in FStartupOptions then 64 | Result:=Result or startf_USEPOSITION; 65 | if suoUSECOUNTCHARS in FStartupoptions then 66 | Result:=Result or startf_usecountchars; 67 | if suoUsefIllAttribute in FStartupOptions then 68 | Result:=Result or startf_USEFILLATTRIBUTE; 69 | end; 70 | end; 71 | 72 | Function GetCreationFlags(P : TProcess) : Cardinal; 73 | 74 | begin 75 | With P do 76 | begin 77 | Result:=0; 78 | if poNoConsole in FProcessOptions then 79 | Result:=Result or Detached_Process; 80 | if poNewConsole in FProcessOptions then 81 | Result:=Result or Create_new_console; 82 | if poNewProcessGroup in FProcessOptions then 83 | Result:=Result or CREATE_NEW_PROCESS_GROUP; 84 | If poRunSuspended in FProcessOptions Then 85 | Result:=Result or Create_Suspended; 86 | if poDebugProcess in FProcessOptions Then 87 | Result:=Result or DEBUG_PROCESS; 88 | if poDebugOnlyThisProcess in FProcessOptions Then 89 | Result:=Result or DEBUG_ONLY_THIS_PROCESS; 90 | if poDefaultErrorMode in FProcessOptions Then 91 | Result:=Result or CREATE_DEFAULT_ERROR_MODE; 92 | result:=result or PriorityConstants[FProcessPriority]; 93 | end; 94 | end; 95 | 96 | //L505 note: unicode string could be used, but msdn says CREATE_UNICODE_ENVIRONMENT 97 | // must be used with CreateProcessW. For now, ansistring will be used instead 98 | Function StringsToPChars(List : TStrings): pointer; 99 | var 100 | EnvBlock, item: ansistring; 101 | I: Integer; 102 | memsize: integer; 103 | begin 104 | EnvBlock := ''; 105 | For I:=0 to Pred(List.Count) do begin 106 | item := AnsiString(List[i]); 107 | EnvBlock := EnvBlock + item + #0; 108 | end; 109 | EnvBlock := EnvBlock + #0; 110 | memsize := Length(EnvBlock); // if using unicode in the future, remember CHAR size (4) for memory allocation 111 | GetMem(Result, memsize); 112 | CopyMemory(Result, @EnvBlock[1], memsize); 113 | end; 114 | 115 | Procedure InitProcessAttributes(P : TProcess; Var PA : TSecurityAttributes); 116 | 117 | begin 118 | FillChar(PA,SizeOf(PA),0); 119 | PA.nLength := SizeOf(PA); 120 | end; 121 | 122 | Procedure InitThreadAttributes(P : TProcess; Var TA : TSecurityAttributes); 123 | 124 | begin 125 | FillChar(TA,SizeOf(TA),0); 126 | TA.nLength := SizeOf(TA); 127 | end; 128 | 129 | // L505 changed to STARTUPINFOW 130 | // Procedure InitStartupInfo(P : TProcess; Var SI : STARTUPINFOA); 131 | procedure InitStartupInfo(P : TProcess; Var SI : STARTUPINFOW); 132 | Const 133 | SWC : Array [TShowWindowOptions] of Cardinal = 134 | (0,SW_HIDE,SW_Maximize,SW_Minimize,SW_Restore,SW_Show, 135 | SW_ShowDefault,SW_ShowMaximized,SW_ShowMinimized, 136 | SW_showMinNOActive,SW_ShowNA,SW_ShowNoActivate,SW_ShowNormal); 137 | 138 | begin 139 | FillChar(SI,SizeOf(SI),0); 140 | With SI do 141 | begin 142 | dwFlags:=GetStartupFlags(P); 143 | if P.FShowWindow<>swoNone then 144 | dwFlags:=dwFlags or Startf_UseShowWindow 145 | else 146 | dwFlags:=dwFlags and not Startf_UseShowWindow; 147 | wShowWindow:=SWC[P.FShowWindow]; 148 | if (poUsePipes in P.Options) then 149 | begin 150 | dwFlags:=dwFlags or Startf_UseStdHandles; 151 | end; 152 | if P.FillAttribute<>0 then 153 | begin 154 | dwFlags:=dwFlags or Startf_UseFillAttribute; 155 | dwFillAttribute:=P.FillAttribute; 156 | end; 157 | dwXCountChars:=P.WindowColumns; 158 | dwYCountChars:=P.WindowRows; 159 | dwYsize:=P.WindowHeight; 160 | dwXsize:=P.WindowWidth; 161 | dwy:=P.WindowTop; 162 | dwX:=P.WindowLeft; 163 | end; 164 | end; 165 | 166 | { The handles that are to be passed to the child process must be 167 | inheritable. On the other hand, only non-inheritable handles 168 | allow the sending of EOF when the write-end is closed. This 169 | function is used to duplicate the child process's ends of the 170 | handles into inheritable ones, leaving the parent-side handles 171 | non-inheritable. 172 | } 173 | function DuplicateHandleFP(var handle: THandle): Boolean; 174 | var 175 | oldHandle: THandle; 176 | begin 177 | oldHandle := handle; 178 | Result := DuplicateHandle 179 | ( GetCurrentProcess(), 180 | oldHandle, 181 | GetCurrentProcess(), 182 | @handle, 183 | 0, 184 | true, 185 | DUPLICATE_SAME_ACCESS 186 | ); 187 | if Result then 188 | Result := CloseHandle(oldHandle); 189 | end; 190 | 191 | // L505 changed to TStartupInfoW 192 | // Procedure CreatePipes(Var HI,HO,HE : Thandle; Var SI : TStartupInfoA; CE : Boolean; APipeBufferSize : Cardinal); 193 | procedure CreatePipes(Var HI,HO,HE : Thandle; Var SI : TStartupInfoW; CE : Boolean; APipeBufferSize : Cardinal); 194 | begin 195 | CreatePipeHandles(SI.hStdInput,HI, APipeBufferSize); 196 | DuplicateHandleFP(SI.hStdInput); 197 | CreatePipeHandles(HO,Si.hStdOutput, APipeBufferSize); 198 | DuplicateHandleFP(Si.hStdOutput); 199 | if CE then begin 200 | CreatePipeHandles(HE,SI.hStdError, APipeBufferSize); 201 | DuplicateHandleFP( SI.hStdError); 202 | end 203 | else 204 | begin 205 | SI.hStdError:=SI.hStdOutput; 206 | HE:=HO; 207 | end; 208 | end; 209 | 210 | Function MaybeQuote(Const S : String) : String; 211 | begin 212 | If (Pos(' ',S)<>0) then 213 | Result:='"'+S+'"' 214 | else 215 | Result:=S; 216 | end; 217 | 218 | Function MaybeQuoteIfNotQuoted(Const S : String) : String; 219 | begin 220 | If (Pos(' ',S)<>0) and (pos('"',S)=0) then 221 | Result:='"'+S+'"' 222 | else 223 | Result:=S; 224 | end; 225 | 226 | Procedure TProcess.Execute; 227 | Var 228 | i : Integer; 229 | PName,PDir,PCommandLine : PChar; 230 | FEnv: pointer; 231 | FCreationFlags : Cardinal; 232 | FProcessAttributes : TSecurityAttributes; 233 | FThreadAttributes : TSecurityAttributes; 234 | FProcessInformation : TProcessInformation; 235 | // FStartupInfo : STARTUPINFOA; // L505 236 | FStartupInfo : STARTUPINFOW; // L505 237 | HI,HO,HE : THandle; 238 | Cmd : String; 239 | 240 | begin 241 | PName:=Nil; 242 | PCommandLine:=Nil; 243 | PDir:=Nil; 244 | 245 | if (FApplicationName='') and (FCommandLine='') and (FExecutable='') then 246 | Raise EProcess.Create(SNoCommandline); 247 | if (FApplicationName<>'') then 248 | begin 249 | PName:=PChar(FApplicationName); 250 | PCommandLine:=PChar(FCommandLine); 251 | end 252 | else If (FCommandLine<>'') then 253 | PCommandLine:=PChar(FCommandLine) 254 | else if (Fexecutable<>'') then 255 | begin 256 | Cmd:=MaybeQuoteIfNotQuoted(Executable); 257 | For I:=0 to Parameters.Count-1 do 258 | Cmd:=Cmd+' '+MaybeQuoteIfNotQuoted(Parameters[i]); 259 | PCommandLine:=PChar(Cmd); 260 | end; 261 | If FCurrentDirectory<>'' then 262 | PDir:=PChar(FCurrentDirectory); 263 | if FEnvironment.Count<>0 then 264 | FEnv:=StringsToPChars(FEnvironment) 265 | else begin 266 | // writeln('DEBUG: environment nil'); 267 | FEnv:=Nil; 268 | end; 269 | 270 | Try 271 | FCreationFlags:=GetCreationFlags(Self); 272 | InitProcessAttributes(Self,FProcessAttributes); 273 | InitThreadAttributes(Self,FThreadAttributes); 274 | InitStartupInfo(Self,FStartUpInfo); 275 | If poUsePipes in FProcessOptions then begin 276 | CreatePipes(HI,HO,HE,FStartupInfo,Not(poStdErrToOutPut in FProcessOptions), FPipeBufferSize); 277 | end; 278 | 279 | Try 280 | // L505: changed to CreateProcessW, fpc uses CreateProcess which is CreateProcessA 281 | If Not CreateProcessW(PName,PCommandLine,@FProcessAttributes,@FThreadAttributes, 282 | FInheritHandles,FCreationFlags,FEnv,PDir,FStartupInfo, 283 | fProcessInformation) then 284 | Raise EProcess.CreateFmt(SErrCannotExecute,[FCommandLine,GetLastError]); 285 | FProcessHandle:=FProcessInformation.hProcess; 286 | FThreadHandle:=FProcessInformation.hThread; 287 | FProcessID:=FProcessINformation.dwProcessID; 288 | Finally 289 | if POUsePipes in FProcessOptions then 290 | begin 291 | FileClose(FStartupInfo.hStdInput); 292 | FileClose(FStartupInfo.hStdOutput); 293 | if Not (poStdErrToOutPut in FProcessOptions) then 294 | FileClose(FStartupInfo.hStdError); 295 | CreateStreams(HI,HO,HE); 296 | end; 297 | end; 298 | FRunning:=True; 299 | Finally 300 | If FEnv<>Nil then 301 | FreeMem(FEnv); 302 | end; 303 | if not (csDesigning in ComponentState) and // This would hang the IDE ! 304 | (poWaitOnExit in FProcessOptions) and 305 | not (poRunSuspended in FProcessOptions) then 306 | WaitOnExit; 307 | end; 308 | 309 | Function TProcess.WaitOnExit : Boolean; 310 | Var 311 | R : DWord; 312 | begin 313 | R:=WaitForSingleObject (FProcessHandle,Infinite); 314 | Result:=(R<>Wait_Failed); 315 | If Result then 316 | GetExitStatus; 317 | FRunning:=False; 318 | end; 319 | 320 | Function TProcess.Suspend : Longint; 321 | begin 322 | Result:=SuspendThread(ThreadHandle); 323 | end; 324 | 325 | Function TProcess.Resume : LongInt; 326 | begin 327 | Result:=ResumeThread(ThreadHandle); 328 | end; 329 | 330 | Function TProcess.Terminate(AExitCode : Integer) : Boolean; 331 | begin 332 | Result:=False; 333 | If ExitStatus=Still_active then 334 | Result:=TerminateProcess(Handle,AexitCode); 335 | end; 336 | 337 | Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); 338 | begin 339 | FShowWindow:=Value; 340 | end; --------------------------------------------------------------------------------