Problem with disk caching using inno-setup?

I will try to be as concise as possible without linking all related source files. I traced the problem in the same way that my knowledge of Pascal allows me ...

I discovered a disk caching problem that occurs for my case in the ssInstall step. I have an installer for an application that, if it finds an older version of the application, will cause the uninstall as follows:

procedure CurStepChanged(CurStep: TSetupStep); var uninstallStr: String; ResultCode: Integer; begin if (CurStep = ssInstall) and IsUpdatableApplicationInstalled() then begin uninstallStr := GetUninstallString(); uninstallStr := RemoveQuotes(uninstallStr); Result := Exec(uninstallStr, '/SILENT /NORESTART /SUPPRESSMSGBOXES', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); if Result and (ResultCode = 0) then Log('CurStepChanged = ssInstall; uninstall OK'); //------------- //Sleep(30000); //------------- end; 

Also folders / files are defined as follows:

 [Dirs] Name: "{app}\db"; Flags: uninsalwaysuninstall [Files] Source: "..\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion createallsubdirs recursesubdirs Source: "..\java\jre\*"; DestDir: "{app}\jre"; Flags: ignoreversion recursesubdirs createallsubdirs blah... 

Test case1; Normal installation: everything goes smoothly. Part of the log file:

 Starting the installation process. Creating directory: C:\Program Files <--- Creating directory: C:\Program Files\MyApp <--- Creating directory: C:\Program Files\MyApp\db <--- Creating directory: C:\Program Files\MyApp\jre <--- Creating directory: C:\Program Files\MyApp\jre\lib Creating directory: C:\Program Files\MyApp\jre\lib\applet Directory for uninstall files: C:\Program Files\MyApp Creating new uninstall log: C:\Program Files\MyApp\unins000.dat <--- !!! -- File entry -- Dest filename: C:\Program Files\MyApp\unins000.exe <--- !!! blah... 

Test case2; Update the old version: when the ssInstall step is reached , the uninstall program starts, it ends, and then the installation starts. Part of the log file:

 CurStepChanged = ssInstall; uninstall OK Starting the installation process. Creating directory: C:\Program Files\MyApp\jre\lib Creating directory: C:\Program Files\MyApp\jre\lib\applet Directory for uninstall files: C:\Program Files\MyApp Creating new uninstall log: C:\Program Files\MyApp\unins001.dat <--- !!! -- File entry -- Dest filename: C:\Program Files\MyApp\unins001.exe <--- !!! blah... 

As you can see, some folders are not created, and my application does not work later when it tries to write to the 'db' folder.

If I uncomment the Sleep () command, everything runs smoothly and both log files are identical.

The disk seems to have enough time to discard changes! Somehow or other inno-setup is missing the flush () command.

Can any of the Innoguru comment or help? Is there a flash () that I could call instead of sleep ()? Any help is appreciated. I just want to be sure before I submit an error request.

+2
caching inno-setup
Sep 19 '13 at 18:13
source share
3 answers

This is how I really worked on this issue. I am posting my decision in the hope of helping others with the same problem.

Many thanks to everyone that helped, and especially to Miral for pointing me in the right direction!

The solution is pretty simple; wait for uninstall exinstaller exe! A.

 const DELAY_MILLIS = 250; MAX_DELAY_MILLIS = 30000; function GetUninstallString(): String; var uninstallPath: String; uninstallStr: String; begin uninstallPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1'); uninstallStr := ''; if not RegQueryStringValue(HKLM, uninstallPath, 'UninstallString', uninstallStr) then RegQueryStringValue(HKCU, uninstallPath, 'UninstallString', uninstallStr); Result := RemoveQuotes(uninstallStr); end; function ForceUninstallApplication(): Boolean; var ResultCode: Integer; uninstallStr: String; delayCounter: Integer; begin // 1) Uninstall the application Log('forcing uninstall of application); uninstallStr := GetUninstallString(); Result := Exec(uninstallStr, '/SILENT /NORESTART /SUPPRESSMSGBOXES /LOG', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0); if not Result then begin Log('application uninstall failed!'); Exit end; Log('application uninstalled!'); // 2) Be sure to wait a while, until the actual uninstaller is deleted! Log('waiting a while until uninstaller changes are flushed in the filesystem...'); delayCounter := 0; repeat Sleep(DELAY_MILLIS); delayCounter := delayCounter + DELAY_MILLIS; until not FileExists(uninstallStr) or (delayCounter >= MAX_DELAY_MILLIS); if (delayCounter >= MAX_DELAY_MILLIS) then RaiseException('Timeout exceeded trying to delete uninstaller: ' + uninstallStr); Log('waited ' + IntToStr(delayCounter) + ' milliseconds'); end; 

