Assembler & Win32 - страница 2
>
> mov eax,IDOK
>@@cancel: call EndDialog, @@hDlg, eax
>@@ret_false: xor eax,eax
> ret
>@@init: call GetDlgItem, @@hDlg, IDR_NAME
> call SetFocus, eax
> jmp @@ret_false
>endp DlgProc
>end Start
>#include "resource.h"
>IDD_DIALOG DIALOGEX 0, 0, 187, 95
>STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU
>EXSTYLE WS_EX_CLIENTEDGE
>CAPTION "Dialog"
>FONT 8, "MS Sans Serif"
>BEGIN
> DEFPUSHBUTTON "OK",IDOK,134,76,50,14
> PUSHBUTTON "Cancel",IDCANCEL,73,76,50,14
> LTEXT "Type your name",IDC_STATIC,4,36,52,8
> EDITTEXT IDR_NAME,72,32,112,14,ES_AUTOHSCROLL
>END
Остальные файлы из данного примера, приведены в приложении 1.
Краткие комментарии к программе
Сразу после метки Start, программа обращается к функции API Win32 GetModuleHandle для получения handle данного модуля (данный параметр чаще именуют как handle of instance). Получив handle, мы вызываем диалог, созданный либо вручную, либо с помощью какой-либо программы построителя ресурсов. Далее программа проверяет результат работы диалогового окна. Если пользователь вышел из диалога посредством нажатия клавиши OK, то приложение запускает MessageBox с текстом приветствия.
Диалоговая процедура обрабатывает следующие сообщения. При инициализации диалога (WM_INITDIALOG) она просит Windows установить фокус на поле ввода имени пользователя. Сообщение WM_COMMAND обрабатывается в таком порядке: делается проверка на код нажатия клавиши. Если была нажата клавиша OK, то пользовательский ввод копируется в переменную szValue, если же была нажата клавиша Cancel, то копирования не производится. Но и в том и другом случае вызывается функция окончания диалога: EndDialog. Остальные сообщения в группе WM_COMMAND просто игнорируются, предоставляя Windows действовать по умолчанию.
Вы можете сравнить приведённую программу с аналогичной программой, написанной на ЯВУ, разница в написании будет незначительна. Очевидно те, кто писал приложения на ассемблере под Windows 3.x, отметят тот факт, что исчезла необходимость в сложном и громоздком startup коде. Теперь приложение выглядит более просто и естественно.
Пример 2. Динамическая библиотека
Написание динамических библиотек под Win32 также значительно упростилось, по сравнению с тем, как это делалось под Windows 3.x. Исчезла необходимость вставлять startup код, а использование четырёх событий инициализации/деинициализации на уровне процессов и потоков, кажется логичным.
Рассмотрим простой пример динамической библиотеки, в которой всего одна функция, преобразования целого числа в строку в шестнадцатеричной системе счисления.
>Ideal
>P586
>Radix 16
>Model flat
>DLL_PROCESS_ATTACH = 1
>extrn GetVersion: proc
>DataSeg
>hInst dd 0
>OSVer dw 0
>CodeSeg
>proc libEntry stdcall
>arg @@hInst :dword, @@rsn :dword, @@rsrv :dword
> cmp [@@rsn],DLL_PROCESS_ATTACH
> jne @@1
> call GetVersion
> mov [OSVer],ax
> mov eax,[@@hInst]
> mov [hInst],eax
>@@1: mov eax,1
> ret
>endP libEntry
>public stdcall Hex2Str
>proc Hex2Str stdcall
>arg @@num :dword, @@str :dword
>uses ebx
> mov eax,[@@num]
> mov ebx,[@@str]
> mov ecx,7
>@@1: mov edx,eax
> shr eax,4
> and edx,0F
> cmp edx,0A
> jae @@2
> add edx,'0'
> jmp @@3
>@@2: add edx,'A' - 0A
>@@3: mov [byte ebx + ecx],dl
> dec ecx
> jns @@1
> mov [byte ebx + 8],0
> ret
>endp Hex2Str
>end libEntry
Остальные файлы, которые необходимы для данного примера, можно найти в приложении 2.
Краткие комментарии к динамической библиотеке
Процедура libEntry является точкой входа в динамическую библиотеку, её не надо объявлять как экспортируемую, загрузчик сам определяет её местонахождение. LibEntry может вызываться в четырёх случаях: