Код (ASM): include win64a.inc HINST_COMMCTRL equ -1 ID_MENU equ 600 ID_EXIT equ 15 ID_ABOUT equ 16 STD_CUT equ 0 STD_COPY equ 1 STD_PASTE equ 2 STD_UNDO equ 3 STD_REDOW equ 4 STD_DELETE equ 5 STD_FILENEW equ 6 STD_FILEOPEN equ 7 STD_FILESAVE equ 8 STD_PRINTPRE equ 9 STD_PROPERTIES equ 10 STD_HELP equ 11 STD_FIND equ 12 STD_REPLACE equ 13 STD_PRINT equ 14 TB_AUTOSIZE equ WM_USER + 33 TB_ADDBUTTONS equ WM_USER + 20 TB_ADDBITMAP equ WM_USER + 19 TBADDBITMAP STRUCT hInst QWORD ? nID QWORD ? TBADDBITMAP ENDS .code WinMain proc local msg:MSG xor ebx,ebx mov esi,IMAGE_BASE mov edi,offset wTitle mov eax,10027h ; registering the window class | push rax ;hIconSm push rdi ;lpszClassName push ID_MENU ;lpszMenuName push COLOR_BTNFACE+1;hbrBackground push 10005h ;hCursor push rax ;hIcon push rsi ;hInstance push rbx ;cbClsExtra & cbWndExtra db 68h dd WndProc ;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ; creating the main window push rbx push rsi shl esi,9 push rbx push rbx push rsi push rsi push rsi push rsi sub rsp,20h invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE lea edi,msg ; entering the message loop message_loop: invoke GetMessage,edi,0,0,0 invoke DispatchMessage,edi jmp message_loop WinMain endp ; the window procedure WndProc proc hwnd:qword,uMsg:qword,wParam:qword,lParam:qword local caW:qword local caH:qword local Rct:RECT local tbb:TBBUTTON local Tba:TBADDBITMAP local Paint:PAINTSTRUCT mov hwnd,rcx mov wParam,r8 mov lParam,r9 cmp edx,WM_CREATE je wmCREATE cmp edx,WM_DESTROY je wmDESTROY cmp edx,WM_SIZE je wmSIZE cmp edx,WM_PAINT je wmPAINT cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND jne default1 wmCOMMAND: mov rdi,wParam cmp edi,14 ja @f invoke SendMessage,hStatus,SB_SETTEXT,0,[handler+rdi*8] invoke MessageBox,hwnd,[handler+rdi*8],&aYou,MB_OK jmp default1 @@: cmp edi,15 jnz @f invoke SendMessage,hwnd,WM_SYSCOMMAND,SC_CLOSE,0 jmp default1 @@: invoke MessageBox,hwnd,&aAssembler,&wTitle,MB_OK jmp default1 wmDESTROY: invoke ExitProcess,0;завершение программы wmCLOSE: invoke MessageBox,hwnd,&aPlease,&wTitle,MB_YESNO cmp eax,IDNO; 7 jnz wmDESTROY end_wm_check: leave xor eax,eax retn wmPAINT:lea edx,Paint invoke BeginPaint invoke Paint_Proc,rax,hwnd lea edx,Paint invoke EndPaint,hwnd ;Освобождаем контекст отображения jmp end_wm_check wmCREATE:lea edi,tbb mov tbb.iBitmap,ebx;0 mov tbb.idCommand,ebx;0 mov tbb.fsState,bl;0 mov tbb.fsStyle,bl;0 mov tbb.dwData,ebx;0 mov tbb.iString,ebx;0 mov word ptr tbb.fsState,TBSTATE_ENABLED + 256*TBSTYLE_SEP;or WS_CLIPSIBLINGS invoke CreateToolbarEx,,WS_CHILD or WS_VISIBLE,\ 300,1,ebx,ebx,edi,1,10h,10h,ebx,ebx,sizeof(TBBUTTON) mov hToolBar,rax or Tba.hInst,HINST_COMMCTRL; 0FFFFFFFFh mov Tba.nID,1; btnsize 1=big 2=small invoke SendMessage,rax,TB_ADDBITMAP,1,&Tba mov tbb.fsStyle,bl;TBSTYLE_BUTTON=0 or tbb.idCommand,-1 or ebx,15 @@: mov rax,[handler1+rbx*8-8] mov tbb.iBitmap,eax inc tbb.idCommand invoke SendMessage,hToolBar,TB_ADDBUTTONS,1,edi dec ebx jnz @b ; Create the status bar invoke CreateStatusWindow,WS_CHILD or WS_VISIBLE or SBS_SIZEGRIP,\ ebx,hwnd,200 mov hStatus,rax jmp default1 wmSIZE: invoke SendMessage,hToolBar,TB_AUTOSIZE,0,0 mov rax,caW mov dword ptr lParam,eax mov caH,rax mov eax,dword ptr lParam+2 lea edx,Rct invoke GetWindowRect,hStatus mov eax,Rct.bottom sub eax,Rct.top sub caH,rax invoke MoveWindow,hStatus,ebx,caH,caW,caH,TRUE ;все сообщения, не обрабатываемые в функции ;WndProc, направляются на обработку по умолчанию default1: leave jmp DefWindowProc WndProc endp Paint_Proc proc hWin:QWORD, hDC:QWORD local Rct:RECT local caW:dword local caH:dword local tbH:dword local sbH:dword mov hWin,rcx mov hDC,rdx lea edi,Rct invoke GetClientRect,hWin,edi mov eax,Rct.right mov caW,eax mov eax,Rct.bottom mov caH,eax invoke GetWindowRect,hToolBar,edi mov eax,Rct.bottom sub eax,Rct.top mov tbH,eax invoke GetWindowRect,hStatus,edi mov eax,Rct.bottom sub eax,Rct.top mov sbH,eax sub caH,eax mov Rct.left,0 mov eax,tbH mov Rct.top,eax mov eax,caW mov Rct.right,eax mov eax,caH mov Rct.bottom,eax invoke DrawEdge,hDC,edi,EDGE_SUNKEN,BF_RECT leave retn Paint_Proc endp aPlease db "Please Confirm Exit",0 aNewFile db 'New File',0 aOpenFile db 'Open File',0 aSaveFile db 'Save File',0 aRedow db 'Redow',0 aDelete db 'Delete',0 aCut db 'Cut',0 aCopy db 'Copy',0 aPaste db 'Paste',0 aUndo db 'Undo',0 aSearch db 'Search',0 aReplace db 'Replace',0 aPrint db 'Print',0 aPreview db 'Previw',0 aProperties db 'Properties',0 aHelp db 'Help',0 aAbout db "О программе",0 aAssembler db "Assembler, Pure & Simple",0 aYou db "You have selected",0 handler dq aNewFile,aOpenFile,aSaveFile,aRedow dq aDelete,aCut,aCopy,aPaste,aUndo dq aSearch,aReplace,aPrint,aPreview dq aProperties,aHelp handler1 dq STD_HELP,STD_PROPERTIES,STD_PRINTPRE,STD_PRINT,STD_REPLACE,STD_FIND dq STD_UNDO,STD_PASTE,STD_COPY,STD_CUT,STD_DELETE,STD_REDOW,STD_FILESAVE dq STD_FILEOPEN,STD_FILENEW wTitle db 'Iczelion Tutorial #8k: инструментальная панель в MASM64',0 hStatus dq ? hToolBar dq ? end © Mikl___ 2021Глава двадцать шестая. Братец Кролик подключает стандартные диалоги к инструментальной панели Теория ― мать склерозаПодключаем к инструментальной панели модальные диалоги «Открыть файл», «Сохранить как...», «Выбор параметров страницы», «Печать» и немодальные диалоги «Поиск» и «Замена». Диалоговые окошки поиска и замены текстаФункции FindText и ReplaceText используют структуру типа FINDREPLACE. Так как окна диалога являются немодальными, поэтому в случае их вывода на экран придется изменять главный цикл обработки сообщений, чтобы вызвать функцию IsDialogMessage. Структура FINDREPLACE передаваемая функциям FindText и ReplaceText должна быть задана как статическая переменная, а так как окна диалога являются немодальными, то функции должны заканчивать свою работу уже после того, как окна диалога выведены на экран, а не после того как они будут закрыты. И несмотря на это, необходимо продолжать обеспечивать возможность доступа к структуре из процедуры окна диалога. До тех пор пока ока диалога остаются на экране функции FindText и ReplaceText взаимодействуют с окном владельцем посредством специального сообщения. Номер этого сообщения может быть получен с помощью вызова функции RegisterWindowMessage с параметром FINDMSGSTRING. Это делается при обработке сообщения WM_CREATE, полученный номер сохраняется в статической переменной hSearch. При обработке очередного сообщения, номер сообщения сравнивается со значением в hSearch. Параметр lParam такого сообщения ― это указатель на структуру FINDREPLACE поле Flags которого показывает, использовал ли пользователь окно для поиска/замены или пользователь закрыл окно. Чтобы использовать диалоги «Поиск» или «Замена» необходимо проделать следующие операции: Получить идентификатор для зарегистрированного сообщения FINDMSGSTRING Отобразить диалоговое окошко Обработать сообщение FINDMSGSTRING когда диалог откроется При инициализации приложения регистрируем и получаем идентификатор сообщения FINDMSGSTRING при помощи функции RegisterWindowMessage в дескриптор hSearch. Перед отображением диалога «Поиска/Замены текста» заполняем структуру FINDREPLACE, а затем вызываем функцию FindText или ReplaceText. Структура FINDREPLACE и буфер для строки поиска объявлены глобально, чтобы они не вышли за пределы видимости, до того, как диалоговое окошко будет закрыто. Для указания, какое окно будет получать зарегистрированные сообщения, необходимо присвоить его дескриптор переменной hwndOwner. Чтобы диалоговое окно «Поиск/Замена текста» обрабатывало сообщения от клавиатуры ― в главный цикл сообщений включен вызов функции IsDialogMessage, которой в качестве параметра передается дескриптор диалога hSearch. Практика ― сестра шизофрении
Код (ASM): include win64a.inc HINST_COMMCTRL equ -1 ID_MENU equ 600 ID_EXIT equ 6 ID_ABOUT equ 7 TB_AUTOSIZE equ WM_USER + 33 TB_ADDBUTTONS equ WM_USER + 20 TB_ADDBITMAP equ WM_USER + 19 TBADDBITMAP STRUCT hInst QWORD ? nID QWORD ? TBADDBITMAP ENDS PAGESETUPDLG STRUCT ;(sizeof=0x78, align=0x8, standard type) lStructSize DWORD ?,? hwndOwner QWORD ? hDevMode QWORD ? hDevNames QWORD ? Flags DWORD ? ptPaperSize POINT <> rtMinMargin RECT <> rtMargin RECT <> DWORD ? hInstance QWORD ? lCustData DWORD ?,? lpfnPageSetupHook QWORD ? lpfnPagePaintHook QWORD ? lpPageSetupTemplateName QWORD ? hPageSetupTemplate QWORD ? PAGESETUPDLG ENDS PRINTDLG STRUCT lStructSize DWORD ?,? hwndOwner QWORD ? hDevMode QWORD ? hDevNames QWORD ? hDC QWORD ? Flags DWORD ? nFromPage WORD ? nToPage WORD ? nMinPage WORD ? nMaxPage WORD ? nCopies WORD ?,? hInstance QWORD ? lCustData QWORD ? lpfnPrintHook QWORD ? lpfnSetupHook QWORD ? lpPrintTemplateName QWORD ? lpSetupTemplateName QWORD ? hPrintTemplate QWORD ? hSetupTemplate QWORD ? PRINTDLG ENDS FINDREPLACE STRUCT lStructSize DWORD ?,? hwndOwner QWORD ? hInstance QWORD ? Flags DWORD ?,? lpstrFindWhat QWORD ? lpstrReplaceWith QWORD ? wFindWhatLen WORD ? wReplaceWithLen WORD ? lCustData DWORD ? lpfnHook QWORD ? lpTemplateName QWORD ?,? FINDREPLACE ENDS .code WinMain proc local msg:MSG xor ebx,ebx mov esi,IMAGE_BASE mov edi,offset wTitle mov eax,10027h ;------------------------------+ ; registering the window class | ;------------------------------+ push rax ;hIconSm push rdi ;lpszClassName push ID_MENU ;lpszMenuName push COLOR_BTNFACE+1;hbrBackground push 10005h ;hCursor push rax ;hIcon push rsi ;hInstance push rbx ;cbClsExtra & cbWndExtra pushaddr WndProc;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;--------------------------+ ; creating the main window | ;--------------------------+ push rbx push rsi shl esi,9 push rbx push rbx push rsi push rsi push rsi push rsi sub rsp,20h invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE ;---------------------------+ ; entering the message loop | ;---------------------------+ lea edi,msg @@: invoke GetMessage,edi,0,0,0 invoke IsDialogMessage,hSearch,edi or eax,eax jnz @b invoke DispatchMessage,edi jmp @b WinMain endp ;----------------------+ ; the window procedure | ;----------------------+ WndProc proc hwnd:qword,uMsg:qword,wParam:qword,lParam:qword local caW:qword local caH:qword local Rct:RECT local tbb:TBBUTTON local Tba:TBADDBITMAP local Paint:PAINTSTRUCT local ofn:OPENFILENAME local tbH:dword;<-- align 8 for FINDREPLACE, PRINTDLG, PAGESETUPDLG local fr:FINDREPLACE local pd:PRINTDLG local psd:PAGESETUPDLG local sbH:dword local hDC:qword mov hwnd,rcx mov wParam,r8 mov lParam,r9 xor ebx,ebx cmp edx,WM_CREATE je wmCREATE cmp edx,WM_DESTROY je wmDESTROY cmp edx,WM_SIZE je wmSIZE cmp edx,WM_PAINT je wmPAINT cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND jne default wmCOMMAND: mov rdi,wParam invoke SendMessage,hStatus,SB_SETTEXT,0,[handlers+rdi*8] xor eax,eax jmp [handler+rdi*8] wmCLOSE::mov edx,offset aPlease mov r8d,offset wTitle invoke MessageBox,,,,MB_YESNO cmp eax,IDNO jz end_wm_check wmDESTROY:: invoke ExitProcess,0;завершение программы wmPAINT:lea edx,Paint invoke BeginPaint mov hDC,rax lea edi,Rct invoke GetClientRect,hwnd,edi mov eax,Rct.right mov caW,rax mov eax,Rct.bottom mov caH,rax invoke GetWindowRect,hToolBar,edi mov eax,Rct.bottom sub eax,Rct.top mov tbH,eax invoke GetWindowRect,hStatus,edi mov eax,Rct.bottom sub eax,Rct.top mov sbH,eax sub caH,rax mov Rct.left,ebx;0 mov eax,tbH mov Rct.top,eax mov rax,caW mov Rct.right,eax mov rax,caH mov Rct.bottom,eax invoke DrawEdge,hDC,edi,EDGE_SUNKEN,BF_RECT lea edx,Paint invoke EndPaint,hwnd;Освобождаем контекст отображения end_wm_check: leave xor eax,eax retn wmCREATE:lea edi,tbb mov tbb.iBitmap,ebx;0 mov tbb.idCommand,ebx;0 mov tbb.fsState,bl;0 mov tbb.fsStyle,bl;0 mov tbb.dwData,ebx;0 mov tbb.iString,ebx mov word ptr tbb.fsState,TBSTATE_ENABLED + 256*TBSTYLE_SEP;or WS_CLIPSIBLINGS invoke CreateToolbarEx,,WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS,\ 300,1,ebx,ebx,edi,1,10h,10h,ebx,ebx,sizeof(TBBUTTON) mov hToolBar,rax or Tba.hInst,HINST_COMMCTRL; 0FFFFFFFFh mov Tba.nID,1; btnsize 1=big 2=small invoke SendMessage,rax,TB_ADDBITMAP,1,&Tba mov tbb.fsStyle,bl;TBSTYLE_BUTTON=0 or tbb.idCommand,-1 or ebx,6 @@: mov rax,handler1[rbx*8-8] mov tbb.iBitmap,eax inc tbb.idCommand invoke SendMessage,hToolBar,TB_ADDBUTTONS,1,edi dec ebx jnz @b ; Create the status bar invoke CreateStatusWindow,WS_CHILD or WS_VISIBLE or SBS_SIZEGRIP,\ 0,hwnd,200 mov hStatus,rax mov ecx,offset FINDMSGSTRING invoke RegisterWindowMessage mov hSearch,rax jmp default wmSIZE: invoke SendMessage,hToolBar,TB_AUTOSIZE,0,0 mov rax,caW mov dword ptr lParam,eax mov caH,rax mov eax,dword ptr lParam+2 lea edx,Rct invoke GetWindowRect,hStatus mov eax,Rct.bottom sub eax,Rct.top sub caH,rax invoke MoveWindow,hStatus,0,caH,caW,caH,TRUE jmp default SaveFile:: _OpenFile::push rdi mov ecx,(sizeof OPENFILENAME)/8 lea edi,ofn rep stosq;обнулили структуру OPENFILENAME pop rdi ;заполняем "ненулевые" поля OPENFILENAME mov ofn.lStructSize,size OPENFILENAME mov rax,hwnd mov ofn.hwndOwner,rax mov eax,OFFSET szFile mov ofn.lpstrFile,rax mov ofn.nMaxFile,SIZEOF szFile mov eax,OFFSET strFilter mov ofn.lpstrFilter,rax mov ofn.nFilterIndex,1 mov ofn.Flags,OFN_PATHMUSTEXIST lea ecx,ofn or edi,edi; rdi = ID open_file ? jnz @f invoke GetOpenFileName jmp default @@: invoke GetSaveFileName jmp default Replace:: Search::push rdi mov ecx,(sizeof FINDREPLACE)/8 lea edi,fr rep stosq;обнулили структуру FINDREPLACE pop rdi ;заполняем "ненулевые" поля FINDREPLACE mov fr.lStructSize,SIZEOF fr mov rax,hwnd mov fr.hwndOwner,rax mov eax,OFFSET szFindWhat mov fr.lpstrFindWhat,rax mov fr.wFindWhatLen,80 lea ecx,fr cmp edi,5; edi = ID Replace ? jnz @f mov eax,OFFSET szReplaceWith mov fr.lpstrReplaceWith,rax mov fr.wReplaceWithLen,80 mov fr.Flags,FR_WHOLEWORD invoke ReplaceText xor eax,eax jmp default @@: mov fr.Flags,FR_DOWN or FR_WHOLEWORD invoke FindText xor eax,eax jmp default Properties::lea edi,psd mov ecx,sizeof(PAGESETUPDLG)/8 rep stosq;обнулили структуру PAGESETUPDLG ;заполняем "ненулевые" поля PAGESETUPDLG mov psd.lStructSize,sizeof(PAGESETUPDLG) mov rax,hwnd mov psd.hwndOwner,rax lea ecx,psd invoke PageSetupDlg jmp default Print:: mov ecx,(sizeof PRINTDLG)/8 lea edi,pd rep stosq ;обнулили структуру PRINTDLG ;заполняем "ненулевые" поля PRINTDLG mov pd.lStructSize,sizeof PRINTDLG mov rax,hwnd mov pd.hwndOwner,rax mov pd.Flags,PD_ALLPAGES mov pd.nCopies,1 mov pd.nFromPage,1 mov pd.nToPage,1 mov pd.nMinPage,1 mov pd.nMaxPage,2 lea ecx,pd invoke PrintDlg jmp default About:: invoke ShellAbout,hwnd,&wTitle,&aAssembler,10027h ;все сообщения, не обрабатываемые в функции ;WndProc, направляются на обработку по умолчанию default:leave jmp DefWindowProc WndProc endp ;-------------------------------------------- aPlease db "Please Confirm Exit",0 aReplace db 'Replace',0 aOpenFile db 'Open File',0 aSaveFile db 'Save File',0 aSearch db 'Search',0 aProperties db 'Properties',0 aPrint db 'Print',0 aAbout db 'О программе',0 aAssembler db "Assembler, Pure & Simple",0 aYou db "You have selected",0 handlers dq aOpenFile,aSaveFile,aPrint,aProperties dq aSearch,aReplace,0,aAbout handler dq _OpenFile,SaveFile,Print,Properties dq Search,Replace,wmDESTROY,About szFile db "*.*",256 dup (0) strFilter db "All Files",0 handler1 dq STD_REPLACE,STD_FIND,STD_PROPERTIES dq STD_PRINT,STD_FILESAVE,STD_FILEOPEN wTitle db 'Iczelion Tutorial #8l: инструментальная панель в MASM64',0 hStatus dq ? hToolBar dq ? szFindWhat db "Masm is",73 dup (0) szReplaceWith db "Great !",73 dup (0) hSearch dq ? FINDMSGSTRING db "commdlg_FindReplace",0 end © Mikl___ 2016
Глава двадцать седьмая. Пример использования диалога «Открыть файл» Предопределенные диалоговые окна находятся в comdlg32.dll. Эти диалоговые окна создаются вызовом соответствующих функций. Для диалога «Открыть файл» существует функция GetOpenFileName, для сохранения ― GetSaveFileName, функция вызывающая диалог для работы с принтером ― PrintDlg и так далее. Каждая из этих функций в качестве параметра получает указатель на соответствующую структуру. В этой главе демонстрируется инициализация и использование диалога «Открыть файл». Прототип функции GetOpenFileName. Код (C): BOOL WINAPI GetOpenFileName( _Inout_ LPOPENFILENAME lpofn ); Функция в качестве единственного параметра получает указатель на структуру OPENFILENAME. Если функция вернула TRUE значит пользователь выбрал файл, если функция вернула FALSE значит пользователь нажал на «Отменить» или закрыл диалог. Рассмотрим структуру OPENFILENAME: Код (ASM): OPENFILENAME STRUC lStructSize DWORD ?,? hwndOwner QWORD ? hInstance QWORD ? lpstrFilter QWORD ? lpstrCustomFilter QWORD ? nMaxCustFilter DWORD ? nFilterIndex DWORD ? lpstrFile QWORD ? nMaxFile DWORD ?,? lpstrFileTitle QWORD ? nMaxFileTitle DWORD ?,? lpstrInitialDir QWORD ? lpstrTitle QWORD ? Flags DWORD ? nFileOffset WORD ? nFileExtension WORD ? lpstrDefExt QWORD ? lCustData DWORD ?,? lpfnHook QWORD ? lpTemplateName QWORD ? OPENFILENAME ENDS Значения часто используемых параметров. lStructSizeразмер структуры OPENFILENAME в байтах.hwndOwnerдескриптор файлового диалогового окна.hInstanceдескриптор процесса, который создает файловое диалоговое окно.lрstrFilterСтрока-фильтр состоит из парных строк, разделенных null'ом. Первая строка в каждой паре ― это описание. Вторая строка ― это шаблон фильтра. Например: FilterString db "All Files (*.*)",0, "*.*",0 db "Text Files (*.txt)",0,"*.txt",0,0 Отметьте, что шаблон во второй строке каждой пары действительно используется для фильтрации файлов. Также отметьте, что вам нужно добавить дополнительный 0 в конце фильтровых строк, чтобы указать конец. Определите, какая пара фильтровых строк будет использоваться при первом отображении файлового диалогового окна. Индекс основывается на единице, то есть первая пара ― 1, вторая ― 2 и так далее. Поэтому в вышеприведенном экземпляре, если мы укажем nFilterIndex как 2, будет использован второй шаблон ― "*.txt".lpstrFileУказатель на буфер, который содержит имя файла, используемого для инициализации edit control'а имени файла на диалоговом окне. Буфер должен быть длиной по крайней мере 260 байтов. После того, как пользователь выберет файл для открытия, имя файла с полным путем будет сохранено в этом буфере. Вы можете извлечь информацию из него позже.nMaxFileразмер буфера.lpstrTitleУказатель на заголовок открытого файлового диалогового окна.FlagsОпределите стили и характеристики диалогового окна.nFileOffsetПосле того, как пользователь выбрал файл для открытия, этот параметр содержит индекс первого символа собственно названия файла. Например, если полное имя с путем "c:\windows\system\lz32.dll", то этот параметр будет содержать значение 18.nFileExtensionПосле того, как пользователь выберет файл для открытия, этот параметр содержит индекс первого символа расширения файла.Практика ― сестра шизофренииСкачайте пример здесь. Нижеприведенная программа отображает диалог «Открыть файл», когда пользователь выбирает пункт «File»→«Open» в меню. Когда пользователь выберет файл в диалоговом окне, программа отобразит сообщение, содержащее полное имя, имя файла и расширение выбранного файла. Код (ASM): include win64a.inc IMAGE_BASE equ 400000h ZZZ_OPEN equ 0 ZZZ_EXIT equ 1 MAXSIZE equ 256 OUTPUTSIZE equ 512 IDR_MAINMENU equ 30 .code WinMain proc local msg:MSG xor ebx,ebx mov edi,offset ClassName mov esi,IMAGE_BASE mov eax,10029h push rax ;hIconSm push rdi ;lpszClassName push IDR_MAINMENU;lpszMenuName push COLOR_WINDOW;hbrBackground push 10005h ;hCursor push rax ;hIcon push rsi ;hInstance push rbx ;cbClsExtra & cbWndExtra db 68h dd WndProc;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX push rbx push rsi ;rsi=400000h shl esi,9 ;rsi=CW_USEDEFAULT push rbx push rbx push rsi push rsi push rsi push rsi mov r9d,WS_OVERLAPPEDWINDOW or WS_VISIBLE sub esp,20h invoke CreateWindowEx,WS_EX_CLIENTEDGE,edi,edi lea edi,msg @@:invoke GetMessage,edi,0,0,0 invoke DispatchMessage,edi jmp @b WinMain endp WndProc proc hWnd:HWND, uMsg, wParam, lParam local dlgOpenBuffer [MAXSIZE]:BYTE strMsgSize equ 512 local strMsg [strMsgSize]:BYTE mov esi,offset dlgOpenOfn mov hWnd,rcx cmp edx,WM_DESTROY je wmDESTROY cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_CREATE je wmCREATE leave jmp DefWindowProc wmDESTROY:invoke DestroyWindow invoke ExitProcess,0 wmCOMMAND:cmp r8d,ZZZ_OPEN jnz wmDESTROY invoke GetOpenFileName,esi;offset dlgOpenOfn.lStructSize or eax,eax jz wmBYE mov ecx,OUTPUTSIZE lea rdi,strMsg mov esi,offset FullPathName call StringOut1 mov rsi,dlgOpenOfn.lpstrFile call StringOut1 mov esi,offset FullName call StringOut1 movzx rsi,dlgOpenOfn.nFileOffset add rsi,dlgOpenOfn.lpstrFile call StringOut1 mov esi,offset ExtensionName call StringOut1 movzx rsi,dlgOpenOfn.nFileExtension add rsi,dlgOpenOfn.lpstrFile call StringOut1 mov [rdi],bl mov r8d,offset ClassName lea edx,strMsg invoke MessageBox,hWnd,,,MB_OK jmp wmBYE wmCREATE:lea eax,dlgOpenBuffer mov [rsi+OPENFILENAME.lpstrFile],rax wmBYE: leave retn WndProc endp StringOut1 proc @@: movsb cmp [rsi],bl loopnz @b retn StringOut1 endp ;--------------------------------------- ClassName db 'Win64 Iczelion''s lesson #11: More about Dialog Box',0 dlgOpenTitle db 'Open File',0 dlgOpenOfn OPENFILENAME <<sizeof OPENFILENAME>,,IMAGE_BASE,\ FilterString,,,,,MAXSIZE> FilterString db 'All Files (*.*)',0,'*.*',0 db 'Text Files (*.txt)',0,'*.txt',0,0 FullPathName db 'The Full Filename with Path is : ',0 FullName db 10,'The Filename is : ',0 ExtensionName db 10,'The Extension is : ',0 end
Разбор полётовПоля структуры dlgOpenOfn уже заполнены. Код (ASM): dlgOpenTitle db 'Open File',0 dlgOpenOfn OPENFILENAME <<sizeof OPENFILENAME>,,IMAGE_BASE,\ FilterString,,,,,MAXSIZE> FilterString ― это фильтр имен файлов, который мы определяем следующим образом. Код (ASM): FilterString db "All Files",0,"*.*",0 db "Text Files",0,"*.txt",0,0 Заметьте, что каждая строка заканчивается нулем. Первая строка ― это описание следующей строки. В качестве фильтра мы можем определить все, что захотим. После последнего фильтра нужно добавить дополнительный ноль , чтобы указать конец. Мы указываем, куда диалоговое окно поместит имена файлов, выбранные пользователем. Мы должны указать размер буфера в nMaxFile. Затем извлечем имя файла из этого буфера. Флаги определяющие характеристики окна. OFN_FILEMUSTEXIST и OFN_PATHMUSTEXIST ― указывают то, что имя файла и путь, который пользователь набирает в edit control'е имени файла, должен существовать. OFN_LONGNAMES ― указывает диалоговому окну показывать длинные имена. OFN_EXPLORER ― указывает на то, что появление диалогового окна должно быть похоже на explorer. OFN_HIDEREADONLY ― прячет неизменяемый checkbox на диалоговом окне. Есть много других флагов, которые вы можете использовать. Код (ASM): invoke GetOpenFileName,esi;offset dlgOpenOfn or eax,eax jz wmBYE В качестве параметра функции GetOpenFileName передается указатель на структуру OPENFILENAME. После этого диалог "открыть файл" появляется на экране. Функция возвратит TRUE, если пользователь выбрал файл, если пользователь нажмет кнопку 'Cancel' или закрыл окно диалога в этом случае функция вернет FALSE. В случае, если пользователь выбирает файл, мы подготавливаем строку вывода, которая будет отображаться в окне сообщения. Код (ASM): mov ecx,OUTPUTSIZE lea rdi,strMsg mov esi,offset FullPathName call StringOut1 mov rsi,dlgOpenOfn.lpstrFile call StringOut1 mov esi,offset FullName call StringOut1 movzx rsi,dlgOpenOfn.nFileOffset add rsi,dlgOpenOfn.lpstrFile call StringOut1 mov esi,offset ExtensionName call StringOut1 movzx rsi,dlgOpenOfn.nFileExtension add rsi,dlgOpenOfn.lpstrFile call StringOut1 mov [rdi],bl; завершающий ноль в строке Немного пояснений. dlgOpenOfn.nFileOffset содержит индекс в dlgOpenOfn.lpstrFile. Hо вы не можете непосредственно сложить их, так размерности этих переменных разные (размер dlgOpenOfn.lpstrFile ― QWORD, размер dlgOpenOfn.nFileOffset и dlgOpenOfn.nFileExtension ― WORD) поэтому сперва используем movzx, а потом add. Код (ASM): mov r8d,offset ClassName lea edx,strMsg invoke MessageBox,hWnd,,,MB_OK Мы отображаем строку в окне сообщения. © Mikl___ 2021Глава двадцать восьмая. Братец Кролик выводит картинки на экран (часть первая) В этой главе мы научимся использовать рисунки в своих программах. Если быть более точным, мы научимся отображать рисунок в клиентскую область нашей программы. Скачайте пример и рисунок.
Теория ― мать склерозаНа компьютерах используется множество различных форматов изображений, но Windows естественным образом поддерживает только формат растровых изображений Windows (bmp). На этом уроке, когда речь будет идти о рисунках, будет подразумеваться именно этот формат. Самый простой способ использовать рисунок ― это использовать его как ресурс. Есть три способа это выполнить. Можно включить рисунок в файл определения ресурсов (.rc) следующим образом: Код (C): #define IDB_MYBITMAP 100 IDB_MYBITMAP BITMAP "c:\\project\\example.bmp" В этом методе для представления рисунка используется константа. В первой строчке просто задаётся константа с именем IDB_MYBITMAP и значением 100. По этому имени мы и будем обращаться к рисунку в нашей программе. В следующей строке объявляется ресурс-рисунок. Таким образом, компилятор узнаёт, где ему искать собственно сам bmp-файл. В другом методе для представления рисунка используется имя рисунка, делается это следующим образом: Код (C): MyBitMap BITMAP "c:\\project\\example.bmp" При использовании этого метода, в вашей программе вам придётся ссылаться на рисунок по имени "MyBitMap". Это имя является идентификатором данного ресурса. Оба метода прекрасно работают, главное ― определиться, какой именно вы будете использовать. После включения рисунка в файл ресурсов, можно приступить к его отображению в клиентской области нашего окна: Для загрузки растрового изображения используется функция LoadBitmap Синтаксис: Код (C): HBITMAP LoadBitmap( _In_ HINSTANCE hInstance, // дескриптор вашей программы _In_ LPCTSTR lpBitmapName /* указатель на строку, содержащую имя рисунка (необходимо при использовании 2-го метода). Если для обращения к рисунку вы используете константу (например, IDB_MYBITMAP), то её значение вы и должны сюда поместить (в нашем случае это было бы значение 100). */ ); Функция возвращает дескриптор рисунка. Не помешает небольшой пример:Первый метод: Код (ASM): IDB_MYBITMAP equ 100 ............ invoke LoadBitmap,IMAGE_BASE,IDB_MYBITMAP Второй метод: Код (ASM): .data BitmapName db "MyBitMap",0 ............. mov edx,offset BitmapName invoke LoadBitmap,IMAGE_BASE Третий метод:Если вы ассоциировали с вашим рисунком число 125, то можно загрузить его следующим образом Код (ASM): .data BitmapName db "#125",0 ............. invoke LoadBitmap,IMAGE_BASE,125 Получить контекст устройствa (DC ― Device Context) для окна, в котором будет выводиться растровое изображение. Это можно сделать либо вызовом функции BeginPaint в ответ на сообщение WM_PAINT, либо вызовом GetDC в любое время. Получить эквивалентный контекст устройствa для памяти (memory DC), в которой будет храниться растровое изображение (растровое изображение хранится в памяти и оттуда копируется в окно) с теми же атрибутами, что и контекст устройствa, полученный на предыдущем шаге. Идея в том, чтобы создать некоторую "невидимую" поверхность, на которой мы можем отобразить рисунок. Выбрать растровое изображение в контексте устройства памяти. Скопировать растровое изображение из памяти в окно вывода, из контекста устройства памяти в контекст устройствa окна с помощью вызова одной-единственной функции. Это приведет к появлению растрового изображения на экране. Этот приём называется двойной буферизацией (double buffering) и используется для быстрого вывода изображений на экран. Создать "невидимую" поверхность можно вызовом CreateCompatibleDC: Код (C): HDC CreateCompatibleDC( _In_ HDC hdc //контекст устройствa, с которым должен быть совместим DC в памяти ); Функция возвращает дескриптор области памяти, совместимой с контекстом устройства окна, который задается в параметре hdc. Эта память будет использоваться для создания изображения перед выводом его на экран. После создания невидимой поверхности вы можете отобразить на ней рисунок с помощью вызова SelectObject, передав ей в качестве первого параметра дескриптор DC в памяти, а в качестве второго ― дескриптор рисунка.Синтаксис: Код (C): HGDIOBJ SelectObject( _In_ HDC hdc, _In_ HGDIOBJ hgdiobj ); Теперь рисунок отображен на контекст устройствa в памяти. Единственное, что осталось сделать ― это скопировать его на на устройство вывода, то есть на настоящий контекст устройствa. Этого можно добиться с помощью таких функций, как BitBlt и StretchBlt. BitBlt просто копирует содержимое одного DC в другой, поэтому она работает быстро; StretchBlt может сжимать или растягивать изображение по размерам того DC, куда копирует. Для простоты здесь мы будем использовать BitBlt.Синтаксис: Код (C): BOOL BitBlt( _In_ HDC hdcDest, //контекст устройствa вывода _In_ int nXDest, //координаты верхнего левого угла прямоугольника, в который _In_ int nYDest, //будет выводится растровое изображение _In_ int nWidth, //ширина и высота выводимого растрового изображения _In_ int nHeight, _In_ HDC hdcSrc, //дескриптор исходного контекста устройства _In_ int nXSrc, //координаты левого верхнего угла растрового изображения _In_ int nYSrc, _In_ DWORD dwRop // способ вывода растрового изображения на экран ); После завершения работы с рисунком удалите его с помощью вызова DeleteObject. Вот и всё! Если коротко, то сначала добавьте рисунок в файл ресурсов. После этого загрузите его из ресурсов с помощью LoadBitmap. Вы получите дескриптор рисунка. Далее узнайте контекст устройствa, на которое собираетесь выводить изображение. Затем создайте контекст устройствa в памяти, совместимый с DC, на который вы хотите выводить. "Выберите" рисунок на DC в памяти (то есть отрисуйте его), затем скопируйте его содержимое в настоящий DC.Практика ― сестра шизофрении Код (ASM): ; GUI # include win64a.inc IMAGE_BASE equ 400000h IDB_MYBITMAP equ 100 .code WinMain proc local msg:MSG xor ebx,ebx invoke LoadCursorFromFile,&FileName push rax ;hIconSm mov edi,offset ClassName push rdi ;lpszClassName push rbx ;lpszMenuName push COLOR_WINDOW;hbrBackground push rax ;hCursor push rax ;hIcon mov esi,IMAGE_BASE push rsi ;hInstance push rbx ;cbClsExtra & cbWndExtra pushaddr WndProc ;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX push rbx push rsi ;rsi=400000h shr esi,7;Special CreateWindow position value CW_USEDEFAULT=8000h push rbx push rbx push 418 push 562 push rsi push rsi sub esp,20h invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE lea edi,msg @@: invoke GetMessage,edi,0,0,0 invoke DispatchMessage,edi jmp @b WinMain endp WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM LOCAL ps:PAINTSTRUCT LOCAL hMemDC:HDC LOCAL rect:RECT mov hWnd,rcx cmp edx,WM_DESTROY je wmDESTROY cmp edx,WM_CREATE je wmCREATE cmp edx,WM_PAINT je wmPAINT leave jmp NtdllDefWindowProc_ wmDESTROY:invoke DeleteObject,hBitmap invoke RtlExitUserProcess,NULL wmCREATE:invoke LoadBitmap,IMAGE_BASE,IDB_MYBITMAP mov hBitmap,rax jmp wmBYE wmPAINT:invoke BeginPaint,,&ps invoke CreateCompatibleDC,rax mov hMemDC,rax invoke SelectObject,rax,hBitmap invoke GetClientRect,hWnd,&rect invoke BitBlt,ps.hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY invoke DeleteDC,hMemDC invoke EndPaint,hWnd,&ps wmBYE: leave retn WndProc endp ;--------------------------------------- ClassName db 'Uncle Remus tales:#25 Picture on screen',0 hBitmap dq ? FileName db "br_Rabbit3.cur",0 end Файл ресурсов Код (C): #define IDB_MYBITMAP 100 IDB_MYBITMAP BITMAP "47.bmp" Скачайте пример Анализ:Собственно, на этом уроке и анализировать нечего Код (C): #define IDB_MYBITMAP 100 IDB_MYBITMAP BITMAP "47.bmp" Определите константу IDB_MYBITMAP, присвоив ей значение 100. Затем используйте эту константу при определении ресурса рисунка. Файл, который будет включен в ресурсы, называется "47.bmр" и располагается в той же папке. Код (ASM): wmCREATE:invoke LoadBitmap,IMAGE_BASE,IDB_MYBITMAP mov hBitmap,rax После получения сообщения WM_CREATE мы вызываем LoadBitmaр для загрузки рисунка из файла ресурсов, передаем идентификатор рисунка в качестве второго параметра. По завершению работы функции получим дескриптор рисунка. Теперь, когда рисунок загружен, его можно отобразить в клиентской области нашего приложения. Код (ASM): wmPAINT:invoke BeginPaint,,&ps invoke CreateCompatibleDC,rax mov hMemDC,rax invoke SelectObject,rax,hBitmap invoke GetClientRect,hWnd,&rect invoke BitBlt,ps.hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY invoke DeleteDC,hMemDC invoke EndPaint,hWnd,&ps
Мы выводим рисунок в ответ на сообщение WM_PAINT. Для этого мы сначала вызываем BeginPaint и получаем дескриптор DC. Затем создаем совместимый memory DC вызовом CreateComрatibleDC. Далее "выбираем" рисунок в память с помощью SelectObject. Определяем размеры клиентской области окна через GetClientRect. Теперь можно наконец-то вывести изображение в клиентскую область, вызвав функцию BitBlt, которая скопирует рисунок из памяти в настоящий DC. По завершению рисования мы удаляем DC в памяти вызовом DeleteDC, так как он нам больше не нужен. Подаём сигнал о завершении отрисовки окна с помощью EndPaint. Код (Text): wmDESTROY:invoke DeleteObject,hBitmap invoke ExitProcess,0 По окончанию работы удаляем рисунок посредством DeleteObject.Рисуем самиСкачайте файл примера здесь.Теория ― мать склерозаИтак, мы хотим вывести рисунок на окно, но как это сделать проще, не используя множество API-функций: BeginPaint и EndPaint, CreateCompatibleDC и DeleteDC, GetClientRect, BitBlt, SelectObject и DeleteObject... Открываем книгу отечественных классиков, исследователей недр MSDN, братьев Александра Вячеслововича и Григория Вячеслововича Фроловых «Graphic Device Interface»Создание кистиЕсли нам понадобилось окрасить наше окно, то мы в WNDCLASSEX в поле hbrBackground указываем одну из 28 констант COLOR_SCROLLBAR000000COLOR_BACKGROUND COLOR_DESKTOP100001COLOR_ACTIVECAPTION200010COLOR_INACTIVECAPTION300011COLOR_MENU400100COLOR_WINDOW500101COLOR_WINDOWFRAME600110COLOR_MENUTEXT700111COLOR_WINDOWTEXT801000COLOR_CAPTIONTEXT901001COLOR_ACTIVEBORDER1001010COLOR_INACTIVEBORDER1101011COLOR_APPWORKSPACE1201100COLOR_HIGHLIGHT1301101COLOR_HIGHLIGHTTEXT1401110COLOR_BTNFACE COLOR_3DFACE1501111COLOR_BTNSHADOW COLOR_3DSHADOW1610000COLOR_GRAYTEXT1710001COLOR_BTNTEXT1810010COLOR_INACTIVECAPTIONTEXT1910011COLOR_BTNHIGHLIGHT COLOR_3DHIGHLIGHT COLOR_3DHILIGHT COLOR_BTNHILIGHT2010100COLOR_3DDKSHADOW2110101COLOR_3DLIGHT2210110COLOR_INFOTEXT2310111COLOR_INFOBK2411000―2511001COLOR_HOTLIGHT2611010COLOR_GRADIENTACTIVECAPTION2711011COLOR_GRADIENTINACTIVECAPTION2811100Цвет соответствующего компонента можно изменить, если щелкнуть по пустой области экрана правой клавишей, выбрать раздел «Свойства» [math]\to[/math] «Оформление» и выбрать цветовую схему соответствующему элементу. Цвет кисти можно задать функцией GetStockBrush из нескольких типов системных кистей, которые можно использовать: Код (ASM): WHITE_BRUSH equ 0;белый цвет заполнения LTGRAY_BRUSH equ 1;светло-серый GRAY_BRUSH equ 2;серый DKGRAY_BRUSH equ 3;темно-серый BLACK_BRUSH equ 4;черный NULL_BRUSH equ 5;прозрачная кисть HOLLOW_BRUSH equ NULL_BRUSH Если предопределенный цвет вам не подходит, то с помощью функции CreateSolidBrush можно создать цветную кисть: Код (C): BOOL CreateSolidBrush( COLORREF crColor ); В качестве параметра для этой функции необходимо указать цвет кисти. Для выбора цвета можно воспользоваться 32-битовым целым типа COLORREF. Windows позволяет задать цвет тремя различными способами. Первый и наиболее общий заключается в задании RGB-значений (Red, Green, Blue). RGB-значение комбинирует относительные интенсивности трех различных цветов, в результате чего получается реальный цвет. старшиймладшийБайты3210СодержимоеДолжен быть равен нулюИнтенсивность синегоИнтенсивность зеленогоИнтенсивность красногоинтенсивность каждого цвета в RGB-значении может задаваться в диапазоне от 0 до 0FFh(255), причем значение 0 определяет минимальную, а значение 0FFh ― максимальную интенсивность задаваемого цвета. Например, вот так задаются основные цвета значениецвет 00FFFFFFh белый000000FFhкрасный000080FFhоранжевый0000FFFFhжелтый0000FF00hзеленый00D0D000hголубой00FF0000hсиний00FF00FFhфиолетовый000070A0hкоричневый______00000000hчерный Второй способ определения цвета предполагает задание индекса цвета в логической палитре. Третий заключается в определении RGB-значения относительно текущей логической палитры. Windows может выбрать для кисти чистые или смешанные цвета, в зависимости от текущего цветового разрешения. После использования созданной кисти ее следует удалить, не забыв перед этим выбрать в контекст отображения старую кисть. Для удаления кисти используют функцию DeleteObject: Код (C): BOOL DeleteObject( _In_ HGDIOBJ hObject ); Можно заштриховать внутреннюю область замкнутой фигуры, создав одну из двадцати шести штриховых кистей при помощи функции CreateHatchBrush: Код (C): BOOL CreateHatchBrush( int iHatch, COLORREF color ); Параметр color определяет цвет линий штриховки, а параметр iHatch задает стиль штриховки: Стиль штриховкичислоВнешний видdecbinHS_HORIZONTAL000000HS_VERTICAL100001HS_FDIAGONAL200010HS_BDIAGONAL300011HS_CROSS400100HS_DIAGCROSS500101HS_FDIAGONAL1600110Заполнено цветом определенном в параметре colorHS_BDIAGONAL1700111HS_SOLID801000Заполнено черным цветомHS_DENSE1901001HS_DENSE21001010HS_DENSE31101011HS_DENSE41201100HS_DENSE51301101HS_DENSE61401110HS_DENSE71501111HS_DENSE81610000HS_NOSHADE1710001HS_HALFTONE1810010HS_SOLIDCLR1910011HS_DITHEREDCLR2010100HS_SOLIDTEXTCLR2110101HS_DITHEREDTEXTCLR2210110HS_SOLIDBKCLR2310111HS_DITHEREDBKCLR2411000HS_API_MAX2511001А вот самое главное, ради чего мы полезли в недра GDI ― «можно использовать свой собственный стиль штриховки, создав кисть из битового изображения размером 8х8 пикселей (можно использовать только такой размер)...» Если битовое изображение кисти определено в ресурсах приложения, его следует загрузить при помощи функции LoadBitmap, а если из файла ― то при помощи LoadImage. Эти функции возвратят идентификатор битового изображения. Затем для создания кисти этот идентификатор следует передать в качестве параметра функции CreatePatternBrush: Код (C): HBRUSH CreatePatternBrush( _In_ HBITMAP hbmp ); А что если братья Фроловы ошибаются и размер рисунка не ограничен 8 на 8 точек? Загружаем изображение из файла при помощи LoadImage, передаем идентификатор функции CreatePatternBrush, создаем кисть и, с ее помощью, закрашиваем окно. И всё! Не нужно никаких BeginPaint и EndPaint, CreateCompatibleDC и DeleteDC, GetClientRect, BitBlt, SelectObject и DeleteObject... Никакой обработки WM_PAINT, ни каких дескрипторов и ни каких контекстов изображения. Код (ASM): ; GUI # include win64a.inc .code WinMain proc local msg:MSG xor ebx,ebx mov esi,IMAGE_BASE mov edi,offset ClassName invoke LoadImage,esi,edi,0,0,0,LR_LOADFROMFILE invoke CreatePatternBrush,eax push 10027h ;hIconSm push rdi ;lpszClassName push rbx ;lpszMenuName push rax ;hbrBackground push 10003h ;hCursor push 10027h ;hIcon push rsi ;hInstance push rbx ;cbClsExtra & cbWndExtra pushaddr WndProc ;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX push rbx push rsi ;rsi=400000h shl esi,9 ;rsi=CW_USEDEFAULT push rbx push rbx push 405 push 520 push rsi push rsi sub esp,20h invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPED or \ WS_VISIBLE or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX lea edi,msg @@: invoke GetMessage,edi,0,0,0 invoke DispatchMessage,edi jmp @b WinMain endp WndProc:cmp edx,WM_DESTROY je wmDESTROY jmp DefWindowProc wmDESTROY:invoke ExitProcess,NULL ;--------------------------------------- ClassName db 'Images\12.bmp',0 end © Mikl___ 2017
Глава двадцать девятая. Братец Кролик создает дочерние окна В этой главе мы изучим дочерние элементы управления (child window controls), которые являются важными частями ввода и вывода для наших программ. Скачайте пример здесь.Теория ― мать склерозаWindows предоставляет несколько предопределенных классов окон, которые можно использовать в программах. Как правило, их используют как компоненты окон-диалогов, поэтому они носят название дочерних элементов управления. Эти элементы обрабатывают сообщения от клавиатуры и мыши и уведомляют родительское окно, если их состояние изменяется. В этой главе элементы управления размещены на обычном окне, только для того, чтобы продемонстрировать, как их можно создать и использовать, но в реальности вам лучше размещать элементы управления при создании окна-диалога. Примерами предопределенных классов окон являются кнопки, списки (list box), контрольные переключатели (сheck box), селекторные кнопки (radio button) и так далее. Чтобы использовать дочернее окно, вы должны создать его с помощью функции CreateWindow или CreateWindowEx. Вы не должны регистрировать классы окон дочерних элементов управления, так как они уже зарегистрированы в Windows. Имя класса окна должно быть именем предопределенного класса. Если вы хотите создать кнопку, вы должны указать «button» в качестве имени класса в CreateWindowsEx. Другие параметры, которые вы должны указать ― это дескриптор родительского окна и ID элемента управления. ID элемента управления должно быть уникальным. Вы используете его для того, чтобы отличать данный элемент управления от других. После того, как элемент управления создан, он посылает сообщение, уведомляющие родительское окно об изменении своего состояния. Обычно дочерние окна создаются после того, когда главному окну отправлено сообщения WM_CREATE Дочернее окно посылает сообщение WM_COMMAND родительскому окну со своим ID в младшем слове wParam'а, код уведомления в старшем слове wParam'а, а ее дескриптор в lParam'е. Каждое окно имеет разные коды уведомления, сверяйтесь со справочником по Win32 API, чтобы получить более подробную информацию. Родительское окно также может посылать команды дочерним окнам, вызывая функцию SendMessage. Функция SendMessage посылает определенные сообщения с сопутствующими значениями в wParam и lParam окну, чей дескриптор передается функции. Эта функция посылает сообщения любому окну, дескриптор которого у вас есть. После создания дочерних окон, родительское окно должно обрабатывать сообщения WM_COMMAND, чтобы быть способным получать коды уведомления от дочерних окон. Практика ― сестра шизофрении Мы создадим окно, которое содержит окно ввода (edit box), картинку 128×128 и две кнопки. Когда вы нажмете на кнопку «Say Hello», в окне редактирования появится текст «Wow! I'm in an edit box now», при нажатии на кнопку «Exit» программа завершится. В окно ввода можно ввести любой текст. Также имеется меню «Text Controls» с 4 пунктами: «Say Hello» ― ввести текстовую строку в окно ввода «Get Text» ― вывести с текст из окна ввода в MessageBox «Clear Edit Box» ― очистить содержимое окна ввода «Exit» ― закрыть программу asm-файл Код (ASM): ; GUI # include win64a.inc IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_ICON1 equ 500 ICON_SIZE equ 744 IDC_IMG equ 1001 ;----------------------------------------- .code WinMain proc local msg:MSG xor ebx,ebx mov esi,IMAGE_BASE invoke LoadCursorFromFile,&FileName mov edi,offset ClassName push rax ;hIconSm push rdi ;lpszClassName pushaddr MenuName ;lpszMenuName push COLOR_BTNFACE+1;hbrBackground push rax ;hCursor push rax ;hIcon push rsi ;hInstance push rbx ;cbClsExtra & cbWndExtra pushaddr WndProc ;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX push rbx push rsi ;rsi=400000h shl esi,9 ;rsi=CW_USEDEFAULT push rbx push rbx push 175 push 450 push rsi push rsi sub esp,20h invoke CreateWindowEx,WS_EX_CLIENTEDGE,edi,edi,\ WS_OVERLAPPEDWINDOW or WS_VISIBLE lea edi,msg @@:invoke GetMessage,edi,0,0,0 invoke TranslateMessage,edi invoke DispatchMessage,edi jmp @b WinMain endp WndProc proc hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local ps:PAINTSTRUCT local buffer[96]:BYTE mov hWnd,rcx mov lParam,r9 mov wParam,r8 cmp edx,WM_DESTROY je wmDESTROY cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_CREATE je wmCREATE leave jmp NtdllDefWindowProc_ wmCREATE:;создаем поле ввода push rbx push IMAGE_BASE push ebx;IDC_EDIT=0 push rcx push 26 push 190 push 35 push 130 sub esp,20h invoke CreateWindowEx,WS_EX_CLIENTEDGE,&EditClassName,0,\ WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL mov hwndEdit,rax invoke SetFocus,eax ;создаем кнопку push rbx push IMAGE_BASE push IDC_BUTTON push hWnd push 26 push 104 push 20 push 320 sub esp,20h invoke CreateWindowEx,0,&ButtonClassName,&ButtonText1,\ WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON ;создаем кнопку push rbx push IMAGE_BASE push IDC_EXIT push hWnd push 26 push 104 push 52 push 320 sub esp,20h invoke CreateWindowEx,0,&ButtonClassName,&ButtonText2,\ WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON ;----------------------------------------------- invoke LoadImage,IMAGE_BASE,&FileBmp,IMAGE_BITMAP,0,0,LR_LOADFROMFILE mov image,rax push rbx push IMAGE_BASE push IDC_IMG push hWnd push 101 push 128 push rbx;0 push rbx;0 sub esp,20h invoke CreateWindowEx,0,&StaticClassName,0,\ WS_CHILD or WS_VISIBLE or SS_CENTERIMAGE or SS_BITMAP invoke SendMessage,rax,STM_SETIMAGE,IMAGE_BITMAP,image jmp wmBYE wmCOMMAND:movzx eax,r8w;word ptr wParam or r9,r9;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8] @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov edx,offset TestString jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE wmDESTROY:invoke RtlExitUserProcess,NULL;завершение программы @0: invoke SetWindowText,hwndEdit invoke SendMessage,hwndEdit,WM_KEYDOWN,VK_END,0 jmp wmBYE CLEAR: invoke SetWindowText,hwndEdit,0 jmp wmBYE GETTEXT:invoke GetWindowText,hwndEdit,&buffer,92 lea rdx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect wmBYE: leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmDESTROY WndProc endp ;--------------------------------------- ClassName db 'Uncle Remus tales:#9 Create a button and editing window',0 MenuName db "FirstMenu",0 ButtonClassName db "button",0 ButtonText1 db "Say Hello",0 ButtonText2 db "Exit",0 EditClassName db "edit",0 StaticClassName db "static",0 TestString db "Wow! I'm in an edit box now",0 hwndEdit dq ? FileName db "br_Rabbit3.cur",0 FileBmp db "03.bmp",0 mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq MenuName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId image dq ? end rc-файл Код (C): #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_ICON1 500 IDC_ICON1 ICON "br_Fox1.ico" FirstMenu MENU { POPUP "&Test Controls" { MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text", IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT } } Для создания элементов управления мы вызываем CreateWindowEx с дополнительным стилем, из-за чего клиентская область выглядит «вдавленной». Имя каждого элемента управления предопределено ― «edit» для элемента управления «окно ввода», «button» ― для кнопки и так далее. Затем мы указываем стили дочерних окон. У каждого элемента управления есть дополнительные стили, кроме обычных стилей окна. Например, стили кнопок начинаются с «BS_» (Buttom Style), стили окон ввода ― с «ES_» (Edit Style). Посмотрите информацию об этих стилях в справочнике по Win32 API. Заметьте, что вместо дескриптора меню передается ID элемента управления. Это не вызывает никаких противоречий, поскольку дочерний элемент управления не может иметь меню. После создания каждого элемента управления, мы сохраняем его дескриптор в соответствующей переменной для будущего использования. Функция SetFocus вызывается для того, чтобы направить фокус на окно ввода, чтобы пользователь мог сразу начать вводить в него текст. Код (ASM): wmCOMMAND: movzx eax,r8w;word ptr wParam or r9,r9;cmp lParam,0 jnz @f
Обратите внимание, что меню тоже шлет сообщение WM_COMMAND, чтобы уведомить окно о своем состоянии. Как мы можем провести различие между сообщениями WM_COMMAND, исходящими от меню и элементов управления? lParamwParamстаршее двойное словомладшее двойное словостаршее двойное словомладшее двойное словобиты63-3231-063-3231-1615-0Меню00―0ID менюЭлемент управления―Дескриптор дочернего окна―Код уведомленияID элемента управленияИз таблицы видно, что пользователь должен проверять lParam. Если он равен нулю, текущее сообщение WM_COMMAND было послано меню. Вы не можете использовать wParam, чтобы различать меню и элемент управления, так как ID меню и ID элемента управления могут быть идентичными. Код (ASM): SAYHELLO: invoke SetWindowText,hwndEdit,&TestString invoke SendMessage,hwndEdit,WM_KEYDOWN,VK_END,0 Вы можете поместить текстовую строку в окно редактирования с помощью вызова SetWindowText. Вы очищаете содержимое окна редактирования с помощью вызова функции SetWindowText, передавая ей NULL. SetWindowText ― это функция общего назначения. Вы можете использовать ее, чтобы изменить заголовок окна или текст на кнопке. Чтобы получить текст в окне редактирования, вы можете использовать GetWindowText. Код (ASM): GETTEXT:invoke GetWindowText,hwndEdit,&buffer,92 lea rdx,buffer mov mb.lpszText,rdx invoke MessageBoxIndirect,&mb Приведенный выше фрагмент программы является фрагментом обработкой нажатия на кнопку. Сначала проверяем содержимое младшего слова wParam'а, чтобы убедиться, что ID элемента управления принадлежит кнопке. Если это так, проверяем старшее слово wParam'а, чтобы убедиться, что был послан код уведомления BN_CLICKED, то есть кнопка была нажата. После этого идет собственно обработка нажатия на клавиш. Мы хотим получить текст из окна редактирования и отобразить его с помощью вызова MessageBoxIndirect. Мы можем продублировать код в секции IDM_GETTEXT выше, но это не имеет смысла. Если мы сможем каким-либо образом послать сообщение WM_COMMAND с младшим словом wParam, содержащим значение IDM_GETTEXT нашей процедуре окна, то избежим дублирования кода и упростим программу. Функция SendMessage ― это ответ. Эта функция посылает любое сообщение любому окну с любым wParam'ом и lParam'ом, которые нам понадобятся. Поэтому вместо дублирования кода мы вызываем SendMessage с дескриптором родительского окна, WM_COMMAND, IDM_GETTEXT и 0. Это дает тот же эффект, что и выбор пункта меню "Get Text". Процедура окна не почувствует никакой разницы. Вы должны использовать эту технику так часто, насколько возможно, чтобы сделать ваш код более упорядоченным. Не забудьте вставить функцию TranslateMessage в очередь сообщений. Так как вам нужно печатать текст в окно редактирования, ваша программа должна транслировать ввод в читабельный текст. Если вы пропустите эту функцию, вы не сможете напечатать что-либо в вашем окне редактирования. © Mikl___ 2019
Глава тридцатая. Братец Кролик и диалогиТЕОРИЯ ― МАТЬ СКЛЕРОЗАЕсли вы изучили примеры в предыдущих главах достаточно подробно, вы заметили, что вы не могли перемещать фокус ввода от одного дочернего окна на другое, используя кнопку Tab. Вы могли сделать это только кликнув на нужном контроле, чтобы перевести на него фокус. Это довольно неудобно. Также вы могли заметить, что изменился цвет родительского окна на серый. Это было сделано для того, чтобы цвет дочерних окон не контрастировал с клиентской областью родительского окна. Есть путь, чтобы обойти эту проблему, но он не очень прост. Вы должны сабклассить все дочерние элементы управления в вашем родительском окне. Причина того, почему возникают подобные неудобства состоят в том, что дочерние окна изначально проектировались для работы с диалоговым окном, а не с обычным. Цвет дочернего окна по умолчанию серый, так как это обычный цвет диалогового окна. Прежде чем мы углубимся в детали, мы должны сначала узнать, что такое диалоговое окно. Диалоговое окно ― это не что иное, как обычное окно, которое спроектировано для работы с дочерними элементами управления. Windows также предоставляет внутренний «менеджер диалоговых окон», который воплощает большую часть диалоговой логики, такую как перемещение фокуса ввода, когда юзеp нажимает Tab, нажатие кнопки по умолчанию, если нажатие на кнопку 'Enter, и так далее, так чтобы программисты могли заниматься более высокоуровневыми задачами. Поскольку диалоговое окно можно считать «черным ящиком» (это означает то, что вы не обязаны знать, как работает диалоговое окно, для того, чтобы использовать его), вы должно только знать, как с ним взаимодействовать. Это принцип объектно-ориентированного программирования, называемого скрытием информации. Если черный ящик спроектирован совершенно, пользователь может использовать его не зная, как он работает. Правда, загвоздка в том, что черный ящик должен быть совершенным, это труднодостижимо в реальном мире. Win32 API также спроектирован как черный ящик. Диалоговые окна спроектированы так, чтобы снизить нагрузку на программиста. Обычно, если вы помещает дочерний элемент управления на обычное окно, вы должны сабклассить их и самостоятельно обрабатывать нажатия на клавиши. Hо если вы помещаете их на диалоговое окно, оно обработает их за вас. Вы только должны как получать информацию, вводимую пользователем, или как посылать команды окну. Диалоговое окно определяется как ресурс (похожим образом, как и меню). Вы пишете шаблон диалогового окна, описывая характеристики диалогового окна и его элементов управления, а затем компилируете его с помощью редактора ресурсов. Обратите внимание, что все ресурсы располагаются в одном скрипте ресурсов. Вы можете использовать любой текстовый редактор, чтобы написать шаблон диалогового окна, но я бы не рекомендовал это. Вы должны использовать редактор ресурсов, чтобы сделать визуально расположить дочерние окна. Существует несколько прекрасных редакторов ресурсов. К большинству из основных компиляторов прилагаются подобные редакторы. Вы можете использовать их, чтобы создать скрипт ресурса. После этого стоит вырезать лишние строки, например, те, которые относятся к MFC. Есть два основных вида диалоговых окон: модальные и немодальные. В большинстве случаев используются модальные диалоги. Это означает, что программа дожидается завершения диалога и только затем ее выполнение будет продолжаться. Модальный диалог не позволяет также переключить ввод на другие окна нашего приложения. Немодальные диалоговые окна дают вам возможность перемещать фокус ввода на другие окна. Пример ― диалоговое окно 'Find' в MS Word. Немодальный диалог не задерживает выполнение приложения, то есть для ее продолжения не требуется завершение диалога. При этом разрешается переключение между диалогом и другим окном приложения. Есть два подтипа модальных диалоговых окон: модальные к приложению модальные к системе Первые не дают вам переключаться на другое окно того же приложения, но вы можете переключиться на другое приложение. Вторые не дают вам возможности переключиться на любое другое окно. Немодальное диалоговое окно создается с помощью вызова функции CreateDialogParam. Модальное диалоговое окно создается вызовом DialogBoxParam. Единственное различие между диалоговым окном, модальным отношению к приложению, и диалоговым окном, модальным по отношению к системе, ― это стиль DS_SYSMODAL. Если вы включите стиль DS_SYSMODAL в шаблон диалогового окна, это диалоговое окно будет модальным к системе. Вы можете взаимодействовать с любым дочерним элементом управления на диалоговом окне с помощью функции SendDlgItemMessage. Ее синтаксис следующий: Код (C): LRESULT WINAPI SendDlgItemMessage( _In_ HWND hDlg, _In_ int nIDDlgItem, _In_ UINT Msg, _In_ WPARAM wParam, _In_ LPARAM lParam ); Эта API-функция неоценимо полезна при взаимодействии с дочерним окном. Например, если вы хотите получить текст из окна редактирования, вы можете сделать следующее: Код (ASM): invoke SendDlgItemMessage,hDlg, ID_EDITBOX,WM_GETTEXT,256,ADDR text_buffer Чтобы знать, какое сообщение когда посылать, вы должны проконсультироваться с вашим Win32 API-справочником. Windows также предоставляет несколько специальных API-функций, заточенных под дочерние окна, для быстрого получения и установки нужных данных, например, GetDlgItemText, CheckDlgButton и так далее. Эти специальные функции создание, чтобы программисту не приходилось выяснять каждый раз значения wParam и lParam. Как правило, вы должны использовать данные функции, если хотите, чтобы управление кодом было легче. Используйте SendDlgItemMessage только, если нет соответствующей API-функции. Все события внутри диалога передаются программе посредством механизма сообщений, как это делается в "оконных" приложениях. Но сообщения диалога не передаются в функцию главного окна программы. Для создаваемого диалога необходимо определить специальную callback-функцию, которая называется функцией диалога или оконной функцией диалога, которая имеет следующий формат: Код (C): BOOL CALLBACK DlgProc ( hDlg:HWND, iMsg:UINT, wParam:WPARAM, lParam:LPARAM ); Процедура диалогового окна очень похожа на процедуру окна, если не считать тип возвращаемого значения ― TRUE/FALSE, вместо обычных LRESULT. Внутренний менеджер диалоговых окон внутри Windows ― истинная процедура для диалоговых окон. Она вызывает нашу процедуру диалоговых окон, передавая некоторые из полученных сообщений. Поэтому главное правило следующее: если наша процедура диалогового окна обрабатывает сообщение, она должна вернуть TRUE в rax и если она не обрабатывает сообщение, тогда она должна вернуть в eax FALSE. Заметьте, что процедура диалогового окна не передает сообщения функции DefWindowProc, так как это не настоящая процедура окна. Диалоговое окно можно использовать в двух целях. Вы можете использовать ее как основное окно или как вспомогательное для получения информации, вводимой пользователем. В этой главе мы изучим первый вариант. «Использование диалогового окна как основное окно» можно понимать двояко. Вы можете использовать шаблон диалогового окна как шаблон класса, который вы регистрируете с помощью функции RegisterClassEx. В этом случае, диалоговое окно ведет себя как «нормальное»: оно получает сообщения через процедуру окна, на которую ссылается lрfnWndProc, а не через процедуру диалогового окна. Выгода данного подхода состоит в том, что вы не должны самостоятельно создавать дочерние элементы управления, Windows создает их во время создания диалогового окна. Также Windows берет на себя логику нажатий на клавиши (Tab и так далее.). Плюс вы можете указать курсор и иконку вашего окна в структуре класса окна. Ваша программа создает диалоговое окно без создания родительского окна. Этот подход делает цикл сообщений ненужным, так как сообщения шлются напрямую процедуре диалогового окна. Вам даже не нужно регистрировать класс окна! DlgProcWndProc+ClassDlgProc+WndProcDialogBoxParamtut_10a.asmtut_10f.asmtut_10e.asmCreateDialogParamtut_10b.asmtut_10c.asmtut_10d.asmDialogBoxIndirectParamtut_10g.asmtut_10i.asmtut_10k.asmCreateDialogIndirectParamtut_10h.asmtut_10j.asmtut_10l.asmИ наконец tut_10m.asm ― вишенка на торте ― превращаем MessageBox при помощи хуков в диалог
ПРАКТИКА ― СЕСТРА ШИЗОФРЕНИИ CreateDialogParam+WndProc+Classтекст файла tut_10c.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local msg:MSG local hwnd:QWORD mov esi,IMAGE_BASE invoke LoadImage,esi,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR mov hIcon,rax xor ebx,ebx mov edi,offset ClassName push rax ;hIconSm push rdi ;lpszClassName push IDC_MENU ;lpszMenuName push COLOR_BTNFACE+1;hbrBackground push 10005h ;hCursor push rax ;hIcon push rsi ;hInstance push DLGWINDOWEXTRA;cbClsExtra & cbWndExtra pushaddr dialog_procedure;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX invoke CreateDialogParam,esi,IDC_DIALOG,0,&dialog_procedure,hIcon;0 mov hwnd,rax lea edi,msg message_loop:invoke GetMessage,edi,0,0,0 or eax,eax jz exit_msg_loop invoke IsDialogMessage,hwnd,edi or eax,eax jnz message_loop invoke DispatchMessage,edi jmp message_loop exit_msg_loop:invoke RtlExitUserProcess,NULL WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8]; choose menu ; choose button or EditBox @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke SendMessage,,WM_SETICON,1;,r9=lParam invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect jmp wmBYE wmCLOSE:invoke DestroyWindow;,hDlg invoke PostQuitMessage,0 wmBYE: xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE dialog_procedure endp ;--------------------------------------- ClassName db 'DLGCLASS',0 expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Third Dialog Box',0 hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId end Текст файла tut_10c.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_DIALOG DIALOG 10, 10, 200, 80 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Tutorial 10c: CreateDialogParam+WndProc+Class" MENU IDC_MENU BEGIN CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,0,0,78,100 EDITTEXT IDC_EDIT, 5,2,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 121,2,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 121,18,52,13 END IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/ MENUITEM "E&xit",IDM_EXIT END END Разбор полетовДавайте проанализируем первый пример. Этот пример показывает, как зарегистрировать диалоговый шаблон как класс окна и создает «окно» из этого класса. Это упрощает вашу программу, так как вам не нужно создавать дочерние элементы управления самостоятельно. Анализ шаблона окна диалога. Код (C): IDC_DIALOG DIALOG 10, 10, 200, 80 Объявление ID диалога, в данном случае ― IDC_DIALOG=200, за которым следует ключевое слово «DIALOG». Следующие четыре числа ― это значения координат x, y, ширины и высоты диалогового окна в специальных единицах (не в пикселях). Код (C): STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK Объявление стилей диалогового окна. Код (C): CAPTION "Tutorial 10c: CreateDialogParam+WndProc+Class" Это текст, который появится в заголовке окна. А это строка из asm-файла Код (ASM): ClassName db 'DLGCLASS',0 Эта строка позволяет нам использовать шаблон диалогового окна в качестве класса окна. Диалог использует меню Код (C): MENU IDC_MENU Данный блок определяет дочерние элементы управления в диалоговом окне. Они определены между ключевыми словами BEGIN и END. Код (C): BEGIN CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,0,0,78,100 EDITTEXT IDC_EDIT, 5,2,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 121,2,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 121,18,52,13 END Общий синтаксис таков: Код (C): тип_элемента_управления "текст на элементе управления", идентификатор_элемента_управления, x, y (координаты левого верхнего угла элемента), ширина, высота[,стили] типы элементов управления ― константы компилятора ресурсов, которые можно найти в руководстве по компилятору ресурсов. Теперь мы углубляемся непосредственно в ассемблерный код. Интересующая нас часть находится в структуре класса окна. Код (ASM): push DLGWINDOWEXTRA;mov wc.cbWndExtra,DLGWINDOWEXTRA push rdi;mov wc.lpszClassName,OFFSET ClassName Обычно этот параметр оставляется равным нулю, но если мы хотим зарегистрировать шаблон диалогового окна как класс окна, мы должны установить это параметр равным DLGWINDOWEXTRA. Заметьте, что имя класса должно совпадать с именем, что определено в шаблон диалогового окна. Остающиеся параметры инициализируются как обычно. После того, как вы заполните структуру класса окна, зарегистрируйте ее с помощью RegisterClassEx. Звучит знакомо. Точно также вы регистрируете обычный класс окна. Код (ASM): invoke CreateDialogParam,esi,IDC_DIALOG,0,&dialog_procedure,hIcon После регистрации «класса окна», мы создаем наше диалоговое окно. В этом примере он создается как независимое диалоговое окно функцией CreateDialogParam. Эта функция получает 5 параметров, но вам нужно заполнить только первые два: дескриптор процесса и указатель на имя шаблона диалогового окна. Заметьте, что 2-ой параметр ― это не указатель на имя класса. В этот момент, диалоговое окно и его дочерние элементы управления создаются Windows. Ваша процедура окна получит сообщение WM_INITDIALOG как обычно. Код (ASM): wmINITDIALOG:invoke SendMessage,hDlg,WM_SETICON,1,lParam invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam invoke GetDlgItem,hDlg,IDC_EDIT invoke SetFocus,eax После того, как диалоговое окно создано, устанавливается фокус ввода на окне редактирования. Функция GetDlgItem получает ID элемента управления и возвращает соответствующий дескриптор окна. Так же можно получить дескриптор окна, если вы знаете его control ID. Код (ASM): lea edi,msg message_loop:invoke GetMessage,edi,0,0,0 or eax,eax jz exit_msg_loop invoke IsDialogMessage,hwnd,edi or eax,eax jnz message_loop invoke DispatchMessage,edi jmp message_loop exit_msg_loop:invoke RtlExitUserProcess,NULL Программа входит в цикл сообщений и перед тем, как мы транслируем и передаем сообщения, мы вызываем функцию IsDialogMessage, чтобы позволить менеджеру диалоговых сообщений обрабатывать логику сообщений за нас. Если эта функция возвращает TRUE, это значит, что сообщение сделано для диалогового окна и обрабатывается менеджером диалоговых сообщений. Когда процедура окна хочет получить текст из окна редактирования, она вызывает функцию GetDlgItemText, вместо функции GetWindowText. GetDlgItemText принимает ID элемента управления вместо дескриптора окна. Скачайте пример здесь.
DialogBoxParam+DlgProc текст файла tut_10a.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc enter 30h,0 invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128, LR_DEFAULTCOLOR mov hIcon,rax mov qword ptr [ebp-10h],rax;IDC_MENU invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,0,&dialog_procedure invoke RtlExitUserProcess,NULL WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8] @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke SendMessage,,WM_SETICON,1;,r9=lParam invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx invoke MessageBoxIndirect,&mb jmp wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE dialog_procedure endp ;--------------------------------------- expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our First Dialog Box',0 hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId end Текст файла tut_10a.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_DIALOG DIALOG 10, 10, 200, 80 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Tutorial 10a: DialogBoxParam+DlgProc" MENU IDC_MENU BEGIN CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,0,0,78,100 EDITTEXT IDC_EDIT, 5,2,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 121,2,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 121,18,52,13 END IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Разбор полетов Код (C): INT_PTR WINAPI DialogBoxParam( _In_opt_ HINSTANCE hInstance, //дескриптор процесса _In_ LPCTSTR lpTemplateName, //имя шаблона диалогового окна _In_opt_ HWND hWndParent, //дескриптор родительского окна _In_opt_ DLGPROC lpDialogFunc, //адрес процедуры диалогового окна _In_ LPARAM dwInitParam //специальные данные для диалогового окна ); DialogBoxParam создает модальное диалоговое окно. Оно не передает управление, пока диалоговое окно не будет уничтожено. Код (ASM): cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND: ... Процедура диалогового окна выглядит как процедура окна, не считая того, что она не получает сообщение WM_CREATE. Первое сообщение, которое она получает ― это WM_INITDIALOG. Обычно вы помещаете здесь код инициализации. Заметьте, что вы должны вернуть в регистре eax значение TRUE, если вы обрабатываете это сообщение. Внутренний менеджер диалогового окна не посылает нашей процедуре сообщение WM_DESTROY, а вот WM_CLOSE шлет. Поэтому если мы хотим отреагировать на то, что пользователь нажимает кнопку закрытия на нашем диалоговом окне, мы должны обработать сообщение WM_CLOSE. В нашем примере мы посылаем сообщение WM_CLOSE со значение IDM_EXIT в wParam. Это произведет тот же эффект, что и выбор пункта 'Exit' в меню. EndDialog вызывается в ответ на IDM_EXIT. Обработка сообщений WM_COMMAND остается такой же. Когда вы хотите уничтожить диалоговое окно ― это вызывайте функцию EndDialog. Не пробуйте DestroyWindow! EndDialog не уничтожает диалоговое окно немедленно. Она только устанавливает флаг для внутреннего менеджера диалогового окна и продолжает выполнять следующие инструкции. Теперь давайте изучим файл ресурсов. Заметное изменение ― это то, что вместо использования текстовой строки в качестве имени меню, мы используем значение IDC_MENU. Это необходимо, если вы хотите прикрепить меню к диалоговому окну, созданному DialogBoxParam'ом. Заметьте, что в шаблоне диалогового окна вы должны добавить ключевое слово 'MENU', за которым будет следовать ID ресурса меню. Чтобы установить иконку, посылаем сообщение WM_SETICON диалоговому окну во время обработки WM_INITDIALOG. Используем "нестандартую" иконку с размером 128х128 (размер стандартной иконки 32х32) Скачайте пример здесь.
CreateDialogParam+DlgProcфайл tut_10b.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local msg:MSG invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128, LR_DEFAULTCOLOR mov hIcon,rax invoke CreateDialogParam,IMAGE_BASE,IDC_DIALOG,0,&dialog_procedure,eax mov hWnd,rax lea edi,msg message_loop: invoke GetMessage,edi,0,0,0 or eax,eax jz exit_msg_loop invoke IsDialogMessage,hWnd,edi or eax,eax jnz message_loop invoke DispatchMessage,edi jmp message_loop exit_msg_loop:invoke RtlExitUserProcess,NULL WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8]; choose menu ; choose button or EditBox @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke SendMessage,,WM_SETICON,1;,r9=lParam invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer mov r8d,offset AppName lea edx,buffer mov mb.lpszText,rdx invoke MessageBoxIndirect,&mb jmp wmBYE wmCLOSE:invoke DestroyWindow;,hDlg invoke PostQuitMessage,0 wmBYE: xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE dialog_procedure endp ;--------------------------------------- expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Second Dialog Box',0 hWnd dq ? hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId end файл tut_10b.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_DIALOG DIALOG 10, 10, 200, 80 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Tutorial 10b: CreateDialogParam+DlgProc" MENU IDC_MENU BEGIN CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,0,0,78,100 EDITTEXT IDC_EDIT, 5,2,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON,121,2,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 121,18,52,13 END IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/ MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.
CreateDialogParam+DlgProc+WndProcфайл tut_10d.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local msg:MSG invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128, LR_DEFAULTCOLOR mov hIcon,rax invoke CreateDialogParam,IMAGE_BASE,IDC_DIALOG,0,&dialog_procedure,eax mov hWnd,rax lea edi,msg @@: invoke GetMessage,edi,0,0,0 invoke IsDialogMessage,hWnd,edi or eax,eax jnz @b invoke TranslateMessage,edi invoke DispatchMessage,edi jmp @b WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD mov hDlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG jne wmBYE wmINITDIALOG:;mov rcx,hWnd invoke GetWindowLongPtr,,GWL_STYLE or eax,WS_THICKFRAME OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX invoke SetWindowLongPtr,hDlg,GWL_STYLE,rax invoke SetWindowLongPtr,hDlg,GWL_WNDPROC,&WndProc invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,1,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam wmBYE: xor eax,eax leave retn dialog_procedure endp WndProc proc hwnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hwnd,rcx mov wParam,r8 mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND leave jmp NtdllDialogWndProc_ wmCLOSE:invoke DestroyWindow invoke RtlExitUserProcess,NULL wmCOMMAND:movzx rax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8]; choose menu ; choose button or EditBox @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE CLEAR:xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:lea r8d,buffer invoke GetDlgItemText,,0,,size_of_buffer lea edx,buffer mov mb.lpszText,rdx invoke MessageBoxIndirect,&mb wmBYE: leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE WndProc endp ;--------------------------------------- expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Fourth Dialog Box',0 hWnd dq ? hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId end файл tut_10d.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_DIALOG DIALOG 10, 10, 200, 80 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Tutorial 10d: CreateDialogParam+DlgProc+WndProc" MENU IDC_MENU BEGIN // ICON IDC_ICON1,WS_VISIBLE | WS_CHILD | SS_ICON, 5,10,32,32 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,0,0,78,100 EDITTEXT IDC_EDIT, 5,2,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 121,2,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 121,18,52,13 END IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.
DialogBoxParam+DlgProc+WndProc файл tut_10e.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local msg:MSG invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128, LR_DEFAULTCOLOR mov hIcon,rax invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,0,&dialog_procedure,rax invoke RtlExitUserProcess,NULL WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD mov hDlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG jne wmBYE wmINITDIALOG:invoke GetWindowLongPtr,,GWL_STYLE or eax,WS_THICKFRAME OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX invoke SetWindowLongPtr,hDlg,,GWL_STYLE,rax invoke SetWindowLongPtr,hDlg,GWL_WNDPROC,&WndProc invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,1,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam wmBYE: xor eax,eax leave retn dialog_procedure endp WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hWnd,rcx mov wParam,r8 mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND leave jmp NtdllDialogWndProc_ wmCLOSE:invoke EndDialog,,0 jmp wmBYE wmCOMMAND:movzx rax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8]; choose menu ; choose button or EditBox @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE CLEAR:xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx invoke MessageBoxIndirect,&mb wmBYE: leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE WndProc endp ;--------------------------------------- expTxt db "Wow! I'm in an edit box now",0 AppName1 db 'Our Fifth Dialog Box',0 hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName1 ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId end файл tut_10e.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_DIALOG DIALOG 10, 10, 200, 80 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Tutorial 10e: DialogBoxParam+DlgProc+WndProc" MENU IDC_MENU BEGIN CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,0,0,78,100 EDITTEXT IDC_EDIT, 5,2,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 121,2,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 121,18,52,13 END IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.
DialogBoxParam+WndProc+Classфайл tut_10f.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local msg:MSG mov esi,IMAGE_BASE invoke LoadImage,esi,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR mov hIcon,rax xor ebx,ebx push rax ;hIconSm push rbx ;lpszClassName push IDC_MENU ;lpszMenuName push COLOR_BTNFACE+1;hbrBackground push 10005h ;hCursor push rax ;hIcon push rsi ;hInstance push DLGWINDOWEXTRA;cbClsExtra & cbWndExtra push rbx ;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX invoke DialogBoxParam,esi,IDC_DIALOG,0,&WndProc,hIcon invoke RtlExitUserProcess,NULL WinMain endp WndProc proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx rax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8] @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke SendMessage,,WM_SETICON,1;,r9=lParam invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect jmp wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE WndProc endp ;--------------------------------------- expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Sixth Dialog Box',0 hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId end файл tut_10f.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_DIALOG DIALOGEX 10, 10, 200, 80 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Tutorial #10f: DialogBoxParam+WndProc+Class" //CAPTION "Tutorial #10k: DialogBoxIndirectParam+DlgProc+WndProc" MENU IDC_MENU BEGIN CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,0,0,78,100 EDITTEXT IDC_EDIT, 5,2,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 121,2,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 121,18,52,13 END IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text", IDM_GETTEXT MENUITEM "Clear Text", IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END END Скачайте пример здесь.
DialogBoxIndirectParam+DlgProcфайл tut_10g.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local hMem:QWORD invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024 ; memory buffer size mov hMem,rax mov edi,eax mov esi,offset temp mov ecx,len/8 rep movsq invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR invoke DialogBoxIndirectParam,IMAGE_BASE,hMem,0,&DialogFunc,rax invoke GlobalFree,hMem leave retn WinMain endp DialogFunc proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8] @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke GetDlgItem,,0 invoke SetFocus,eax invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,1,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect jmp wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE DialogFunc endp expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Seventh Dialog Box',0 mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId align 4 temp: dw 1,-1 dd 0,0,DS_CENTER or WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU \ or WS_VISIBLE or WS_OVERLAPPED or DS_MODALFRAME or DS_3DLOOK dw 4,10,10,200,80,-1,IDC_MENU,0 du <Tutorial #10g: DialogBoxIndirectParam+DlgProcs> align 4;dw 0 dd 0,0,WS_VISIBLE or WS_CHILDWINDOW or SS_ICON or SS_CENTERIMAGE dw 0,0,78,100,IDC_IMG1,0,-1,82h dd 0,0,0,WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or WS_BORDER or WS_TABSTOP;,0 dw 5,2,111,13,IDC_EDIT,0,-1,81h dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_DEFPUSHBUTTON dw 121,2,52,13,IDC_BUTTON,0,-1,80h du <Say Hello> dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_PUSHBUTTON dw 121,18,52,13,IDC_EXIT,0,-1,80h du <E&xit> dw 0,0 len = $ - temp end файл tut_10g.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.
CreateDialogIndirectParam+DlgProcфайл tut_10h.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local hMem:QWORD local msg:MSG invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024 ; memory buffer size mov hMem,rax mov edi,eax mov esi,offset temp mov ecx,len/8 rep movsq invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR invoke CreateDialogIndirectParam,IMAGE_BASE,hMem,0,&DialogFunc,rax mov hWnd,rax lea edi,msg message_loop:invoke GetMessage,edi,0,0,0 or eax,eax jz exit_msg_loop invoke IsDialogMessage,hWnd,edi or eax,eax jnz message_loop invoke DispatchMessage,edi jmp message_loop exit_msg_loop:invoke GlobalFree,hMem invoke RtlExitUserProcess,NULL WinMain endp DialogFunc proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8] @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke GetDlgItem,,0 invoke SetFocus,eax invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,0,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect jmp wmBYE wmCLOSE:invoke DestroyWindow;,hDlg invoke PostQuitMessage,0 wmBYE: xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE DialogFunc endp expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Eighth Dialog Box',0 mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId hWnd dq ? align 4 temp: dw 1,-1 dd 0,0,DS_CENTER or WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU \ or WS_VISIBLE or WS_OVERLAPPED or DS_MODALFRAME or DS_3DLOOK dw 4,10,10,200,80,-1,IDC_MENU,0 du <Tutorial #10h: CreateDialogIndirectParam+DlgProc> align 4 dd 0,0,WS_VISIBLE or WS_CHILDWINDOW or SS_ICON or SS_CENTERIMAGE dw 0,0,78,100,IDC_IMG1,0,-1,82h;,-1,IDC_ICON1,0 dd 0,0,0,WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or WS_BORDER or WS_TABSTOP;,0 dw 5,2,111,13,IDC_EDIT,0,-1,81h dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_DEFPUSHBUTTON;,0 dw 121,2,52,13,IDC_BUTTON,0,-1,80h du <Say Hello> dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP;,0 dw 121,18,52,13,IDC_EXIT,0,-1,80h du <E&xit> len = $ - temp end файл tut_10h.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.
DialogBoxIndirectParam+WndProc+Classфайл tut_10i.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local hMem:QWORD local msg:MSG mov esi,IMAGE_BASE invoke LoadImage,esi,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR mov hIcon,rax xor ebx,ebx push rax ;hIconSm push rbx ;lpszClassName push IDC_MENU ;lpszMenuName push COLOR_BTNFACE+1;hbrBackground push rax ;hCursor push rax ;hIcon push rsi ;hInstance push DLGWINDOWEXTRA;cbClsExtra & cbWndExtra push rbx ;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024 ; memory buffer size mov hMem,rax mov edi,eax mov esi,offset temp mov ecx,len/8 rep movsq invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR invoke DialogBoxIndirectParam,IMAGE_BASE,hMem,0,&WndProc,rax invoke GlobalFree,hMem leave retn WinMain endp WndProc proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8] @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke GetDlgItem,,0 invoke SetFocus,eax invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,0,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect jmp wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE:xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE WndProc endp expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Ninth Dialog Box',0 hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId align 4 temp: dw 1,-1 dd 0,0,DS_CENTER or WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU \ or WS_VISIBLE or WS_OVERLAPPED or DS_MODALFRAME or DS_3DLOOK dw 4,10,10,200,80,-1,IDC_MENU,0 du <Tutorial #10i: DialogBoxIndirectParam+WndProc+Class> align 4 dd 0,0,WS_VISIBLE or WS_CHILDWINDOW or SS_ICON or SS_CENTERIMAGE dw 0,0,78,100,IDC_IMG1,0,-1,82h dd 0,0,0,WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or WS_BORDER or WS_TABSTOP dw 5,2,111,13,IDC_EDIT,0,-1,81h dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_DEFPUSHBUTTON dw 121,2,52,13,IDC_BUTTON,0,-1,80h du <Say Hello> dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP dw 121,18,52,13,IDC_EXIT,0,-1,80h du <E&xit> dw 0,0 len = $ - temp end файл tut_10i.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.
CreateDialogIndirectParam+WndProc+Classфайл tut_10j.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local hMem:QWORD local msg:MSG mov esi,IMAGE_BASE invoke LoadImage,esi,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR mov hIcon,rax mov edi,offset ClassName push rax ;hIconSm push rdi ;lpszClassName push IDC_MENU ;lpszMenuName push COLOR_BTNFACE+1;hbrBackground push rax ;hCursor push rax ;hIcon push rsi ;hInstance push DLGWINDOWEXTRA;cbClsExtra & cbWndExtra pushaddr dialog_procedure;lpfnWndProc push sizeof WNDCLASSEX;cbSize & style invoke RegisterClassEx,esp ;addr WNDCLASSEX invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024 ; memory buffer size mov hMem,rax mov edi,eax mov esi,offset temp mov ecx,len/8 rep movsq invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR invoke CreateDialogIndirectParam,IMAGE_BASE,hMem,0,&dialog_procedure,eax mov hwnd,rax lea edi,msg message_loop:invoke GetMessage,edi,0,0,0 or eax,eax jz exit_msg_loop invoke IsDialogMessage,hwnd,edi or eax,eax jnz message_loop invoke DispatchMessage,edi jmp message_loop exit_msg_loop:invoke GlobalFree,hMem invoke RtlExitUserProcess,NULL WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hDlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_COMMAND jne wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8]; choose menu ; choose button or EditBox @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE wmINITDIALOG:invoke GetDlgItem,,0 invoke SetFocus,eax invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,1,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect jmp wmBYE wmCLOSE:invoke DestroyWindow,hDlg invoke PostQuitMessage,0 wmBYE: xor eax,eax leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE dialog_procedure endp ;--------------------------------------- ClassName db 'DLGCLASS',0 expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Tenth Dialog Box',0 hwnd dq ? hIcon dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId align 4 temp: dw 1,-1 dd 0,0,DS_CENTER or WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU \ or WS_VISIBLE or WS_OVERLAPPED or DS_MODALFRAME or DS_3DLOOK dw 4,10,10,200,80,-1,IDC_MENU,0 du <Tutorial #10j: CreateDialogIndirectParam+WndProc+Class> align 4 dd 0,0,WS_VISIBLE or WS_CHILDWINDOW or SS_ICON or SS_CENTERIMAGE dw 0,0,78,100,IDC_IMG1,0,-1,82h dd 0,0,0,WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or WS_BORDER or WS_TABSTOP dw 5,2,111,13,IDC_EDIT,0,-1,81h dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_DEFPUSHBUTTON dw 121,2,52,13,IDC_BUTTON,0,-1,80h du <Say Hello> dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP dw 121,18,52,13,IDC_EXIT,0,-1,80h du <E&xit> dw 0,0 len = $ - temp end файл tut_10j.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.
DialogBoxIndirectParam+DlgProc+WndProcфайл tut_10k.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local hMem:QWORD invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024 ; memory buffer size mov hMem,rax mov edi,eax mov esi,offset temp mov ecx,len/8 rep movsq invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR invoke DialogBoxIndirectParam,IMAGE_BASE,hMem,0,&dialog_procedure,rax invoke GlobalFree,hMem invoke RtlExitUserProcess,NULL WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD mov hDlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG jne wmBYE wmINITDIALOG:;mov rcx,hWnd invoke GetWindowLongPtr,,GWL_STYLE or eax,WS_THICKFRAME OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX invoke SetWindowLongPtr,hDlg,GWL_STYLE,rax invoke SetWindowLongPtr,hDlg,GWL_WNDPROC,&WndProc invoke GetDlgItem,hDlg,0 invoke SetFocus,eax invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,1,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam wmBYE: xor eax,eax leave retn dialog_procedure endp WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hWnd,rcx mov wParam,r8 mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND leave jmp NtdllDialogWndProc_ wmCLOSE:invoke EndDialog,,0 jmp wmBYE wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8]; choose menu ; choose button or EditBox @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect wmBYE: leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE WndProc endp ;------------------------------------------------------------ expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Eleventh Dialog Box',0 mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId align 4 temp: dw 1,-1 dd 0,0,DS_CENTER or WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU \ or WS_VISIBLE or WS_OVERLAPPED or DS_MODALFRAME or DS_3DLOOK dw 4,10,10,200,80,-1,IDC_MENU,0 du <Tutorial #10k: DialogBoxIndirectParam+DlgProc+WndProc> align 4 dd 0,0,WS_VISIBLE or WS_CHILDWINDOW or SS_ICON or SS_CENTERIMAGE dw 0,0,78,100,IDC_IMG1,0,-1,82h dd 0,0,0,WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or WS_BORDER or WS_TABSTOP;,0 dw 5,2,111,13,IDC_EDIT,0,-1,81h dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_DEFPUSHBUTTON dw 121,2,52,13,IDC_BUTTON,0,-1,80h du <Say Hello> dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP dw 121,18,52,13,IDC_EXIT,0,-1,80h du <E&xit> len = $ - temp end файл tut_10k.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь. CreateDialogIndirectParam+DlgProc+WndProc файл tut_10l.asm Код (ASM): ; GUI # include win64a.inc IDM_SAYHELLO equ 0 IDM_GETTEXT equ 1 IDM_CLEAR equ 2 IDM_EXIT equ 3 IDC_EDIT equ 0 IDC_BUTTON equ 1 IDC_EXIT equ 2 IDC_MENU equ 100 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 102 .code WinMain proc local hMem:QWORD local msg:MSG invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024 ; memory buffer size mov hMem,rax mov edi,eax mov esi,offset temp mov ecx,len/8 rep movsq invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON,128,128,LR_DEFAULTCOLOR invoke CreateDialogIndirectParam,IMAGE_BASE,hMem,0,&dialog_procedure,eax mov hwnd,rax invoke GlobalFree,hMem lea edi,msg message_loop:invoke GetMessage,edi,0,0,0 invoke IsDialogMessage,hwnd,edi or eax,eax jnz message_loop invoke TranslateMessage,edi invoke DispatchMessage,edi jmp message_loop WinMain endp dialog_procedure proc hDlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD mov hDlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG jne wmBYE wmINITDIALOG:invoke GetWindowLongPtr,,GWL_STYLE or eax,WS_THICKFRAME OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX invoke SetWindowLongPtr,hDlg,GWL_STYLE,rax invoke SetWindowLongPtr,hDlg,GWL_WNDPROC,&WndProc invoke GetDlgItem,hDlg,0 invoke SetFocus,eax invoke LoadIcon,IMAGE_BASE,IDC_ICON1 invoke SendMessage,hDlg,WM_SETICON,1,rax invoke GetDlgItem,hDlg,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam xor ecx,ecx mov mb.cbSize,sizeof MSGBOXPARAMS mov mb.hwndOwner,rcx mov mb.hInstance,IMAGE_BASE movr mb.lpszCaption,AppName mov mb.dwStyle,MB_OK or MB_USERICON mov mb.lpszIcon,IDC_ICON1 mov mb.dwContextHelpId,ecx mov mb.lpfnMsgBoxCallback,rcx mov mb.dwLanguageId,ecx wmBYE: xor eax,eax leave retn dialog_procedure endp WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE mov hWnd,rcx mov wParam,r8 mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND leave jmp NtdllDialogWndProc_ wmCLOSE:invoke DestroyWindow invoke RtlExitUserProcess,NULL wmCOMMAND:movzx eax,r8w ;movzx eax,word ptr wParam or r9,r9 ;cmp lParam,0 jnz @f jmp [menu_handlers+rax*8]; choose menu ; choose button or EditBox @@: dec eax ;cmp eax,IDC_BUTTON=1 jne @f SAYHELLO:mov r8d,offset expTxt jmp @0 @@: dec eax ;cmp eax,IDC_EXIT=2 jne wmBYE invoke SendMessage,,WM_CLOSE,0,0 jmp wmBYE CLEAR: xor r8d,r8d @0: invoke SetDlgItemText,,0 jmp wmBYE GETTEXT:invoke GetDlgItemText,,0,&buffer,size_of_buffer lea edx,buffer mov mb.lpszText,rdx lea ecx,mb invoke MessageBoxIndirect wmBYE: leave retn menu_handlers dq SAYHELLO,GETTEXT,CLEAR,wmCLOSE WndProc endp ;--------------------------------------- expTxt db "Wow! I'm in an edit box now",0 AppName db 'Our Twelfth Dialog Box',0 hwnd dq ? mb label MSGBOXPARAMS dd sizeof MSGBOXPARAMS,?;cbSize dq 0 ;hwndOwner dq IMAGE_BASE ;hInstance dq ? ;lpszText dq AppName ;lpszCaption dd MB_OK or MB_USERICON,?;dwStyle dq IDC_ICON1 ;lpszIcon dd 0,?;dwContextHelpId dq 0 ;lpfnMsgBoxCallback dd 0,?;dwLanguageId align 4 temp: dw 1,-1 dd 0,0,DS_CENTER or WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU \ or WS_VISIBLE or WS_OVERLAPPED or DS_MODALFRAME or DS_3DLOOK dw 4,10,10,200,80,-1,IDC_MENU,0 du <Tutorial #10l: CreateDialogIndirectParam+DlgProc+WndProc> align 4 dd 0,0,WS_VISIBLE or WS_CHILDWINDOW or SS_ICON or SS_CENTERIMAGE dw 0,0,78,100,IDC_IMG1,0,-1,82h dd 0,0,0,WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or WS_BORDER or WS_TABSTOP dw 5,2,111,13,IDC_EDIT,0,-1,81h dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_DEFPUSHBUTTON dw 121,2,52,13,IDC_BUTTON,0,-1,80h du <Say Hello> dd 0,0,0,WS_VISIBLE or WS_CHILD or WS_TABSTOP dw 121,18,52,13,IDC_EXIT,0,-1,80h du <E&xit> len = $ - temp end файл tut_10l.rc Код (C): #include "resource.h" #define IDM_SAYHELLO 0 #define IDM_GETTEXT 1 #define IDM_CLEAR 2 #define IDM_EXIT 3 #define IDC_EDIT 0 #define IDC_BUTTON 1 #define IDC_EXIT 2 #define IDC_MENU 100 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 102 IDC_ICON1 ICON "icon3.ico" IDC_MENU MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Say Hello",IDM_SAYHELLO MENUITEM "Get Text",IDM_GETTEXT MENUITEM "Clear Edit Box",IDM_CLEAR MENUITEM SEPARATOR MENUITEM "E&xit",IDM_EXIT END END Скачайте пример здесь.