Обработка конечного процесса приложения Windows - PullRequest
10 голосов
/ 08 мая 2009

Возможно ли захватить процесс завершения диспетчера задач приложения Windows в том же самом приложении Windows? Я использую приложение Win # C # 2.0, и я хотел бы выполнить некоторую обработку базы данных (изменить флаг с 'Y' на 'N' в БД), когда произойдет конечный процесс.

Ответы [ 6 ]

10 голосов
/ 10 мая 2009

Нет, невозможно перехватить решение операционной системы об окончании процесса. Обратите внимание, что это не делается менеджером задач, завершение процесса является обязанностью ядра.

Здесь вам нужно будет сделать две вещи:

  1. Подключите обработчики событий к обычным сообщениям пользовательского интерфейса, которые сообщают приложению о выходе. Используйте эти события, чтобы сохранить данные, освободить ресурсы и иным образом завершить работу.
  2. Обрабатывайте исключения соответствующим образом для выявления ошибок, очистки и сохранения данных, если это возможно.

Вот три ссылки на блог Раймонда, объясняющие, почему вы не можете делать то, о чем просите.

Также я обратился к аналогичному вопросу StackOverflow здесь .

3 голосов
/ 12 мая 2009

Как насчет немного другого подхода:

Попросите ваше приложение обновить поле даты и времени, например, LastPollDate очень часто во время работы и имеет отдельное поле, например "AppTerminationNormally", для которого вы установили N и измените на Y, если получите событие закрытия формы.

Если приложение будет убито через диспетчер задач, дата больше не будет обновляться, а ваш AppTerminationNormally по-прежнему будет №.

Таким образом, вы могли бы выполнить запрос, который находит все строки, где LastPollDate старше 10 минут и AppTerminationNormally равно N, и у вас будут все сеансы, которые были ненормально завершены.

2 голосов
/ 23 июня 2009

Если вы ориентируетесь на Windows Vista (или выше), вас может заинтересовать API RegisterApplicationRecoveryCallback ...

http://msdn.microsoft.com/en-us/library/aa373345.aspx

Это позволяет вам указать подпрограмму обратного вызова в вашем приложении, которая будет вызываться, когда процесс собирается завершиться сбоем. Нотабене он предназначен только для сбоев и не будет вызываться автоматически, если процесс был намеренно убит.

Вы можете p / вызвать этот API из C # (я сделал это), но имейте в виду, что когда вызывается ваш обратный вызов, ваше приложение уже находится в очень плохом состоянии, и вы можете сделать очень мало предположений о состоянии вашей памяти. Если у вас есть какие-либо данные в памяти, которые вы хотите использовать в этой подпрограмме, я бы поставил их в статическом виде в очень общем объеме, чтобы у вас была максимальная вероятность того, что они не будут «прибраны» при выполнении процедуры обратного вызова работает.

Есть несколько других интересных API, связанных с этим, которые позволяют автоматически перезапускать ваше приложение после сбоя и т. Д.

2 голосов
/ 12 мая 2009

Вы все плюете на этот пост, но здесь идет ...

Вы пытаетесь решить проблему на неправильном уровне (т.е. запускать код в вашем приложении, когда ядро ​​убивает приложение). Реальная проблема заключается в том, чтобы гарантировать, что база данных правильно отражает наличие (или отсутствие) ее клиентских приложений.

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

Если вы будете следовать вышеупомянутой практике, вы найдете очень мало сценариев, в которых вам нужно «быстро очиститься» перед завершением. Вне взаимодействия, когда пользователь нажимает «ОК» или «Сохранить» и т. Д., Хорошо написанное приложение должно выдерживать немедленное завершение без какого-либо длительного повреждения или повреждения своих хранилищ данных.

Если вам абсолютно необходимо установить флаг в базе данных при выходе (что звучит типично для шаблона, используемого для определения, вошел ли пользователь в систему или нет), то рассмотрите одну из следующих альтернатив:

  1. Периодически (возможно, каждые 30 секунд) вставляйте / обновляйте поле, подобное метке времени, в базе данных, чтобы указать, как недавно приложение было в сети. Другие приложения могут проверять эти временные метки, чтобы определить, как недавно другое приложение было в сети ... если значение находится в течение последних 30 секунд, другое приложение все еще работает в режиме онлайн.

  2. Как справедливо предположил Вудхендж, создайте отдельный процесс (в идеале сервис) для мониторинга состояния основного приложения. Службы Windows можно настроить на автоматический перезапуск в случае сбоя службы. Этот процесс мониторинга затем выдаст временные метки в базу данных.

Обратите внимание, что оба приведенных выше предложения решают реальную проблему (обнаружение доступа приложений к базе данных), даже не оставляя базу данных в «несовместимом состоянии» (вышеупомянутый флаг равен «Y», когда приложение действительно мертво и флаг должен быть "N").

1 голос
/ 09 мая 2009

Я не думаю, что это возможно сделать из приложения. Цель End Task - немедленно остановить процесс. Это не позволяет выполнять какой-либо код очистки.

Шобан указал другой способ достижения вашей цели. Другое приложение или служба должны будут искать основной процесс. Когда другой процесс не может найти основной процесс, вы можете выполнить обработку базы данных в этот момент.

1 голос
/ 08 мая 2009

Что вы можете сделать, это получить идентификатор процесса и отслеживать процесс, а также использовать свойство HasExited, чтобы проверить, завершился ли процесс или нет. Ниже приведен быстрый код VB (извините, у меня сейчас нет VS. Это было написано мной на другом форуме)

Public Class Form1
    Dim p As ProcessStartInfo
    Dim process As Process
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        p = New ProcessStartInfo("iexplore.exe")
        process = process.Start(p)
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        MsgBox(process.Id)
        If process.HasExited Then
            MsgBox("yes")
        Else
            MsgBox("no")
        End If
    End Sub
End Class

Над кодом запускается Internetexplorer и кнопка проверяет, завершился ли процесс или нет. Вы можете использовать аналогичный процесс, чтобы получить все запущенные процессы и использовать processID.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...