Lazarus(Pascal) RunError(5) - pascal

My program exits with RunError(5), which would suggest that it can't access the file, which it should be able to. I have checked and the file is used as it should be, the file isn't read-only, etc. What the program does is, it creates a .dat file if one doesn't exists and uses it for saving stuff. If I run the program and the file doesn't exist, the file is created, but after that, in the same execution, the program won't access the file. This ONLY happens if the file was created in the current execution.
This is the way in which the procedures are called(the code is quite long but I am giving you the first few lines, where the error occurs):
fileName := 'labSave.dat';
CreateFile;
assign(labyrinthFile,fileName);
writeln(CheckFileSize);
and then there is each of the procedures:
procedure Initialize;
begin
fileName := 'labSave.dat';
assign(labyrinthFile,fileName);
end;
procedure CreateFile;
begin
if not FileExists(fileName) then FileCreate(fileName);
end;
function CheckFileSize: integer;
begin
reset(labyrinthFile);
CheckFileSize := FileSize(labyrinthFile);
close(labyrinthFile);
end;

According to Lazarus forum (http://forum.lazarus.freepascal.org/index.php?topic=4936.0):
Runtime Error 5 means Access denied. The file maybe readonly and you
use the wrong (default) filemode, or you try to re-open the file with
a new filehandle without having closed it before (somewhere in the
while and repeat loops possibly you assignfile more then once, then
the reset fails?).
If I recall correctly now, the workflow should be as follows for create:
AssignFile(f, filename); Rewrite(f); CloseFile(f);
and for existing file:
AssignFile(f, filename); Reset(f); CloseFile(f);
Seeing other mistakes found in your code through questions in comments, I strongly suggest you to devote more time to debugging and when such errors happen - strip out ALL of the irrelevant code and check your code design for cases like above (assigning file before creating it, etc.).

Related

How do I save a picture from a open picture dialogue to a file

Hi I'm currently using Delphi 2010.
I basically have a form where a user has to enter information about themselves and upload a picture. I have an Image component on my form. I did some research and many of the websites I looked at said to use a OpenPictureDialogue to allow the user to select an image and display it in the Image component.
My question is, how can I save this image to a file on my computer? Keeping in mind I will have multiple users adding their picture and that I will have to use the picture later on again, basically I want to use the LoadFromFile procedure to display the picture in my program later on.
I also read many websites saying to use the SavePictureDialogue, but that allows the user to select the file they want the image to be saved to and I don't want that, I want it to save to a file that only I can access.
I have this so far, I know it is very limited.
if opdAcc.Execute then
begin
if opdAcc.FileName <> '' then
begin
imgAccImage.Picture.LoadFromFile(opdAcc.FileName);
end;
end;
I am a student and my knowledge is quite limited and I would appreciate any help. :)
First of all, there is no place on the hard drive that only you can access. But you can create a folder to store your files and copy users' pictures there. This reduces the likelihood that the user will have access to these files. The usual folder for storing such files is the AppData folder. It is better to create a folder with the same name as your application in AppData and store such files there.
Suppose the GetPicturesDirectoryPath function generates the address of such a folder and ensures that this folder has already been created or will be created. The next step is to generate a unique name for the file you want to store. Note that multiple users may select files with the same name. In this case, after copying the picture selected by the second user, the image file will be written over the previous user's file. If a unique identifier is assigned to each user, this identifier is the best choice for the picture file name. But you can use the GetGUIDFileName function to create a unique address. Make sure the generated address is kept with the rest of the user information, or the connection between the copied file and the user will be lost. The implementation of all these will be something like the following:
uses IOUtils;
function GetAppDataDirectoryPath: string;
begin
...
end;
function GetPicturesDirectoryPath: string;
begin
Result := TPath.Combine(GetAppDataDirectoryPath, 'MyApp');
TDirectory.CreateDirectory(Result);
end;
function GetUniqueFilePath(const Extension: string): string;
begin
Result := TPath.ChangeExtension(
TPath.Combine(GetPicturesDirectoryPath, TPath.GetGUIDFileName),
Extension);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
DestPath: string;
begin
OpenPictureDialog1.Options := OpenPictureDialog1.Options +
[ofFileMustExist]; // make sure that selected file exists
if OpenPictureDialog1.Execute then
begin
DestPath := GetUniqueFilePath(TPath.GetExtension(OpenPictureDialog1.FileName));
TFile.Copy(OpenPictureDialog1.FileName, DestPath);
if TFile.Exists(DestPath) then
Image1.Picture.LoadFromFile(DestPath)
else
ShowMessage('Well, something went wrong!');
end;
end;
Read this to implement GetAppDataDirectoryPath.

