Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.11.19;
Скачать: CL | DM;

Вниз

Этот таинственный MessageBox...   Найти похожие ветки 

 
Bless ©   (2006-10-10 10:21) [0]

Сперва приведу тестовый пример.
Итак, создаем новое приложение с двумя формами. На form1 бросаем кнопку и пишем обработчик OnClick:
procedure TForm1.Button1Click(Sender: TObject);
begin
form2 := tform2.create(self);
end;


У form2 есть такие обработчики:
procedure TForm2.FormCreate(Sender: TObject);
begin
 try
   raise Exception.Create("my exception");
 except
   PostMessage(handle, WM_CLOSE,0,0);
   Windows.MessageBox(0, "11", "22", mb_ok); //!!!!!!!!!!!!!!!!!!!!!!!
 end;{try}
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 action := caFree;
end;


Если поставить точку останова на выделенную строчку в TForm2.FormCreate и нажать f8, то меня заносит в обработчик TForm2.FormClose (!?!), после чего возвращает назад в TForm2.FormCreate (на последний end;). Почему это происходит?


 
ors_archangel ©   (2006-10-10 10:34) [1]

Думаю, появление MessageBox вызывает обработку сообщения WM_CLOSE (у него там модальный message loop, видимо) приложением, а так как мы трейсимся, то мы и трейсимся в WM_CLOSE-обработчик, но Делфи останавливается по Ф8 только на коде нашего проекта, поэтому мы попадаем, я так думаю, в FormClose. После присвоения в этом обработчике, сообщение WM_CLOSE мы больше не увидим (больше негде) и поэтому возвращаемся к коду FormCreate. Код FormCreate в блоке except по любому выполняется, даже если мы и присваиваем action = caFree, мы не убиваем этим форму (и тем более нить) сейчас же. Когда отлаживаешь multithread-проги, тоже весело бывает очень :)


 
Плохиш ©   (2006-10-10 10:38) [2]


> Почему это происходит?

Потому что происходит обработка оереди сообщений.


 
Bless ©   (2006-10-10 10:46) [3]


> ors_archangel ©   (10.10.06 10:34) [1]


Не совсем понимаю, что такое модальный message loop, но ты уверен, что он имеет какое-то отношение к Windows.MessageBox, к тому же с параметром hWnd (который Identifies the owner window) = 0?

То, что FormClose вызвался как результат обработки сообщения WM_CLOSE, это понятно.
Непонятно только, кто его сгенерировал.
Причем (тут я могу ошибаться, конечно), впечатление такое, что WM_CLOSE попало к Form2 не из очереди сообщений (такое впечатление сложилось потому, что в Application.ProcessMessages по F8 на выделенной строчке не попало, а ведь должно бы?), а через прямой вызов оконной процедуры (DispatchMessage?). Но кто этот вызов сделал, что-то не пойму.


 
Bless ©   (2006-10-10 10:49) [4]


> Плохиш ©   (10.10.06 10:38) [2]
> Потому что происходит обработка оереди сообщений.


А как я в эту обработку тогда попал, не расскажешь?


 
Bless ©   (2006-10-10 10:52) [5]

Вдогонку [4]
Приложение-то однопоточное, я сейчас нахожусь в обработчике FormCreate. Каким образом меня вдруг закинуло в цикл обработки сообщений, а потом вернуло обратно?


 
Игорь Шевченко ©   (2006-10-10 10:52) [6]

Bless ©   (10.10.06 10:46) [3]


> Не совсем понимаю, что такое модальный message loop


Выборка из очереди потока сообщений, относящихся только к определенному окну. Поток-то один, в недрах MessageBox крутится цикл выборки сообщений, который больше никому не отдает управления.


 
Elen ©   (2006-10-10 10:53) [7]


> Bless

Ну ты ж вызываеш эту обработку через PostMessage(handle, WM_CLOSE,0,0)?
Верно ведь? Хендл то формовский


 
Игорь Шевченко ©   (2006-10-10 10:53) [8]

Bless ©   (10.10.06 10:52) [5]


> Каким образом меня вдруг закинуло в цикл обработки сообщений,
>  а потом вернуло обратно?


