emileverh 21 Posted October 25 Hi! I need to copy a file to the Windows-temp folder. But on some of my clients it fails. I can not reproduce it, but when they open a mail with attachment in Outlook and my app is working on the same filename it fails. The routine below fails. Please do not focus on Outlook, but in general. How can I 'force delete' a file? Or how can I safe save a file to the temp folder without problems? Any suggestions? Please help! -Emile function TdtmBoot.CopyFileToTempFolder(const AFullFileName: TFileName): string; begin var lFileName: string := ExtractFileName(AFullFileName); var lTempFolderFullFileName: string := GetTempFolder + lFileName; try if DeleteFile(lTempFolderFullFileName) = False then; // @17.22 begin SendMadBugReport(Self, 'CopyFileToTempFolder(), delete failed'); // <<<<<<<< HERE IT FAILS!!!!!!! end; except end; Result := lTempFolderFullFileName; try TFile.Copy(AFullFileName, lTempFolderFullFileName, true); // true = overwrite Result := lTempFolderFullFileName; except end; end; Share this post Link to post
Lajos Juhász 293 Posted October 25 You should check GetLastError to see the reason why it fails. https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-deletefile One of the possible reason is that the file doesn't exists and the other is that the file is in use by other application. Share this post Link to post
emileverh 21 Posted October 25 17 minutes ago, Lajos Juhász said: You should check GetLastError to see the reason why it fails. https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-deletefile One of the possible reason is that the file doesn't exists and the other is that the file is in use by other application. Thanks and agree! I had to check if the file exists. But the DeleteFile() call was recently added. In previous versions of my app it failed on the next statement TFIle.Copy(). So again; is there a way to force delete a file? Share this post Link to post
Rollo62 536 Posted October 25 https://docwiki.embarcadero.com/Libraries/Athens/en/System.SysUtils.DeleteFile Quote DeleteFile deletes the file named by FileName from the disk. If the file cannot be deleted or does not exist, the function returns False. Share this post Link to post
Lajos Juhász 293 Posted October 25 1 hour ago, emileverh said: So again; is there a way to force delete a file? No there is no way if the file is locked it is not going to be deleted. You should first try to add: If FileExists(lTempFolderFullFileName) then if not DeleteFile(lTempFolderFullFileName ) then SendMadBugReport(Self, 'CopyFileToTempFolder(), delete failed'); // <<<<<<<< HERE IT FAILS!!!!!!! Why do you have an empty try ... except block? That is very dangerous at least you should send a bug report with the exception. Ignoring an exception can lead to other bugs in a program. 1 Share this post Link to post
DelphiUdIT 176 Posted October 25 First of all you should know why the file is not deleted. AFter that there are other ways to delete a file, for example when is locked. BUt this go over my competence. Share this post Link to post
Remy Lebeau 1392 Posted October 25 (edited) You cannot delete a file that is in use, unless the app that is using the file explicitly permits the deletion (by specifying FILE_SHARE_DELETE when opening the file). Nobody does that under normal usage, so you will need to detect when this condition happens (check GetLastError() when the deletion fails) and then. either 1) retry the deletion later or 2) ask Windows to delete the file on the next reboot (via MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT)). Edited October 25 by Remy Lebeau Share this post Link to post
emileverh 21 Posted October 25 Just now, Remy Lebeau said: You cannot delete a file that is in use, unless the app that is using the file explicitly permits the deletion (by specifying FILE_SHARE_DELETE when opening the file). Nobody does that under normal usage, so you will need to detect when this condition happens (check GetLastError() when the deletion fails) and then. either 1) retry the deletion later or 2) ask Windows to delete the file on the next reboot (via MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT)). You are right force deleting a file is not a good idea. The other (unknown for me) process needs the file. Any idea if there is an API to add a kind of duplication number like: file (1).txt, file (2).txt, file (3).txt ? I did Google something but I did not find 1-2-3 an API for that. Anybody knows? Share this post Link to post
Remy Lebeau 1392 Posted October 25 (edited) 33 minutes ago, emileverh said: Any idea if there is an API to add a kind of duplication number like: file (1).txt, file (2).txt, file (3).txt ? Use the Win32 SHFileOperation() API to copy the file with the FOF_RENAMEONCOLLISION flag: Quote Give the file being operated on a new name in a move, copy, or rename operation if a file with the target name already exists at the destination. If you need to know what the copied filename was renamed to, include the FOF_WANTMAPPINGHANDLE flag as well: Quote If FOF_RENAMEONCOLLISION is specified and any files were renamed, assign a name mapping object that contains their old and new names to the hNameMappings member. This object must be freed using SHFreeNameMappings when it is no longer needed. Alternatively, on Windows Vista+, you can use the IFileOperation API instead, using IFileOperation.SetOperationFlags() to set the FOF_RENAMEONCOLLISION flag, IFileOperation.CopyItem() and IFileOperation.PerformOperations() to perform the copy, and if needed use an IFileOperationProgressSink event sink to discover the copied filename in the PostCopyItem event. Edited October 25 by Remy Lebeau 1 Share this post Link to post
emileverh 21 Posted October 25 39 minutes ago, Remy Lebeau said: Use the Win32 SHFileOperation() API to copy the file with the FOF_RENAMEONCOLLISION flag: If you need to know what the copied filename was renamed to, include the FOF_WANTMAPPINGHANDLE flag as well: Alternatively, on Windows Vista+, you can use the IFileOperation API instead, using IFileOperation.SetOperationFlags() to set the FOF_RENAMEONCOLLISION flag, IFileOperation.CopyItem() and IFileOperation.PerformOperations() to perform the copy, and if needed use an IFileOperationProgressSink event sink to discover the copied filename in the PostCopyItem event. Thanks Remy for your help!!! Share this post Link to post