How to find out which windows process is using a file? - c#

I've seen several answers about using Handle or Process Monitor, but I would like to be able to find out in my code (C#) which process is locking a file.
Ex. I open two files like test.xlsx and test_1.xlsx and I want to close the only process of text.xlsx, but right whatever I find that close only my last open excel file or both files.
This only example, I have so many files of different types and I need to close from them only several.
I try to "Handle" but it needs administrative rights, and restart manager also not provide exact process id which I use from different examples.

Related

Delete an "in use" file after no processes reference it

Searched a lot, but without luck - so here goes
My C# winforms application creates temp files which are opened using the default registered application (let's call them viewer apps). Once the user is done viewing those files, I want to delete them.
Currently, I register for an Application.ApplicationExit event, to delete the file. This approach covers most of the situations but not all. Sometimes the user still has the viewing application open while exiting my app, so the success of my File.Delete depends on whether the viewer has opened the file with FileShare.Delete or not - which is out of my control.
This is what I have found so far, but fall short of what I want
FileOptions.DeleteOnClose does not help, since my app will already be closed in some cases and the temp file will still be needed. Also, when I create the file like this: new FileStream(fn, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete, 4096, FileOptions.DeleteOnClose), the viewer apps like say adobe reader & notepad, still complain about file in use by my application The process cannot access the file because it is being used by another process
MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT dwFlags works, but it would wait till a reboot to delete it - I would rather have it deleted once the use is done, since reboots can be few and far between and forcing reboots IMO is not the most user friendly approach. On a side note, does windows automatically clear the %temp% folder on restart? Or is there any temp folder that windows automatically clears on restart?
I can write another background process which constantly tries to delete the temp files till it succeeds, but I would like to avoid deploying one more piece of software to accomplish this. It can be done using a windows service or scheduled task or adding command line switches to my existing app and making it run in "delete mode" in background or through task scheduler. All of it decrease my ease of deployment and use along with increasing my footprint on client's computer
In a nutshell, I am wondering if there is any Win32 API or .NET Framework API that will delete a file as soon as there are no processes with open handle to that file?
EDIT:
The information in the temp files are reasonably private (think your downloaded bank account statements) and hence the need for immediate deletion after viewing as opposed to waiting for a reboot or app restart
Summary of all Answers and Comments
After doing some more experiments with inputs from Scott Chamberlain's answer, and other comments on this question, the best path seems to be to force the end users to close the viewer app before closing my application, if the viewer app disallows deletion (FileShare.Delete) of the temp file. The below factors played a role in the decision
The best option is FileOptions.DeleteOnClose, but this only works if all files open before or after this call use FileShare.Delete option to open the file.
Viewer apps can frequently open files without FileShare.Delete option.
Some viewers close the handle immediately after reading/displaying the file contents (like notepad), whereas some other apps (like Adobe Reader) retain such handle till the file is closed in the viewer
Keeping sensitive files on disk for any longer than required is definitely not a good way to proceed. So waiting till reboot should only be used as a fail-safe and not as the main strategy.
The costs of maintaining another process to do the temp file cleanup, far exceeds the slight user inconvenience when they are forced to "close" the viewer before proceeding further.
This answer is based on my comments in the question.
Try write the file without the delete, close the file, let the editor open the file, then open a new filestream as a read with DeleteOnClose with an empty body in the using section.
If that 2nd opening does not fail it will behave exactly like you wanted, it will delete the file as soon as there are no processes with open handle to that file. If the 2nd opening for the delete does fail you can use MoveFileEx as a fallback failsafe.

How to programmatically determine which process created a file in .net?

There are several threads on SO that describe how to check which application creates a file with tools like Sysinternals process monitor. Is something like this possible programmatically from .net?
Background: My program has to remote-control a proprietary third party application using its automation interface, and one of the functions I need from this application has a bug where it creates a bunch of temporary files in %TEMP% that are called tmpXXXX.tmp (the same as .net's Path.GetTempFileName() does) but does not delete them. This causes the C drive to become full over time, eventually failing the application. I already filed a bug to the manufacturer, but we need a temporary workaround for the time being, so I thought of putting a FileSystemWatcher on %TEMP% that watches tmp*.tmp, collects these files, and after the operation on the third-party application finishes, deletes them. But this is risky as another application might also write files with the same file name pattern to %TEMP% so I only want to delete those created by NastyBuggyThirdPartyApplication.exe.
Is this anyhow possible?
This kind of things is possible, but maybe a bit tricky.
To know who created the file, look at the user that owns it. Therefore you might need to create a specific user, and that application will run under this specific user. In order to do that, you need to create a small application that will start your buggy app by impersonating another user, so anything done within the app will be under this user so as file creating...
I don't know how to monitor and get triggered when a file is created, but nothing can prevent you from setting a timer that wakes up every five or ten minutes, then checks if any file in the directory is owned by the application user and closed, so it deletes it.
Maybe if they react fast for this bug fixing, you won't need your app very long time. So another solution, if possible might just to change the Temp folder into another drive, which has lots of space...
One solution is that you use a FileWatcher to automatically delete all the files but before deleting you should check if the file is not currently locked or used by other process, for example the Sysinternal Suite has a tool called handle.exe that can do this. Use it from the command line:
handle.exe -a
You can invoke this from a c# program (there might be some performance issues though)
So what you would do is when a file is created you verify if it is in use or locked (for example u can use the code provided in Is there a way to check if a file is in use?) and then delete it.
Most of the time when an app is using a temp file it will lock it to prevent just what you fear, that you might delete files from other processes.
As far as I can tell there is no sure way to identify which process created a specific file.

Get username of user who has file open on network drive - Microsoft Office Style

I would like to add user friendly file locking to a software running under Windows (Windows 7 mostly), written in C#.
I already achieved the file locking part, by keeping the files in use "open" in the corresponding process. What I now still would like to add is recognition of the user who has a file currently open/locked.
The files being accessed lie on a mapped network drive, used by different users on different computers.
When a file is locked and a second person tries to open the file, he should be confronted with a dialog, similar to the "File in use"-dialog from the Microsoft Office programs. There, also the name of the user, currently editing the file, is displayed.
I found solutions to find out the processes, which have a certain file open (used this one: How do I find out which process is locking a file using .NET?)
and I'm also able to read the name of the user who created this process out of it. However, when opening a locked file on a network drive, the username yielded by doing it like this, is always my own one, instead of the one from the user locking the file.
Does anyone have an idea how one could achieve this? I mean Microsoft Office somehow can do this on my same PC with the same user permissions, too. I just'd like to know how...
Cheers!
Office uses a very simple technique, I'll talk about it in .NET terms. Whenever an Office app opens a document file, using FileShare.None, it also creates a hidden "lock-file" with a name that's based on the document file (say, with ".lockfile" appended). And writes Environment.UserDomainName into that file. The file is created with FileOptions.DeleteOnClose and FileShare.Read and kept open as long as the document file is open.
It closes the lock-file when the document is closed again. Using FileOptions.DeleteOnClose ensures that the lock-file disappears even when the program bombs.
When opening the file produces a locking violation, it goes looking for the lock-file and reads the user name. Easy peasy, simple to implement yourself. But can of course only work if it is one particular app that opens the file.

C# - Locking folders from being edited

i'm making a small project. it's Windows Form Application. i got some sources in a folder (C:/sources). When my program runs, it uses sources from the folder. Currently i can edit the folder by windows explorer, it can cause errors for my program. So i want to lock the folder (C:/sources) from being edited/renamed/deleted when my program runs. How to do so?
EDIT;
Is it possible to show a message like this when user has tried to edit the folder:
"the action cannot be completed because the folder or a file in it is open in another program"
the program that we are talking about is mine..
There are a couple of approaches that you could venture and they vary in difficulty of implementation. It all depends on how important this task is for you. But, before discussing these options; can't you embed those resources in your WinForms application instead? If this is not an option then you can do one of the following:
Write a device driver that can prohibit the access of such resources if your application is running. There are fallbacks to this approach. For example one can impersonate your application by having the same name. But, am not getting in to too much details in trying to break any approach as I am trying to address possible solutions to the current problem. There are different types of drivers that you can consider. Probably the simplest form of this approach would be to implement a mini-filter driver.
Hook certain API's like CreateFile(), NtCreateFile(), ZwCreateFile() although there are many ways to circumvent such mechanism of defense. But, again we are only venturing what you can do to address this constraint of yours.
Open these resources directly from your application and lock it exclusively. For example:
File.Open("test.txt", FileMode.Open, FileAccess.Read, FileShare.None);
as this will result in people getting the message that you desire if they try to open the file.
Maybe you can give more information on what these resources are and we can help you determine which is the best way to protect your files in a reasonable fashion?
Although I don't believe it's the best idea to have files that are critical to the application in a open area like the C: drive, I would look into NTFS file permissions and set the folder to read only, but this wont stop administrative users
See these two posts
restrict access to folder outside of program c#
Setting NTFS permissions in C#.NET

Generate an .exe file with embedded settings

I have a window application which performs some tasks, One of which is opening some files and we all know .net provides exe file for the application, which can be used as click to start.
I am calling this application application1.
Now I want to generate one more window application(simple exe), let us call it application2, which will open a form with some options(say the names of the files to be opened by application1) and a generate button.
On clicking the generate button, it should generate the exe file for the application1 with the data passed from application2.
Please suggest how can I do it.
EDIT
I need to generate exe which will be available on different systems which will perform some task on regular intervals. and the interval colud be different for different computers.
so I am asked to generate which will accept the time interval and will generate the exe for that interval
There are a number of ways to consider doing this:
use a reg key with the name of the settings file to read in, and then store the settings you write from app2, for app1 in the file, so app 1 can run it
you call app1 with a parameter with either the name of a file, or commandline parameters, and it updates its own applications settings file.
put the settings in a database, so any copy of app1 anywhere can find it, assuming all users would be able to see the db server
if app1 is always to be running while app2 is you could go with some interprocess communication but probably this is the more complex of the 4
Rather than recompiling an exe, it would make sense to have a config file that goes with.
Failing that, compiling .net is only that, you can have an exe that generates a .cs file (or updates one, and reruns the whole compile and outputs an exe.. take a google, on command line compilation) but I wouldnt be my choice.
I think what your looking for is for application1 to be able to receive command line arguments and application2 to allow you to pick files and run application1 and pass in those arguments.
I don't think its wish to be generating .exe's
Another way, although not that easy, would be to
write application 1 to try and read settings from class that does not exist, say SettingsOverride, by reflection; if not found, fall back to its own hard-coded settings
application 2 uses CodeDOM or similar to create a new assembly that provides a SettingsOverride class with the new saved settings
application 2 uses ILMerge to build the new .exe from application 1 and the settings assembly; the reflection code in application 1 should now pick up the new settings.
It's probably also possible to do this with embedded resources, though I'm not sure how. Finally you could put a string constant in your .exe, say 400 X characters, and then application 2 could scan the file to find that (as Unicode/UTF-16 text) and replace that with a string containing the new settings - but I'm not 100% if you then need to recompute a checksum or similar.

Categories