从应用程序打开的Outlook电子邮件中拖动附件时,如何防止文件锁定?



我的应用程序存储所有类型的文件,并允许用户打开这些文件。我们只使用Process.Start使用默认应用程序打开文件。我们还允许用户拖动&将文件从多个位置(包括Outlook)放入我们的应用程序。

这个功能通常工作得很好,但有一种情况会导致问题:当用户打开存储在我们的应用程序中的Outlook电子邮件时,它有一个附件,然后试图拖动&将附加文件放入我们的应用程序中,Outlook将锁定电子邮件文件,并且永远不会释放锁定,直到我们的应用程序或Outlook关闭。

我在WPF和Winforms以及从3.0到4.5.1的所有。net版本的一个简单的测试应用程序中重现了这个问题。

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>

隐藏代码文件:

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());
                }
            }
        }
    }
}

此示例依赖于有一个名为Testing.msg的电子邮件,该电子邮件中有一个附件。

重现问题的步骤如下:

  1. 确保Outlook已经在运行
  2. 运行测试应用程序并点击"打开文件"按钮-这将打开电子邮件文件
  3. 将附件从电子邮件拖到标记为"将文件拖到这里!"
  4. 关闭邮件窗口
  5. 点击"尝试删除文件"按钮

在这一点上,由于电子邮件已经关闭,我希望能够删除我的文件,因为它不应该在使用中,但Outlook为该文件保持一个打开的句柄,不允许我删除它。我必须关闭Outlook或我的应用程序来释放该句柄。

如果我跳过步骤3,拖动&删除操作,我可以删除文件。

我的问题是,如果有一些方法来防止这个文件锁定或强制Outlook放弃锁定,以便我可以与拖拽后的文件进行交互?

您可以使用System。用于查看正在运行的进程并获得进程ID (pid)列表的诊断。当你调用process。首先,将正在运行的pid存储为类级别变量。当您完成后,对与该pid相关的进程调用kill()。

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;
   }
}

然后获取ID:

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

关键在于确定需要删除哪个pid,因为会有许多Outlook实例正在运行。做到这一点的最佳方法是运行一个监视线程,该线程将调用进程上的Kill()方法。

最新更新