В нашем приложении 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
}
}
Возможные решения:
- Обнаружить, что файл все еще открыт в другом процессе
- Обнаружить, что второй процесс на самом деле не был полностью завершен и что файл вместо этого открыт в первом процессе