Как лучше всего изменить / установить путь к библиотеке компонентов в Delphi IDE, не делая это вручную? - PullRequest
3 голосов
/ 25 июля 2011

Я готовлю установщик ( Inno Setup ) для установки пакета компонентов в Delphi XE без необходимости вручную манипулировать в IDE.

Мне нужно изменить путь к библиотеке Delphi, например, чтобы удалить его часть (например, xxx;MyOldPath;yyy) и вставить новый путь, xxxx;MyNewPath;yyyy. Есть ли предпочтительный способ сделать это, или мне придется написать утилиту для этого?

Спасибо

1 Ответ

5 голосов
/ 25 июля 2011

Изменение пути - это базовая обработка строк: вы читаете текущий путь из реестра, манипулируете им в соответствии с вашими потребностями, записываете обратно.

Вы, вероятно, можете написать функцию сценария Inno Setup, чтобы вы нене имеет никаких внешних зависимостей.Или напишите Delphi DLL, которая используется из скрипта Inno Setup, чтобы ее было легче отлаживать.


Edit

Вот модифицированная версия подпрограммы, которую я фактически использую в производстве,Он прочитает весь список путей либо из значения реестра 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;

Обратите внимание на ToRemove и ToAdd.Я могу смело указать путь поиска в списках «Удалить» и «Добавить»: пути удаляются только в том случае, если они соответствуют критериям «Удалить», но отсутствуют в списке «Добавить».Также обратите внимание на функцию PathMatchesRemoveCriteria.

Возможно, вы можете изменить код так, чтобы он работал прямо из самого InnoScript, или вы можете поместить код в DLL и использовать DLL из программы установки.Преимущество варианта DLL в том, что он легко отлаживается в Delphi и очень прост в самой Inno;Преимущество варианта Inno заключается в отсутствии внешних зависимостей, но код необходимо будет адаптировать и отладить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...