Помогите разобраться с работой API-функции MessageBox.

Тема в разделе "WASM.WIN32", создана пользователем Oleg_SK, 6 сен 2004.

  1. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine




    Усё там понятно :) , посмотри исходник по ссылке .





    If this parameter is NULL, no window is associated with the timer and the nIDEvent parameter is ignored.









    Ну вот и обрабатывает мессаги потока , и в "старое" передаёт (можешь spyxx-ом посмотреть) . А на счёт можальности (в чём она выражаеться под дебаггером) надо будет ещё посмотреть .







    Тю ! Так мы ж с тобой не спорим , просто делимся впечатлениями :) Four-F , скорее по ядрам , а тут всё в юзермоде происходит .
     
  2. rsrc

    rsrc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2004
    Сообщения:
    24
    Адрес:
    Russia
    bogrus



    1. Ответ нашел у Рихтера: как только поток обратиться к той или иной GUI-функции (например, для проверки очереди сообщений или создания окна), система автоматом выделит ему ресурсы (THREADINFO, очередь сообщений и т.д.) и вот поэтому твой код работает без окон, но с GetMessage()!



    И потом я имел ввиду оконный обработчик WM_TIMER, а не callback!



    2. А по этому пункту я прав однозначно! %)



    P.S. bogrus, и все же я прав по всем пунктам! Ну, а то что я раньше думал, что если у потока нет окон, то и нет очереди сообщений, то это ни-че-го и к делу не относится :)
     
  3. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Ну с дядькой мне спорить тяжко , а с тобой попробую :)







    Т.е. ты (вы с дядькой ?) хотите сказать , что пока поток не обращаеться
    , то у него нет очереди ?



    Брехня ! А давай сделаем эксперимент - пошлем чужому потоку любое сообщение . Следовательно , если он никуда не обращался к той или иной GUI , то сообщение пропадёт .



    А вот и нет , оно не пропадёт , а будет храниться в его очереди - значит она у него есть (см. аттач) , и заметь - никаких окон .







    У MessageBox'a тот же цикл , что и у диалога . А "старый" это значит свой (тот что сами делаем в своём модуле , например при создании окна "ручками") . Тут ещё надо определиться , что ты хочешь доказать , я не вижу конкретного утверждения .
     
  4. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Вот аттач , в первом была маленькая ошибочка

    [​IMG] 1258456590__Msg.zip
     
  5. rsrc

    rsrc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2004
    Сообщения:
    24
    Адрес:
    Russia
    1. щас буду смотреть и думать.

    2. тоже самое и я говорил, но токо другими словами... :)
     
  6. rsrc

    rsrc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2004
    Сообщения:
    24
    Адрес:
    Russia
    Привожу полностью слова Рихтера:





    И из этого можно сделать вывод – у любого потока есть очередь сообщений, а когда эта очередь сообщений для него создается нам должно быть пох…й :)



    <font size=1>bogrus, я был не прав!</font><!--size-->
     
  7. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine




    Я понял , что дядька имел ввиду . Указатель на THREADINFO лежит в [fs:40] . Теперь простыми экспериментами видно , что для консольной проги он пустой , а для гуёвой заполнен . Т.е. он хотел сказать о Subsystem в PE , если GUI , то загрузчик должен создать THREADINFO .
     
  8. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    [ Oleg_SK: но к сожалению кроме этой статьи я больше ни чего ни где не нашел по этой теме ]



    Есть, по крайней мере, ещё одна супер-статья по SEH - "A Crash Course in Structured Exception Handling" дядьки Питрека. http://www.microsoft.com/msj/0197/Exception/Exception.htm





    [ Oleg_SK: В случае же использования функции MessageBox все летит кувырком, т.к. выполнение потока возобновляется в то время, когда процедура обработчика исключений еще не отработала:dntknw: ]



    В этом случае выполнение потока вообще не прекращается. Тебе просто кажется, что пока 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
     
  9. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Four-F Чесно говоря , я пока ставлю эксперименты только в юзер моде . О ядре я очень мало знаю , не интересуюсь . Наверное из-за сайса , уже три раза его ставил и потом три раза сносил , не могу вытерпеть его интерфейс . Чтобы научиться ним пользоваться , нужно читать мануал , а я не очень люблю :)



    Если THREADINFO о которой говорил Рихтер лежит в [fs:40] , то он заполняеться в момент инициализации gdi32.dll , вот таким кодом (w2ksp4) :
    Код (Text):
    1. ====================GDI32.GdiDllInitialize=======================
    2. 77F4224D    B8 D4100000          MOV     EAX, 10D4
    3. 77F42252    8D5424 04            LEA     EDX, DWORD PTR SS:[ESP+4]
    4. 77F42256    CD 2E                INT     2E
    5. 77F42258    C3                   RETN
    6. ==================================================================


    Т.е. я правильно понимаю , что после этого вызова ядра мы имеем очередь сообщений , а если в нашем процессе нету gdi32.dll , то нет и очереди ?
     
  10. rsrc

    rsrc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2004
    Сообщения:
    24
    Адрес:
    Russia
    bogrus, скорее всего нет!

    gdi32.dll загружается (отображается) в процесс, который может содержать GUI-потоки и НЕ GUI-потоки, ты же можешь юзать gdi32.dll!TextOutW() в НЕ GUI-потоке, а там очередь сообщений тебе не нужна, например, рисовать в окне Рабочего стола TextOutW() и тогда нет смысла системе из-за этого делать GUI-поток.



    через прерывание int 2Eh вызываются сервисы ядра.
     
  11. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    [ <font color="indigo]bogrus:</font><!--color--> <font color="indigo]Т.е. я правильно понимаю, что после этого вызова ядра мы имеем очередь сообщений, а если в нашем процессе нету gdi32.dll, то нет и очереди?</font><!--color--> ]



    Возможно вызов каких то функций из gdi32.dll тоже приводит к конвертации потока в GUI-поток, но в основном это функции user32.dll. Тут надо ставить бряк на изменение поля KTHREAD.ServiceTable и звать функцию, ну или просто после каждого вызова смотреть это поле.
     
  12. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    [ bogrus: <font color="indigo]уже три раза его ставил и потом три раза сносил , не могу вытерпеть его интерфейс</font><!--color--> ]



    Ну да, по-началу жутковато: кругом темно и ничего не понятно :) Потом привыкнешь.
     
  13. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine




    Да , теперь я понял , так и происходит . Я нашёл ещё в user32.dll вызовы ядра , которые так делают . Из юзера видно , что они заполняют [fs:40h] . После CreateThread оно действительно ещё пустое , а после вызова некоторых гди-юзер ф-ций уже заполнено .
     
  14. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Код (Text):
    1. 77F4224D    B8 D4100000          MOV     EAX, 10D4




    Собсна всё несколько проще. Я как-то сразу не сообразил. Индекс 10D4 однозначно говорит о том, что поток будет преобразован в GUI, если он конечно уже не GUI. Индексы в диапазоне 0-0FFFh - это индексы сервисов в ntoskrnl.exe, в диапазоне 1000-1FFFh - индексы сервисов в win32k.sys. При первом же вызове любого сервиса из win32k.sys поток конвертится в GUI. Вот кусок кода обработчика int2E:


    Код (Text):
    1. #define NUMBER_SERVICE_TABLES 4
    2. #define SERVICE_NUMBER_MASK ((1 << 12) -  1)
    3.  
    4. #define SYSTEM_SERVICE_INDEX 0
    5. #define WIN32K_SERVICE_INDEX 1
    6.  
    7. #define SERVICE_TABLE_SHIFT (12 - 4)
    8. #define SERVICE_TABLE_MASK (((1 << 2) - 1) << 4)
    9. #define SERVICE_TABLE_TEST (WIN32K_SERVICE_INDEX << 4)
    10.  
    11. _KiSystemService        proc
    12.  
    13. ;
    14. ; (eax) = Service number
    15. ; (edx) = Callers stack pointer
    16. ; (esi) = Current thread address
    17. ;
    18.  
    19. _KiSystemServiceRepeat:
    20.         mov     edi, eax                  ; copy system service number
    21.         shr     edi, SERVICE_TABLE_SHIFT  ; isolate service table number
    22.         and     edi, SERVICE_TABLE_MASK   ;
    23.         mov     ecx, edi                  ; save service table number
    24.         add     edi, [esi]+ThServiceTable ; compute service descriptor address
    25.         mov     ebx, eax                  ; save system service number
    26.         and     eax, SERVICE_NUMBER_MASK  ; isolate service table offset
    27.  
    28. ;
    29. ; If the specified system service number is not within range, then attempt
    30. ; to convert the thread to a GUI thread and retry the service dispatch.
    31. ;
    32.  
    33.         cmp     eax, [edi]+SdLimit        ; check if valid service
    34.         jae     Kss_ErrorHandler          ; if ae, try to convert to GUI thread
    35.  
    36. . . .
    37.  
    38. ;
    39. ; The specified system service number is not within range. Attempt to
    40. ; convert the thread to a GUI thread if the specified system service is
    41. ; not a base service and the thread has not already been converted to a
    42. ; GUI thread.
    43. ;
    44.  
    45. Kss_ErrorHandler:
    46.         cmp     ecx, SERVICE_TABLE_TEST ; test if GUI service
    47.         jne     short Kss_LimitError    ; if ne, not GUI service
    48.         push    edx                     ; save argument registers
    49.         push    ebx                     ;
    50.         stdcall _PsConvertToGuiThread   ; attempt to convert to GUI thread
     
  15. Oleg_SK

    Oleg_SK Guest

    Публикаций:
    0
    [Four-F: Запусти тот же notepad и выбери там любой диалог из меню.]

    Да, действительно, в приведенном тобой примере функция MessageBox работает вполне логично (во время своей работы, позволяет окну владельцу перерисовываться и т.д., т.е. обрабатывать свои сообщения). С другой стороны, когда она начинает вести себя так в процессе работы процедуры обработки исключений, то, IMHO, это поведение уже нельзя назвать логичным, потому что нет смысла пытаться обрабатывать оконные сообщения в условиях когда весьма вероятно повторное исключения (которое, кстати, может произойти и при обработке сообщения WM_PAINT). Мне кажется, что гораздо логичнее было бы, если бы в этом случае выполнение кода в проблемном потоке блокировалось (пусть даже в ущерб интерфейсу пользователя). Ладно, это все лирика.



    Приношу огромную благодарность всем участникам! По сути, вопрос исчерпан.
     
  16. Oleg_SK

    Oleg_SK Guest

    Публикаций:
    0
    Хочу, до кучи, добавить еще третий возможный способ решения этой проблемы (БОГ троицу любит:)):

    3. В процедуре обработчика можно создать отдельный поток и уже в нем вызвать MessageBox. В этом случае, сразу после создания этого потока можно явно усыпить проблемный поток одной из ожидающих функций (например: WaitForSingleObject) до окончания новоиспеченного потока, который завершится сразу после отработки MessageBox.
     
  17. Edmond

    Edmond узник замка IF THEN ELSE

    Публикаций:
    0
    Регистрация:
    2 сен 2002
    Сообщения:
    203
    Адрес:
    WASM.RU
    Oleg_SK

    Твой перевод у меня на стадии завершения правки.

    Ты где? :)
     
  18. Oleg_SK

    Oleg_SK Guest

    Публикаций:
    0
    Edmond

    Сегодня и ближайшие несколько дней я буду здесь появляться.

    З.Ы.: Извени за задержку с ответом.