|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Сен 6, 2004 23:26:18 пока енто сообщение не обработалося не приходит НОВОЕ! Если быть точнее , то поток "спит" (крутиться в ядре) пока очередь сообщений пуста . Давайте попорядку . 1. SetTimer - говорим ядру период и адрес процедуры обработки WM_TIMER . 2. GetMessage - говорим ядру адрес структуры MSG и уходим в ожидание (поток спит этот период) . 3. Когда приходит время (для любого сообщения) ЯДРО пишет в структуру MSG номер сообщения и передаёт управление за GetMessage . 4. Теперь DispatchMessage смотрит в структуру MSG и анализирует тип сообщения . Если это WM_TIMER (113h) , то передаём управление на MSG.lParam , а там уже как раз лежит (вписанный ядром) адрес нашей процедуры . Всё !! А теперь представьте , что у вас х-ва туча сообщений , а MSG.message это всего один дворд , ядро туда может и пишет все WM_TIMER , но DispatchMessage ведь не может создавать потоки на каждое . Можете поэкспериментировать на одном WM_TIMER . http://wasm.ru/forum/files/_934647330__timeproc.zip |
|
|
Дата: Сен 7, 2004 00:13:12 · Поправил: rsrc bogrus Немного не так! :) Вот этот код дает возможность жить окну(ам):
BOOL bRet;
MSG msg;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Примерно тоже самое есть и у MessageBox (это же окно!) где-то :))). GetMessage() проверяет очередь сообщений потока на WM_TIMER в самую последнюю очередь (это сообщение низкоприоритетное!) и если находит его, то тогда тогда сбрасывает таймер и возвращает управление. Таймер отправляет сообщение твоему окну и ждет когда его сбросят, чтобы опять посчитать и отправить WM_TIMER, но Sleep() это (сбросить таймер) сделать не может! А вот когда ты вызываешь MessageBox(), то вот тогда (см. код выше!) его GetMessage() и сбрасывает таймер и он опять считает и дает WM_TIMER, а ты в это время зыришь свой MessageBox() и :) неожиданно для тебя выскакивает еще один…. Oleg_SK, и вот теперь ты уже все знаешь! З.Ы. Дядька Рихтер толковую книжку написал. |
|
|
Дата: Сен 7, 2004 00:56:43 rsrc Скоро мы доберёмся до истины ! :) Это я привёл случай , когда процесс вообще без окон , но с обработкой WM_TIMER . Т.е. у нас крутиться свой цикл . Теперь , если мы добавим в процедуру Sleep , то после очередного её вызова GetMessage пойдёт уже с этой задержкой . Если же мы добавим MessageBox , то доставть наши сообщения (а поток у нас один) будет НЕ наш GetMessage ! Примерно тоже самое есть и у MessageBox (это же окно!) где-то :))). Это называеться DefDlgProc . Вот он и будет доставать теперь наши сообщения . Т.е. этот "чужой" GetMessage указывает ядру свою MSG (на стеке) , НО ЯДРО ПОМНИТ адрес нашей процедуры (WM_TIMER) и записывает его в "чужой" MSG , и 113h туда записывает . Ну а DefDlgProc тоже имеет DispatchMessage (см. пункт 4) , вот он и передаёт управление снова в нашу процедуру , а там MessageBox готовиться создать ещё одно окно (цикл они имеют все один - в DefDlgProc) . з.ы. Дядька Олли тоже гуд :) |
|
|
Дата: Сен 7, 2004 01:22:22 · Поправил: rsrc bogrus 1. Непонятно тогда как поток без окна может получить WM_TIMER? У него раз нет окон, то тогда нет и очереди сообщений! The SetTimer function creates a timer with the specified time-out value. UINT_PTR SetTimer( HWND hWnd, // handle to window UINT_PTR nIDEvent, // timer identifier UINT uElapse, // time-out value TIMERPROC lpTimerFunc // timer procedure ); 2. Не совсем DefDlgProc(), она конечно для каждого диалога вызывается, но надо же еще кое-какие мессаги обработать MessageBox'у раньше "старого" окна, MessageBox же модальное окно! У MessageBox'a должен быть еще свой цикл выборки сообщений, ведь "старый" GetMessage()-DispatchMessage() ему никак не найти!!! |
|
|
Дата: Сен 7, 2004 01:28:48 bogrus, вот придет Four-F и нас рассудит! |
|
|
Дата: Сен 7, 2004 01:39:54 1. Непонятно тогда как поток без окна может получить WM_TIMER? Усё там понятно :) , посмотри исходник по ссылке . HWND hWnd, // handle to window If this parameter is NULL, no window is associated with the timer and the nIDEvent parameter is ignored. надо же еще кое-какие мессаги обработать MessageBox'у раньше "старого" окна Ну вот и обрабатывает мессаги потока , и в "старое" передаёт (можешь spyxx-ом посмотреть) . А на счёт можальности (в чём она выражаеться под дебаггером) надо будет ещё посмотреть . вот придет Four-F и нас рассудит! Тю ! Так мы ж с тобой не спорим , просто делимся впечатлениями :) Four-F , скорее по ядрам , а тут всё в юзермоде происходит . |
|
|
Дата: Сен 7, 2004 02:27:50 · Поправил: rsrc bogrus 1. Ответ нашел у Рихтера: как только поток обратиться к той или иной GUI-функции (например, для проверки очереди сообщений или создания окна), система автоматом выделит ему ресурсы (THREADINFO, очередь сообщений и т.д.) и вот поэтому твой код работает без окон, но с GetMessage()! И потом я имел ввиду оконный обработчик WM_TIMER, а не callback! 2. А по этому пункту я прав однозначно! %) P.S. bogrus, и все же я прав по всем пунктам! Ну, а то что я раньше думал, что если у потока нет окон, то и нет очереди сообщений, то это ни-че-го и к делу не относится :) |
|
|
Дата: Сен 7, 2004 12:09:22 · Поправил: bogrus Ну с дядькой мне спорить тяжко , а с тобой попробую :) 1. Ответ нашел у Рихтера: как только поток обратиться Т.е. ты (вы с дядькой ?) хотите сказать , что пока поток не обращаеться к той или иной GUI-функции , то у него нет очереди ? Брехня ! А давай сделаем эксперимент - пошлем чужому потоку любое сообщение . Следовательно , если он никуда не обращался к той или иной GUI , то сообщение пропадёт . А вот и нет , оно не пропадёт , а будет храниться в его очереди - значит она у него есть (см. аттач) , и заметь - никаких окон . 2. А по этому пункту я прав однозначно У MessageBox'a тот же цикл , что и у диалога . А "старый" это значит свой (тот что сами делаем в своём модуле , например при создании окна "ручками") . Тут ещё надо определиться , что ты хочешь доказать , я не вижу конкретного утверждения . |
|
|
Дата: Сен 7, 2004 12:28:06 |
|
|
Дата: Сен 7, 2004 12:29:05 1. щас буду смотреть и думать. 2. тоже самое и я говорил, но токо другими словами... :) |
|
|
Дата: Сен 7, 2004 13:56:11 · Поправил: rsrc Привожу полностью слова Рихтера: Создавая какой-либо поток, система предполагает, что он не будет иметь отношения к поддержке пользовательского интерфейса. Это позволяет уменьшить объем выделяемых ему системных ресурсов. Но, как только поток обратиться к той или иной GUI-функции (например, для проверки очереди сообщений или создания окна), система автоматически выделит ему дополнительные ресурсы, необходимые для выполнения задач, связанных с пользовательским интерфейсом. А если конкретнее, то система создает структуру THREADINFO (недокументированная!) и сопоставляет ее с этим потоком. Когда с потоком связывается структура THREADINFO, он получает свой набор очередей сообщений. И из этого можно сделать вывод – у любого потока есть очередь сообщений, а когда эта очередь сообщений для него создается нам должно быть пох…й :) bogrus, я был не прав! |
|
|
Дата: Сен 7, 2004 14:39:01 И из этого можно сделать вывод – у любого потока есть очередь сообщений, а когда эта очередь сообщений для него создается нам должно быть пох…й :) Я понял , что дядька имел ввиду . Указатель на THREADINFO лежит в [fs:40] . Теперь простыми экспериментами видно , что для консольной проги он пустой , а для гуёвой заполнен . Т.е. он хотел сказать о Subsystem в PE , если GUI , то загрузчик должен создать THREADINFO . |
|
|
Дата: Сен 7, 2004 15:38:02 [ Oleg_SK: но к сожалению кроме этой статьи я больше ни чего ни где не нашел по этой теме ] Есть, по крайней мере, ещё одна супер-статья по SEH - "A Crash Course in Structured Exception Handling" дядьки Питрека. http://www.microsoft.com/msj/0197/Exception/Exception.htm [ Oleg_SK: В случае же использования функции MessageBox все летит кувырком, т.к. выполнение потока возобновляется в то время, когда процедура обработчика исключений еще не отработала:( ] В этом случае выполнение потока вообще не прекращается. Тебе просто кажется, что пока MessageBox не вернется поток спит. Если бы это было так, то любая прога вызвавшая MessageBox не смогла бы себя перерисовывать. Запусти тот же notepad и выбери там любой диалог из меню. Сверни все окна и разверни. Основное окно notepad перерисуется. А Sleep суспедит поток, т.е. она явно исключает его из планирования. Если её влепить куда-нить в процедуру окна, то такое окно не сможет себя перерисовывать, его нельзя будет двигать и т.д. и т.п. [ bogrus: Брехня! А давай сделаем эксперимент - пошлем чужому потоку любое сообщение. Следовательно, если он никуда не обращался к той или иной GUI, то сообщение пропадёт. ] Точнее не будет послано. Тут Рихтер и rsrc правы :) bogrus, ты неверно ставищь эксперимент. Дело в том, что первичный поток процесса уже автоматом является GUI-потоком. Т.е. очередь сообщений у него появляется ещё до того, как система вызовет точку входа. Нужно создать рабочий поток и уже ему слать мессагу, но только до того как он вызовет GetMessage. Ибо тогда он сразу будет конвертирован в GUI-поток и у него появится очередь сообщений. Если вызвать PostThreadMessage до этого, то она обломится и GetLastError вернет ERROR_INVALID_THREAD_ID. [ rsrc: И из этого можно сделать вывод – у любого потока есть очередь сообщений... ] Нет. Создай поток через CreateThread и не будет у него никакой очереди сообщений и нельзя ему будет ничего послать, до тех пор пока он не вызовет какую-нить функцию требующую перевода его в GUI поток. [ bogrus: Т.е. он хотел сказать о Subsystem в PE, если GUI, то загрузчик должен создать THREADINFO. ] Не знаю, что хотел сказать Рихтер, но GUI поток или не GUI однозначно можно определить по полю KTHREAD.ServiceTable. Смещения 0DCh, 0E0h, 124h для w2k, xp и Server 2003, соответственно. Повторяю, первичный поток процесса автоматом является GUI-потоком. Даже для КОНСОЛЬНОГО приложения. Для НЕ GUI потоков в KTHREAD.ServiceTable будет указатель на KeServiceDescriptorTable, а для GUI потоков - указатель на KeServiceDescriptorTableShadow. Указатели на KTHREAD можно получить по команде thread (для текущего потока можно посмотреть разделительную зеленую полоску в айсе). Указатель на KeServiceDescriptorTable можно получить набрав exp keser |
|
|
Дата: Сен 7, 2004 15:52:19 Four-F Чесно говоря , я пока ставлю эксперименты только в юзер моде . О ядре я очень мало знаю , не интересуюсь . Наверное из-за сайса , уже три раза его ставил и потом три раза сносил , не могу вытерпеть его интерфейс . Чтобы научиться ним пользоваться , нужно читать мануал , а я не очень люблю :) Если THREADINFO о которой говорил Рихтер лежит в [fs:40] , то он заполняеться в момент инициализации gdi32.dll , вот таким кодом (w2ksp4) : ====================GDI32.GdiDllInitialize======================= 77F4224D B8 D4100000 MOV EAX, 10D4 77F42252 8D5424 04 LEA EDX, DWORD PTR SS:[ESP+4] 77F42256 CD 2E INT 2E 77F42258 C3 RETN ================================================================== Т.е. я правильно понимаю , что после этого вызова ядра мы имеем очередь сообщений , а если в нашем процессе нету gdi32.dll , то нет и очереди ? |
|
|
Дата: Сен 7, 2004 16:37:56 bogrus, скорее всего нет! gdi32.dll загружается (отображается) в процесс, который может содержать GUI-потоки и НЕ GUI-потоки, ты же можешь юзать gdi32.dll!TextOutW() в НЕ GUI-потоке, а там очередь сообщений тебе не нужна, например, рисовать в окне Рабочего стола TextOutW() и тогда нет смысла системе из-за этого делать GUI-поток. через прерывание int 2Eh вызываются сервисы ядра. |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.061 |