The ForceUninstallApplication() function can be successfully called either from PrepareToInstall or CurStepChanged(ssInstall) . For my case, it takes about 500 milliseconds when I use an SSD hard drive and maybe a couple of seconds when I use my external usb hard drive.

+4
Sep 24 '13 at 17:44
source share

Just to comment on the following question:

Do not delete

The best solution is not to run the uninstaller at all. You can delete redundant files through the [InstallDelete] section; eg. to completely remove the "jre" subfolder (so that it is replaced as part of your installation), follow these steps:

 [InstallDelete] Type: filesandordirs; Name: "{app}\jre" 

(Use this only for subfolders like this, and only sparingly, you may run into problems if you delete too many things.)

For regular individual application files installed by a previous version that are now redundant, you can delete them like this:

 [InstallDelete] Type: files; Name: "{app}\redundant.dll" 

(You need to do something a little more fun if they had a "regserver" or "sharedfile" during installation.)

If you delete independently, wait longer

Uninstaller cannot delete itself or the folder in which it is located while it is still running. While Inno takes care of this in such a way that it can remove the uninstaller and the folder, this means that your Exec call to the uninstaller will return before this removal happens and before the removal process actually ends.

You will need to wait longer after Exec for a final uninstall before you can proceed with the installation. Using Sleep is quite simple and will work in most cases, but if you want the best results, you will need to call WinAPI to check the list of running processes.

In addition, you must use the PrepareToInstall event PrepareToInstall to perform the actual uninstall. This will allow you to deal with cases such as uninstall errors or when a reboot is required between uninstalling and reinstalling. (And because it runs at the β€œright” time during the installation process.)

+3
Sep 24 '13 at 4:19
source share

Thank you for this answer! I just made a small modification to avoid the same problem with the installation folder, which is deleted during the uninstall process. You can remove it after calling ForceUninstallApplication () and avoid creating the installation folder.

To avoid this problem, I simply create a temporary file in the installation folder and delete it when the installation is complete. If a folder with an unknown file is present, unins000.exe does not delete the folder.

Here is updated fubar code:

 const DELAY_MILLIS = 250; MAX_DELAY_MILLIS = 30000; var tempUninstallFilename: String; function GetUninstallString(): String; var uninstallPath: String; uninstallStr: String; begin uninstallPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1'); uninstallStr := ''; if not RegQueryStringValue(HKLM, uninstallPath, 'UninstallString', uninstallStr) then RegQueryStringValue(HKCU, uninstallPath, 'UninstallString', uninstallStr); Result := RemoveQuotes(uninstallStr); end; function ForceUninstallApplication(): Boolean; var ResultCode: Integer; uninstallStr: String; delayCounter: Integer; begin // 1) Create a temporary file to avoid destruction of install folder during uninstall. uninstallStr := RemoveQuotes(GetUninstallString()); tempUninstallFilename := ExtractFileDir(uninstallStr) + '\uninstall.log'; SaveStringToFile(tempUninstallFilename, '...', False); Log('Create temp file: ' + tempUninstallFilename); // 2) Uninstall the application Log('forcing uninstall of application); uninstallStr := GetUninstallString(); Result := Exec(uninstallStr, '/SILENT /NORESTART /SUPPRESSMSGBOXES /LOG', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0); if not Result then begin Log('application uninstall failed!'); Exit end; Log('application uninstalled!'); // 2) Be sure to wait a while, until the actual uninstaller is deleted! Log('waiting a while until uninstaller changes are flushed in the filesystem...'); delayCounter := 0; repeat Sleep(DELAY_MILLIS); delayCounter := delayCounter + DELAY_MILLIS; until not FileExists(uninstallStr) or (delayCounter >= MAX_DELAY_MILLIS); if (delayCounter >= MAX_DELAY_MILLIS) then RaiseException('Timeout exceeded trying to delete uninstaller: ' + uninstallStr); Log('waited ' + IntToStr(delayCounter) + ' milliseconds'); end; //============================================================================================================ // SUMMARY // You can use this event function to perform your own pre-install and post-install tasks. procedure CurStepChanged(CurStep: TSetupStep); begin if (CurStep = ssInstall) then begin ForceUninstallApplication(); end ; if (CurStep = ssPostInstall) then begin DeleteFile(tempUninstallFilename); end; end; 
0
Oct 10 '14 at 20:24
source share



All Articles