Inno Setup - Change directory permission not affect time to time - windows

I have application which is installed in C://ProgramFiles. I need installation directory full access to user group to handle update process of application (File download, move, delete, write). So I update inno-script as below.
[InstallDelete]
Type: filesandordirs; Name: "{app}\assets"; BeforeInstall: TaskKill()
[Dirs]
Name: "{app}\assets"; Permissions: users-full; Flags: uninsalwaysuninstall;
[Files]
; Change file path when necessary
; Service, Launcher, Killer, runtime Binaries
Source: "..\..\_Source\Bin\*"; DestDir: "{app}"; Flags: recursesubdirs ignoreversion;
In _Source\Bin folder (Source folder which contained all files) there is some files and assert folder.
The problem is, Installation did not change the assert folder permission time to time, for user group. (Most of times work fine). Here are comparison of two logs with and without issue.
Please give any idea or any possibility overcome this issue.

After referring the logs of installer, I found permission granted folder recreated when files copping.
So I decided to set user permission by executing windows icacls command after installer process. So I changed the script like below and after that work as expected.
// Following method will execute to grant user permisions after installation //
procedure PermissionUpdate();
var
ResultCode: integer;
begin
Log(ExpandConstant('Giving user group permission :O - CODE: - ' + ExpandConstant('"{app}/assets" /grant *S-1-5-32-545:(OI)(CI)M /t /c /q')));
if Exec('icacls.exe', ExpandConstant('"{app}/assets" /grant *S-1-5-32-545:(OI)(CI)M /t /c /q'), '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
Log('Successfully gave user group permission :)' + IntToStr(ResultCode));
end
else begin
Log('Giving user group permission unsuccessfull :(' + IntToStr(ResultCode));
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep=ssInstall) then
begin
if (IsUpgrade()) then
begin
UnInstallOldVersion();
end;
end
else if (CurStep=ssPostInstall) then
begin
PermissionUpdate();
end;
end;
So in this fix CurStepChanged method is event hander of the installer. I use post install step (CurStep=ssPostInstall) to run permission update method.
In executing icacls method, S-1-5-32-545 is security identifier for User Group.
This may not the solution for which I posted but this fix worked for me.

Related

Inno Setup - File in use, disallow skip/cancel

I have configured "Inno Setup" as needed, but there is one point which I'm not able to modify.
We have an application which is installed on a network folder on the customers server. Basically updating the files works as expected.
If some client on the network, someone which has not initiated the update, has opened the application I'm receiving an messagebox/errorbox "delete file failed.... file is in use by another process" - including 3 buttons "try again", "skip this files (not recommended)", "cancel installation". I have attached an example picture (found on the internet, but the same message).
There you can see the 3 buttons. I want to disable "skip this file" and "cancel installation". The user should have the ability to hit "try again" - they should get stucked until all client have closed their application.
I do not think you can alter that message box.
There are two alternatives:
You can delete the target file using your own code before installing the new version, not allowing to proceed until the file is gone.
[Files]
Source: "Source: "C:\SampleApplicationData\*"; DestDir: "{app}\SampleApp"; \
Flags: recursesubdirs createallsubdirs; BeforeInstall: ForcedDelete
[Code]
procedure ForcedDelete;
var
FileName: string;
Deleted: Boolean;
begin
FileName := ExpandConstant(CurrentFileName);
repeat
if not FileExists(FileName) then
begin
Log(Format('File %s does not exist', [FileName]));
Deleted := True;
end
else
if DeleteFile(FileName) then
begin
Log(Format('File %s was deleted', [FileName]));
Deleted := True;
end
else
begin
MsgBox(Format('Error deleting %s.', [FileName]), mbError, MB_OK);
Deleted := False;
end;
until Deleted;
end;
Though I still believe the code should at least allow an abort.
Or use restartreplace flag.

Inno Setup ExtractTemporaryFile causes wizard to freeze

