0

See steps below how to reproduce. I use Delphi 10.1 Berlin and Windows 10 and compile to win32.

  1. Create a new VCL Forms Application
  2. Place a TTimer and a TMemo on the form
  3. Set the timer's Interval to 10 ms
  4. Put this code in the OnTimer event:
if FileExists('named.txt') then
begin
  Memo1.Lines.Add('named.txt exists');
  DeleteFile('renamed.txt');  //delete if it exists
  if RenameFile('named.txt', 'renamed.txt') then
    Memo1.Lines.Add(' renamed OK')
  else
    Memo1.Lines.Add(' rename failed with error : '+ IntToStr(GetLastError));
end;
  1. Run the program

  2. Create a file named.txt

TMemo output shows:

named.txt exists
 renamed OK
  1. Now rename the file renamed.txt back to named.txt in the explorer.

TMemo output now shows:

named.txt exists
 renamed OK
named.txt exists
 renamed OK

But there will come an error message showing "File or folder does not exists". Why?

(Renamefile returns OK).

Setting the timer's Interval to e.g 500 ms seems to be ok (no error message).

Here is the message (in Swedish):

image

I even copied the exe-file to another PC with the same result:

enter image description here

Thomas
  • 375
  • 1
  • 2
  • 11
  • Try it out with another set of file names - but *only* in this little test program - and see if you can reproduce the problem. If you're in a race condition with another process, then the use of other file names will eliminate the interaction from that other process, and you can see if the problem is reproducible... You may already have different files names in your test (from the names used it could appear so). Have you tried it with this *exact* code on your end? – HeartWare Aug 13 '19 at 05:33
  • @RemyLebeau I would advice against using of `FILE_FLAG_DELETE_ON_CLOSE` flag when opening existing files that contain data to be processed. Why? Using such flags means that the file will be deleted as soon as all handles to it are closed. So if for some reason your application crashes and fhus fials to process teh data corectly as soon as it wil be closed the open file handle to the file Will be closed and file deleted and thus all the data with it. The application should be closing such file only when it was processed corectly and not before ... – SilverWarior Aug 13 '19 at 06:14
  • ... Using of `FILE_FLAG_DELETE_ON_CLOSE` is much more common when dealing with temporary files that are being created by your application as it makes sure that they get deleted even if your application has crashed and thus even an unstable application would not be slowly comsuming entire drive space by creating and never deleting a bunch of temporary files. – SilverWarior Aug 13 '19 at 06:17
  • @HeartWare: Thanks for all comments and help. I changed the names but get the same error. I even copied the exe-file to another PC (to c:\test) and get the same error: "The file or folder does not exist". – Thomas Aug 13 '19 at 10:06
  • @Thomas what about virusscanner locking the file (when both PC have the same...) – R. Hoek Aug 13 '19 at 14:43
  • @ R. Hoek : I tried it but still get the error, thanks – Thomas Aug 14 '19 at 12:55

2 Answers2

1

I was experiencing the same problem,

first: it doesnt seem to have something to do with your code.

From what i figured out the error is an Windows error and occurs, when you try to rename a file again before the first rename process(form Windows) has properly finished, so the delphi rename process may have finished and your code continues(and starts another rename) but the windows rename isnt properly finished yet.

The same problem happens, when you use diffrent programming languages for example with an batch file:

:loop
    ren named.txt renamed.txt
goto loop

you get the same error message.

To fix your problem the only thing i can think of, is to increse the timer delay like you suggested in your post.

I hope, this was any help and I am very sory i coulndt solve your problem

  • Thanks, good to know that at least one person could reproduce the error. My layman guess is that it is more likely to occur on "fast" systems. My tests are on a "high-end" cpu I7-6900K with ssd-disk. And it is not always the error occurs. Anyway, it still puzzles me that Renamefile returns OK but Windows reports an error. Thanks again for your comment. – Thomas Aug 27 '19 at 13:00
0

My guess is that one of the lines in the timer event ends up calling Application.ProcessMessages (possibly the adding to the Memo.Lines property). If more than 10ms has occured from the time the timer started executing the event, there will be a new timer event waiting in the message queue, which will trigger a call to the event once again.

In essense, you are then executing statements along these lines:

  if FileExists('named.txt') then
  begin
    memo1.Lines.Add('named.txt exists');
    // Embedded ProcessMessages at some point leads to
    // the timer event being called again
    if FileExists('named.txt') then
    begin
      DeleteFile('renamed.txt');  //delete if it exists
      if RenameFile('named.txt', 'renamed.txt') then
        memo1.Lines.Add(' renamed OK')
      else
        memo1.Lines.Add(' rename failed with error : '+IntToStr(GetLastError));
    end;
    // Nested Timer Event could end here,
    // which returns execution to the outer event
    DeleteFile('renamed.txt');  //delete if it exists
    // The named.text file does not exist anymore - renamed away 7 lines above
    if RenameFile('named.txt', 'renamed.txt') then
      memo1.Lines.Add(' renamed OK')
    else
      memo1.Lines.Add(' rename failed with error : '+ IntToStr(GetLastError));
  end;
  // Original Timer event ends here...

One solution would be this:

Timer.Enabled := False;
try
  if FileExists('named.txt') then
  begin
    memo1.Lines.Add('named.txt exists');
    DeleteFile('renamed.txt');  //delete if it exists
    if RenameFile('named.txt', 'renamed.txt') then
      memo1.Lines.Add(' renamed OK')
    else
      memo1.Lines.Add(' rename failed with error : '+ IntToStr(GetLastError));
  end;
finally
  Timer.Enabled := True
end;

to make sure that no new timer events can occur while you are processing one.

HeartWare
  • 7,464
  • 2
  • 26
  • 30
  • `Memo1.Lines.Add` doesn't pump the message queue – David Heffernan Aug 12 '19 at 11:03
  • Something probably does - maybe something that the OP hasn't shown. Otherwise, what he describes seems to be impossible... If he tries out the suggested solution and it solves the issue, then most definitely something does. – HeartWare Aug 12 '19 at 11:06
  • @Thomas: Then something strange is going on, most likely externally from the supplied code. What you describe should be impossible with only the code shown. This is also backed by Tom not being able to reproduce the issue... – HeartWare Aug 12 '19 at 12:34
  • @HeartWare: Can't you reproduce it even if you rename "renamed.txt" to "named.txt" in the explorer window while the program is running? I get this error all the time: https://i.stack.imgur.com/ZR76G.png – Thomas Aug 12 '19 at 13:45
  • @HeartWare: I agree with your anti-reentrancy measure, but think there's a bit more to it - see my comment on the q. – MartynA Aug 12 '19 at 14:07
  • @Thomas I could not reproduce your problem even when I set up the timer interval to 1 ms and tried renaming the `renamed.txt` to `named.txt` using another application. I used another application to be able to do this renaming very quickly. Any way in my comment on the question itself I have wrote a possible cause for the errors you are getting. – SilverWarior Aug 12 '19 at 20:00