Эта статья больше похожа на сборник примеров с объяснениями о WinAPI | FASM. Какие окна бывают в Windows.

Окна бывают: Диалоговое окно, немодальное диалоговое окно, обычное (стандартное) окно. (это все которые я знаю)

  • Диалоговое окно не возвращает управление после вызова, она вернет управление после выполнения EndDialog.

  • Немодальное диалоговое окно тоже что и диалоговое окно, но возвращает управление, и нам придется делать цикл обработки сообщений.

  • Обычное (стандартное) окно тоже что и немодальное диалоговое окно, но нужно обрабатывать все сообщения нам самим.

Диалоговое окно

DialogBoxParam - Создание диалогового окна по шаблону из ресурсов. Код дальше не выполняется пока не будет вызвана функция EndDialog.

invoke DialogBoxParamA hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam

hInstance - дескриптор модуля, можно получить из GetModuleHandle.

lpTemplateName - номер шаблона в ресурсах.

hWndParent - hWnd родительского окна, или Null.

lpDialogFunc - адрес на диалоговую процедуру.

dwInitParam - значение передается в lParam (диалоговую процедуру).

DialogBoxIndirectParamA - Создание диалогового окна по шаблону из памяти.

_Диалоговая процедура

Эта процедура должна возвращать False, если она не обрабатывает сообщения. То есть если вы не хотите писать код по обработке стандартных сообщений, то возвращаете False и Windows сделает все за вас.

Пример процедуры:

proc DialogProc hwnddlg, msg, wparam, lparam
  cmp [msg], WM_CLOSE
  jne @f
    invoke EndDialog, [hwnddlg], 0 ; Выход из диалога
  @@:
  xor eax, eax ; return false
  ret
endp

__Ресурсы, шаблоны

section '.rsrc' resource data readable
directory RT_DIALOG, dialogs
  resource dialogs, 1,\ 							; 1 - номер шаблона
  LANG_ENGLISH, form1
  
  dialog form1, 'My Window',\ 				; имя окна
  	100, 100, 100, 50,\ 							; координаты окна\размер окна
  	WS_VISIBLE+WS_CAPTION+WS_SYSMENU 	; стили окна
  
enddialog
Пример диалогового окна
format PE GUI 4.0
entry start
include 'win32a.inc'
section '.code' code readable writeable executable
start:
  invoke GetModuleHandle, 0
  invoke DialogBoxParam, eax, 1, 0, DialogProc, 0
  invoke ExitProcess, 0
  
proc DialogProc hwnddlg, msg, wparam, lparam
  cmp [msg], WM_CLOSE
  jne @f
    invoke EndDialog, [hwnddlg], 0
  @@:
  
  cmp [msg], WM_COMMAND
  jne .if1
    cmp [boolBut], 0
    jne @f
      invoke SetDlgItemText, [hwnddlg], 2, Button_Text1
      inc [boolBut]
      jmp .if1
    @@:
      invoke SetDlgItemText, [hwnddlg], 2, Button_Text2
      dec [boolBut]
  .if1:
  
  xor eax, eax
  ret
endp
; DATA
Button_Text1 db 'Hello world!',0
Button_Text2 db 'Hello!',0
boolBut db 0

section '.idata' import data readable writeable
  library kernel, 'KERNEL32.DLL',\
          user , 'USER32.DLL'
          
  import kernel,\
          GetModuleHandle, 'GetModuleHandleA',\
          ExitProcess, 'ExitProcess'
          
  import user,\
          DialogBoxParam, 'DialogBoxParamA',\
          EndDialog, 'EndDialog',\
          SetDlgItemText, 'SetDlgItemTextA'

section '.rsrc' resource data readable
directory RT_DIALOG, dialogs
  resource dialogs, 1, LANG_ENGLISH, form1
  
  dialog form1, 'My Window1', 100, 100, 100, 50,\
  WS_VISIBLE+WS_CAPTION+WS_SYSMENU
  
    dialogitem 'Button', 'hi', 2,10,15,70,15,WS_VISIBLE
  enddialog

Немодальное диалоговое окно

