Inno setup can not create desktop icon in windows 10 - windows-10

I have setup file for inno setup of latest version. It compiles and works great from windows xp to windows 8, but in windows 10 it fails on the moment when it creates desktop icon with next error:
IPersistFile::Save failed; code 0x80070002
This is how I create icon in setup file:
[Icons]
Name: "{userdesktop}\Forex Tester 4"; Filename: "{app}\ForexTester4.exe"; Tasks: desktopicon
Part of the installation log file:
2019-02-01 12:50:46.376 -- Icon entry --
2019-02-01 12:50:46.376 Dest filename: C:\Users\Mike\Desktop\Forex Tester 4.lnk
2019-02-01 12:50:46.376 Creating the icon.
2019-02-01 12:50:46.376 Exception message:
2019-02-01 12:50:46.376 Message box (OK):
IPersistFile::Save failed; code 0x80070002.
The system cannot find the file specified.
2019-02-01 12:50:59.066 User chose OK.
This folder exists and I can create files there manually. But inno setup fails to do this... All other icons except desktop one were created without problems.
Any ideas?

I had the same error on Windows 7 and Windows 10 because I was trying to create shortcut to file that didn't exist yet.
[Icons]
; Create icons for the app
Name: "{group}\{#AppName}"; \
Filename: "{app}\{#AppName}.lnk"; \
BeforeInstall: CreateAppRunLink();
Name: "{commondesktop}\{#AppName}"; \
Filename: "{app}\{#AppName}.lnk"; \
Tasks: desktopicon;
So I had to make sure that file "{app}{#AppName}.lnk" exists prior to creating the Icon:
This goes to [Code] section:
procedure CreateAppRunLink();
var
Filename: string;
Description: string;
ShortcutTo: string;
Parameters: string;
WorkingDir: string;
IconFilename: string;
begin
Filename := ExpandConstant('{app}\MyApp.lnk');
Description := 'Description';
ShortcutTo := 'Full path to file that will be run (MyApp.exe)';
Parameters := 'parameters if any';
WorkingDir := ExpandConstant('{app}');
IconFilename := ExpandConstant('{app}') + '\icon.ico';
CreateShellLink(Filename, Description, ShortcutTo, Parameters, WorkingDir,
IconFilename, 0, SW_HIDE);
end;
CreateAppRunLink will will be called after extracting any files from [Files] section which will make sure that our file is in place.
Hope that'll help.

It could be a relatively new (since version 1709) Windows 10 feature called Controlled folder access. See Allow a blocked app in Windows Security for instructions on turning it on or off.

Related

Setup is "unresponsive" at startup if I compile it with compression [duplicate]

My Installer created with Inno Setup is about 850 MB in size containing about 7000 files and 890 Folders to an uncompressed size of 1.98 GB.
When starting the install process, after the Windows UAC Dialog shows up, the Installer is sitting with an empty icon in the Taskbar for approx. 45 seconds before the Welcome Dialog is being shown.
I'm assuming that this is happening during the process of unpacking the installer? Running the installer with just a dummy file entry has the Welcome Dialog show up immediately.
In the [Files] section, I only specify a single relative folder:
Source: "{#Source}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Compression in the [Setup] section is set to:
Compression=lzma
SolidCompression=yes
Is there a dialog I can show during that time that gives the user visual feedback that something is being prepared?
To append to this question:
The last entry in the Log file before the 45 second hang is:
Extracting temporary file: C:\Users\Markus\AppData\Local\Temp\is-CBETM.tmp\license.rtf
I'm using a custom License Page on which I extract the file and load it as RTFText:
procedure LicensePage_Create;
var
LicenseFileName: string;
LicenseFilePath: string;
LicenseText: AnsiString;
begin
LicensePage := CreateOutputMsgMemoPage(wpSelectDir, SetupMessage(msgWizardLicense), SetupMessage(msgLicenseLabel), SetupMessage(msgLicenseLabel3), '');
LicensePage.RichEditViewer.Height := WizardForm.LicenseMemo.Height;
LicenseFileName := 'license.rtf';
ExtractTemporaryFile(LicenseFileName);
LicenseFilePath := ExpandConstant('{tmp}\license.rtf');
LoadStringFromFile(LicenseFilePath, LicenseText);
LicensePage.RichEditViewer.RTFText := LicenseText;
DeleteFile(LicenseFilePath);
LicensePage.OnActivate := #LicensePageActivate;
LicenseAcceptedRadio := CloneLicenseRadioButton(WizardForm.LicenseAcceptedRadio);
LicenseNotAcceptedRadio := CloneLicenseRadioButton(WizardForm.LicenseNotAcceptedRadio);
LicenseNotAcceptedRadio.Checked := True;
LicensePageID := LicensePage.ID;
end;
When you want to use SolidCompression (is it really worth it?), you have to put all files that are needed for the installer to start (like "license" file) before the big files.
Otherwise the installer has to decompress all the big files while starting.

