c# - 启动第二个实例时 Adob​​e Reader 进程失败

标签 c# winforms process.start adobe-reader

在我们的 C# WinForms 应用程序中,我们生成 PDF 文件并通过 Process 类启动 Adob​​e Reader(或任何默认的系统 .pdf 处理程序)。由于我们的 PDF 文件可能很大(大约 200K),我们处理 Exited 事件,然后清理临时文件。

当文件打开然后再次关闭时,系统会按要求工作。但是,当打开第二个文件时(在关闭 Adob​​e Reader 之前),第二个进程立即退出(因为 Reader 现在正在使用它的 MDI 功能)并且在我们的 Exited 处理程序中我们的 File.Delete 调用应该失败,因为它是被现在加入的 Adob​​e 流程锁定。但是,在 Reader 中,我们得到的是:

There was an error opening this document. This file cannot be found.

不寻常的是,如果我在文件删除之前放置一个调试器断点并允许它尝试(并失败)删除,那么系统会按预期运行!

我肯定该文件存在并且相当肯定该文件的所有句柄/文件流在开始该过程之前已关闭。

我们使用以下代码启动:

// Open the file for viewing/printing (if the default program supports it) 
var pdfProcess = new Process();
pdfProcess.StartInfo.FileName = tempFileName;
if (pdfProcess.StartInfo.Verbs.Contains("open", StringComparer.InvariantCultureIgnoreCase))
{
    var verb = pdfProcess.StartInfo.Verbs.First(v => v.Equals("open", StringComparison.InvariantCultureIgnoreCase));
    pdfProcess.StartInfo.Verb = verb;
}
pdfProcess.StartInfo.Arguments = "/N"; // Specifies a new window will be used! (But not definitely...)
pdfProcess.SynchronizingObject = this;
pdfProcess.EnableRaisingEvents = true;
pdfProcess.Exited += new EventHandler(pdfProcess_Exited);

_pdfProcessDictionary.Add(pdfProcess, tempFileName);

pdfProcess.Start();

注意:我们正在使用 _pdfProcessDictionary 来存储对 Process 对象的引用,以便它们保持在范围内,以便可以成功引发 Exited 事件。

我们的清理/退出事件是:

void pdfProcess_Exited(object sender, EventArgs e)
{
    Debug.Assert(!InvokeRequired);
    var p = sender as Process;
    try
    {
        if (_pdfProcessDictionary.ContainsKey(p))
        {
            var tempFileName = _pdfProcessDictionary[p];
            if (File.Exists(tempFileName)) // How else can I check if I can delete it!!??
            {
                // NOTE: Will fail if the Adobe Reader application instance has been re-used!
                File.Delete(tempFileName);
                _pdfProcessDictionary.Remove(p);
            }

            CleanOtherFiles(); // This function will clean up files for any other previously exited processes in our dictionary
        }
    }
    catch (IOException ex)
    {
        // Just swallow it up, we will deal with trying to delete it at another point
    }
}

可能的解决方案:

  • 检测到该文件仍在另一个进程中打开
  • 检测到第二个进程并没有真正完全退出,而是在第一个进程中打开了文件

最佳答案

几天前我刚刚处理了这个问题。

当没有实例打开时,文档直接在新实例中打开。

当有一个实例已经打开时,我相信该实例会生成一个您实际上没有句柄的新实例。发生的事情是控制权立即返回到您的函数,然后在新实例有机会读取文件之前,它会去删除文件——因此它似乎不存在。

我通过不立即删除文件来“解决”这个问题,而是跟踪列表中的路径,然后在程序退出时对所有路径进行核对(将每个删除包装在 try/catch 中,其中包含一个空的 catch block 以防文件同时消失)。

关于c# - 启动第二个实例时 Adob​​e Reader 进程失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4496373/

相关文章:

javascript - 浏览器加载 html 页面时出现脚本错误

winforms - 为什么在我在文本框中输入 "only"一个字符后,我的文本框 TextChanged 事件会被触发?

c# - 如何从 C# 启动进程?

c# - Process.Start 是否在父程序终止时终止子程序?

c# - OSX 上的 Mono,Process.Start 有时会抛出无法处理的 native 包装器异常

c# - 根据答案更改表单颜色

c# - 从 memorystream 打开 excel 工作簿

c# - 在数据库中添加表运行时

c# - 如何在 lambda 表达式中传递 ref 参数? - 线程问题

c# - 如何将 Windows 窗体设计器生成的组合框放入数组中