Сбой процесса Adobe Reader при запуске второго экземпляра - PullRequest
3 голосов
/ 21 декабря 2010

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

3 голосов
/ 21 декабря 2010

Я просто разбирался с этим пару дней назад.

Если открытый экземпляр еще не создан, документ открывается в новом экземпляре напрямую.

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

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

1 голос
/ 21 декабря 2010

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

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