Lazarus 2.2.0 cannot create file on disk? - lazarus

The code below shows: "Unable to create file "test.txt". Access is denied."
var F: TFileStream;
begin
F := TFileStream.Create('test.txt', fmCreate);
F.free;
end;
Am I doing something wrong? Folder is not protected in any way and all other programs can write files there. Lazarus 2.2.0 on Windows 7.

It doesn't guaranteed create the file in the same dir as the EXE. It creates the file in the working dir of the application, which is not necessarily the EXE dir, which varies depending on how you execute the EXE.
Try
var sExePath : string;
..
sExePath := includetrailingpathdelimiter(ExtractFilePath(paramstr(0)));
F := TFileStream.Create(sExePath+'test.txt', fmCreate);
Note this is similar to Delphi

Related

How find shortcut name by program name?

Is there some way to find the name of a shortcut (present on desktop) through the associated program name?
Ex:
Filename:
C:\Program Files\Mozilla Firefox\firefox.exe
and result in:
C:\Users\Public\Desktop\Firefox.lnk
I found something near to this, but is made the opposite way (returns the associated program name by shortcut name).
The application knows nothing about shortcuts that are created to point to it, so this isn't possible. You'd have to iterate every file in the user's Desktop folder looking for shortcut files, open them using IShellLink, and look to see if they launched the application you're looking to find. Here's an example of doing so. You'll need to add ShellAPI to your uses clause. FileName is the fully qualified name of the shortcut file.
function GetLinkPath(const FileName: WideString): String;
var
ShellLink: IShellLink;
Path: array[0..MAX_PATH] of Char;
begin
Result := '';
ShellLink := CreateComObject(CLSID_ShellLink) as IShellLink;
if (ShellLink as IPersistFile).Load(PWideChar(FileName), STGM_READ) = 0 then
begin
if ShellLink.GetPath(Path, MAX_PATH, nil, SLGP_SHORTPATH) = 0 then
Result := Path;
end;
end;

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

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;

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”.

How to get the parent directory path of a path in FreePascal/Lazarus?

I have a path to a directory saved as a string, and wanted to know how I can easily and robustly extract the parent directory from this string?
I tried to see if there is some method for this in FileUtil and SysUtils, but haven't found anything so far.
The simplest way is to find the last path delimiter character and trim the source string. BTW there are some alternative:
program Project1;
uses
sysutils;
var
sExe: string;
sParent: string;
sParentProper: string;
begin
sExe := ExtractFilePath(ParamStr(0)); // Get executable directory
Writeln(sExe);
sParent := IncludeTrailingPathDelimiter(sExe) + '..' + PathDelim; // Make parent path for executable
Writeln(sParent);
sParentProper := ExpandFileName(sParent); // Get absolute path based on relative path
WriteLn(sParentProper);
Readln;
end.
And output is:
C:\Users\nd\AppData\Local\Temp\
C:\Users\nd\AppData\Local\Temp\..\
C:\Users\nd\AppData\Local\
So using this technique the proper way is ExpandFileName(IncludeTrailingPathDelimiter(sBasePath) + '..')
PS: We are using only sysutils unit so it is pure FPC solution and it is not require any LCL libraries.
An even simpler way to do this would be:
parentDirPath := ExtractFilePath(ExcludeTrailingPathDelimiter(thePath));
This works on the three major platforms (Linux, Mac OS X and Windows), and thePath may refer to a file or a folder.
Well, I of course figured it out only after asking about it here:
parentDirPath := FileUtil.ExtractFileNameOnly(
FileUtil.ChompPathDelim(theSubDirPath));
... will do!
The FileUtil.ChompPathDelim() part is necessary to "fool" FPC to believe the top folder is a "file" (so no trailing slash allowed).

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.

Resources