C ++ - полностью приостановить приложение Windows - PullRequest
3 голосов
/ 21 мая 2010

Я занимаюсь разработкой простого приложения WinAPI и начал с написания собственной системы утверждений.

У меня есть макрос, определенный как ASSERT(X), который делает почти то же самое, что и assert(X), но с большей информацией, большим количеством опций и т. Д.

В какой-то момент (когда эта система утверждений уже работала и работала) я понял, что есть проблема.

Предположим, я написал код, который выполняет какое-то действие, используя таймер, и (просто пример) это действие выполняется при обработке сообщения WM_TIMER. И теперь ситуация меняет способ, которым этот код начинает выдавать утверждение. Это сообщение об утверждении будет отображаться каждые TIMER_RESOLUTION миллисекунд и будет просто заполнять экран.

Варианты решения этой ситуации могут быть:

1) Полностью приостановить выполнение приложения (возможно, также приостановить все потоки), когда отображается окно сообщения подтверждения, и продолжить работу после его закрытия.

2) Создайте статический счетчик для показанных подтверждений и не отображайте подтверждения, когда один из них уже отображается (но это не приостанавливает приложение)

3) Группировать подобные утверждения и показывать только по одному для каждого типа утверждений (но это также не приостанавливает применение)

4) Измените код приложения (например, цикл сообщений Get / Translate / Dispatch), чтобы он приостанавливался при наличии подтверждений. Это хорошо, но не универсально и похоже на взлом.

На мой взгляд, вариант № 1 является лучшим. Но я не знаю, как это можно сделать. То, что я ищу, - это способ приостановить время выполнения (что-то похожее на кнопку Pause в отладчике). Кто-нибудь знает, как этого добиться?

Кроме того, если кто-то знает эффективный способ решения этой проблемы - я был бы признателен за вашу помощь. Спасибо.

Ответы [ 5 ]

4 голосов
/ 21 мая 2010

Важно понять, как работают программы Windows UI, чтобы ответить на этот вопрос.

В основе модели программирования пользовательского интерфейса Windows лежит, конечно, «очередь сообщений». Сообщения поступают в очереди сообщений и извлекаются с помощью насосов сообщений. Насос сообщений не является специальным. Это просто цикл, который извлекает одно сообщение в время, блокирующее поток, если ничего не доступно.

Теперь, почему вы получаете все эти диалоги? Диалоговые окна, в том числе MessageBox, также содержат насос сообщений. Таким образом, они будут извлекать сообщения из очереди сообщений (в модели Windows не имеет большого значения , кто перекачивает сообщения). Это позволяет рисовать, перемещать мышь и вводить с клавиатуры. Это также вызовет дополнительные таймеры и, следовательно, диалоговые окна.

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

В вашей ситуации я бы рассмотрел небольшое изменение. Вы действительно хотите сохранить состояние своего стека в том месте, где произошло утверждение. Это особенность утверждений, которые заслуживают уважения. Поэтому выделите поток для своего диалога и создайте его без родительского HWND. Это дает диалогу изолированную очередь сообщений, независимую от исходного окна. Поскольку для него также есть новый поток, вы можете приостановить исходный поток, в который поступает WM_TIMER.

2 голосов
/ 22 мая 2010

Создайте рабочий поток для вашего кода отладки.Когда произойдет подтверждение, отправьте сообщение в рабочий поток.Рабочий поток будет вызывать SuspendThread для каждого потока в процессе (кроме самого себя), чтобы остановить его, а затем отображать окно сообщения.

Чтобы получить потоки в процессе - создайте dllи отслеживать DllMain для присоединения к потоку (и отключения) - каждый вызов будет выполняться в контексте создаваемого (или уничтожаемого) потока, чтобы вы могли получить текущий идентификатор потока и создать дескриптор для использования с SuspendThread.

Или отладочный API toolhelp поможет вам найти потоки для приостановки.

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

2 голосов
/ 21 мая 2010

Не показывать подсказку - либо войти в файл / вывод отладки, либо просто принудительно отключить отладчик (обычно для конкретной платформы, например.Вы должны сделать что-то более пассивное, чем показывать диалог, если есть вовлеченные потоки, которые могут вызвать множество сбоев.

1 голос
/ 22 мая 2010

Моя собственная реализация ASSERT вызывает DebugBreak () или как альтернативу INT 3 (__asm int 3 в MS VC ++). ASSERT должен сломаться на отладчике.

0 голосов
/ 21 мая 2010

Используйте функцию MessageBox. Это будет блокировать, пока пользователь не нажмет «ОК». После того, как это будет сделано, вы можете отказаться от дополнительных сообщений об ошибках подтверждения или по-прежнему отображать их по своему выбору.

...