Сбой процесса Adobe Reader при запуске второго экземпляра

В нашем приложении 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
    }
}

Возможные решения:

  • Определить, что файл все еще открыт в другом процессе
  • Обнаружить, что второй процесс на самом деле не был полностью завершен и вместо этого файл открывается в первом процессе

2 ответа

Решение

Я только что имел дело с этим пару дней назад.

Когда уже нет открытого экземпляра, документ открывается в новом экземпляре напрямую.

Когда экземпляр уже открыт, я считаю, что этот экземпляр порождает новый экземпляр, с которым вы фактически не можете справиться. Что происходит, так это то, что управление немедленно возвращает вашу функцию, которая затем отправляет и удаляет файл, прежде чем новый экземпляр сможет прочитать файл - следовательно, его там, похоже, нет.

Я "решил" это, не удаляя файлы сразу, а следя за путями в списке, а затем обнуляя все из них при выходе из программы (оберните каждое удаление в try/catch с пустым блоком catch в случае, если файл исчез в то же время).

Я бы предложил следующий подход:

  1. Создайте файлы во временном каталоге пользователя ( Path.GetTempPath). Вы можете создать некоторую подпапку под ним.
  2. Попытайтесь удалить файлы только при выходе из последнего экземпляра процесса (т. Е. Вам нужно подсчитать количество запущенных вами процессов, при выходе уменьшить значение счетчика и, когда он станет равным нулю, попытаться удалить (все) открытые до сих пор файлы)
  3. Попробуйте очистить созданную подпапку (в папке temp) при запуске и завершении приложения. Вы можете даже попытаться выполнить периодическую очистку, используя таймер.
Другие вопросы по тегам