Все тоже что и в диалоговом окне, но добавлен цикл обработки сообщений.

Пример немодального диалогового окна
format PE GUI 4.0
entry start
include 'win32a.inc'
section '.code' code readable writeable executable
start:
  invoke GetModuleHandle, 0
  invoke CreateDialogParam, eax, 1, 0, DialogProc, 0
  mov [hDialog], eax
  
  StartLoop:
    invoke GetMessage, msg, NULL, 0, 0
    cmp eax, 1
    jb Exit
      invoke IsDialogMessage, [hDialog], msg
  jmp StartLoop
  Exit:
    invoke ExitProcess, 0

proc DialogProc hwnddlg, msg, wparam, lparam
  xor eax, eax
  cmp [msg], WM_CLOSE
  jne @f
    invoke DestroyWindow, [hwnddlg]
    invoke PostQuitMessage, 0
  @@:
  xor eax,eax
ret
endp

msg MSG
hDialog dd 0

section '.idata' import data readable writeable
  library kernel, 'KERNEL32.DLL',\
          user, 'USER32.DLL'
          
  import kernel,\
          GetModuleHandle, 'GetModuleHandleA',\
          ExitProcess, 'ExitProcess'
          
  import user,\
          CreateDialogParam, 'CreateDialogParamA',\
          DestroyWindow, 'DestroyWindow',\
          GetMessage, 'GetMessageA',\
          IsDialogMessage, 'IsDialogMessageA',\
          PostQuitMessage, 'PostQuitMessage'
          
section '.rsrc' resource data readable
directory RT_DIALOG, dialogs
resource dialogs,1,LANG_ENGLISH, form1
  dialog form1, 'New Window', 100, 100, 100, 50,\
  WS_VISIBLE+WS_CAPTION+WS_SYSMENU+DS_CENTER
  
  enddialog

обычное (стандартное) окно

Оно немного отличается от немодального диалогового окна: шаблон не требуется. Используется часто эта функция: CreateWindowExA

Но перед тем нужно зарегистрировать класс: RegisterClassA

Цикл обработки сообщений:

@@:
  invoke GetMessage, msg, [hwnd], 0, 0
  test eax, eax
  jz @f
  invoke TranslateMessage, msg
  invoke DispatchMessage, msg
  jmp @b
@@:
Пример окна
format PE GUI 4.0
entry Start

include 'win32a.inc'

section '.code' code readable writeable executable

proc WinProc, hWnd, msg, wParam, lParam
  cmp [msg], WM_CLOSE
  jne @f
    invoke DestroyWindow, [hWnd]
    jmp .Exit
  @@:
  
  cmp [msg], WM_DESTROY
  jne @f
    invoke ExitProcess,0  
  @@:
  
  .Exit:
    invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam]
ret
endp

Start:
    
    invoke GetModuleHandle, 0
    mov [wnd.hInstance], eax
    
    invoke RegisterClass, wnd
    test eax, eax
    jnz @f
      invoke MessageBox, 0, Error.FailRegisterClass, Error.Text, MB_OK+MB_ICONERROR
      jmp Exit
    @@:
    
    invoke CreateWindowEx, 0, ClassName, WindowName, WS_OVERLAPPEDWINDOW + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, 0, 0, [wnd.hInstance], 0
    test eax, eax
    jnz @f
      invoke MessageBox, 0, Error.FailCreateWindow, Error.Text, MB_OK+MB_ICONERROR
      jmp Exit
    @@:
    
    mov [hwnd], eax
    
    @@:
      invoke GetMessage, msg, [hwnd], 0, 0
      test eax, eax
      jz @f
      invoke TranslateMessage, msg
      invoke DispatchMessage, msg
      jmp @b
    @@:
    
Exit: 
    invoke ExitProcess,0

section '.data' data readable writeable

    ClassName db 'WinClass',0
    WindowName db 'Window Proj',0
    
    hwnd dd 0
    
    msg MSG
    wnd WNDCLASS 0, WinProc, 0, 0, 0, 0, 0, COLOR_WINDOW, 0, ClassName   

    Error:
      .Text db 'Error',0
      .FailRegisterClass db 'RegisterClassA - Fail',0
      .FailCreateWindow db 'CreateWindowExA - Fail',0

section '.idata' import readable writeable

  library kernel, 'kernel32.dll',\
          user, 'user32.dll'
  
  import kernel,\
          ExitProcess, 'ExitProcess',\
          GetModuleHandle, 'GetModuleHandleA'
          
  import user,\
          MessageBox, 'MessageBoxA',\
          RegisterClass, 'RegisterClassA',\
          CreateWindowEx, 'CreateWindowExA',\
          GetMessage, 'GetMessageA',\
          TranslateMessage, 'TranslateMessage',\
          DispatchMessage, 'DispatchMessageA',\
          DestroyWindow, 'DestroyWindow',\
          PostQuitMessage, 'PostQuitMessage',\
          DefWindowProc, 'DefWindowProcA'
Пример окна с кнопкой
format PE GUI 4.0
entry Start

include 'win32ax.inc'

section '.code' code readable writeable executable

proc WinProc, hWnd, msg, wParam, lParam
  cmp [msg], WM_CLOSE
  jne @f
    invoke DestroyWindow, [hWnd]
    jmp .Exit
  @@:
  
  cmp [msg], WM_DESTROY
  jne @f
    invoke ExitProcess,0  
  @@:
  
  cmp [msg], WM_COMMAND
  jne @f
    mov eax, [hwndButton]
    cmp [lParam], eax
    jne @f
      invoke MessageBox, 0, 'Hi', 'Hello', MB_OK  
  @@:
  
  
  .Exit:
    invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam]
ret
endp

Start:
    
    invoke GetModuleHandle, 0
    mov [wnd.hInstance], eax
    
    invoke RegisterClass, wnd
    test eax, eax
    jnz @f
      invoke MessageBox, 0, Error.FailRegisterClass, Error.Text, MB_OK+MB_ICONERROR
      jmp Exit
    @@:
    
    invoke CreateWindowEx, 0, ClassName, WindowName, WS_OVERLAPPEDWINDOW + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, 0, 0, [wnd.hInstance], 0
    test eax, eax
    jnz @f
      invoke MessageBox, 0, Error.FailCreateWindow, Error.Text, MB_OK+MB_ICONERROR
      jmp Exit
    @@:
    mov [hwnd], eax
    
    invoke CreateWindowEx, 0, ClassButton, ButtonName, WS_VISIBLE+WS_CHILD, 10, 10, 50, 30, eax, 0, [wnd.hInstance], 0
    mov [hwndButton], eax
    
    @@:
      invoke GetMessage, msg, [hwnd], 0, 0
      test eax, eax
      jz @f
      invoke TranslateMessage, msg
      invoke DispatchMessage, msg
      jmp @b
    @@:
    
Exit: 
    invoke ExitProcess,0

section '.data' data readable writeable

    ClassName db 'WinClass',0
    WindowName db 'Window Proj',0
    ClassButton db 'BUTTON',0
    ButtonName db 'Hello',0
    
    hwnd dd 0
    hwndButton dd 0
    
    msg MSG
    wnd WNDCLASS 0, WinProc, 0, 0, 0, 0, 0, COLOR_WINDOW, 0, ClassName   

    Error:
      .Text db 'Error',0
      .FailRegisterClass db 'RegisterClassA - Fail',0
      .FailCreateWindow db 'CreateWindowExA - Fail',0

section '.idata' import readable writeable

  library kernel, 'kernel32.dll',\
          user, 'user32.dll'
  
  import kernel,\
          ExitProcess, 'ExitProcess',\
          GetModuleHandle, 'GetModuleHandleA'
          
  import user,\
          MessageBox, 'MessageBoxA',\
          RegisterClass, 'RegisterClassA',\
          CreateWindowEx, 'CreateWindowExA',\
          GetMessage, 'GetMessageA',\
          TranslateMessage, 'TranslateMessage',\
          DispatchMessage, 'DispatchMessageA',\
          DestroyWindow, 'DestroyWindow',\
          PostQuitMessage, 'PostQuitMessage',\
          DefWindowProc, 'DefWindowProcA'