Цикл выборки сообщений вызвал оконную процедуру формы для обработки синхронного сообщения, например.


 
Elen ©   (2006-10-10 10:59) [9]

Поправочка - "вызываеш" надо читать "помешаеш в очередь сообщений"


 
Bless ©   (2006-10-10 11:18) [10]

> Игорь Шевченко ©   (10.10.06 10:53) [8]
> Цикл выборки сообщений вызвал оконную процедуру формы для
> обработки синхронного сообщения, например.


Не понял. Где я ошибаюсь?
Вся программа по сути - это цикл обработки сообщений. В данный момент я как раз обрабатываю одно из них, которое завело меня в конечном итоге в procedure TForm2.FormCreate. Когда я закончу, то попаду  назад в цикл, который выберет следующее сообщение (которое вполне может оказаться WM_CLOSE, которое я туда поместил строчкой PostMessage(handle, WM_CLOSE,0,0);) из очереди и обработает его.
На самом деле все происходит не совсем так?


 
Bless ©   (2006-10-10 11:22) [11]

Или Вы хотите сказать, что обработчик сообщения WM_CLOSE для окна был вызван изнутри цикла MessageBox-а?


 
Elen ©   (2006-10-10 11:25) [12]


> Bless

Нет когда ты возвал PostMessage. Ты поставил WM_Close в очередь событий. Просто перед ним были tit сообщения, ожидающие своей обработки. А когда дело дошло до WM_Close то пошло в close. Замени MessageBox на любой другой оператор и будет практически та же реакция Имхо


 
Bless ©   (2006-10-10 11:28) [13]


> Elen ©   (10.10.06 10:59) [9]
> Поправочка - "вызываеш" надо читать "помешаеш в очередь
> сообщений"


Вот именно. Не вызываю, а помещаю в очередь, в расчете на то, что оно будет обработано не раньше, чем произойдет очередная выборка очередного сообщения из очереди сообщений. То есть всяко после TForm2.FormCreate, а не посредине него.


 
Bless ©   (2006-10-10 11:32) [14]


>  Замени MessageBox на любой другой оператор и будет практически
> та же реакция


Заменил на form2 := nil;. Реакция другая. Как и следовало ожидать, процедура TForm2.FormCreate отработала до конца и лишь затем был вызван TForm2.FormClose.


 
han_malign ©   (2006-10-10 11:33) [15]

MB_TASKMODAL


 
Плохиш ©   (2006-10-10 11:34) [16]


> Bless ©   (10.10.06 11:22) [11]

Объясняю на пальцах. Вызвав MessageBox, который ждёт, как, надеюсь,  известно, реакции пользователя, ты передал управление из своей программы системе, а та в свою очередь включила обработку сообщений, потому что другим способом реакцию пользователя как-то узнать труднова-то. Соответственно были обработаны все сообщения пришедшие приложению. Тот же самый эффект ты получишь просто вызвав Application.ProcessMessages.


 
Elen ©   (2006-10-10 11:35) [17]


> Bless

Чего б не поставить PostMessage или Form2.close после всех нужных действий в Эксцепте?


 
Bless ©   (2006-10-10 11:40) [18]


> Плохиш ©   (10.10.06 11:34) [16]


Т.е. я в [11] все верно написал?

Но меня как-то смущает:

> Игорь Шевченко ©   (10.10.06 10:52) [6]
> Bless ©   (10.10.06 10:46) [3]
> > Не совсем понимаю, что такое модальный message loop
> Выборка из очереди потока сообщений, относящихся только
> к определенному окну
. Поток-то один, в недрах MessageBox
> крутится цикл выборки сообщений, который больше никому не
> отдает управления.


Так внутренний цикл MessageBox-а обрабатывает только сообщения, относящиеся к окну MessageBox-а или все-таки все сообщения? Где об этом можно четко прочитать?


 
Плохиш ©   (2006-10-10 11:44) [19]


> Так внутренний цикл MessageBox-а обрабатывает только сообщения,
>  относящиеся к окну MessageBox-а или все-таки все сообщения?

MessageBox выполняется в основном потоке программы, а сообщения  обрабатываются по потокам, а не по окнам.


 
han_malign ©   (2006-10-10 12:02) [20]


