0

I need some help and/or advice please.

I'm opening a file from code in either the default associated windows program or with a selected windows program using either ShellExecute or CreateProcess. I then wait for the process to complete. But this does not really work for me because:

Let's say the default associated program for text files (*.txt) is Notepad ++ (NPP). For the process to complete, NPP must not be open to start with and must be closed to complete the process.

But if NPP is already open, the file will be opened in the already opened NPP. But I do not necessarily want to close NPP to complete the process, I just want to close the opened text file and need to detect that the file has been closed and not NPP.

So I realised that waiting for the process to complete is not going to work. I've tried several things like trying to detect if the if the file is opened in another process but have not had any success.

So my question is, what would be the best method to detect when a file is open or in use and vice versa?

bluscape
  • 317
  • 3
  • 10
  • Although I already wrote an answer, this sounds like an [XY Problem](https://meta.stackexchange.com/a/66378/166177). What are you really trying to do? – selbie Sep 21 '19 at 10:12

1 Answers1

2

It sounds like you want to know when the file handle is "closed", not necessiarly when the program that operated on that file has exited.

Your question is closely related to this question. You could reference that to periodically poll the process handle to see what files are open. There will be timing issues - it might take a few seconds for the process to open the file in the first place.

There are also tools such as Handle.exe that may be useful.

However - none of these solutions are perfect. Some apps, including Notepad.exe, just open the file, read the contents, and immediately close the handle. When the user clicks "save", the file is re-opened for writing, contents saved back to disk, then the file handle is closed again.

A simpler approach would be to periodically poll the last-modified timestamp on the file via GetFileTime. When it changes, you could assume the file has been "Saved". Or apply this technique with some combination of the above and/or waiting for the application that was launched to exit.

selbie
  • 100,020
  • 15
  • 103
  • 173
  • There is no Y variable... I need to know when the file is not open so that I can operate on it. As simple as that. I've tried Handle.exe, ProcessExplorer, OpenedFilesView, etc. I also implemented ```NtQuerySystemInformation```. but none of them can detect the file I've opened with ShellExecute. Unless if I'm doing something wrong. Just create a normal text file "test.txt" and open it in Notepad and check if you can determine if it is opened? – bluscape Sep 21 '19 at 17:24
  • Here's the thing - ShellExecute does not "open a file". Not directly at least. ShellExecute launches an application and passes the path to that application as a command line param. Typically, the launched application will quickly open the file, read in the file's contents, and then close the handle. I believe Office applications tend to hold handles and locks while the file is "open", but that might be the exception. Most applications probably don't hold file handles to the documents they show to the user after the document is loaded and shown on the screen. Make sense? – selbie Sep 21 '19 at 17:53
  • I understand you might be hesitant to tell me what "Y" is. But the scenario I suspect you are trying to implement is tricky - synchronizing file changes is a **hard** problem. – selbie Sep 21 '19 at 17:58
  • I'm not hesitant. It is as I'm saying it. I'm opening a file for viewing or editing with ShellExecute or CreateProcess. It could be any type of file. I know what ShellExecute and/or CreateProcess does. Timestamps will not work. But if the file is opened, read and closed (the handle closed) then I do not know what I'm going to do. It also explains why I'm not able to detect the file in the process list. – bluscape Sep 21 '19 at 18:15
  • @bluscape "*I need to know when the file is not open so that I can operate on it*" - open the file yourself for exclusive access. If the file is already open, your open will fail with a sharing violation. If the file is not already open, and your open succeeds, use the file as needed. – Remy Lebeau Sep 21 '19 at 18:17
  • I'm starting to thing I should maybe implement a virtual drive or file system filter or something.... Not sure yet how that is going to help or work. But there might be something in it – bluscape Sep 21 '19 at 18:17
  • @RemyLebeau Sorry, my description might have been a bit confusing. I need to launch the file for the user and allow the user to view or edit the file. But I need to put the file back from where it originally came from. But I can only do that once the file is not being viewed or edited anymore. As in when it is closed by the user. It could be any type of file opened by any program. – bluscape Sep 21 '19 at 18:20
  • @bluescape - *But I need to put the file back from where it originally came from*. That's the Y variable. It sounds like you are trying to sync changes on the file and want to reliably detect when the first "save" has happened or when the file is not in use anymore. – selbie Sep 21 '19 at 18:23
  • If that's the case why not just wait for either the original application to close or first timestamp change to assume the user is done editing the file. Possibly even continually monitor the file for subsequent changes. – selbie Sep 21 '19 at 18:25
  • @selbie Waiting for the the viewer or editor to close is not reliable, so is timestamps. If a file is not modified the timestamp is not modified. You know what they say about assumptions – bluscape Sep 21 '19 at 18:32
  • @bluscape - please relax. I'm just trying to help. I also happen to work on a software application that specializes in monitoring file changes and reacting to those changes. And the scenario you describe resonates with a similar feature we considered building and prototyped. That's why I was hoping you would elaborate more on your actual scenario - because the degree of reliability you need might vary depending on what you are trying to provide to the user. – selbie Sep 21 '19 at 18:37
  • @selbie I'm relaxed and thanks for your interest anyways. I think the original question covers what I'm trying to do. I do not have a problem sharing the actual application. I have a file system for a custom storage device. The file system is not recognized by windows but the files on the storage and file system are normal windows files. As an interim solution I've written a file explorer to modify the file system and files inside windows. I'm also busy with an FSD drive but for the short term I'm using the File Explorer – bluscape Sep 21 '19 at 18:41
  • So to allow editing or viewing the files in windows, I first make a copy of the file in a windows folder and then launch it from there for viewing and/or editing. But I need to write the file back to the file system when it is not in use anymore. But I also need to delete it. I also had this scenario in mind. If a file is not modified then do not update it. If it is modified, then update it. But question is when do one make that decision – bluscape Sep 21 '19 at 18:45
  • Maybe I should take this approach. Put all the file in a temp folder. Constantly monitor the timestamp. Like you said. If the timestamp changes, update the file to my storage device. When the explorer is closed (or opened), delete all the temp files. – bluscape Sep 21 '19 at 18:53
  • @bluscape - yes exactly. It sounds like long term you want to have the device mount as a drive and file system. But in the short term, you need to build an app that can synchronize between device and local tmp file. Your final statement above about constantly monitoring (syncing) while your explorer is open is spot-on as a short term solution. – selbie Sep 21 '19 at 19:04
  • Also, have a look at [this](https://learn.microsoft.com/en-us/windows/win32/cfapi/build-a-cloud-file-sync-engine). It could fit your scenario as a balanced solution between a FSD and a full time polling loop. – selbie Sep 21 '19 at 19:08
  • Since it is very difficult to detect when the user is done viewing/editing the file in any possible app, I would suggest simply having the user tell your app when they are done working with the file, then you can sync and cleanup as needed – Remy Lebeau Sep 21 '19 at 21:46
  • Although the above solution will work, I do not think it is the most elegant. I do not like making decisions for the user. I want it to be seamless and give the user full control. If I delete a file without the user knowing there could still exist a scenario where the user expect the file to be available. It would have been great if I could implement the original question but that is not going to happen. Will have to complete the FSD sooner – bluscape Sep 22 '19 at 06:36
  • one more [link for you](https://learn.microsoft.com/en-us/windows/win32/fileio/obtaining-directory-change-notifications). So you don't have to poll... – selbie Sep 22 '19 at 07:27
  • @selbie Not fishing for compliments, but thought I should show you. I'm happy with the result. https://github.com/bluscape/LittleFS-Explorer-for-Windows – bluscape Oct 01 '19 at 19:06
  • cool - another idea. Have you looked at [Dokan](https://en.wikipedia.org/wiki/Dokan_Library) as a file system driver? – selbie Oct 01 '19 at 23:48