0
votes

I am new in Delphi and I am trying to make an application in which I will give as an input a .dpr file and the application will create a list with all the .pas files used by this .dpr... I still cannot find a function in Delphi or a way to read the uses of the .dpr in order to navigate through the file system to these pas files and read their uses, and so on... Does anyone has any idea on how to achieve this?

3
Delphi has no built in functionality to do that. Either write a parser or find a third party one. Why do you need to do this anyway? - David Heffernan
Also: from the exe, not the dpr you can get the unit list from one of the resources: RCData / PACKAGEINFO. Not the answer but perhaps an alternative. - Ritsaert Hornstra
Thank you very much guys! I'll take a better look in each solution... David, I want to create an application where I will give a .dpr and it will copy to another folder in file system all relative units to this .dpr. That way I can get easily a copy with all the necessary units for the project even if I have .pas files in the same folder used by other projects. - thpst
Your revision control system is what you need to use. Please tell me that you are using revision control. - David Heffernan

3 Answers

3
votes

It's not exactly straightforward: You don't just need to read the .dpr file, but you also need to parse the .dproj and registry to get Search Paths. If you're trying to do this right, you also have to parse the .dpr and .pas files as code files so you can find the uses statements, handle {$I '...'} includes, {$IFDEF} blocks, interface vs implementation sections, and so on.

All that said, you might want to look to the open source CnPack and GExperts projects for inspiration. Both of them have solved this problem, and you may be able to leverage their work towards whatever problem you're trying to solve.

0
votes

If you let Delphi create a .map file (linker option), it will contain a list of all source and dcu files used in that project. GExperts does that, using a simple parser for a map file which is taken from my dzlib https://sourceforge.net/p/dzlib/code/HEAD/tree/dzlib/trunk/src/u_dzMapFileReader.pas

0
votes

I would like to update this question for possible answer for future reference.

Create a separate unit file (PhonyObject.pas)

unit PhonyObject;

interface

uses
  System.Classes, FMX.Forms, FMX.Dialogs;

type
  TPhonyObject = class(TObject)
  end;

  TPhonyClass = class of TPhonyObject;

procedure FindUnitName(anObject: TObject);

var
  PhonyName: string;
  PhonyClass: TPhonyClass;
  PhonyInstance: TObject;
  PhonyClassName: procedure(anObject: TObject) = FindUnitName;  //function: String = FindUnitName;

implementation

uses System.TypInfo;

procedure FindUnitName(anObject: TObject);
begin
  if anObject <> nil then  PhonyName := anObject.UnitName
  else if not (TObject.UnitName <> 'System') then
  begin
    if TypInfo.GetTypeData(anObject.ClassInfo) <> nil then  PhonyName := String(GetTypeData(anObject.ClassInfo)^.UnitName);
  end else  PhonyName := TObject.UnitName;
  //FreeAndNilProperties
end;

initialization
  PhonyClass := TPhonyObject;
  PhonyInstance := PhonyClass.Create;

  ShowMessage('Unit Name =' + PhonyInstance.UnitName);

  PhonyInstance.Free;


finalization
  PhonyClass := nil; //PhonyClass.Free;

end.

And in order to use this inside another (multiple) units, this is the code I have used so far, but I hope to update it later on. I have this showing up inside a hand made "console" with black background and white text in a TMemo. If anyone wants the code for the TMemo (its not commonly known), or how to show all these inside basically a debug window, all you just have to do let me know. This is the best I have gotten it so far, but I need a better understanding of the child/parent object/classes

unit AnotherUnit;

interface

uses
  System.Classes, PhonyObject;

type
  TPhonyObj = class(TPhonyObject)
  end;

//var

implementation

{$R *.fmx}

uses ...;

initialization

  PhonyClass := TPhonyObj;
  PhonyInstance := PhonyClass.Create;

  ShowMessage('UnitName= ' + PhonyInstance.UnitName + ' (AnotherUnit)'); // PhonyClass.UnitName  // PhonyClassName(PhonyInstance);

  PhonyInstance.Free;

finalization
  PhonyClass := nil;

end;

I used as unique of Unit Names and class names, as I could and I realize I don't actually use any objects till the end, none the less it should work with out any problems. Please comment if there are some better ideas, but I think this is a powerful feature for Delphi programming when you can predict when certain unit names are going to suddenly show up. And how to predict for them too.