Форум программистов, компьютерный форум, киберфорум
Наши страницы

Assembler, MASM, TASM

Войти
Регистрация
Восстановить пароль
 
 
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 05:05  [ТС] #16
Win32 API. Урок 6a. Клавиатура
ПРАКТИКА, СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
.686P
.model flat
include windows.inc
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
extern _imp__MessageBoxA@16:dword
extern _imp__WriteFile@20:dword
extern _imp__CreateFileA@28:dword
extern _imp__CloseHandle@4:dword
extern _imp__LoadLibraryA@4:dword
extern _imp__CreateWindowExA@48:dword
extern _imp__DefWindowProcA@16:dword
extern _imp__DispatchMessageA@4:dword
extern _imp__GetMessageA@16:dword
extern _imp__RegisterClassA@4:dword
extern _imp__TranslateMessage@4:dword
extern _imp__InvalidateRect@12:dword
extern _imp__BeginPaint@8:dword
extern _imp__EndPaint@8:dword
extern _imp__TextOutA@20:dword
extern _imp__ExitProcess@4:dword
;-----------------------------
image_base=400000h
hdrsize=sections-buffer
SizeOfHeaders=((hdrsize+3)/4)*4
SizeOfImage=((hdrsize+3)/4)*4+((codesize+3)/4)*4
 
.code
start:  xchg ebx,eax
        push MB_ICONINFORMATION OR MB_SYSTEMMODAL;1040h
        push offset szInfoCap 
        push offset namefile
        push ebx
    call _imp__MessageBoxA@16
    mov eax,_imp__LoadLibraryA@4
    sub eax,offset _LoadLibraryA-delta+4
    mov _LoadLibraryA,eax
    mov eax,_imp__RegisterClassA@4
    sub eax,offset _RegisterClassA-delta+4
    mov _RegisterClassA,eax
    mov eax,_imp__CreateWindowExA@48
    sub eax,offset _CreateWindowExA-delta+4
    mov _CreateWindowExA,eax
    mov eax,_imp__DefWindowProcA@16
    sub eax,offset _DefWindowProcA-delta+4
    mov _DefWindowProcA,eax
    mov eax,_imp__DispatchMessageA@4
    sub eax,offset _DispatchMessageA-delta+4
    mov _DispatchMessageA,eax
    mov eax,_imp__GetMessageA@16
    sub eax,offset _GetMessageA-delta+4
    mov _GetMessageA,eax
    mov eax,_imp__ExitProcess@4
    sub eax,offset _ExitProcess-delta+4
    mov _ExitProcess,eax
    mov eax,_imp__TranslateMessage@4
    sub eax,offset _TranslateMessage-delta+4
    mov _TranslateMessage,eax
    mov eax,_imp__InvalidateRect@12
    sub eax,offset _InvalidateRect-delta+4
    mov _InvalidateRect,eax
    mov eax,_imp__TextOutA@20
    sub eax,offset _TextOutA-delta+4
    mov _TextOutA,eax
    mov eax,_imp__BeginPaint@8
    sub eax,offset _BeginPaint-delta+4
    mov _BeginPaint,eax
    mov eax,_imp__EndPaint@8
    sub eax,offset _EndPaint-delta+4
    mov _EndPaint,eax
 
    push ebx    ;NULL   
    push FILE_ATTRIBUTE_ARCHIVE
    push CREATE_ALWAYS
    push ebx
    push FILE_SHARE_READ or FILE_SHARE_WRITE
    push GENERIC_READ or GENERIC_WRITE
    push offset namefile
    call _imp__CreateFileA@28
    mov edi,eax     ;hFile
    push ebx        ;lpOverlapped
    push offset SizeReadWrite   ;lpNumberOfBytesToWrite
    push sizeof_image       ;nNumberOfBytesToWrite
    push offset buffer  ;lpBuffer
    push edi    ;hFile
    call _imp__WriteFile@20
    push edi    ;hFile
    call _imp__CloseHandle@4
QUIT:   retn
buffer:
delta=$ - image_base
    dd 'ZM','EP'
    dw 14Ch ; machine
    dw 0    ; NumberOfSections
 
main:   xchg ebx,eax ; 12 - 11
    mov edi,offset style-delta
    assume edi:ptr WNDCLASSA
        push [edi].lpszClassName;"user32"
    nop
    jmp next_1 
 
    dw sections-optional_header ;sizeof_optional_header
    dw 103h ; characteristics
 
optional_header:
    dw 10Bh   ; magic
 
next_1: ; 14 байт
    db 0E8h; call LoadLibraryA
_LoadLibraryA dd 0
    push edi 
    db 0E8h; call RegisterClassA
_RegisterClassA dd 0
    push ebx       
    jmp next_2
 
    dd main-buffer ; entry point
 
next_2: mov ecx,CW_USEDEFAULT;B9 00 00 00 80h; 8 - 7
    jmp next_3
 
    db 'M'
    dd image_base
    dd 4;sectalign
    dd 4;filealign
 
next_3: push [edi].hInstance;FF7710h; 8 байт
    push ebx    
    push ebx
    push ecx
    jmp next_4
 
    dw 4 ; major sub-system version
szWinClass  db 'user32'
;%define round(n, r) (((n+(r-1))/r)*r)
    dd sizeof_image and 0FF00h
;round(hdrsize, sectalign)+round(codesize,sectalign) ;
    dd SizeOfHeaders
;round(hdrsize, filealign) ;sizeof_headers
 
next_4: push ecx; 4 - 3
    jmp next_5
 
    db 'i';nop
    dw 2 ; subsystem
char    db '  '
    dd 10000h
    dd 1000h
 
next_5: push ecx;12 байт
        push ecx
    push WS_OVERLAPPEDWINDOW + WS_VISIBLE;68 00 00 CF 10h
        push [edi].lpszClassName;FF7724
        jmp next_6
 
    dd 0 ; number of directories
sections:
 
next_6: push [edi].lpszClassName; 6 байт
    push ebx
 
    db 0E8h     ;call CreateWindowExA
_CreateWindowExA dd 0
message_loop: push ebx  ;цикл обработки сообщений             
    push ebx
    push ebx
    push edi
    db 0E8h
_TranslateMessage dd 0
    push edi 
    db 0E8h     ;call GetMessageA
_GetMessageA dd 0
    push edi
 
    db 0E8h     ;call DispatchMessageA
_DispatchMessageA dd 0
    jmp short message_loop
;WNDCLASSA -----------------------------------------------
style       dd CS_HREDRAW or CS_VREDRAW; Стиль нашего окна
lpfnWndProc dd WndProc-delta;Адрес процедуры обработки событий
cbClsExtra  dd 0        ;Это нам не нужно
cbWndExtra  dd 0        ;и это тоже
hInstance   dd image_base;Адрес нашей проги в памяти(Windows всегда её грузит по этому адресу)
hIcon       dd 10003h   ;Иконка окна по умолчанию
hCursor     dd 10011h   ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
hbrBackground   dd COLOR_WINDOW+1;Фон нашего окна
lpszMenuName    dd 0        ;Меню у нас отсутствует
lpszClassName   dd szWinClass-delta; Указатель на имя нашего класса
;----------------------------------------------------------
WndProc: 
hwnd    equ [ebp+8]
Msg equ [ebp+0Ch]
wParam  equ [ebp+10h]
ps  equ [ebp-size(PAINTSTRUCT)]
    enter size(PAINTSTRUCT),0 
    mov edi,offset char-delta
    mov esi,hwnd
        mov eax,Msg
        dec eax
    dec eax ;cmp Msg,WM_DESTROY
    je short @@WM_DESTROY
        sub eax,WM_PAINT-WM_DESTROY ;cmp Msg,WM_PAINT
    je short @@WM_PAINT
        sub eax,WM_CHAR-WM_PAINT    ;cmp Msg,WM_CHAR
    je short @@WM_CHAR
        leave;все сообщения, не обрабатываемые в функции 
    db 0E9h        ;jmp DefWindowProcA
_DefWindowProcA dd 0
@@WM_CHAR: 
    mov eax,wParam
    mov [edi],al
    push TRUE
    push ebx
    push esi
    db 0E8h
_InvalidateRect dd 0
        jmp short a1
@@WM_PAINT:
    mov eax,esp;lea eax,ps
    push eax       ;eax=offset ps
    push eax
    push esi    ;hwnd
    db 0E8h
_BeginPaint dd 0
        push 1
    push edi
    push ebx    ;0
    push ebx    ;0
        push eax    ;hdc
    db 0E8h
_TextOutA dd 0      ;call TextOut
    push esi        ;esi=hwnd
    db 0E8h
_EndPaint dd 0
a1:     leave
    retn 10h
@@WM_DESTROY: push ebx;0          ;завершение программы
    db 0E8h        ;call ExitProcess
_ExitProcess dd 0
sizeof_image=$-buffer
codesize=$ - main
szInfoCap db "Creator tiny Win Application",0
namefile db 'TinyWin286.exe',0
SizeReadWrite dd 0
end start
___________________________
© Mikl___ 2013
7
Вложения
Тип файла: zip tut06a.zip (3.2 Кб, 76 просмотров)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.01.2013, 05:05
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Сам себе Iczelion (Assembler):

создать програму которая содержит в себе команды обработки строк языка асемблер - Assembler
Создать програму которая содержит в себе команды обработки строк языка асемблер. Выполнить введение строки из 40 символов. Слова в строке...

Регистры eax & edx сами по себе принимают непонятные значения - Assembler
Задача программы сортировка массива состоящего из 5ти двойных слов. Ассемблер конечно сортирует, но только максимум 3 первых числа, а 2...

Создать программу, которая содержит в себе элементы цикла и разветвления - Assembler
в массиве из n=10 элементов найти наибольшее число

Выключается сам по себе - Компьютерное железо
После очистки компа от пыли (снимал кулер, проц, оперативку и видюху, так же менял термопасту). Я нажимаю на кнопку Power, происходит...

ПК сам по себе перезагружается - Компьютерное железо
Добрый вечер,у меня такая же проблема,сам себе перезагружается,без синего экрана,без зависаний,просто раз и потух на доли...

Вырубается ПК сам по себе - Компьютерное железо
Нужна помощь в проблеме. Пару недель назад кулер в БП сильно шумел время от времени, я решил почистить пк. Почистил ПК от пыли полностью,...

131
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 05:21  [ТС] #17
Win32 API. Урок 6b. Светомузыка на клавиатуре
Кролики ― это не только ценный мех,
но и три-четыре килограмма диетического мяса...

Клавиатура это не только 102 клавиши, но и три волшебные лампочки:
  • Num Lock
  • Caps Lock
  • Scroll Lock
Если назначение ассемблера ― прямое программирование аппаратуры компьютера, то как программно зажигать и гасить лампочки Caps Lock, Num Lock и Scroll Lock на клавиатуре?
  1. Включаем лампочки функцией keybd_event с параметрами (VK_NUMLOCK (VK_CAPITAL, VK_SCROLL), 45h, KEYEVENTF_EXTENDEDKEY, 0) и гасим keybd_event с параметрами (VK_NUMLOCK (VK_CAPITAL, VK_SCROLL), 45h, (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP), 0)

    Функция keybd_event синтезирует нажатие клавиши. Система может использовать такое синтезируемое нажатие клавиши, чтобы создать сообщение WM_KEYUP или WM_KEYDOWN. Вызывает функцию keybd_event программа обработки прерываний драйвера клавиатуры.

    Синтаксис
    Кликните здесь для просмотра всего текста
    C
    1
    2
    3
    4
    5
    6
    7
    
    VOID keybd_event
    (
        BYTE bVk,       // код виртуальной клавиши
        BYTE bScan,     // аппаратный скэн-код
        DWORD dwFlags,  // флажки, определяющие различные параметры функции
        DWORD dwExtraInfo   // дополнительные данные, связанные с нажатием клавиши
    )
    Параметры
    • bVk ― Определяет код виртуальной клавиши. Код должен быть значением в диапазоне от 1 до 254. В нашем случае это коды VK_NUMLOCK, VK_CAPITAL, VK_SCROLL
    • bScan ― Определяет для клавиши аппаратный скэн-код.
    • dwFlags ― Набор флаговых битов, которые определяют различные виды операций функции. Прикладная программа может использовать любую комбинацию следующих предопределенных постоянных значений, чтобы установить флажки:
      • KEYEVENTF_EXTENDEDKEY ― Если она установлена, скэн-коду предшествует префиксный байт, имеющий значение 0E0h.
      • KEYEVENTF_KEYUP ― Если установлена, клавиша была отпущена. Если не установлена, клавиша была нажата.
    • dwExtraInfo ― Определяет дополнительное 32-разрядное значение, связанное с нажатием клавиши. В нашем случае ноль.
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    .686P
    .model flat
    include windows.inc
    includelib user32.lib
    includelib kernel32.lib
    extern _imp__MessageBoxA@16:dword
    extern _imp__keybd_event@16:dword
    extern _imp__Sleep@4:dword
    .code
    start:  xor ebx,ebx; ebx=0
        push ebx ;push 0
        push offset sztext 
        push offset szText 
        push ebx ;push 0
        call _imp__MessageBoxA@16
        mov edi,80h ;инициируем счетчик
    @@: mov esi,VK_CAPITAL;счетчик=XXX1b горит CapsLock
        mov eax,VK_NUMLOCK;счетчик=XX1Xb горит NumLock
        mov ecx,VK_SCROLL ;счетчик=X1XXb горит ScrollLock
        test edi,1
        cmovnz esi,eax
        test edi,2
        cmovnz esi,ecx
    ;включаем/выключаем индикатор
        push ebx ;dwExtraInfo -- additional data associated with keystroke
        push KEYEVENTF_EXTENDEDKEY;dwFlags flags specifying various function options
        push 45h ;bScan -- hardware scan code
        push esi ;bVk -- virtual-key code
        call _imp__keybd_event@16; имитируем нажатие на клавишу
        push ebx ;push 0
        push KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP
        push 45h
        push esi
        call _imp__keybd_event@16;иммитируем отпускание клавиши 
        push 500
        call _imp__Sleep@4;ждем полсекунды
        dec edi   ;уменьшаем счетчик
        jnz @b
        ret
    sztext db "Моё первое приложение",0
    szText db "Цветомузыка на Num, Caps и ScrollLock",0
    end start
  2. Отладчиком заходим внутрь функции keybd_event и, спускаясь во внутрь вложенных в keybd_event функций, дойдем до int 2Eh или до команды sysenter. Внутри функции keybd_event вложена функция user32.SendInput, которая вызывает sysenter с eax=11F6h. Через int 2Eh программно зажигаем и гасим лампочки Caps Lock, Num Lock и Scroll Lock на клавиатуре.
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    
    .686P
    .model flat
    include windows.inc
    includelib user32.lib
    includelib kernel32.lib
    extern _imp__MessageBoxA@16:dword
    extern _imp__Sleep@4:dword
    .code
    start:  xor ebx,ebx     ;ebx=0
        push ebx        ;push 0
        push offset sztext 
        push offset szText 
        push ebx        ;push 0
        call _imp__MessageBoxA@16
        mov edi,80h     ;инициируем счетчик
    @@: mov esi,VK_CAPITAL  ;счетчик=XXX1b горит CapsLock
        mov eax,VK_NUMLOCK  ;счетчик=XX1Xb горит NumLock
        mov ecx,VK_SCROLL   ;счетчик=X1XXb горит ScrollLock
        test edi,1
        cmovnz esi,eax
        test edi,2
        cmovnz esi,ecx
    ;включаем/выключаем индикатор
    ; имитируем нажатие на клавишу
        sub esp,1Ch
        mov [esp+10h],ebx;dwExtraInfo -- additional data associated with keystroke
        mov [esp+0Ch],ebx
        mov dword ptr [esp+8],KEYEVENTF_EXTENDEDKEY;dwFlags flags specifying various function options
        mov ecx,45FFFFh     ;bScan -- hardware scan code
        mov cx,si       ;bVk -- virtual-key code
        mov [esp+4],ecx
        mov dword ptr [esp],1
        mov ecx,esp
        push 1Ch
        push ecx
        push 1
        mov eax,11F6h       ;SendInput
        mov edx,esp
        int 2Eh
        add esp,3Ch;выравниваю стек
    ; имитируем отпускание клавиши 
        mov dword ptr [esp+8],KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP
    ;dwFlags flags specifying various function options
        mov ecx,45FFFFh     ;bScan -- hardware scan code
        mov cx,si       ;bVk -- virtual-key code
        mov [esp+4],ecx
        mov dword ptr [esp],1
        mov ecx,esp
        push 1Ch
        push ecx
        push 1
        mov eax,11F6h       ;SendInput
        mov edx,esp
        int 2Eh
        sub esp,8       ;выравниваю стек
        push 500
        call _imp__Sleep@4  ;ждем полсекунды
        dec edi         ;уменьшаем счетчик
        jnz @b
        ret
    sztext db "Моё первое приложение",0
    szText db "Цветомузыка на Num, Caps и ScrollLock",0
    end start
  3. Через драйвер ― в системе уже есть драйвер управления клавиатурой "\\.\KbdGarland". Поэтому сам драйвер писать не придется. В KmdKit от Four-F есть пример управления состоянием светодиодов на клавиатуре. Это модификация этого примера.
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    
    .686P
    .model flat
    include windows.inc
    include w2k\ntddkbd.inc
    includelib user32.lib
    includelib kernel32.lib
    extern _imp__MessageBoxA@16:dword
    extern _imp__keybd_event@16:dword
    extern _imp__Sleep@4:dword
    extern _imp__CreateFileA@28:dword
    extern _imp__DefineDosDeviceA@12:dword
    extern _imp__DeviceIoControl@32:dword
    extern _imp__CloseHandle@4:dword
    FILE_DEVICE_KEYBOARD            equ 0000000Bh
    FILE_ANY_ACCESS         equ 0
    METHOD_BUFFERED                 equ 0
    .code
    start:  xor ebx,ebx ; ebx=0
        push ebx    ;push 0
        push offset sztext 
        push offset szText 
        push ebx    ;push 0
        call _imp__MessageBoxA@16
        push offset szText3
        push offset szText4+4
        push DDD_RAW_TARGET_PATH
        call _imp__DefineDosDeviceA@12
        test eax,eax
        jnz short @f
        push MB_ICONEXCLAMATION
        push ebx 
        push offset szText1
        push ebx
        call _imp__MessageBoxA@16
        retn
    @@:     push ebx
            push ebx
            push OPEN_EXISTING
        push ebx
        push ebx
        push ebx
        push offset szText4
        call _imp__CreateFileA@28
        inc eax     ;.if eax != INVALID_HANDLE_VALUE
        jnz @f
        push MB_ICONEXCLAMATION
        push ebx
        push offset szText5
        push ebx 
        call _imp__MessageBoxA@16
        jmp short a6    ;.else
    @@: dec eax
        mov ebp,eax
        push ebx
        push offset dwBytesReturned
        push sizeof kip
        mov esi,offset kip
        push esi
        push ebx
        push ebx
        push IOCTL_KEYBOARD_QUERY_INDICATORS
        push eax    ;hDevice
        call _imp__DeviceIoControl@32
        test eax,eax                            
        jz a2       
        cmp dwBytesReturned,ebx
        jz a2
        assume esi:ptr KEYBOARD_INDICATOR_PARAMETERS
        movzx eax,[esi].LedFlags
        push eax    ;mov LedFlags,eax   
        push 5
        pop edi
    @@: mov [esi].LedFlags, KEYBOARD_NUM_LOCK_ON
        call Do
        mov [esi].LedFlags, KEYBOARD_CAPS_LOCK_ON
        call Do
        mov [esi].LedFlags, KEYBOARD_SCROLL_LOCK_ON
        call Do
        dec edi
        jnz @b      ;.endw
        pop eax     ;mov eax,LedFlags
        mov [esi].LedFlags,ax   ;restore
        push ebx
        push offset dwBytesReturned
        push ebx
        push ebx 
        push sizeof kip
        push esi    ;adr kip
        push IOCTL_KEYBOARD_SET_INDICATORS
        push ebp    ;hDevice
        call _imp__DeviceIoControl@32
        assume esi:nothing
    a2: push ebp    ;hDevice
        call _imp__CloseHandle@4
    a6: push ebx
        push offset szText4+4
        push DDD_REMOVE_DEFINITION
        call _imp__DefineDosDeviceA@12
        ret
    Do proc
        push ebx
        push offset dwBytesReturned
        push ebx
        push ebx 
        push sizeof kip
        push esi;adr kip
        push IOCTL_KEYBOARD_SET_INDICATORS
        push ebp;hDevice
        call _imp__DeviceIoControl@32
        push 100                
        call _imp__Sleep@4
        retn
    Do endp
    sztext db "Моё первое приложение",0
    szText db "Цветомузыка на Num, Caps и ScrollLock",0
    szText1 db "Couldn't define link to keyboard device",0
    szText3 db "\Device\KeyboardClass0",0
    szText4 db "\\.\KbdGarland",0
    szText5 db "Couldn't open keyboard device",0
    dwBytesReturned dd 0
    kip KEYBOARD_INDICATOR_PARAMETERS <>
    end start
  4. Еще один "низкоуровневый" способ зажигать и гасить лампочки на клавиатуре Caps Lock, Num Lock и Scroll Lock заключается в записи байта в порт 60h, младшие три бита этого байта определяют состояние светодиодов на лицевой панели клавиатуры. Но WinXP, в отличии от DOS, не "переваривает" обращение к портам ввода/вывода от user-mode программ. Поэтому придется использовать драйвер, который спрячем в ресурсах и вытащим из ресурсов на диск при запуске приложения, по завершению приложения драйвер будем удалять

    Пример использования, исходные тексты во вложении
_______________________________________
© Mikl___ 2013
8
Вложения
Тип файла: rar KbdGarland.rar (6.1 Кб, 140 просмотров)
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 05:47  [ТС] #18
Win32 API. Урок 7. Мышь
Мы научимся как получать и отвечать на ввод с мыши в нашей процедуре окна. Программа-пример будет ждать нажатия на левую кнопку мыши и отображать текстовую строку в точности в том месте клиентской области, где кликнули на мышь.
Скачайте пример здесь.
ТЕОРИЯ, МАТЬ СКЛЕРОЗА
Так же, как и при вводе с клавиатуры, Windows определяет и посылает уведомления об активности мыши относительно какого-либо окна. Эта активность включает в себя нажатия на правую и левую клавишу, передвижения курсора через окно, двойные нажатия. В отличие от клавиатуры, сообщения от которой направляются окну, имеющему в данный момент фокус ввода, сведения о котором передаются окну, над которым находится мышь, независимо от того, активно оно или нет. Вдобавок, есть сообщения от мыши, связанные с не-клиентской части окна, но, к счастью, мы можем их, как правило, игнорировать. Мы можем сфокусироваться на связанных с клиентской областью.
Есть два сообщения для каждой из кнопок мыши: WM_LBUTTONDOWN, WM_RBUTTONDOWN и WM_LBUTTONUP, WM_RBUTTONUр. Если мышь трехкнопочная, то есть еще WM_MBUTTONDOWN и WM_MBUTTONUP. Когда курсор мыши двигается над клиентской областью, Windows шлет WM_MOUSEMOVE окну, над которым он находится. Окно может получать сообщения о двойных нажатиях, WM_LBUTTONDBCLK или WM_RBUTTONDBCLK, тогда и только тогда, когда окно имеет стиль CS_DBLCLKS, или же оно будет получать только серию сообщений об одинарных нажатиях.
Во всех этих сообщениях значение lParam содержит позицию мыши. Младшее слово ― это x-координата, старшее слово ― y-координата верхнего левого угла клиентской области окна. wParam содержит информацию о состоянии кнопок мыши, Shift'а и Ctrl'а.
ПРАКТИКА, СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
   .386
   .model flat,stdcall
   option casemap:none
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
 
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   include \masm32\include\gdi32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
   includelib \masm32\lib\gdi32.lib
 
   .data
   ClassName db "SimpleWinClass",0
   AppName  db "Our First Window",0
   MouseClick db 0         ; 0=no click yet
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   hitpoint POINT 
 
   .code
start:       invoke GetModuleHandle, NULL
       mov    hInstance,eax
       invoke GetCommandLine
       mov CommandLine,eax
       invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
       invoke ExitProcess,eax
WinMain proc   hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
       LOCAL wc:WNDCLASSEX
       LOCAL msg:MSG
       LOCAL hwnd:HWND
       mov   wc.cbSize,SIZEOF WNDCLASSEX
       mov   wc.style, CS_HREDRAW or CS_VREDRAW
       mov   wc.lpfnWndProc, OFFSET WndProc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_WINDOW+1
       mov   wc.lpszMenuName,NULL
       mov   wc.lpszClassName,OFFSET ClassName
       invoke LoadIcon,NULL,IDI_APPLICATION
       mov   wc.hIcon,eax
       mov   wc.hIconSm,eax
       invoke LoadCursor,NULL,IDC_ARROW
       mov   wc.hCursor,eax
       invoke RegisterClassEx, addr wc
       invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW,\
       CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInst,NULL
       mov   hwnd,eax
       invoke ShowWindow, hwnd,SW_SHOWNORMAL
       invoke UpdateWindow, hwnd
       .WHILE TRUE
                   invoke GetMessage, ADDR msg,NULL,0,0
                   .BREAK .IF (!eax)
                   invoke DispatchMessage, ADDR msg
       .ENDW
       mov     eax,msg.wParam
       ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
       LOCAL hdc:HDC
       LOCAL ps:PAINTSTRUCT
 
       .IF uMsg==WM_DESTROY
           invoke PostQuitMessage,NULL
       .ELSEIF uMsg==WM_LBUTTONDOWN
           mov eax,lParam
           and eax,0FFFFh
           mov hitpoint.x,eax
           mov eax,lParam
           shr eax,16
           mov hitpoint.y,eax
           mov MouseClick,TRUE
           invoke InvalidateRect,hWnd,NULL,TRUE
       .ELSEIF uMsg==WM_PAINT
           invoke BeginPaint,hWnd, ADDR ps
           mov    hdc,eax
           .IF MouseClick
               invoke lstrlen,ADDR AppName
               invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
           .ENDIF
           invoke EndPaint,hWnd, ADDR ps
       .ELSE
           invoke DefWindowProc,hWnd,uMsg,wParam,lParam
           ret
       .ENDIF
       xor    eax,eax
       ret
   WndProc endp
   end start
Разбор полётов
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
       .ELSEIF uMsg==WM_LBUTTONDOWN
           mov eax,lParam
           and eax,0FFFFh
           mov hitpoint.x,eax
           mov eax,lParam
           shr eax,16
           mov hitpoint.y,eax
           mov MouseClick,TRUE
           invoke InvalidateRect,hWnd,NULL,TRUE
Процедура окна ждет нажатия на левую клавишу мыши. Когда она получает WM_LBUTTONDOWN, lParam содержит координаты курсора мыши в клиентской области. Процедура сохраняет их в переменной типа POINT, определенной следующим образом:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
   POINT STRUCT
       x   dd ?
       y   dd ?
   POINT ENDS
Затем устанавливает флаг, MouseClick, в TRUE, что значит в клиентской области была нажата левая клавиша мыши.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
           mov eax,lParam
           and eax,0FFFFh
           mov hitpoint.x,eax
Так как x-координата ― это младшее слово lParam и члены структуры POINT размером в 32 бита, мы должны обнулить верхнее слово eax, прежде чем сохранить значение в hitpoint.x.
Кликните здесь для просмотра всего текста
Assembler
1
2
           shr eax,16
           mov hitpoint.y,eax
Так как y-координата ― это старшее слово lParam, мы должны ее в нижнее слово, прежде чем сохранять в hitрoint.y. Мы делаем это сдвигая eax на 16 битов вправо.
После сохранения позиции мыши, мы устанавливаем флаг MouseClick в TRUE для того, чтобы отрисовывающий код в секции WM_PAINT, знал, что было нажатие в клиентской области, и значит поэтому он может нарисовать строку в позиции, где была мышь при нажатии. Затем мы вызываем функцию InvalidateRect, чтобы заставить окно полностью перерисовать ее клиентскую область.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
           .IF MouseClick
               invoke lstrlen,ADDR AppName
               invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
           .ENDIF
Отрисовывающий код в секции WM_PAINT должен проверять, установлен ли флаг MouseClick в TRUE, потому что когда окно создается, процедура окна получает сообщение WM_PAINT в то время, когда не было сделано еще ни одного нажатия, то есть строку отрисовывать нельзя. Мы инициализируем MouseClick в FALSE и меняем ее значение в TRUE, когда происходит нажатие на мышь. Если по крайней мере одно нажатие на мышь произошло, она вырисовывает строку в клиентской области в позиции, где была мышь при нажатии. Заметьте, что она вызывает функцию lstrlen для того, чтобы определить длину строки и шлет полученное значение в качестве последнего параметра функции TextOut.
______________________________
© Iczelion, пер. Aquila.
7
Вложения
Тип файла: zip tut07.zip (2.8 Кб, 81 просмотров)
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 06:11  [ТС] #19
Win32 API. Урок 7a. Мышь
В отличии от Урока 7 Iczelion'a где обрабатывалось событие по нажатию левой клавиши мыши и выводилась единственная надпись "Our First Window", мы будем обрабатывать нажатие на левую и правую клавиши мыши и будем выводить надписи "Нажата левая клавиша" и "Нажата правая клавиша" и этих надписей будет столько, какое значение мы присвоим константе MAXRECTS. Если количество нажатий превысит число MAXRECTS ― будет раздаваться звуковой сигнал.
ПРАКТИКА, СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
.586
.model tiny,stdcall
;for WinXP - 1063 bytes
include windows.inc
;константы
exebase equ 400000h
MAXRECTS=40;максимальное количество обрабатываемых кликов мыши
.code
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;+------------------------------+
;| registering the window class |
;+------------------------------+
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ebx,edi
;+--------------------------+
;| creating the main window |
;+--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
    esi,esi,esi,esi,ebx,ebx
    mov ebp,esp
; +---------------------------+
; | entering the message loop |
; +---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
; +----------------------+
; | the window procedure |
; +----------------------+
window_procedure:
hWnd    equ ebp+8
uMsg    equ ebp+0Ch
wParam  equ ebp+10h
lParam  equ ebp+14h
Rect    equ ebp-sizeof(RECT)
    enter sizeof(PAINTSTRUCT)+sizeof(RECT),0
    mov eax,[uMsg]
    mov edi,[hWnd]
    dec eax; cmp uMsg,WM_DESTROY
    dec eax
    je wmDESTROY
    sub eax,WM_PAINT-WM_DESTROY; cmp uMsg,WM_PAINT
    je wmPAINT
    sub eax,WM_LBUTTONDOWN-WM_PAINT;cmp eax,WM_LBUTTONDOWN
    je wmLBUTTONDOWN
    sub eax,WM_RBUTTONDOWN-WM_LBUTTONDOWN
    je wmRBUTTONDOWN
    leave
    jmp DefWindowProc+exebase
wmDESTROY: invoke ExitProcess,ebx;завершение программы
wmPAINT: mov ebx,[nextRect+exebase]
    inc ebx;cmp nextRect,-1
    jz a1;если массив координат пуст, тогда ничего не делаем
    invoke BeginPaint,edi,esp
    invoke SetBkMode,eax,TRANSPARENT;надпись имеет прозрачный фон
a3: mov edx,8;рисуем все прямоугольники
    mov eax,[ebx*4+recs-4+exebase]
    mov ecx,eax
    shl ecx,1
    jnc a4
    shl edx,1
a4: shr ecx,17
    push dword ptr [PS+edx+exebase];если edx=8 [PS+8]=numtext1, если edx=16 [PS+16]=numtext2
    push dword ptr [PS+edx+4+exebase];если edx=8 [PS+12]=&text1, если edx=16 [PS+20]=&text2
    push ecx
    movzx eax,ax
    push eax
    invoke TextOut,dword ptr [esp+16]
    dec  ebx
    jnz a3
    invoke EndPaint,edi,esp
    jmp a1
wmLBUTTONDOWN: mov eax,80000000h;если нажали левую клавишу, тогда 31-ый бит равен 1
wmRBUTTONDOWN: add eax,[lParam];добавляем координаты мыши в момент клика
    cmp nextRect+exebase,MAXRECTS-1;если количество прямоугольников не достигло 
    jge short a2;максимального значения
    inc nextRect+exebase;увеличить счетчик прямоугольников
    mov ecx,[nextRect+exebase];записать положение прямоугольника, которое совпадает
    mov [ecx*4+recs+exebase],eax;с координатами щелчка
    movzx edx,ax; edx равно младшим 16 битам lParam (координата X)
    shl eax,1; удаляем метку "левый/правый клик"
    shr eax,17; eax равно младшим 16 битам lParam (координата Y)
    lea esi,[Rect]
    assume esi: ptr RECT
    mov [esi].left,edx
    mov [esi].top,eax
    add edx,150
    mov [esi].right,edx
    add eax,20
    mov [esi].bottom,eax
    assume esi:nothing
    invoke InvalidateRect,edi,esi,FALSE;перерисовать часть окна
    jmp a1
a2: invoke MessageBeep,ebx;выдать звуковой сигнал, если для следующего
a1: leave;прямоугольника не осталось места
    retn 10h
;-----------------------------------------------------------------
text1   db 'Нажата правая кнопка'
text2   db 'Нажата левая кнопка'
PS  dd 0,0,text2-text1, text1+exebase, PS-text2, text2+exebase
recs    dd MAXRECTS dup(?)
nextRect dd -1
wTitle  db 'Iczelion Tutorial #7:Mouse Input';name of our window
;---------------------------------------------------------------------------------
import:
dd 0,0,0,user32_dll  ,user_table
dd 0,0,0,gdi32_dll   ,gdi_table
dd 0,0,0,kernel32_dll,kernel_table
dd 0,0
kernel_table:
ExitProcess             dd _ExitProcess,0
user_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
BeginPaint      dd _BeginPaint
EndPaint        dd _EndPaint
InvalidateRect      dd _InvalidateRect
MessageBeep     dd _MessageBeep,0
gdi_table:
TextOut         dd _TextOut
SetBkMode       dd _SetBkMode
            dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_BeginPaint     db 0,0,'BeginPaint'
_InvalidateRect     db 0,0,'InvalidateRect'
_MessageBeep        db 0,0,'MessageBeep'
_EndPaint       db 0,0,'EndPaint',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_SetBkMode      db 0,0,'SetBkMode'
_TextOut        db 0,0,'TextOutA',0
gdi32_dll       db 'gdi32'
end_import:
end main
Разбор полётов
MAXRECTS ― константа, значение которой определяет максимальное количество обрабатываемых кликов мыши, которые пользователь может разместить в окне. Если вам захочется обрабатывать больше кликов, достаточно увеличить значение MAXRECTS. В массиве recs хранятся координаты всех прямоугольников. Переменная nextRect используется и как счетчик прямоугольников, и как индекс в массиве recs.
Когда пользователь нажимает на левую кнопку мыши при нахождении курсора над окном приложению посылается сообщение WM_LBUTTONDOWN, когда на правую ― RBUTTONDOWN. При обработке сообщений WM_LBUTTONDOWN и RBUTTONDOWN параметр lParam процедуры окна WndProc содержит координаты X и Y курсора мыши в момент щелчка. Координата X хранится в 16 младших битах lParam, а координата Y ― в 16 старших битах. Параметр wParam определяет, какие виртуальные клавиши были нажаты в момент щелчка. Его значение может состоять из любого сочетания констант MK_CONTROL, MK_MBUTTON, MK_RBUTTON и MK_SHIFT, представляющих клавишу CONTROL, среднюю клавишу мыши и клавишу SHIFT соответственно.
Когда приложение получило сообщение WM_LBUTTONDOWN или RBUTTONDOWN, оно должно нарисовать прямоугольник с текстом 'Нажата левая кнопка' или 'Нажата правая кнопка' в месте щелчка.
Структурный тип RECT содержит координаты левой, верхней, правой и нижней сторон прямоугольника. Если пользователь не вывел на экран предельное количество прямоугольников программа увеличит значение счетчика прямоугольников
Кликните здесь для просмотра всего текста
Assembler
1
2
inc nextRect
mov ecx,nextRect
Затем координаты X, Y курсора мыши вместе с меткой правая или левая кнопка мыши была нажата копируются в массив recs
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
wmLBUTTONDOWN: mov eax,80000000h
wmRBUTTONDOWN: add eax,lParam;перд получением сообщения WM_RBUTTONDOWN eax равно 0
. . .
mov recs[ecx*4],eax
Затем программа использует координаты курсора мыши для определения той минимальной прямоугольной области окна, которую необходимо перерисовать для отображения происшедших изменений
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
    movzx edx,ax; edx равно младшим 16 битам lParam (координата X)
    shl eax,1; удаляем метку "левый/правый клик"
        shr eax,17; eax равно младшим 16 битам lParam (координата Y)
    lea esi,[Rect]
    assume esi:ptr RECT 
        mov [esi].left,edx
        mov [esi].top,eax
        add edx,150
        mov [esi].right,edx
        add eax,20
        mov [esi].bottom,eax
        invoke InvalidateRect,edi,esi,FALSE;перерисовать часть окна
Вызов функции InvalidateRect приводит к тому, что окну посылается сообщение WM_PAINT. Функция InvalidateRect получает при вызове три аргумента: логический номер окна, адрес структуры RECT и логическое значение, которое указывает, должен ли перерисовываться фон окна.
Обработка сообщения WM_PAINT начинается с проверки того, имеются ли прямоугольники, которые необходимо нарисовать
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
wmPAINT: mov ebx,nextRect
    inc ebx;cmp nextRect,-1 
    jz a1;если массив координат пуст, тогда ничего не делаем
    . . .
a1: leave
    retn 10h
Если массив координат recs не пуст, тогда вызывается функция BeginPaint для заполнения структуры PAINTSTRUCT и получения hDC
Кликните здесь для просмотра всего текста
Assembler
1
2
    invoke BeginPaint,edi,esp;esp=&Paint для BeginPain
        mov esi,eax;esi=hdc
Однако на этот раз поле rcPaint структуры PAINTSTRUCT содержит прямоугольник, переданный нами при вызове InvalidateRect. Он представляет собой минимальную часть окна подлежащую перерисовке. При использовании hDC, возвращаемого функцией BeginPaint, Windows не будет ничего рисовать за пределами этого прямоугольника, который называется областью отсечения (clipping region) - это позволяет ускорить обновление окна. После вызова BeginPaint функция SetBkMode устанавливает для надписей прозрачный фон, далее по значению в 31-ом бите расшифровывается какая надпись и какой длины будет выведена функцией TextOut на экран и какие координаты будут у этой надписи и далее в цикле от nextRect до 0 выводим прямоугольники на экран.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
wmPAINT: mov ebx,nextRect
    inc ebx
    . . .
a3: mov edx,8;рисуем все прямоугольники
    mov eax,[ebx*4+recs-4+exebase];-4 компенсирует увеличение ebx на 1
    mov ecx,eax
    shl ecx,1
    jnc short a4
        shl edx,1
a4: shr ecx,17
    push [PS+edx+exebase];если edx=8 [PS+8]=numtext1 если edx=16 [PS+16]=numtext2
        push [PS+edx+4+exebase];если edx=8 [PS+12]=&text1 если edx=16 [PS+20]=&text2
        push ecx
    movzx eax,ax
        push eax
    invoke TextOut,dword ptr [esp+16];hdc
        dec  ebx
    jnz short a3
________________________________________
© Mikl___ 2013
8
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 07:42  [ТС] #20
Win32 API. Урок 7b. Мышь

Скачайте пример здесь.
ПРАКТИКА, СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
.686P
.model flat
include windows.inc
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
extern _imp__MessageBoxA@16:dword
extern _imp__WriteFile@20:dword
extern _imp__CreateFileA@28:dword
extern _imp__CloseHandle@4:dword
extern _imp__LoadLibraryA@4:dword
 
extern _imp__CreateWindowExA@48:dword
extern _imp__DefWindowProcA@16:dword
extern _imp__DispatchMessageA@4:dword
extern _imp__GetMessageA@16:dword
extern _imp__ExitProcess@4:dword
extern _imp__RegisterClassA@4:dword
extern _imp__MessageBeep@4:dword
extern _imp__InvalidateRect@12:dword
extern _imp__TextOutA@20:dword
extern _imp__BeginPaint@8:dword
extern _imp__EndPaint@8:dword
extern _imp__TextOutA@20:dword
extern _imp__SetBkMode@8:dword
;-----------------------------
image_base=400000h
hdrsize=sections-buffer
SizeOfHeaders=((hdrsize+3)/4)*4
SizeOfImage=((hdrsize+3)/4)*4+((codesize+3)/4)*4
MAXRECTS=20
.code
start:  xor ebx,ebx
        push MB_ICONINFORMATION OR MB_SYSTEMMODAL;1040h
        push offset szInfoCap 
        push offset namefile
        push ebx
    call _imp__MessageBoxA@16
    mov eax,_imp__LoadLibraryA@4
    sub eax,offset _LoadLibraryA-delta+4
    mov _LoadLibraryA,eax
    mov eax,_imp__RegisterClassA@4
    sub eax,offset _RegisterClassA-delta+4
    mov _RegisterClassA,eax
    mov eax,_imp__CreateWindowExA@48
    sub eax,offset _CreateWindowExA-delta+4
    mov _CreateWindowExA,eax
    mov eax,_imp__DefWindowProcA@16
    sub eax,offset _DefWindowProcA-delta+4
    mov _DefWindowProcA,eax
    mov eax,_imp__DispatchMessageA@4
    sub eax,offset _DispatchMessageA-delta+4
    mov _DispatchMessageA,eax
    mov eax,_imp__GetMessageA@16
    sub eax,offset _GetMessageA-delta+4
    mov _GetMessageA,eax
    mov eax,_imp__ExitProcess@4
    sub eax,offset _ExitProcess-delta+4
    mov _ExitProcess,eax
    mov eax,_imp__MessageBeep@4
    sub eax,offset _MessageBeep-delta+4
    mov _MessageBeep,eax
    mov eax,_imp__TextOutA@20
    sub eax,offset _TextOutA-delta+4
    mov _TextOutA,eax
    mov eax,_imp__InvalidateRect@12
    sub eax,offset _InvalidateRect-delta+4
    mov _InvalidateRect,eax
        mov eax,_imp__SetBkMode@8
    sub eax,offset _SetBkMode-delta+4
    mov _SetBkMode,eax
    mov eax,_imp__BeginPaint@8
    sub eax,offset _BeginPaint-delta+4
    mov _BeginPaint,eax
    mov eax,_imp__EndPaint@8
    sub eax,offset _EndPaint-delta+4
    mov _EndPaint,eax
 
    push ebx    ;NULL   
    push FILE_ATTRIBUTE_ARCHIVE
    push CREATE_ALWAYS
    push ebx
    push FILE_SHARE_READ or FILE_SHARE_WRITE
    push GENERIC_READ or GENERIC_WRITE
    push offset namefile
    call _imp__CreateFileA@28
    mov edi,eax     ;hFile
    push ebx        ;lpOverlapped
    push offset SizeReadWrite   ;lpNumberOfBytesToWrite
    push sizeof_image       ;nNumberOfBytesToWrite
    push offset buffer  ;lpBuffer
    push edi    ;hFile
    call _imp__WriteFile@20
    push edi    ;hFile
    call _imp__CloseHandle@4
QUIT:   retn
buffer:
delta equ $-image_base
    dd 'ZM','EP'
    dw 14Ch ; machine
    dw 0    ; NumberOfSections
 
main:   xor ebx,ebx ; 12 - 12
    mov edi,offset style-delta
    assume edi:ptr WNDCLASSA
        push [edi].lpszClassName;"user32"
    jmp next_1 
 
    dw sections-optional_header ;sizeof_optional_header
    dw 103h ; characteristics
 
optional_header:
    dw 10Bh   ; magic
 
next_1: ; 14 байт
    db 0E8h; call LoadLibraryA
_LoadLibraryA dd 0
    push edi 
    db 0E8h; call RegisterClassA
_RegisterClassA dd 0
    push ebx       
    jmp return_1
 
    dd main-buffer ; entry point
 
return_1: mov ecx,CW_USEDEFAULT;B9 00 00 00 80h; 8 - 7
    jmp next_2
 
    db 'i'
    dd image_base
    dd 4;sectalign
    dd 4;filealign
 
next_2: push [edi].hInstance;FF7710h; 8 байт
    push ebx    
    push ebx
    push ecx
    jmp next_3
 
    dw 4 ; major sub-system version
szWinClass  db 'user32'
;%define round(n, r) (((n+(r-1))/r)*r)
    dd sizeof_image and 0FF00h
;round(hdrsize, sectalign)+round(codesize,sectalign) ;
    dd SizeOfHeaders
;round(hdrsize, filealign) ;sizeof_headers
 
next_3: push ecx; 4 - 3
    jmp next_4
 
    db 'i';nop
    dw 2 ; subsystem
char    db '  '
    dd 10000h
    dd 1000h
 
next_4: push ecx;12 байт
        push ecx
    push WS_OVERLAPPEDWINDOW + WS_VISIBLE;68 00 00 CF 10h
        push [edi].lpszClassName;FF7724
        jmp next_5
 
    dd 0 ; number of directories
sections:
next_5: push [edi].lpszClassName; 6 байт
    push ebx
    db 0E8h     ;call CreateWindowExA
_CreateWindowExA dd 0
message_loop: push ebx  ;цикл обработки сообщений             
    push ebx
    push ebx
    push edi
    db 0E8h     ;call GetMessageA
_GetMessageA dd 0
    push edi
    db 0E8h     ;call DispatchMessageA
_DispatchMessageA dd 0
    jmp short message_loop
;WNDCLASSA -----------------------------------------------
style       dd CS_HREDRAW or CS_VREDRAW; Стиль нашего окна
lpfnWndProc dd WndProc-delta;Адрес процедуры обработки событий
cbClsExtra  dd 0        ;Это нам не нужно
cbWndExtra  dd 0        ;и это тоже
hInstance   dd image_base;Адрес нашей проги в памяти(Windows всегда её грузит по этому адресу)
hIcon       dd 10003h   ;Иконка окна по умолчанию
hCursor     dd 10011h   ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
hbrBackground   dd COLOR_WINDOW+1;Фон нашего окна
lpszMenuName    dd 0        ;Меню у нас отсутствует
lpszClassName   dd szWinClass-delta; Указатель на имя нашего класса
;----------------------------------------------------------
    text1       db 'Нажата левая кнопка'
    numtext1    =$-text1
    text2       db 'Нажата правая кнопка'
    numtext2    =$-text2
    PS          dd 0,0,numtext1, text1-delta, numtext2, text2-delta
    recs        dd MAXRECTS dup (?)
    nextRect    dd  -1
 
WndProc:
hwnd    equ [ebp+8]
Msg equ [ebp+0Ch]
lParam  equ [ebp+14h]
Rect    equ [ebp-size(RECT)]
ps  equ Rect-size(PAINTSTRUCT)
 
    enter (size(RECT)+size(PAINTSTRUCT)),0
    mov edi,hwnd
        mov eax,Msg
        dec eax
    dec eax     ;cmp Msg,WM_DESTROY
    je short @@WM_DESTROY
        sub eax,WM_PAINT-WM_DESTROY
    je short @@WM_PAINT
    sub eax,WM_LBUTTONDOWN-WM_PAINT;cmp eax,WM_LBUTTONDOWN
        je short @@WM_LBUTTONDOWN
    sub eax,WM_RBUTTONDOWN-WM_LBUTTONDOWN
    je short @@WM_RBUTTONDOWN
        leave;все сообщения, не обрабатываемые в функции 
    db 0E9h        ;jmp DefWindowProcA
_DefWindowProcA dd 0
@@WM_DESTROY: push ebx;0          ;завершение программы
    db 0E8h        ;call ExitProcess
_ExitProcess dd 0
@@WM_PAINT: 
    db 8Bh,1Dh
    dd nextRect-delta;mov ebx,nextRect
    inc ebx;cmp nextRect,-1
    jz a1
    lea eax,ps
    push eax       ;eax=offset ps
    push eax
    push edi    ;hwnd
    db 0E8h         ;call BeginPaint
_BeginPaint dd 0
        mov esi,eax ;esi:=hdc
    push TRANSPARENT
        push eax    ;push hdc
    db 0E8h         ;call SetBkMode
_SetBkMode dd 0
a3: xor edx,edx
    mov eax,(recs-4-delta)[ebx*4]
    mov ecx,eax
    shl ecx,1
    setnc dl    ;if ecx ]=80000000h then edx=1 else edx=0
    shr ecx,17
    lea edx,[PS-delta+8+edx*8]
    push [edx]  ;push numtext1     or push numtext2
        push [edx+4]    ;push offset text1 or push offset text2
        push ecx
    movzx eax,ax
        push eax
    push esi;hdc
    db 0E8h
_TextOutA dd 0;call _imp__TextOutA@20
        dec  ebx
    jnz short a3
    push edi    ;hWnd
    db 0E8h
_EndPaint dd 0
        jmp short a1
@@WM_LBUTTONDOWN: inc eax;mov eax,80000000h
    shl eax,31
@@WM_RBUTTONDOWN: add eax,lParam
    db 83h,3Dh       ;cmp nextRect,MAXRECTS-1
    dd nextRect-delta
    db MAXRECTS-1
        jge short a5
        db 0FFh,5
    dd nextRect-delta;inc nextRect
    db 8Bh,0Dh
        dd nextRect-delta;mov ecx,nextRect
        mov [recs-delta+ecx*4],eax
        movzx edx,ax
    shl eax,1
        shr eax,17
    lea esi,Rect;esi=&Rect
    assume esi:ptr RECT 
        mov [esi].left,edx
        mov [esi].top,eax
        add edx,150
        mov [esi].right,edx
        add eax,20
        mov [esi].bottom,eax
        push ebx    ;FALSE=0
        push esi    ;&Rect
        push edi    ;hWnd
    db 0E8h
_InvalidateRect dd 0
        jmp short a1
a5:     push ebx;0
    db 0E8h
_MessageBeep dd 0
a1:     leave
    retn 10h
 
sizeof_image=$-buffer
codesize=$ - main
szInfoCap db "Creator tiny Win Application",0
namefile db 'TinyWin553.exe',0
SizeReadWrite dd 0
end start
___________________________
© Mikl___ 2013
6
Вложения
Тип файла: zip tut07b.zip (4.0 Кб, 89 просмотров)
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 07:55  [ТС] #21
Win32 API. Урок 7c. Фокусы с иконкой и курсором
(часть первая)
В качестве курсора и иконки используем иконку из файла Cursor.cur. Убеждаемся, что разницы между курсором и иконкой нет.
Скачайте пример здесь.
ПРАКТИКА, СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
.586p
.model tiny
include windows.inc
;for WinXP - 580 bytes
.code
exebase     equ 400000h
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------+
; registering the window class |
;------------------------------+
    invoke LoadCursorFromFile,offset FileName+exebase,COLOR_WINDOW+1,ebx,edi
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,ebx,\
    ebx,esi,eax,eax
;--------------------------+
; creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
    esi,esi,esi,esi,ebx,ebx
    mov ebp,esp
;---------------------------+
; entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
; the window procedure |
;----------------------+
window_procedure: cmp dword ptr [esp+8],WM_DESTROY
    je @@WM_DESTROY
    jmp DefWindowProc+exebase
@@WM_DESTROY: invoke ExitProcess,ebx
     ;exp=experiment
FileName db "Images\Cursor.cur",0
wTitle db 'Iczelion Tutorial #7-1:Курсор и иконка из файла *.cur в MASM'
;----------------------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
LoadCursorFromFile  dd _LoadCursorFromFile
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_LoadCursorFromFile db 0,0,"LoadCursorFromFileA",0
user32_dll      db 'user32'
 
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
________________________________
© Mikl___ 2013
5
Вложения
Тип файла: zip tut07c.zip (1.9 Кб, 93 просмотров)
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 09:41  [ТС] #22
Win32 API. Урок 7d. Фокусы с иконкой и курсором
(часть вторая)

ТЕОРИЯ, МАТЬ СКЛЕРОЗА
Добавляем курсор и иконку из файла Cursor.cur в секцию ресурсов. В MASM нет возможности добавлять содержимое бинарных файлов директивой incbin как в NASM'е мы либо должны воспользоваться компилятором ресурсов и в нем указать:
Кликните здесь для просмотра всего текста
Код
#define ID_CURSOR 18 
ID_CURSOR CURSOR "Images\cursor.cur"
либо воспользоваться тузлой bintodb.exe из "\masm32\tools" и преворатить Cursor.cur в текстовый файл состоящий из наборов DB
Скачайте пример здесь.
ПРАКТИКА, СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
.586p
.model tiny
include windows.inc
;for WinXP - 1501 bytes
.code
exebase     equ 400000h
ID_CURSOR   equ 18
main:
include capito_res.asm
;---------------------------------------------------------
start:  xchg ebx,eax
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke LoadCursor,esi,ID_CURSOR,COLOR_WINDOW+1,ebx,edi
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
    ebx,ebx,esi,eax,eax
;--------------------------+
;  creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
    esi,esi,esi,esi,ebx,ebx
    mov ebp,esp
;---------------------------+
;  entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
;  the window procedure |
;----------------------+
window_procedure: cmp dword ptr [esp+8],WM_DESTROY
    je @@WM_DESTROY
    jmp DefWindowProc+exebase
@@WM_DESTROY: invoke ExitProcess,ebx
;---------------------------------------
wTitle db 'Iczelion Tutorial #7-2:Курсор и иконка из ресурсов в MASM'
;--------------------------------------------------------------------
;align 2
resource:
;RT_CURSOR=1
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 2;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_CURSOR,0
dw cur1-resource,8000h
dw RT_GROUP_CURSOR,0
dw gr1-resource,8000h
cur1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором ресурса 
dw 1,0
dw cur2-resource,8000h
gr1:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором ресурса 
dw ID_CURSOR,0
dw gr2-resource,8000h
cur2:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором ресурса 
dw ID_CURSOR,0
dd cur3-resource
gr2:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором ресурса 
dw ID_CURSOR,0
dd gr3-resource
cur3 dd cursor,748,0,0
gr3 dd group1,14h,0,0
cursor dd 0      
; пропуск первых 22 байт размер курсора 766-22=748
db 40,0,0,0,32,0,0,0,64,0,0,0,1,0,4,31 dup(0)
db 128,0,0,128,0,0,0,128,128,0,128,0,0,0,128
db 0,128,0,128,128,0,0,192,192,192,0,128,128
db 128,0,0,0,255,0,0,255,0,0,0,255,255,0,255
db 0,0,0,255,0,255,0,255,255,0,0,255,255,255
db 0,0,10,5 dup(170),160,10 dup(0),3 dup(170)
db 160,12 dup(0),10,170,0,10,4 dup(170),0,128
db 8 dup(0),10,6 dup(170),168,6 dup(0),8,10,170
db 160,0,0,0,10,170,170,7 dup(0),170,170,1,16
db 5 dup(170),168,5 dup(0),10,170,160,17,10
db 4 dup(170),0,0,0,128,0,0,0,74,170,160,16
db 8 dup(170),160,0,8,0,0,170,160,10,9 dup(170)
db 0,128,10,3 dup(170),10,170,160,8,6 dup(170)
db 168,0,3 dup(170),160,0,170,138,160,136,160
db 4 dup(170),160,10,170,170,74,170,170,168,170
db 15,0,0,10,170,170,170,168,10,170,164,10,170
db 170,10,160,255,0,15,0,10,170,170,0,10,170
db 64,10,160,168,10,160,255,240,15,5 dup(0),10
db 160,0,170,160,8,10,160,4 dup(255),10,4 dup(0)
db 3 dup (170),0,128,10,160,255,255,15,255,10
db 0,0,0,7,10,170,160,8,248,10,170,15,240,15,240
db 170,0,0,0,15,112,0,15,255,255,0,170,160,10,168
db 10,160,128,0,0,15,5 dup(255),128,3 dup (170)
db 138,170,8,0,0,0,7,5 dup(255),248,10,170,160
db 96,0,0,0,0,0,0,6 dup(255),128,0,15,255,247
db 112,4 dup(0),9 dup(255),119,119,128,0,128
db 0,0,6 dup(255),127,136,136,128,8,255,255
db 248,0,8,127,5 dup(255),247,112,8,4 dup(255)
db 240,0,0,15,5 dup(255),248,143,5 dup(255),240
db 0,0,135,12 dup(255),248,0,0,0,12 dup(255)
db 4 dup(0),7,10 dup(255),240,5 dup(0),135
db 8 dup(255),247,7 dup(0),7,6 dup(255),247,8
db 8 dup(0),8,127,3 dup(255),247,8,10 dup(0)
db 128,0,0,0,8,5 dup(0),192,0,255,255,224,0,15
db 255,240,0,1,255,248,0,0,255,248,0,0,127,248
db 0,0,63,240,0,0,7,224,0,0,3,128,0,0,1,15 dup(0)
db 1,0,0,0,3,4 dup(0,0,0,31),0,0,0,63,0,0,0,127
db 128,0,0,63,128,0,0,7,128,0,0,3,128,0,0,3,192
db 0,0,3,192,0,0,3,224,0,0,7,240,0,0,15,248,0
db 0,31,254,0,0,63,255,128,0,255,255,240,3,255
  dd group1
  dd 14h,000h,0
group1 dd 20000h
  dw 1,20h,40h,1,4,748,0,1
;32 x 32 (2^4=16 colors) - Ordinal name: 1
;--------------------------------------------------
end_resource:
;align 2
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
LoadCursor      dd _LoadCursor
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_LoadCursor     db 0,0,"LoadCursorA",0
user32_dll      db 'user32'
 
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
______________________________________
© Mikl___ 2013
5
Вложения
Тип файла: zip tut07d.zip (4.2 Кб, 71 просмотров)
Mikl___
Заблокирован
Автор FAQ
06.01.2013, 09:49  [ТС] #23
Win32 API. Урок 7e. Добавляем курсор и иконку из секции данных функцией CreateIconFromResource
В секцию данных добавим рисунок из файла Cursor.cur, воспользовавшись программкой bintodb.exe из "\masm32\tools", которая превратит рисунок в текстовый файл состоящий из наборов DB. При помощи функции CreateIconFromResource получаем указатель на иконку, и, передав его DrawIcon, выводим рисунок из Cursor.cur на клиентскую область окна.
Скачайте пример здесь.
Функция CreateIconFromResource создает пиктограмму или курсор из битов ресурса, описывающих пиктограмму.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
HICON CreateIconFromResource
(
    PBYTE presbits, // указатель на биты пиктограммы или курсора
    DWORD dwResSize,    // число байтов в буфере битов
    BOOL fIcon, // флажок пиктограммы или курсора
    DWORD dwVer // версия формата Windows
);
Параметры
  • presbits ― Указывает на буфер, содержащий биты ресурса пиктограммы или курсора. Эти биты обычно загружаются при помощи вызова функций LookupIconIdFromDirectory и LoadResource.
  • dwResSize ― Определяет размер, в байтах, набор битов, указанных параметром presbits.
  • fIcon ― Определяет, что должно быть создано ― пиктограмма или курсор. Если этот параметр ― TRUE, должна быть создана пиктограмма. Если ― FALSE, должен быть создан курсор.
  • dwVer ― Определяет номер версии формата пиктограммы или курсора для битов ресурса, указанных параметром presbits. Параметр dwVer может быть одним из следующих значений:
    Формат dwVer
    Windows 2.x 20000h
    Windows 3.x 30000h
    Прикладные программы, базирующиеся на Microsoft Win32, используют для пиктограмм и курсоров формат Windows 3.x.
Возвращаемые значения
Если функция завершается успешно, величина возвращаемого значения ― дескриптор пиктограммы или курсора. Если функция не выполняет задачу, величина возвращаемого значения ― NULL. Чтобы получать расширенные данные об ошибках, вызовите GetLastError.
Функция DrawIcon рисует пиктограмму в рабочей области окна заданным контекстом устройства.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
BOOL DrawIcon
(       HDC hDC,    // дескриптор контекста устройства
    int X,  // x-координата верхнего левого угла
    int Y,  // y- координата верхнего левого угла
    HICON hIcon // дескриптор иконы, которую надо нарисовать
);
Параметры
  • hDC ― Идентифицирует контекст устройства для окна.
  • X ― Определяет логическую x-координату левого верхнего угла пиктограммы.
  • Y ― Определяет логическую y-координату левого верхнего угла пиктограммы.
  • hIcon ― Идентифицирует пиктограмму, которая будет нарисована.
Возвращаемые значения
Если функция завершается успешно, величина возвращаемого значения отличная от нуля. Если функция не выполняет задачу, величина возвращаемого значения нулевая. Чтобы получать расширенные данные об ошибках, вызовите GetLastError.
Пpимеp:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
.586p
.model tiny
include windows.inc
;for WinXP - 1450 bytes
.code
exebase     equ 400000h
ICON_SIZE   equ 744
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
        invoke CreateIconFromResource,offset ptIcon+exebase,\
    ICON_SIZE,-1,30000h,COLOR_WINDOW+1,ebx,edi
        mov hIcon+exebase,eax
    invoke RegisterClass,esp,ebx,offset window_procedure+\
    exebase,ebx,ebx,esi,eax,eax
;--------------------------+
;  creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW \
    or WS_VISIBLE,esi,esi,esi,esi,ebx,ebx
    mov ebp,esp
;---------------------------+
;  entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
;  the window procedure |
;----------------------+
window_procedure:
hWnd    equ [ebp+8]
uMsg    equ [ebp+0Ch]
    enter sizeof(PAINTSTRUCT),0
        mov eax,uMsg
        mov edi,hWnd
    dec eax
        dec eax; cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_PAINT-WM_DESTROY
        jz @@WM_PAINT
    leave
    jmp DefWindowProc+exebase
@@WM_PAINT: invoke BeginPaint,edi,esp
    invoke DrawIcon,eax,134,68,hIcon+exebase;Рисуем иконку в клиентской области
    invoke EndPaint,edi,esp
exit:   leave
        retn 10h
@@WM_DESTROY: invoke ExitProcess,ebx
;----------------------------------------------------------
ptIcon:;sauter le header du fichier d'icone
; пропуск первых 22 байт 
db 40,0,0,0,32,0,0,0,64,0,0,0,1,0,4,31 dup(0)
db 128,0,0,128,0,0,0,128,128,0,128,0
db 0,0,128,0,128,0,128,128,0,0,192,192,192,0,128,128
db 128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0
db 0,0,255,0,255,0,255,255,0,0,255,255,255,0,0,10
db 5 dup(170),160,10 dup(0),3 dup(170),160,12 dup(0)
db 10,170,0,10,4 dup(170),0,128,8 dup(0)
db 10,6 dup(170),168,6 dup(0)
db 8,10,170,160,0,0,0,10,170,170,7 dup(0)
db 170,170,1,16,5 dup(170),168,5 dup(0)
db 10,170,160,17,10,4 dup(170),0,0,0,128,0,0,0
db 74,170,160,16,8 dup(170),160,0,8,0
db 0,170,160,10,9 dup(170),0,128,10
db 3 dup(170),10,170,160,8,6 dup(170),168,0,170
db 170,170,160,0,170,138,160,136,160,4 dup(170),160,10,170
db 170,74,170,170,168,170,15,0,0,10,170,170,170,168,10,170
db 164,10,170,170,10,160,255,0,15,0,10,170,170,0,10,170
db 64,10,160,168,10,160,255,240,15,0,0,0,0,0,10,160
db 0,170,160,8,10,160,4 dup(255),10,0,0,0,0,170
db 170,170,0,128,10,160,255,255,15,255,10,0,0,0,7,10
db 170,160,8,248,10,170,15,240,15,240,170,0,0,0,15,112
db 0,15,255,255,0,170,160,10,168,10,160,128,0,0,15,5 dup(255)
db 128,170,170,170,138,170,8,0,0,0,7,5 dup(255)
db 248,10,170,160,96,0,0,0,0,0,0,6 dup(255)
db 128,0,15,255,247,112,0,0,0,0,9 dup(255)
db 119,119,128,0,128,0,0,6 dup(255)
db 127,136,136,128,8,255,255,248,0,8,127
db 5 dup(255),247,112,8,4 dup(255),240,0,0,15
db 5 dup(255),248,143,5 dup(255),240,0,0,135
db 12 dup(255),248,0,0,0,12 dup(255),0,0,0,0
db 7,10 dup(255),240,5 dup(0),135,8 dup(255),247,7 dup(0)
db 7,6 dup(255),247,8,8 dup(0)
db 8,127,3 dup(255),247,8,10 dup(0)
db 128,0,0,0,8,5 dup(0),192,0
db 255,255,224,0,15,255,240,0,1,255,248,0,0,255,248,0
db 0,127,248,0,0,63,240,0,0,7,224,0,0,3,128,0
db 0,1,15 dup(0),1,0,0,0,3,4 dup(0,0,0,31)
db 0,0,0,63,0,0,0,127,128,0
db 0,63,128,0,0,7,128,0,0,3,128,0,0,3,192,0
db 0,3,192,0,0,3,224,0,0,7,240,0,0,15,248,0
db 0,31,254,0,0,63,255,128,0,255,255,240,3,255
wTitle db 'Iczelion Tutorial #7-3:создание курсора и иконки '
db 'функцией CreateIconFromResource в MASM'
;---------------------------------------------------------------
import:
dd 0
hIcon dd 0
dd 0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
BeginPaint      dd _BeginPaint
EndPaint        dd _EndPaint
DrawIcon        dd _DrawIcon
CreateIconFromResource  dd _CreateIconFromResource
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_BeginPaint     db 0,0,'BeginPaint'
_EndPaint       db 0,0,'EndPaint'
_DrawIcon       db 0,0,'DrawIcon'
_CreateIconFromResource db 0,0,'CreateIconFromResource',0
 
user32_dll      db 'user32'
 
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
__________________________
© Mikl___ 2013
5
Изображения
              
Вложения
Тип файла: zip tut07e.zip (3.5 Кб, 71 просмотров)
Mikl___
Заблокирован
Автор FAQ
07.01.2013, 09:10  [ТС] #24
Win32 API. Урок 7f. Не используем функции LoadIcon и LoadCursor

Заполняя WNDCLASS(EX) можно и не использовать функции LoadIcon и LoadCursor. Дело в том, что эти функции нужны, если загружаемая иконка или курсор изготовлены собственноручно или позаимствованы из какой-либо понравившейся программы. Для стандартных (системных) иконок, битмапов и курсоров идентификаторы неизменны и их можно посмотреть при помощи программы
System Resources by The Svin, находящейся на WASM.RU http://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrow Исходники http://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrow Система, а также при помощи «связки» из функций wsprintf + LoadIcon/Cursor/Bitmap + MessageBoxA посмотреть хэндл иконки, курсора или битмапы.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
    invoke LoadCursorA, 0, IDC_ARROW
    invoke wsprintfA, addr buffer, addr format, eax
    add esp,12
    invoke MessageBoxA, 0, addr buffer, addr Caption, 0
Полученный хэндл вставлялся в программу, выводящую окно, и проверялся результат.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
.686P
.model flat
includelib user32.lib
includelib kernel32.lib
include windows.inc
extern _imp__CreateWindowExA@48:dword
extern _imp__DefWindowProcA@16:dword
extern _imp__DispatchMessageA@4:dword
extern _imp__GetMessageA@16:dword
extern _imp__ExitProcess@4:dword
extern _imp__RegisterClassA@4:dword 
.code
start:  xor ebx,ebx ;ebx=0
    mov edi,offset wTitle; Имя нашего класса окна
        mov esi,400000h ; Хэндл нашей программы
; заполнение структуры wc
    push edi ;lpszClassName
    push ebx ;lpszMenuName
    push COLOR_WINDOW+1 ;hbrBackground
    push 10011h ;hCursor: Хэндл курсора вычисленный заранее
    push ebx ;hIcon: Хэндл иконки
    push esi ;hInstance
    push ebx ;cbWndExtra
    push ebx ;cbClsExtra
    push offset WndProc;lрfnWndProc: Адрес процедуры окна
    push ebx ;style
    push esp ;адрес структуры WNDCLASSEX                   
    call _imp__RegisterClassA@4 ; регистрация нашего класса окна
    push ebx;lрParam
    push esi ;hInstance
        shl esi,9;esi=CW_USEDEFAULT
    push ebx;hMenu
    push ebx;hWndParent
    push esi;X-координата верхнего левого угла окна.
    push esi;Y-координата верхнего левого угла окна. 
    push esi;ширина окна в пикселях     
    push esi;высота окна в пикселях
    push WS_OVERLAPPEDWINDOW + WS_VISIBLE ;dwStyle
    push edi;lрWindowName
    push edi;lрClassName
    push ebx;dwExStyle
    call _imp__CreateWindowExA@48   ;создать окно
    mov ebp,esp
message_loop: push ebx  ;цикл обработки сообщений
    push ebx
    push ebx
    push ebp 
    call _imp__GetMessageA@16   
    push ebp
    call _imp__DispatchMessageA@4     ;вернуть управление Windows        
    jmp short message_loop
WndProc:
        cmp dword ptr [esp+8],WM_DESTROY;cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
        jmp _imp__DefWindowProcA@16;все сообщения, не обрабатываемые в функции 
;WndProc, направляются на обработку по умолчанию    
@@WM_DESTROY: push ebx    ;если пользователь закрывает окно
    call _imp__ExitProcess@4; выходим из программы  
;--данные------------------------------------------------------
wTitle  db 'Iczelion Tutorial #3:A Simple Window in masm',0; Имя нашего окна
end start
Начав с курсоров IDC_ARROW, IDC_IBEAM очень скоро замечаем, что хэндлы курсоров могут быть только нечетными числами: 10011h, 10013h, 10015h и т.д. Теперь уже без «связки» wsprintf+LoadCursor+MessageBox подставляем значения в шаблон окна и смотрим, что будет выведено в качестве курсора. Если хэндл четный, то окно становится невидимым. Когда, хэндл окажется меньше 10011h, в качестве курсоров появятся стандартные системные иконки IDI_APPLICATION, IDI_QUESTION и т.д. то есть разница между иконкой и курсором отсутствует (на это я наткнулся случайно, когда во время заполнения WNDCLASSEX перепутал местами функции LoadIcon и LoadCursor). Для части системных курсоров и иконок в файле windows.inc константы IDC_ и IDI_ отсутствуют, константы IDI_APPLICATION и IDI_WINLOGO хотя и имеют разное значение (32512 и 32517 соответственно), но соответствуют одной и той же иконке. IDC_SIZE (=32640) и IDC_ICON (=32641), вероятно, устарели и в Windows XP не соответствуют никакому курсору. Часть курсоров, принадлежащих системе, находятся в «Панель управления»http://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrow«Оформление и темы» http://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrow«Указатели мыши»
Кликните здесь для просмотра всего текста
Результат исследования помещен в таблицу
Кликните здесь для просмотра всего текста
тип значение Оформление и темы: указатели мыши хэндл картинка
  системные иконки  
IDI_APPLICATION 32512 иконка программы большая 10003h
IDI_EXCLAMATION/IDI_WARNING 32515 предупреждение 10005h
IDI_QUESTION 32514 вопрос 10007h
IDI_HAND/IDI_ERROR 32513 ошибка 10009h
IDI_ASTERISK/IDI_INFORMATION 32516 информация 1000Bh
? ? иконка программы малая 1000Dh
IDI_WINLOGO 32517 иконка программы большая 1000Fh
  системные курсоры  
IDC_ARROW 32512 Основной режим 10011h
IDC_IBEAM 32513 Выделение текста 10013h
IDC_WAIT 32514 Система недоступна 10015h
IDC_CROSS 32515 Графическое выделение 10017h
IDC_UPARROW 32516 Специальное выделение 10019h
IDC_SIZENWSE 32642 Изменение размера по диагонали 1 1001Bh
IDC_SIZENESW 32643 Изменение размера по диагонали 2 1001Dh
IDC_SIZEWE 32644 Изменение горизонтальных размеров 1001Fh
IDC_SIZENS 32645 Изменение вертикальных размеров 10021h
IDC_SIZEALL 32646 Перемещение 10023h
IDC_NO 32648 Операция невозможна 10025h
IDC_APPSTARTING 32650 Фоновый режим 10027h
IDC_HELP 32651 Выбор справки 10029h
? 32631 Рукописный ввод 1002Bh
IDC_HAND 32649 Выбор ссылки 1002Dh
? ? ? 1002Fh
6
Миниатюры
Сам себе Iczelion  
Изображения
              
Mikl___
Заблокирован
Автор FAQ
08.01.2013, 04:04  [ТС] #25
Кликните здесь для просмотра всего текста
тип значение Оформление и темы: указатели мыши хэндл картинка
? 32663 Ожидание готовности CD/DVD 10031h
IDC_SIZE 32640 - 0 -
IDC_ICON 32641 - 0 -
32652 0C36023Fh
32653 0AA9023Bh
32654 17D1022Fh
32655 0C8A023Fh
32656 0EC40231h
32657 0C95023Fh
32658 09EF0191h
32659 0DE2023Fh
32660 1963022Fh
32661 0CCF023Fh
32662 01970022h

________________________________
© Mikl___ 2013
4
Изображения
      
Mikl___
Заблокирован
Автор FAQ
08.01.2013, 09:56  [ТС] #26
Win32 API. Урок 8. Меню
В этом туториале мы научимся, как вставить в наше окно меню.
Скачайте пример #1 и пример #2.
ТЕОРИЯ, МАТЬ СКЛЕРОЗА
Меню ― это один из важнейших компонентов вашего окна. Меню ― список всех возможностей, которые программа предлагает пользователю.
Пользователь не обязан читать мануал, поставляемый с программой, чтобы использовать ее (весьма спорная точка зрения ― прим. пер.), он может досконально исследовать меню, чтобы получить представление о возможностях данной программы и начать 'играть' с ней немедленно. Так как меню ― это инструмент для того, чтобы дать пользователю 'быстрый старт', вы должны следовать стандарту.
Короче говоря, первые два пункта меню обязательно "File" и "Edit", а последний ― "Help". Вы можете вставить ваши собственные пункты между "Edit" и "Help". Если пункт меню вызывает диалоговое окно, вам нужно заканчивать название пункта эллипсисом (...).
Меню ― это разновидность ресурсов. Есть несколько видов ресурсов, таких как диалоговые окна, строковые таблицы, иконки, битмапы, меню и т.д. Ресурсы описываются в отдельном файле, называющемся файлом ресурсов, который, как правило, имеет расширение .rc. Вы можете соединять ресурсы с исходным кодом во время линковки. Окончательный продукт ― это исполняемый файл, который содержит как инструкции, так и ресурсы.
Файлы ресурсов можно создать используя любой текстовый редактор. Они состоят из набора фраз, определяющих внешний вид и другие атрибуты ресурсов, используемых в программе. Хотя вы можете писать файлы ресурсов в текстовом редакторе, это довольно тяжело. Лучшая альтернатива ― использовать редактор ресурсов, который позволит визуально создавать дизайн ваших ресурсов не отвлекаясь на текстовую рутину. Редакторы ресурсов обычно входят в пакет с IDE, таких как Visual C++, Borland C++ и т.д.
В ресурсах меню описано примерно так:
Кликните здесь для просмотра всего текста
C
1
2
3
4
       MyMenu  MENU
       {
         [menu list here]
       }
Си-программисты могут заметить, что это похоже на объявление структуры.
MyMenu ― это имя меню, за ним следует ключевое слово MENU и список пунктов меню, заключенный в фигурные скобки. Вместо них вы можете использовать BEGIN и END. Этот вариант больше понравится программистам на Паскале.
Список меню включает в себя выражения 'MENUITEM' или 'POPUP'.
  • 'MENUITEM' определяет пункт меню, который не является подменю. Его синтаксис следующий:
    Кликните здесь для просмотра всего текста
    C
    1
    
           MENUITEM "&tex", ID [,options]
    Выражение начинается ключевым словом 'MENUITEM', за который следует текст, который будет отображаться. Обратите внимание на & (амперсанд). Его действие заключается в том, что следующий за ним символ будет подчеркнут. Затем идет строка в качестве ID пункта меню. ID ― это номер, который будет использоваться для обозначения пункта меню в сообщении, посылаемое процедуре окно, когда этот пункт меню будет выбран. Каждое ID должно быть уникальным.
    Доступны следующие опции:
    • GRAYED ― пункт меню неактивен, и он не генерирует сообщение WM_COMMAND. Текст серого цвета.
    • INACTIVE ― пункт меню неактивен, и он не генерирует сообщение WM_COMMAND. Текст отображается нормально.
    • MENUBREAK ― этот пункт меню и последующие пункты отображаются после новой строки меню.
    • HELP ― этот пункт меню и последующие пункты выравнены по правой стороне.
    Вы можете использовать одну из вышеописанных опций или комбинировать их оператором "or". Учтите, что 'INACTIVE' и 'GRAYED' не могут комбинироваться вместе.
  • Выражение 'POPUP' имеет следующий синтаксис:
    Кликните здесь для просмотра всего текста
    C
    1
    2
    3
    4
    
       POPUP "&text" [,options]
       {
         [menu list]
       }
    Выражение 'POPUP' определяет пункт меню, при выборе которого выпадает список пунктов в маленьком popup-окне. Список меню может быть выражением 'MENUITEM' или 'POPUP'. Есть специальный вид выражения 'MENUITEM' ― 'MENUITEM SEPARATOR', который отрисовывает горизонтальную линию в popup-окне.
  • Последний шаг ― это ссылка на ваш скрипт ресурса меню в программе.
Вы можете сделать это в двух разных местах.
  • В поле lрszMenuName структуры WNDCLASSEX. Скажем, если у вас было меню под названием "FirstMenu", вы можете присоединить меню к вашему окну следующим образом:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    
                   .DATA
                       MenuName  db "FirstMenu",0
                   ...........................
                   ...........................
                   .CODE
                       ...........................
                       mov   wc.lpszMenuName, OFFSET MenuName
                       ...........................
  • С помощью параметра-хэндла меню в функции CreateWindowEx:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
                   .DATA
                       MenuName  db "FirstMenu",0
                       hMenu HMENU ?
                   ...........................
                   ...........................
                   .CODE
                       ...........................
                       invoke LoadMenu, hInst, OFFSET MenuName
                       mov   hMenu, eax
                       invoke CreateWindowEx,NULL,OFFSET ClsName,OFFSET Caption,\
                       WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,\
                       CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,hInst,NULL
                       ...........................
