Why doesn't Inno Setup constant {userdesktop} work in OutputDir directive and how to fix it? - inno-setup

I created Inno Setup script, which works perfectly, but I wanted to change OutputDir to create the output file on my desktop. But instead of creating output file on desktop it was creating subfolder {userdesktop} at the same directory, where script is and output was inside.
I found solution so far, but I believe there should be better way. What am I missing?
; these attempts didn't work
[Setup]
OutputDir={userdesktop}
; some more attampts:
OutputDir=userdesktop
OutputDir=userdesktop:
OutputDir="{userdesktop}"
; this workaround worked for me
[Setup]
OutputDir=userdocs:..\Desktop

Constants like {userdesktop} are resolved on install time (on the target user's machine), not on compile time (on your development machine). So it makes no sense to use constants in compile-time only directive like OutputDir. And actually it's not possible to use them at all (as it's useless).
With the default user profile directory layout, use you can use the userdocs: prefix, as you did:
[Setup]
OutputDir=userdocs:..\Desktop
Though it's not a perfect solution, as the "Documents" folder can be moved by the user and then the userdocs:..\Desktop will not point to the desktop.
A more reliable solution is to use USERPROFILE environment variable using GetEnv preprocessor function:
[Setup]
OutputDir={#GetEnv('USERPROFILE')}\Desktop

Related

How to get the file name of the current Inno Setup script file?

I want to obtain the name of the current Inno Setup script file in order to name the generated setup package after it. For example if the current Inno Setup script file is "MyAppSetup.iss", I want the generated setup file to be "MyAppSetup.exe".
The name of the generated setup file is controlled by the OutputBaseFilename declaration in the [Setup] section of Inno Setup, so if there's an Inno Setup preprocessor variable that returns the name of the current script file that would be great. Something like:
OutputBaseFilename={#SourceFileName}.exe
Unfortunately, there isn't an Inno Setup preprocessor variable {#SourceFileName}. I know about the {#SourcePath} variable, but it returns the directory path of the script file without it's file name. Here's a list with some predefined Inno Setup preprocessor variables, but none of them seems to return the name of the current script file. I hoped the __FILE__ variable would work after reading the descriptions of the variables in the list, but it returns an empty string.
It's not possible. There's the __FILE__, but it has a value for #included files only.
If you never have more than one .iss file in a directory, you can use the FindFirst to find its name.
#define ScriptFindHandle = FindFirst(SourcePath + "\*.iss", 0)
#if !ScriptFindHandle
#error "No script found"
#endif
#define SourceFileName = FindGetFileName(ScriptFindHandle)
#if FindNext(ScriptFindHandle)
#error "More than one script found"
#endif
#expr FindClose(ScriptFindHandle)
#define SourceBaseName = RemoveFileExt(SourceFileName)
Then to name the setup file after the current script file in the [Setup] section you should use:
[Setup]
OutputBaseFilename={#SourceBaseName}
But if you are automating compilation of a large number of installers, I assume you use a command-line compilation. So then you can simply pass a script name in a parent batch file (or a similar script):
set SCRIPT=MyAppSetup
"C:\Program Files (x86)\Inno Setup 5\ISCC.exe" %SCRIPT%.iss /DBaseName=%SCRIPT%
Use the BaseName like:
[Setup]
OutputBaseFilename={#BaseName}
I know this is not exactly what you want, but why can't you do this:
[ISPP]
#define ScriptFileName "MyAppSetup"
[Setup]
AppPublisher={#AppPublisher}
OutputBaseFilename={#ScriptFileName}Setup
Then all you need to do it edit the one reference at the top of your file.
Update
I came across this link where it states:
You can use:
#expr SetSetupSetting("OutputBaseFilename", sFileName)
However, the difficult part is automatically finding the file name.
You could use the following ISPP functions to do additional
compile-time tasks that can't be done by ISPP built-in functions:
Exec function: Executes an external program to do the additional
functionality, and writes the result to an INI file. By default Exec
waits for the process to finish.
ReadIni function: Reads the result
from the INI file, and incorporates it into the script.
How do you determine the file name is up to you. Perhaps you could
enumerate the windows and extract the file name from Inno Setup
window title, but because you may be having multiple Inno Setup
copies open, you must find a reliable way to do it. Inno adds
[Compiling] to the title during compilation which makes it easier to
find which copy is being used, but there could be multiple copies in
compiling state. You can be absolutely sure about which copy is
running your program by checking the process ID of the parent
process, you can get that by using Process32First/Process32Next and
checking the 32ParentProcessID for your process. Too much work, I
know..
But there was another comment:
(If you're doing an automated build, though, you can set the output
filename from the command line -- that might be sufficient for what
you actually want.)
So have you considered using a batch file and the command line? Then you can use the benefits of batch lines with your compiling. Information is provided here about using the current file name in batch files.
I personally think that the batch file compilation is the way to go.

Find out which process prevents to modify application data files

Sometimes it happens, that some files of my application are used by some processes. For example, user opens application log, or something like that, and forgets to close it. This causes some errors while installing/upgrading/uninstalling. In such cases, I'd like to find out, what process is using file, and show user a message, indicating, that files are used.
Is it possible in Inno Setup to find out, what process prevents script from modifying file? At least, when I'm trying to do this in Code section.
The Inno Setup can automatically check, if the installed files are locked by some processes, and offer a user to close (and restart later) the applications automatically (since 5.5.0).
Make sure the CloseApplications directive is set to its default value yes.
Though by default, only *.exe,*.dll,*.chm files are checked. If you want to check also other or all other files, modify the CloseApplicationsFilter directive:
[Setup]
; default
CloseApplications=yes
; check all files
CloseApplicationsFilter=*.*
If you are installing some files by a code, use the RegisterExtraCloseApplicationsResources event function:
procedure RegisterExtraCloseApplicationsResources;
begin
RegisterExtraCloseApplicationsResource(
False, ExpandConstant('{userappdata}\My Program.log'));
end;

Calling consecutive DLL's from {tmp} in Inno Setup

I want to use a DLL (lets say 'A.dll'), that I created in Delphi, within my Inno Setup script that uses a bunch of other DLLs ('B.dll', 'C.dll', ...). All these dll-files are included in the Files-section as follows:
[Files]
Source:"libs\*.dll"; Flags: dontcopy
In the code section I declare methods of the used DLL as described in the Online help and add the loadwithalteredsearchpath flag:
procedure MyMethod; external 'MyMethod#files:A.dll,B.dll,C.dll stdcall loadwithalteredsearchpath';
When the installer starts, all needed files are copied into the temporary directory the constant {#tmp} is pointing to. However, MyMethod starts its execution just fine (checked it with some Showmessages), but the whole thing breaks, when the method tries to use the other DLLs.
Next to the temporary folder from {#tmp} two other temporary directories are created during the setup (all with the 'IS-xxxxx.tmp' pattern), which contain 'setup.tmp' (which is not occurent in {#tmp}). When I now manually copy all the DLL's (besides A.dll) into both these other directories at the beginning of the setup, then everything works fine. But when I let it run only as defined in my script, then A.dll doesn't seem to find the other libraries.
Does anybody know, why this is happening and how I can fix this? This seems to be a problem with the PATH, but I thought that Inno Setup adds the tmp-dir into the PATH, so that the setup can find the DLL's (which it does, but strangely only for A.dll).
Thanks in advance for your help! :)
EDIT: The actual error I get, when I use one of the 'foreign' DLL's (B.dll, C.dll, ...) by calling one of their methods inside of A.dll during the Inno Setup:
Access violation at address 00408CC7 in module 'setup.tmp'. Read of adress 00000000.
EDIT 2: I think I realized why my problem is happening: With ExtractFilePath (first link) in my own A.dll I discovered, that the setup.exe is not executed within {tmp} but one of the other two temporary dirs that are creating at the beginning of the setup. It also appears, that not {tmp} but the current working dir (thus the dir, where inno is executed) is added to the library search path (second link). This would explain, why the other libraries (B.dll, C.dll, ...) can only be accessed when manually copying to this other temp dir. I suppose that A.dll is extracted and called from {tmp} without a problem, because it is referred as the "main-library" in the external command. I thought that with loadwithalteredsearchpath the other libraries could remain in the same directory, but that doesn't seem to work.
But how can I fix this now in an nifty way? I think I could copy the DLLs manually to the setup-path (by using ExtractFilePath(ParamStr(0)), after they have been extracted to {tmp} to solve the problem. But this seems to be a dirty workaround as using DLLs in Inno Setup is supposed to work differently.
How to get path where is temporary Inno setup file is located
External function calls with multiple dependent DLLs
Well I'm not sure if you only load the DLLs without registering them in the system registry. However your first EDIT shows an error triggered by attempts to access some stack of the registry, so I assume you are. In that case, I simply use a batch file (which fires commands in the CMD console) to register my DLLs as I would one by one:
#echo off
echo Registering DevExpress DLLs
%~dp0gacutil.exe /i %~dp0DevExpress.BonusSkins.v12.1.dll
%~dp0gacutil.exe /i %~dp0DevExpress.Charts.v12.1.Core.dll
So, I place this in the RUN section of the iss script:
[Run]
Filename:C:\myFolder\RegisterDevExpress.bat"
Hope this helps.

Inno-Setup checking file location prior to installation, then using it during installation

I need to check for the location of a file during program installation utilizing inno setup. I then need inno setup to use the location of that file in the "Filename" line to create a desktop ICON for program initialization. I have the code for the "Icons" option working fine with the exception of how to do the above.
Here is the line of code I am currently using;
Name: "{commondesktop}\SA - NH Bricscad V12"; Filename:"**c:\program files\septic assistant\new hampshire\support\**SA - NH Bricscad V12.exe"; IconFilename: "C:\Program Files\Septic Assistant\New Hampshire\Support\Bricscadlogo.ico"; Comment: "Septic Assistant the only Septic Design Program"
Hi-Lited section would be the path to the exe file that I need inno setup to search for.
Any assistance with this would be very much appreciated.
Bruce
Just use a {code:...} constant and corresponding [Code] function that returns the appropriate path for your [Icons] entry. You will probably also want to use a Check function to avoid installing the icon in the case that you cannot find the correct location.
Another option is to use a {reg:...} constant, assuming that the path you are trying to locate is specified somewhere in the registry (which is usually the case).
If the path is not already specified somewhere well-defined in the Registry when the other app is installed, and you don't have some other means to quickly identify where the other app is located (note that doing a global search of the user's HD is not a valid option), then you should add a page that prompts the user to enter the location themselves (which you can then verify that they have chosen the correct location). You can see examples of prompting the user for information and then doing something with that info in the CodeDlg.iss example included with Inno, and in the ISXKB wiki.

Write to AppData directory using InnoIDE?

I need to write to the:
C:\Users\user\AppData\Roaming\AppName
folder during the setup process. I'm using the InnoIDE program for setup, and it's awesome. However, it seems to be lacking an 'AppData' special folder for easily accessing that directory.
For example, you can use:
DestDir: "{app}"
to write the application directory.
But how do you get to AppData? Is there a list of all the preset DestDir options?
Arg, got it.
{userappdata} → C:\Users\user\AppData\Roaming\AppName
as found here:
http://news.jrsoftware.org/news/innosetup/msg74694.html
As you said in your own answer, {userappdata} is the one you need. The help manual has a list of all the Inno Setup directory constants.
It is not recommend to write to AppData directory using InnoIDE. You better save user-specific data to a shared location first (e.g. under {app}) and have your application copy it from there on first startup.
more https://stackoverflow.com/a/3036259/5929293

Resources