How to detect programmatically what program caught my file - c#

My program tries to write some data to a text file. But sometimes this file can be opened by some other program exclusively.
How to detect programmatically what program caught my file? I have to know user-friendly program name (here is my second question :)) that did it.

You detect it by the IOException you get when you try to open the file. This is a necessary evil on a multi-tasking operating system, there is no reliable way to implement a File.IsLocked() method. Windows doesn't have an API function for it. Because if such a function returns false, another process could interrupt your program and lock the file. When you get the cpu back, you'll find that the file is locked anyway. That's called a threading race.
So open the file with, say, the FileStream constructor. Pass FileShare.ReadWrite if you want to read from a file that's being written by another process. You have to allow ReadWrite sharing, the other process already gained the write access right. Catch the IOException you may get, you'll have to try again 'later'. Tell the user about it, she'll probably know what to do to help you. Like closing another program.
Btw, Windows does not provide any way to find out what other process has the file locked. There are utilities for that, like SysInterals' Handle utility. It grovels through undocumented internal kernel structures with a device driver that's dynamically installed. Nothing you'd want to tackle yourself.

Related

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.

Is it possible to edit a file outside of my running application without closing the attached FileStream first?

I have a Windows Service that's always running as a part of my application. The service uses a TextWriterTraceListener to write to a log file so it's easier for me to debug later if needed.
The TraceListener uses a FileStream object. I thought by using FileShare.ReadWrite in the construction of the FileStream, I would be able to edit this file in Windows Explorer as needed (edit the file and save it/rename the file/move the file), but this does not seem to be the case. The MSDN article on FileShare states: "even if this flag is specified, additional permissions might still be needed to access the file," but is not very clear as to what those permissions might be.
As of now whenever I try to edit that file I keep running into the following error: "The process cannot access the file because it is being used by another process."
Two thoughts:
Regarding FileShare statement that additional permissions might still be needed - that's likely in reference tha while your program says it can handle someone reading or wrting to the file while it has it open, others may still need necessary access permissions (as in ACL) to access files.
The second thought is the reason you're experiencing this is probably because the other program with which you're trying to open the file is trying to open it in exclusive mode (i.e. NOT FileShare.ReadWrite. So that program demands exclusive access and does not receive it because you have it open (even if willing to share).
Test with a program (or write quick one yourself where you know you're setting flag to share) that can open in shared mode to see if it works.
To rename or remove the file, it must be opened with FileShare.Delete. If it is deleted or renamed while you have it open, you may find that subsequent operations on the file will fail with the error "File was removed or deleted".

There is a way to delete an file that is being executed without kill it?

I have a question that I believe that is complex. I have an application that I execute under my Windows and it takes a long time to finish. I want to keep it running (normally), however I want to kill the file on disk - but obviously it's not possible because it's locked / in-use. I need a way to disassociate it from the running process to kill it and at the same time keep the file running. Any example of code or tool is very welcome.
Well, workarounds are welcome, for example, if there is a way to spawn it from a process, key the master and migrate the child to kill the app, or any other idea that works is welcome - even the ugly ones. :)
Thanks.
A couple of suggestions (completely stolen) from this questions answers:
You could use the MoveFileEx api function to mark the file for deletion upon next reboot.
You can inject a dll to close the handle yourself:
The typical method is as follows. You've said you want to do this in C# so here goes...
If you don't know which process has the file locked, you'll need to examine each process's handle list, and query each handle to determine if it identifies the locked file. Doing this in C# will likely require P/Invoke or an intermediary C++/CLI to call the native APIs you'll need.
Once you've figured out which process(es) have the file locked, you'll need to safely inject a small native DLL into the process (you can also inject a managed DLL, but this is messier, as you then have to start or attach to the .NET runtime).
That bootstrap DLL then closes the handle using CloseHandle etc.
Essentially: the way to unlock a "locked" file is to inject a DLL into the offending process's address space and close it yourself. You can do this using native or managed code. No matter what, you're going to need a small amount of native code or at least P/Invoke into the same.
Helpful links:
http://www.codeproject.com/KB/threads/winspy.aspx
http://damianblog.com/2008/07/02/net-code-injection/
That is a matter the application you want to kill has to handle. It shouldn't keep files open during a long running process. If the application doesn't close the file, killing it will lead to exception in that application.
Not sure if this will work on every Windows version, but here it is:
Rename process executable "foo.exe" to "foo.old"
Put new "foo.exe" to correct place
Send message to process, so it will execute new "foo.exe" image and terminate himself.
On start, remove "foo.old" file in program directory.
Update: oops, looks like you do not want to put new image, just remove old one. Then MoveFileEx is only "legal" option.

Reading a file without preventing other processes from reading it at the same time

I'm making a little app in C#/.NET that watch for the creation of a file and when it is created it gets its content, parse it and write it in another file.
Everything is working fine so far. But the problem is : there's another process that watch for this file as well. My process is only READING the file while the second one reads it and then DELETES it.
My application is making its job but when it reads the file, the other process can't read it and totally crashes (Not made by me and don't have the sources to fix it).
My application is running very fast and other open the files for a very little time to get the content and put it in a variable so it could close the file faster and then parse the content of the file which is in the variable.
I clearly don't know how but I'd like to be able to read the file and let the other read the file at the same time without any hiccups. Is it possible? I still think that there will be a problem about the fact that the file is being deleted after the other app is done parsing it...
Any suggestions or ideas?
Thanks very much!
You can open the file as follows to ensure you don't lock it from other processes:
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// do your stuff
}
But if the other process is trying to open it in exclusive mode, it won't help and it will still crash. There's no way to deal with that other than fixing the code for the other process.
KISS: Can you have the file created in a location which the first program isn't looking at, but your software is - and when you are done processing it you then move it to the current location where the first program is looking?
Otherwise:
You are going to have contention since it's going to be a race to see which process actually "notices" the file first and begins working.
I'm assuming you also don't have any control over the process creating the file?
In that case you might look at PsSuspend or PauseSp - if you can control the other process by suspending it until you are ready for it (done with the file) then that might be viable. Not sure how robust this would be.
There's also still the potential race condition of "noticing" the file and performing an action (whatever it is) - keeping the other process paused perpetually until you want it to run (or killing it and starting it) is the only completely deterministic way to achieve what you want within the constraints.
If you are using an NTFS drive (which is very likely), then you can create a hard-link to the file. Essentially, this duplicates the file without actually creating a duplicate. You can read the file with the hard-link. The other process can delete the file, which will only remove their link to the file. This will leave the file in place for you to read. When your program is done reading the file, it can delete the hard-link, and the file system will see that both links have been deleted, and it will delete the file itself.
This can be done from the command line with
fsutil hardlink create <NewFileName> <ExistingFileName>
Or you can P/Invoke the CreateHardLink function in the Windows API.
Can you create another empty zero bytes file called .reading file which has the same name but extension "reading" to it. Then once first process is done reading the file, rename .reading to .done and the second process can check .done files and delete the original file,since both .done and original file have same name but different extensions ?.
#Prashant's response gave me the inspiration for this, and it's very similar, but I believe will solve your problem.
If the other process must match a certain filename pattern
Rename the file to something that
won't match first, a very cheap/fast
operation
Rename it back when finished
If it matches every file in a given folder
Move it to another folder (also a very cheap operation in most filesystems)
Move it back when finished.
If the other process had already locked your file (even for read) then your process would fail, and you can make that graceful. If not you should be safe.
There is still a race condition possibility, of course, but this should be much safer than what you are doing.

Cannot write to XML file in another computer from my program

When I write to an XML file, an exception occurs: "Cannot access file because it used by another process". How can I fix that problem?
You can use things like "Process Explorer" (easy to find) on the machine in question to double-check which process is locking a file. If you don't own the competing process, the best you can do is ask the operator to kindly close the file and/or app that is blocking you.
Assuming you do you manage the other process that is locking the file? The most common cause of unexpected locks is files not being closed cleanly. Check that you are religiously closing all file handles after use, ideally using using so that they are closed even in error conditions - for example:
using(Stream dest = File.Create(path)) {
// write to dest
}
Most likely this means another program has this file locked. Try saving in another location and make sure you're properly disposing objects used to write to the file when you're done writing. Also double-check you have proper permissions to write this folder (try creating a basic text file there)
Keep in mind that your program may be running with different permissions than what you are logged in with.
The XML file that you are trying to write to will be currently open by any other process [file opened] and will be in a locked state. You cannot modify a file that has been locked.
Close any file handles that are currently using the resource.

Categories