启动第二个实例时,Adobe Reader进程失败

时间:2010-12-21 04:48:06

标签: c# winforms process.start adobe-reader

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

打开文件然后再次关闭时,系统会根据需要运行。但是,当打开第二个文件时(关闭Adobe Reader之前),第二个进程会立即退出(因为Reader现在正在使用它的MDI权限)并且在我们的Exited处理程序中,我们的File.Delete调用应该会失败,因为它被锁定了现在加入了Adobe流程。但是,在Reader中我们得到:

  

打开此文档时出错。找不到此文件。

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

我很肯定该文件存在且相当肯定,在启动该进程之前,所有处理/文件流都将关闭。

我们将使用以下代码启动:

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

可能的解决方案:

  • 检测到文件在另一个进程中仍处于打开状态
  • 检测到第二个进程尚未完全退出,并且在第一个进程中打开该文件

2 个答案:

答案 0 :(得分:3)

只是几天前处理过这个问题。

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

当一个实例已经打开时,我相信该实例会产生一个你实际上没有得到句柄的新实例。会发生什么情况是控制立即返回到您的函数,然后在新实例有机会读取文件之前删除文件 - 因此它似乎不在那里。

我通过不立即删除文件来“解决”这个问题,但是跟踪列表中的路径,然后在程序退出时对所有文件进行核对(将try / catch中的每个删除包装在一个空的catch块中)如果文件在此期间消失了。)

答案 1 :(得分:1)

我建议采用以下方法:

  1. 在用户的临时目录(Path.GetTempPath)中创建文件。您可以在其下创建一些子文件夹。
  2. 仅在退出最后一个进程实例时尝试删除文件(即,您需要计算已启动的进程数,退出时,减少计数以及何时变为零,尝试删除(所有)文件到目前为止开放)
  3. 尝试在启动和结束应用程序时清理已创建的子文件夹(在temp目录下)。您甚至可以尝试使用计时器进行定期清理。