Why does Inno Setup ignore DefaultDirName - inno-setup

Running Inno Setup 5.5.6. I corrected an error in my DefaultDirName value, but no matter what I do, the program continues to try to install in the old, erroneous location. Even when I set it to a value matching one of the examples:
DefaultDirName={pf}\My Program
the program continues to choose the old, incorrect path.
How do I get Inno to use the corrected DefaultDirName?

Even though the previous install went to the wrong destination directory, the install did complete. According to the documentation for DefaultDirName:
If UsePreviousAppDir is yes (the default) and Setup finds a previous
version of the same application is already installed, it will
substitute the default directory name with the directory selected
previously.
So my previous installation was overriding the new DefaultDirName. Once I uninstalled the program and re-ran the installer, it began using my corrected DefaultDirName.

Set the AppendDefaultDirName directive to no, e.g.:
[Setup]
...
AppendDefaultDirName=no
As the reference says (emphasized by me):
By default, when a folder in the dialog displayed by the Browse...
button on the Select Destination Location wizard page is clicked,
Setup automatically appends the last component of DefaultDirName onto
the new path.
For example, if DefaultDirName is {pf}\My Program and "Z:\" is clicked, the new path will become "Z:\My Program".
Setting this directive to no disables the aforementioned behavior. In
addition, it causes a Make New Folder button to appear on the dialog.

Related

How can I tell (programmatically) when an Installshield installer is running silently?

I have a history of Installscript MSI installers (that have been replaced by Basic MSI installers), and when I uninstall them I need to know if the uninstall is being run silently or not. I run some custom code that checks for the existence of .iss files (necessary for silent uninstalls) and if they're not there I pop up a message saying that the files aren't where they're expected to be. The problem is that when the program is uninstalled from the Control Panel (not silently) this code runs and displays the message. So I need a system variable that will tell me it's running in silent mode so when it's not I can suppress the message.
I can't find anything that tells me this. Does anyone know of a way I can tell programmatically?
Assuming you want to detect a silent install from within the install, the answer depends on the project type:
InstallScript projects can check whether they're running silently by comparing the MODE system variable to SILENTMODE
Basic MSIs can compare the UILevel property to 2
InstallScript MSIs can check whichever is more relevant for the context (using MsiGetProperty to retrieve UILevel, if necessary, but watch out in deferred custom actions; they'll need to pass it through CustomActionData).
For completeness, but unlikely to be relevant for your question, Suites can reference the ISSilentInstall property.

How do deal with Installshield installations that extract an MSI with pywinauto?

I am trying to automate an installation that starts out with an InstallShield setup.exe. That kicks off the installation of a MS Visual C++ redistributable. That leads to an error about Adobe Flash not being up to date. I have asked about how to deal with that here:
Error during automated software install using pywinauto
Once I click OK for the Adobe dialog(have to use pyautogui.click() for this for now) I see that there is an .msi being extracted. I have followed the install and it puts it into a new Temp folder under my Users\AppData directory.
How do you get pywinauto to find this new application? I have tried using
adobe = Application().connect(title_re="MyInstaller",class_name="#32770", visible_only=True)
And then try to print_control_identifiers() but get this error:
AttributeError: Neither GUI element (wrapper) nor wrapper method 'print_control_identifiers' were found (typo?)
I have checked Spy++ and Inspect and AutoIT to find the class which I can. I can't use the procid as it will always change.
Any thoughts on how to attach to the .msi process so I can then connect() to it?
Edit:
Is there a way to regex pywinauto to point to a path if I know where MyProgram.msi is? It seems to be in C:\Users\me\AppData\Local\Temp{xxx}\MyProgram.msi as I found several copies there. Thanks!
Add timeout=10 or whatever you need to connect() params. Current default timeout is zero, but it should be timings.Timings.window_find_timeout which is 5 sec by default.
Auto detection of spawned child process is planned for next major release (as well as default timeout fix).
For running an unpacked .msi file you need msiexec standard Windows command in method .start(). Play with it in cmd.exe manually first starting from msiexec /?.
Here is how I deal with the fact that InstallShield exe extracts to an .msi in (into my DownloadedInstallations folder). Yes, timeout is important, but also identifying the new msi window that opens is too. (Also, I found that wait_for_idle had to be FALSE but don't remember why. YMMV :) ).
exe = pywinauto.Application(backend="uia").start(exepath, wait_for_idle=False)
Now it's going to unzip the .exe into .msi installer and that could take a while, and since the .exe window might be named the same as the .msi window must be careful not to attach to the exe window too early and must wait for the .msi window to open!! So, add an appropriate timeout in seconds. The dialog window may not exist yet here, so it's CRITICAL to use class_name of MsiDialogCloseClass especially if the title of the exe and msi are the same. This will identify the .msi window specifically, whenever it arrives.
title = "Enter Title of your App - InstallShield Wizard"
msi = pywinauto.Application(backend="uia").connect(title=title,
class_name="MsiDialogCloseClass",timeout=120)
And for the final touch, in a line I always forget, must use the title again to get the dialog window (for reasons I don't yet understand)
dlg = msi[title]
EXTREMELY HELPFUL way to view all control identifiers at this point is:
print(dlg.print_control_identifiers())
This is what hours of trial and error yielded. To continue on, now you can click buttons, like this:
dlg.Next.wait("ready",timeout=2)
dlg.Next.click()
And to click on radio buttons, this works (there may be other ways that do, but I could never find how to get a handle on the buttons by name)
dlg['I &accept the terms in the License Agreement'].wait('enabled').click()
Then moving on
dlg.Next.click()
dlg.Install.wait("enabled",timeout=5)
dlg.Install.click()

Change Inno Setup messages from Pascal code

I need to change ConfirmUninstall, UninstalledMost (just in case), and UninstalledAll specifically from script to set a condition. Something like this:
if FileExists(ExpandConstant('{app}\Slash.exe')) then
SetupMessage(msgConfirmUninstall) := FmtMessage(SetupMessage(msgConfirmUninstall), ['Dagon Slasher'])
else if FileExists(ExpandConstant('{app}\Frank.exe')) then
SetupMessage(msgConfirmUninstall) := FmtMessage(SetupMessage(msgConfirmUninstall), ['Dagon Frankenstein'])
else
SetupMessage(msgConfirmUninstall) := FmtMessage(SetupMessage(msgConfirmUninstall), ['Dagon Video Tools']);
But this doesn't work. These messages are used in MsgBoxes, so I can't think of any other way. Running in silent mode is not really suitable for me, since setup will run uninstall if the programs (or one of them) has already been installed, so I don't want the user to accidentally uninstall the program by running the setup.
You cannot change these easily, see:
Replace or customize modal uninstallation windows in Inno Setup
Regarding the silent uninstall solution: I do not understand your problem with "setup will run uninstall if the programs (or one of them) has already been installed".
I assume you run the uninstaller only after the user confirms (s)he wants to install the new version, so you actually want to run the uninstaller silently, right?
And anyway, there's nothing that prevents you from running the uninstaller non-silently from your installer, even if the entry in "Add/Remove programs" refers to "silent" installation.
You can use generic messages that covers all setup types:
[Messages]
ConfirmUninstall=Are you sure you want to completely remove this game?
As your uninstall messages depend on a type of the installed application, you can modify the installer to:
Create custom "type" page (like a menu) as the very first one.
Once the user selects the "type", restart the installer with a custom switch (e.g. /APPTYPE=slasher) and exit.
Once the installer is (re-)run with the /APPTYPE, you know from the beginning, what component/type you are installing and hence you can set the AppName accordingly (using a scripted constant).
Of course, you skip the custom "type" page.
This is actually not difficult to implement. The only drawback is that the setup window is "recreated" after the user selects the "type".
I've sketched this solution already in my answer to Inno Setup Change AppName based on component(s) selected.

Inno setup a simple update

Is it possible to use same Inno Setup installer for installing new or updating/upgrading application. For example If the application is already installed the installer will check current version against newly availible. If it is true then I would like the installation procedure to be silent, meaning showing only the progress of update and not all availible installation features (e.g. folder location e.t.c). Thanks.
=======
The solution to the problem was :
Passing the parameters /SILENT/SUPPRESSMSGBOXES
taken from
http://www.jrsoftware.org/ishelp/index.php?topic=setupcmdline
For the standard screens, simply add the following to your [Setup] section:
[Setup]
DisableDirPage=auto
DisableProgramGroupPage=auto
This will automatically hide the directory and group selection pages on subsequent installs (using the previously selected values, by default, unless you've used other settings that disable that behaviour).
Components and Tasks will still display, but that's usually a good thing as it allows the user to add additional components or re-perform certain tasks. (Note that you can use the checkedonce flag on [Tasks] entries to only tick them by default during the initial install, but allow the user to re-tick them manually if required.)
It's possible to skip even more pages through use of [Code], but this is rarely necessary.
Another option is that if the installer is being run from your application itself (eg. as part of a "Check for new versions" task) you can use the /SILENT command line parameter to hide the normal interactive UI.

Is it possible to change the uninstall icon in Inno Setup?

From what i've read it looks like that is no parameter that allows you to change the uninstall icon:
[Setup]: UninstallIconFile
Description:
Obsolete in 5.0.0. As Setup and Uninstall have been merged into a single executable, setting a custom icon for Uninstall is no longer possible.
So, is there another way to change this icon?
I'm asking because if, for example you have only your launch exe, an readme and the uninstall, users may accidentally click on the uninstall instead of lauch, which is a little bit annoying.
Thanks.
To change the uninstall executable icon, you have to change the installer executable icon, as it is the same exe, using the SetupIconFile setup section directive.
For example:
SetupIconFile=MyProgSetup.ico
You can also change the Icon that is displayed on the control panel, setting the UninstallDisplayIcon setup section directive
For example:
UninstallDisplayIcon={app}\MyProg.exe,4
;or
UninstallDisplayIcon={app}\Uninstaller.ico
Your Uninstall Icon would only be the same as your application icon if you set the IconFilename setting to the same icon as the application or have the SetupIconFile setting set to the same as your application.
By default, the Uninstall Icon is the same as the Setup icon. If you really want to make sure the user isn't confused, you can set the IconFilename parameter in the [Icons] section to your uninstall icon. Something like:
Name: "{group}\Uninstall My Program"; Filename: "{uninstallexe}"; IconFilename: "{app}\uninstall.ico"
You would need to include the uninstall.ico in your [Files] section as well.
The "setup.exe" file icon can be set by SetupIconFile
The control panel icon can be set by UninstallDiaplayIcon
In script file, I added these lines to the [Setup] section:
[Setup]
.
.
.
; Icons for setup.exe and control panel
UninstallDisplayIcon={app}\Icon.ico
SetupIconFile="Icon.ico"
Note that:
UninstallDisplayIcon is given {app} path
SetupIconFile uses absolute path, because the setup program to be created by Inno (by compiling) is yet to have {app} before my program is installed.
jachguate's answer has given me the best clue to figure out my case. This solution is tested on a few Windows 10 computers.
In Win10 This works for me when you need to have the same icon as the application icon:
UninstallDisplayIcon={app}\youApp.exe
Set the uninstaller icon as SetupIconFile, then change the resource icon in the compiled .exe. (There are many programs to do that like the ResHacker)
If you see the compiled .exe still with the uninstaller icon, just move that .exe to another folder and you will notice.

Resources