0
votes

My application stores all types of files and allows users to open those files. We just use Process.Start to open the file using the default application. We also allow the user to drag & drop files into our application from multiple locations, including Outlook.

This functionality generally works fine, but there's one situation that is causing a problem: when the user opens an Outlook email that is stored in our applicaton which has an attachment and then attempts to drag & drop the attached file into our application, Outlook locks the email file and never releases the lock until either our application or Outlook is closed.

I've reproduced this problem in a simple test app both in WPF and Winforms, and in all .Net versions from 3.0 to 4.5.1.

The XAML:

<Window x:Class="DragDropBug.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="250" Width="300">
    <Grid AllowDrop="True" Drop="HandleDrop">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.ColumnSpan="2" Text="DROP THE FILE HERE!"/>
        <Button Grid.Row="1" Grid.Column="0" Content="Open File" Click="OpenTheFile"/>
        <Button Grid.Row="1" Grid.Column="1" Content="Try to Delete File" Click="DeleteTheFile"/>
    </Grid>
</Window>

The code-behind file:

using System;
using System.Diagnostics;
using System.IO;
using System.Windows;

namespace DragDropBug
{
    public partial class MainWindow : Window
    {
        private const string ORIGINAL_FILENAME = "Testing.msg";
        private const string WORKING_FILENAME = "Testing-copy.msg";

        public MainWindow()
        {
            InitializeComponent();

            if (File.Exists(WORKING_FILENAME))
            {
                File.Delete(WORKING_FILENAME);
            }
        }

        private void HandleDrop(object sender, DragEventArgs e)
        {
            MessageBox.Show("Drop completed");
        }

        private void OpenTheFile(object sender, RoutedEventArgs e)
        {
            if (!File.Exists(ORIGINAL_FILENAME))
            {
                MessageBox.Show("File does not exist.");
            }
            else
            {
                // Make a copy so we can repeat the test multiple times
                File.Copy(ORIGINAL_FILENAME, WORKING_FILENAME);

                // Launch the default program for the email file
                // (this should be Outlook -- haven't tested with other email clients)
                Process myprocess = new Process();
                myprocess.StartInfo.FileName = WORKING_FILENAME;
                myprocess.Start();
            }
        }

        private void DeleteTheFile(object sender, RoutedEventArgs e)
        {
            if (!File.Exists(WORKING_FILENAME))
            {
                MessageBox.Show("File does not exist.");
            }
            else
            {
                try
                {
                    File.Delete(WORKING_FILENAME);
                    MessageBox.Show("File deleted successfully!");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }
    }
}

This sample depends on having an email called Testing.msg that has an attachment in it.

The steps to reproduce the problem are:

  1. Make sure Outlook is already running
  2. Run the test app and click the "Open File" button - this will open the email file
  3. Drag the attachment from the email onto the space labeled "DROP THE FILE HERE!"
  4. Close the email window
  5. Click the "Try to Delete File" button

At this point, since the email has been closed I expect to be able to delete my file since it should not be in use, but Outlook keeps a handle open for that file and doesn't allow me to delete it. I have to shut down either Outlook or my Application to release that handle.

If I skip step 3, the drag & drop operation, I am able to delete the file.

My question is if there is some way to prevent this file locking or force Outlook to relinquish the lock so that I can interact with the file after dragging?

1

1 Answers

0
votes

You could use System.Diagnostics to look at the running processes and get a list of the process ID's (pids). When you call process.start, store the running pid as a class level variable. When you are finished, call kill() on the process related to that pid.

using System.Diagnostics

public static ProcessThread [] GetProcessThreads (int procID)
{
   try
   {
      Process proc = Process.GetProcessById (procID);
      ProcessThread [] threads = proc.Threads;
      return threads;
   }
   catch ( Exception e)
   {
      Console.WriteLine (e.Message);
      return null;
   }
}

Then to get the ID:

threadIDs[i] = threads[i].Id;

The trick is to determine which pid you need to kill, as there will be many instances of Outlook running. The best way to do this is to have a monitoring thread running that will call the Kill() method on the process.