I've made custom pages to manage specific redist tools install depending on the user choice.
Those tools are linked to checkboxes checked by the user if he wants or not install those tools.
Then come a page only there to show the user the progression of the installation of each tool.
The issue I have here is that the progress page is shown only when first ExtractTemporaryFile of the setups for the tools is done, showing the last page as if it has frozen.
The only way I have to let the progress page be shown before the ExtractTemporaryFile happens is to put a MsgBox before any install function.
But even in this case, when the ExtractTemporaryFile is launched, the progress bar animation is frozen until the ExtractTemporaryFile is done...
Here is the part of the code doing this:
procedure CurPageChanged(CurPageID: Integer);
begin
If CurPageID=PageInstallationPersonnalisee.ID then
begin
ProgressBarLabelPageInstPerso.Caption := 'Initialisation...';
if InstallTool1 = True then
begin
ProgressBarLabelPageInstPerso.Caption := 'Installing InstallTool1...';
F_InstallTool1();
end;
if InstallTool2 = True then
begin
ProgressBarLabelPageInstPerso.Caption := 'Installing InstallTool2...';
F_InstallTool2();
end;
if InstallTool3 = True then
begin
ProgressBarLabelPageInstPerso.Caption := 'Installing InstallTool3...';
F_InstallTool3();
end;
ProgressBarPageInstPerso.Style := npbstMarquee;
//ProgressBarPageInstPerso.Style := npbstNormal;
ProgressBarPageInstPerso.Position := 100;
CancelWithoutPrompt:=True;
WizardForm.Close;
end;
end;
Note that ExtractTemporaryFile() is made in each F_InstallTooln() function.
Others part of Setup and File Sections that could help:
[Setup]
SolidCompression=no
[Files]
;Temporary redists
Source: "{#MyRessourcesPath}InstallTool1_Setup.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall noencryption dontcopy
Source: "{#MyRessourcesPath}InstallTool2_Setup.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall noencryption dontcopy
Source: "{#MyRessourcesPath}InstallTool3_Setup.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall noencryption dontcopy
Here, the page PageInstallationPersonnalisee is not shown until first ExtractTemporaryFile is done...
I'm aware that ExtractTemporaryFile can cause some delay in install process, but why should it cause the wizard to freeze?
So my question is: in my scenario, is there a way to force the wizard refreshing so that he shows up before any ExtractTemporaryFile procedure is launched?
The ExtractTemporaryFile really hangs the wizard form. As most code does.
The only custom page that allows forcing Windows message queue to get pumped is the TOutputProgressWizardPage (created by the CreateOutputProgressPage).
You can do something like this:
function NextButtonClick(CurPageID: Integer): Boolean;
var
ProgressPage: TOutputProgressWizardPage;
begin
if CurPageID = wpReady then
begin
ProgressPage := CreateOutputProgressPage('Preparing installations', '');
ProgressPage.Show;
try
ProgressPage.Msg1Label.Caption := 'Installing 1 ...';
ProgressPage.SetProgress(0, 100);
ExtractTemporaryFile('1.exe');
Exec(...);
ProgressPage.Msg1Label.Caption := 'Installing 2 ...';
ProgressPage.SetProgress(33, 100);
ExtractTemporaryFile('2.exe');
Exec(...);
ProgressPage.Msg1Label.Caption := 'Installing 3 ...';
ProgressPage.SetProgress(66, 100);
ExtractTemporaryFile('3.exe');
Exec(...);
ProgressPage.SetProgress(100, 100);
ProgressPage.Hide;
finally
end;
end;
Result := True;
end;
Though it does not work really well either on modern versions of Windows that have fancy progress bar with animation, if you cannot call the SetProgress frequently. Note that the SetProgress call is what does pump the message queue behind the scenes. So it makes sense to call it even when its parameter do not change. But you cannot, as the ExtractTemporaryFile blocks.
Alternatively, you can leave the deployment to the [Files] section and have the installers be executed from the AfterInstall event.
[Files]
;Temporary redists
Source: "{#MyRessourcesPath}InstallTool1_Setup.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall noencryption dontcopy; AfterInstall: Install1
Source: "{#MyRessourcesPath}InstallTool2_Setup.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall noencryption dontcopy; AfterInstall: Install2
Source: "{#MyRessourcesPath}InstallTool3_Setup.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall noencryption dontcopy; AfterInstall: Install3
I know this is an old thread but I was facing a similar situation where some of the files I was extracting using the ExtractTemporaryFile function were significantly slower than the others.
After some investigation I found this on Inno Setup help pages:
When solid compression is enabled, be sure to list your temporary files at (or near) the top of the [Files] section. In order to extract an arbitrary file in a solid-compressed installation, Setup must first decompress all prior files (to a temporary buffer in memory). This can result in a substantial delay if a number of other files are listed above the specified file in the [Files] section.
This means that for optimal performance you should move the files that you want to extract using that function to the top of the [Files] section.

