0

I have a need to temporarily save and open a downloaded file. The product owner's stated need is to not have to go through a file save dialog to retrieve these files, nor to have the file sit on their hard drive indefinitely.

To that end, I've implemented a "View Only" option when downloading these files. When used, the file is saved with the default file name into the user's Temporary Internet Files directory, then opened with the default program using Process.Start(fileName). This behavior mimics that of the web UI that my desktop app is based on.

Here's the problem. The user wants me to go one step further and immediately delete the file when the program opened to view the file is closed by the user. "No problem", I thought, and wrote the following code:

    protected static readonly ConcurrentDictionary<int, Process> OpenFileViewers 
        = new ConcurrentDictionary<int, Process>();

    protected void LaunchFileAndWatch(string fileName, Action<string> closeFileCallback)
    {
        try
        {
            var process = Process.Start(fileName);

            OpenFileViewers.TryAdd(process.Id, process);

            process.WaitForExit();

            OpenFileViewers.TryRemove(process.Id, out process);

            closeFileCallback(fileName);

        }
        catch (Exception ex)
        {
            HandleExceptionInUIThread(ex);
        }
    }

    protected virtual void HandleExceptionInUIThread(Exception ex)
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action<Exception>(HandleExceptionInUIThread), ex);
            return;
        }

        //TODO: Whatever we want to do with the exception; for now, throw it out to ThreadException handler
        throw ex;
    }

    protected void DeleteFile(string fileName)
    {
        try
        {
        File.Delete(fileName);
        }
        catch (Exception ex)
        {
            HandleExceptionInUIThread(ex);
        }
    }

...

((Action<string, Action<string>>)LaunchFileAndWatch).BeginInvoke(downloadedFileName, DeleteFile, null, null);

The ConcurrentDictionary exists to allow me to close any open viewer programs when the application closes (if the user wishes it) so the files can be deleted then too.

The problem is, this code fails when the call to Process.Start() doesn't actually start a new process. I didn't know this could happen, but apparently the shell will re-use exiting processes, and when that happens, you don't get the process information back from any version of Process.Start, whether static or instance.

In that case, the file's not deleted and the user's not happy.

Is there a way that I can open a file using Process.Start that will force Windows to give me control over the process, without having to abandon the use of Windows' default program database?

KeithS
  • 70,210
  • 21
  • 112
  • 164
  • have you tried stepping through the code.. also what type of file is it that they want you to delete immediately could you not create a Class that reads and stores that data in memory and once you read all the Text for example immediately delete the file.. and also that would eliminate the need to use the Process.Start() unless I am not understanding your issue completely – MethodMan Mar 06 '15 at 22:39
  • 1
    Check out [CreateFile: delete_on_close flag](https://msdn.microsoft.com/en-us/library/aa363858.aspx) and http://stackoverflow.com/questions/546049/delete-on-close-files... It *may* work for some cases... Also in general Windows does not have concept "corresponding application completed reading this file" so there will always be cases when something goes wrong - fail to delete/prematurely delete... – Alexei Levenkov Mar 06 '15 at 22:52
  • @MethodMan I don't think you're understanding. The files in question are more or less everyday data files, like JPGs, PDFs, Excel/Word files, etc. Not exactly plain text, but not proprietary to this system, so I want to use whatever program Windows would choose to open the file. The natural choice, then, is Process.Start. However, some of those default programs don't create a new instance for each file, and a few don't create a new instance at all (they're part of the OS shell), so it's not always possible to get a Process instance to monitor. – KeithS Mar 06 '15 at 23:54
  • @AlexeiLevenkov - Thanks, I'll see if I can make this work. P/Invoke isn't ideal, but very little about the situation is; ideally the PO would be happy having the file go in the Internet cache and being disposed of in time. – KeithS Mar 06 '15 at 23:57

0 Answers0