简体   繁体   English

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

[英]Adobe Reader process fails when starting second instance

In our C# WinForms application, we generate PDF files and launch Adobe Reader (or whatever the default system .pdf handler is) via the Process class. 在我们的C#WinForms应用程序中,我们通过Process类生成PDF文件并启动Adobe Reader(或任何默认系统.pdf处理程序)。 Since our PDF files can be large (approx 200K), we handle the Exited event to then clean up the temp file afterwards. 由于我们的PDF文件可能很大(大约200K),我们处理Exited事件然后清理临时文件。

The system works as required when a file is opened and then closed again. 打开文件然后再次关闭时,系统将根据需要运行。 However, when a second file is opened (before closing Adobe Reader) the second process immediately exits (since Reader is now using it's MDI powers) and in our Exited handler our File.Delete call should fail because it's locked by the now joined Adobe process. 但是,当打开第二个文件时(关闭Adobe Reader之前),第二个进程立即退出(因为Reader现在正在使用它的MDI权限)并且在我们的Exited处理程序中,我们的File.Delete调用应该失败,因为它被现在加入的Adobe进程锁定。 However, in Reader we instead get: 但是,在Reader中,我们得到:

There was an error opening this document. 打开此文档时出错。 This file cannot be found. 找不到此文件。

The unusual thing is that if I put a debugger breakpoint before the file deletion and allow it to attempt (and fail) the deletion, then the system behaves as expected! 不寻常的是,如果我在删除文件之前放置一个调试器断点并允许它尝试(并失败)删除,那么系统就会按预期运行!

I'm positive that the file exists and fairly positive that all handles/file streams to the file are closed before starting the process. 我很肯定该文件存在并且相当肯定,在启动进程之前,文件的所有句柄/文件流都已关闭。

We are launching with the following code: 我们将使用以下代码启动:

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

Note: We are using the _pdfProcessDictionary to store references to the Process objects so that they stay in scope so that Exited event can successfully be raised. 注意:我们使用_pdfProcessDictionary来存储对Process对象的引用,以便它们保持在范围内,以便可以成功引发Exited事件。

Our cleanup/exited event is: 我们的清理/退出活动是:

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

Possible solutions: 可能的解决方案:

  • Detect that the file is still open in another process 检测到文件在另一个进程中仍处于打开状态
  • Detect that the second process hasn't really been fully exited and that the file is opened in the first process instead 检测到第二个进程尚未完全退出,而是在第一个进程中打开该文件

I just dealt with this a couple of days ago. 刚刚在几天前处理过这个问题。

When there is no instance open already, the document opens in a new instance directly. 当没有实例打开时,文档将直接在新实例中打开。

When there is an instance already open, I believe that instance spawns a new instance which you don't actually get a handle to. 当一个实例已经打开时,我相信该实例会产生一个你实际上没有得到句柄的新实例。 What happens is control returns to your function immediately, which then goes and deletes the file before the new instance has had a chance to read the file -- hence it appears to not be there. 发生的是控制立即返回到您的函数,然后在新实例有机会读取文件之前删除文件 - 因此它似乎不在那里。

I "solved" this by not deleting the files immediately, but keeping track of the paths in a list, and then nuking all of them when the program exits (wrap each delete in a try/catch with an empty catch block in case the file has disappeared in the meantime). 我通过不立即删除文件来“解决”这个问题,但是跟踪列表中的路径,然后在程序退出时对所有文件进行核对(在try / catch中使用空catch块包装每个删除以防文件在此期间已经消失了)。

I would suggest following approach: 我建议采用以下方法:

  1. Create files in user's temp directory ( Path.GetTempPath ). 在用户的临时目录( Path.GetTempPath )中创建文件。 You can create some sub-folder under it. 您可以在其下创建一些子文件夹。
  2. Attempt to delete files only when last instance of process gets exited (ie you need to count number of processes that you had launched, on exit, decrement the count and when it becomes zero, attempt to delete (all) files that are open so far) 尝试仅在最后一个进程实例退出时删除文件(即,您需要计算已启动的进程数,退出时,减少计数以及何时变为零,尝试删除目前为止打开的(所有)文件)
  3. Try to clean-up created sub-folder (under temp directory) while starting and ending the application. 尝试在启动和结束应用程序时清理创建的子文件夹(在临时目录下)。 You can even attempt for periodic clean-up using timer. 您甚至可以尝试使用计时器进行定期清理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM