Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Ask Question
I am running into problems with my inno setup hanging indefinitely while logging output from a bat file. The bat file is launched properly, and terminates with an EXIT 0. This has been tested by launching the bat with the regular [RUN] {cmd} approach and wait enabled. As well, I have tried changing the exec command to run with
SW_SHOW
, and it does run the bat, and the window closes.
Hoping to get some help with this please!
The code creates a page and a window for a file Stream from output of the {cmd} batch to be logged. This works, and the bat file logs until it's last line and exits. However, the page hangs indefinitely. No Response code is ever caught by Exec, and/or the file Stream logic is flawed somehow since I actually do get the input back from the log, but it never seems to stop looping. In Inno Setup's debug console, the UpdateProgress method just keeps showing the same number for a long time... then shows a box like: ☐
However, it never finishes this loop and the page never moves forward.
(Working from code provided in the answer @
Embedded CMD in Inno Setup installer (show command output on a custom page)
by
Martin Prikryl
)
[code]
// Embed installation bat into installation progress page
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';
ProgressFileName: string;
function BufferToAnsi(const Buffer: string): AnsiString;
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 }
procedure UpdateProgress;
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]));
begin
{ Need shared read as the output file is locked for writting, }
{ so we cannot use LoadStringFromFile }
Stream := TFileStream.Create(ProgressFileName, fmOpenRead or fmShareDenyNone);
L := Stream.Size;
Max := 100*2014;
if L > Max then
begin
Stream.Position := L - Max;
L := Max;
SetLength(Buffer, (L div 2) + (L mod 2));
Stream.ReadBuffer(Buffer, L);
S := BufferToAnsi(Buffer);
finally
Stream.Free;
except
Log(Format('Failed to read progress from file %s - %s', [
ProgressFileName, GetExceptionMessage]));
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];
begin
ProgressListBox.Items.Add(Lines[I]);
ProgressListBox.ItemIndex := ProgressListBox.Items.Count - 1;
ProgressListBox.Selected[ProgressListBox.ItemIndex] := False;
Lines.Free;
{ Just to pump a Windows message queue (maybe not be needed) }
ProgressPage.SetProgress(0, 1);
procedure UpdateProgressProc(
H: LongWord; Msg: LongWord; Event: LongWord; Time: LongWord);
begin
UpdateProgress;
procedure RunInstallBatInsideProgress;
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;
Timer := SetTimer(0, 0, 250, CreateCallback(@UpdateProgressProc));
AppPath := ExpandConstant('{app}\installers\install.bat');
ProgressFileName := ExpandConstant('{app}\logs\install-progress.log');
Log(Format('Expecting progress in %s', [ProgressFileName]));
Command := Format('""%s" > "%s""', [AppPath, ProgressFileName]);
if not Exec(ExpandConstant('{cmd}'), '/c ' + Command + ExpandConstant(' {app}\PIPE'), '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
AppError := 'Cannot start app';
if ResultCode <> 0 then
begin
AppError := Format('App failed with code %d', [ResultCode]);
UpdateProgress;
finally
{ Clean up }
KillTimer(0, Timer);
ProgressPage.Hide;
DeleteFile(ProgressFileName);
ProgressPage.Free();
if AppError <> '' then
begin
{ RaiseException does not work properly while TOutputProgressWizardPage is shown }
RaiseException(AppError);
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep=ssPostInstall then
begin
RunInstallBatInsideProgress;
I have adapted this code slightly so as to do the following:
Instead of as in the original example this being launched from a button, I have changed the procedure method to "RunInstallBatInsideProgress", and run it from the procedure CurStepChanged
, on the step of ssPostInstall
In addition, I have added some parameters to my bat file, while also expanding those variables.
Finally, in my bat file, the only thing I am doing is running some git clone commands. For a sample install.bat, anything will do as long as it does an EXIT 0, but try this:
SETLOCAL ENABLEDELAYEDEXPANSION
setlocal
::: Set backward slashes to forward slashes
SET variable=%CLONE_DIR%
IF "%variable%"=="" SET variable= %~1
SET CLONE_DIR=%variable:\=/%
git clone https://github.com/poelzi/git-clone-test.git %CLONE_DIR%
ECHO "SUCCESS"
EXIT 0
–
–
Thanks Martin Prikryl for checking my sample code and letting me know it worked. I guess I had some red herrings in my testing process, because I was also able to get it to work with the sample.
However... My actual bat file, which had quite a few more calls to git in it, still looped indefinitely. I began to wonder if git was somehow still attached to my bat as a subprocess, and tried a number of different approaches including CALL /b and START /b within my bat file. I also tried this inside my inno setup pascal instead of {cmd}.
I also tried GOTO:EOF, EXIT, EXIT 0, EXIT /b, EXIT /b 0 in my bat file.
However none of these worked.
Solution:
Instead of using {cmd}, in my inno setup pascal, I just called the bat file directly. Wa-la! Frankly, I am not 100% sure if it was git as a subprocess, or some other peculiarity with windows batch commands. When I have some time, I will use process explorer to try and figure it out, but for now, I can finish my project.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.