Delphi tmediaplayer don't play mp3 file with "strange" cover image embedded

I have developed a mp3 player with Delphi (XE) using the BASS library.
Due to certain reasons, I want to remove the BASS libraries and want to use the TMediaPlayer component in Delphi (also want to "move" the project to Delphi 10 Seattle).
Now I found out that some of my mp3 files have a "strange" jpg image embedded.
Means, that the Delphi components run into an error due to the image.
With long time debugging I can say the following:
try
mplMain.FileName := CurrentSong;
progbSong.Max := mplMain.Duration;
lblDuration.Text := DurationToString(mplMain.Duration);
PlayClick(Self);
except
on E: Exception do
begin
FMX.Dialogs.MessageDlg('Cannot play song: ' + CurrentSong + #10 + #13 +
'Reason: ' + E.Message,
TMsgDlgType.mtWarning, [TMsgDlgBtn.mbOK], 0,
procedure(const AResult: TModalResult)
begin
MediaNext;
end
);
end;
end;
This line:
mplMain.FileName := CurrentSong;
causes the problem.
Diving deeper in debugging it comes to here:
FMX.Media library:
procedure TMediaPlayer.SetFilename(const Value: String);
...
FMedia := TMediaCodecManager.CreateFromFile(FFileName);
...
At the end it ends up in FMX.Media.Win:
constructor TWindowsMedia.Create(const AFileName: string);
...
HR := FGraphBuilder.RenderFile(PChar(AFileName), nil);
...
When the line
HR := FGraphBuilder.RenderFile(PChar(AFileName), nil);
is called, in debug mode, the program just returns to the IDE.
In runtime mode, nothing happens. No error message, just "nothing".
As you can see, I wrapped the related line into a try...except block, but no error is raised. The program/player doesn't continue.
That's very bad for me, because I wanted to catch this "special case" and log the affected mp3 files to a logfile so that I can change the embedded image.
I found out that it is only caused by some images. Maybe they are "somehow corrupt", but shown in all other players.
When I remove the image and embed a "new" one and save the file, everything is fine and the TMediaPlayer can play the file.
How can I catch this certain kind of "error" to get the list of affected files?
I got it managed now.
Only in debug mode the application/player is exited without any thrown error and I find myself back in the IDE.
During runtime the try...except block works, when I chose an "affected file" manually. For the case that one file is played ("good one") and the next file is a "bad one", I had to change my "MediaNext" procedure. In this procedure I also had a try...except block when the filename was associated to the TMediaPlayer, but I just had set a bool variable for further use and didn't "jump" to the next file.
The code just was:
try
mplMain.FileName := CurrentSong;
except
on E:Exception do
SongNotPlayable := true;
end;
Here I can implement a routine to log the affected mp3 files into a logfile and then jump to the next file (if exists). :-)
Thanks again to all!

Read/Write to file on old IBM PS/2 in turbo pascal 5.5