> Где об этом можно четко прочитать?

Help->MessageBox->Flags: MB_APPLMODAL/MB_SYSTEMMODAL/MB_TASKMODAL

модальные окна не блокируют(по умолчанию) очередь сообщений для других окон,
тут кто-то уже ставил MB на таймер и был (не)приятно удивлен...
Application.ProcessMessages
    GetMessage(MSG, 0,...)
         DispatchMessage
              <MB.ProcessMessages>
              GetMessage((MSG, зависит от флагов,...)
                   DispatchMessage
              loop
    loop


 
Bless ©   (2006-10-10 12:13) [21]


> Elen ©   (10.10.06 11:35) [17]
> Чего б не поставить PostMessage или Form2.close после всех
> нужных действий в Эксцепте?


В данном примере это можно сделать. Но к сути вопроса это отношения не имеет, а пример создан лишь для иллюстрации вопроса.


 
default ©   (2006-10-10 12:31) [22]

Bless ©   (10.10.06 12:13) [21]
представь, что вместо вызова MessageBox ты создаёшь окно для диалога с пользователем(через CreateWindow(Ex)) и запускаешь цикл выборки сообщений отбирая в нём сообщения относящиеся только к созданному окну - это получится некое подобие модального вызова MessageBox
а вот если ты принимаешь на обработку сообщения относящиеся ко всем окнам, то тогда это будет некое подобие немодального вызова MessageBox
у тебя MessageBox вызывается немодально, поэтому ведётся обработка сообщений для всех окон и потому WM_CLOSE главного окна и обрабатывается


 
default ©   (2006-10-10 12:44) [23]


> отбирая в нём сообщения относящиеся только к созданному
> окну - это получится некое подобие модального вызова MessageBox

это лишь некое подобие
на самом деле модальный показ MessageBox блокирует не все сообщения для других окон
в чём легко убедиться, например, вызвав модально MessageBox на главном окне, потом открыть другую программу и снова исходную программу - и увидим, что главное окно перерисовалось - значит сообщения по отрисовке главного окна "пропускаются" циклом выборки сообщений генерируемым модальным вызовом MessageBox
а вот сообщения по закрытию окна в модальном вызове MessageBox не  пропускаются


 
default ©   (2006-10-10 12:49) [24]


> "пропускаются" циклом

пропускаются на обработку всмысле:)всмысле обрабатываются:)


 
Bless ©   (2006-10-10 17:13) [25]


> han_malign ©   (10.10.06 12:02) [20]
> > Где об этом можно четко прочитать?
>
> Help->MessageBox->Flags: MB_APPLMODAL/MB_SYSTEMMODAL/MB_TASKMODAL


Что-то я здесь не нашел информации о том, какие сообщения обрабатываются внутри MessageBox.


> default ©   (10.10.06 12:31) [22]
> у тебя MessageBox вызывается немодально, поэтому ведётся
> обработка сообщений для всех окон и потому WM_CLOSE главного
> окна и обрабатывается


Даже если я вызову его немодально, WM_CLOSE все-равно обработается.

Видимо, в [11] я угадал правильно (точнее не угадал, а переспросил сказанное в [6]). Внутри MessageBox, похоже, действительно организован свой собственный цикл выборки сообщений, который и вызвал обработчик WM_CLOSE.


 
Bless ©   (2006-10-10 17:14) [26]

Да, чуть не забыл.
Спасибо :)



Страницы: 1 вся ветка

Текущий архив: 2006.11.19;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.054 c
2-1162480191
Riply
2006-11-02 18:09
2006.11.19
Два комонента, использующие OpenGL


2-1162472187
Sergey_b
2006-11-02 15:56
2006.11.19
SELECT, UPDATE, INSERT


15-1162183145
Slider007
2006-10-30 07:39
2006.11.19
С днем рождения ! 28 октября


1-1160585051
AndreyGor
2006-10-11 20:44
2006.11.19
Вызов функции из стандартных библиотек винды


3-1158743677
kaif
2006-09-20 13:14
2006.11.19
Преемственность данных и суррогатные ключи