Assembler & Win32 [Александр Усов] (fb2) читать постранично, страница - 2


 [Настройки текста]  [Cбросить фильтры]

созданный либо вручную, либо с помощью какой-либо программы построителя ресурсов. Далее программа проверяет результат работы диалогового окна. Если пользователь вышел из диалога посредством нажатия клавиши OK, то приложение запускает MessageBox с текстом приветствия.

Диалоговая процедура обрабатывает следующие сообщения. При инициализации диалога  (WM_INITDIALOG) она просит Windows установить фокус на поле ввода имени пользователя. Сообщение WM_COMMAND обрабатывается в таком порядке: делается проверка на код нажатия клавиши. Если была нажата клавиша OK, то пользовательский ввод копируется в переменную szValue, если же была нажата клавиша Cancel, то копирования не производится. Но и в том и другом случае вызывается функция окончания диалога: EndDialog. Остальные сообщения в группе WM_COMMAND просто игнорируются, предоставляя Windows действовать по умолчанию.

Вы можете сравнить приведённую программу с аналогичной программой, написанной на ЯВУ, разница в написании будет незначительна. Очевидно те, кто писал приложения на ассемблере под Windows 3.x, отметят тот факт, что исчезла необходимость в сложном и громоздком startup коде. Теперь приложение выглядит более просто и естественно.

Пример 2. Динамическая библиотека

Написание динамических библиотек под Win32 также значительно упростилось, по сравнению с тем, как это делалось под Windows 3.x. Исчезла необходимость вставлять startup код, а использование четырёх событий инициализации/деинициализации на уровне процессов и потоков, кажется логичным.

Рассмотрим простой пример динамической библиотеки, в которой всего одна функция, преобразования целого числа в строку в шестнадцатеричной системе счисления.

Файл mylib.asm
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 может вызываться в четырёх случаях:

— при проецировании библиотеки в адресное пространство процесса (DLL_PROCESS_ATTACH);

— при первом вызове библиотеки из потока (DLL_THREAD_ATTACH), например, с помощью функции LoadLibrary;

— при выгрузке библиотеки потоком (DLL_THREAD_DETACH);

— при выгрузке библиотеки из адресного пространства процесса (DLL_PROCESS_DETACH).

В нашем примере обрабатывается только первое из событий DLL_PROCESS_ATTACH. При обработке данного события библиотека запрашивает версию OS сохраняет её, а также свой handle of instance.

Библиотека содержит только одну экспортируемую функцию, которая собственно не требует пояснений. Вы, пожалуй, можете обратить внимание на то, как производится запись преобразованных значений. Интересна система адресации посредством двух регистров общего назначения: ebx + ecx, она позволяет нам использовать регистр ecx одновременно и как счётчик и как составную часть адреса.

Пример 3. Оконное приложение

Файл dmenu.asm
Ideal

P586

Radix  16

Model  flat


struc  WndClassEx

       cbSize       dd     0

       style        dd     0

       lpfnWndProc  dd     0

       cbClsExtra   dd     0

       cbWndExtra   dd     0

       hInstance    dd     0

       hIcon        dd     0

       hCursor             dd     0

       hbrBackground dd     0

       lpszMenuName dd     0

       lpszClassName dd     0

       hIconSm             dd     0

ends   WndClassEx


struc  Point

       left         dd     0

       top          dd     0

       right        dd     0

       bottom       dd     0           

ends   Point


struc  msgStruc

       hwnd         dd     0

       message             dd     0

       wParam       dd     0

       lParam       dd     0

       time         dd     0

       pt           Point  <>

ends   msgStruc


MyMenu              = 0065

ID_OPEN                    = 9C41