在 Inno Setup 中验证目录路径

Validate directory path in Inno Setup

如果您输入无效路径或空路径,Inno Setup 将给出此错误:

我需要创建一个函数来为我执行此操作。目前我正在使用 DirExists 函数,但我认为它没有涵盖我正在寻找的内容。

Inno Setup 所做的验证相对复杂。检查 ValidateCustomDirEdit 函数的源代码以了解它的作用。

下面是翻译成 Pascal Script 的默认 Inno Setup 设置 (AllowUNCPath=yes, AllowRootDirectory=no, AllowNetworkDrive=yes) 代码的非常等价物。请注意,它可能无法与 MBCS 一起正常工作。

procedure TidyUpDirName(var Path: String);
var
  Prefix: string;
  Prev: string;
begin
  StringChangeEx(Path, '/', '\', True);
  repeat
    Prev := Path;
    Path := Trim(Path);
    Prefix := '';
    if Copy(Path, 1, 2) = '\' then
    begin
      Prefix := '\';
      Path := Copy(Path, 3, Length(Path) - 2);
    end;
    StringChangeEx(Path, '\', '\', True);
    Path := Prefix + Path;
    Path := RemoveBackslashUnlessRoot(Path);
  until Prev = Path;
end;

function ValidatePath(Path: string): Boolean;
var
  I, P: Integer;
  S, S2: string;
begin
  TidyUpDirName(Path);
  Result := False;
  if Length(Path) > 240 then Exit;

  if Copy(Path, 1, 2) <> '\' then
  begin
    if (Length(Path) < 4) or
       (Uppercase(Path[1])[1] < 'A') or (Uppercase(Path[1])[1] > 'Z') or
       (Path[2] <> ':')
       or (Path[3] <> '\') then Exit;
  end
    else
  begin
    if Pos('\', Copy(Path, 3, Length(Path) - 2)) = 0 then Exit;
  end;

  for I := 1 to Length(Path) do
  begin
    if Path[I] <= #31 then Exit;

    if (Path[I] = ' ') and
       ((I = Length(Path)) or (Path[I + 1] = '\')) then Exit;
  end;

  S := Path;
  while Length(S) > 0 do
  begin
    P := Pos('\', S);
    if P > 0 then
    begin
      S2 := Copy(S, 1, P - 1);
      S := Copy(S, P + 1, Length(S) - P);
    end
      else
    begin
      S2 := S;
      S := '';
    end;
    S2 := Trim(S2);
    if (Length(S2) > 0) and (S2 = StringOfChar('.', Length(S2))) then Exit;
  end;

  for I := 3 to Length(Path) do
  begin
    if Pos(Path[I], '/:*?"<>|') > 0 then Exit;
  end;

  Result := True;
end;

测试:

procedure DoTest(Path: string; Expected: Boolean);
var
  Actual: Boolean;
  M: string;
begin
  Actual := ValidatePath(Path);
  M := Format('Path: "%s"; Result: %d; Expected: %d', [
         Path, Integer(Actual), Integer(Expected)]);
  Log(M);
  if Actual <> Expected then RaiseException(M);
end;

procedure Test;
begin
  DoTest('C:\path', True);
  DoTest('\server\path', True);
  DoTest('c:\path', True);
  DoTest('C:/path', True);
  DoTest('//server/path', True);
  DoTest('C:\path ', True);
  DoTest(' C:\path ', True);
  DoTest('C:\path', True);
  DoTest('\server\path', True);
  DoTest('C:', False);
  DoTest('C:\', False);
  DoTest('1:\path', False);
  DoTest('|:\path', False);
  DoTest('C;\path', False);
  DoTest('C:|path\sub', False);
  DoTest('\server', False);
  DoTest('C:\pa'#27'th', False);
  DoTest('C:\path \sub', False);
  DoTest('C:\path\sub \sub', False);
  DoTest('C:\.', False);
  DoTest('C:\..\sub', False);
  DoTest('C:\path\.\sub', False);
  DoTest('C:\path\ .\sub', False);
  DoTest('C:\path\.. \sub', False);
  DoTest('C:\path\su:b', False);
  DoTest('C:\pa?th\sub', False);
end;

Inno Setup 额外测试驱动器是否存在:

DirExists(ExtractFileDrive(Path))

如果您希望自己的路径编辑框具有与标准 Select 目录页面相同的验证,请使用 CreateInputDirPage/TInputDirWizardPage,而不是完全自定义的页面。 TInputDirWizardPage 为您进行验证。

或者您可以调用隐藏的 TInputDirWizardPage 来进行验证。