Выбрать главу

Директивы условной компиляции позволяют включить все варианты в текст одной и той же программы. Подобная техника удобна не только для демонстрации, но и для отладки. Например, когда Вам требуется включить в программу новый фрагмент кода, то Вы можете применить данную технику, дабы не потерять функционирующий модуль. Ну, и конечно, применение директив условной компиляции – наиболее удобное средство тестирования различных решений (алгоритмов) на одном модуле.

Представляет определённый интерес использование стековых фреймов и заполнение структур в стеке посредством регистра указателя стека (esp). Именно это продемонстрировано при заполнении структуры WndClassEx. Выделение места в стеке (фрейма) делается простым перемещением esp:

       sub    esp,SIZE WndClassEx

Теперь мы можем обращаться к выделенной памяти используя всё тот же регистр указатель стека. При создании 16-битных приложений такой возможностью мы не обладали. Данный приём можно использовать внутри любой процедуры или даже произвольном месте программы. Накладные расходы на подобное выделение памяти минимальны, однако, следует учитывать, что размер стека ограничен и размещать большие объёмы данных в стеке вряд ли целесообразно. Для этих целей лучше использовать “кучи” (heap) или виртуальную память (virtual memory).

Остальная часть программы достаточно тривиальна и не требует каких-либо пояснений. Возможно более интересным покажется тема использования макроопределений.

Макроопределения

Мне достаточно редко приходилось серьёзно заниматься разработкой макроопределений при программировании под DOS. В Win32 ситуация принципиально иная. Здесь грамотно написанные макроопределения способны не только облегчить чтение и восприятие программ, но и реально облегчить жизнь программистов. Дело в том, что в Win32 фрагменты кода часто повторяются, имея при этом не принципиальные отличия. Наиболее показательна, в этом смысле, оконная и/или диалоговая процедура. И в том и другом случае мы определяем вид сообщения и передаём управление тому участку кода, который отвечает за обработку полученного сообщения. Если в программе активно используются диалоговые окна, то аналогичные фрагменты кода сильно перегрузят программу, сделав её малопригодной для восприятия. Применение макроопределений в таких ситуациях более чем оправдано. В качестве основы для макроопределения, занимающегося диспетчеризацией поступающих сообщений на обработчиков, может послужить следующее описание.

Пример макроопределений

macro  MessageVector message1, message2:REST

       IFNB   <message1>

             dd     message1

             dd     offset @@&message1

             @@VecCount = @@VecCount + 1

             MessageVector message2

       ENDIF

endm   MessageVector

macro  WndMessages  VecName, message1, message2:REST

       @@VecCount   = 0

DataSeg

label  @@&VecName   dword

       MessageVector message1, message2

       @@&VecName&Cnt      = @@VecCount

CodeSeg

             mov    ecx,@@&VecName&Cnt

             mov    eax,[@@msg]

@@&VecName&_1:      dec    ecx

             js     @@default

             cmp    eax,[dword ecx * 8 + offset @@&VecName]

             jne    @@&VecName&_1

             jmp    [dword ecx + offset @@&VecName + 4]

@@default:   call   DefWindowProcA, [@@hWnd], [@@msg], [@@wPar], [@@lPar]

@@ret:       ret

@@ret_false: xor    eax,eax

             jmp    @@ret

@@ret_true:  mov    eax,-1

             dec    eax

              jmp    @@ret

endm   WndMessage

Комментарии к макроопределениям

При написании процедуры окна Вы можете использовать макроопределение WndMessages, указав в списке параметров те сообщения, обработку которых намерены осуществить. Тогда процедура окна примет вид: