如何最好地修改/安装组件库路径到 Delphi IDE 中而不手动进行?

Posted

技术标签:

【中文标题】如何最好地修改/安装组件库路径到 Delphi IDE 中而不手动进行?【英文标题】:How best to modify / install a component library path into the Delphi IDE without doing it manually? 【发布时间】:2011-10-12 09:49:02 【问题描述】:

我正在准备一个安装程序 (Inno Setup) 来将我的组件包安装到 Delphi XE 中,而无需手动在 IDE 中摆弄。

我需要修改 Delphi 库路径,例如删除其中的一部分(例如,xxx;MyOldPath;yyy)并插入一个新路径,xxxx;MyNewPath;yyyy。有没有首选的方法,或者我必须编写一个实用程序来做到这一点?

谢谢

【问题讨论】:

库路径是注册表中的子项;请考虑可能有多个注册表项(与传递给 bds 可执行文件的 -r 命令行开关一起使用)。安装程序可能应该枚举所有现有的注册表项并提供一个复选框或类似的界面,以便用户可以选择应该修改哪些注册表项。 如果你正在做我认为你正在做的事情(在 innosetup 中制作组件安装程序),这可能最终值得写一篇关于并在你的博客上发布的小文章。 【参考方案1】:

修改路径是基本的字符串操作:您从注册表中读取当前路径,根据需要对其进行操作,然后将其写回。

您可能可以编写一个 Inno Setup 脚本函数,这样您就没有任何外部依赖项。或者编写一个从 Inno Setup 的脚本中使用的 Delphi DLL,这样会更容易调试。


编辑

这是我实际在生产中使用的例程的修改版本。它将从Search Path 注册表值或Browsing Path(与此相关的任何其他路径)读取整个路径列表,可能会删除一些路径,如果它们不存在,则添加一些路径。

procedure UpdateDelphiPaths(const RegistryKey, RegistryValue: string; PathsToRemove, PathsToAdd: TStrings);
var R:TRegistry;
      SKeys:TStringList;
      Found:Boolean;
      Updated:Boolean;
      i,j:Integer;
      s:string;
      R_Globals:TRegistry;

  // This function normalises paths in comparasions
  function PrepPathForComparasion(const Path:string):string;
  begin
    if Path = '' then Result := '\'
    else
      if Path[Length(Path)] = '\' then
        Result := LowerCase(Path)
      else
        Result := LowerCase(Path) + '\';
  end;

  function PathMatchesRemoveCriteria(const Path:string): Boolean;
  var i:Integer;
  begin
    // This needs to be addapted to match your criteria!
    for i:=0 to PathsToRemove.Count-1 do
      if AnsiPos(PathsToRemove[i], Path) <> 0 then
        Exit(True);
    Result := False;
  end;

begin
  R := TRegistry.Create;
  try
    R.RootKey := HKEY_CURRENT_USER;
    if R.OpenKey(RegistryKey + '\Library', False) then
      if R.ValueExists(RegistryValue) then
      begin
        SKeys := TStringList.Create;
        try
          SKeys.Delimiter := ';';
          SKeys.StrictDelimiter := True;
          SKeys.DelimitedText := R.ReadString(RegistryValue);

          Updated := False;

          // Look at all the paths in the PathsToAdd list, if any one's missing add it to the list and mark
          // "Updated".
          for i:=0 to PathsToAdd.Count-1 do
          begin
            Found := False;
            for j:=0 to SKeys.Count-1 do
              if LowerCase(Trim(SKeys[j])) = LowerCase(Trim(PathsToAdd[i])) then
                Found := True;
            if not Found then
            begin
              SKeys.Add(PathsToAdd[i]);
              Updated := True;
            end;
          end;

          // Look at every single path in the current list, if it's not in the "PathsToAdd" and it matches
          // a name in "PathsToRemove", drop it and mark "Updated"
          i := 0;
          while i < SKeys.Count do
          begin
            if PathMatchesRemoveCriteria(SKeys[i]) then
              begin
                // Path matches remove criteria! It only gets removed if it's not actually present in
                // PathsToAdd
                Found := False;
                for j:=0 to PathsToAdd.Count-1 do
                begin
                  if PrepPathForComparasion(SKeys[i]) = PrepPathForComparasion(PathsToAdd[j]) then
                    Found := True;
                end;
                if not Found then
                  begin
                    SKeys.Delete(i);
                    Updated := True;
                  end
                else
                  Inc(i);
              end
            else
              Inc(i);
          end;

          // If I've updated the SKeys in any way, push changes back to registry and force updates
          if Updated then
          begin
            s := SKeys[0];
            for i:=1 to SKeys.Count-1 do
              if SKeys[i] <> '' then
              begin
                s := s + ';' + SKeys[i];
              end;
            R.WriteString(RegistryValue, s);

            // Force delphi to re-load it's paths.
            R_Globals := TRegistry.Create;
            try
              R_Globals.OpenKey(RegistryKey + '\Globals', True);
              R_Globals.WriteString('ForceEnvOptionsUpdate', '1');
            finally R_Globals.Free;
            end;

          end;

        finally SKeys.Free;
        end;
      end;
  finally R.Free;
  end;
end;

从 Delphi 代码中,我可以像这样调用例程,以确保安装了给定库的最新搜索路径:

var ToRemove, ToAdd: TStringList;
begin
  ToRemove := TStringList.Create;
  try
    ToAdd := TStringList.Create;
    try
      ToRemove.Add('LibraryName\Source');
      ToAdd.Add('C:\LibraryName\Source');
      UpdateDelphiPaths('Software\CodeGear\BDS\7.0', 'Test Path', ToRemove, ToAdd);
    finally ToAdd.Free;
    end;
  finally ToRemove.Free;
  end;
end;

注意ToRemoveToAdd。我可以在 Remove 和 Add 列表中安全地指定搜索路径:仅当路径匹配“Remove”条件但不在“ToAdd”列表中时才会删除路径。还要注意PathMatchesRemoveCriteria 函数。

您可以修改代码以直接从 InnoScript 本身工作,或者您可以将代码放入 DLL 并使用安装程序中的 DLL。 DLL 变体的优点是在 Delphi 中易于调试,在 Inno 本身上也很容易; Inno 变体的优点是没有外部依赖,但代码需要调整和调试。

【讨论】:

以上是关于如何最好地修改/安装组件库路径到 Delphi IDE 中而不手动进行?的主要内容,如果未能解决你的问题,请参考以下文章

Delphi语言最好的JSON代码库 mORMot学习笔记1

转:Delphi语言最好的JSON代码库 mORMot学习笔记1

delphi第三方控件是如何安装到delphi里去的???

如何在 Delphi 中将带有图像的 RichText (RTF) 文档转换为 HTML?

Delphi 组件保存

如何查询 Delphi 组件面板?