Inno Setup - Prevent extraction of files from setting progress bar to 100%

In the Inno Setup wpInstalling page how can I prevent the initial extraction of the files as defined in the [Files] section from setting the progress bar to (almost) 100%?
My installation script mainly consists of installing a number of third party installation files from the '[Run]' section. Example below:
[Run]
Filename: "{tmp}\vcredist_x86-2010-sp1.exe"; Parameters: "/q /norestart"; \
Check: InstallVCRedist; \
BeforeInstall: UpdateProgress(10, 'Installing Microsoft Visual C++ 2010 x86 Redistributable - 10.0.40219...');
Filename: "{tmp}\openfire_3_8_1.exe"; Check: InstallOpenFire; \
BeforeInstall: UpdateProgress(25, 'Installing OpenFire 3.8.1...');
Filename: "{tmp}\postgresql-8.4.16-2-windows.exe"; \
Parameters: "--mode unattended --unattendedmodeui none --datadir ""{commonappdata}\PostgreSQL\8.4\data"" --install_runtimes 0"; \
Check: InstallPostgreSQL; \
BeforeInstall: UpdateProgress(35, 'Installing PostgreSQL 8.4...'); \
AfterInstall: UpdateProgress(50, 'Setting up database...');
The installation of these third party components takes longer than any other part of the install (by far) but unfortunately the progress bar goes from 0% to close to 100% during the initial extraction of these files. I then can reset the progress bar to an amount of my choosing by using the following procedure:
procedure UpdateProgress(Position: Integer; StatusMsg: String);
begin
WizardForm.StatusLabel.Caption := StatusMsg;
WizardForm.ProgressGauge.Position :=
Position * WizardForm.ProgressGauge.Max div 100;
end;
Ideally however I'd prefer the initial extraction to instead go from 0–10% (approx.) as that would more closely represent what is actually happening.
Is there any event to capture the progression of the extraction of the files or alternatively a way to prevent or block the extraction of the files from updating the progress bar?
You have to increase the WizardForm.ProgressGauge.Max.
But unfortunately there's no event that happens after the Inno Setup sets its initial maximum.
You can abuse the BeforeInstall parameter of the first installed file though.
And then in the [Run] section, use the AfterInstall to progress the bar.
This expands on my answer to Inno Setup: How to manipulate progress bar on Run section?
[Files]
Source: "vcredist_x86-2010-sp1.exe"; DestDir: "{tmp}"; \
BeforeInstall: SetProgressMax(10)
Source: "openfire_3_8_1.exe"; DestDir: "{tmp}"
[Run]
Filename: "{tmp}\vcredist_x86-2010-sp1.exe"; AfterInstall: UpdateProgress(55);
Filename: "{tmp}\openfire_3_8_1.exe"; AfterInstall: UpdateProgress(100);
[Code]
procedure SetProgressMax(Ratio: Integer);
begin
WizardForm.ProgressGauge.Max := WizardForm.ProgressGauge.Max * Ratio;
end;
procedure UpdateProgress(Position: Integer);
begin
WizardForm.ProgressGauge.Position :=
Position * WizardForm.ProgressGauge.Max div 100;
end;

How to manipulate progress bar on Inno Setup Run section?

Similar to this question:
How to set the progress bar value in the [Run] section of the Inno Setup install script?
When the Inno Setup gets to the [Run] section, the progress bar shows at 100% and stops in this position.
I have many files that I install in this Run section, which I wish to restart the progress bar and control it, as it goes installing each program.
The status message is easy to change (StatusMsg), but the progress I'm missing something. Could you guys help me out, please?
Example:
[Run]
Filename: "msiexec.exe"; Parameters: "/i ""msxml.msi"" /quiet"; \
StatusMsg: "MSXML..."; Flags: runascurrentuser
Filename: "msiexec.exe"; Parameters: "/i ""capicom_dc_sdk.msi"" /quiet"; \
StatusMsg: "CAPICOM..."; Flags: runascurrentuser
Since I want to control the progress bar during it's installation, I don't know what to do. I thought in maybe using BeforeInstall parameter, creating a code to set the progress bar to 0 by doing something like WizardForm.ProgressGauge.Position = 0; and in the AfterInstall parameter, the opposite, WizardForm.ProgressGauge.Position = 100;, but how to change during the installation?
Thanks.
It would be rather difficult to update the progress bar, while another process is running.
I do not see a point of endeavoring it, as you are unlikely able to tell the progress of the sub-installer, so you won't know what to update the progress bar to.
Except for special cases, when the sub-installer provides an API to report its progress.
For an example, see:
Inno Setup Get progress from .NET Framework 4.5 (or higher) installer to update progress bar position or
Make Inno Setup Installer report its installation progress status to master installer.
To update the progress bar according to number of sub-installers finished, you can do:
[Run]
FileName: "process1"; BeforeInstall: SetProgress(0); AfterInstall: SetProgress(33)
FileName: "process2"; AfterInstall: SetProgress(66)
FileName: "process3"; AfterInstall: SetProgress(100)
[Code]
procedure SetProgress(Position: Integer);
begin
WizardForm.ProgressGauge.Position :=
Position * WizardForm.ProgressGauge.Max div 100;
end;
To divide part of the progress range for installing files and the rest to running the sub-installers, see
Inno Setup - Prevent extraction of files from setting progress bar to 100%
Another option is to use a "marquee" (= infinite) progress bar style.
See Progress bar control styles.
[Run]
FileName: "process1"; BeforeInstall: SetMarqueeProgress(True)
FileName: "process2"
FileName: "process3"; AfterInstall: SetMarqueeProgress(False)
[Code]
procedure SetMarqueeProgress(Marquee: Boolean);
begin
if Marquee then
begin
WizardForm.ProgressGauge.Style := npbstMarquee;
end
else
begin
WizardForm.ProgressGauge.Style := npbstNormal;
end;
end;
Works even on Windows XP, despite not being listed in the official Microsoft documentation anymore. Tested on Windows XP SP3.
As an addition to Martin Prikryl answer (https://stackoverflow.com/a/34349900):
When this style should be set on the uninstall form, the call looks slightly different:
procedure SetMarqueeProgressUninstall(Marquee: Boolean);
begin
if Marquee then
begin
UninstallProgressForm.ProgressBar.Style := npbstMarquee;
end
else
begin
UninstallProgressForm.ProgressBar.Style := npbstNormal;
end;
end;
This can be easily called from the InitializeUninstallProgressForm event and the original one from InitializeWizard if there are no files to be installed at all.

ORA-29283: invalid file operation ORA-06512: at "SYS.UTL_FILE", line 536

Below is the code i use to extract data from a table to a flat file.
BEGIN
DECLARE
file_name VARCHAR2(50);
file_handle utl_file.file_type;
BEGIN
file_name := 'table.txt';
file_handle := utl_file.fopen('SEND',file_name,'W');
FOR rec in(
SELECT column 1
||'~'||column 2
||'~'||column 3 out_line
FROM table1)LOOP
UTL_FILE.PUT_LINE(file_handle,rec.out_line);
UTL_FILE.FFLUSH(file_handle);
END LOOP;
UTL_FILE.FCLOSE(file_handle);
END;
end;
This code is working fine in our development database but its throwing the below error if i execute in a new DB.
Error starting at line 1 in command:
BEGIN
DECLARE
file_name VARCHAR2(50);
file_handle utl_file.file_type;
BEGIN
file_name := 'table.txt';
file_handle := utl_file.fopen('SEND',file_name,'W');
FOR rec in(
SELECT column 1
||'~'||column 2
||'~'||column 3 out_line
FROM table1)LOOP
UTL_FILE.PUT_LINE(file_handle,rec.out_line);
UTL_FILE.FFLUSH(file_handle);
END LOOP;
UTL_FILE.FCLOSE(file_handle);
END;
end;
Error report:
ORA-29283: invalid file operation
ORA-06512: at "SYS.UTL_FILE", line 536
ORA-29283: invalid file operation
ORA-06512: at line 7
29283. 00000 - "invalid file operation"
*Cause: An attempt was made to read from a file or directory that does
not exist, or file or directory access was denied by the
operating system.
*Action: Verify file and directory access privileges on the file system,
and if reading, verify that the file exists.
Oracle directory 'SEND' points to some UNIX directory which has rights as
'rwxrwsr-x' (Octal 2775)
Oracle Version:11g
Please help me to solve this issue.
Guys please do let me know if you require more data from me to solve this question.
So, #Vivek has got the solution to the problem through a dialogue in the Comments rather than through an actual answer.
"The file is being created by user oracle just noticed this in our development database. i'm getting this error because, the directory where i try to create the file doesn't have write access for others and user oracle comes under others category. "
In the absence of an accepted answer to this question I proffer a link to an answer of mine on the topic of UTL_FILE.FOPEN(). Find it here.
P.S. I'm marking this answer Community Wiki, because it's not a proper answer to this question, just a redirect to somewhere else.
Assume file is already created in the predefined directory with name "table.txt"
1) change the ownership for file :
sudo chown username:username table.txt
2) change the mode of the file
sudo chmod 777 table.txt
Now, try it should work!
On Windows also check whether the file is not encrypted using EFS. I had the same problem untill I decrypted the file manualy.
I had been facing this problem for two days and I found that the directory you create in Oracle also needs to created first on your physical disk.
I didn't find this point mentioned anywhere i tried to look up the solution to this.
Example
If you created a directory, let's say, 'DB_DIR'.
CREATE OR REPLACE DIRECTORY DB_DIR AS 'E:\DB_WORKS';
Then you need to ensure that DB_WORKS exists in your E:\ drive and also file system level Read/Write permissions are available to the Oracle process.
My understanding of UTL_FILE from my experiences is given below for this kind of operation.
UTL_FILE is an object under SYS user. GRANT EXECUTE ON SYS.UTL_FILE TO
PUBLIC; needs to given while logged in as SYS. Otherwise, it will
give declaration error in procedure. Anyone can create a directory as
shown:- CREATE OR REPLACE DIRECTORY DB_DIR AS 'E:\DBWORKS'; But CREATE
DIRECTORY permission should be in place. This can be granted as
shown:- GRANT CREATE ALL DIRECTORY TO user; while logged in as SYS
user. However, if this needs to be used by another user, grants need
to be given to that user otherwise it will throw error. GRANT READ,
WRITE, EXECUTE ON DB_DIR TO user; while loggedin as the user who
created the directory. Then, compile your package. Before executing
the procedure, ensure that the Directory exists physically on your
Disk. Otherwise it will throw 'Invalid File Operation' error. (V.
IMPORTANT) Ensure that Filesystem level Read/Write permissions are in
place for the Oracle process. This is separate from the DB level
permissions granted.(V. IMPORTANT) Execute procedure. File should get
populated with the result set of your query.
The ORA-29283: invalid file operation is also raised on utl_file.put if there is an attempt to write line longer than max_linesize in text mode. max_linesize is optional 4th parameter of utl_file.fopen function defaulting to 1024.
(My case was dumping CSV from within Oracle in Docker into file in host directory mapped as Docker volume and I was misleaded by this error for pretty significat time - I seeked cause in filesystem rights or volume mapping between Docker and host, actually it was so stupid cause.)
UPDATE: another occurence of same exception also happened on utl_file.fopen. The database rejected to create file even if the file did not exist before. The directory in which the attempt of file creation happened was mapped on Docker volume. It started to work if the zero-sized file was created on host machine in advance. Attempt to create file from within container (touch /dir/file) failed though. Perhaps some docker issue - it disappeared after restarting Docker Desktop.
You need give permission by creating folder.
create or replace directory DINESH as '/home/oracle/DINESH/';
grant read, write
on directory DINESH
to public;
Simple PLSQL to open a file,
-- write two lines into the file,
-- and close the file
declare
fhandle utl_file.file_type;
begin
fhandle := utl_file.fopen(
'DINESH' -- File location
, 'test_file.txt' -- File name
, 'w' -- Open mode: w = write.
);
utl_file.put(fhandle, 'Hello world!'|| CHR(10));
utl_file.put(fhandle, 'Hello again!');
utl_file.fclose(fhandle);
exception
when others then
dbms_output.put_line('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
raise;
end;
test_file.txt file created in /home/oracle/DINESH.

Resources