本文介绍了Inno Setup安装程序中的嵌入式CMD(在自定义页面上显示命令输出)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我创建了一个输入页面,该页面使用从这些输入中创建的变量来执行命令行应用程序。自然地, cmd 窗口在我的屏幕上弹出。我想知道是否有任何方法可以将 cmd 窗口(或输出)嵌入到我的Inno Setup安装程序页面上。 我正在运行Inno Setup 5.6.1(因为与Windows XP兼容),但是如果必须切换到最新版本,我可以。 [代码] var 邮件:TInputQueryWizardPage; 最终:TWizardPage; BotonIniciar:Tbutton; 程序BotonIniciarOnClick(Sender:TObject); 开始 WizardForm.NextButton.Onclick(nil); Exec(ExpandConstant('{tmp} \imapsync.exe'),'MAIL.Values [0]',',SW_SHOW, ewWaitUntilTerminated,ResultCode); 结尾; 程序InitializeWizard; 开始邮件:= CreateInputQueryPage(wpWelcome,’’,’,’); MAIL.Add(‘请输入您的信息’,错); 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; 结尾; 我可能会丢失部分代码,但我认为这是可以理解的。 Fist Ii创建输入页面,然后创建一个带有 OnClick 属性的按钮,该按钮调用 BotonIniciarOnClick 过程。 实际上,该代码非常有用。但是正如我说的那样,我有一个 cmd 浮动窗口。 我希望看到这样的内容: 这只是我从Google拍摄的随机图像。 我想要看到的内容类似于安装程序上的标准显示详细信息选项解决方案您可以将命令输出重定向到文件,并监视文件中的更改,将其加载到列表框(或备忘录框)中。 var ProgressPage:TOutputProgressWizardPage; ProgressListBox:TNewListBox; 函数SetTimer( Wnd:LongWord; IDEvent,Elapse:LongWord; TimerFunc:LongWord):LongWord; 外部 [email protected] stdcall; 函数KillTimer(hWnd:LongWord; uIDEvent:LongWord):BOOL; 外部 [email protected] stdcall; var ProgressFileName:字符串; 函数BufferToAnsi(con​​st Buffer:string):AnsiString; var W:单词; I:整数; begin SetLength(Result,Length(Buffer)* 2); for I:= 1到Length(Buffer)做开始 W:= Ord(Buffer [I]); 结果[(I * 2)]:= Chr(W shr 8); {高字节} 结果[(I * 2)-1]:= Chr(Byte(W)); {低字节} 结尾; 结尾; 过程UpdateProgress; var S:AnsiString; I,L,Max:整数; 缓冲区:字符串; 流:TFileStream; 行:TStringList; 如果没有FileExists(ProgressFileName),则以开头;然后以开头。 Log(Format(进度文件%s不存在,[ProgressFileName])); 结束否则开始尝试 {需要共享读取,因为输出文件被锁定写,} {所以我们不能使用LoadStringFromFile} Stream:= TFileStream.Create(ProgressFileName,fmOpenRead或fmShareDenyNone); try L:= Stream.Size; Max:= 100 * 2014;如果L> 最大然后开始 Stream.Position:= L-Max; L:=最大值; 结尾; SetLength(Buffer,(L div 2)+(L mod 2)); Stream.ReadBuffer(Buffer,L); S:= BufferToAnsi(Buffer); 最后流。免费; 结尾; ,但除外Log(Format(无法从文件%s-%s中读取进度,[[ ProgressFileName,GetExceptionMessage]))); 结尾; 结尾;如果S<> ’’然后开始 Log(’Progress len =’+ IntToStr(Length(S))); 行:= TStringList.Create(); Lines.Text:= S; I的:Lines。= 0-如果I< 1则从开始ProgressListBox.Items.Count然后开始 ProgressListBox.Items [I]:=行[I]; 结束否则开始 ProgressListBox.Items.Add(Lines [I]); 结束结束; ProgressListBox.ItemIndex:= ProgressListBox.Items.Count-1; ProgressListBox.Selected [ProgressListBox.ItemIndex]:= False; 行。免费; 结尾; {仅用于泵送Windows消息队列(可能不需要)} ProgressPage.SetProgress(0,1); 结尾; 过程UpdateProgressProc( H:LongWord; Msg:LongWord; Event:LongWord; Time:LongWord); 开始 UpdateProgress; 结尾; 程序BotonIniciarOnClick(Sender:TObject); var ResultCode:整数; 计时器:LongWord; AppPath:字符串; AppError:字符串; 命令:字符串; 开始 ProgressPage:= $​​ b $ b CreateOutputProgressPage(‘正在安装某些东西’,‘请等待,直到完成...’); ProgressPage.Show(); ProgressListBox:= TNewListBox.Create(WizardForm); ProgressListBox.Parent:= ProgressPage.Surface; ProgressListBox.Top:= 0; ProgressListBox.Left:= 0; ProgressListBox.Width:= ProgressPage.SurfaceWidth; ProgressListBox.Height:= ProgressPage.SurfaceHeight; {UpdateProgressProc中的Fake SetProgress调用将显示它,} {确保用户不会看到它} ProgressPage.ProgressBar.Top:= -100; 试试 Timer:= SetTimer(0,0,250,CreateCallback(@UpdateProgressProc)); ExtractTemporaryFile('install.bat'); AppPath:= ExpandConstant(’{tmp} \install.bat’); ProgressFileName:= ExpandConstant(’{tmp} \progress.txt’); 日志(格式(期待进度,%s,[ProgressFileName])); 命令:=格式(%s>%s [AppPath,ProgressFileName]); 如果不是Exec(ExpandConstant('{cmd}'),'/ c'+ Command,'',SW_HIDE, ewWaitUntilTerminated,ResultCode)然后开始 AppError:= '无法启动应用程序'; 结束,否则,如果ResultCode<> 0,然后开始 AppError:=格式(应用程序失败,代码为%d,[ResultCode]); 结尾; UpdateProgress; 最终 {清理} KillTimer(0,Timer); ProgressPage.Hide; DeleteFile(ProgressFileName); ProgressPage.Free(); 结尾; 如果AppError<> ’’然后开始 {在显示TOutputProgressWizardPage时RaiseException无法正常工作} RaiseException(AppError); 结尾; 结尾; 上面已用以下批处理文件测试过: @echo off echo开始 echo正在执行A ... echo提取某物... echo正在执行B ... echo提取某物... 超时/ t 1> nul echo正在执行... echo正在提取... echo正在执行... echo正在提取... 超时/ t 1> ; nul echo正在执行... echo正在提取... echo正在执行... echo正在提取... 超时/ t 1> ; nul ... 如果要将输出显示为一部分安装过程的详细信息,而不是单击按钮,请参阅: 在安装并显示后执行批处理文件其输出在Inno Setup中完成页面之前的自定义页面上 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. I would like to know if there is any way to embed the cmd window (or the output) on my Inno Setup installer page.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.[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.Actually, the code works great. But as I said I'm having a floating cmd window.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 '[email protected] stdcall';function KillTimer(hWnd: LongWord; uIDEvent: LongWord): BOOL; external '[email protected] 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 offecho Startingecho Doing A...echo Extracting something...echo Doing B...echo Extracting something...timeout /t 1 > nulecho Doing C...echo Extracting something...echo Doing D...echo Extracting something...timeout /t 1 > nulecho 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安装程序中的嵌入式CMD(在自定义页面上显示命令输出)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-11 01:23