Adding custom icon in inno setup [duplicate]

This question already has an answer here:
How to create a desktop icon with Inno Setup
(1 answer)
Closed 2 years ago.
I wish to add a custom Desktop icon to my executable in Inno Setup.
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}";
[Files]
Source: C:\icons\javelin.ico; DestDir: {app}; Flags: dontcopy;
[Icons]
Name: "{userdesktop}\{#MyAppName}"; Filename: "{code:GetDir}\source\app\{#MyAppExeName}"; Tasks: desktopicon; IconFilename: "{tmp}\javelin.ico";
function InitializeSetup(): Boolean;
begin
ExtractTemporaryFile('javelin.ico');
Result := True;
end;
The above code is adding the icon on desktop but when the user restarts the machine the javelin image will disappears only file's default icon will remain.
It is because you use Temp Folder for your icon. if you want your icon path to be available all the time you should use some permanent path. for example copy it to {app} folder or some other path.

Inno script not detecting that vcredist_x64.exe is not installed

I have the following code in my Inno Setup script:
[Files]
Source: "C:\Users\Myname\Documents\Visual Studio
2010\Redistributional\vcredist_x86.exe"; DestDir: "{tmp}"; Flags:
deleteafterinstall;
Source: "C:\Users\Myname\Documents\Visual Studio
2010\Redistributional\vcredist_x64.exe"; DestDir: "{tmp}"; Flags:
deleteafterinstall;
[Run]
Filename: "{tmp}\vcredist_x86.exe"; Parameters: "/install /passive"; Check:
not IsWin64 and not VCinstalled32
Filename: "{tmp}\vcredist_x64.exe"; Parameters: "/install /passive"; Check:
IsWin64 and not VCinstalled64
Filename: "{app}\Myprogram.exe"; Description {cm:LaunchProgram,Myprogram}";
[Code]
function VCinstalled32: Boolean;
var
installed: Cardinal;
key: String;
begin
Result := False;
key := 'SOFTWARE\Microsoft\VisualStudio\10.0\VC\Runtimes\x86';
if DirExists
('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0\VC\Runtimes\x86')
then begin
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, key, 'Installed', installed)
then begin
if installed = 1 then begin
Result := True;
end;
end;
end;
end;
function VCinstalled64: Boolean;
var
installed: Cardinal;
key: String;
begin
Result := False;
key := 'SOFTWARE\Microsoft\VisualStudio\10.0\VC\Runtimes\x64';
if DirExists
('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0\VC\Runtimes\x64')
then begin
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, key, 'Installed', installed)
then begin
if installed = 1 then begin
Result := True;
end;
end;
end;
end;
I have tried to run this on a 64 bits Windows 10 machine in which the directory HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0\VC\Runtimes\x64 does not exist, but I get an error message saying that MSVCR100 is not found.
Thanks in advance.
Update
Thank you very much for you answer, but still I get the same error message. Maybe I have overlooked something.
Update
I am not very acquainted with Inno script and don't know anything about how to log the result. I have tried to google the latter, but it seems to be very complicated, so I'll try to wait with this to later, if I can't find the answer in any other way.
Update
Here is some of the output from the Log file:
2018-03-05 14:01:03.567 -- File entry --
2018-03-05 14:01:03.568 Dest filename: C:\Users\Bruker\AppData\Local\Temp\is-SP07M.tmp\vcredist_x86.exe
2018-03-05 14:01:03.568 Time stamp of our file: 2018-02-18 14:27:32.000
2018-03-05 14:01:03.568 Installing the file.
2018-03-05 14:01:04.016 Successfully installed the file.
2018-03-05 14:01:04.017 -- File entry --
2018-03-05 14:01:04.018 Dest filename: C:\Users\Bruker\AppData\Local\Temp\is-SP07M.tmp\vcredist_x64.exe
2018-03-05 14:01:04.018 Time stamp of our file: 2018-02-18 16:00:00.000
2018-03-05 14:01:04.018 Installing the file.
2018-03-05 14:01:04.937 Successfully installed the file.
2018-03-05 14:01:08.883 -- Run entry --
2018-03-05 14:01:08.883 Run as: Current user
2018-03-05 14:01:08.883 Type: Exec
2018-03-05 14:01:08.883 Filename: C:\Users\Bruker\AppData\Local\Temp\is-SP07M.tmp\vcredist_x64.exe
2018-03-05 14:01:08.883 Parameters: /install /passive
2018-03-05 14:01:21.800 Process exit code: 0
2018-03-05 14:01:21.800 -- Run entry --
2018-03-05 14:01:21.800 Run as: Current user
2018-03-05 14:01:21.800 Type: Exec
2018-03-05 14:01:21.800 Filename: C:\Program Files (x86)\Myfile\myfile.exe
2018-03-05 14:01:28.020 Process exit code: 3221225781
2018-03-05 14:01:28.023 Need to restart Windows? No
2018-03-05 14:01:30.504 Deinitializing Setup.
2018-03-05 14:01:30.593 Log closed.
As I have understood, Process exit code: 0 means that the file has executed successfully, so I still don't understand what could be wrong.
I just read up on MSVCR100.DLL:
MSVCR100.dll = Visual Studio 2010 Runtime
MSVCR110.dll = Visual Studio 2012 Runtime
MSVCR120.dll = Visual Studio 2013 Runtime
So are you actually installing the correct redistributables?
With respects to your script, why are you using DirExists? That is designed to verify if a directory exists. You are working with the registry so you should be using RegKeyExists. The help provides an example:
begin
if RegKeyExists(HKEY_CURRENT_USER, 'Software\Jordan Russell\Inno Setup') then
begin
// The key exists
end;
end;
I have not tested this but you would want something like:
function VCinstalled64: Boolean;
var
installed: Cardinal;
key: String;
begin
Result := False;
key := 'SOFTWARE\Microsoft\VisualStudio\10.0\VC\Runtimes\x64';
if RegKeyExists(HKEY_LOCAL_MACHINE, key) then
begin
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, key, 'Installed', installed)
then begin
if installed = 1 then begin
Result := True;
end;
end;
end;
end;
The other method VCinstalled32 would need similar changes.
Logging
The help system supplied with Inno Setup (also online) explains about logging:
/LOG
Causes Setup to create a log file in the user's TEMP directory detailing file installation and [Run] actions taken during the installation process. This can be a helpful debugging aid. For example, if you suspect a file isn't being replaced when you believe it should be (or vice versa), the log file will tell you if the file was really skipped, and why.
The log file is created with a unique name based on the current date. (It will not overwrite or append to existing files.)
The information contained in the log file is technical in nature and therefore not intended to be understandable by end users. Nor is it designed to be machine-parsable; the format of the file is subject to change without notice.
/LOG="filename"
Same as /LOG, except it allows you to specify a fixed path/filename to use for the log file. If a file with the specified name already exists it will be overwritten. If the file cannot be created, Setup will abort with an error message.
So, from the Windows Start Menu type in the box cmd and click on Command Prompt:
Next, navigate to the folder where the installer is and run it with the /log parameter:
Edit your question and add the output from the log to it. Also consider replacing your snippet of script with your complete script (the original script that used DirExists.
I have done a bit more research and found this interesting question. If you look at your log output it only installs the 64 bit edition:
2018-03-05 14:01:08.883 -- Run entry --
2018-03-05 14:01:08.883 Run as: Current user
2018-03-05 14:01:08.883 Type: Exec
2018-03-05 14:01:08.883 Filename: C:\Users\Bruker\AppData\Local\Temp\is-SP07M.tmp\vcredist_x64.exe
2018-03-05 14:01:08.883 Parameters: /install /passive
2018-03-05 14:01:21.800 Process exit code: 0
Change this line from:
Filename: "{tmp}\vcredist_x86.exe"; Parameters: "/install /passive"; Check: not IsWin64 and not VCinstalled32
to:
Filename: "{tmp}\vcredist_x86.exe"; Parameters: "/install /passive"; Check: not VCinstalled32
Your executable appears to be 32 bit, and based on that question I referred to it states:
No, you need the x86 version to run 32-bit VC++ programs, and you need the x64 version to run 64-bit VC++ programs.

Inno Setup desktop shortcut (link) which has "Run as administrator" advanced property set

I am struggling to get Inno setup (5.5.9u) to created a desktop shortcut that has an icon and has the advanced property of "Run as administrator" set.
Issue
This question, is a little different than: How to set 'Run as administrator' on a file using Inno Setup
Since what I am trying to do is not run a program at setup time with admin rights, (setup is already running at Admin), but rather leave a link on the desktop that has has the advanced property of "Run as Administrator".
Code Sample
[Icons]
Name: "{group}\EGPL Watson Uninstall"; Filename: "{uninstallexe}"; \
WorkingDir: "{app}"
Name: "{commondesktop}\DashBoard"; \
Filename: "{app}\dashboard\node_modules\electron\dist\electron.exe main.js"; \
WorkingDir: "{app}\dashboard"; \
IconFilename: "{src}\dashboard\build\configure.ico"
First, make sure you have a very good reason to run your application with Administrator privileges. User applications should not need Administrator privileges. If they need it, it's usually a sign of a bad design. One common (bad) reason to want an application to run with Administrator privileges, is that the application needs to write to its installation folder.
See Application does not work when installed with Inno Setup
Inno Setup does not natively support creating a shortcut with "Run as Administrator" flag set.
The "Run as Administrator" flag is a bit the .lnk file. See:
LinkFlags in [MS-SHLLINK]: Shell Link (.LNK) Binary File Format;
How to create a Run As Administrator shortcut using Powershell
How can I use JScript to create a shortcut that uses "Run as Administrator"
You can set the bit using the following code:
[Icons]
Name: "{userdesktop}\My Program"; Filename: "{app}\MyProg.exe"; \
AfterInstall: SetElevationBit('{userdesktop}\My Program.lnk')
[Code]
procedure SetElevationBit(Filename: string);
var
Buffer: string;
Stream: TStream;
begin
Filename := ExpandConstant(Filename);
Log('Setting elevation bit for ' + Filename);
Stream := TFileStream.Create(FileName, fmOpenReadWrite);
try
Stream.Seek(21, soFromBeginning);
SetLength(Buffer, 1);
Stream.ReadBuffer(Buffer, 1);
Buffer[1] := Chr(Ord(Buffer[1]) or $20);
Stream.Seek(-1, soFromCurrent);
Stream.WriteBuffer(Buffer, 1);
finally
Stream.Free;
end;
end;
Tested on Unicode version of Inno Setup (the only version as of Inno Setup 6). But it should, even more naturally, work on Ansi version too.

How to get Inno Setup to unzip a file it installed (all as part of the one installation process)

To save bandwidth/space as well as prevent accidental meddling, the installation files for a database product (call it Ajax), have been zipped up (call that file "AJAX_Install_Files.ZIP). I would like to have Inno-Setup "install" (i.e., copy) the AJAX_Install_Files.ZIP file to the destination, and then Unzip the files into the same folder where the .ZIP file is located. A subsequent program would be fired off by Inno Setup to actually run the install of product "Ajax".
I've looked through the documentation, FAQ, and KB at the Inno Setup website, and this does not seem possible other than writing a Pascal script (code) - would that be correct, or are there are any alternative solutions?
You can use an external command line tool for unzipping your archive, see here for example. Put it in your [Files] section:
[Files]
Source: "UNZIP.EXE"; DestDir: "{tmp}"; Flags: deleteafterinstall
Then call it in your [Run] section, like this:
[Run]
Filename: "{tmp}\UNZIP.EXE"; Parameters: "{tmp}\ZipFile.ZIP -d C:\TargetDir"
(You'll probably want to take your target directory from a script variable, so there is some more work that needs to be done)
You can use the shell Folder.CopyHere method to extract a ZIP.
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
procedure UnZip(ZipPath, TargetPath: string);
var
Shell: Variant;
ZipFile: Variant;
TargetFolder: Variant;
begin
Shell := CreateOleObject('Shell.Application');
ZipFile := Shell.NameSpace(ZipPath);
if VarIsClear(ZipFile) then
RaiseException(
Format('ZIP file "%s" does not exist or cannot be opened', [ZipPath]));
TargetFolder := Shell.NameSpace(TargetPath);
if VarIsClear(TargetFolder) then
RaiseException(Format('Target path "%s" does not exist', [TargetPath]));
TargetFolder.CopyHere(
ZipFile.Items, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
end;
Note that the flags SHCONTCH_NOPROGRESSBOX and SHCONTCH_RESPONDYESTOALL work on Windows Vista and newer.
For an example of extracting some files only, see:
How to get Inno Setup to unzip a single file?
I answered a very similar question and some of the details apply.
I would question why you need a ZIP file of the contents? I personally would place the uncompressed files into the setup. I would then have two [category] entries one for the application and one for the data. Default both the be checked.
This would allow the users to install a fresh set of the data if needed at a later date.
If you really want a ZIP file and want to keep it easy you could, ship both the zip files and the uncompressed files in the same setup.
Update:
By default files that get placed in your setup.exe are compressed.
You can also have the files extracted to a temporary location so you can run your
installation application, then have them deleted.
[Files]
Source: "Install1.SQL"; DestDir: "{tmp}"; Flags:deleteafterinstall;
Source: "Install2.SQL"; DestDir: "{tmp}"; Flags:deleteafterinstall;
You can just create silent self-extracting archive (SFX) archive, example described here how to create SFX archive for stuff you need, and write Pascal code to just run it like this (script for Inno Setup 6.0.2):
[Tasks]
Name: "intallSenselockDriver"; Description: "Install Senselock driver."; GroupDescription: "Install the necessary software:";
[Code]
function ExecTmpFile(FileName: String): Boolean;
var
ResultCode: Integer;
begin
if not Exec(ExpandConstant('{tmp}\' + FileName), '', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode)
then
begin
MsgBox('Other installer failed to run!' + #13#10 + SysErrorMessage(ResultCode), mbError, MB_OK);
Result := False;
end
else
Result := True;
end;
procedure RunOtherInstallerSFX(ArchiveName: String; ExePath: String);
begin
ExtractTemporaryFile(ArchiveName);
ExecTmpFile(ArchiveName);
ExecTmpFile(ExePath);
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
if WizardIsTaskSelected('intallSenselockDriver') then
RunOtherInstallerSFX('1_senselock_windows_3.1.0.0.exe', '1_senselock_windows_3.1.0.0\InstWiz3.exe');
Result := '';
end;
It worked perfectly for me.
Using Double quotes worked for me.
Single quotes were not working.
[Files]
Source: "unzip.exe"; DestDir: "{userappdata}\{#MyAppName}\{#InputFolderName}"; Flags: ignoreversion
[Run]
Filename: "{userappdata}\{#MyAppName}\{#InputFolderName}\unzip.exe"; Parameters: " ""{userappdata}\{#MyAppName}\{#InputFolderName}\ZIPFILENAME.zip"" -d ""{userappdata}\{#MyAppName}\{#InputFolderName}"" "; Flags: runascurrentuser

Resources