I want to create a .txt file and write to it at any moment at run-time. To do this, I'm using the AssignFile() function. But I am having trouble in instances where my file already exists. I get an error that says: File access denied.
To better explain, see these two examples:
Ex1: if I call AssignFile() the first time when the file does not exist, OK! But, if the file exists, this does not work.
Ex2: if I call AssignFile() the second time (when AssignFile() was successful the first time), this also does not work.
Is this a bug in the AssignFile() function?
var
myfile: TextFile;
Procedure WriteFileContent(const MyTxtFile: string; MyNumber: DWORD);
var
F: TextFile;
Begin
If FileExists(MyTxtFile) Then
Begin
AssignFile(F, MyTxtFile);
Rewrite(F);
Writeln(F, '0x' + IntToHex(MyNumber,8));
CloseFile(F);
End;
End;
begin
try
// Calling AssignFile() by first time
AssignFile(myfile, 'myfile.txt');
Rewrite(myfile);
CloseFile(myfile);
setfileattributes('myfile.txt', FILE_ATTRIBUTE_HIDDEN);
Sleep(5000);
// Calling AssignFile() by second time
WriteFileContent('myfile.txt', 123456789);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
It is not AssignFile() that fails, but your call to Rewrite() on a file with the Hidden attribute set. Following explains it:
Typically you call Rewrite(F) in order to erase the file and write new data to it with subsequent Write(F, ...) or WriteLn(F, ...) calls.
From docs (System.Rewrite):
If an external file with the same name already exists, it is deleted
and a new empty file is created in its place.
There is no problem opening the file for writing with the Append() command.
(Based on above I drew the conclusion that it is the deletion that fails with the Access denied message. That was cutting the corners too much.)
Beaten by comments I traced through the code and compared actual code with MSDN documentation for CreateFile:
Actual code:
// if mode is fmOutput (as it is for Rewrite)
OpenMode = GENERIC_WRITE
Flags = CREATE_ALWAYS
// ...
Temp := CreateFile(t.Name, OpenMode, FILE_SHARE_READ, nil, Flags, FILE_ATTRIBUTE_NORMAL, 0);
And documentation:
If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile
fails and sets the last error to ERROR_ACCESS_DENIED if the file
exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM
attribute.
Calling Rewrite() on a existing file with the hidden attribute fails always.
Related
I have a main.c function and a subfunction that is called within it. In the subfunction I have used CreateFile to make a file. I then use CloseHandle to close the handle to that file. When I use fopen_s after that (within the subfunction) it works with both read and write modes. But if I use fopen_s in the main function afterwards, I can only open with read access, or else I get error code 13 - permission denied. The parameters of my CreateFile function are as follows:
hAppend = CreateFile(centralDataFilepath, // open central data file
FILE_APPEND_DATA, // open for writing
FILE_SHARE_READ|FILE_SHARE_WRITE, // allow multiple readers
NULL, // no security
OPEN_ALWAYS, // open or create
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
And I use fopen_s as follows:
FILE *f2;
errno_t errorCode3 = 0;
errorCode3 = fopen_s(&f2, centralDataFilepath, "a+");
fclose(f2);
I don't actually know if CreateFile has anything to do with this, it seems like the permission of the file changes after I exit the subfunction? I need to be able to write to this file, would anyone know why I am getting this permission denied error, and how to fix it?
As described here:
Files that are opened by fopen_s and _wfopen_s are not sharable.
Function failed because it can't lock file for writing. You need to use _fsopen instead. Try this:
f2 = _fsopen(centralDataFilepath, "a+", _SH_DENYNO);
I have noticed that SoundPlay does not work with every wav I use. I can play the files normally, but when I use SoundPlay, some of them won't play and throw an error. I tried to get more details about the error but the exception does not show anything.
In the sample code the first file does not play and throws an exception but 'e' is empty. If I comment it out the other two plays without any problem. Any ideas?
try
{
SoundPlay, c:\Alarm Files\La Cucaracha - Intro.wav, Wait ; THIS DOES NOT PLAY
SoundPlay, c:\Alarm Files\Marimba.wav, Wait ; PLAYS WITH NO ERROR
SoundPlay, c:\Alarm Files\Train Crossing.wav, Wait ; PLAYS WITH NO ERROR
}
catch e
{
MsgBox, An exception was thrown!`nDetails: %e%
}
return
Per the documentation
Known limitation: If the WAIT parameter is omitted, the OS might consider the playing file to be "in use" until the script closes or until another file is played (even a nonexistent file).
SoundPlay, FILEPATH, Wait
As an obscure alternative you could try running the audio via a DLL call.
FilePath := "c:\Alarm Files\La Cucaracha - Intro.wav"
DllCall("winmm.dll\PlaySound", AStr, FilePath, uint, 0, uint, 0)
I have a delphi form with a button on it. At the click of this button, it allows user to browse for a file and copy the file to a directory.
My code for the function is this:
function TdmData.CopyAFile(Const Sourcefile, DestFile: string): boolean;
var Src, Dest : PChar;
begin
Src := StrAlloc(Length(SourceFile)+1);
Dest := StrAlloc(Length(DestFile)+1);
try
StrPCopy(Src,SourceFile);
StrPCopy(Dest,DestFile);
result := (CopyFile(Src,Dest,FALSE));
finally
StrDispose(Src);
StrDispose(Dest);
end;
end;
The click event for the button:
CopyAFile(fn, Path +'\'+ ExtractFileName(fn));
What I cant understand when I run this form and press the button on a win XP machine, it works fine, if I browse to the directory to where it is being copied to I can see the file in there.
However running this form on a later OS such as Win 8.1 it does not copy the file, again checking the directory I see no file in there.
I don't get any errors, I've stepped through the code which goes through fine.
Has anyone ever come across this or have an idea what the cause could be? If so any help would be great.
You are not doing any error checking.
If the CopyFile function fails, the return value is zero. To get extended error information call GetLastError (or raise an exception via RaiseLastOSError)
e.g.
if not CopyFile(A, B, False) then
RaiseLastOSError;
or equivalently
Win32Check(CopyFile(A, B, False));
BTW, correct usage is:
CopyFile(PChar(Sourcefile) , PChar(Destfile), False);
No need for the extra allocations.
If you do not include a UAC manifest, then your application is running in virtualized mode. And saving files to restricted areas e.g. Program Files will not raise any errors but actually save the file into a virtual store location e.g. [CSIDL_LOCAL_APPDATA]\VirtualStore\Program Files.
I am facing this strange problem.
To delete a file unlink() API is called in my code. This call removes the file and succeeds on non-windows platforms. On windows it succeeds (returns 0) but doesn't remove the file.
To experiment I added a loop to call same API repeatedly. In second iteration I got an Permission denied error, Error code =13. Though read/write attributes are set on file and program has full permission to access the file.
I then called DeleteFile() instead of unlink() API. To my surprise I see the same result,call succeeded i.e. returned 1 but file is not removed physically.
I checked through unlocker utility, no other program is accessing the file except the program which is trying to remove this file.
Does anyone has idea what else could be wrong ?
Edit1:
Just to ensure file was not opened at the time of removing it. I saved the handle when file was created and tried to close before removing the file but I got error "'UNOPENED' (Errcode: 9 - Bad file descriptor)". Thus I conclude the file was not open at the time of removing it.
Edit2
As requested, here is the simplified version of code used to create and remove the file.
// Code to create the file
int create_file(const char* path)
{
HANDLE osfh; /* OS handle of opened file */
DWORD fileaccess; /* OS file access (requested) */
DWORD fileshare; /* OS file sharing mode */
DWORD filecreate; /* OS method of opening/creating */
DWORD fileattrib; /* OS file attribute flags */
SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength= sizeof(SecurityAttributes);
SecurityAttributes.lpSecurityDescriptor= NULL;
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
fileaccess= GENERIC_WRITE;
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
filecreate= CREATE_NEW;
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
{
// error handling
}
}
//Code to delete the file -
int remove_file (const char* name)
{
if ((err = unlink(name)) == -1)
{ //Error handling }
}
Edit3
As pointed by Joachim Pileborg and icabod, that DeleteFile() does not remove file if it is still open. As suggested by Remy Lebeau, to use process explorer. I found that one handle to file was indeed open when I closed that from process explorer file deleted like a charm :)
I had also mentioned in the Edit1 when I tried to close the file I got an error. It happened because the file descriptor I get from createfile() is not the actual handle returned by CreateFile() API instead a logical mapped handle due to underlying code complexities to support other non-windows platforms. Anyways, now I understood the root cause of problem but I was expecting if a file with open handle is passed to DeleteFile() API then it should fail in first attempt rather succeed and wait for open handles to close.
Assuming that you call your Createfile function, then later call your remove_file function... you still have a handle open to the file. The WinAPI function CreateFile, if it succeeds, keeps a handle open on the file. In your provided code, you don't close that handle.
From the documentation on DeleteFile:
The DeleteFile function marks a file for deletion on close. Therefore, the file deletion does not occur until the last handle to the file is closed. Subsequent calls to CreateFile to open the file fail with ERROR_ACCESS_DENIED.
My guess is that you still have a handle open, and when you close that handle the file will be deleted.
However, your sample code is incomplete, so it is difficult to tell.
I want to point to a http://somesite.com/somefile.exe and check the file version of the exe server side and compare the version info to the same .exe file all ready on my computer. If the server side file is newer then I want to down load it.
I have functions to download the file and check the file version but I want to check if the file version is newer than the one i have on my computer.
I do not want to download the exe to my computer and then check the file version.
Has anyone here been able to do this?
function GetVersion(sFileName:string): string;
var
VerInfoSize: DWORD;
VerInfo: Pointer;
VerValueSize: DWORD;
VerValue: PVSFixedFileInfo;
Dummy: DWORD;
begin
VerInfoSize := GetFileVersionInfoSize(PChar(sFileName), Dummy);
GetMem(VerInfo, VerInfoSize);
GetFileVersionInfo(PChar(sFileName), 0, VerInfoSize, VerInfo);
VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize);
with VerValue^ do
begin
Result := IntToStr(dwFileVersionMS shr 16);
Result := Result + '.' + IntToStr(dwFileVersionMS and $FFFF);
Result := Result + '.' + IntToStr(dwFileVersionLS shr 16);
Result := Result + '.' + IntToStr(dwFileVersionLS and $FFFF);
end;
FreeMem(VerInfo, VerInfoSize);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Http: TIdHTTP;
MS: TMemoryStream;
begin
Http := TIdHTTP.Create(nil);
try
MS := TMemoryStream.Create;
try
Http.OnWork:= HttpWork;
Http.Get('http://live.sysinternals.com/ADExplorer.exe', MS);
MS.SaveToFile('C:\ADExplorer.exe');
finally
MS.Free;
end;
finally
Http.Free;
end;
end;
You cannot access the file version remotely. You need to either download the file locally first, or you need to store the file version in a separate file that you can download, or you need to write a server-side script that your client can send a request to and have it access the file version and return it back to your client.
A better option is to use HTTP's built-in "Conditional GET" feature instead (if the server supports it). Your client can include an "If-Modified-Since" header in its request, then the server will deliver the requested file only if it has been modified on the server-side after the requested timestamp. Otherwise a 304 reply code will be sent back indicating the client already has the latest file. Read RFC 2616 Section 14.25 for more details.
You can't check the FileVersion of the file without physically having it to inspect, which means you have to be able to have all the bytes available, and the file version API functions expect a physical disk file. (IOW, you can't do this without downloading the file to your local drive first.)
Besides, you're already fully downloading it to memory with the HTTP GET anyway, so you're not saving anything in bandwidth in the first place.
The alternative (if it's an option) is to have a file on the server that contains the version number that the local file can download and read instead. If you can't do that, you're probably out of luck and will have to do the full download.