Howto create threadsave a file without overwriting an existent one? - delphi

until now, whenever I wanted to create a file without overwriting an existing one, I've done something like this:
if not FileExists(filename) then
stream := TFileStream.Create(filename, fmCreate);
But that's not threadsafe. So now I am looking for a threadsafe version.
Perhaps I can combine some modes so that TFileStream.Create(filename, fmCreate +fm???); fails if the file exists?
I need this to communicate directory-locks with old DOS programs. But the DOS programs don't hold the files opened. :-(

TFileStream's file-name based constructor relies on the WIndows API call CreateFile to create the file handle that'll be used to access the file. The API itself has multiple parameters, and especially interesting for you is the Create Disposition: if you specify CREATE_NEW, the function fails if the file already exists. You can take advantage of that by calling CreateFile yourself, then using the returned handle to create the TFileStream. You can do that because TFileStream inherits from THandleStream, inherits it's handle-based constructor and owns the handle (calls CloseHandle on the handle you pass to the constructor).
Since this relies on the OS-provided function CreateFile, it'll be trehad-safe (no race condition between FileExists() and actually creating the file. It also blocks the old application from accessing the newly crearted file until you actually close the handle.
var FH: NativeUInt;
// ...
FH := CreateFile('FileName', GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_NEW, 0, 0);
if FH = INVALID_HANDLE_VALUE then
begin
// Creating the new file failed! I'm raizing an exception, but you can do something
// better-suited for your case, like trying a new file name.
RaiseLastOSError;
end;
// Create the stream using the prepared Handle
HS := TFileStram.Create(FH);

I would keep the FileExists check because it handles most cases without relying on exception handling. For the border cases you have to handle exceptions in TFileStream constructor properly. The second thread trying to create the file should fail if you use it with share mode fmShareDenyWrite.

Related

THandle of File in MemoryStream (Delphi)

I have a file loaded in a memorystream and want to get the filehandle of it without saving the file on the harddisk.
I can't figure out how to do it.
It should return the same result as CreateFile does.
myFile:= CreateFile('myfile.exe', GENERIC_READ, FILE_SHARE_READ...
I tried it with the Memory attribute of memorystream but it doesn't return the same handle as CreateFile
mem_stream := TMemoryStream.Create;
mem_stream.LoadFromFile('myfile.exe');
mem_hFile := mem_stream.Memory;
Writeln(Format('mem_hFile: %d', [mem_hFile]));
mem_stream.Free;
I have a file loaded in a memorystream and want to get the filehandle of it without saving the file on the harddisk.
There is no file handle in TMemoryStream. What you have done is load a copy of the file's bytes into a block of memory. The TMemoryStream.Memory property returns a pointer to that memory block.
It should return the same result as CreateFile does.
Then you have to actually call CreateFile(), either directly or indirectly, such as with a TFileStream:
fs_stream := TFileStream.Create('myfile.exe', fmOpenRead or fmShareDenyWrite);
fs_hFile := fs_stream.Handle; // <-- returns the HANDLE from CreateFile()
...
fs_stream.Free;
A memory stream has no file handle associated with it. You cannot use a memory stream with any function that expects a file handle.
Whatever your problem is, getting a file handle from a memory stream is, by dint of being impossible, not the solution.
You also seem to have a misunderstanding about the numeric values of handles. You cannot compare the numeric values of two handles and expect them to be the same value if the handles refer to the same object. Two distinct file handles have different numeric value, even if they refer to the same value.

Delphi 2010 - Is File in Use?

I have a function which works ok to check if a local file is in use.
However if I map a network drive and try to check if a file from the mapped drive is in use then the result of the function is always false.
I need to wait before a large file is being copied to the mapped drive and after completion I rename the file.
If the file in not in use then i start performing various actions else i wait another minute and check again.
How can I modify the function below in order to work with mapped drive files that are constantly copied?
Thank you
function IsFileInUse(FileName: TFileName): Boolean;
var
HFileRes: HFILE;
begin
Result := False;
if not FileExists(FileName) then
begin
showmessage('Fisierul "'+Filename+'" nu exista!');
Exit;
end
else
begin
HFileRes := CreateFile(PChar(FileName),
GENERIC_READ or GENERIC_WRITE,
0,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
Result := (HFileRes = INVALID_HANDLE_VALUE);
if not Result then
CloseHandle(HFileRes);
end;
end;
What you are claiming is that CreateFile succeeds in opening a file in exclusive mode whilst another party is writing to the file. Possible explanations:
You have made a mistake with the file name and the file you are opening is not the one in use.
The other party is writing to the file without having locked it. In other words it opened the file with a share mode that allowed other parties to read and write. This would be quite unusual. If this is the case then you need to fix the other process.
The remote file server is broken and fails to respect locks. I'd regard this as quite unlikely.
I think the final option can be rejected immediately. Option 2 seems rather unlikely. Which leaves option 1. You are able to lock the file because it is not locked.
I'd also comment that the function is spurious. You can remove it. Simply attempt whatever operation you need to perform. If that operation fails due to a sharing violation you know that the file was locked. Consider also the race condition in any code using that function. The fact that a file is unlocked now does not prevent another party locking the file before you can do anything with it.

Is there a way to get my delphi program to wait for a large number of files to be copied?

I have written a program that does the following...
Monitors a folder for the creation of a new file with a specific filename that will eventually be created in a sub folder.
On creation of the file, the sub folders path is added to a queue in the form of a TList.
The files must be processed in the creation order.
A procedure is called to process all the files (images in this case) in the subfolder which involves moving the files to a network location.
The subfolder path is removed from the queue (TList).
If any more paths exist in the queue, the next path is passed to the processing procedure.
The problem I am having is that the time to copy the files to a network location varies depending on the number and size of the images so...
Is there a way to get Delphi to wait for procedure of file operation to finish?
I tried a while loop that waited for a boolean value to change (changed when the last file to be copied was found on the network) but that hung the application (even with application.processMessage) and the dirMonitor component failed to add the next sub folder to the TList.
Any suggestions would be most appreciated.
Thanks in advance.
Thanks for the replys...
I had a look at OmniThread which looks ideal... although I only have access to Delphi 7 so its a no go.
The problem Im having is that the folders take varying amounts of time to transfer due to differing sizes and network traffic etc... When a folder with a lot of images is followed by a folder with only a few images, the smaller of the two is reaching the network destination first. The network desination being a third party print spooler so the prints come off in the wrong order.
The simplified code:
procedure TForm1.programTimerTimer(Sender: TObject);
begin
if (fileOperationInProgress = false) AND (programPaused = false) then
begin
processOrderQueue;
end;
end;
procedure TForm1.processOrderQueue;
begin
// gets folder paths from queue
// processes images
// copy to print spooler (network location)
copyFolder(fromPath, toPath);
// remove temp files
end;
procedure TForm1.copyFolder(copyFrom : String; copyTo : String);
var
fos : TSHFileOpStruct;
begin
fileOperationInProgress := True;
ZeroMemory(#fos, SizeOf(fos));
with fos do
begin
wFunc := FO_COPY;
fFlags := FOF_FILESONLY or FOF_SILENT;
pFrom := PChar(copyFrom);
pTo := PChar(copyTo)
end;
ShFileOperation(fos);
fileOperationInProgress := False;
end;
Think I've come up with the answer... I'm going to do all file operationions in a single thread and set a global 'busy' boolean when it starts and change it again on completion.
That way the shell monitor won't miss messages when any file operations are in progress.
You could implement a file system watch. Essentially, you create a file handle with the following flags:
CreateFile(PChar(FDirectoryToWatch), FILE_LIST_DIRECTORY or GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, nil, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
and then create a loop to call ReadDirectoryChangesW.
Linked is an example class:
Why does ReadDirectoryChangesW omit events?
The only thing I would do differently is provide an event in the creation of the class to notify of changes (remembering that when calling the event in the Execute procedure it probably needs to be Synchronized).

Delphi Determine filesize in real time

Is it possible in Delphi to determine the size of a file as it is being copied? I get a notification when a file is first copied to a folder, but need to wait until the copy is complete before I can process the file.
I've used JclFileUtils.GetSizeOfFile(Filename) but that gives me the 'expected' file size, not the current filesize.
Regards, Pieter
Prompted by the first answer I decided to give up on trying to determine when a file copy has completed. Instead I found that using TFileStream gave me a reliable indication whether a file is in use or not.
function IsFileInUse(Filename: string; var ResultMessage: string): boolean;
var
Stream: TFileStream;
begin
Result := True;
ResultMessage := '';
try
Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
try
Result := False;
finally
FreeAndNil(Stream);
end;
Except on E: Exception do
ResultMessage := 'IsFileInUse: ' + E.Message
end;
end;
In this way I can keep on checking until the file is not in use anymore before attempting to process it.
It depends on the technique that is used by the copying function. Most copy-methods will allocate the disk space first before they start to copy a file. Thus, if you want to copy a file of 4 GB, the system starts by creating a file with random data for 4 GB in total. (Which is done lightning-fast, btw.) It then copies the data itself, but the file size is already what you expect.
This has as advantage that the sysmen can check if there's enough disk space available to actually copy the data.
If you write your own file copy function then you can have total control over how it does this. Else, you're limited to whatever the chosen copy-method offers you. So, how do you copy a file?
If you have control over the file copy process, it is easiest to have the copy routine create the file using a temporary filename, and when done, rename it to correct filename.
That way, you can use Windows folder monitoring to watch for the renaming (JCL contains a component to help with this, not sure about the name from here). When your code gets triggered you are sure the other side has finished writing the file.
A simple trick I used was to have the copying process create new files with a '$$$' extension. My code still got triggered for those but I ignored them until they were renamed to their proper filename.
Hope this helps.

How can I tell if another instance of my program is already running?

How do i tell if one instance of my program is running?
I thought I could do this with a data file but it would just be messy :(
I want to do this as I only want 1 instance to ever be open at one point.
As Jon first suggested, you can try creating a mutex. Call CreateMutex. If you get a non-null handle back, then call GetLastError. It will tell you whether you were the one who created the mutex or whether the mutex was already open before (Error_Already_Exists). Note that it is not necessary to acquire ownership of the mutex. The mutex is not being used for mutual exclusion. It's being used because it is a named kernel object. An event or semaphore could work, too.
The mutex technique gives you a Boolean answer: Yes, there is another instance, or no, there is not.
You frequently want to know more than just that. For instance, you might want to know the handle of the other instance's main window so you can tell it to come to the foreground in place of your other instance. That's where a memory-mapped file can come in handy; it can hold information about the first instance so later instances can refer to it.
Be careful when choosing the name of the mutex. Read the documentation carefully, and keep in mind that some characters (such as backslash) are not allowed in some OS versions, but are required for certain features in other OS versions.
Also remember the problem of other users. If your program could be run via remote desktop or fast user switching, then there could be other users already running your program, and you might not really want to restrict the current user from running your program. In that case, don't use a global name. If you do want to restrict access for all users, then make sure the mutex object's security attributes are such that everyone will be able to open a handle to it. Using a null pointer for the lpSecurityAttributes parameter is not sufficient for that; the "default security descriptor" that MSDN mentions gives full access to the current user and no access to others.
You're allowed to edit the DPR file of your program. That's usually a good place to do this kind of thing. If you wait until the OnCreate event of one of your forms, then your program already has a bit of momentum toward running normally, so it's clumsy to try to terminate the program at that point. Better to terminate before too much UI work has been done. For example:
var
mutex: THandle;
mutexName: string;
begin
mutexName := ConstructMutexName();
mutex := CreateMutex(nil, False, PChar(mutexName));
if mutex = 0 then
RaiseLastOSError; // Couldn't open handle at all.
if GetLastError = Error_Already_Exists then begin
// We are not the first instance.
SendDataToPreviousInstance(...);
exit;
end;
// We are the first instance.
// Do NOT close the mutex handle here. It must
// remain open for the duration of your program,
// or else later instances won't be able to
// detect this instance.
Application.Initialize;
Application.CreateForm(...);
Application.Run;
end.
There's a question of when to close the mutex handle. You don't have to close it. When your process finally terminates (even if it crashes), the OS will automatically close any outstanding handles, and when there are no more handles open, the mutex object will be destroyed (thus allowing another instance of your program to start and consider itself to be the first instance).
But you might want to close the handle anyway. Suppose you chose to implement the SendDataToPreviousInstance function I mentioned in the code. If you want to get fancy, then you could account for the case that the previous instance is already shutting down and is unable to accept new data. Then you won't really want to close the second instance. The first instance could close the mutex handle as soon as it knows it's shutting down, in effect becoming a "lame duck" instance. The second instance will try to create the mutex handle, succeed, and consider itself the real first instance. The previous instance will close uninterrupted. Use CloseHandle to close the mutex; call it from your main form's OnClose event handler, or wherever else you call Application.Terminate, for example.
You can create a Semaphore and stop execution (put the code into your *.dpr file) and bring you running application to the screen.
var
Semafor: THandle;
begin
{ Don't start twice ... if already running bring this instance to front }
Semafor := CreateSemaphore(nil, 0, 1, 'MY_APPLICATION_IS_RUNNING');
if ((Semafor <> 0) and { application is already running }
(GetLastError = ERROR_ALREADY_EXISTS)) then
begin
RestoreWindow('TMyApplication');
CloseHandle(Semafor);
Halt;
end;
Application.CreateForm(....);
Application.Initialize;
Application.Run;
CloseHandle(Semafor);
end;
EDIT (added the RestoreWindow method):
The aFormName is the name of your main form class in your application.
procedure RestoreWindow(aFormName: string);
var
Wnd,
App: HWND;
begin
Wnd := FindWindow(PChar(aFormName), nil);
if (Wnd <> 0) then
begin { Set Window to foreground }
App := GetWindowLong(Wnd, GWL_HWNDPARENT);
if IsIconic(App) then
ShowWindow(App, SW_RESTORE);
SetForegroundwindow(App);
end;
end;
The all-mighty JVCL has a component for this purpose. See "TJvAppInstances".
The normal solution is to create a named, system-wide mutex.
If you manage to create it, you're the one running application.
If you don't, you know there's a different one.
EDIT:
I haven't provided code as I don't know Delphi. I can provide C# code if that would be helpful though.
You create a system mutex.
I don't have Delphi code, but here's C++ code:
HANDLE Mutex;
const char MutexName[] = "MyUniqueProgramName";
Mutex = OpenMutex(MUTEX_ALL_ACCESS, false, MutexName);
if (Mutex)
throw Exception("Program is already running.");
else
Mutex = CreateMutex(NULL, true, MutexName);
I'd like to add one point to the excellent answer by Rob Kennedy (apart from the fact that it would be best to make a function out of his code instead of copying everything into the DPR file. You only need two parameters, the name of the mutex, and a boolean whether the mutext should be per-user or system-wide).
The answer does not give much consideration to the naming of the mutex. If you expect your program to be installed via Inno Setup (and maybe other setup tools too) you should choose the name carefully, as the mutex can be used to have the setup program check whether the application is currently running, and alert the user that they should close all instances of the application. If you choose to allow one instance of the program per user you may need to create a second system-wide mutex too, as the setup may need to have no running instances of the application at all in order to be able to replace files. The name that is to be used for synchronization with an InnoSetup installer must be hard-coded.
I would say that there are several different strategies that you can employ. But the easiest one (and not platform specific) is the one you yourself suggested, namely to, at the start of the program check to see if there is a lock file created in a set, specific location. If this lock file exists, then another instance is already running, if it doesn't exist, then there is not another instance running. When your program exits, you delete the lock file.
However, employing this strategy you have another problem, what happens if your program crashes? The lock file still remains, and this specific case need to be handled.
Another strategy is the system-wide mutex solution, where you register your presence within the operating system (or it's also plausible that this is done automagically). When a second instance then tries to start, it checks if there's already a process active with a specific ID. If it already exists, the second process chooses not to start, and optionally brings the first process' window in focus (if the process in question owns a window that is).
However, this strategy is platform specific, and the implementation will differ from platform to platform.
You can simply use FindWindow windows api function. In delphi class name of the window is the same as class name, you can redefine class name by overriding CreateParams function. To check if window exists add code before main window is created , before Application.Initialize;
Program test
var
handle :HWND;
begin
handle := FindWindow('TMySuperApp', nil);
if IsWindow(handle) then
begin
//app is running
exit;
end.
Application.Initialize;
Application.CreateForm(TMySuperApp, SuperApp);
Application.Run;
end;
Controlling the number of application instances:
http://delphi.about.com/od/windowsshellapi/l/aa100703a.htm
If You want to stop execution your app more then once in the same time (put the code into *.dpr file of the project).
will show a message after second app will be running and stop it instantly .
Forms,
Unit1 in 'Unit1.pas' {Form1},
// add this units ....
TlHelp32,SysUtils,Windows,Dialogs;
{$R *.res}
function ProcessCount(const ExeName: String): Integer;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
FSnapshotHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize:= SizeOf(FProcessEntry32);
ContinueLoop:= Process32First(FSnapshotHandle, FProcessEntry32);
Result:= 0;
while Integer(ContinueLoop) <> 0 do begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeName)) or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeName))) then Inc(Result);
ContinueLoop:= Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;
begin
if ProcessCount(ExtractFileName(Application.ExeName)) > 1 then begin
MessageDlg('Application is already running!', mtError, [mbOK], 0);
Application.Terminate;
end else begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
end.
See this unit (using CreateMutex): UiApp
Additionally at this page, you can read the advantages and disadvantages for to this work with differents methods (mutex, FindWindows,...).
This unit have the solution to activate the previos instance of the application when this is detected.
Regards and excuse-me for my bad english.
Neftalí -Germán Estévez-
In the past, I've used a socket to prevent multiple instances from running at the same time. If the socket is in use, don't continue the program, if it's available let everything run as normal.

Resources