Комментарии (11)


  1. little-brother
    11.09.2021 03:13
    -1

    А в чем сакральный смысл применения двух уже практически неиспользуемых технологий WinAPI и asm в связке?


    1. vilgeforce
      11.09.2021 10:31
      +7

      Как это WinAPI не используемая? Что, все используемые не поверх нее построены?


    1. iiopy4uk_mck
      11.09.2021 16:25

      Вторя уже ответившему, многие десктопные фреймворки можно "хакать" просто влезая с уровня WinApi. Получаешь дескриптор окна, и декорируешь функцию обработчик своей оберткой. Хук так называемый.


      1. little-brother
        11.09.2021 16:36

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

        P.S. Сам разрабатываю небольшой проект на WinAPI и С.


        1. iiopy4uk_mck
          14.09.2021 18:06

          Так декоратор делает, что нужно, а остальное передается на обработку.

          Из примера довольно простого, именно приведенный вами фреймворк, и в нем два тяжеленных контролла. Надо было скролы синхронизировать у 2х из них. Если пользоваться интерфейсом передачи этим контролам колбэка для вызова при скролле, то из-за тяжести внутреннего обработчика этих контролов, пока твой вызывался по эвенту, все выглядело тормознуто. Но хукнув обработчик, просто сначала синхронизировал положения скроллов, а потом уже вызывал обычный обработчик. Бантик, а приятно.

          Конечно подводных в таких вещах хватает, я ни в коем случае не про хорошие практики, но имеют место быть, под час хорошо себя показывают.


  1. insecto
    11.09.2021 07:29
    +8

    Как сразу молодостью повеяло! Общага, виновс икспи, жена ещё не жена, лабы-курсачи, вот это всё, ммм...


  1. COKPOWEHEU
    11.09.2021 11:47
    +1

    А можно пояснить зачем эта статья?
    Я могу понять зачем нужно изучать ассемблер х86 (не для обучения ассемблеру и архитектуре компьютера, разумеется). С дальнейшей специализацией на драйверах, сверхэффективных вычислениях, компиляторах и прочем низком уровне.
    Я могу понять зачем изучать основы winapi (вот тут наоборот — только для освоения низкого уровня). С дальнейшим переходом на современные графические библиотеки вроде хотя бы gtk, а может sdl если нужно просто создать окно.
    Но эти задачи противоположны. На winapi-gui вы не будете писать драйвер или компилятор. На ассемблере вы не будете писать программу с развесистым GUI. Бывают, конечно, любители ненормального программирования вроде разработчиков Колибри, но их мало и для них это хобби.


    1. Int_13h
      11.09.2021 13:18
      -1

      Оконные WinAPI-шные процедуры писать на ассемблере (с синтаксическим сахаром) чуть ли не легче чем на Це. Нет битвы за соответствие типов, калькуляторкомпилятор не ругается на каждый неаккуратный чих. Та же вижуалстудио тянет через библиотеки в простое оконное приложение кучу всякой всячины, типа всех этих Redistributable Packages (ну простое винапи, зачем?) или _security_check_cookie (а я их не просил подключать).


    1. sled
      11.09.2021 16:58

      COKPOWEHEU Уважаемый, пока "профи" и "знатоки" предлагали всем классический подход - прикрутить либы и т.д. на Асме/Си для AVR, самому спаять программатор, нарисовать и собрать схему на рассыпухе, тем временем родился Ардуино для простолюдинов и что Вы можете возразить этому явлению?! Оно есть и кому-то нужно!


      1. COKPOWEHEU
        11.09.2021 18:58
        -1

        У ардуины хотя бы ниша понятна — «контроллеры для домохозяек».
        А тут вроде бы низкий уровень — ассемблер и винапи, то есть о непрофессионалах речь не идет. Отсюда и вопрос: для кого эта статья?


  1. da-nie
    11.09.2021 19:22
    +1

    Вот в этой книжке всё это, помнится, было.

    image