是否有一个Delphi库可以返回项目的所有有效源路径?

是否有一个Delphi库可以返回项目的所有有效源路径?,delphi,path,code-analysis,delphi-2009,Delphi,Path,Code Analysis,Delphi 2009,对于静态代码分析工具,需要知道给定Delphi项目的所有有效源代码路径,这些路径在项目级别和全局IDE配置中定义 是否有可以收集此类项目信息的Delphi库 据我所知,DelphiIDE的注册表设置可以位于不同的位置,以支持多种配置。但是对于IDE注册表位置和项目文件的给定组合,应该可以收集源路径 编辑:另一种解决方案是使用--depends开关。这将导致dcc32.exe写入一个“.d”文件,其中包含项目的所有dcu文件名(以及所有依赖项),包括路径名。但是,文件列表包含已编译的单元,因此它不

对于静态代码分析工具,需要知道给定Delphi项目的所有有效源代码路径,这些路径在项目级别和全局IDE配置中定义

是否有可以收集此类项目信息的Delphi库

据我所知,DelphiIDE的注册表设置可以位于不同的位置,以支持多种配置。但是对于IDE注册表位置和项目文件的给定组合,应该可以收集源路径


编辑:另一种解决方案是使用--depends开关。这将导致dcc32.exe写入一个“.d”文件,其中包含项目的所有dcu文件名(以及所有依赖项),包括路径名。但是,文件列表包含已编译的单元,因此它不是解决原始问题的正确解决方案。

您可以使用OpenTools API获取活动项目的搜索路径(从活动配置和选项集合并)和IDE的全局库路径。以下是我的快速测试设计包中的一个单元:

unit Unit1;

interface

uses
  Windows, SysUtils, Classes,
  ToolsAPI;

type
  TTestWizard = class(TNotifierObject, IOTAWizard, IOTAMenuWizard)
  private
    { IOTAWizard }
    function GetIDString: string;
    function GetName: string;
    function GetState: TWizardState;
    procedure Execute;
    { IOTAMenuWizard }
    function GetMenuText: string;
  private
    function AddLibraryPaths(Strings: TStrings): Integer;
    function AddProjectSearchPaths(Strings: TStrings): Integer;
  end;

procedure Register;

implementation

uses
  Dialogs,
  DCCStrs, TypInfo;

var
  WizardIndex: Integer = -1;

procedure GetEnvironmentVariables(Strings: TStrings);
var
  P: PChar;
begin
  P := nil;
  Strings.BeginUpdate;
  try
    Strings.Clear;
    P := GetEnvironmentStrings;
    repeat
      Strings.Add(P);
      P := StrEnd(P);
      Inc(P);
    until P^ = #0;
  finally
    if Assigned(P) then
      FreeEnvironmentStrings(P);
    Strings.EndUpdate;
  end;
end;

function EvaluateEnvironmentVariables(const S: string): string;
var
  Strings: TStringList;
  I: Integer;
begin
  Result := S;

  Strings := TStringList.Create;
  try
    GetEnvironmentVariables(Strings);
    for I := 0 to Strings.Count - 1 do
      Result := StringReplace(Result, Format('$(%s)', [Strings.Names[I]]), Strings.ValueFromIndex[I],
        [rfReplaceAll, rfIgnoreCase]);
  finally
    Strings.Free;
  end;
end;

procedure Register;
begin
  WizardIndex := (BorlandIDEServices as IOTAWizardServices).AddWizard(TTestWizard.Create);
end;

{ TTestWizard private: IOTAWizard }

function TTestWizard.GetIDString: string;
begin
  Result := 'TOndrej.TestWizard';
end;

function TTestWizard.GetName: string;
begin
  Result := 'TestWizard';
end;

function TTestWizard.GetState: TWizardState;
begin
  Result := [wsEnabled];
end;

procedure TTestWizard.Execute;
var
  Paths: TStrings;
begin
  Paths := TStringList.Create;
  try
    AddProjectSearchPaths(Paths);
    AddLibraryPaths(Paths);
    ShowMessage(EvaluateEnvironmentVariables(Paths.Text));
  finally
    Paths.Free;
  end;
end;

{ TTestWizard private: IOTAMenuWizard }

function TTestWizard.GetMenuText: string;
begin
  Result := GetIDString;
end;

function TTestWizard.AddLibraryPaths(Strings: TStrings): Integer;
var
  Paths: TStringList;
  EnvironmentOptions: IOTAEnvironmentOptions;
begin
  Paths := TStringList.Create;
  try
    Paths.Delimiter := ';';
    Paths.StrictDelimiter := True;
    EnvironmentOptions := (BorlandIDEServices as IOTAServices).GetEnvironmentOptions;
    Paths.DelimitedText := EnvironmentOptions.Values['LibraryPath'];
    Strings.AddStrings(Paths);
    Result := Paths.Count;
  finally
    Paths.Free;
  end;
end;

function TTestWizard.AddProjectSearchPaths(Strings: TStrings): Integer;
var
  ActiveProject: IOTAProject;
  Configurations: IOTAProjectOptionsConfigurations;
  Configuration: IOTABuildConfiguration;
  Paths: TStringList;
begin
  Result := -1;
  ActiveProject := GetActiveProject;
  if not Assigned(ActiveProject) then
    Exit;
  Configurations := ActiveProject.ProjectOptions as IOTAProjectOptionsConfigurations;
  Configuration := Configurations.ActiveConfiguration;
  if not Assigned(Configuration) then
    Exit;

  Paths := TStringList.Create;
  try
    Configuration.GetValues(sUnitSearchPath, Paths, True);
    Strings.AddStrings(Paths);
    Result := Paths.Count;
  finally
    Paths.Free;
  end;
end;

initialization

finalization
  if WizardIndex <> -1 then
    (BorlandIDEServices as IOTAWizardServices).RemoveWizard(WizardIndex);

end.
单元1;
接口
使用
Windows、SysUtils、类、,
图尔萨皮;
类型
TTestWizard=类(TNotifierObject、IOTAWizard、IOTAMenuWizard)
私有的
{IOTAWizard}
函数GetIDString:string;
函数GetName:string;
函数GetState:TWizardState;
程序执行;
{IOTAMenuWizard}
函数GetMenuText:string;
私有的
函数addLibraryPath(字符串:TStrings):整数;
函数addProjectSearchPath(字符串:TStrings):整数;
结束;
程序登记册;
实施
使用
对话,
DCCStrs,TypInfo;
变量
向导索引:整数=-1;
过程GetEnvironmentVariables(字符串:TStrings);
变量
P:PChar;
开始
P:=零;
Strings.BeginUpdate;
尝试
字符串。清晰;
P:=GetEnvironmentString;
重复
字符串。添加(P);
P:=强度(P);
公司(P),;
直到P^=#0;
最后
如果分配(P),则
自由环境字符串(P);
Strings.EndUpdate;
结束;
结束;
函数EvaluateEnvironmentVariables(const S:string):string;
变量
字符串:TStringList;
I:整数;
开始
结果:=S;
字符串:=TStringList.Create;
尝试
GetEnvironmentVariables(字符串);
对于I:=0到字符串。计数-1 do
结果:=StringReplace(结果,格式(“$(%s)”,[Strings.Names[I]],Strings.ValueFromIndex[I],
[rfReplaceAll,rfIgnoreCase]);
最后
字符串。免费;
结束;
结束;
程序登记册;
开始
WizardIndex:=(作为IOTAWizardServices的设备)。添加向导(TTestWizard.Create);
结束;
{TTestWizard private:IOTAWizard}
函数TTestWizard.GetIDString:string;
开始
结果:='TOndrej.TestWizard';
结束;
函数TTestWizard.GetName:string;
开始
结果:='TestWizard';
结束;
函数TTestWizard.GetState:TWizardState;
开始
结果:=[wsEnabled];
结束;
程序Twiszard.Execute;
变量
路径:TStrings;
开始
路径:=TStringList.Create;
尝试
AddProjectSearchPath(路径);
添加库路径(路径);
ShowMessage(EvaluateEnvironmentVariables(path.Text));
最后
免费的;
结束;
结束;
{TTestWizard private:IOTAMenuWizard}
函数TTestWizard.GetMenuText:string;
开始
结果:=GetIDString;
结束;
函数TTestWizard.AddLibraryPath(Strings:TStrings):整数;
变量
路径:TStringList;
环境选项:IoTaenEnvironment选项;
开始
路径:=TStringList.Create;
尝试
路径。分隔符:=';';
Paths.StrictDelimiter:=True;
EnvironmentOptions:=(将设备作为IoTaskServices)。GetEnvironmentOptions;
Paths.DelimitedText:=EnvironmentOptions.Values['LibraryPath'];
Strings.AddStrings(路径);
结果:=路径。计数;
最后
免费的;
结束;
结束;
函数TTestWizard.AddProjectSearchPath(Strings:TStrings):整数;
变量
活动项目:物联网项目;
配置:物联网项目选项配置;
配置:IOTABuildConfiguration;
路径:TStringList;
开始
结果:=-1;
ActiveProject:=GetActiveProject;
如果未分配(ActiveProject),则
出口
配置:=ActiveProject.ProjectOptions作为IOTAProjectOptions配置;
配置:=Configurations.ActiveConfiguration;
如果未分配(配置),则
出口
路径:=TStringList.Create;
尝试
getvalue(sUnitSearchPath,path,True);
Strings.AddStrings(路径);
结果:=路径。计数;
最后
免费的;
结束;
结束;
初始化
定稿
如果索引为-1,则
(将设备作为IOTAWizardServices)移除向导(WizardIndex);
结束。

刚刚找到另一个解决方案:

如果我启动RAD Studio命令提示符并运行

msbuild /t:Rebuild
在项目目录中,msbuild将显示调用dcc32的完整命令行,包括所有路径设置。将构建日志重定向到一个文件(或者用只捕获参数的自制版本替换dcc32.exe)并解析输出似乎比解析dproj文件容易得多


另一个优点是,它可以用于自动构建/持续集成。

您想知道的任何特定Delphi版本?Delphi 2009-因为它的构建配置更复杂,甚至可以继承,并且可以包含诸如“$(DCC\U UnitSearchPath)之类的宏“-这似乎比预期的难…这看起来很有希望,非常感谢!我会仔细看看在线旅行社。很容易获得项目源文件的列表(所有已明确添加到DPR的文件)?我还将看看GExpert/cnWizard的源代码。是的,通过OTA,您可以枚举项目的模块。查看IOTAProject接口。具体来说,IoTapProject 40方法GetModuleCount、GetModule。