В нашем приложении C # WinForms мы генерируем файлы PDF и запускаем Adobe Reader (или любой другой системный обработчик .pdf по умолчанию) через класс Process
. Поскольку наши PDF-файлы могут быть большими (около 200 КБ), мы обрабатываем событие 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
}
}
Возможные решения:
- Обнаружить, что файл все еще открыт в другом процессе
- Обнаружить, что второй процесс действительно не был полностью завершен и вместо этого файл открывается в первом процессе