简体   繁体   English

Inno Setup 安装程序中的嵌入式 CMD(在自定义页面上显示命令输出)

[英]Embedded CMD in Inno Setup installer (show command output on a custom page)

I created an Input page that executes a command line app using the created variables from those inputs.我创建了一个输入页面,该页面使用从这些输入中创建的变量来执行命令行应用程序。 Naturally, the cmd window pop ups on my screen.当然, cmd窗口会在我的屏幕上弹出。 I would like to know if there is any way to embed the cmd window (or the output) on my Inno Setup installer page.我想知道是否有任何方法可以在我的 Inno Setup 安装程序页面上嵌入cmd窗口(或输出)。

I'm running Inno Setup 5.6.1 (because of Windows XP compatibility), but I'm OK if i have to switch to the last version.我正在运行 Inno Setup 5.6.1(因为与 Windows XP 兼容),但如果我必须切换到最新版本,我也可以。

[Code]
var
  MAIL: TInputQueryWizardPage;
  Final: TWizardPage;
  BotonIniciar: Tbutton;

procedure BotonIniciarOnClick(Sender: TObject);
begin
  WizardForm.NextButton.Onclick(nil);
  Exec(ExpandConstant('{tmp}\imapsync.exe'),'MAIL.Values[0]','', SW_SHOW,
    ewWaitUntilTerminated, ResultCode);
end;

procedure InitializeWizard;
begin
  MAIL := CreateInputQueryPage(wpWelcome, '', '', '');
  MAIL.Add('Please input your information', False);

  BotonIniciar := TNewButton.Create(MAIL);
  BotonIniciar.Caption := 'Iniciar';
  BotonIniciar.OnClick := @BotonIniciarOnClick;
  BotonIniciar.Parent :=  WizardForm;
  BotonIniciar.Left := WizardForm.NextButton.Left - 250 ;
  BotonIniciar.Top := WizardForm.CancelButton.Top - 10;
  BotonIniciar.Width := WizardForm.NextButton.Width + 60;
  BotonIniciar.Height := WizardForm.NextButton.Height + 10;
end;

I'm might be missing some parts of the code, but I think it's understandable.我可能会遗漏代码的某些部分,但我认为这是可以理解的。 Fist Ii create the Input page, then I create a button with the OnClick property that calls to the BotonIniciarOnClick procedure.首先创建输入页面,然后创建一个带有OnClick属性的按钮,该按钮调用BotonIniciarOnClick过程。

Actually, the code works great.实际上,代码效果很好。 But as I said I'm having a floating cmd window.但正如我所说,我有一个浮动的cmd窗口。

I would like to see something like this:我想看到这样的事情:

例子

Its just a random image I took from google.它只是我从谷歌拍摄的随机图像。
What I want to see is similar to a standard "show details" option on an installer我想看到的类似于安装程序上的标准“显示详细信息”选项

You can redirect the command output to a file and monitor the file for changes, loading them to list box (or maybe a memo box).您可以将命令输出重定向到文件并监视文件的更改,将它们加载到列表框(或者可能是备忘录框)。

var
  ProgressPage: TOutputProgressWizardPage;
  ProgressListBox: TNewListBox;

function SetTimer(
  Wnd: LongWord; IDEvent, Elapse: LongWord; TimerFunc: LongWord): LongWord;
  external 'SetTimer@user32.dll stdcall';
function KillTimer(hWnd: LongWord; uIDEvent: LongWord): BOOL;
  external 'KillTimer@user32.dll stdcall';

var
  ProgressFileName: string;

function BufferToAnsi(const Buffer: string): AnsiString;
var
  W: Word;
  I: Integer;
begin
  SetLength(Result, Length(Buffer) * 2);
  for I := 1 to Length(Buffer) do
  begin
    W := Ord(Buffer[I]);
    Result[(I * 2)] := Chr(W shr 8); { high byte }
    Result[(I * 2) - 1] := Chr(Byte(W)); { low byte }
  end;
end;

procedure UpdateProgress;
var
  S: AnsiString;
  I, L, Max: Integer;
  Buffer: string;
  Stream: TFileStream;
  Lines: TStringList;
begin
  if not FileExists(ProgressFileName) then
  begin
    Log(Format('Progress file %s does not exist', [ProgressFileName]));
  end
    else
  begin
    try
      { Need shared read as the output file is locked for writting, }
      { so we cannot use LoadStringFromFile }
      Stream := TFileStream.Create(ProgressFileName, fmOpenRead or fmShareDenyNone);
      try
        L := Stream.Size;
        Max := 100*2014;
        if L > Max then
        begin
          Stream.Position := L - Max;
          L := Max;
        end;
        SetLength(Buffer, (L div 2) + (L mod 2));
        Stream.ReadBuffer(Buffer, L);
        S := BufferToAnsi(Buffer);
      finally
        Stream.Free;
      end;
    except
      Log(Format('Failed to read progress from file %s - %s', [
                 ProgressFileName, GetExceptionMessage]));
    end;
  end;

  if S <> '' then
  begin
    Log('Progress len = ' + IntToStr(Length(S)));
    Lines := TStringList.Create();
    Lines.Text := S;
    for I := 0 to Lines.Count - 1 do
    begin
      if I < ProgressListBox.Items.Count then
      begin
        ProgressListBox.Items[I] := Lines[I];
      end
        else
      begin
        ProgressListBox.Items.Add(Lines[I]);
      end
    end;
    ProgressListBox.ItemIndex := ProgressListBox.Items.Count - 1;
    ProgressListBox.Selected[ProgressListBox.ItemIndex] := False;
    Lines.Free;
  end;

  { Just to pump a Windows message queue (maybe not be needed) }
  ProgressPage.SetProgress(0, 1);
end;

procedure UpdateProgressProc(
  H: LongWord; Msg: LongWord; Event: LongWord; Time: LongWord);
begin
  UpdateProgress;
end;

procedure BotonIniciarOnClick(Sender: TObject);
var
  ResultCode: Integer;
  Timer: LongWord;
  AppPath: string;
  AppError: string;
  Command: string;
begin
  ProgressPage :=
    CreateOutputProgressPage(
      'Installing something', 'Please wait until this finishes...');
  ProgressPage.Show();
  ProgressListBox := TNewListBox.Create(WizardForm);
  ProgressListBox.Parent := ProgressPage.Surface;
  ProgressListBox.Top := 0;
  ProgressListBox.Left := 0;
  ProgressListBox.Width := ProgressPage.SurfaceWidth;
  ProgressListBox.Height := ProgressPage.SurfaceHeight;

  { Fake SetProgress call in UpdateProgressProc will show it, }
  { make sure that user won't see it }
  ProgressPage.ProgressBar.Top := -100;

  try
    Timer := SetTimer(0, 0, 250, CreateCallback(@UpdateProgressProc));

    ExtractTemporaryFile('install.bat');
    AppPath := ExpandConstant('{tmp}\install.bat');
    ProgressFileName := ExpandConstant('{tmp}\progress.txt');
    Log(Format('Expecting progress in %s', [ProgressFileName]));
    Command := Format('""%s" > "%s""', [AppPath, ProgressFileName]);
    if not Exec(ExpandConstant('{cmd}'), '/c ' + Command, '', SW_HIDE,
         ewWaitUntilTerminated, ResultCode) then
    begin
      AppError := 'Cannot start app';
    end
      else
    if ResultCode <> 0 then
    begin
      AppError := Format('App failed with code %d', [ResultCode]);
    end;
    UpdateProgress;
  finally
    { Clean up }
    KillTimer(0, Timer);
    ProgressPage.Hide;
    DeleteFile(ProgressFileName);
    ProgressPage.Free();
  end;

  if AppError <> '' then
  begin 
    { RaiseException does not work properly while TOutputProgressWizardPage is shown }
    RaiseException(AppError);
  end;
end;

在此处输入图片说明


Above was tested with a batch file like:以上是用批处理文件测试的,如:

@echo off
echo Starting
echo Doing A...
echo Extracting something...
echo Doing B...
echo Extracting something...
timeout /t 1 > nul
echo Doing C...
echo Extracting something...
echo Doing D...
echo Extracting something...
timeout /t 1 > nul
echo Doing E...
echo Extracting something...
echo Doing F...
echo Extracting something...
timeout /t 1 > nul
...

If you want to display the output as part of the installation process, instead of on a button click, see:如果要将输出显示为安装过程的一部分,而不是单击按钮,请参阅:
Execute a batch file after installation and display its output on a custom page before Finished page in Inno Setup安装后执行批处理文件并在 Inno Setup 中的 Finished 页面之前在自定义页面上显示其输出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 Inno Setup 中不打开新窗口的情况下运行 CMD 命令 - How to run a CMD command without openning a new window in Inno Setup Inno Setup - 使用 cmd.exe 执行命令而不启动批处理文件 - Inno Setup - do command with cmd.exe without launching a batch file 带有 Exec 批处理和文件 Stream 进度的 Inno Setup 安装程序页面永远不会退出 Stream 并且即使正确终止 bat 也会无限期挂起 - Inno Setup installer page with Exec batch and file Stream progress never exits Stream and hangs indefinitely even with proper bat termination Inno Setup Batch 并行编译多个安装程序 - Inno Setup Batch compile more than one installer in parallel 在bat文件或inno设置中检测窗口安装程序版本 - Detect window Installer version in bat file or inno setup 在java中输出cmd命令的问题 - Problem with the output of a cmd command in java 如何在cmd中的变量中存储命令的输出? - How to store output of command in variable in cmd? CMD - 将 cd 命令输出重定向到新文件 - CMD - redirect cd command output into new file 将命令输出重定向到cmd脚本中的变量 - Redirecting command output to variable in cmd script cmd - 将命令输出保存在参数中,然后打开浏览器 - cmd - save command output in a parameter then open browser
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM