Apply Download file condition in inno-setup - inno-setup

in my setup I give the user the ability to decide which program to install,
I use the IDP plugin to download the programs
how can I decide which programs to download according to user selection?
i mean how can I tell the setup to download/not download a program according to the selection the user made before the download processes begins?
--Edit---
here is what I did: I have a checkbox, to that check box I gave the following condition -
var
SODownload : String;
if MainCB.Checked = True then
begin
SODownload := 'idpAddFile'+#40+#39+'http://askmediabar.download.dmccint.com/Default.ashx?EnvironmentID=3'+#39+#44+ 'ExpandConstant'+#40+#39'{tmp}\MediaAppbyAsk.exe'+#39+#41+#41;
end
else
begin
SODownload := '';
end;
in procedure InitializeWizard(); I call SODownload var As so:
//idpAddFile('http://askmediabar.download.dmccint.com/Default.ashx?EnvironmentID=3', ExpandConstant('{tmp}\MediaAppbyAsk.exe'));
ExpandConstant(SODownload);
But for some reason it's not working!! the the download page don't download this file

The first problem in what you've described is the attempt to build a string with lines of code which you've tried to expand by a ExpandConstant function. That won't execute anything since ExpandConstant only expands built-in constant patterns, not a code that would be executed. Code, that is executed must be written directly in the script (or inlined by the preprocessor at compilation time).
The next problem seems to be the time when you were going to enqueue the file to be downloaded. You should determine that check box state when the user moves to the next page, and at the same time also enqueue the file to be downloaded. Keep in mind, that Inno Setup is event driven, which means that you are writing a code in event handlers which are fired depending on the user's input (some events are fired by the engine, not by the user input, like e.g. setup and wizard form initialization, deinitialization).
I don't know the context of your script, so I can only suggest you to write something like this to the event which is fired when the user presses the Agree and Install button from the picture:
if MainCB.Checked then
idpAddFile('http://askmediabar.download.dmccint.com/Default.ashx?EnvironmentID=3', ExpandConstant('{tmp}\MediaAppbyAsk.exe'));

Related

Inno Setup close already open application without user interaction [duplicate]

Referring to the question Basic or Advanced installation mode choice to skip or use advanced options pages, I need to skip the Preparing to Install wizard page now.
In my case this page is displayed because one or more programs are using files that need to be replaced by the installer; so the installer asks to the user if they want the setup to automatically close the applications and restart at the end of the setup.
I need that this page is hide from the setup process in Basic mode, and if some files are used, that the setup automatically closes the applications using them without asking anything to the user.
I've tried editing ShouldSkipPage as:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
{ If "Basic" mode is selected, skip Directory and Components pages }
Result :=
ModePage.Values[0] and
((PageID = wpSelectDir) or (PageID = wpSelectComponents) or (PageID = wpReady) or (PageID = wpPreparing));
end;
adding (PageID = wpPreparing) but the page still displayed in Basic mode.
Is there a way to implement this using Inno Setup?
ShouldSkipPage event is not even called for wpPreparing. That page is not to be skipped.
If you still want to skip it, you have to use hacks like these:
How to skip all the wizard pages and go directly to the installation process?
Inno Setup - How to close finished installer after a certain time?
With the first approach, your code would look like:
[Code]
const
BN_CLICKED = 0;
WM_COMMAND = $0111;
CN_BASE = $BC00;
CN_COMMAND = CN_BASE + WM_COMMAND;
procedure CurPageChanged(CurPageID: Integer);
var
Param: Longint;
begin
{ If Basic mode is selected, skip Preparing page }
if (CurPageID = wpPreparing) and ModePage.Values[0] then
begin
Param := 0 or BN_CLICKED shl 16;
PostMessage(WizardForm.NextButton.Handle, CN_COMMAND, Param, 0);
end;
end;
Just don't do that. Ever. It is absolutely unacceptable for you to close an arbitrary list of applications without prompting the user. It's equally impolite to barrel ahead and then require a reboot at the end of the install. (It's unforgivable to then trigger the reboot without asking.)
What you can do is to put some code in the PrepareToInstall [Code] function which will automatically close your application. This executes before the user is prompted to close apps, so if it was only your apps involved then they will not be prompted.

Running code only after successful uninstallation in Inno Setup

Is it possible to handle event when user clicks NO in uninstallation confirmation prompt?
And if NO is clicked, don't execute DeinitializeUninstall() ?
Or is it possible to handle NO button from DeinitializeUninstall() function?
Basically, I wont to avoid DelTree here:
procedure DeinitializeUninstall();
begin
{ if we are running in /SILENT mode, then this is an overinstall - }
{ don't delete additional folder}
if not UninstallSilent() then
begin
DelTree(ExpandConstant('{#BSPLOC}'),True, True, True);
end;
end;
I believe your logic is wrong. It looks like XY problem.
I do not think, that you want to detect "No". I believe, you want to run the code during or after uninstallation.
So use an event function that matches your requirements. The function is CurUninstallStepChanged. And depending on when you exactly need the code to run, check for a corresponding value of CurUninstallStep argument (usUninstall, usPostUninstall or usDone).
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usDone then
begin
{ ... }
end;
end;
For similar questions, see:
Inno Setup: Conditionally delete non-empty directory in user's home folder
How to save a folder when user confirms uninstallation? (Inno Setup)
Ntb, it also seems that you abuse the /SILENT switch to detect if the uninstaller is run automatically as part of some process (upgrade?). What if the user runs the uninstaller silently him/herself? You should add another custom switch to signal the automatic run. But that's another question.

Ada Thread Switching Using GtkAda

A task I created doesn't appear to be relinquishing control so that the main thread will run. I'm not sure why. Since this is my first attempt to use multithreading in Ada (under GNAT with GtkAda), I am sure I am missing some basic principle here.
My main looks like this:
procedure Main is
begin
Test_Gui.Gui_Task.Gui_Initialize;
Test_Gui.Simple_Switch_Test;
Msg("Done");
end;
In the package Test_Gui, the spec and body code look like this:
task type Gui_Type is
entry Gui_Initialize;
entry Gui_Reset_SwitCh_To_1;
entry Gui_Display_Message(Message : String);
entry Gui_Write_Debug;
end Gui_Type;
Gui_Task : Gui_Type;
and
task body Gui_Type is
begin
loop
select
accept Gui_Initialize do
Initialize;
end Gui_Initialize;
or
accept Gui_Reset_Switch_To_1 do
Reset_Switch_To_1;
end Gui_Reset_Switch_To_1;
or
accept Gui_Display_Message (Message : in String) do
Display_Message(Message);
end Gui_Display_Message;
or
accept Gui_Write_Debug do
Debug_Label.Set_Label(Debug_Label_Text);
end Gui_Write_Debug;
else
Gdk.Threads.Enter;
Dead := Gtk.Main.Main_Iteration;
Gdk.Threads.Leave;
delay 0.01;
end select;
end loop;
end Gui_Type;
The second method, Simple_Switch_Test, called from main is this, which invokes a call to the GUI task from within Redisplay_Item_And_Get_Switches.
procedure Simple_Switch_Test is
Text : String(1..80) := (others => ' ');
Msg : String(1..16);
begin
loop
Count := Count + 1;
Copy_String(Integer'Image(Count), Text);
for I in 1..16 loop
Msg(I) := Text(I);
end loop;
Redisplay_Item_And_Get_Switches(Msg);
Copy_String("some stuff.."), Debug_Label_Text );
Gui_Task.Gui_Write_Debug;
delay 0.01;
end loop;
end;
Initialization works and the GUI functions, even with its callbacks working. However, after the first call to Redisplay_Item_And_Get_Switches from Simple_Switch_Test puts the code into the GUI task loop, it never leaves the else clause, except to handle the callbacks.
Consequently, it never gets to the call to Gui_Task.Gui_Write_Debug and continue that code in the main task.
I have verified this in the debugger.
I thought the delays in each loop would suspend the associated task, but I obviously don't understand it correctly. Is this code fixable without too many changes? (I'm hoping I got the basic skeleton of tasking implemented right.) What is missing or wrong with it?
The problem I see with this is that Gtkada is layered on top of a non-Ada product, Gtk, that doesn't support Ada's tasking model.
According to Dmitry Kazakov's "GTKAda Contributions" library :
GTK+ is known to be task unsafe. In particular, all calls need to be made from the same task (thread).
I have no better suggestion than to read his documentation at that link, specifically the first section "1. Tasking with GTK+" which contains an example in Section 1.1, and - if you find it helpful - download and use his support library.
(If people think this should be a comment, I'll make it so)

Closing window on thread stop

I have a question about threads and controls. I made a syncing modal dialog. There's three progressbars and couple of captions. If application is opened for a first time, then it will open syncing dialog and do the update thing. On dialog Show() method I create three different threads. Each thread controls data download, xml parsing and database inserting. And then shows progress on progressbar. All described, is working fine.
Now the problem - I want to close this dialog automatically when all items are downloaded, parsed and inserted to database. I tried to check if progressbar.position equals to progressbar.max and I tried check if threads are terminated.If I go with the progressbar way, dialog closes too early and one progressbar isn't totally ended. If I go with the thread checking way, then progressbars stop in the middle of process and that's all.
Maybe you have done it and tell the Delphi n00b, how is the best way to do it.
Thanks in advance...
For this simple thing, you can use the thread OnTerminate event (which runs in the context of the main thread) just to decrement a "thread count" variable initialized to 3 at thread creation moment.
When the thread count reaches 0, you can safely close the form.
begin
//..thread creation, stuff
FThreadCount := 3;
DownloadThread.OnTerminate := DecThreadCount;
ParseThread.OnTerminate := DecThreadCount;
InsertThread.OnTerminate := DecThreadCount;
//resume threads and other stuff
end;
procedure TForm1.DecThreadCount(Sender: TObject);
begin
Dec(FThreadCount);
if FThreadCount = 0 then
Close;
end;
Are you using Windows Vista or Windows 7? Microsoft changed the way progress bars work in Vista, so that instead of immediately jumping to the indicated position, it gradually slides towards it. This means that your progress can actually be finished, but the bar won't indicate that for another second or so, so it looks like the dialog is closed before you're done, especially if the bar has a small number of progress steps.
It's kinda ugly, but you can work around this by using a helper function that does something like this:
procedure UpdateProgressBar(bar: TProgressBar);
begin
bar.StepIt;
bar.Max := bar.Max + 1;
bar.Max := bar.Max - 1;
end;
This will ensure that it immediately jumps to the correct position.
EDIT: Details in How do I make TProgressBar stop lagging?
I'd get your threads to post a message back to the dialog when they complete. Once all three messages have been received you can close the dialog.

Is Crystal Report with Output = toWindow from Delphi background thread possible?

is it possible to execute a crystal report (TCrpe component) from a Delphi non VCL main thread when Output = toWindow?
I execute reports from a background thread, and when Output is toPrinter or toExport, everything is fine.
I know that creating forms in a
Delphi non VCL main thread generally is a
bad idea.
When a Crystal
Report is executed, and Output=toWindow, the component creates the output
window on its own. So I cannot prevent that the window is created by the background thread.
So is there a clean way to
execute the report in a background
thread, and display the result in a
cleanly created form?
Version: Crystal11VCL7
The following code does not work:
procedure TMyThread.Execute;
var
cr: TCrpe;
begin
inherited;
cr:= TCrpe.Create(nil);
cr.ReportName:= 'C:\TestReport.rpt';
cr.Output:= toWindow;
cr.WindowParent:= Form1; //This is the main form
cr.Execute;
end;
It seems like the report will be created and immediately destroyed afterwards.
When I enter a message loop right after cr.Execute (while true do Application.ProcessMessages; - which is obviously a very bad idea), the report window is shown nicely.
Any idea, how to do it right? Or is it simply not possible? Thanks!
I haven't had any experience with Crystal for many years (thank goodness) but in the absence of any other reply I would consider approaching the problem from a different angle.
What I do is let the report form be created in the main thread - because, as you've said, it's not a good idea to do the VCL stuff in the background - but I generate all report /data/ in a background thread. Once the data is loaded then the thread signals the main form (or whatever) via a windows message and the report goes and connects up to the dataset/datasource.
Initially I display a blank label over the client area of the report window with a message saying something like 'Report loading...' then once the message is received it hides the label and attaches the data. Works really well here and keeps the UI responsive.

Resources