1

The scenario is that we wrote a console application, that we want to call during an Inno Setup and read its output. In contrast to this problem it is necessary to read this output from Inno Setup while the other program is still running. The output shall contain progress information of the runnig application (double or int values), that we want to display in Inno with the ProgressGauge. The app is a simple executable written in C# and can run from some seconds to several minutes.

Is this possible and if yes, can it be done without freezing the GUI of Inno Setup (as the application can take some time)?

Community
  • 1
  • 1
Nurio
  • 193
  • 11
  • 1
    There are few ways... One might be to pass to that console application handle to the InnoSetup's progress bar and drive it through the [`progress bar messages`](http://msdn.microsoft.com/en-us/library/windows/desktop/ff485990(v=vs.85).aspx) from your application. Another way could be to make from your application DLL library passing a callback to an InnoSetup function where would you update the progress bar. Yet another option might be COM. And yet another... (etc.) – TLama Sep 10 '13 at 16:28
  • Your first suggestion helped me solve this problem. I didn't knew about the progress bar messages so thanks for the hint! – Nurio Sep 13 '13 at 16:05
  • You're welcome! Yup, direct messaging is usually the easiest solution, but also quite unsafe if you consider that window might be recreated for some reason (e.g. changing a window style). But I can confirm you that if you don't explicitly manipulate with window style after you pass the progres handle into your application, the handle of the progress bar remain persistent. – TLama Sep 13 '13 at 16:09
  • I have another feature, that changes WizardForm.Borderstyle and the window size at some point and may be combined with this direct messaging here. But those Form-changes only appears after the install-process is complete (when 100% is hit and thus I'm done sending the messages) and so it shouldn't intervene. – Nurio Sep 13 '13 at 16:18
  • Changing `BorderStyle` recreates the window (changing size doesn't), but you're safe if you pass the progress handle after that. Feel free to post your solution and accept it (since I must go now). – TLama Sep 13 '13 at 16:21

1 Answers1

3

With TLama pointing to the progress bar messages I was able to solve the problem.

At first I needed to pass the progress bar handle from Inno to my C# app. For this I created a function that would return me the int-pointer as a string

function GetProgressHandle(Param: String): String;
begin
  Result := Format('%d',[WizardForm.ProgressGauge.Handle]);
end;

and use it in the Run-section when calling my app:

[Run]
Filename: "{app}\myApp.exe"; Parameters: "{code:GetProgressHandle}"; ....

In C# I read the int-pointer from the console arguments and use it to create an IntPtr:

IntPtr pointer = new IntPtr(Int32.Parse(args[0]));

To send the messages to the progress bar I imported user32.dll and re-defined the needed constants, that normally can be found in commctrl.h:

[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

public const uint PBM_SETRANGE = 0x401;
public const uint PBM_SETPOS = 0x402;

Finally, I could set the range of the progress bar from 0 to max and a specific position pos with

PostMessage(pointer, PBM_SETRANGE, (IntPtr)0, (IntPtr)(max << 16));    
PostMessage(pointer, PBM_SETPOS, (IntPtr)pos, (IntPtr)0);

NOTE: Changing the progress bar position didn't seem to update the Inno Setup Window immediately. I tested it by increasing the position every 500 ms but there where noticeable differences (pauses were more in the range of ca. 0.2-0.8 ms). For my case it is not important that changing the progress bar is accurately timed, but I assume that the Inno Setup window can be updated in a similar way (with the specific handle and a different message-constant) for those who need this.

Nurio
  • 193
  • 11