Inno Setup - Create folder in Public Users Documents in Windows 10 - windows

I am trying to add a folder to an installation which will eventually hold user output data. I can't put a folder into Program Files because users will not have the required permissions to write to it.
If it is not being installed to Program Files, then the data folder can be created inside the application folder (this is working fine).
I have a little piece of code to detect whether the installation was made to Program Files and, if so, I wanted to use CreateDir() to make a data folder in C:\Users\Public\Documents\{'MyAppName}\DB This seems to fail, in [Code] even though the standard Inno Setup script works:
[Dirs]
Name: "{commondocs}\{#MyAppName}\DB"
I am using the DeinitialiseSetup() procedure to make this happen at the end of installation, once the path is definite.
This is my code:
[Code]
procedure DeinitializeSetup();
begin
{ If it has been installed in the Program Files Folder put DB in Public Documents }
if Pos(ExpandConstant('{pf}'),ExpandConstant('{app}')) > 0 then
begin
if not CreateDir (ExpandConstant('{commondocs}\{#MyAppName}\DB')) then
MsgBox('Error: Data folder could not be created.', mbInformation, MB_OK);
end
else
begin
if not CreateDir (ExpandConstant('{app}\DB')) then
MsgBox('Error: Data folder could not be created.', mbCriticalError, MB_OK);
end;
end;
Following another SO suggestion I used:
PrivilegesRequired=lowest
in the script but it did not work with or without this. I am beginning to think this may be a permissions issue but am not sure why, as the installer standard [Dirs] script works fine.
This is not the same as the other questions regarding identifying the path - I have got all the paths I want, only: [Code] CreateDir() does not seem able to create a folder in {commondocs}.
Many thanks for any suggestions.

My guess is that the {commondocs}\{#MyAppName} does not exist. CreateDir function can create a single directory only. It won't create parent folders for you, if they do not exist (contrary to [Dirs] section entry).
You can use ForceDirectories function instead:
Creates all the directories along the specified directory path all at once.
Side note: Do not use DeinitializeSetup to create the directories – Is is triggered even if the installation fails, or even if the user cancels the installation.
Use CurStepChanged(ssPostInstall):
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
{ Your code }
end;
end;

Related

How to use the {app} path name in Inno Setup UninstalledAll message?

I see how to use the macro [name] or [ver] in a message in Inno Setup. Is there any way to use the application path (specified elsewhere in Inno Setup by {app})? When I uninstall my app, I want to tell the user that a file still exists on the disk with the pathname of the app and that there's an environmental variable that contains it. I don't want to delete the file with the pathname and I don't want to clear the variable, because they might have other paths in them, but I do want to warn the user.
This is the Inno Setup entry I'm trying to fix:
[Messages]
UninstalledAll=%1 uninstall complete.%n%nI did not try to remove the APP-PATHNAME-HERE from the PATH16 environment variable, or from the PATH statement in autoexec.bat in your otvdm\C folder. You may safely ignore these.
That's not a custom message. That's a standard message. You cannot modify standard messages this way.
All you can do is to display yet another message. For example from CurUninstallStepChanged(usPostUninstall).
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
Message: string;
begin
if CurUninstallStep = usPostUninstall then
begin
Message :=
Format('I did not try to remove the %s from the PATH16 environment variable, ' +
'or from the PATH statement in autoexec.bat in your otvdm\C folder. ' +
'You may safely ignore these.', [ExpandConstant('{app}')]);
MsgBox(Message, mbInformation, MB_OK);
end;
end;

How can this code generate a file with a filename containing a colon on Windows?

I see the pascal code below on another forum. How can this code be possible?
Doesn't windows allow user to create a filename with colon?
However, this code only work when you create a file with name contains colon in root directory of drive (Ex: D:, C:, E:, etc). And when the file is created, it's completely invisible.
uses crt, sysutils;
var
f, f1: file of char;
c:char;
begin
clrscr;
assign(f, 'D:\src\payload.exe');
reset(f);
assign(f1, 'D:\:malware.exe');
rewrite(f1);
while not eof(f) do
begin
read(f, c);
write(f1, c);
end;
close(f1);
close(f);
executeprocess('D:\:malware.exe', ''); //here
readln;
erase(f1);
end.
You can compile the code above with free pascal
fpc [filename].pas
Thank you.
EDIT:
For more detail:
You can execute D:\:malware.exe from CreateProcess (WinAPI)
You can't execute D:\:malware.exe from command line, path, etc
I use process explorer to find D:\:malware.exe path/contain folder. However, when I pressed explore button, it takes me to %UserProfile%
It only work for D:\:malware.exe, D:\\malware.exe, D:\/malware.exe
It works because it is possible*. You can name files all kinds of horrid things, regardless of proper naming convention.
*Yes, I know MSDN lists colons as “reserved”. That is not the same as forbidden or impossible. It is only the same as “don’t do it”.

Inno Setup creating an unwanted empty folder with value in DefaultDirName

Inno Setup installer is creating an unwanted empty folder using my initial value of DefaultDirName, even though I have set WizardForm.DirEdit.Text = 'c:\preferredinstalldir' in CurStepChanged (curStep = ssInstall). The installer puts the files in the right installation folder, but because I have to assign a dummy value to DefaultDirName, it creates that dummy folder. I have tried using a {code:xx} function for the DefaultDirName but since the actually folder I want hasn't been determined until the wizard runs, I seem to need a placeholder folder (but I don't want it created!)
AppId = {code:GetAppId}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppCopyright={#MyAppCopyright}
VersionInfoCopyright={#MyAppCopyright}
AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetFilesDestDir} //this says error path not valid, no root/unc etc etc because the function has no path set yet
DefaultDirName=c:\mydummyfolder //this creates a dummy folder even though the files are installed correctly to location i set later in CurStepChanged (I assign WizardForm.DirEdit.Text := InstallPath )
DisableDirPage=yes
DefaultGroupName=SomeName
DisableProgramGroupPage=yes
OutputBaseFilename=mysetup_setup
Compression=lzma
SolidCompression=yes
UsePreviousAppDir=no
UsePreviousLanguage=no
UninstallFilesDir = {code:GetFilesDestDir}\uninst
.............
function GetFilesDestDir(def:string): string;
begin
if InstallPathSet then
begin
Result := InstallPath;
end
end;
I've seen this question here
Inno Script: Strange Empty Folder
but it wasn't answered and I couldn't post a comment.
I think I've found the solution, setting CreateAppDir=no seems to do the trick.At least its no longer creating an empty folder at the initial dummy location.
I cannot reproduce what you describe.
Changing WizardForm.DirEdit.Text in CurStepChanged(ssInstall) has no effect at all. It's too late.
Anyway, just change the value sooner. For example in the InitializeWizard or CurPageChanged.

How to access user directory in lazarus?

I'm trying to open file changelog.txt and I need to open it no matter what user is opening it. It's however always located in ~/ directory. Access the file. Here's my code:
procedure TForm1.FormCreate(Sender: TObject);
var myFile : TextFile;
line : string;
begin
AssignFile(myFile, '~/changelog.txt');
Reset(myFile);
while not Eof(myFile) do
begin
ReadLn(myFile, line);
Label3.Caption := (Label3.Caption + line + #13#10);
end;
CloseFile(myFile);
end;
It doesn't work. However, if I replace ~ with the actual username, it works. However, I cannot know the username of each user that will run my program. Any ideas how can I get the username of user that started the program? Thanks!
Edit1: I have tried this, but it also includes a new line:
RunCommand('/bin/bash',['-c','whoami'],user);
This is normal. "~" is a shell level concept and thus needs a separate shell invocation to evaluate. Assignfile calls the kernel interfaces directly though and thus doesn't understand this.
Use getenvironmentvariable('HOME') to get the homedir from the environment. Better even, getuserdir allows to get the home dir in a crossplatform manner.

Can't write to a file. Oracle

I'm trying to execute these lines:
DECLARE
V_FILEHANDLE UTL_FILE.FILE_TYPE;
BEGIN
V_FILEHANDLE := UTL_FILE.FOPEN('C:\samples', '1.csv', 'w');
UTL_FILE.PUT_LINE(V_FILEHANDLE, 'sample string');
UTL_FILE.FCLOSE_ALL;
END;
Previously I've successfully executed these statements:
create directory sample as 'C:\samples';
(though I can't find the directory on the C:\ drive?)
But this gives me an output like:
ORA-29280: "invalid directory path"
*Cause: A corresponding directory object does not exist.
*Action: Correct the directory object parameter, or create a corresponding directory object with the CREATE DIRECTORY command.
Also I've tried to grant previleges to my username:
grant read, write on directory sample to brick;
But this gives me an output like
ORA-01749: you may not GRANT/REVOKE privileges to/from yourself
What am I doing wrong?
Replace
V_FILEHANDLE := UTL_FILE.FOPEN('C:\samples', '1.csv', 'w');
with :
V_FILEHANDLE := UTL_FILE.FOPEN('SAMPLE', '1.csv', 'w');
As indicated in the doc, the first parameter is the directory object name.
In older versions of Oracle, the first parameter of UTL_FILE.open used to be the directory path, but this has been deprecated since the introduction of the DIRECTORY object (in 9i?).
Thank you SOOO MUCH! I found my error. I was creating the directory like
create or REPLACE DIRECTORY dat_dir as '/u01/oracle/Desktop/Migration/Data';
Then I used it in my UTL_FILE like this
file1 := utl_file.fopen('dat_dir','output.txt','w');
I've been trying this to work for 3 days now. I found the problem, since it's in quotation mark, it's a case sensitive string. It doesn't matter if initially I tiped dat_dir, oracle stores things like this in uppercase. Your simple answer helped me realize this, thank you a million times!
The right way to do it was:
file1 := utl_file.fopen('DAT_DIR','output.txt','w');

Resources