Passing stream objects / file handles between two processes in .NET - c#

I have a windows service and a desktop application running on the same machine. The app pre-processes some documents and transfers them to a folder where the service can take over. When the app is creating the new file for the service, it keeps a read-only lock on the file while writing. It them releases it so that the service can acquire a new read-only lock (FileStream).
I'd like the app to somehow hand-over this lock to the service without closing it. Is this possible in the managed runtime? If not, is there a way to P/Invoke this behaviour?
The reason this behaviour is desired is so that no other processes can modify or delete the file until both the app and service are done with it.

This is not possible in a managed-only way.
Try to use a simpler approach, such as naming the file with a random name in a temp directory such that no other application will try to open it.
If you insist on passing the handle, you must duplicate the handle into the service process and pass the numeric handle value of that process to the service process. Use OpenProcess, DuplicateHandle and CloseProcess for that.
From http://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx:
The duplicate handle refers to the same object as the original handle.
Therefore, any changes to the object are reflected through both
handles. For example, if you duplicate a file handle, the current file
position is always the same for both handles. For file handles to have
different file positions, use the CreateFile function to create file
handles that share access to the same file.

Related

Does Ionic ZipFile lock/unlock files?

I am busy developing an additional module for an existing C# (4.0) application that uses Ionic Zip library to manage the data. In my module I need to load data from zip files, manipulate them, and write back again. My routine runs OK in Unit Tests, but when called from within the host application, it throws an exception reading "The process cannot access the file because it is being used by another process". This happens at a point when I try to call the Save() function of the Zip archive.
I checked which process actually locks the file, and it happens to be the application itself. Therefore I conclude that there might be some kind of interference with the host program: e.g. a file stream opened at some place and not closed. (BTW, are there some smart techniques to look after such places?)
What puzzles me is whether those ZipFile's of Ionic really lock / unlock files when dealing with files, as in the following code piece:
ZipFile zf = new ZipFile("test01.zip");
zf.Save();
// FileSystemTools.WhoIsLocking is a utility showing a list pf processes
// holding access to a given file
// Similar to http://stackoverflow.com/questions/1304/how-to-check-for-file-lock/20623302#20623302
List<Process> processes = FileSystemTools.WhoIsLocking("test01.zip");
Assert.That(processes.Count == 1);
zf.Dispose();
processes = FileSystemTools.WhoIsLocking("test01.zip");
Assert.That(processes.Count == 0);
After Save() the number of locking processes is 1 (the running process itself), but after Dispose() there are none, which attests that Ionic.ZipFile obviously holds some file streams internally and manages them somehow. At other places, however, Dispose() has no effect: the number of locking process is not decremented. Iconic.Zip documentation is scarce and nconvincing.

c# FileSystemWatcher fires on multiple clients

