Juan C.Cilleruelo 12 Posted November 5, 2018 My application generates a data file with instructions to generate a graphic file and after call an external program that processes this information and generates the graphic file. Next, my program, that is waiting until the graphic file exists, takes this graphic file and incorporates it to his database. The problem is the the time that the external application take to processing the data file. This time can be very large. An sometimes, my program traying to get the resulting file meanwhile the external program is processing it. This becomes in an OS exception. Can I ask to the OS, if the file I want to take is been still processing by another application? The program is cross platform, because of this I can't call the external application waiting to his finallization. And of course, if the solution is for crossplatform, more better. Thank in advance. Share this post Link to post
Vince Bartlett 1 Posted November 5, 2018 Try opening the file with an exclusive lock? I'd imagine that would work under Windows at least. 1 Share this post Link to post
Lars Fosdal 1792 Posted November 5, 2018 I assume you are in control of the output location. f.x. %somepath%\generated\myimg.png What if you create a "signal" file that basically is the URL of your graphics output file with f.x. '.processing' at the end before you start generating the file? %somepath%\generated\myimg.png.processing Once the processing is complete, you delete the %somepath%\generated\myimg.png.processing That way, your other process could check if the file %somepath%\generated\myimg.png exists, but continue to wait if there is a %somepath%\generated\myimg.png.processing file there? Share this post Link to post
Markus Kinzler 174 Posted November 5, 2018 If the external program is written by himself then the task can be done with a "lockfile" or with ipc. If not the check for exclusive access in an interval is the next best solution. Share this post Link to post
dummzeuch 1505 Posted November 5, 2018 Building on Lars Fosdal's answer: Let your external program generate the file under a different name (or in a different location on the same drive) and when it is done, rename/move it to where your program expects it. 1 Share this post Link to post
Markus Kinzler 174 Posted November 5, 2018 Just now, dummzeuch said: Building on Lars Fosdal's answer: Let your external program generate the file under a different name (or in a different location on the same drive) and when it is done, rename/move it to where your program expects it. That solves not the problem. The graphic file is generated by the external program. The file exists with start of the process. If the finishing cannot be signaled by the external program the name doesn't matter. Share this post Link to post
Zacherl 3 Posted November 5, 2018 Just trying to open the file is already the correct solution IMHO. You should catch the exception and retry until it works. 1 Share this post Link to post
Lars Fosdal 1792 Posted November 5, 2018 2 hours ago, Markus Kinzler said: That solves not the problem. The graphic file is generated by the external program. The file exists with start of the process. If the finishing cannot be signaled by the external program the name doesn't matter. You are right, unless he is in control of the external program as well. Share this post Link to post
Juan C.Cilleruelo 12 Posted November 5, 2018 (edited) The external program is OpenSCAD. I can't control how it works. The generated file exists during all the process. I can't control this. Edited November 5, 2018 by Juan C.Cilleruelo Share this post Link to post
Zacherl 3 Posted November 5, 2018 I remember a that that discussed a similar topic .. it was something like "How to detect, if I can append data to a file". The solution was: Try it and catch errors. There are just too many variables that you would have to check (file exists, access privileges, exclusive access, ...). If you need cross-platform, I can just quote myself: 3 hours ago, Zacherl said: Just trying to open the file is already the correct solution IMHO. You should catch the exception and retry until it works. There are other approaches, if cross-platform support is not needed, but none of them are easy (on Windows you could enumerate all open handles to the file e.g. or work with global `CloseHandle` hooks). 1 Share this post Link to post
Juan C.Cilleruelo 12 Posted November 5, 2018 3 hours ago, Zacherl said: Just trying to open the file is already the correct solution IMHO. You should catch the exception and retry until it works. This is my current code. I think now is working well. Any idea! Thanks to all. ...... CountErrors := 0; while not (TFile.Exists(PNG_FileName) or (CountErrors > 5)) do begin Inc(CountErrors); Sleep(1000); end; Sleep(1000); CountErrors := 0; SuccessLoad := False; while (not SuccessLoad) or (CountErrors > 10) do begin try BlobField.LoadFromFile(PNG_FileName); SuccessLoad := True; except on EFOpenError do begin SuccessLoad := False; Inc(CountErrors); Sleep(1000); end; end; end; ..... 1 Share this post Link to post
Zacherl 3 Posted November 5, 2018 Just now, Juan C.Cilleruelo said: This is my current code. I think now is working well. Should work 👍 Was just about to recommend adding an additional timeout to the code, but you already did with your error counter 🙂 Share this post Link to post
Juan C.Cilleruelo 12 Posted November 5, 2018 Just now, Zacherl said: Should work 👍 Was just about to recommend adding an additional timeout to the code, but you already did with your error counter 🙂 Each error waits one second. I think is absurd repeat without allow the other process finish. 1 Share this post Link to post
Attila Kovacs 629 Posted November 5, 2018 (edited) CreateProcess / WaitForSingleObject Ahm, crossplatform! In this case, not! 😉 Btw, what is the cross-platform OpenSCAD calling convention? Is there any? ifdef? Maybe you could place the wait code for the process into those sections? Edited November 5, 2018 by Attila Kovacs Share this post Link to post
KodeZwerg 54 Posted November 6, 2018 (edited) *removed* Edited November 6, 2018 by KodeZwerg Share this post Link to post
Lars Fosdal 1792 Posted November 6, 2018 @Juan C.Cilleruelo - Do you invoke a new instance of OpenSCAD for each image? If you do, can't you execute it from a thread that waits for it to complete and return? Share this post Link to post
Juan C.Cilleruelo 12 Posted November 6, 2018 6 minutes ago, Lars Fosdal said: @Juan C.Cilleruelo - Do you invoke a new instance of OpenSCAD for each image? If you do, can't you execute it from a thread that waits for it to complete and return? This was my first option, effectively, but, how to do this in Mac OS X? Share this post Link to post
Lars Fosdal 1792 Posted November 6, 2018 I have no experience with the MacOS shell, but a bit of googling dug up this? Not sure if appropriate.https://stackoverflow.com/questions/43020737/delphi-capture-osx-console-output Share this post Link to post
Emrah 1 Posted July 12, 2019 function IsFileInUse(FileName: TFileName): Boolean;var HFileRes: HFILE;begin Result := False; if not FileExists(FileName) then Exit; 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;procedure TForm1.Button1Click(Sender: TObject);begin if IsFileInUse('c:\Programs\delphi6\bin\delphi32.exe') then ShowMessage('File is in use.'); else ShowMessage('File not in use.');end; 1 Share this post Link to post
Remy Lebeau 1393 Posted July 16, 2019 (edited) On 7/12/2019 at 6:06 AM, Emrah said: if not FileExists(FileName) then Exit; 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); The FileExists() check is unnecessary and should be removed. It introduces a race condition (the file may exist before FileExists() is called, and then gets deleted before CreateFile() is called) as well as a possible failure point (FileExists() is not 100% accurate in all possible situations, there are cases where it returns a wrong result). Calling CreateFile() by itself with OPEN_EXISTING is good enough. If the file really does not exist, CreateFile() will fail with an ERROR_FILE_NOT_FOUND error code. Also, your code does not take ERROR_SHARING_VIOLATION into account, which would mean the file is actually in use but you don't have access to open it. Try this instead: function IsFileInUse(FileName: TFileName): Boolean; var HFileRes: THandle; begin HFileRes := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (HFileRes <> INVALID_HANDLE_VALUE) then begin CloseHandle(HFileRes); Result := False; end else Result := (GetLastError() = ERROR_SHARING_VIOLATION); end; Edited July 16, 2019 by Remy Lebeau 1 Share this post Link to post
Tom F 83 Posted August 20, 2019 Not cross platform, but this might interest you: JCLSYSUTILS.Execute(). Share this post Link to post