在我们的 C# WinForms 应用程序中,我们生成 PDF 文件并通过 Process
类启动 Adobe Reader(或任何默认的系统 .pdf 处理程序)。由于我们的 PDF 文件可能很大(大约 200K),我们处理 Exited
事件,然后清理临时文件。
当文件打开然后再次关闭时,系统会按要求工作。但是,当打开第二个文件时(在关闭 Adobe Reader 之前),第二个进程立即退出(因为 Reader 现在正在使用它的 MDI 功能)并且在我们的 Exited
处理程序中我们的 File.Delete 调用应该失败,因为它是被现在加入的 Adobe 流程锁定。但是,在 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# - 启动第二个实例时 Adobe Reader 进程失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4496373/