The Question: I recently acquired a 1989 IBM PS2 and I am trying move large files from my newer UNIX-based machine to this IBM via floppy. I have a bash script that splits my files into ~2MB chunks, now I am trying to write a pascal program to reconstruct these files after they have been transferred.
I am unable to find the correct read/write to file methods on this computer. I have tried various pascal tutorial sites, but they are all for newer versions (the site I followed with File Handling In Pascal). I am able to create an empty file (as described below), but I am unable to write to it. Does anyone know the correct pascal read and write methods for this type of computer?
I know this is an obscure question, so thank you in advance for any help you can give me!
The Details:
The current test code that creates a file correctly is this:
program testingFiles;
uses Crt, Win;
const FILE_NAME = 'testFile.txt';
var outFile : File;
begin
writeln('creating file ...');
Assign(outFile, FILE_NAME);
rewrite(outFile);
end.
This is some test code that does not work, the method's append() and close() could not be found:
program testingFiles;
uses Crt, Win;
const FILE_NAME = 'testFile.txt';
var outFile : File;
begin
writeln('creating file ...');
Assign(outFile, FILE_NAME);
append(outFile);
writeln('this should be in the file');
close(outFile);
end.
This is an alternative that also did not work, the writeln() method only ever prints to the terminal. But otherwise this does compile.
program testingFiles;
uses Crt, Win;
const FILE_NAME = 'testFile.txt';
var outFile : File;
begin
writeln('creating file ...');
Assign(outFile, FILE_NAME);
rewrite(outFile);
writeln('this should be in the file');
close(outFile);
end.
The system: As was previously mentioned, this is a 1989 IBM PS2.
It has Windows 3.0 installed and can also run DOS and MS-DOS terminals.
It has Microsoft SMARTDrive Disk Cache version 3.06
It has Turbo Pascal 5.5 installed and I am using turbo as my command line pascal editor. (the readme was last updated in 1989)
It has Turbo debugger 1.5 installed.
Again, I know this is an obscure question, so thank you in advance for any help you can give me!
My Pascal memory is VERY rusty... but as other have pointed out, here is what you should consider:
program testingFiles;
uses Crt, System;
//No need of importin Win Win is for Windows enviorment, however I'm not sure if you need to use System, Sysutils or was there a Dos class???
const FILE_NAME = 'testFile.txt';
var outFile,inFile : File;
begin
writeln('creating file ...');
Assign(outFile, FILE_NAME);
rewrite(outFile);
//Now Open the first chunk of the file you want to concatenate
AssignFile(inFile, "fisrt_chunk.dat");
reset(inFile);
while not eof(inFile) do
begin
readln(inFile, s);
writeln(outFile,s);
end;
close(inFile);
end.
I don't have Turbo/Borland Pascal installed any longer so I couldn't compile it myself, no promise that it will work it is more like an idea:
Key thing to remember, readln and writeln will ALWAYS add a return at the end of the string/line, read and write on the other hand will leave the cursor wherever it is without jumping to a new line.
Here's some old Delphi code that should be at least close to syntax-compatible that will give you the gist of copying a file (with limited error checking and resource handling in case of error - I'll leave that as an exercise for you). It works to copy both binary and text content.
program Project2;
uses
SysUtils;
var
NumRead, NumWritten: LongInt;
pBuff : PChar;
SrcFile, DstFile: File;
const
BuffSize = 2048; // 2K buffer. Remember not much RAM available
InFileName = 'somefile.txt';
OutFileName = 'newfile.txt';
begin
NumRead := 0;
NumWritten := 0;
AssignFile(SrcFile, InFileName);
AssignFile(DstFile, OutFileName);
// Allocate memory for the buffer
GetMem(pBuff, BuffSize);
FileMode := 0; // Make input read-only
Reset( SrcFile, 1 );
FileMode := 2; // Output file read/write
Rewrite( DstFile, 1 );
repeat
// Read a buffer full from input
BlockRead(SrcFile, pBuff^, BuffSize, NumRead);
// Write it to output
BlockWrite(DstFile, pBuff^, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead);
// Cleanup stuff. Should be protected in a try..finally,
// of course.
CloseFile(SrcFile);
CloseFile(DstFile);
FreeMem(pBuff);
end.
The above code compiles under Delphi 2007 currently (the oldest version I have installed). (See the note below.)
As a side note, this was from an archived version of some code I had that compiled both for 16-bit Delphi 1 and was extended to also compile under 32-bit Delphi 2 back in the mid-to-late 90s. It's still hanging around in my source repositories in an old tagged branch. I think I need to do some pruning. :-) I cleaned it up to remove some other functionality and removed a lot of {$IFDEF WIN32} ... {$ELSE} ... {$ENDIF} stuff before posting.)

