Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.11.19;
Скачать: [xml.tar.bz2];

Вниз

Этот таинственный 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.047 c
15-1162534780
strannik
2006-11-03 09:19
2006.11.19
а софтик то нужен только для личного пользования.


1-1160396740
IMHO
2006-10-09 16:25
2006.11.19
Быстрый поиск в двоичном файле


15-1162324851
Колдун
2006-10-31 23:00
2006.11.19
Сохранение TreeView в HTML-формате


3-1158822752
ujhtw
2006-09-21 11:12
2006.11.19
GUID из БД


3-1158737783
NotGooDP
2006-09-20 11:36
2006.11.19
XML + MsSQL





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский