Inno Setup 6 调用 Windows API 实现 MoveFileEx 移动大文件夹

Pascal/Delphi wes 3 hours ago (2026-10-25) 6 views
📑 本文导航

Inno Setup 6 调用 Windows API 实现DirMove移动大文件夹。

调试版本

[Code]
const
  MOVEFILE_REPLACE_EXISTING = $00000001;
  MOVEFILE_COPY_ALLOWED     = $00000002;
// 注意:改用 W 版本,避免 Unicode 路径问题
function MoveFileExW(lpExistingFileName, lpNewFileName: string; dwFlags: Integer): Integer;
  external 'MoveFileExW@kernel32.dll stdcall';
function MoveDirectory(const SourceDir, DestDir: string;
  const AllowCrossVolume, Overwrite: Boolean; const ShowError: Boolean): Boolean;
var
  Flags, ErrorCode: Integer;
  Src, Dst: string;
  Msg: string;
begin
  // 规范化:去掉尾部反斜杠,避免 API 解析异常
  Src := RemoveBackslashUnlessRoot(SourceDir);
  Dst := RemoveBackslashUnlessRoot(DestDir);

  // 源必须存在
  if not DirExists(Src) then
  begin
    if ShowError then
      MsgBox('源文件夹不存在:' + Src, mbError, MB_OK);
    Log('MoveDirectory: 源不存在 ' + Src);
    Result := False;
    Exit;
  end;

  // 目标已存在则直接失败(REPLACE_EXISTING 对目录不可靠)
  if DirExists(Dst) then
  begin
    if ShowError then
      MsgBox('目标文件夹已存在,拒绝移动:' + Dst, mbError, MB_OK);
    Log('MoveDirectory: 目标已存在 ' + Dst);
    Result := False;
    Exit;
  end;

  Flags := 0;
  if Overwrite then
    Flags := Flags or MOVEFILE_REPLACE_EXISTING;
  if AllowCrossVolume then
    Flags := Flags or MOVEFILE_COPY_ALLOWED;

  Result := MoveFileExW(Src, Dst, Flags) <> 0;

  if not Result then
  begin
    ErrorCode := DLLGetLastError;
    Msg := Format('MoveFileExW 失败。'#13#10 +
                  '源: %s'#13#10 +
                  '目标: %s'#13#10 +
                  'Flags: %d'#13#10 +
                  '错误码: %d'#13#10 +
                  '消息: %s',
                  [Src, Dst, Flags, ErrorCode, SysErrorMessage(ErrorCode)]);
    Log(Msg);
    if ShowError then
      MsgBox(Msg, mbError, MB_OK);
  end
  else
    Log(Format('MoveDirectory 成功: %s -> %s', [Src, Dst]));
end;

调用处改成:

pascal
if DirExists(CacheSrc) then
begin
  // 打印一下实际路径,便于确认
  MsgBox('准备移动:'#13#10 + CacheSrc + #13#10 + '->'#13#10 + CacheTmp,
         mbInformation, MB_OK);

  MoveDirectory(CacheSrc, CacheTmp, False, True, True); // 最后一个 True = 弹错误
end;

发布版本

[Code]
const
  MOVEFILE_COPY_ALLOWED = $00000002;
// 改用 W 版本,避免 Unicode 路径问题
function MoveFileExW(lpExistingFileName, lpNewFileName: string; dwFlags: Integer): Integer;
  external 'MoveFileExW@kernel32.dll stdcall';
function MoveDirectory(const SourceDir, DestDir: string; const AllowCrossVolume: Boolean): Boolean;
var
  Flags, ErrorCode: Integer;
  Src, Dst: string;
begin
  // 规范化:去掉尾部反斜杠,避免 API 解析异常
  Src := RemoveBackslashUnlessRoot(SourceDir);
  Dst := RemoveBackslashUnlessRoot(DestDir);

  // 源必须存在
  if not DirExists(Src) then
  begin
    Log('MoveDirectory 失败: 源文件夹不存在 ' + Src);
    Result := False;
    Exit;
  end;

  // 目标已存在则直接失败(防止意外覆盖数据)
  if DirExists(Dst) then
  begin
    Log('MoveDirectory 失败: 目标文件夹已存在 ' + Dst);
    Result := False;
    Exit;
  end;

  Flags := 0;
  if AllowCrossVolume then
    Flags := Flags or MOVEFILE_COPY_ALLOWED;

  Result := MoveFileExW(Src, Dst, Flags) <> 0;

  if not Result then
  begin
    ErrorCode := DLLGetLastError;
    Log(Format('MoveDirectory 失败: API 报错 %d (%s) - %s -> %s', 
      [ErrorCode, SysErrorMessage(ErrorCode), Src, Dst]));
  end;
end;


↑