В чем разница между этими двумя методами? Когда делается ссылка на меню в структуре WNDCLASSEX, меню становится "меню по умолчанию" для данного класса окна. Каждое окно этого класса будет иметь такое меню.
Если вы хотите, чтобы каждое окно, созданное из одного класса, имело разное меню, вы можете выбрать второй вариант. В этом случае, любое окно, которому передается хэндл меню в функции CreateWindowEx будет иметь меню, которое замещает меню по умолчанию, указанное в структуре WNDCLASSEX. Сейчас мы узнаем, как меню уведомляет процедуру окна о том, что пользователь выбрал пункт меню.
Когда пользователь выберет пункт меню, процедура окна получит сообщение WM_COMMAND. Младшее слово wParam'а содержит ID выбранного пункта меню.
Теперь у нас достаточно информации для того, чтобы создать и использовать меню. Давайте сделаем это.
ПРАКТИКА, СЕСТРА ШИЗОФРЕНИИ
Первый пример показывает нам как создать и использовать меню, указав имя меню в классе окна.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
   .386
   .model flat,stdcall
   option casemap:none
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
 
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
 
   .data
   ClassName db "SimpleWinClass",0
   AppName  db "Our First Window",0
   MenuName db "FirstMenu",0               ; The name of our menu in the resource file.
   Test_string db "You selected Test menu item",0
   Hello_string db "Hello, my friend",0
   Goodbye_string db "See you again, bye",0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
 
   .const
   IDM_TEST equ 1                    ; Menu IDs
   IDM_HELLO equ 2
   IDM_GOODBYE equ 3
   IDM_EXIT equ 4
 
   .code
   start:       invoke GetModuleHandle, NULL
       mov    hInstance,eax
       invoke GetCommandLine
 
       mov CommandLine,eax
       invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
       invoke ExitProcess,eax
 
   WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
       LOCAL wc:WNDCLASSEX
       LOCAL msg:MSG
       LOCAL hwnd:HWND
 
       mov   wc.cbSize,SIZEOF WNDCLASSEX
       mov   wc.style, CS_HREDRAW or CS_VREDRAW
       mov   wc.lpfnWndProc, OFFSET WndProc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_WINDOW+1
       mov   wc.lpszMenuName,OFFSET MenuName        ; Put our menu name here
       mov   wc.lpszClassName,OFFSET ClassName
       invoke LoadIcon,NULL,IDI_APPLICATION
       mov   wc.hIcon,eax
       mov   wc.hIconSm,eax
       invoke LoadCursor,NULL,IDC_ARROW
       mov   wc.hCursor,eax
 
       invoke RegisterClassEx, addr wc
       invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
              WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,\
              CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInst,NULL
       mov   hwnd,eax
       invoke ShowWindow, hwnd,SW_SHOWNORMAL
       invoke UpdateWindow, hwnd
       .WHILE TRUE
                   invoke GetMessage, ADDR msg,NULL,0,0
                   .BREAK .IF (!eax)
                   invoke DispatchMessage, ADDR msg
       .ENDW
       mov     eax,msg.wParam
       ret
   WinMain endp
 
   WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
       .IF uMsg==WM_DESTROY
           invoke PostQuitMessage,NULL
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .IF ax==IDM_TEST
               invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK
           .ELSEIF ax==IDM_HELLO
               invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK
           .ELSEIF ax==IDM_GOODBYE
               invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK
           .ELSE
               invoke DestroyWindow,hWnd
           .ENDIF
       .ELSE
           invoke DefWindowProc,hWnd,uMsg,wParam,lParam
           ret
       .ENDIF
       xor    eax,eax
       ret
   WndProc endp
   end start
Menu.rc
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   #define IDM_TEST 1
   #define IDM_HELLO 2
   #define IDM_GOODBYE 3
   #define IDM_EXIT 4
 
   FirstMenu MENU
    {
      POPUP "&PopUp"
           {
            MENUITEM "&Say Hello",IDM_HELLO
            MENUITEM "Say &GoodBye", IDM_GOODBYE
            MENUITEM SEPARATOR
            MENUITEM "E&xit",IDM_EXIT
           }
      MENUITEM "&Test", IDM_TEST
   }
Разбор полетов
Давайте сначала проанализируем файл ресурсов.
Кликните здесь для просмотра всего текста
C
1
2
3
4
   #define IDM_TEST 1                /* все равно, что IDM_TEST equ 1*/
   #define IDM_HELLO 2
   #define IDM_GOODBYE 3
   #define IDM_EXIT 4
Вышенаписанные строки определяют ID пунктов меню. Вы можете присваивать ID любое значение, главное, чтобы оно было уникально.
Кликните здесь для просмотра всего текста
Assembler
1
   FirstMenu MENU
Определите ваше меню ключевым словом 'MENU'.
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
    POPUP "&PopUp"
           {
             MENUITEM "&Say Hello",IDM_HELLO
             MENUITEM "Say &GoodBye", IDM_GOODBYE
             MENUITEM SEPARATOR
             MENUITEM "E&xit",IDM_EXIT
           }
Определите рoрuр-меню с четырьмя пунктами меню, третье ― это разделитель пунктов меню.
Кликните здесь для просмотра всего текста
Assembler
1
   MENUITEM "&Test", IDM_TEST
Определите пункт меню в основном меню.
Далее мы изучим исходный код.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
   MenuName db "FirstMenu",0                ; Имя нашего меню в файле ресурсов
   Test_string db "You selected Test menu item",0
   Hello_string db "Hello, my friend",0
   Goodbye_string db "See you again, bye",0
'MenuName' ― это имя меню в файле ресурсов. Заметьте, что вы можете определить более, чем одно меню в файле ресурсов, поэтому вы можете указывать, какое меню хотите использовать. Остающиеся три строки определяют текстовые строки, которые будут отображаться в messagebox'е при выборе соответствующего пункта меню пользователем.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
   IDM_TEST equ 1                    ; ID меню
   IDM_HELLO equ 2
   IDM_GOODBYE equ 3
   IDM_EXIT equ 4
Определите ID меню для использования в процедуре окна. Эти значения должны совпадать с теми, что были определены в файле ресурсов.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .IF ax==IDM_TEST
             invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK
           .ELSEIF ax==IDM_HELLO
             invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK
           .ELSEIF ax==IDM_GOODBYE
             invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK
           .ELSE
             invoke DestroyWindow,hWnd
           .ENDIF
В процедуре окна мы обрабатываем сообщение WM_COMMAND. Когда пользователь выбирает пункт меню, его ID посылается процедуре окна в нижнем слове wParam'а вместе с сообщением WM_COMMAND. Поэтому, когда мы сохраняем значение wParam в eax, мы сравниваем значение в ax с ID пунктов меню, определенными ранее, и поступаем соответствующим образом. В первых трех случаях, когда пользователь выбирает 'Test', 'Say Hell' и 'Say GoodBye', мы отображаем текстовую строку в MessageBox'е.
Если пользователь выбирает пункт 'Exit', мы вызываем DestroyWindow с хэндлом нашего окна в качестве его параметра, которое закрывает наше окно.
Как вы можете видеть, указание имени меню в классе окна довольно просто и прямолинейно. Тем не менее, вы также можете использовать альтернативный метод для того, чтобы загружать меню в ваше окно. Я не буду воспроизводить здесь весь исходный код. Файл ресурсов такой же. Есть небольшие изменения в исходнике, которые я покажу ниже.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   hMenu HMENU ?                    ; handle of our menu
Определите переменную типа HMENU, чтобы сохранить хэндл нашего меню.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
           invoke LoadMenu, hInst, OFFSET MenuName
           mov    hMenu,eax
           INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
              WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
              CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,\
              hInst,NULL
Перед вызовом CreateWindowEx, мы вызываем LoadMenu, передавая ему хэндл процесса и указатель на имя меню. LoadMenu возвращает хэндл нашего меню, который мы передаем CreateWindowEx.
____________________________
© Iczelion, пер. Aquila.
4
Вложения
Тип файла: zip tut08-1.zip (3.3 Кб, 100 просмотров)
Тип файла: zip tut08-2.zip (3.3 Кб, 80 просмотров)
Mikl___
Заблокирован
Автор FAQ
08.01.2013, 12:34  [ТС] #27
Win32 API. Урок 8a. Создание меню через файл ресурсов
В этом туториале мы научимся, как вставить в наше окно меню.
Скачайте пример.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
.686P 
.model flat
includelib user32.lib
includelib kernel32.lib
include windows.inc
;вызываемые функции Windows (внешние ссылки)
extern _imp__CreateWindowExA@48:dword;создание окна
extern _imp__DefWindowProcA@16:dword;стандартная обработка сообщения
extern _imp__DispatchMessageA@4:dword;отправка сообщения
extern _imp__GetMessageA@16:dword;получение сообщения
extern _imp__ExitProcess@4:dword;выход из программы
extern _imp__RegisterClassA@4:dword;регистрация класса окна
extern _imp__MessageBoxA@16:dword
.const
IDM_TEST    equ 0
IDM_HELLO   equ 1
IDM_GOODBYE equ 2
IDM_EXIT    equ 3
.code
start:  xchg ebx,eax
    mov edi,offset wTitle
        mov esi,400000h
    push edi   ; Указатель на имя нашего класса
    push offset MenuName ;Меню
    push COLOR_WINDOW+1  ;Фон нашего окна
    push 10011h ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    push ebx    ;Иконка окна по умолчанию
    push esi;Адрес нашей программы в памяти - Windows всегда её грузит 
;по этому адресу
    push ebx  ;Эта хрень нам не нужна
    push ebx  ;и эта тоже
    push offset WndProc ;Адрес процедуры обработки событий
    push ebx  ; Стиль нашего окна
    push esp  ;&WNDCLASSA 
    call _imp__RegisterClassA@4
    push ebx       
    push esi
        shl esi,9;esi=CW_USEDEFAULT
    push ebx    
    push ebx    
    push esi    
    push esi    
    push esi    
    push esi    
    push WS_OVERLAPPEDWINDOW + WS_VISIBLE
    push edi; szWinTitle            
    push edi; lpszClassName
    push ebx
    call _imp__CreateWindowExA@48   ;создать окно
    mov ebp,esp
message_loop: push ebx  ;цикл обработки сообщений
    push ebx
    push ebx
    push ebp 
    call _imp__GetMessageA@16   
    push ebp
    call _imp__DispatchMessageA@4     ;вернуть управление Windows        
    jmp short message_loop
;----------------------------------------------------------------
WndProc:
Msg equ dword ptr [esp+8]
hwnd    equ dword ptr [esp+10h];поправка на аргументы, 
wParam  equ dword ptr [esp+0Ch];которые передаются MessageBox 
 
    mov eax,Msg
        dec eax;cmp eax,WM_DESTROY=2
    dec eax
    je short @@WM_DESTROY
        sub eax,WM_COMMAND-WM_DESTROY
    je short @@WM_COMMAND
        jmp _imp__DefWindowProcA@16
@@WM_DESTROY: push eax;0          ;завершение программы
    call _imp__ExitProcess@4
@@WM_COMMAND: mov ebx,wParam
        cmp ebx,IDM_EXIT
        je short @@WM_DESTROY
    push eax;MB_OK
    push offset MenuName
    push menu_handlers[ebx*4]
    push hwnd
    call _imp__MessageBoxA@16
    retn 10h
;----------------------------------------------------------
wTitle db 'создание меню через файл ресурсов',0
MenuName    db "FirstMenu",0
Test_string db "You selected Test menu item",0
Hello_string    db "Hello, my friend",0
Goodbye_string  db "See you again, bye",0
menu_handlers   dd Test_string, Hello_string, Goodbye_string
end start
Для работы с ресурсами нам потребуется создать файл с таким же именем, но с расширением .RC, ниже показано его содержимое
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define IDM_TEST 0
#define IDM_HELLO 1
#define IDM_GOODBYE 2
#define IDM_EXIT 3
 
FirstMenu MENU
{
 POPUP "&PopUp"
        {
         MENUITEM "&Say Hello",IDM_HELLO
         MENUITEM "Say &GoodBye", IDM_GOODBYE
         MENUITEM SEPARATOR
         MENUITEM "E&xit",IDM_EXIT
        }
 MENUITEM "&Test", IDM_TEST
}
Перед тем как заниматься основной программой, давайте посмотрим на файл ресурсов приложения Menu.rc, содержание которого приведено в листинге. Файлы ресурсов можно создавать в текстовом виде (при условии, что вы знакомы с их синтаксисом), а можно воспользоваться редактором ресурсов. Важно понимать, что файл ресурсов ― это обычный текстовый файл. После его создания его компилируют и превращают в двоичный файл с расширением .RES.
Важно!
Комментарии в файлах ресурсов, как и комментарии в программах на C++, начинаются с двойного символа наклонной черты.
В следующих четырех строках определяются четыре константы
Кликните здесь для просмотра всего текста
C
1
2
3
4
#define IDM_TEST 0
#define IDM_HELLO 1
#define IDM_GOODBYE 2
#define IDM_EXIT 3
Константы соответствуют идентификаторам ресурсов, с помощью которых программа обращается к коммандам меню. Точно такие же идентификаторы есть и в основном файле
Кликните здесь для просмотра всего текста
C
1
2
3
4
IDM_TEST    equ 0
IDM_HELLO   equ 1
IDM_GOODBYE equ 2
IDM_EXIT    equ 3
Важно чтобы в разные файлы включались одни и те же идентификаторы.
Добавление меню в класс окна
Далее вы должны указать меню в классе окна. Если взглянуть на определение структуры WNDCLASS в основном приложении, можно найти следующую строку
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    . . .
    push edi   ; Указатель на имя нашего класса
    push offset MenuName ;Меню
    push COLOR_WINDOW+1  ;Фон нашего окна
    push 10011h ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    push ebx    ;Иконка окна по умолчанию
    push esi;Адрес нашей программы в памяти -- Windows всегда её грузит 
;по этому адресу
    push ebx  ;Эта хрень нам не нужна
    push ebx  ;и эта тоже
    push offset WndProc ;Адрес процедуры обработки событий
    push ebx  ; Стиль нашего окна
    push esp  ;&WNDCLASSA
    call _imp__RegisterClassA@4
    . . .
MenuName    db "FirstMenu",0
То же имя должно быть и в файле ресурсов
Кликните здесь для просмотра всего текста
C
1
2
FirstMenu MENU
{
Добавление имени меню в структуру WNDCLASS ― это все что требуется для установления связи между приложением и меню.
Обработка команд меню
Теперь, когда в главном окне нашего приложения появилось меню, вам наверняка хочется знать, как реагировать на действия пользователя при выполнении им определенной команды. При выполнении команды меню Windows посылает вашему приложению сообщение ― в данном случае WM_COMMAND. Это означает, что вы должны включить в процедуру окна обработку сообщения WM_COMMAND. Когда приложение получает сообщение WM_COMMAND в параметре wParam хранится идентификатор выполненной команды меню.
При выборе пунктов меню "Say Hello", "Say GoodBye" и "Test" должны быть выведены мессаджбоксы с сообщениями "Hello, my friend", "See you again, bye" и "You selected Test menu item" соответственно, а при выборе пункта меню "Exit" мы должны закрыть приложение.

Iczelion на нашем месте три раза повторяет одинаковые фрагменты
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .IF ax==IDM_TEST
             invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK
           .ELSEIF ax==IDM_HELLO
             invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK
           .ELSEIF ax==IDM_GOODBYE
             invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK
           .ELSE
             invoke DestroyWindow,hWnd
           .ENDIF
А мы будем только менять сообщение у мессаджбокса в зависимости от содержимого wParam и если wParam=IDM_EXIT перейдем на обработку сообщения WM_DESTROY. Простенько, но со вкусом!
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
@@WM_COMMAND: mov ebx,wParam
        cmp ebx,IDM_EXIT
        je short @@WM_DESTROY
    push eax;MB_OK
    push offset MenuName
    push menu_handlers[ebx*4]
    push hwnd
    call _imp__MessageBoxA@16
    . . .
Test_string db "You selected Test menu item",0
Hello_string    db "Hello, my friend",0
Goodbye_string  db "See you again, bye",0
menu_handlers   dd Test_string, Hello_string, Goodbye_string
Небольшие пояснения
  • к моменту перехода на @@WM_COMMAND в регистре eax ноль, константа MB_OK=0, команда push 0 это два байта (6800h), а push eax ― это один байт (50h)
  • содержимое регистра ebx=wParam является индексом в таблице адресов menu_handlers:
    menu_handlers[0]=offset Test_string,
    menu_handlers[4]=offset Hello_string,
    menu_handlers[8]=offset Goodbye_string
Сам себе компилятор ресурсов.
Теперь уменьшим размер с 972 до 892 байт за счет уменьшения размера заголовка и ручной сборки ресурсов.
Скачайте ещё один пример.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
.686p
.model tiny,stdcall
;for WinXP - 892 bytes
include windows.inc
exebase     equ 400000h
IDM_TEST    equ 0
IDM_HELLO   equ 1
IDM_GOODBYE equ 2
IDM_EXIT    equ 3
ID_MENU     equ 30
POPUP       equ 10h
MFR_END     equ 80h
MFR_POPUP   equ 1
du  macro string
local bslash
bslash=0
    irpc c,<string>
    if bslash eq 0
        if '&c' eq "/"
            bslash=1
        elseif '&c' gt 127
        db ('&c'- 0B0h),4
        else
        dw '&c'
        endif
    else
           bslash=0
           if '&c' eq "n"
           DW 0Dh,0Ah
           elseif '&c' eq "/"
           dw '/'
           elseif '&c' eq "r"
           dw 0Dh
           elseif '&c' eq "l"
           dw 0Ah
           elseif '&c' eq "s"
           dw 20h
           elseif '&c' eq "c"
           dw 3Bh
           elseif '&c' eq "t"
           dw 9
       endif
    endif
    endm
    dw 0
endm
.code
main:
include capito_res.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov edi,offset wTitle+exebase
        mov esi,exebase
    invoke RegisterClass,esp,ebx,offset WndProc+exebase,ebx,ebx,esi,ebx,\
    10011h,COLOR_WINDOW+1,offset MenuName+exebase,edi
    push ebx       
    push esi
        shl esi,9;esi=CW_USEDEFAULT
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW + WS_VISIBLE,\
    esi,esi,esi,esi,ebx,ebx
    mov ebp,esp
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx;цикл обработки сообщений
    invoke DispatchMessage,ebp     ;вернуть управление Windows        
    jmp short message_loop
;----------------------------------------------------------------
WndProc:
Msg equ dword ptr [esp+8]
hwnd    equ dword ptr [esp+10h];поправка на аргументы, 
wParam  equ dword ptr [esp+0Ch];которые передаются MessageBox 
 
    mov eax,Msg
        dec eax;cmp eax,WM_DESTROY=2
    dec eax
    je short @@WM_DESTROY
        sub eax,WM_COMMAND-WM_DESTROY
    je short @@WM_COMMAND
        jmp DefWindowProc+exebase
@@WM_DESTROY: invoke ExitProcess,eax;0          ;завершение программы
@@WM_COMMAND: mov ebx,wParam
        cmp ebx,IDM_EXIT
        je short @@WM_DESTROY
    invoke MessageBox,hwnd,menu_handlers[ebx*4+exebase],\
    offset MenuName+exebase,eax
    retn 10h
;----------------------------------------------------------
wTitle db 'создание меню через файл ресурсов',0
MenuName    db "FirstMenu",0
Test_string db "You selected Test menu item",0
Hello_string    db "Hello, my friend",0
Goodbye_string  db "See you again, bye",0
menu_handlers   dd Test_string+exebase, Hello_string+exebase, Goodbye_string+exebase
;-------------------------------------------------------
align 2
resource:
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0;номер типа ресурса
dw x-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление второго уровня. В 1-ом слове смещение второго оглавления 
;относительно начала раздела ресурсов
x:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 1;количество ресурсов с именами
NumberOfIdEntries2  dw 0;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw 88,8000h
dw x1-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
x1:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 16 * SUBLANG_ + LANG_
dw (LANG_ENGLISH or SUBLANG_ENGLISH_CAN*100h),0,x2-resource,0
x2:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu1
Size1       dd end_menu-menu1
CodePage1   dd 0
Reserved1   dd 0 
dw 9;количество букв в слове FIRSTMENU
du <FIRSTMENU>
dw 0;выравниваем размер до четного количества слов
menu1:
dw 0,0,POPUP
du <&PopUp>
dw MFT_STRING or MFS_ENABLED,IDM_HELLO
du <&Say Hello>
dw MFT_STRING or MFS_ENABLED,IDM_GOODBYE
du <Say &GoodBye>
dw 0,0,0;NOTEXT
dw MFT_STRING or MFS_ENABLED or MFR_END,IDM_EXIT
du <E&xit>
dw MFT_STRING or MFS_ENABLED or MFR_END,IDM_TEST
du <&Test>
dw 0,0
end_menu:
end_resource:
import: 
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
MessageBox      dd _MessageBox
DefWindowProc           dd _DefWindowProc
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_MessageBox     db 0,0,'MessageBoxA'
_DefWindowProc      db 0,0,'DefWindowProcA',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
_____________________________________
© Mikl___ 2013
4
Вложения
Тип файла: zip tut08a-01.zip (3.6 Кб, 92 просмотров)
Mikl___
Заблокирован
Автор FAQ
09.01.2013, 11:49  [ТС] #28
Win32 API. Урок 8 b. Создание меню через функцию LoadMenu
В этом туториале вы увидите еще один способ вставить меню в окно.
Скачайте пример.
Этот способ Iczelion назвал альтернативным методом для того, чтобы загружать меню в окно. Исходный код практически такой же как в уроке 8а. Файл ресурсов такой же.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
.686P 
.model flat
includelib user32.lib
includelib kernel32.lib
include windows.inc
extern _imp__CreateWindowExA@48:dword
extern _imp__DefWindowProcA@16:dword
extern _imp__DispatchMessageA@4:dword
extern _imp__GetMessageA@16:dword
extern _imp__ExitProcess@4:dword
extern _imp__RegisterClassA@4:dword
extern _imp__LoadMenuA@8:dword
extern _imp__MessageBoxA@16:dword
.const
IDM_TEST    equ 0
IDM_HELLO   equ 1
IDM_GOODBYE equ 2
IDM_EXIT    equ 3
.code
start:  xor ebx,ebx
    mov edi,offset wTitle
        mov esi,400000h
    push edi    ; Указатель на имя нашего класса
    push ebx    ; Меню в WNDCLASS не предусмотрено
    push COLOR_WINDOW+1  ;Фон нашего окна
    push 10011h ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    push ebx    ;Иконка окна по умолчанию
    push esi;Адрес нашей программы в памяти -- Windows всегда её грузит 
;по этому адресу
    push ebx  ;Эта хрень нам не нужна
    push ebx  ;и эта тоже
    push offset WndProc ;Адрес процедуры обработки событий
    push ebx  ; Стиль нашего окна
    push esp  ;&WNDCLASSA 
    call _imp__RegisterClassA@4
    push ebx       
    push esi        ;hInst для CreateWindowEx
    push offset MenuName
    push esi        ;hInst для LoadMenu
    call _imp__LoadMenuA@8
    push eax    ; handle of our menu    
    push ebx
        shl esi,9;esi=CW_USEDEFAULT 
    push esi    
    push esi    
    push esi    
    push esi    
    push WS_OVERLAPPEDWINDOW + WS_VISIBLE
    push edi; szWinTitle            
    push edi; lpszClassName
    push ebx
    call _imp__CreateWindowExA@48   ;создать окно
    mov ebp,esp
message_loop: push ebx  ;цикл обработки сообщений
    push ebx
    push ebx
    push ebp 
    call _imp__GetMessageA@16   
    push ebp
    call _imp__DispatchMessageA@4     ;вернуть управление Windows        
    jmp short message_loop
;----------------------------------------------------------------
WndProc:
Msg equ dword ptr [esp+8]
hwnd    equ dword ptr [esp+10h];поправка на аргументы, 
wParam  equ dword ptr [esp+0Ch];которые передаются MessageBox 
 
    mov eax,Msg
        dec eax;cmp eax,WM_DESTROY=2
    dec eax
    je short @@WM_DESTROY
        sub eax,WM_COMMAND-WM_DESTROY
    je short @@WM_COMMAND
        jmp _imp__DefWindowProcA@16
@@WM_DESTROY: push eax;0          ;завершение программы
    call _imp__ExitProcess@4
@@WM_COMMAND: mov ebx,wParam
        cmp ebx,IDM_EXIT
        je short @@WM_DESTROY
    push eax;MB_OK
    push offset MenuName
    push menu_handlers[ebx*4]
    push hwnd
    call _imp__MessageBoxA@16
    retn 10h
;----------------------------------------------------------
wTitle db 'создание меню через функцию LoadMenu',0
MenuName    db "FirstMenu",0
Test_string db "You selected Test menu item",0
Hello_string    db "Hello, my friend",0
Goodbye_string  db "See you again, bye",0
menu_handlers   dd Test_string, Hello_string, Goodbye_string
end start
Для работы с ресурсами нам потребуется создать файл с таким же именем, но с расширением .RC, ниже показано его содержимое
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define IDM_TEST 0
#define IDM_HELLO 1
#define IDM_GOODBYE 2
#define IDM_EXIT 3
 
FirstMenu MENU
{
 POPUP "&PopUp"
        {
         MENUITEM "&Say Hello",IDM_HELLO
         MENUITEM "Say &GoodBye", IDM_GOODBYE
         MENUITEM SEPARATOR
         MENUITEM "E&xit",IDM_EXIT
        }
 MENUITEM "&Test", IDM_TEST
}
Для большей убедительности уберем указатель на имя меню из определения структуры WNDCLASS
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
    push edi    ; Указатель на имя нашего класса
    push ebx    ; Меню в WNDCLASS не предусмотрено
    push COLOR_WINDOW+1  ;Фон нашего окна
    push 10011h ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    push ebx    ;Иконка окна по умолчанию
    push esi;Адрес нашей программы в памяти -- Windows всегда её грузит 
;по этому адресу
    push ebx  ;Эта хрень нам не нужна
    push ebx  ;и эта тоже
    push offset WndProc ;Адрес процедуры обработки событий
    push ebx  ; Стиль нашего окна
    push esp  ;&WNDCLASSA 
    call _imp__RegisterClassA@4
вызываем LoadMenu, передавая ему хэндл процесса и указатель на имя меню. LoadMenu возвращает хэндл нашего меню, который мы передаем CreateWindowEx.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    push ebx       
    push esi        ;hInst для CreateWindowEx
    push offset MenuName
    push esi        ;hInst для LoadMenu
    call _imp__LoadMenuA@8
    push eax    ; handle of our menu
    push ebx
        shl esi,9;esi=CW_USEDEFAULT 
    push esi    
    push esi    
    push esi    
    push esi    
    push WS_OVERLAPPEDWINDOW + WS_VISIBLE
    push edi; szWinTitle            
    push edi; lpszClassName
    push ebx
    call _imp__CreateWindowExA@48   ;создать окно
Теперь уменьшим размер с 1000 до 919 байт за счет уменьшения размера заголовка и ручной сборки ресурсов.
Скачайте ещё один пример.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
.686p
.model tiny,stdcall
;for WinXP - 919 bytes
include windows.inc
exebase     equ 400000h
IDM_TEST    equ 0
IDM_HELLO   equ 1
IDM_GOODBYE equ 2
IDM_EXIT    equ 3
ID_MENU     equ 30
POPUP       equ 10h
MFR_END     equ 80h
MFR_POPUP   equ 1
du  macro string
local bslash
bslash=0
    irpc c,<string>
    if bslash eq 0
        if '&c' eq "/"
            bslash=1
        elseif '&c'gt 127
        db ('&c'- 0B0h),4
        else
        dw '&c'
        endif
    else
           bslash=0
           if '&c' eq "n"
           DW 0Dh,0Ah
           elseif '&c' eq "/"
           dw '/'
           elseif '&c' eq "r"
           dw 0Dh
           elseif '&c' eq "l"
           dw 0Ah
           elseif '&c' eq "s"
           dw 20h
           elseif '&c' eq "c"
           dw 3Bh
           elseif '&c' eq "t"
           dw 9
       endif
    endif
    endm
    dw 0
endm
.code
main:
include capito_res.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov edi,offset wTitle+exebase
        mov esi,exebase
    invoke RegisterClass,esp,ebx,offset WndProc+exebase,ebx,ebx,esi,ebx,\
    10011h,COLOR_WINDOW+1,ebx,edi
    invoke LoadMenu,esi,offset MenuName+exebase,esi,ebx
        shl esi,9;esi=CW_USEDEFAULT
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW + WS_VISIBLE,\
    esi,esi,esi,esi,ebx,eax
    mov ebp,esp
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx;цикл обработки сообщений
    invoke DispatchMessage,ebp     ;вернуть управление Windows        
    jmp short message_loop
;----------------------------------------------------------------
WndProc:
Msg equ dword ptr [esp+8]
hwnd    equ dword ptr [esp+10h];поправка на аргументы, 
wParam  equ dword ptr [esp+0Ch];которые передаются MessageBox 
 
    mov eax,Msg
        dec eax;cmp eax,WM_DESTROY=2
    dec eax
    je short @@WM_DESTROY
        sub eax,WM_COMMAND-WM_DESTROY
    je short @@WM_COMMAND
        jmp DefWindowProc+exebase
@@WM_DESTROY: invoke ExitProcess,eax;0          ;завершение программы
@@WM_COMMAND: mov ebx,wParam
        cmp ebx,IDM_EXIT
        je short @@WM_DESTROY
    invoke MessageBox,hwnd,menu_handlers[ebx*4+exebase],\
    offset MenuName+exebase,eax
    retn 10h
;----------------------------------------------------------
wTitle db 'создание меню через функцию LoadMenu',0
MenuName    db "FirstMenu",0
Test_string db "You selected Test menu item",0
Hello_string    db "Hello, my friend",0
Goodbye_string  db "See you again, bye",0
menu_handlers   dd Test_string+exebase, Hello_string+exebase, Goodbye_string+exebase
;-------------------------------------------------------
align 2
resource:
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0;номер типа ресурса
dw x-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление второго уровня. В 1-ом слове смещение второго оглавления 
;относительно начала раздела ресурсов
x:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 1;количество ресурсов с именами
NumberOfIdEntries2  dw 0;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw 88,8000h
dw x1-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
x1:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 16 * SUBLANG_ + LANG_
dw 409h,0,x2-resource,0
x2:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu1
Size1       dd end_menu-menu1
CodePage1   dd 0
Reserved1   dd 0 
dw 9
du <FIRSTMENU>
dw 0
menu1:
dw 0,0,POPUP
du <&PopUp>
dw MFT_STRING or MFS_ENABLED,1
du <&Say Hello>
dw MFT_STRING or MFS_ENABLED,2
du <Say &GoodBye>
dw 0,0,0;NOTEXT
dw MFT_STRING or MFS_ENABLED or MFR_END,3
du <E&xit>
dw MFT_STRING or MFS_ENABLED or MFR_END,0
du <&Test>
dw 0,0
end_menu:
end_resource:
import: 
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
MessageBox      dd _MessageBox
LoadMenu        dd _LoadMenu
DefWindowProc           dd _DefWindowProc
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_MessageBox     db 0,0,'MessageBoxA'
_LoadMenu       db 0,0,'LoadMenuA'
_DefWindowProc      db 0,0,'DefWindowProcA',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
______________________________
© Mikl___ 2013


Win32 API. Урок 8 с. Имитация меню через toolbar
Еще один способ создать меню.
Скачайте пример.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
.586p
.model tiny
include windows.inc
;for WinXP - 1327 bytes
.code
exebase     equ 400000h
ZZZ_TEST    equ 0
ZZZ_OPEN    equ 1
ZZZ_SAVE    equ 2
ZZZ_EXIT    equ 3
 
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    sub esp,sizeof(INITCOMMONCONTROLSEX)
    mov dword ptr [esp+INITCOMMONCONTROLSEX.dwSize],sizeof(INITCOMMONCONTROLSEX)
    mov dword ptr [esp+INITCOMMONCONTROLSEX.dwICC],ICC_BAR_CLASSES
    invoke InitCommonControlsEx,esp
    add esp,sizeof(INITCOMMONCONTROLSEX)
    invoke GlobalAlloc,40h,1024; memory buffer size
    xchg esi,eax
    mov edi, esi
    mov dword ptr [edi],WS_OVERLAPPED or WS_SYSMENU or DS_CENTER or 40h
    mov word ptr [edi+8],1    ; number of controls
    mov word ptr [edi+0Ah],50 ; x y co-ordinates
    mov word ptr [edi+0Ch],50
    mov word ptr [edi+0Eh],230
    mov word ptr [edi+10h],100
    add edi, 16h
    invoke MultiByteToWideChar,ebx,1,offset wTitle+exebase,\
    -1,edi,aMsSansSerif-wTitle        ;cchWideChar
    add edi,(aMsSansSerif-wTitle)*2; 1Ah
    mov word ptr [edi],10 ;pointsize
    inc edi;add edi, 2
    inc edi
    invoke MultiByteToWideChar,ebx,1,offset aMsSansSerif+exebase,\
    -1,edi,aMsctls_statusb-aMsSansSerif; cchWideChar
    add edi,(aMsctls_statusb-aMsSansSerif)*2+4-1
    and edi,-4 ;align 4=add edi,4-1 /and edi,-4
    mov dword ptr [edi], 50000000h
    mov word ptr [edi+10h],150  ;DlgStatus=150
    add edi, 12h
    invoke MultiByteToWideChar,ebx,1,offset aMsctls_statusb+exebase,\
    -1,edi,aToolbarwindow3-aMsctls_statusb   ; cchWideChar
    invoke DialogBoxIndirectParam,exebase,esi,ebx,\
        offset DialogFunc+exebase,ebx    ; dwInitParam=0
    invoke GlobalFree,esi; hMem
    retn
;================================================================
DialogFunc:
hDlg    equ esp+4
uMsg    equ esp+8
wParam  equ esp+0Ch
lParam  equ esp+10h
 
    xor ebx,ebx
    mov eax,[uMsg]
    mov edi,[hDlg]
    sub eax,WM_CLOSE ;cmp uMsg,10h
    jz wmCLOSE
    sub eax,WM_INITDIALOG-WM_CLOSE;cmp uMsg,110h
    jz wmINITDIALOG
    dec eax     ;cmp uMsg,111h
    jnz wmBye
wmCOMMAND: mov ebx,[wParam]
    cmp ebx,ZZZ_EXIT;03
    je wmCLOSE;menu_exit
show_msg: invoke MessageBox,edi,[menu_handlers+ebx*4]+exebase,\
        offset menu_name+exebase,eax
    jmp short wmBye
wmINITDIALOG: mov esi,offset SendMessage+exebase
    push ebx
    push 1
    push -128
    push edi;      ; hDlg
    call dword ptr [esi];SendMessageA
    invoke GetStockObject,SYSTEM_FIXED_FONT
    push TRUE
    push eax
    push WM_SETFONT
    push edi      ; hWndParent
    call text_bar
    push edi    ;hToolbar
    call dword ptr [esi];SendMessageA
    jmp short wmBye
;----------------------------------------------------------------
wmCLOSE: invoke EndDialog,edi,ebx
wmBye:  xchg eax,ebx
    retn 10h
;-------------------------------------------------------------
text_bar: invoke CreateWindowEx,ebx,offset aToolbarwindow3+exebase,ebx,\    
    WS_CHILD or WS_VISIBLE or TBSTYLE_TOOLTIPS or TBSTYLE_FLAT or \
    TBSTYLE_LIST or TBSTYLE_TRANSPARENT,ebx,ebx,500,20,\
        dword ptr [esp+10h],ebx,exebase,ebx
    xchg edi,eax;edi:=[TBhWnd]
    push ebx
    push sizeof (TBBUTTON)
    push TB_BUTTONSTRUCTSIZE
    push edi;TBhWnd      
    call dword ptr [esi]
 
    push ebx
    push 5
    push TB_SETINDENT
    push edi
    call dword ptr [esi]
 
    ;esp=&tbb
    sub esp,sizeof(TBBUTTON);создаем буфер под структуру TBBUTTON
    mov dword ptr [esp+TBBUTTON.iBitmap],I_IMAGENONE
    mov [esp+TBBUTTON.dwData],ebx
    mov [esp+TBBUTTON.iString],ebx
    mov byte ptr [esp+TBBUTTON.fsStyle],BTNS_BUTTON or BTNS_AUTOSIZE;byte [edi+9],10h;
    mov byte ptr [esp+TBBUTTON.fsState],TBSTATE_ENABLED
;TxtItem  0,  0, "Test"
    mov [esp+TBBUTTON.idCommand],ebx ;0
    push esp
    push 1
    push TB_ADDBUTTONS
    push edi      ; hWnd
    call dword ptr [esi]
    push offset aTest+exebase
    push ebx
    push TB_ADDSTRING
    push edi      ; hWnd
    call dword ptr [esi]
;TxtItem  1,  1, "Open"
    inc dword ptr [esp+TBBUTTON.idCommand]
    inc dword ptr [esp+TBBUTTON.iString]
    push esp
    push 1
    push TB_ADDBUTTONS
    push edi      ; hWnd
    call dword ptr [esi]
    push offset aOpen+exebase
    push ebx
    push TB_ADDSTRING
    push edi      ; hWnd
    call dword ptr [esi]
;TxtItem  2,  2, "Save"
    inc dword ptr [esp+TBBUTTON.idCommand]
    inc dword ptr [esp+TBBUTTON.iString]
    push esp
    push 1
    push TB_ADDBUTTONS
    push edi      ; hWnd
    call dword ptr [esi]
    push offset aSave+exebase
    push ebx
    push TB_ADDSTRING
    push edi      ; hWnd
    call dword ptr [esi]
;TxtSeperator
    mov [esp+TBBUTTON.idCommand],ebx; 0
    mov byte ptr [esp+TBBUTTON.fsStyle],BTNS_SEP;byte [edi+9],1;
    push esp
    push 1
    push TB_ADDBUTTONS
    push edi      ; hWnd
    call dword ptr [esi]
;TxtItem  4,  3, "Exit"
    add dword ptr [esp+TBBUTTON.idCommand], 3h
    mov byte ptr [esp+TBBUTTON.fsStyle],BTNS_BUTTON or BTNS_AUTOSIZE
    inc dword ptr [esp+TBBUTTON.iString]
    push esp
    push 1
    push TB_ADDBUTTONS
    push edi      ; hWnd
    call dword ptr [esi]
    push offset aExit+exebase
    push ebx
    push TB_ADDSTRING
    push edi      ; hWnd
    call dword ptr [esi]
    add esp,sizeof(TBBUTTON);уничтожаем буфер
    retn 4
;----------------------------------------------------------------
wTitle db 'Iczelion Tutorial #8-3:Иммитация меню через toolbar в MASM',0 ;name of our window
aMsSansSerif    db  'MS Sans Serif',0
aMsctls_statusb db  'msctls_statusbar32',0
aToolbarwindow3 db  'ToolbarWindow32',0 
aTest db 'Test',0
aOpen db 'Open',0
aSave db 'Save',0
aExit db 'Exit',0
 
menu_name db 'ZZZ_Menu',0
test_msg  db 'You select menu item TEST',0
open_msg  db 'You select menu item OPEN',0
save_msg  db 'You select menu item SAVE',0
menu_handlers dd test_msg+exebase, open_msg+exebase, save_msg+exebase
;----------------------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0,0,gdi32_dll
dd gdi32_table
dd 0,0,0,comctl32_dll
dd comctl32_table
dd 0,0
comctl32_table:
InitCommonControlsEx    dd _InitCommonControlsEx,0
user32_table:
DialogBoxIndirectParam  dd _DialogBoxIndirectParam
LoadIcon            dd _LoadIcon
EndDialog           dd _EndDialog
CreateWindowEx          dd _CreateWindowEx
SendMessage             dd _SendMessage
MessageBox      dd _MessageBox,0
gdi32_table:
GetStockObject      dd _GetStockObject,0
kernel32_table:
GlobalAlloc     dd _GlobalAlloc
MultiByteToWideChar dd _MultiByteToWideChar
GlobalFree      dd _GlobalFree
                        dw 0
_CreateWindowEx     db 0,0,'CreateWindowExA'
_SendMessage        db 0,0,'SendMessageA'
_DialogBoxIndirectParam db 0,0,"DialogBoxIndirectParamA"
_LoadIcon           db 0,0,"LoadIconA"
_EndDialog          db 0,0,"EndDialog"
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
_GlobalAlloc        db 0,0,"GlobalAlloc"
_MultiByteToWideChar    db 0,0,"MultiByteToWideChar"
_GlobalFree     db 0,0,"GlobalFree",0
kernel32_dll        db 'kernel32'
_InitCommonControlsEx   db 0,0,"InitCommonControlsEx",0
comctl32_dll        db 'comctl32'
_GetStockObject     db 0,0,"GetStockObject",0
gdi32_dll       db 'gdi32'
end_import:
end main
________________________
© Mikl___ 2013


Win32 API. Урок 8 d. Программное создание меню
В этом туториале мы научимся, создавать меню программно, при помощи функций CreateMenu, CreatePopupMenu, AppendMenu, SetMenu
Скачайте пример.
Теория ― мать склероза
Меню чаще всего описывается в файле ресурсов, так как в этом случае облегчается задача изменения его состава или пунктов меню. Но в некоторых случаях может оказывается более удобным создавать меню программно, без помощи редактора и компилятора ресурсов. Программное создание меню включает следующие действия:
  1. создание линейки меню приложения (пока пустой) функцией CreateMenu с получением дескриптора этого меню;
  2. создание «всплывающего» меню для помещения в него требуемого набора пунктов меню (но пока тоже пустого и без названия) функцией CreatePopupMenu с получением дескриптора «всплывающего» меню;
  3. заполнение «всплывающего» меню при помощи функции AppendMenu пунктами меню.
    Функции AppendMenu передается четыре параметра:
    • первым параметром указывается дескриптор всплывающего меню;
    • вторым параметром указывается константа MF_STRING (или MF_SEPARATOR для разделительной линии);
    • третьим параметром ― идентификатор данного пункта меню;
    • четвертым параметром ― адрес строки текста, представляющего собой название пункта меню
      (для разделительной линии передается значение NULL).
  4. включение «всплывающего» меню в линейку меню при помощи функции AppendMenu и передачи этой функции:
    • первым параметром имени «всплывающего» меню;?
    • вторым параметром указывается константа MF_POPUP;
    • третьим ― дескриптор «всплывающего» меню;
    • четвертым ― адрес строки с названием «всплывающего» меню;
  5. присоединение всего меню к главному окну приложения функцией SetMenu.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
.586p
.model tiny
include windows.inc
;for WinXP - 872 bytes
.code
exebase     equ 400000h
ZZZ_TEST    equ 0
ZZZ_OPEN    equ 1
ZZZ_SAVE    equ 2
ZZZ_EXIT    equ 3
 
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+\
    exebase,ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ebx,edi
;--------------------------+
; creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW \
    or WS_VISIBLE,esi,esi,esi,esi,ebx,ebx
    push eax;сохраним hWnd в стеке
    invoke CreatePopupMenu
    xchg edi,eax;mov edi,eax;    mov hPopupMenu,eax
    lea esi,AppendMenu+exebase
    push 5
    pop ebp;ebp=5
    push offset menu_exit1+exebase
    push ZZZ_EXIT
    push ebx
    push ebx
    push offset menu_save1+exebase
    push ZZZ_SAVE
    push offset menu_open1+exebase
    push ZZZ_OPEN
    push offset menu_test1+exebase
    push ebx
@@: push ebx
    push edi;hPopupMenu
    call dword ptr [esi];AppendMenu
    dec ebp
    jnz @b
    invoke CreateMenu,MF_POPUP,edi,offset menu_file+exebase
    xchg edi,eax;mov edi,hMenu
    push edi;hMenu
    call dword ptr [esi];AppendMenu
    push offset menu_exit1+exebase
    push ZZZ_EXIT
    push ebx
    push edi;hMenu
    call dword ptr [esi];AppendMenu
    pop eax;возвращаем hWnd
    invoke SetMenu,eax,edi
    mov ebp,esp
;---------------------------+
; entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
; the window procedure |
;----------------------+
window_procedure:
hWnd    equ esp+4
uMsg    equ esp+8
wParam  equ esp+0Ch
    mov eax,[uMsg]
    dec eax
    dec eax; cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_COMMAND-WM_DESTROY; cmp uMsg,WM_PAINT
    je @@WM_COMMAND
    jmp DefWindowProc+exebase
@@WM_COMMAND: mov ebx,[wParam]
    cmp ebx,ZZZ_EXIT
    je @@WM_DESTROY;menu_exit
    invoke MessageBox,dword ptr [hWnd+12],menu_handlers[ebx*4]+exebase,\
    offset menu_name+exebase,eax 
    retn 10h
@@WM_DESTROY: invoke ExitProcess,ebx
;--------------------------------------------------------------------
menu_file  db '&File',0
menu_test1 db '&Test',0
menu_open1 db '&Open',0
menu_save1 db '&Save',0
menu_exit1 db 'E&xit',0
menu_name db 'ZZZ_Menu',0
test_msg  db 'You select menu item TEST',0
open_msg  db 'You select menu item OPEN',0
save_msg  db 'You select menu item SAVE',0
menu_handlers dd test_msg+exebase, open_msg+exebase, save_msg+exebase
wTitle db 'Iczelion Tutorial #8-4:Программное создание меню в MASM'
;----------------------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
CreateMenu      dd _CreateMenu
CreatePopupMenu     dd _CreatePopupMenu
AppendMenu      dd _AppendMenu
SetMenu         dd _SetMenu
MessageBox      dd _MessageBox
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_CreateMenu     db 0,0,'CreateMenu'
_CreatePopupMenu    db 0,0,'CreatePopupMenu'
_AppendMenu     db 0,0,'AppendMenuA'
_SetMenu        db 0,0,"SetMenu"
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
 
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
Функция CreatePopupMenu создает «всплывающее» меню, подменю или контекстное меню. Меню вначале пустое. Вы можете вставлять или добавлять в конец пункты меню при помощи использования функции InsertMenuItem. Вы можете также использовать функцию InsertMenu, чтобы вставить пункты меню, а функцию AppendMenu, чтобы добавлять в конец пункты меню.
Функция CreateMenu создает меню. Меню вначале пустое, но оно может быть заполнено пунктами меню при помощи использования функций InsertMenuItem, AppendMenu и InsertMenu.
Функция SetMenu связывает новое меню с заданным окном.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
BOOL SetMenu
(       HWND hWnd,  // дескриптор окна
    HMENU hMenu // дескриптор меню
);
Параметры
  • hWnd идентифицирует окно, с которым должно быть связано меню.
  • hMenu идентифицирует новое меню. Если этот параметр имеет значение ПУСТО (NULL), текущее меню окна удаляется.
Функция AppendMenu добавляет в конец определяемой строки меню, «всплывающего» меню, подменю или контекстного меню новый пункт. Вы можете использовать эту функцию, чтобы определить содержание, внешний вид и характеристики пункта меню.
Функция AppendMenu была заменена функцией InsertMenuItem. Вы можете все еще использовать AppendMenu, в том случае, если Вы не нуждаетесь в какой-либо из расширенных функций InsertMenuItem.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
BOOL AppendMenu(
    HMENU hMenu,    // дескриптор меню, который будет изменен
    UINT uFlags,    // флажки пункта меню
    UINT uIDNewItem,// идентификатор пункта меню или дескриптор 
            // "всплывающего" меню или подменю
    LPCTSTR lpNewItem// пункт контекстного меню
);
Параметры
  • hMenu ― идентифицирует строку меню, «всплывающее» меню, подменю или контекстное меню, которое будет изменено.
  • uFlags ― определяет флажки, которые управляют внешним видом и характеристиками нового пункта меню. Этот параметр может быть комбинация значений, перечисленных в разделе Замечаний ниже.
  • uIDNewItem ― Определяет или идентификатор нового пункта меню или, если параметр uFlags установлен в MF_POPUP, дескриптор «всплывающего» меню или подменю.
  • lpNewItem ― Определяет содержание нового пункта меню. Интерпретация lpNewItem зависит от того, включает ли параметр uFlags в себя флажок MF_BITMAP, MF_OWNERDRAW или MF_STRING, как указано ниже:
MF_BITMAP Содержит дескриптор растрового рисунка.
MF_OWNERDRAW Содержит 32-разрядное значение, предоставленное прикладной программой, которое может быть использовано, чтобы утвердить, что дополнительные данные касаются пункта меню. Значение является полем itemData структуры, указываемой параметром lParam при помощи передачи сообщения WM_MEASURE или WM_DRAWITEM, когда создается меню, или его внешний вид модифицируется.
MF_STRING Содержит указатель на строку с символом нуля в конце.
Возвращаемые значения
  • Если функция завершается успешно, величина возвращаемого значения ― не ноль.
  • Если функция не выполняет задачу, величина возвращаемого значения ― ноль. Чтобы получать расширенные данные об ошибках, вызовите GetLastError.
Замечания
Прикладная программа должна вызывать функцию DrawMenuBar всякий раз, когда меню изменяется, независимо от того, находится оно или нет в отображаемом окне.

Следующие флажки могут быть установлены в параметре uFlags:
MF_BITMAP Использует точечный рисунок как пункт меню. Параметр lpNewItem содержит дескриптор точечного рисунка.
MF_CHECKED Помещает галочку рядом с пунктом меню. Если прикладная программа предоставляет значки «галочки» (см. SetMenuItemBitmaps), этот флажок показывает на экране точечный рисунок галочки рядом с пунктом меню.
MF_DISABLED Отключает пункт меню, так что он не может быть выбран, но флажок не окрашивает его в серый цвет.
MF_ENABLED Включает пункт меню, так что он может быть выбран и восстанавливает его из недоступного состояния.
MF_GRAYED Отключает пункт меню и окрашивает его в серый цвет (делает недоступным), так что он не может быть выбран.
MF_MENUBARBREAK Исполняет такую же функцию, как и флажок MF_MENUBREAK для строки меню. Для «всплывающего» меню, подменю или контекстного меню, новый столбец отделяется от старого столбца вертикальной линией.
MF_MENUBREAK Помещает пункт в новую строку (для строки меню) или в новом столбце (для «всплывающего» меню, подменю, или контекстного меню) без разделения столбцов.
MF_OWNERDRAW Определяет, что пункт является «собственным» пунктом (нарисованным пользователем). Перед тем как меню отображается впервые, окно, которое владеет им, получает сообщение WM_MEASUREITEM, чтобы извлечь данные о ширине и высоте пункта меню. Сообщение WM_DRAWITEM затем отправляется в оконную процедуру окна владельца всякий раз, когда внешний вид пункта меню должен модифицироваться.
MF_POPUP Определяет, что пункт меню открывает «всплывающее» меню или подменю. Параметр uIDNewItem определяет дескриптор «всплывающего» меню или подменю. Этот флажок используется, чтобы добавить имя меню в строке меню, или пункт меню, который открывает подменю «всплывающего» меню, подменю или контекстное меню.
MF_SEPARATOR Рисует горизонтальную разделительную линию. Этот флажок используется только во «всплывающем» меню, подменю или контекстном меню. Строка не может быть недоступна, заблокирована, или выделена. Параметры lpNewItem и uIDNewItem игнорируются.
MF_STRING Определяет, что пункт меню ― текстовая строка; параметр lpNewItem указывает на строке.
MF_UNCHECKED Удаляет галочку рядом с пунктом (значение по умолчанию). Если прикладная программа предоставляет точечные рисунки (значки) «галочки» (см. SetMenuItemBitmaps), этот флажок показывает на экране снятую метку «галочки» рядом с пунктом меню.
_________________________________
© Mikl___ 2013


Win32 API. Урок 8 e. Создание динамического меню
Во многих программах меню может динамически изменяться во время работы ― исчезают и добавляются пункты меню, одно меню встраивается в другое и т.п. Пример простейших манипуляций с меню приведен в этом туториале.
Скачайте пример.
Теория:
В приложение открывается окно с кнопкой и «пустым» меню (MENU3). При нажатии на кнопку появляется одно меню (MENU1), которое сменяется следующим меню (MENU2), которое заменяет «пустое» меню (MENU3) и т.д. по кругу. При передвижении по меню название его пунктов и заголовков выпадающих (popup) подменю отображается в заголовке окна
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
.586p
.model tiny
include windows.inc
;for WinXP - 1530 bytes
du  macro string
local bslash
bslash=0
    irpc c,<string>
    if bslash eq 0
        if '&c' eq "/"
            bslash=1
        elseif '&c'gt 127
        db ('&c'- 0B0h),4
        else
        dw '&c'
        endif
    else
           bslash=0
           if '&c' eq "n"
           DW 0Dh,0Ah
           elseif '&c' eq "/"
           dw '/'
           elseif '&c' eq "r"
           dw 0Dh
           elseif '&c' eq "l"
           dw 0Ah
           elseif '&c' eq "s"
           dw 20h
           elseif '&c' eq "c"
           dw 3Bh
           elseif '&c' eq "t"
           dw 9
       endif
    endif
    endm
    dw 0
    endm
 
.code
exebase     equ 400000h
ZZZ_EXIT    equ 5
ID_MENU1    equ 10h
ID_MENU2    equ 11h
ID_MENU3    equ 12h
main:
include capito_res.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;-----------------------------+
; registering the window class| 
;-----------------------------+
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ID_MENU3,edi
;--------------------------+
; creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW \
    or WS_VISIBLE,esi,esi,esi,esi,ebx,ebx
    invoke CreateWindowEx,ebx,offset name2+exebase,offset name1+\
        exebase,BS_DEFPUSHBUTTON or WS_VISIBLE or WS_CHILD,10,10,120,\
    25,eax,ebx,esi,ebx
    mov HWNDBTN+exebase,eax;запомнить дескриптор кнопки
    mov ebp,esp
;---------------------------+
; entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
; the window procedure |
;----------------------+
window_procedure:
hWnd    equ ebp+8
uMsg    equ ebp+0Ch
wParam  equ ebp+10h
lParam  equ ebp+14h
MENI    equ ebp-sizeof(MENUITEMINFO)
buffer  equ MENI-100
    enter (100+sizeof(MENUITEMINFO)),0
    mov eax,[uMsg]
        mov edi,[hWnd]
    dec eax
    dec eax     ;cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_COMMAND-WM_DESTROY; cmp uMsg,WM_PAINT
    je @@WM_COMMAND
    sub eax,WM_MENUSELECT-WM_COMMAND
    je @@WM_MENUSELECT
    leave
    jmp DefWindowProc+exebase
@@WM_COMMAND: mov eax,HWNDBTN+exebase;проверить, не нажата ли кнопка
    cmp [lParam],eax
    je YES_BUT
    cmp word ptr [wParam],ZZZ_EXIT;проверить, не выбран ли пункт 
;меню MENUC - выход
    je @@WM_DESTROY
    cmp word ptr [wParam],4;проверить, не выбран ли пункт меню 
    jne @@WM_BYE;с идентификатором 4
YES_BUT:;обработка нажатия кнопки. сначала стереть текст в заголовке
    invoke SendMessage,edi,WM_SETTEXT,ebx,offset SPACE+exebase
    dec PRIZN+exebase
    cmp PRIZN+exebase,0Fh
    jne @f
    add PRIZN+exebase,3;if (PRIZN < 10h) PRIZN=12h
@@: invoke LoadMenu,exebase,PRIZN+exebase;загрузить необходимое меню
    invoke SetMenu,edi,eax;установить меню 
    jmp @@WM_BYE
@@WM_MENUSELECT: mov ecx,[lParam]
    jecxz @@WM_BYE;пропускаем первое сообщение при обращении к меню
    test word ptr [wParam+2],MF_POPUP;проверяем, что активизировано - пункт 
;меню или заголовок выпадающего меню
    setne al
;заполнение структуры для вызова функции GetMenuItemInfo
    lea esi,[MENI]
        assume esi: ptr MENUITEMINFO
    mov dword ptr [esi].cbSize,sizeof(MENUITEMINFO)
    mov dword ptr [esi].fMask,MIIM_TYPE
    mov [esi].hSubMenu,ecx;MENI.hSubMenu:=lParam
    mov [esi].dwTypeData,esp
;указатель на буфер, получающий необходимую строку
    mov dword ptr [esi].cch,100;sizeof.buffer;длина буфера
    push esi;получить информацию о выбранном пункте меню
    push eax
;если 0, то в lword wParam идентификатор пункта меню
;если 1, то в lword wParam номер заголовка выпадающего меню
    movzx eax,word ptr [wParam]
    invoke GetMenuItemInfo,ecx,eax
;проверить результат выполнения функции
    xchg eax,ecx;cmp eax,0
    jecxz @@WM_BYE
;вывести название пункта меню как заголовок всего окна
    invoke SendMessage,edi,WM_SETTEXT,ebx,[esi].dwTypeData
        assume esi: nothing
@@WM_BYE: leave  
    retn 10h
@@WM_DESTROY: invoke ExitProcess,ebx
;--------------------------------------------------------------------
name1 db "Сменить меню",0
name2 db "BUTTON",0
wTitle db 'Iczelion Tutorial #8-5:Создание динамического меню в MASM'
SPACE db 50 dup(20h),0
HWNDBTN dd ?
PRIZN dd 12h;инициализировали счетчик
;12h- загружено меню MENU3
;11h- загружено меню MENU2
;10h- загружено меню MENU1
;--------------------------------------------------------------------
MFR_END     equ 80h
POPUP       equ 10h
MENUBREAK       equ 40h
align 2
resource:
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0;номер типа ресурса
dw m1-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление второго уровня. В 1-ом слове смещение второго оглавления 
;относительно начала раздела ресурсов
m1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 3;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw ID_MENU1,0
dw m21-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
dw ID_MENU2,0
dw m22-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
dw ID_MENU3,0
dw m23-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
m21:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 256 * SUBLANG_ + LANG_
dw 40Ah,0,m31-resource,0
m22:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 256 * SUBLANG_ + LANG_
dw 40Ah,0,m32-resource,0
m23:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 256 * SUBLANG_ + LANG_
dw 40Ah,0,m33-resource,0
m31:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu1
Size1       dd end_menu1-menu1
CodePage1   dd 0
Reserved1   dd 0
m32:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData2   dd menu2
Size2       dd end_menu2-menu2
CodePage2   dd 0
Reserved2   dd 0
m33:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData3   dd menu3
Size3       dd end_menu3-menu3
CodePage3   dd 0
Reserved3   dd 0
menu1 dw 0,   0,POPUP
du <Первый пункт>
dw MFT_STRING  or  MFS_ENABLED,1
du <Первый>
dw MFT_STRING  or  MFS_ENABLED  or  MFR_END,2
du <Второй>
dw MFR_END or POPUP;,0
du <Второй пункт>
dw MFT_STRING  or  MFS_ENABLED,3
du <Третий>
dw MFT_STRING  or  MFS_ENABLED,4
du <Четвертый>
dw MENUBREAK,0,0;NOTEXT
dw MFT_STRING  or  POPUP
du <Еще подменю>
dw MFT_STRING  or  MFS_ENABLED or  MFR_END,6
du <Дополнительный пункт>
dw MFT_STRING  or  MFS_ENABLED or  MFR_END,ZZZ_EXIT
du <Выход>
end_menu1:
 
menu2 dw 0,   0,POPUP
du <Набор первый>
dw MFT_STRING  or  MFS_ENABLED,101
du <Белый>
dw MFT_STRING or MFS_ENABLED,102
du <Серый>
dw MFT_STRING or MFS_ENABLED  or  MFR_END,103
du <Черный>
dw MFR_END or POPUP;,0
du <Набор второй>
dw MFT_STRING or MFS_ENABLED,104
du <Красный>
dw MFT_STRING or MFS_ENABLED,105
du <Синий>
dw MFT_STRING or MFS_ENABLED or MFR_END,106
du <Зеленый>
end_menu2:
 
menu3 dw 0,0,MFR_END,106
du <>
end_menu3:
 
end_resource:
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
DestroyWindow           dd _DestroyWindow
LoadMenu        dd _LoadMenu
GetMenuItemInfo     dd _GetMenuItemInfo
SetMenu         dd _SetMenu
SendMessage     dd _SendMessage
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_DestroyWindow      db 0,0,"DestroyWindow"
_LoadMenu       db 0,0,"LoadMenuA"
_SetMenu        db 0,0,"SetMenu"
_GetMenuItemInfo    db 0,0,'GetMenuItemInfoA'
_SendMessage        db 0,0,"SendMessageA",0
 
user32_dll      db 'user32'
 
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
В ресурсах программы находятся три меню. Ресурсы мы создали сами не используя компилятор ресурсов.
Важно! Адрес начала сегмента ресурсов должен начинаться с адреса кратного 2. Поэтому перед началом секции ресурсов
Кликните здесь для просмотра всего текста
Assembler
1
2
align 2
resource:      . . .
Так как при построении ресурсов (например меню) все надписи должны быть в UNICODE используется макрос du (define unicode string) для перевода CP-1251 Windows кодировки в UNICODE
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
du  macro string
    irpc c,
    if '&c' gt 127
    db ('&c'- 0B0h),4
    else
    dw '&c'
    endif
    endm
    dw 0
    endm
В переменной PRIZN хранится состояние меню:
  • 12h ― загружено меню MENU3
  • 11h ― загружено меню MENU2
  • 10h ― загружено меню MENU1
Начальное состояние обеспечивается заданием меню при регистрации класса окна
Кликните здесь для просмотра всего текста
Assembler
1
2
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ID_MENU3,edi
При нажатии на кнопку происходит циклическое изменение значения PRIZN от 12h к 11h, далее 10h и снова 12h
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
    dec PRIZN+exebase
    cmp PRIZN+exebase,0Fh
    jne @f
    add PRIZN+exebase,3;if (PRIZN < 10h) PRIZN=12h
@@:     . . .
При определении названия выбранного пункта меню приходит сообщение WM_MENUSELECT.
При активизации меню приходит сообщение WM_MENUSELECT со значением lParam, которое определяет идентификатор меню равным нулю.
Кликните здесь для просмотра всего текста
Assembler
1
2
    mov ecx,[lParam]
    jecxz @@WM_BYE;пропускаем первое сообщение при обращении к меню
При получении сообщения WM_MENUSELECT в младшем слове параметра wParam может содержаться либо идентификатор пункта меню, либо номер заголовка выпадающего меню. Определить, что выбрано, можно по старшему слову параметра wParam
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    test word ptr [wParam+2],MF_POPUP
;проверяем, что активизировано - пункт меню или заголовок выпадающего меню
    setne al
    . . .
    push esi;получить информацию о выбранном пункте меню
    push eax
;если 0, то в lword wParam идентификатор пункта меню
;если 1, то в lword wParam номер заголовка выпадающего меню
    movzx eax,word ptr [wParam]
    invoke GetMenuItemInfo,ecx,eax;ecx=[lParam]
;проверить результат выполнения функции
    xchg eax,ecx;cmp eax,0
    jecxz @@WM_BYE
;вывести название пункта меню как заголовок всего окна
после команды setne выполняющейся после test регистр al установится в 1 или сбросится в 0. Далее, для получения строки-названия используется функция GetMenuItemInfo. Третьим параметром этой функции как раз и может быть либо ноль, либо единица. Если ноль, то второй параметр ― это идентификатор пункта меню, если единица, то второй параметр ― номер заголовка выпадающего меню. Четвертым параметром является указатель на структуру, которая и будет заполняться в результате выполнения функции. Некоторые поля этой структуры должны быть заполнены заранее. Поле dwTypeData, которое должно содержать указатель на буфер, получающий необходимую нам строку. Поле cch должно содержать длину этого буфера. Для того чтобы поля idwTypeData и cch трактовались функцией как указатель на буфер и его длину, поля fMask и fType должны быть правильно заполнены. Поле cbSize должно содержать длину всей структуры.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
;заполнение структуры для вызова функции GetMenuItemInfo
    mov ecx,[lParam]
    . . .
    lea esi,[MENI]
        assume esi: ptr MENUITEMINFO
    mov dword ptr [esi].cbSize,sizeof(MENUITEMINFO)
    mov dword ptr [esi].fMask,MIIM_TYPE
    mov [esi].hSubMenu,ecx;MENI.hSubMenu:=lParam
    mov [esi].dwTypeData,esp
;указатель на буфер, получающий необходимую строку
    mov dword ptr [esi].cch,100;sizeof.buffer;длина буфера
После получения нужной информации, то есть строки-названия пункта меню, при помощи функции SendMessage посылается сообщение WM_SETTEXT, которое дает команду установить заголовок окна.
Функция GetMenuItemInfo извлекает информацию о пункте меню.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
BOOL WINAPI GetMenuItemInfo(
    HMENU hMenu,
    UINT uItem,
    BOOL fByPosition,
    LPMENUITEMINFO lpmii
);
Параметры:
  • hMenu ― Дескриптор меню, которое содержит пункт меню.
  • uItem ― Идентификатор или позиция пункта меню, о котором надо получить информацию. Предназначение этого параметра зависит от значения fByPosition.
  • fByPosition ― Значение, определяющее предназначение uItem. Если этот параметр ― FALSE, uItem ― идентификатор пункта меню. Иначе, это ― позиция пункта меню.
  • lpmii ― Указатель на структуру MENUITEMINFO, которая определяет информацию, чтобы извлечь и получить информацию о пункте меню.
Возвращаемые значения
  • Если функция завершается успешно, величина возвращаемого значения отличная от нуля.
  • Если функция не выполняет задачу, величина возвращаемого значения нулевая. Чтобы получать расширенные данные об ошибках, используйте функцию GetLastError.
_____________________________________
© Mikl___ 2013


Win32 API. Урок 8 f. «Плавающее» меню
В этом туториале мы научимся, как вставить в наше окно меню.
Скачайте пример.
Теория ― мать склероза
В приложениях Windows широко используется «плавающее» меню (не путать с «всплывающим» меню (popup menu), являющимся элементом обычного меню), активизируемые обычно щелчком правой клавиши мыши. «Плавающее» меню появляется в том месте экрана, где в данный момент находится курсор мыши.
Поскольку «плавающее» меню должно активизироваться нажатием правой клавиши мыши, в оконную функцию следует включить обработку сообщения WM_RBUTTONDOWN, и все действия по созданию меню выполнить в функции обработки этого сообщения.
Установка «плавающего» меню почти не отличается от программного создания обычного статического меню и включает в себя следующие действия:
  1. создание «всплывающего» меню для помещения в него требуемого набора пунктов (пока пустого) функцией CreatePopupMenu с получением дескриптора «всплывающего» меню (линейка меню в этом случае не создается);
  2. заполнение «всплывающего» меню конкретными пунктами функцией AppendMenu в точности так же, как и при создании обычного меню. Поскольку линейки меню в этом случае нет, «всплывающее» меню ни к чему не подсоединяется;
  3. объявление созданного «всплывающего» меню «плавающим» при помощи функции TrackPopupMenu. Второй параметр этой функции задается равным 0. В качестве третьего и четвертого параметров указывают текущие координаты курсора мыши, пятый параметр ― дескриптор окна, шестой ― NULL
Для более точного позиционирования рекомендуют передавать экранные координаты мыши из структурной переменной MSG
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
.586p
.model tiny
include windows.inc
;for WinXP - 984 bytes
.code
exebase     equ 400000h
ZZZ_TEST    equ 0
ZZZ_OPEN    equ 1
ZZZ_SAVE    equ 2
ZZZ_EXIT    equ 3
 
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+\
    exebase,ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ebx,edi
;--------------------------+
; creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW \
    or WS_VISIBLE,esi,esi,esi,esi,ebx,ebx
    mov ebp,offset msg+exebase
;---------------------------+
; entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
; the window procedure |
;----------------------+
window_procedure:
hWnd    equ dword ptr [ebp+8]
uMsg    equ dword ptr [ebp+0Ch]
wParam  equ dword ptr [ebp+10h]
lParam  equ dword ptr [ebp+14h]
hMenu   equ dword ptr [ebp-4]
count   equ dword ptr [ebp-8]
    enter (sizeof(RECT)+8),0
 
    mov eax,uMsg
    dec eax
    dec eax; cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_COMMAND-WM_DESTROY; cmp uMsg,WM_PAINT
    je @@WM_COMMAND
        sub eax,WM_RBUTTONDOWN-WM_COMMAND;cmp uMsg,WM_RBUTTONDOWN
    je @@WM_RBUTTONDOWN
    leave
    jmp DefWindowProc+exebase
@@WM_RBUTTONDOWN: invoke CreatePopupMenu
    xchg edi,eax;    mov hPopupMenu,eax
        invoke CreateMenu
    mov hMenu,eax
    lea esi,AppendMenu+exebase
    mov count,5
    push offset menu_exit1+exebase
    push ZZZ_EXIT
    push ebx
    push ebx
    push offset menu_save1+exebase
    push ZZZ_SAVE
    push offset menu_open1+exebase
    push ZZZ_OPEN
        push offset menu_test1+exebase
    push ebx;ZZZ_TEST
@@: push ebx
    push edi;hPopupMenu
    call dword ptr [esi];AppendMenu
    dec count
    jnz @b
    push offset menu_file+exebase
    push edi;hPopupMenu
    push MF_POPUP
    push hMenu
    call dword ptr [esi];AppendMenu
    push offset menu_exit1+exebase
    push ZZZ_EXIT
    push ebx
    push hMenu
    call dword ptr [esi];AppendMenu
    mov eax,offset msg.pt.x+exebase
;второй параметр TrackPopupMenu uFlags равен TPM_LEFTALIGN or TPM_LEFTBUTTON, 
;что соответствует нулю
;третий и четвертый параметры TrackPopupMenu равны msg.pt.x и msg.pt.y соответственно
        invoke TrackPopupMenu,edi,ebx,\
    dword ptr [eax],dword ptr [eax+4],ebx,hWnd,ebx
    invoke GetWindowRect,hWnd,esp;rect
    jmp end_wm_check
@@WM_COMMAND: mov ebx,wParam
    cmp ebx,ZZZ_EXIT
    je @@WM_DESTROY;menu_exit
    invoke MessageBox,hWnd,menu_handlers[ebx*4]+exebase,\
    offset menu_name+exebase,eax
end_wm_check: leave 
    retn 10h
@@WM_DESTROY: invoke ExitProcess,ebx
;--------------------------------------------------------------------
menu_file   db '&File',0
menu_test1  db '&Test',0
menu_open1  db '&Open',0
menu_save1  db '&Save',0
menu_exit1  db 'E&xit',0
menu_name   db 'ZZZ_Menu',0
test_msg    db 'You select menu item TEST',0
open_msg    db 'You select menu item OPEN',0
save_msg    db 'You select menu item SAVE',0
menu_handlers   dd test_msg+exebase, open_msg+exebase, save_msg+exebase
msg     MSG &lt;&gt
wTitle db 'Iczelion Tutorial #8-6: Создание плавающего меню в MASM'
;--------------------------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
CreateMenu      dd _CreateMenu
CreatePopupMenu     dd _CreatePopupMenu
TrackPopupMenu      dd _TrackPopupMenu
GetWindowRect       dd _GetWindowRect
AppendMenu      dd _AppendMenu
MessageBox      dd _MessageBox
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_CreateMenu     db 0,0,'CreateMenu'
_CreatePopupMenu    db 0,0,'CreatePopupMenu'
_AppendMenu     db 0,0,'AppendMenuA'
_TrackPopupMenu     db 0,0,'TrackPopupMenu'
_GetWindowRect      db 0,0,'GetWindowRect'
_MessageBox     db 0,0,'MessageBoxA',0
user32_dll      db 'user32'
 
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
Функция TrackPopupMenu показывает на экране контекстное меню в заданном расположении и устанавливает выбор пунктов в меню. Контекстное меню может появляться в любом месте на экране.

Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
BOOL TrackPopupMenu(
    HMENU hMenu,        // дескриптор контекстного меню
    UINT uFlags,        // флажки расположения на экране и кнопки мыши
    int x,          // горизонтальная позиция в экранных координатах
    int y,          // вертикальная позиция в экранных координатах
    int nReserved,      // зарезервирован, должен быть ноль
    HWND hWnd,          // дескриптор окна владельца
    CONST RECT *prcRect     // указывает на RECT, которая определяет не освобожденную область
);
Параметры:
  • hMenu ― Идентифицирует контекстное меню, которое нужно отобразить. Дескриптор может быть получен путем вызова CreatePopupMenu, чтобы создать новое контекстное меню, или путем вызова GetSubMenu, чтобы извлечь дескриптор подменю, связанного с существующим пунктом меню.
  • uFlags ― Набор битовых флажков, которые определяют параметры функции.
    Используйте одну из следующих констант битовых флажков, чтобы определить, как функция установит контекстное меню по горизонтали:
    • TPM_CENTERALIGN (= 4) ― Если этот флажок установлен, функция выравнивает по центру горизонтали контекстное меню, относительно координаты, определяемой параметром x.
    • TPM_LEFTALIGN (= 0) ― Если этот флажок установлен, функция устанавливает контекстное меню так, чтобы его левая сторона была выровнена по координате, определяемой параметром x.
    • TPM_RIGHTALIGN (= 8) ― Устанавливает контекстное меню так, чтобы правая сторона была выровнена по координате, определяемой параметром x.
    Используйте одну из следующих констант битового флажка, чтобы определить, какой кнопкой мыши установится контекстное меню:
    • TPM_LEFTBUTTON (= 0) ― Если этот флажок установлен, контекстное меню устанавливается левой кнопкой мыши.
    • TPM_RIGHTBUTTON (= 2) ― Если этот флажок установлен, контекстное меню устанавливается правой кнопкой мыши.
  • x ― Определяет горизонтальное расположение контекстного меню, в экранной системе координат.
  • y ― Определяет вертикальное расположение контекстного меню, в экранной системе координат.
  • nReserved ― Зарезервировано; должен быть ноль.
  • hWnd ― Идентифицирует окно, которое владеет контекстным меню. Это окно принимает все сообщения от меню. Окно не получает сообщение WM_COMMAND от меню до тех пор, пока функция не возвратит значение.
  • prcRect ― Указывает на структуру RECT, которая определяет часть экрана, в которой пользователь может выбирать контекстное меню без ее освобождения. Если этот параметр имеет значение ПУСТО (NULL), контекстное меню освобождается, если пользователь щелкает кнопкой мыши вне контекстного меню.
Возвращаемые значения:
  • Если функция завершается успешно, величина возвращаемого значения ― не ноль.
  • Если функция не выполняет задачу, величина возвращаемого значения ― ноль. Чтобы получать расширенные данные об ошибках, вызовите GetLastError.
_____________________________
© Mikl___ 2013


Win32 API. Урок 8 g. Создание меню через Template-структуру
В этом туториале мы научимся, как обойтись без компилятора ресурсов и вставить в наше окно меню при помощи функции LoadMenuIndirect.
Скачайте пример.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
.586p
.model tiny
;for WinXP - 929 bytes
include windows.inc
exebase     equ 400000h
ZZZ_TEST    equ 0
ZZZ_OPEN    equ 1
ZZZ_SAVE    equ 2
ZZZ_EXIT    equ 3
MFR_END     equ 80h
MFR_POPUP   equ 1
 
du  macro string
local bslash
bslash=0
    irpc c,<string>
    if bslash eq 0
        if '&c' eq "/"
            bslash=1
        elseif '&c'gt 127
        db ('&c'- 0B0h),4
        else
        dw '&c'
        endif
    else
           bslash=0
           if '&c' eq "n"
           DW 0Dh,0Ah
           elseif '&c' eq "/"
           dw '/'
           elseif '&c' eq "r"
           dw 0Dh
           elseif '&c' eq "l"
           dw 0Ah
           elseif '&c' eq "s"
           dw 20h
           elseif '&c' eq "c"
           dw 3Bh
           elseif '&c' eq "t"
           dw 9
       endif
    endif
    endm
    dw 0
    endm
.code
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
        ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ebx,edi
    invoke LoadMenuIndirect,offset appMenuTemplate+exebase
;--------------------------+
;  creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
    esi,esi,esi,esi,ebx,eax
    mov ebp,esp
;---------------------------+
;  entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
;  the window procedure |
;----------------------+
window_procedure:
hWnd    equ esp+4
uMsg    equ esp+8
wParam  equ esp+0Ch
lParam  equ esp+10h
    mov eax,[uMsg]
    dec eax
    dec eax; cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_COMMAND-WM_DESTROY; cmp uMsg,WM_PAINT
    je @@WM_COMMAND
    jmp DefWindowProc+exebase
@@WM_COMMAND: mov ebx,[wParam]
    cmp ebx,ZZZ_EXIT
    je @@WM_DESTROY;menu_exit
    invoke MessageBox,dword ptr [hWnd+12],menu_handlers[ebx*4]+exebase,\
        offset menu_name+exebase,eax;MB_OK
    retn 10h
@@WM_DESTROY: invoke ExitProcess,ebx
     ;exp=experiment
wTitle db 'Iczelion Tutorial #8-3: Создание меню через Template-структуру в MASM',0 ;name of our window
menu_name db 'ZZZ_Menu',0
test_msg  db 'You select menu item TEST',0
open_msg  db 'You select menu item OPEN',0
save_msg  db 'You select menu item SAVE',0
menu_handlers dd test_msg+exebase, open_msg+exebase, save_msg+exebase
appMenuTemplate dw 1    ; menu template version
        dw 4    ; offset from end of this word to menu item list
        dd 0    ; menu bar help ID
        dd MFT_STRING,MFS_ENABLED,0
        dw MFR_POPUP; first column
        du <&File&>
        dw 0; pad to align 4
        dd 0; popup help ID
        dd MFT_STRING,MFS_ENABLED,ZZZ_TEST
        dw 0
        du <&Test>
        dw 0; pad to align 4
        dd MFT_STRING,MFS_ENABLED,ZZZ_OPEN
        dw 0
        du <&Open>
        dw 0; pad to align 4
        dd MFT_STRING,MFS_ENABLED,ZZZ_SAVE
        dw 0
        du <&Save>
        dw 0; pad to align 4
        dd MFT_SEPARATOR,0,0
        dw 0,0  ; pad to align 4
        dd MFT_STRING,MFS_ENABLED,ZZZ_EXIT
        dw MFR_END; bottom of column
        du <&Exit>
        dw 0    ; pad to align 4
        dd MFT_STRING,MFS_ENABLED,ZZZ_EXIT
        dw MFR_END     ; second column, last one
        du <&Exit>
        dw 0    ; pad to align 4
import:     
dd 0    ; popup help ID
;----------------------------------------------------------------------------------
dd 0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
LoadMenuIndirect    dd _LoadMenuIndirect
MessageBox      dd _MessageBox
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_LoadMenuIndirect   db 0,0,"LoadMenuIndirectA"
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
Меню может быть создано из шаблона меню, который формируется в памяти во время выполнения программы. Например, прикладная программа, которая позволяет пользователю настраивать свое меню, может создать шаблон меню в памяти, основанной на стандартных установках пользователя. Приложение может затем сохранить шаблон в файле или в системном реестре для будущего использования. Чтобы создать меню из шаблона в памяти, используют функцию LoadMenuIndirect. Это может быть полезно если ваша прикладная программа создает шаблоны меню динамически.
Синтаксис функции LoadMenuIndirect
Кликните здесь для просмотра всего текста
C
1
2
3
HMENU LoadMenuIndirect
{       CONST MENUTEMPLATE *lpMenuTemplate  // адрес шаблона меню
);
Параметр функции:
  • lpMenuTemplate - Указывает на шаблон или расширенный шаблон меню.
Стандартный шаблон меню состоит из структуры MENUITEMTEMPLATEHEADER, сопровождаемой одной или несколькими структурами MENUITEMTEMPLATE.
Расширенный шаблон меню состоит из структуры MENUEX_TEMPLATE_HEADER, сопровождаемой одной или несколькими структурами MENUEX_TEMPLATE_ITEM.
Структура MENUITEMTEMPLATEHEADER определяет заголовок для шаблона меню. Полный шаблон меню состоит из заголовка и одного или нескольких перечисляемых пунктов меню.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
typedef struct {            // mith
    WORD versionNumber; // номер версии, должен быть нуль
    WORD offset;        // смещение первой структуры MENUITEMTEMPLATE
} MENUITEMTEMPLATEHEADER;
Члены структуры
  • versionNumber Устанавливает номер версии. Этот член должен быть нулевой.
  • offset Устанавливает смещение, в байтах, от конца заголовка. Перечисление пунктов меню начинается с этого смещения. Обычно, этот член структуры нулевой, а список пунктов меню следует непосредственно после заголовка.
Замечания

Одна или несколько структур MENUITEMTEMPLATE объединяются, чтобы сформировать список пунктов меню.
Структура MENUEX_TEMPLATE_HEADER определяет заголовок расширенного шаблона меню.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
typedef struct  {
     WORD  wVersion;
     WORD  wOffset;
     DWORD dwHelpId;
} MENUEX_TEMPLATE_HEADER;
Члены структуры
  • wVersion Номер версии шаблона. Этот член должен быть равен 1 для расширенных шаблонов меню.
  • wOffset Смещение первой структуры MENUEX_TEMPLATE_ITEM, относительно конца этого члена структуры. Если первый пункт определяется непосредственно следом за членом dwHelpId, этот член должен быть равен 4.
  • dwHelpId Идентификатор пункта Справка (Help) горизонтального меню
Замечания

Расширенный шаблон меню состоит из структуры MENUEX_TEMPLATE_HEADER, сопровождаемой одной или несколькими следующими друг за другом структурами MENUEX_TEMPLATE_ITEM. Структуры MENUEX_TEMPLATE_ITEM, которые являются переменными в длине, выравниваются по границам двойного слова.

Структура MENUEX_TEMPLATE_ITEM определяет пункт меню в расширенном шаблоне.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
typedef struct {
    DWORD dwType;
    DWORD dwState;
    UINT uId;
    WORD bResInfo;
    WCHAR szText[1];
    DWORD dwHelpId;
 } MENUEX_TEMPLATE_ITEM;
Поля структуры:
  • dwType Тип пункта меню. Этот член может быть комбинацией типов (начинающихся с MFT) значений, перечисляемых структурой MENUITEMINFO.
  • dwState Состояние пункта меню. Этот член может быть комбинацией значений состояний (начинающихся с MFS), перечисляемых структурой MENUITEMINFO.
  • uId Идентификатор пункта меню. Это ― определяемое программой 16-разрядное значение, которое идентифицирует пункт меню. В расширенном ресурсе меню, пункты, которые открывают "выскакивающие" меню или подменю также как командные пункты могут иметь идентификаторы.
  • bResInfo Значение, устанавливающее, является ли пункт меню последним пунктом в горизонтальном, "выскакивающем" меню, подменю или контекстном меню и является ли он пунктом, который, открывает "выскакивающее" меню или подменю. Этот член может быть нулевым или иметь такие значения:
    • 80h - Структура определяет последний пункт меню в горизонтальном, "выскакивающем" меню, подменю или контекстном меню.
    • 01 - Структура определяет пункт, который открывает "выскакивающее" меню или подменю. Последующие структуры определяют пункты меню в соответствующем "выскакивающем" меню или подменю.
    Для 32-разрядных прикладных программ, этот член - WORD.
    • szText ― Текст пункта меню. Этот член, который является строкой UNICODE с нулевым символом в конце, выравнивается по границе слова. Размер пункта меню определяется вариантами, зависящими от длины этой строки.
    • dwHelpId ― Идентификатор Справки (Help) для "выскакивающего" меню или подменю. Этот член, который включается только для пунктов, которые открывают "выскакивающие" меню или подменю, помещается в начале границы двойного слова, следом за членом szText переменной длины.
Структура MENUITEMTEMPLATE определяет пункт меню в шаблоне меню.
Синтаксис
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
typedef struct {    // mit
    WORD mtOption;  // флажки пункта меню
    WORD mtID;// идентификатор пункта меню (опускается для пунктов
                // открывающих выскакивающее меню)
    WCHAR mtString[1];// строка с нулем в конце для пункта меню
} MENUITEMTEMPLATE;
Члены структуры:
  • mtOption ― Устанавливает один или несколько нижеследующих предопределенных параметров меню, которые управляют внешним видом пункта меню:
    • MF_CHECKED ― Указывает, что пункт меню рядом с собой имеет галочку.
    • MF_GRAYED ― Указывает, что пункт меню с самого начала неактивный и нарисован с серым эффектом (недоступен).
    • MF_HELP ― Указывает, что пункт меню имеет вертикальный разделитель со своей левой стороны.
    • MF_MENUBARBREAK ― Указывает, что пункт меню помещен в новом столбце. Старые и новые столбцы отделены полосой.
    • MF_MENUBREAK ― Указывает, что пункт меню помещен в новом столбце.
    • MF_OWNERDRAW ― Указывает, что окно владелец меню ответственно за прорисовку всех визуальных элементов пункта меню, включая выделение, установку "галочки" и неактивного состояния. Этот параметр не допустим для пункта в горизонтальном меню.
    • MF_POPUP ― Указывает, что это пункт один из тех, который, открывает "выскакивающее" меню или подменю.
  • mtID ― Устанавливает идентификатор командный пункта меню; командный пункт отправляет сообщение о команде своему окну владельцу. Структура MENUITEMTEMPLATE для пункта, который открывает "выскакивающее" меню или подменю, не содержит члена структуры.
  • mtString ― Устанавливает строку с символом нуля в конце для пункта меню.
________________________________
© Mikl___ 2013


Win32 API. Урок 8h. Работа с таблицей акселераторов
Скачайте пример.
Теория ― мать склероза
Включение акселераторов меню
Прежде чем закончить разговор о меню, следует упомянуть еще об одной возможности, связанной с меню. Это акселераторные клавиши, или акселераторы. Акселераторные клавиши ― клавиатурные комбинации, которые можно определить и которые, будучи нажаты, автоматически выбирают соответствующие им команды меню даже в том случае, когда мню не активировано и не отображается. При помощи акселератора можно выбирать соответствующий элемент меню, не обращаясь к самому меню. Термин акселератор является довольно точным, поскольку ввод команд с использованием таких клавиш осуществляется гораздо быстрее, чем активизация меню и выбор этих команд.
Для определения акселераторов необходимо добавить таблицу акселераторов в файл ресурсов. Все определения акселераторов имеют следующий общий вид:
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
ИмяТаблицы ACCELERATORS
{
Клавиша1, MenuID1 [, тип][, параметр] 
Клавиша2, MenuID2 [, тип][, параметр]
   . . .
КлавишаN, MenuIDN [, тип][, параметр]
}
  • Имя Таблицы является именем таблицы акселераторов;
  • Клавиша ― определяет клавишу или комбинацию клавиш акселератора;
  • MenuID ― идентификатор элемента меню;
  • тип ― указывает является ли клавиша стандартной (по умолчанию) или виртуальной;
  • параметр ― может быть одним из следующих макросов: NOINVERT, ALT, SHIFT и CONTROL. Наличие NOINVERT означает, что соответствующий элемент меню при использовании акселератора не будет подсвечен, даже если он присутствует на экране. ALT указывает, что должна быть дополнительно нажата клавиша [Alt]; SHIFT и CONTROL специфицируют дополнительное нажатие клавиш [Shift] и [Ctrl]. Клавиша может быть символом в кавычках, либо целочисленным десятичным ASCII-кодом символа, либо виртуальной клавишей. Если указывается символ в кавычках, предполагается использование ASCII-символа. Если используется десятичное число, следует уточнить, что это код ASCII-символа, задав тип как ASCII. Если предполагается использование виртуальной клавиши, то тип должен быть VIRTKEY.
    Если клавиша представлена символом верхнего регистр в кавычках, соответствующая команда меню будет вызвана только в том случае, когда пользователь нажмет [Shift] вместе с указанной клавишей. Если клавиша представлена символом нижнего регистра и задан параметр ALT, для вызова соответствующей команды необходимо нажать [Alt] и указанный символ, а если задан символ верхнего регистра и ALT, то для вызова команды нужно вместе с заданной клавишей нажимать [Shift] и [Alt]. Наконец, если требуется, чтобы для вызова команды использовалась комбинация [Ctrl+символ], символ в кавычках должен предваряться символом "^".
Виртуальная клавиша ― это системно-независимый код, определенный для основного набора слуежебыных клавиш. Виртуальные клавиши включают определения функциональных клавиш [F1]-[F12], стрелок и других не ASCII-клавиш. Они определены, как макроимена в файле windows.inc. Все эти макроимена начинаются с VK_. Для того чтобы использовать виртуальную клавишу как акселератор, нужно просто указать ее макроимя, а тип должен быть VIRTKEY. Можно также использовать ALT, SHIFT и CONTROL для задания соответствующих комбинаций клавиш. Вот некоторые примеры:
Вот как выглядит файл MENU.RC из предыдущих разделов с добавленной таблицей акселераторов
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define ZZZ_TEST 0
#define ZZZ_OPEN 1
#define ZZZ_SAVE 2
#define ZZZ_EXIT 3
#define IDR_MAINACCEL 105
#define ZZZ_Menu 37
 
ZZZ_Menu MENU  
{
    POPUP "&File"
    {       MENUITEM "&Test\tCtrl+T",ZZZ_TEST
        MENUITEM "&Open\tCtrl+O",ZZZ_OPEN
        MENUITEM "&Save\tCtrl+S",ZZZ_SAVE
        MENUITEM SEPARATOR
        MENUITEM "&Exit\tCtrl+X",ZZZ_EXIT
    }
    MENUITEM "&Exit",ZZZ_EXIT
}
IDR_MAINACCEL ACCELERATORS DISCARDABLE 
{ // определение акселераторов
 "^T",ZZZ_TEST
 "^O",ZZZ_OPEN
 "^S",ZZZ_SAVE
 "^X",ZZZ_EXIT
}
Заметьте, что названия элементов меню расширены и включают в себя названия акселераторов для вызова соответствующих команд. Каждый элемент отделяется от акселератора символом табуляции. Если вы в своем меню будете подключать виртуальные клавиши, то необходимо будет подключить файл "windows.inc", поскольку в нем определены макроимена виртуальных клавиш.
Загрузка таблицы акселераторов
Хотя акселераторы определены в том же файле ресурсов, что и меню, они должны быть отдельно загружены при помощи функции LoadAccelerators, которая имеет следующий прототип
Кликните здесь для просмотра всего текста
C
1
2
3
4
HACCEL LoadAccelerators 
(   HINSTANCE ThisInst, 
    LPSTR     Name
);
  • ThisInst ― дескриптор текущего экземпляра приложения
  • Name ― имя таблицы акселераторов
Функция возвращает дескриптор загруженной таблицы акселераторов либо NULL, если таблица не может быть загружена.
Функцию LoadAccelerators нужно вызвать сразу после создания окна. Например таблица акселераторов для IDR_MAINACCEL загружается так:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
    push IDR_MAINACCEL 
    push esi
    call _imp__LoadAcceleratorsA@8
    mov ACC,eax
Значение ACC будет использовано позже для обработки акселераторных комбинаций.
Несмотря на то, что функция LoadAccelerators загружает таблицу акселераторов, программа не будет их обрабатывать до тех пор, пока в цикл обработки сообщений не добавят функцию TranslateAccelerator
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
int TranslateAccelerator 
(   HWND    hWnd, 
    HACCEL  hAccel, 
    LPMSG   lpMess
);
  • hWnd ― дескриптор окна, для которого должны транслироваться акселераторные комбинации;
  • hAccel ― дескриптор таблицы акселераторов, возвращенный функцией LoadAccelerators;
  • lpMess ― указатель на сообщения
Функция TranslateAccelerator преобразует сообщения WM_KEYDOWN и WM_SYSKEY в сообщения WM_COMMAND и WM_SYSCOMMAND соответственно. При этом в старшем слове параметра wParam помещатся 1, как отличие для акселератора. В младшем слове содержится индентификатор пункта меню. Функция TranslateAccelerator возвращает ненулевое значение, если была использована акселераторная комбинация, и NULL ― в противном случае. С использованием функции TranslateAccelerator цикл обработки сообщений выглядит так
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
message_loop: push ebx  ;цикл обработки сообщений
    push ebx
    push ebx
    push ebp 
    call _imp__GetMessageA@16   
    push ebp
    call _imp__DispatchMessageA@4     ;вернуть управление Windows        
    push ebp
    push ACC
    push hWnd
    call _imp__TranslateAccelerator@12
    test eax,eax
    jne message_loop
    push ebp
    call _imp__TranslateMessage@4;разрешить использование клавиатуры
    jmp short message_loop
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
.686P 
.model flat
includelib user32.lib
includelib kernel32.lib
include windows.inc
;вызываемые функции Windows (внешние ссылки)
extern _imp__CreateWindowExA@48:dword;создание окна                
extern _imp__DefWindowProcA@16:dword;стандартная обработка сообщения
extern _imp__DispatchMessageA@4:dword;отправка сообщения                
extern _imp__GetMessageA@16:dword;получение сообщения                    
extern _imp__ExitProcess@4:dword;выход из программы                 
extern _imp__RegisterClassA@4:dword;регистрация класса окна             
extern _imp__MessageBoxA@16:dword
extern _imp__LoadMenuA@8:dword
extern _imp__LoadAcceleratorsA@8:dword
extern _imp__TranslateAccelerator@12:dword
extern _imp__TranslateMessage@4:dword
 
.const
ZZZ_TEST      equ 0
ZZZ_OPEN      equ 1
ZZZ_SAVE      equ 2
ZZZ_EXIT      equ 3
IDM_MENU      equ 37
IDR_MAINACCEL equ 105
.code
start:  xor ebx,ebx
    mov edi,offset wTitle
        mov esi,400000h
    push edi   ; Указатель на имя нашего класса
    push ebx ;Меню
    push COLOR_WINDOW+1  ;Фон нашего окна
    push 10011h;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    push ebx   ;Иконка окна по умолчанию
    push esi   ;Адрес нашей проги в памяти
    push ebx   ;Эта хрень нам не нужна
    push ebx   ;и эта тоже
    push offset WndProc ;Адрес процедуры обработки событий
    push ebx   ; Стиль нашего окна
    push esp   ;&WNDCLASSA 
    call _imp__RegisterClassA@4
    push IDM_MENU
    push esi
    call _imp__LoadMenuA@8
    push esi
    push ebx       
    push esi
        shl esi,9;esi=CW_USEDEFAULT
    push eax    
    push ebx    
    push esi    
    push esi    
    push esi    
    push esi    
    push WS_OVERLAPPEDWINDOW + WS_VISIBLE
    push edi; szWinTitle            
    push edi; lpszClassName
    push ebx
    call _imp__CreateWindowExA@48   ;создать окно
    mov hWnd,eax
    pop esi
    push IDR_MAINACCEL 
    push esi
    call _imp__LoadAcceleratorsA@8
    mov ACC,eax
    mov ebp,esp
message_loop: push ebx  ;цикл обработки сообщений
    push ebx
    push ebx
    push ebp 
    call _imp__GetMessageA@16   
    push ebp
    call _imp__DispatchMessageA@4;вернуть управление Windows        
    push ebp
    push ACC
    push hWnd
    call _imp__TranslateAccelerator@12
    test eax,eax
    jne message_loop
    push ebp
    call _imp__TranslateMessage@4
    jmp short message_loop
;----------------------------------------------------------------
WndProc:
Msg equ dword ptr [esp+8]
hwnd    equ dword ptr [esp+10h]
wParam  equ word ptr [esp+0Ch]
 
    mov eax,Msg
        dec eax;cmp eax,WM_DESTROY=2
    dec eax
    je short wmDESTROY
        sub eax,WM_COMMAND-WM_DESTROY
    je short wmCOMMAND
        jmp _imp__DefWindowProcA@16;обработка по умолчанию
wmDESTROY: push eax;0          ;завершение программы
    call _imp__ExitProcess@4
wmCOMMAND: mov ax,wParam
        cmp eax,ZZZ_EXIT
        je short wmDESTROY
    push ebx;MB_OK
    push offset menu_name
    push menu_handlers[eax*4]
    push hwnd
    call _imp__MessageBoxA@16
a1:     retn 10h
;----------------------------------------------------------
wTitle db 'Iczelion Tutorial #8-8: Работа с таблицей акселераторов в MASM',0
menu_name   db  'ZZZ_Menu',0
test_msg    db  'You select menu item TEST',0
open_msg    db  'You select menu item OPEN',0
save_msg    db  'You select menu item SAVE',0
menu_handlers dd test_msg, open_msg, save_msg
ACC dd ?
hWnd    dd ?
end start
То же самое, но с ручной компиляцией ресурсов, с сокращенным заголовком и расположении данных в области импорта дает нам выигрыш почти в 100 байт (1296 ->1192)
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
.686P 
.model tiny
;for WinXP - 1192 bytes
du macro string
local bslash
bslash=0
irpc c,<string>
if bslash eq 0
    if '&c' eq "\";;управляющая последовательность символов
    bslash=1
    elseif '&c' eq "ё"
    db 51h,4
    elseif '&c' eq "Ё"
    db 1,4
    elseif '&c' gt 127
    db ('&c'- 0B0h),4;;кириллица
    else
    dw '&c'          ;;латиница
    endif
else
bslash=0
    if '&c' eq "n"    ;;  \n=новая строка
        DW 0Dh,0Ah
        elseif '&c' eq "\";;  \\=обратная косая черта (\)
        dw '\'
        elseif '&c' eq "r";;  \r=возврат каретки
        dw 0Dh
        elseif '&c' eq "l";;  \l=LF
        dw 0Ah
        elseif '&c' eq "s"
        dw 20h
        elseif '&c' eq "c"
        dw 3Bh
        elseif '&c' eq "t";;  \t=табуляция*
        dw 9
    endif
endif
endm
dw 0
endm
;---------------------------------------------------------------
include windows.inc
exebase     equ 400000h
ZZZ_TEST      equ 0
ZZZ_OPEN      equ 1
ZZZ_SAVE      equ 2
ZZZ_EXIT      equ 3
IDM_MENU      equ 37
IDR_MAINACCEL equ 105
POPUP       equ 10h
MFR_END     equ 80h
.code
main:
include capito_res.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov edi,offset wTitle+exebase
        mov esi,exebase
    invoke RegisterClass,esp,ebx,offset WndProc+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ebx,edi
    invoke LoadMenu,esi,IDM_MENU
    push esi
    push ebx       
    push esi
        shl esi,9;esi=CW_USEDEFAULT
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW + WS_VISIBLE,\
    esi,esi,esi,esi,ebx,eax
    mov hWnd+exebase,eax
    pop esi
    invoke LoadAccelerators,esi,IDR_MAINACCEL
    mov ACC+exebase,eax
    mov ebp,esp
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    invoke TranslateAccelerator,hWnd+exebase,ACC+exebase,ebp
    test eax,eax
    jne message_loop
    invoke TranslateMessage,ebp
    jmp short message_loop
;----------------------------------------------------------------
WndProc:
Msg equ dword ptr [esp+8]
hwnd    equ dword ptr [esp+10h]
wParam  equ word ptr [esp+0Ch]
 
    mov eax,Msg
        dec eax;cmp eax,WM_DESTROY=2
    dec eax
    je short wmDESTROY
        sub eax,WM_COMMAND-WM_DESTROY
    je short wmCOMMAND
        jmp DefWindowProc+exebase
wmDESTROY: invoke ExitProcess,eax
wmCOMMAND: mov ax,wParam
        cmp eax,ZZZ_EXIT
        je short wmDESTROY
    invoke MessageBox,hwnd,menu_handlers[eax*4+exebase],offset menu_name\
    +exebase,ebx
a1:     retn 10h
;----------------------------------------------------------
wTitle db 'Iczelion Tutorial #8-8: Работа с таблицей акселераторов в MASM',0
menu_name   db 'ZZZ_Menu',0
test_msg    db 'You select menu item TEST',0
open_msg    db 'You select menu item OPEN',0
save_msg    db 'You select menu item SAVE',0
menu_handlers   dd test_msg+exebase, open_msg+exebase, save_msg+exebase
;-------------------------------------------------------------------------------------------
align 2
resource:
Characteristics0    dd 0
TimeDateStamp0      dd 0
MajorVersion0       dw 0
MinorVersion0       dw 0
NumberOfNamedEntries0   dw 0;количество ресурсов с именами
NumberOfIdEntries0  dw 2;количество ресурсов с идентификаторами
dw RT_MENU,0,m1-resource,8000h;номер типа ресурса
dw RT_ACCELERATOR,0,t1-resource,8000h
m1:
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0
NumberOfNamedEntries1   dw 0
NumberOfIdEntries1  dw 1
dw IDM_MENU,0,m2-resource,8000h
m2:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0
NumberOfNamedEntries2   dw 0
NumberOfIdEntries2  dw 1
dw (LANG_ENGLISH or SUBLANG_ENGLISH_CAN*100h),0,m3-resource,0
m3:
OffsetToData0   dd menu
Size0       dd end_menu-menu
CodePage0   dd 0
Reserved0   dd 0
t1:
Characteristics9    dd 0
TimeDateStamp9      dd 0
MajorVersion9       dw 0
MinorVersion9       dw 0
NumberOfNamedEntries9   dw 0
NumberOfIdEntries9  dw 1
dw IDR_MAINACCEL,0,t2-resource,8000h
t2:
Characteristics10   dd 0;0
TimeDateStamp10     dd 0;0
MajorVersion10      dw 0;0
MinorVersion10      dw 0
NumberOfNamedEntries10  dw 0
NumberOfIdEntries10 dw 1
dw (LANG_ENGLISH or SUBLANG_ENGLISH_CAN*100h),0,t3-resource,0
t3:
OffsetToData10  dd tabl
Size10      dd end_tabl-tabl
CodePage10  dd 0
Reserved10  dd 0
;--------------------------------------------------------------
menu dw 0,0,POPUP
du <&File>
dw MFT_STRING or MFS_ENABLED,ZZZ_TEST
du <&Test\tCtrl+T>
dw MFT_STRING or MFS_ENABLED,ZZZ_OPEN
du <&Open\tCtrl+O>
dw MFT_STRING or MFS_ENABLED,ZZZ_SAVE
du <&Save\tCtrl+S>
dw MFT_STRING or MFS_ENABLED or MFR_END,ZZZ_EXIT
du <&Exit\tCtrl+X>
dw MFR_END,ZZZ_EXIT
du <&Exit>
end_menu:
;dw 0
tabl:
dw FVIRTKEY or FNOINVERT or FCONTROL,'T',ZZZ_TEST,0
dw FVIRTKEY or FNOINVERT or FCONTROL,'O',ZZZ_OPEN,0
dw FVIRTKEY or FNOINVERT or FCONTROL,'S',ZZZ_SAVE,0
dw FVIRTKEY or FNOINVERT or FCONTROL or MFR_END,'X',ZZZ_EXIT;,0
end_tabl:
end_resource:
import:
ACC dd 0
hWnd    dd 0
dd 0,user32_dll
dd user_table
dd 0,0,0,kernel32_dll
dd kernel_table
dd 0,0
kernel_table:
ExitProcess             dd _ExitProcess,0
user_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx      
DefWindowProc           dd _DefWindowProc
DispatchMessage         dd _DispatchMessage
GetMessage              dd _GetMessage
MessageBox              dd _MessageBox
LoadMenu                dd _LoadMenu
LoadAccelerators        dd _LoadAccelerators
TranslateAccelerator    dd _TranslateAccelerator
TranslateMessage        dd _TranslateMessage
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_LoadMenu               db 0,0,'LoadMenuA'
_LoadAccelerators       db 0,0,'LoadAcceleratorsA'
_TranslateAccelerator   db 0,0,'TranslateAccelerator'
_TranslateMessage       db 0,0,'TranslateMessage'
_MessageBox     db 0,0,'MessageBoxA',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
___________________________________
© Mikl___ 2013
6
Mikl___
Заблокирован
Автор FAQ
10.01.2013, 05:08  [ТС] #29
Win32 API. Урок 8 i. Работа с инструментальной панелью (toolbar)
Скачайте пример.
Теория ― мать склероза
Дальнейшего улучшения внешнего вида приложения можно добиться, включив в состав главного окна, наряду с линейкой меню (или вместо нее), инструментальную панель, которая представляет собой набор кнопок с рисунками, действующими точно так же, как и пункты обычного меню. Эти кнопки могут дублировать отдельные команды меню, но могут и дополнять их. На рисунке показана часть главного меню Microsoft Word со строкой заголовка, линейкой обычного меню (Файл, Правка и т.д.) и инструментальной панелью с пиктограммами стандартных действий (открытие и сохранение файла, редактирование, форматирование и т.д.)
Кликните здесь для просмотра всего текста
Панель инструментов, вероятно, самый распространенный из общих элементов управления ― представляет из себя графическое меню с некоторыми дополнительными свойствами. Команды меню в панели инструментов представлены в виде небольших изображений, имеющих форму кнопок. Часто такая панель используется вместе или вместо обычного меню.
Для создания инструментальной панели необходимо прежде всего подготовить файл с растровым изображением рисунка на кнопках (в формате BMP). Могут быть разные варианты размещения кнопок (вплотную друг к другу, с промежутками, группами и т.д.). Обычно кнопки имеют размер 16х16 пикселов, и тогда для размещения на инструментальной панели. например, трех кнопок, нужно создать растровое изображение размером 16х48 пикселов. Разумеется рисунки на кнопках могут быть цветными.
Кликните здесь для просмотра всего текста
Поскольку изображение кнопок будет выступать у нас в качестве ресурса, в файл ресурсов необходимо включить ссылку на файл с изображением кнопок, например, таким образом.
Кликните здесь для просмотра всего текста
C
1
ID_BNS BITMAP "BTNS.BMP"

Здесь ID_BNS ― произвольная символическая константа, которая затем будет использоваться в качестве идентификатора данного ресурса, а BTNS.BMP ― имя файла с изображением кнопок.
Действия по программной организации инструментальной панели удобно выполнить при обработке события WM_CREATE. Здесь прежде всего создается (и обнуляется) структурная переменная ― массив из трех (по числу кнопок) структур типа TBBUTTON. Эта структура описана в заголовочном файле COMMCTRL.H.
После заполнения перечисленных выше элементов во всех трех (если кнопок три) членах нашего массива следует вызвать функцию CreateToolbarEx, указав в качестве ее параметров:
  • hwnd ― дескриптор родительского окна панели инструментов (дескриптор главного окна)
  • dwStyle ― стиль инструментальной панели. Кроме стиля WS_CHILD, он может включать и другие стандартные стили, такие как WS_BORDER или WS_VISIBLE. Имеются еще два стиля, задаваемых для панели инструментов, один из них TBSTYLE_TOOLTIPS позволяет использовать подсказки панели инструментов ― tooltips. Другой специфичный для панели инструментов стиль, называемый TBSYLE_WRAPABLE, обеспечивает возможность отображать длинные панели инструментов (с большим количеством кнопок) в несколько строк.
  • ID ― идентификатор всей инструментальной панели, который в программе не используется и может быть равен, например, -1;
  • NumButtons ― число изображений кнопок в BMP-файле;
  • hInst ― дескриптор текущего экземпляра приложения;
  • BPID ― идентификатор ресурса с изображением кнопок;
  • Buttons ― адрес массива структур типа TBBUTTON;
  • NumButtons ― число кнопок в панели инструментов;
  • ButtonWidt ― ширину каждой кнопки;
  • ButtonHeight ― высоту каждой кнопки;
  • BMPWidth ― ширину изображения на каждой кнопке;
  • BMPHeight ― высоту изображения на каждой кнопке
    размеры кнопок и изображений на них в принципе могут не совпадать, при указании нулевых значений, размеры кнопок подбираются системой автоматически исходя из размеров изображения на них;
  • Size ― размер структуры TBBUTTON, определяемый с помощью sizeof.
Функция CreateToolbarEx возвращает дескриптор панели инструментов.
Каждая кнопка панели инструментов должна иметь связанную с ней структуру типа TBBUTTON.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
TBBUTTON STRUCT
  iBitmap           DWORD      ?
  idCommand         DWORD      ?
  fsState           BYTE       ?
  fsStyle           BYTE       ?
  _wPad1            WORD       ?
  dwData            DWORD      ?
  iString           DWORD      ?
TBBUTTON ENDS
Структура типа TBBUTTON содержит семь элементов:
  • iBitmap ― порядковый номер (индекс) кнопки, этот индекс, в свою очередь, определяет смещение в исходном файле ресурсе растра, начиная с которого рисуется изображение в кнопке. Индексы начинаются от 0;
  • idCommand ― определяет команду, ассоциированную с кнопкой. При нажатии кнопки родительское окно получает сообщение WM_COMMAND. В младшем слове параметра wParam этого сообщения содержится значение idCommand;
  • fsState ― начальное состояние кнопки. Параметр может принимать одно из следующих значений или комбинацией значений:
    Кликните здесь для просмотра всего текста
    состояние значение
    TBSTATE_CHECKED кнопка нажата
    TBSTATE_ENABLED кнопка активна (разрешена)
    TBSTATE_HIDDEN кнопка скрыта неактивна (запрещена)
    TBSTATE_INDETERMINATE кнопка закрашена серым цветом и неактивна
    TBSTATE_PRESSED кнопка нажата
    TBSTATE_WRAP все следующие кнопки будут отображаться в следующей строке
  • fsStyle ― стиль кнопки. Может представлять собой любую из имеющих смысл комбинацию следующих значений:
    Кликните здесь для просмотра всего текста
    стиль эффект
    TBSTYLE_BUTTON обычная кнопка
    TBSTYLE_CHECK при каждом нажатии кнопки ее состояние изменяется на противоположное (нажата ― отпущена)
    TBSTYLE_CHECKGROUP кнопка со стилем TBSTYLE_CHECK в группе кнопок, представляющих собой набор параметров, из которых можно выбрать только один
    TBSTYLE_GROUP обычная кнопка в группе кнопок, представляющих собой набор параметров, из которых можно выбрать только один
    TBSTYLE_SEP задание интервала между кнопками. При задании этого стиля idCommand должно быть равно нулю. Стиль TBSTYLE_SEP используется для задания промежутков между кнопками панели инструментов при объединении этих кнопок в группы по функциональным признакам
  • dwData ― может содержать дополнительную информацию, определяемую программистом;
  • iString ― содержит индекс строки, ассоциированный с кнопкой. Использовать это поле необязательно. Если это поле не используется, тогда его значение равно нулю.
По умолчанию панели инструментов являются полностью автоматическими элементами управления и не требуют от программиста каких-либо действий по управлению ими. Существует возможность программного управления панелями инструментов путем посылки им управляющих сообщений, для чего используется функция SendMessage. Сообщения, которые можно посылать панели инструментов:
Кликните здесь для просмотра всего текста
сообщениеназначениеwParamlParam=0lParam=1
CHECKBUTTON нажать или отпустить кнопку идентификатор кнопкиесли кнопка отпущенаесли кнопка нажата
ENABLEBUTTON запретить или разрешить кнопку идентификатор кнопки если кнопка должна быть запрещена если кнопка должна быть разрешена
HIDEBUTTON скрыть или отобразить кнопку идентификатор кнопки если кнопку требуется отобразить если кнопку необходимо скрыть
При нажатии кнопки инструментальной панели Windows посылает в приложение сообщение WM_COMMAND, которое приводит к вызову с передачей через второй параметр этой функции значение идентификатора нажатой кнопки. Панели инструментов могут также генерировать нотификационные сообщения, которые информируют программу о происходящих в этих панелях событиях. Имена этих сообщений начинаются с TBN_.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
.586p
.model tiny
include windows.inc
;for WinXP - 1021 bytes
.code
exebase equ 400000h
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ebx,edi
;--------------------------+
;  creating the main window |
;--------------------------+
    push esi
    push ebx
    push esi
    shl esi,9;esi=CW_DEFAULT
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
    esi,esi,esi,esi,ebx,ebx
    pop esi;esi=400000h
        xchg edi,eax;в edi дескриптор главного окна
    invoke LoadImage,esi,offset aMybp1+exebase,ebx,ebx,ebx,\
        LR_LOADFROMFILE
;создается структурная переменная - массив из трех структур типа TBBUTTON
    mov edx,sizeof(TBBUTTON)
    inc ebx
    inc ebx;ebx=2
    lea ecx,[tbb+edx*2]+exebase
@@: mov [ecx+TBBUTTON.iBitmap],ebx;порядковый номер кнопки (кнопки нумеруются от 0); 
    mov [ecx+TBBUTTON.idCommand],ebx;идентификатор кнопки 
    mov byte ptr [ecx+TBBUTTON.fsState],TBSTATE_ENABLED;состояние кнопки. 
;Значение TBSTATE_ENABLED разрешает управление с пмощью данной кнопки
    test ebx,ebx;заполняем массив с ebx как индекс в массиве от 2 до 0
    jz short @f
    sub ecx,edx;переходим к следующей структуре TBBUTTON
    dec ebx
    jmp short @b
@@: invoke CreateToolbarEx,edi,WS_CHILD or WS_BORDER or WS_VISIBLE,-1,3,\
    ebx,eax,ecx,3,18,18,18,18,edx
      
    mov edi,offset hBlueBrush+exebase;edi на массив кистей
    mov esi,offset CreateSolidBrush+exebase;функцию CreateSolidBrush вызываю два раза
    mov ebp,08F0000h
    push ebp;синий=08F0000h
    call dword ptr [esi]
    stosd;mov [edi],eax;hBlueBrush
    shr ebp,8
    push ebp;зеленый=08F00h
    call dword ptr [esi]
    stosd;mov [edi+4],eax;hGreenBrush
    mov ebp,esp
; +---------------------------+
; | entering the message loop |
; +---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
; +----------------------+
; | the window procedure |
; +----------------------+
window_procedure:
hWnd    equ ebp+8
uMsg    equ ebp+0Ch
wParam  equ ebp+10h
lParam  equ ebp+14h
    enter sizeof(PAINTSTRUCT),0
    mov eax,[uMsg]
    mov edi,[hWnd]
    dec eax
    dec eax; cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_SIZE-WM_DESTROY;cmp eax,WM_SIZE
    je @@WM_SIZE
    sub eax,WM_PAINT-WM_SIZE;cmp eax,WM_PAINT
    je @@WM_PAINT
    sub eax,WM_COMMAND-WM_PAINT; cmp uMsg,WM_COMMAND
    je @@WM_COMMAND
    leave
    jmp DefWindowProc+exebase
@@WM_PAINT: invoke BeginPaint,edi,esp
    mov ecx,[sw+exebase]
    jecxz @f;в sw при старте программы ноль, если sw=0
;тогда не нужно изменять цвет окна
;заполняем окно выбранной кистью из массива кистей
        lea esi,[esp].PAINTSTRUCT.rcPaint
    invoke FillRect,eax,esi,dword ptr [hBlueBrush+ecx*4-4]+exebase
@@:     invoke EndPaint,edi,esp;Освобождаем контекст отображения
    jmp end_wm_check
@@WM_SIZE: mov eax,[lParam];при изменении размера окна - получаем
;размеры окна
    mov word ptr [esp+PAINTSTRUCT.rcPaint.right],ax
    shr eax,16
    mov dword ptr [esp+PAINTSTRUCT.rcPaint.bottom],eax
    jmp short end_wm_check
@@WM_COMMAND: mov eax,[wParam];в зависимости от значения в wParam
;либо закрываем окно (wParam=2), либо изменяем его цвет (wParam=0 или 1)
    jmp [handler+eax*4]+exebase
a:  inc eax
    mov [sw+exebase],eax
;если wParam=0 или wParam=1 посылаем сообщение WM_PAINT
    invoke InvalidateRect,edi,ebx,1
end_wm_check: leave
    retn 10h
@@WM_DESTROY: invoke ExitProcess,ebx
;==================================================
handler dd a+exebase,a+exebase,@@WM_DESTROY+exebase
wTitle db 'Iczelion Tutorial #8-9:инструментальная панель в MASM'
tbb db sizeof(TBBUTTON)*3 dup (0)
aMybp1  db "Images\btns.bmp"
import:
sw          dd 0
hBlueBrush      dd 0,0
;-----------------------------------------------------------------
dd user32_dll
dd user32_table
dd 0,0,0,gdi32_dll
dd gdi32_table
dd 0,0,0,comctl32_dll
dd comctl32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess     dd _ExitProcess,0
user32_table:
RegisterClass           dd _RegisterClass
DefWindowProc           dd _DefWindowProc
GetMessage          dd _GetMessage
DispatchMessage     dd _DispatchMessage
LoadImage           dd _LoadImage
BeginPaint          dd _BeginPaint
EndPaint            dd _EndPaint
InvalidateRect      dd _InvalidateRect
FillRect            dd _FillRect
CreateWindowEx          dd _CreateWindowEx,0
 
gdi32_table:
CreateSolidBrush        dd _CreateSolidBrush,0
comctl32_table:
CreateToolbarEx     dd _CreateToolbarEx
            dw 0
_RegisterClass          db 0,0,'RegisterClassA'
_DefWindowProc          db 0,0,'DefWindowProcA'
_GetMessage         db 0,0,'GetMessageA'
_DispatchMessage        db 0,0,'DispatchMessageA'
_LoadImage          db 0,0,'LoadImageA'
_BeginPaint         db 0,0,'BeginPaint'
_EndPaint           db 0,0,'EndPaint'
_InvalidateRect         db 0,0,'InvalidateRect'
_FillRect           db 0,0,'FillRect'
_CreateWindowEx     db 0,0,'CreateWindowExA',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_CreateSolidBrush   db 0,0,"CreateSolidBrush",0
gdi32_dll       db 'gdi32'
_CreateToolbarEx    db 0,0,"CreateToolbarEx",0
comctl32_dll        db 'comctl32'
end_import:
end main
Маленькие хитрости:
  • переменные sw и hBlueBrush расположены среди «неиспользуемых» полей импорта:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    
    import:
    sw          dd 0
    hBlueBrush      dd 0,0
    dd user32_dll
    dd user32_table
  • у строк wTitle и aMybp нет завершающих нулей, строка wTitle своим концом «упирается» в заполненную пока нулями структурную переменную tbb, а строка aMybp ― в поле импорта равное нулю.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
wTitle db 'Iczelion Tutorial #8-9:инструментальная панель в MASM'
tbb db sizeof(TBBUTTON)*3 dup (0)
aMybp   db "Images\btns.bmp"
;----------------------------------------------------------------
import:
sw dd 0
___________________________
© Mikl___ 2013
3
Миниатюры
Сам себе Iczelion  
Изображения
 
Mikl___
Заблокирован
Автор FAQ
10.01.2013, 07:55  [ТС] #30
Win32 API. Урок 8 j. Всплывающие подсказки
Скачайте пример.
Теория ― мать склероза
В современных программах, управляемых с помощью меню и инструментальных панелей, принято включать в состав меню всплывающие подсказки (tooltips) ― небольшие текстовые окошки, открываемые автоматически и содержащие краткое описание назначения кнопок, когда курсор мыши помещается на соответствующую кнопку инструментальной панели.
Для организации всплывающих подсказок следует прежде всего создать инструментальную панель, как это было описано в предыдущем подразделе, дополнив ее стиль, указываемый в качестве второго параметра функции CreateToolbarEx, константой TBSYLE_TOOLTIPS.
Отслеживание положения курсора мыши и вывод на экран требуемых подсказок осуществляется в ответ на сообщение Windows WM_NOTIFY, для обработки которого придется дополнить функцию WinProc. В момент прихода сообщения WM_NOTIFY параметр lParam имеет указатель на структуру NMHDR,
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
NMHDR STRUCT
    hwndFrom    DWORD ? ;дескриптор элемента управления
    idFrom      DWORD ? ;идентификатор элемента управления
    icode       DWORD ? ;код, передаваемый в сообщение
NMHDR ends
которая входит в большую по объему структуру типа TOOLTIPTEXT, в которую NMHDR входит в качестве первого элемента.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
TOOLTIPTEXT STRUCT
  hdr           NMHDR      <>
  lpszText      DWORD  ?
  szText        BYTE 80 dup (?)
  union
    hInst   dd     ?
    hinst   dd     ?
  ends
  uFlags        DWORD  ?
  lParam        LPARAM ?
TOOLTIPTEXT ENDS
Таким образом, если использовать параметр lParam непосредственно, он будет служить указателем на структуру NMHDR, и с его помощью можно обращаться к элементам этой структуры, однако остальные поля структуры TOOLTIPTEXT будут недоступны. Если же преобразовать параметр lParam в тип LPTOOLTIPTEXT, то он будет указывать на всю структуру TOOLTIPTEXT, и через него можно получить доступ ко всем элементам этой структуры; через имя вложенной структуры hdr в этом случае можно получить доступ и к элементам структуры NMHDR.
Таким образом, допустимы, в частности, следующие обращения:
  • lParam->icode (lParam ― указатель на структуру NMHDR, а icode ― элемент этой структуры);
  • lParam->idFrom (lParam ― указатель на структуру NMHDR, а idFrom ― элемент этой структуры);
  • ((LPTOOLTIPTEXT)lParam)->szText (выражение (LPTOOLTIPTEXT)lParam является указателем на структуру TOOLTIPTEXT, а szText ― элемент этой структуры);
  • ((LPTOOLTIPTEXT)lParam)->hdr.idFrom (обращение к элементам вложенной структуры посредством указателя на внешнюю).
Сообщения WM_NOTIFY представляют для нас интерес лишь тогда, когда icode, входящий в структуру NMHDR, равен TTN_NEEDTEXT, а поле idFrom содержится идентификатор кнопки, для которой требуется подсказка. Текст подсказки можно задать одним из трех способов:
  1. скопировать текст подсказки в поле szText структуры TOOLTIPTEXT;
  2. записать в поле szText указатель на текстовую строку;
  3. задать идентификатор ресурса строки. В этом случае идентификатор строки записывается в поле lpszText, а поле hInst содержит дескриптор приложения, содержащего ресурс.
Простейшим является способ записать в lpszText указатель на строку, определенную в программе.

Следующий фрагмент обрабатывает запросы подсказок в нашей программе
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
@WM_NOTIFY: mov edx,[lParam]   ;if( LPNMHDR(lParam)->code ==TTN_NEEDTEXT)
    cmp dword ptr [edx+NMHDR.icode],TTN_NEEDTEXT
    jnz end_wm_check        ;LPTOOLTIPTEXT lpttt=(LPTOOLTIPTEXT) lParam;
    mov eax,[edx+NMHDR.idFrom]  ;switch (lpttt->hdr.idFrom) {
    cmp eax,ID_3                ;case ID_1: strcpy(lpttt->szText,"Заполнить синим");break;
    ja end_wm_check         ;case ID_2: strcpy(lpttt->szText,"Заполнить зеленым");break;                    
    lea edx,[edx+TOOLTIPTEXT.szText];case ID_3: strcpy(lpttt->szText,"выход");
    push dword ptr [ps+eax*4]+exebase
    push edx
    call lstrcpy+exebase
После того, как текст подсказки определен, подсказка отображается автоматически при возврате управления к Windows, и программе больше не нужно выполнять никаких действий. Как видите, подсказки хорошо автоматизированы и просты в использовании.
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
.586p
.model tiny
include windows.inc
;for WinXP - 1164 bytes
.code
exebase equ 400000h
ID_1    equ 0
ID_2    equ 1
ID_3    equ 2
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,ebx,edi
;--------------------------+
;  creating the main window |
;--------------------------+
    push esi
    push ebx
    push esi
    shl esi,9;esi=CW_DEFAULT
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
    esi,esi,esi,esi,ebx,ebx
    pop esi;esi=400000h
        xchg edi,eax;в edi дескриптор главного окна
    invoke LoadImage,esi,offset aMybp1+exebase,ebx,ebx,ebx,\
        LR_LOADFROMFILE
;создается структурная переменная - массив из трех структур типа TBBUTTON
    mov edx,sizeof(TBBUTTON)
    inc ebx
    inc ebx;ebx=2
    lea ecx,[tbb+edx*2]+exebase
@@: mov [ecx+TBBUTTON.iBitmap],ebx;порядковый номер кнопки (кнопки нумеруются от 0); 
    mov [ecx+TBBUTTON.idCommand],ebx;идентификатор кнопки 
    mov byte ptr [ecx+TBBUTTON.fsState],TBSTATE_ENABLED;состояние кнопки. 
;Значение TBSTATE_ENABLED разрешает управление с пмощью данной кнопки
    test ebx,ebx;заполняем массив с ebx как индекс в массиве от 2 до 0
    jz short @f
    sub ecx,edx;переходим к следующей структуре TBBUTTON
    dec ebx
    jmp short @b
@@: invoke CreateToolbarEx,edi,WS_CHILD or WS_BORDER or WS_VISIBLE or TBSTYLE_TOOLTIPS,\
    -1,3,ebx,eax,ecx,3,18,18,18,18,edx,edx
      
    mov edi,offset hBlueBrush+exebase;edi на массив кистей
    mov esi,offset CreateSolidBrush+exebase;функцию CreateSolidBrush вызываю два раза
    mov ebp,08F0000h
    push ebp;синий=08F0000h
    call dword ptr [esi]
    stosd;mov [edi],eax;hBlueBrush
    shr ebp,8
    push ebp;зеленый=08F00h
    call dword ptr [esi]
    stosd;mov [edi+4],eax;hGreenBrush
    mov ebp,esp
; +---------------------------+
; | entering the message loop |
; +---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
; +----------------------+
; | the window procedure |
; +----------------------+
window_procedure:
hWnd    equ ebp+8
uMsg    equ ebp+0Ch
wParam  equ ebp+10h
lParam  equ ebp+14h
lpttt   equ ebp-4
    enter sizeof(PAINTSTRUCT)+4,0
    mov eax,[uMsg]
    mov edi,[hWnd]
    dec eax
    dec eax; cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_SIZE-WM_DESTROY;cmp eax,WM_SIZE
    je @@WM_SIZE
    sub eax,WM_PAINT-WM_SIZE;cmp eax,WM_PAINT
    je @@WM_PAINT
    sub eax,WM_NOTIFY-WM_PAINT; cmp uMsg,WM_NOTIFY
    je @@WM_NOTIFY
        sub eax,WM_COMMAND-WM_NOTIFY; cmp uMsg,WM_COMMAND
    je @@WM_COMMAND
    leave
    jmp DefWindowProc+exebase
@@WM_PAINT: invoke BeginPaint,edi,esp
    mov ecx,[sw+exebase]
    jecxz @f;в sw при старте программы ноль, если sw=0
;тогда не нужно изменять цвет окна
;заполняем окно выбранной кистью из массива кистей
        lea esi,[esp].PAINTSTRUCT.rcPaint
    invoke FillRect,eax,esi,dword ptr [hBlueBrush+ecx*4-4]+exebase
@@:     invoke EndPaint,edi,esp;Освобождаем контекст отображения
    jmp end_wm_check
@@WM_NOTIFY: mov edx,[lParam]   ;if( LPNMHDR(lParam)->code ==TTN_NEEDTEXT)
    cmp dword ptr [edx+NMHDR.icode],TTN_NEEDTEXT
    jnz end_wm_check
    mov [lpttt],edx   ;LPTOOLTIPTEXT lpttt=(LPTOOLTIPTEXT) lParam;
    mov eax,[edx+NMHDR.idFrom];switch (lpttt->hdr.idFrom) {
    cmp eax,ID_3          ;case ID_1:strcpy(lpttt->szText,"синий");break;
    ja end_wm_check ;case ID_2:strcpy(lpttt->szText,"зеленый");break;
    ;case ID_3:strcpy(lpttt->szText,"выход");
    lea edx,[edx+TOOLTIPTEXT.szText]
    invoke lstrcpy,edx,dword ptr [ps+eax*4]+exebase
    jmp end_wm_check
@@WM_SIZE: mov eax,[lParam];при изменении размера окна - получаем
;размеры окна
    mov word ptr [esp+PAINTSTRUCT.rcPaint.right],ax
    shr eax,16
    mov dword ptr [esp+PAINTSTRUCT.rcPaint.bottom],eax
    jmp short end_wm_check
@@WM_COMMAND: mov eax,[wParam];в зависимости от значения в wParam
;либо закрываем окно (wParam=2), либо изменяем его цвет (wParam=0 или 1)
    jmp [handler+eax*4]+exebase
a:  inc eax
    mov [sw+exebase],eax
;если wParam=0 или wParam=1 посылаем сообщение WM_PAINT
    invoke InvalidateRect,edi,ebx,1
end_wm_check: leave
    retn 10h
@@WM_DESTROY: invoke ExitProcess,ebx;завершение программы
;==================================================
handler dd a+exebase,a+exebase,@@WM_DESTROY+exebase
wTitle db 'Iczelion Tutorial #8-10:инструментальная панель и всплывающие подсказки в MASM';,0
tbb db sizeof(TBBUTTON)*3 dup (0)
szText1 db 'Заполнить синим',0
szText2 db 'Заполнить зеленым',0
szText3 db 'Выход',0
ps  dd szText1+exebase,szText2+exebase,szText3+exebase
aMybp1  db "Images\btns.bmp"
import:
sw          dd 0
hBlueBrush      dd 0,0
;-----------------------------------------------------------------
dd user32_dll
dd user32_table
dd 0,0,0,gdi32_dll
dd gdi32_table
dd 0,0,0,comctl32_dll
dd comctl32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0
kernel32_table:
ExitProcess     dd _ExitProcess
lstrcpy         dd _lstrcpy,0
user32_table:
RegisterClass           dd _RegisterClass
DefWindowProc           dd _DefWindowProc
GetMessage          dd _GetMessage
DispatchMessage     dd _DispatchMessage
LoadImage           dd _LoadImage
BeginPaint          dd _BeginPaint
EndPaint            dd _EndPaint
InvalidateRect      dd _InvalidateRect
FillRect            dd _FillRect
CreateWindowEx          dd _CreateWindowEx,0
gdi32_table:
CreateSolidBrush        dd _CreateSolidBrush,0
comctl32_table:
CreateToolbarEx     dd _CreateToolbarEx
            dw 0
_RegisterClass          db 0,0,'RegisterClassA'
_DefWindowProc          db 0,0,'DefWindowProcA'
_GetMessage         db 0,0,'GetMessageA'
_DispatchMessage        db 0,0,'DispatchMessageA'
_LoadImage          db 0,0,'LoadImageA'
_BeginPaint         db 0,0,'BeginPaint'
_EndPaint           db 0,0,'EndPaint'
_InvalidateRect         db 0,0,'InvalidateRect'
_FillRect           db 0,0,'FillRect'
_CreateWindowEx     db 0,0,'CreateWindowExA',0
user32_dll      db 'user32'
_lstrcpy        db 0,0,'lstrcpyA'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_CreateSolidBrush   db 0,0,"CreateSolidBrush",0
gdi32_dll       db 'gdi32'
_CreateToolbarEx    db 0,0,"CreateToolbarEx",0
comctl32_dll        db 'comctl32'
end_import:
end main
__________________________________________________
© Mikl___ 2013
2
10.01.2013, 07:55
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.01.2013, 07:55
Привет! Вот еще темы с ответами:

Запрос сам в себе - Базы данных
Ребята, вот например есть таблица Name Time a 12-04-2011 a 14-04-2011 a 05-04-2011 b...

Комп включается сам по себе - Windows
проблема такая - после выключения компьютера, он самопроизвольно включается каждый раз с разным промежутком времени от 2-3 секунд до 1-2...

Монитор гаснет сам по себе - Мониторы
Купил монитор , подключил его в ноуту. Работают оба монитора вместе (новый и монитор ноута), новый монитор гаснет иногда, всего три раза...

Компьютер сам по себе выключается. - Материнские платы
Комп работает, работат, а потом сам по себе выключается... Иногда долго работает, а инода часто отключается...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
30
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru