【问题标题】:How can I prevent file locking when dragging an attachment from an Outlook email that my application opened?从我的应用程序打开的 Outlook 电子邮件中拖动附件时,如何防止文件锁定?
【发布时间】:2014-08-08 06:55:46
【问题描述】:

我的应用程序存储所有类型的文件并允许用户打开这些文件。我们只是使用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 放弃锁定,以便我可以在拖动后与文件交互?

【问题讨论】:

    标签: .net outlook


    【解决方案1】:

    您可以使用 System.Diagnostics 查看正在运行的进程并获取进程 ID (pid) 的列表。当您调用 process.start 时,将正在运行的 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() 方法。

    【讨论】:

    • 这个想法从我脑海中掠过。我什至使用 Restart API 来确定哪个进程具有锁,如下所述:stackoverflow.com/a/20623311/159429。问题是只有在 Outlook 运行 之前 我打开文件时才会出现此问题,这意味着我无法杀死它。感谢您的想法!
    猜你喜欢
    • 2011-01-03
    • 1970-01-01
    • 2010-10-28
    • 2019-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    相关资源
    最近更新 更多