I'm using a FileSystemWatcher to watch a directory. I created a _Created() event handler to fire when a file is moved to this folder. My problem is the following:
The files in this directory get created when the user hits a "real life button" (a button in our stock, not in the application). The FileSystemWatcher take this file, do some stuff in the system and then delete it. That wouldn't be a problem when the application runs only once. But it is used by 6 clients. So every application on every client is trying to delete it. If one client is too slow, it will throw an exception because the file is already deleted.
What I'm asking for is: Is there a way to avoid this?
I tried using loops and check if the file still exists, but without any success.
while (File.Exists(file))
{
File.Delete(file);
Thread.Sleep(100);
}
Can someone give me a hint how it could probably work?
Design
If you want a file to be processed by a single instance only (for example, the first instance that reacts gets the job), then you should implement a locking mechanism. Only the instance that is able to obtain a lock on the file is allowed to process and remove it, all other instances should skip the file.
If you're fine with all instances processing the file, and only care that at least one of them succeeds, then you need to figure out which exceptions indicate a genuine failure and which ones indicate a failure caused by the actions of another instance.
Locking
To 'lock' a file, you can open it with share-mode FileShare.None. This prevents other processes from opening it until you close the file. However, you'll then need to close the file before you can delete it, which leaves a small gap during which another instance could open the file.
A better solution is to create a separate lock file for that purpose. Create it with file-mode FileMode.Create and share-mode FileShare.None and keep it open until the whole process is finished, including the removal of the processed file. Then the lock file can be closed and optionally removed.
Exception
As for the UnauthorizedAccessException you got, according to the documentation, that means one of 4 things:
You don't have the required permission
The file is an executable file that is in use
The path is a directory
The file is read-only
1 and 4 seem most likely in this case (if the file was open in another process you'd get an IOException).
If you want to synchronize access between multiple clients on the same computer you should use a Named Mutex.

Get custom status of process

I want to allow multiple processes of my application on one machine.
Projects (come from local database) can be loaded in each process and I want to ensure that a Project can only be open in one process of my application.
Therefore before opening a Project I want to check if the Project I want to open is already open in another process.
I know that this isn't best programming practice, but I it's just a temporary solution until we implement a more sophisticated locking mechanism on data Level.
I can detect another running process, but can I somehow access or cast it to something more appropriate to get the Information I want ?
Someting like that:
Process[] allProcesses = Process.GetProcessesByName("MyApp");
foreach (Process process in allProcesses)
{
var projects = process.OpenedProjects;
Have come across .net remoting, WCF, IPC but found that to be very heavyweight for this rather "simple" Task.
If it's a temp solution, just choose the easy way:
When a process load a project, just write a file in the app directory with the project name or ID. If the file already exists it means the project is already loaded in another process.
You can also write the process ID as file content, if you want to know which process have opened a project.
Of course you need to delete the file when the process finish.
Be sure that you handle all exceptions so that process can't finish without deleting this file. I.e. intercept AppDomain.UnhandledException.
If this is a temporary solution as you say, you could give each project an identifier (e.g. filename) and display it in the title of the main window, for example
C:\Project1.proj C:\Project2.proj C:\Project3.proj
Then check if the project is open with process.MainWindowTitle.Split(' ').Contains.

Create file with DeleteAfterOpen, and allow other process to read the file

Is it possible to create a file using the FileStream object in .net, specifying DeleteAfterClose option and allow read access to that file?
I've tried using:
System.IO.FileStream strBMP = new System.IO.FileStream(sFileName, System.IO.FileMode.Create, System.Security.AccessControl.FileSystemRights., System.IO.FileShare.ReadWrite, 1024, System.IO.FileOptions.DeleteOnClose);
but the other object attempting the read gets a file share violation.
I'm trying to do this because I'm creating the file (a tif), and then using a COM object (MODI) to perform OCR on the image. My problem is that eve after I call the close method on the MODI com object, I still can't delete the file using the System.File.Delete method because the MODI com object hasn't quite finsished with it. I thought if I could create my file with the DeleteAfterClose option, and still allow reading on that file I'd be set, I just can't figure out how to get passed the sharing violation - if it is even possible.
When two processes are opening the same file, both of them need to specify compatible sets of file sharing flags for the second open to succeed. Unless you can control the flags being passed by MODI when it opens the file, there's probably no way to avoid the sharing violation; for example, if it attempts to open the file in an exclusive mode, it will always fail if your process has the file open, no matter what flags you pass to the FileStream constructor.
A well-designed COM object (which may or may not be the case here) would not leave files open when it was released, so the problem may be related to the .NET COM interop layer; it's possible that it's keeping some MODI COM objects alive in an unanticipated way. Indeed, threads on other forums about this problem all mention managed code. It's possible that some combination of Marshal.FinalReleaseComObject, GC.Collect, and GC.WaitForPendingFinalizers may help solve the problem, but no one appears to have written up a definitive solution (yet) and using those functions feels extremely hacky and very brittle.

Waiting to get exclusive access of file before moving it in C#

I have a requirement to move certain files after they has been processed. Another process access the file and I am not sure when it releases them. Is there any way I can find out when the handle to the file has been released so I can move them at that time.
I am using Microsoft C# and .Net framework 3.5.
Cheers,
Hamid
If you have control of both the producer of the file and the consumer, the old trick to use is create the file under a different name, and rename it once complete.
For example, say the producer is creating files always called file_.txt, and your consumer is scanning for all files beginning file_, then the producer can do this:
1. Create the file called tmpfile_.txt
2. When the file is written, the producer simply renames the file to file_.txt
The rename operation is atomic, so once your consumer sees its available, it is safe to open it.
Of course, this answer depends on if you are writing both programs.
HTH
Dermot.
Just contniually try to open the file for exclusive writing? (e.g. pass FileShare.None to the FileStream constructor). Once you have opened it, you know no one else is using it. However, this might not be the best way to do what you're doing.
If you're after two way communication, see if the other program can be talked to via a pipe.
If you have control of both of the sources, use a named mutex (which works across processes) to control access to the files rather than locking the file at the filesystem level. This way, you don't have to catch the exception raised by attempting to lock a locked file and loop on that, which is rather inelegant.

Categories

Resources