What have I missed in this custom format copy and paste?

My copy code:
if OpenClipboard(mainwnd.Handle) then
MemHandle := GlobalAlloc(GHND or GMEM_SHARE, Succ(StrLen(pLclCopies)));
if MemHandle <> 0 Then
Begin
try
StrCopy(GlobalLock(MemHandle), pLclCopies);
GlobalUnlock(MemHandle);
SetClipboardData(cf_LocalVar,MemHandle);
Finally
CloseClipboard;
GlobalFree(MemHandle);
end;
end;
and my paste code:
if clipboard.HasFormat(cf_LocalVar) then
begin
ClipBoard.Open;
try
MyHandle := Clipboard.GetAsHandle(cf_LocalVar);
LocalsTextPtr := GlobalLock(MyHandle);
CheckForCopiedLocals(LocalsTextPtr, TextPtr); //What I do with the pasted data.
GlobalUnLock(MyHandle);
finally
Clipboard.Close;
end;
end;
My goal is to copy not only text from a special editor in my program, but also to copy some underlying variable data related to that editor. Most everything seems to be working fine clipboard wise - I'm seeing my copied text, and the 'cf_LocalVar' format appear in the ClipBook viewer on windows.
It's when I get to the paste side and the line
LocalsTextPtr := GlobalLock(MyHandle); doesn't get the copied data from the first bit of code. I see that it makes it into pLclCopies but then can't be sure that it's stored in the clipboard.
NB I have left out emptyclipboard from my code as this would get rid of the cf_text that I need along with the cf_LocalVar.

CopyFileEx and 8.3 file names

Suppose you have 2 files in the same directory:
New File Name.txt and
NewFil~1.txt
If you use CopyFileEx to copy both files to the same destination, maintaining the same names, you will end up having only ONE file (the second one replaces the first one) which can be sometimes not a good thing. Any workaround for this behavior?
This happens at file system level so you there is no much you can do if you don't want to disable SFN generation at all.
The way I use to handle this problem is to:
1) Before the file is copied, I check if the file name exists.
2) If there is a collision then I first rename the existing file top some temporary name
3) Then I copy the file
4) rename the first file back.
To detect the collision do something like this:
function IsCollition(const Source, Destination: string; var ExistingName: string): boolean;
var
DesFD: TSearchRec;
Found: boolean;
ShortSource, FoundName: string;
begin
ShortSource:= ExtractFileName(SourceName);
Found:= false;
FoundName:= WS_NIL;
if (FindFirst(DestinationName, faAnyFile, DesFD) = 0) then
begin
Found:= true;
FoundName:= DesFD.Name;
SysUtils.FindClose(DesFD);
end;
if (not Found) or (SameFileName(ShortSource, FoundName)) then
begin
Result:= false;
end else
begin
// There iis a collision:
// A file exists AND it's long name is not equal to the original name
Result:= true;
end;
ExistingName:= FoundName;
end;
There's not a great solution for the automatic generation of short filename aliases. If your application will have adequate privileges, you might be able to use the SetFileShortName() API. Another (heavy handed) alternative might be to disable short name alias generation altogether, though I'd be reluctant to require this of your users. See
http://support.microsoft.com/kb/210638/EN-US/
http://technet.microsoft.com/en-us/library/cc778996.aspx
http://blogs.msdn.com/adioltean/archive/2005/01/27/362105.aspx
for more details.

Resources