CreateWindowEx() и атомы

Тема в разделе "WASM.BEGINNERS", создана пользователем Virtual8086, 12 ноя 2009.

  1. Virtual8086

    Virtual8086 Дмитрий

    Публикаций:
    0
    Регистрация:
    23 окт 2009
    Сообщения:
    9
    Адрес:
    Беларусь
    Листая в очередной раз MSDN решил попробовать передать CreateWindowEx в качестве параметра lpszClassName не адрес строки с именем класса, а атом, который возвращает RegisterClassEx. Вылетает с Exception'ом в модуле user32.dll по смещению 0x00011e87. Под отладчиком (Win32DAsm) - работает как часы: отображает окно, корректно реагирует на закрытие и т.п.

    Переписал, оставив только самое основное. Проблема осталась, всё абсолютно идентично.

    Исходник на FASM:

    Код (Text):
    1. include 'win32a.inc'
    2.  
    3. format PE GUI 4.0
    4. entry WinMain
    5.  
    6. include 'equates\kernel32.inc'
    7. include 'equates\gdi32.inc'
    8. include 'equates\user32.inc'
    9.  
    10. section '.code' code readable executable
    11.  
    12. proc OnIdle
    13.      ret
    14. endp
    15.  
    16. proc WndProc hWnd, uMsg, wParam, lParam
    17.      cmp     [uMsg], WM_DESTROY
    18.      je      .WMDestroy
    19.      jmp     .Default
    20.  
    21. .WMDestroy:
    22.      invoke  PostQuitMessage, ebx
    23.      jmp     .EndProc
    24. .Default:
    25.      invoke  DefWindowProc, [hWnd], [uMsg], [wParam], [lParam]
    26. .EndProc:
    27.      ret
    28. endp
    29.  
    30. proc WinMain
    31.      xor     ebx, ebx
    32.      invoke  GetModuleHandle, ebx
    33.      mov     [_hInstance], eax
    34.  
    35.      ; Filling WNDCLASSEXA
    36.      mov     [WC.cbSize],         sizeof.WNDCLASSEXA
    37.      mov     [WC.style],          CS_HREDRAW or CS_VREDRAW
    38.      mov     [WC.lpfnWndProc],    WndProc
    39.      mov     [WC.cbClsExtra],     ebx
    40.      mov     [WC.cbWndExtra],     ebx
    41.      mov     eax, [_hInstance]
    42.      mov     [WC.hInstance],      eax
    43.      invoke  LoadIcon, eax, IconName
    44.      mov     [WC.hIcon],          eax
    45.      mov     [WC.hIconSm],        eax
    46.      invoke  LoadCursor, ebx, IDC_ARROW
    47.      mov     [WC.hCursor],        eax
    48.      invoke  GetSysColorBrush, COLOR_BTNFACE
    49.      mov     [WC.hbrBackground],  eax
    50.      mov     [WC.lpszMenuName],   ebx
    51.      mov     [WC.lpszClassName],  ClassName
    52.      invoke  RegisterClassEx, addr WC
    53.      test    eax, eax
    54.      jz      .EndProc
    55.  
    56.      invoke  CreateWindowEx, ebx, eax, WinName, WS_POPUP or WS_MAXIMIZE,\
    57.                              ebx, ebx, ebx, ebx, ebx, ebx, [_hInstance], ebx
    58.      test    eax, eax
    59.      jz      .EndProc
    60.      mov     [hWindow], eax
    61.  
    62.      invoke  ShowWindow, eax, SW_MAXIMIZE
    63.      invoke  UpdateWindow, [hWindow]
    64.  
    65. .MsgLoop:
    66.      invoke  PeekMessage, Msg, ebx, ebx, ebx, PM_REMOVE
    67.      test    eax, eax
    68.      jz      .Idle
    69.      invoke  TranslateMessage, Msg
    70.      invoke  DispatchMessage, Msg
    71. .Idle:
    72.      stdcall OnIdle
    73.      jmp     .MsgLoop
    74.  
    75. .EndProc:
    76.      invoke  ExitProcess, ebx
    77.      ret
    78. endp
    79.  
    80. section '.data' data readable writeable
    81.  
    82. IconName        db              "PROGRAM", 0
    83. ClassName       db              "MYWNDCLS", 0
    84. WinName         db              "MYWINDOW", 0
    85.  
    86. _hInstance      dd              ?
    87. WC              WNDCLASSEXA
    88. hWindow         dd              ?
    89. Msg             MSG
    90.  
    91. section '.idata' import data readable writeable
    92.  
    93. library kernel32, 'kernel32.dll',\
    94.         gdi32,    'gdi32.dll',\
    95.         user32,   'user32.dll'
    96.  
    97. include 'apia\kernel32.inc'
    98. include 'apia\gdi32.inc'
    99. include 'apia\user32.inc'
    Ещё одно наблюдение. Старый-добрый трюк со вставкой пустого MessageBox'а показывает, что программа вываливается на CreateWindowEx(). Т.е. сразу после вызова этой функции MessageBox перестаёт выводиться, а перед ней - выводится. Правда, если перед CreateWindowEx(), то и Exception'а не возникает. Вставляемый вызов MessageBox() такой:

    Код (Text):
    1.      pusha
    2.      invoke  MessageBox, ebx, ebx, ebx, 64
    3.      popa
    Значение, возвращаемое RegisterClassEx() при запуске из-под отладчика, равно 0x0000c34a, CreateWindowEx() там же даёт корректный хэндл (что неудивительно, иначе бы не работало и под отладчиком).

    Появилось подозрение, что всё-таки такой трюк не сработает (т.е. вызов CreateWindowEx(..., RegisterClassEx(...), ...)). Но хочется разобраться в сути происходящего. ОС WinXP SP2.
     
  2. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Virtual8086

    Код (Text):
    1.      invoke  RegisterClassEx, addr WC
    2.      test    eax, eax
    3.      jz      .EndProc
    4.  
    5.      invoke  CreateWindowEx, ebx, eax, WinName, WS_POPUP or WS_MAXIMIZE,\
    6.                              ebx, ebx, ebx, ebx, ebx, ebx, [_hInstance], ebx
    После RegisterClassEx обнулите в eax hi.word (and eax,0000FFFFh),
    и тогда CreateWindowEx примет атом (lo.word) с удовольствием.
     
  3. Virtual8086

    Virtual8086 Дмитрий

    Публикаций:
    0
    Регистрация:
    23 окт 2009
    Сообщения:
    9
    Адрес:
    Беларусь
    Хм, спасибо. Сработало. В описании функций видел упоминание про младшее слово, но W32DAsm показывал корректное значение. Больше отладчику доверять не буду :)
     
  4. not1

    not1 Member

    Публикаций:
    0
    Регистрация:
    6 окт 2009
    Сообщения:
    137
    Код (Text):
    1.   mov     [WC.cbClsExtra],     ebx
    2.      mov     [WC.cbWndExtra],     ebx
    3.      mov     eax, [_hInstance]
    4.      mov     [WC.hInstance],      eax
    5.      invoke  LoadIcon, eax, IconName
    6.      mov     [WC.hIcon],          eax
    7.      mov     [WC.hIconSm],        eax
    Объясните почему он двигает все время из регистра eax,ebx? откуда он знает что там те значения которые должны быть вот например mov [WC.cbClsExtra], ebx стало быть ригистр ebx==NULL
     
  5. Virtual8086

    Virtual8086 Дмитрий

    Публикаций:
    0
    Регистрация:
    23 окт 2009
    Сообщения:
    9
    Адрес:
    Беларусь
    Это трюк, подсмотренный у демосценеров. В самом начале программы ebx ксорится с самим собой. Поскольку API-функции не меняют значения этого регистра, его в дальнейшем можно использовать везде, где надо подставить значение 0. Это сокращает на несколько байт каждую инструкцию, где immediate-значение 0 можно заменить регистром ebx.

    Касательно же eax... В первом случае в предшествующей строке значение eax считывается из заранее подготовленной ячейки [_hInstance], во втором - используется тот факт, что API-функции (и не только они %)) возвращают результат в eax.