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

Assembler, MASM, TASM

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 5.00
Mikl___
Заблокирован
Автор FAQ
21.01.2013, 10:06  [ТС] #61
Win32 API. Урок 22a. Суперклассинг
В этом туториале мы изучим суперклассинг, что это такое и для чего он служит. Вы также узнаете, как реализовать навигацию с помощью клавиши 'Tab' в вашем окне.

Скачайте пример здесь.
ПРАКТИКА ― СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
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
.586
.model tiny,stdcall
;for WinXP - 1062 bytes
include windows.inc
exebase equ 400000h
.code
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase;400000h
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClassEx,esp,sizeof(WNDCLASSEX),ebx,offset window_procedure+exebase,\
        ebx,ebx,esi,ebx,10011h,COLOR_APPWORKSPACE,ebx,edi,ebx
;--------------------------+
; creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,edi,edi,\
    WS_OVERLAPPEDWINDOW or WS_VISIBLE,esi,esi,390,240,ebx,ebx
        mov wndH+exebase,eax
    mov edi,offset editCls+exebase
    mov esi,offset ctlClsNameEdit+exebase
    invoke GetClassInfoEx,ebx,esi,edi
    assume edi: ptr WNDCLASSEX
    push [edi].lpfnWndProc
    pop wndProcAddr+exebase
    mov [edi].lpfnWndProc,offset edit_hex_procedure+exebase
    assume edi: nothing
    invoke RegisterClassEx,edi
    push 5
    pop ebp
    push 20
    pop edi
@@:     invoke CreateWindowEx,WS_EX_CLIENTEDGE,esi,ebx,\
    WS_CHILD + WS_VISIBLE + WS_BORDER,20,edi,300,24,wndH+exebase,ebx,exebase,ebx
        mov [editCls.hIcon + 4*ebp + exebase],eax
    invoke SendMessage,eax,EM_LIMITTEXT,15,ebx ;limit to 15 chars
    add edi,30
    dec ebp
    jns @b
        invoke SetFocus,editCls.hIcon+exebase+4*5
    mov ebp,esp
;---------------------------+
; entering the message loop |
;---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
        invoke  TranslateMessage,ebp
    invoke DispatchMessage,ebp
    jmp message_loop
;----------------------+
; the window procedure |
;----------------------+
window_procedure: cmp dword ptr [esp+08],WM_DESTROY
    je short wmDESTROY
    jmp DefWindowProc+exebase
wmDESTROY: invoke ExitProcess,ebx
;---------------------------------------------
edit_hex_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]
    push ebp
    mov ebp,esp
    mov esi,offset GetWindow+exebase
    mov edi,hWnd
        mov eax,wParam
    mov edx,umsg
    sub edx,WM_KEYDOWN
    je edit_hex_wmKEYDOWN
    dec edx;cmp edx,WM_CHAR
    dec edx
    jne  @f
edit1_wmCHAR: cmp al,VK_BACK    ;compare with virtual key BACKSPACE
    je @f
    cmp al,'0'      ;compare with ascii 0
    jb edit_hex_wmBYE
    cmp al,'9'      ;compare with ascii 9
    jbe @f
        and eax,-33     ;so our DL become big letter
    cmp al,'A'      ;compare with ascii A
    jb edit_hex_wmBYE
    cmp al,'F'      ;compare with ascii F
    ja edit_hex_wmBYE     ;something else               
@@: invoke  CallWindowProc,wndProcAddr+exebase,edi,umsg,eax,lParam
    jmp  edit_hex_wmBYE
edit_hex_wmKEYDOWN: cmp al,VK_RETURN    ;compare with virtual key RETURN
    je wmKEYDOWN_VK_RETURN
    cmp  al,VK_TAB
    jne  @b
wmKEYDOWN_VK_TAB: invoke GetKeyState,VK_SHIFT
    test eax,eax;test eax,0x80000000
    js VK_TAB_PREV;jne   VK_TAB_PREV
VK_TAB_NEXT: push GW_HWNDNEXT;=2
    push edi
    call dword ptr [esi];GetWindow
    test  eax,eax
    jne VK_TAB_BYE
    push ebx;GW_HWNDFIRST=0
    jmp @f
VK_TAB_PREV: push GW_HWNDPREV;=3
    push edi
    call dword ptr [esi];GetWindow
    test eax,eax
    jne VK_TAB_BYE
    push GW_HWNDLAST;=1
@@: push edi
    call dword ptr [esi];GetWindow
VK_TAB_BYE: push eax
    jmp @f
wmKEYDOWN_VK_RETURN: invoke SendMessage,edi,EM_GETLINE,ebx,offset ctlClsNameEdit+exebase
    invoke MessageBox,edi,offset ctlClsNameEdit+exebase,offset wTitle+exebase,ebx;MB_OK
    push edi
@@: invoke SetFocus
edit_hex_wmBYE: leave
    retn 10h
;-------------------------------------------------
ctlClsNameEdit db "Edit",0;14 + 2=16 bytes required, 15 for text, 1 for null terminated byte
editCls WNDCLASSEX <sizeof(WNDCLASSEX),0,offset edit_hex_procedure+exebase,\
0,0,exebase,0,0,0,0,0,0>
wTitle db 'Iczelion Tutorial #22:Superclassing in MASM'
;-------------------------------------------------------
import:
dd 0    
wndH dd 0
wndProcAddr dd 0
dd 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:
RegisterClassEx     dd _RegisterClassEx
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
SendMessage     dd _SendMessage
MessageBox      dd _MessageBox
GetClassInfoEx      dd _GetClassInfoEx
GetKeyState     dd _GetKeyState
GetWindow       dd _GetWindow
SetFocus        dd _SetFocus
CallWindowProc      dd _CallWindowProc
DestroyWindow       dd _DestroyWindow
TranslateMessage    dd _TranslateMessage
DefWindowProc           dd _DefWindowProc
                        dw 0
_RegisterClassEx    db 0,0,'RegisterClassExA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_SendMessage        db 0,0,'SendMessageA'
_MessageBox     db 0,0,'MessageBoxA'
_GetClassInfoEx     db 0,0,'GetClassInfoExA'
_GetKeyState        db 0,0,'GetKeyState'
_GetWindow      db 0,0,'GetWindow'
_SetFocus       db 0,0,'SetFocus'
_CallWindowProc     db 0,0,'CallWindowProcA'
_TranslateMessage   db 0,0,'TranslateMessage'
_DestroyWindow      db 0,0,'DestroyWindow'
_DefWindowProc      db 0,0,'DefWindowProcA',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
end main
Что было сделано, чтобы уменьшить размер exe-файла?
  • переменные wndH и wndProcAddr размещены в секции импорта
  • переопределен класс "Edit", а не вводился новый класс "Edit_hex"
  • Окна ввода размещались на главном окне в цикле
  • идентификаторы четырех окон ввода размещены в структуре WNDCLASSEX начиная с поля hIcon
  • совмещено использование функции SetFocus при обработке событий KEYDOWN_VK_RETURN и VK_TAB_BYE
  • адрес часто используемой функции GetWindow помещен в регистр esi
  • под буфер ввода используется строка "Edit" и часть структуры WNDCLASSEX
  • Название окна "Iczelion Tutorial #22:Superclassing in MASM" не имеет конечного нуля, так как первое поле в секции импорт нулевое
  • так как название класса "Edit" используют функции GetClassInfoEx и CreateWindowEx ― помещаем адрес строки "Edit" в регистр esi
____________________________
© Mikl___ 2013
4
Вложения
Тип файла: zip tut22a.zip (3.5 Кб, 67 просмотров)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.01.2013, 10:06
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Сам себе Iczelion (Assembler):

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

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

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

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

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

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

116
Mikl___
Заблокирован
Автор FAQ
21.01.2013, 10:48  [ТС] #62
Win32 API. Урок 23. Иконка в system tray
На этом Уроке мы узнаем, как помещать иконки в system tray и как создавать/использовать всплывающее меню.

Примеp можете скачать здесь.
Теория ― мать склероза
System tray - это прямоугольная область панели задач, в которой располагаются несколько иконок. Скорее всего, вы обнаружите там как минимум цифровые часы. Вы можете самостоятельно помещать иконки в system tray. Далее приводятся шаги, которые нужно для этого выполнить:
  • Заполните структуру NOTIFYICONDATA, содержащую следующие поля:
    • cbSize ― размер данной структуры.
    • hwnd ― хэндл окна, которое будет получать уведомление, когда над иконкой в tray'e произойдет событие мыши.
    • uID ― константа, используемая в качестве идентификатора иконки. Вы сами выбираете значение этой константе. В случае, если вы поместили в system tray несколько иконок, вы сможете узнать, над какой именно из них произошло событие мыши.
    • uFlags - указывает, какие поля данной структуры заполнены
      • NIF_ICON Поле hIcon заполнено.
      • NIF_MESSAGE Поле uCallbackMessage заполнено.
      • NIF_TIP Поле szTip заполнено.
    • uCallbackMessage - пользовательское сообщение, которое Windows отошлет указанному в поле hwnd окну, в случае, когда над иконкой произойдет событие мыши. Сообщение вы создаете сами.
    • hIcon ― хэндл иконки, которую вы хотите поместить в system tray.
    • szTiр - 64-байтовый массив, содержащий строку для использования в качестве всплывающей подсказки к иконке.
  • Вызовите Shell_NotifyIcon, определённую в shell32.inc. Данная функция имеет следующий прототип:
    Assembler
    1
    
     Shell_NotifyIcon PROTO dwMessage:DWORD, pnid:DWORD
    • dwMessage - это тип сообщения, которое нужно отправить оболочке.
      • NIM_ADD Добавляет иконку в system tray.
      • NIM_DELETE Удаляет иконку из system tray.
      • NIM_MODIFY Изменяет иконку в system tray.
    • рnid - это указатель на корректно заполненную структуру NOTIFYICONDATA.
  • Если вы хотите добавить иконку в system tray, используйте сообщение NIM_ADD, если хотите удалить иконку, применяйте NIM_DELETE.
Вот, собственно, и всё. Но чаще всего просто поместить иконку в system tray недостаточно. Вам нужно как-то реагировать на событий мыши, происходящие над этой иконкой. Это можно сделать, обрабатывая сообщение, указанное в поле uCallbackMessage структуры NOTIFYICONDATA. Это сообщение содержит следующие значения в wParam и lParam (отдельное спасибо s__d за эту информацию):
  • wParam содержит ID иконки. Это то же самое значение, что вы поместили в поле uID структуры NOTIFYICONDATA.
  • lParam Младшее слово содержит сообщение мыши. Например, если пользователь сделал правый щелчок по иконке, то lParam будет содержать WM_RBUTTONDOWN.
Обычно иконка в system tray показывает всплывающее меню при правом щелчке по ней. Этого можно добиться, если сначала создать само всплывающее меню, а затем вызывать TrackPoрuрMenu для его отображения. Шаги приведены ниже:
  • Создайте всплывающее меню, вызвав CreatePoрuрMenu. Эта функция создает пустое меню, и при успешном создании возвращает его хэндл в eax.
  • Добавьте пункты в меню с помощью AppendMenu, InsertMenu или InsertMenuItem.
  • Когда вам будет нужно отобразить всплывающее меню на месте курсора мыши, вызовите GetCursorPos, чтобы узнать текущие координаты курсора, а затем вызовите TrackPoрuрMenu, чтобы вывести меню на экран.
  • Когда пользователь щёлкнет на одном из пунктов меню, Windows отправит сообщение WM_COMMAND вашей оконной процедуре, точно так же, как и при работе с обычным меню.
Внимание: остерегайтесь следующих проблем, часто возникающих при pаботе со всплывающими меню.
  • Когда меню отображено на экране, щелчок вне меню не приводит к его немедленному исчезновению. Это происходит потому, что окно, которое будет получать уведомления от меню, ДОЛЖНО быть на переднем плане. Просто вызовите SetForegroundWindow, чтобы исправить эту проблему.
  • После вызова SetForegroundWindow вы обнаружите, что в первый раз всплывающее меню сработает нормально, но при последующем появлении оно будет отображаться, а затем тут же исчезать. Как написано в MSDN, это сделано "намеренно". Необходимо переключить задачу на программу, являющуюся владельцем иконки в system tray. Этого можно добиться, отправив любое сообщение окну вашей программы. Но только используйте PostMessage, а не SendMessage!
ПРАКТИКА ― СЕСТРА ШИЗОФРЕНИИ
Кликните здесь для просмотра всего текста
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
   .386
   .model flat,stdcall
   option casemap:none
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   include \masm32\include\shell32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
   includelib \masm32\lib\shell32.lib
 
   WM_SHELLNOTIFY equ WM_USER+5
   IDI_TRAY equ 0
   IDM_RESTORE equ 1000
   IDM_EXIT equ 1010
   WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
 
   .data
   ClassName  db "TrayIconWinClass",0
   AppName    db "TrayIcon Demo",0
   RestoreString db "&Restore",0
   ExitString   db "E&xit Program",0
 
   .data?
   hInstance dd ?
   note NOTIFYICONDATA <>
   hPopupMenu dd ?
 
   .code
start: invoke GetModuleHandle, NULL
       mov    hInstance,eax
       invoke WinMain, hInstance,NULL,NULL, 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 or CS_DBLCLKS
       mov   wc.lpfnWndProc, OFFSET WndProc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_APPWORKSPACE
       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,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
       WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+\
       WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,350,200,NULL,NULL,hInst,NULL
       mov   hwnd,eax
       .while TRUE
           invoke GetMessage, ADDR msg,NULL,0,0
           .BREAK .IF (!eax)
           invoke TranslateMessage, ADDR msg
           invoke DispatchMessage, ADDR msg
       .endw
       mov eax,msg.wParam
       ret
   WinMain endp
 
   WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
       LOCAL pt:POINT
 
       .if uMsg==WM_CREATE
           invoke CreatePopupMenu
           mov hPopupMenu,eax
           invoke AppendMenu,hPopupMenu,MF_STRING,IDM_RESTORE,addr RestoreString
           invoke AppendMenu,hPopupMenu,MF_STRING,IDM_EXIT,addr ExitString
       .elseif uMsg==WM_DESTROY
           invoke DestroyMenu,hPopupMenu
           invoke PostQuitMessage,NULL
       .elseif uMsg==WM_SIZE
           .if wParam==SIZE_MINIMIZED
               mov note.cbSize,sizeof NOTIFYICONDATA
               push hWnd
               pop note.hwnd
               mov note.uID,IDI_TRAY
               mov note.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP
               mov note.uCallbackMessage,WM_SHELLNOTIFY
               invoke LoadIcon,NULL,IDI_WINLOGO
               mov note.hIcon,eax
               invoke lstrcpy,addr note.szTip,addr AppName
               invoke ShowWindow,hWnd,SW_HIDE
               invoke Shell_NotifyIcon,NIM_ADD,addr note
           .endif
       .elseif uMsg==WM_COMMAND
           .if lParam==0
               invoke Shell_NotifyIcon,NIM_DELETE,addr note
               mov eax,wParam
               .if ax==IDM_RESTORE
                   invoke ShowWindow,hWnd,SW_RESTORE
               .else
                   invoke DestroyWindow,hWnd
               .endif
           .endif
       .elseif uMsg==WM_SHELLNOTIFY
           .if wParam==IDI_TRAY
               .if lParam==WM_RBUTTONDOWN
                   invoke GetCursorPos,addr pt
                   invoke SetForegroundWindow,hWnd
                   invoke TrackPopupMenu,hPopupMenu,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hWnd,NULL
                   invoke PostMessage,hWnd,WM_NULL,0,0
               .elseif lParam==WM_LBUTTONDBLCLK
                   invoke SendMessage,hWnd,WM_COMMAND,IDM_RESTORE,0
               .endif
           .endif
       .else
           invoke DefWindowProc,hWnd,uMsg,wParam,lParam
           ret
       .endif
       xor eax,eax
       ret
   WndProc endp
   end start
Разбор полётов
Программа отобразит на экране обычное окно. По нажатию кнопки "Свернуть" оно свернётся до иконки в system tray. По двойному щелчку по иконке программа восстановит своё окно и удалит иконку из system tray. По правому щелчку будет выведено всплывающее меню, из которого можно восстановить программу или выйти из неё.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
      .if uMsg==WM_CREATE
           invoke CreatePopupMenu
           mov hPopupMenu,eax
           invoke AppendMenu,hPopupMenu,MF_STRING,IDM_RESTORE,addr RestoreString
           invoke AppendMenu,hPopupMenu,MF_STRING,IDM_EXIT,addr ExitString
Когда будет создано главное окно, также создастся всплывающее меню, к которому затем будут добавлены два пункта. Функция AppendMenu имеет следующий синтаксис:
Assembler
1
  AppendMenu PROTO hMenu:DWORD, uFlags:DWORD, uIDNewItem:DWORD, lpNewItem:DWORD
  • hMenu это хэндл меню, к которому вы хотите добавить пункт
  • uFlags информирует Windows о добавляемом пункте меню - изображение ли это, строка или отрисовываемый владельцем объект; включен ли он, неопределён или отключен, и т.д. Полный список есть в win32 api reference. В нашем случае мы используем флаг MF_STRING, который означает, что пункт меню - это строка.
  • uIDNewItem это ID пункта меню. Это значение определяется пользователем, и используется для обращения к пункту меню.
  • lрNewItem хранит содержание пункта меню, в зависимости от значения поля uFlags. Так как мы указали MF_STRING в поле uFlags, то lрNewItem должен содержать указатель на строку для отображения в пункте меню.
После того, как всплывающее меню создано, главное окно будет терпеливо ждать до тех пор, пока пользователь не нажмет на кнопку "Свернуть".

Когда окно сворачивается, оно получает сообщение WM_SIZE со значением SIZE_MINIMIZED в wParam.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
       .elseif uMsg==WM_SIZE
           .if wParam==SIZE_MINIMIZED
               mov note.cbSize,sizeof NOTIFYICONDATA
               push hWnd
               pop note.hwnd
               mov note.uID,IDI_TRAY
               mov note.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP
               mov note.uCallbackMessage,WM_SHELLNOTIFY
               invoke LoadIcon,NULL,IDI_WINLOGO
               mov note.hIcon,eax
               invoke lstrcpy,addr note.szTip,addr AppName
               invoke ShowWindow,hWnd,SW_HIDE
               invoke Shell_NotifyIcon,NIM_ADD,addr note
           .endif
Мы используем этот момент, чтобы заполнить структуру NOTIFYICONDATA. IDI_TRAY это просто константа, определённая в начале исходного кода. Ей можно задать любое значение. Это не очень важно, так как у нас только одна иконка в system tray. Но если вы захотите поместить туда сразу несколько иконок, то вам потребуется задать уникальный ID для каждой из них. Мы выставляем сразу все флаги в поле uFlags, так как мы указываем иконку (NIF_ICON), мы указываем пользовательское сообщение (NIF_MESSAGE), а также текст всплывающей подсказки (NIF_TIP). WM_SHELLNOTIFY это просто пользовательское сообщение, определённое как WM_USER+5. Само значение не так важно, пока оно сохраняет свою уникальность. Я использовал логотип Windows в качестве иконки для этой программы, но вы можете использовать и любую другую иконку Просто загрузите её из файла ресурсов вызовом LoadIcon и сохраните возвращаемое значение в поле hIcon. После всего этого поместим в поле szTiр текст, который мы хотим видеть в качестве всплывающей подсказки к иконке.

Мы скрываем главное окно, чтобы создать эффект "сворачивания в иконку". Затем мы вызываем Shell_NotifyIcon с сообщением NIM_ADD, чтобы добавить иконку в system tray.

Теперь наше главное окно скрыто, а иконка успешно помещена в system tray. Если вы наведёте на неё курсор, то увидите подсказку с текстом, который вы поместили в поле szTip. Далее, если вы дважды щелкните по иконке, восстановится главное окно, а сама иконка исчезнет.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
       .elseif uMsg==WM_SHELLNOTIFY
           .if wParam==IDI_TRAY
               .if lParam==WM_RBUTTONDOWN
                   invoke GetCursorPos,addr pt
                   invoke SetForegroundWindow,hWnd
                   invoke TrackPopupMenu,hPopupMenu,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hWnd,NULL
                   invoke PostMessage,hWnd,WM_NULL,0,0
               .elseif lParam==WM_LBUTTONDBLCLK
                   invoke SendMessage,hWnd,WM_COMMAND,IDM_RESTORE,0
               .endif
           .endif
Когда над иконкой происходит событие мыши, ваше окно получает сообщение WM_SHELLNOTIFY, то есть пользовательское сообщение, указанное в поле uCallbackMessage. Напомню, что по приёму этого сообщения wParam содержит ID иконки, а lParam содержит событие мыши. В вышеприведенном коде сначала проверяется, пришло ли сообщение от интересующей нас иконки. Если да, то тогда мы смотрим на событие мыши. Так как нам нужны только правый щелчок и левый двойной щелчок, то мы обрабатываем лишь сообщения WM_RBUTTONDOWN и WM_LBUTTONDBLCLK.

Если сообщение от мыши это WM_RBUTTONDOWN, мы вызываем GetCursorPos, чтобы узнать текущие координаты курсора мыши. После возврата из функции, структура POINT содержит абсолютные координаты курсора. Под абсолютными координатами я подразумеваю координаты, привязанные ко всему экрану, не берущие во внимание границы окна. Например, если разрешение экрана 640*480, то правый нижний угол это x==639, y==479. Если вы желаете перевести абсолютные координаты в оконные, используйте функцию ScreenToClient.

Однако мы хотим отобразить всплывающее меню в точке, где сейчас расположен курсор мыши, с помощью функции TrackPoрuрMenu, которой требуются именно абсолютные координаты. Поэтому мы просто используем координаты, полученные от GetCursorPos.

TrackPopupMenu имеет следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
TrackPopupMenu PROTO hMenu:DWORD, uFlags:DWORD, x:DWORD, y:DWORD, nReserved:DWORD,hWnd:DWORD, prcRect:DWORD
  • hMenu это хэндл всплывающего меню, которое нужно отобразить.
  • uFlags указывает опции отображения. Например, как pасполагать меню относительно указанных ниже координат, и какая из кнопок мыши используется для отслеживания меню. В нашем примере мы используем флаг TPM_RIGHTALIGN, чтобы pазместить меню слева от указанной точки.
  • x и y указывают местоположение меню в абсолютных координатах.
  • nReserved должно содержать NULL.
  • hWnd это хэндл окна, которое будет получать сообщения от меню.
  • рrcRect это прямоугольная область экрана, щелчки в пределах которой НЕ будут приводить к исчезновению меню. Обычно сюда помещается NULL, чтобы меню исчезало при любом щелчке вне его.
Когда пользователь дважды щёлкнет по иконке, мы отправим нашему окну сообщение WM_COMMAND с указанием IDM_RESTORE, чтобы создать иллюзию выбора пользователем пункта "Восстановить" в меню, и таким образом восстановить окно, а также удалить иконку из system tray. Чтобы иметь возможность получать сообщения двойного щелчка, главное окно должно иметь стиль CS_DBLCLKS.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
               invoke Shell_NotifyIcon,NIM_DELETE,addr note
               mov eax,wParam
               .if ax==IDM_RESTORE
                   invoke ShowWindow,hWnd,SW_RESTORE
               .else
                   invoke DestroyWindow,hWnd
               .endif
Когда пользователь выберет пункт "Восстановить" в меню, мы удаляем иконку повторным вызовом Shell_NotifyIcon, только на этот раз указывая NIM_DELETE в качестве сообщения. Затем мы возвращаем первозданный вид главному окну. Если пользователь выберет пункт "Закрыть", мы тоже удаляем иконку из system tray и уничтожаем главное окно вызовом DestroyWindow.
___________________________________
© Iczelion, пер. WD-40.
3
Вложения
Тип файла: zip tut23.zip (3.4 Кб, 62 просмотров)
Mikl___
Заблокирован
Автор FAQ
22.01.2013, 10:45  [ТС] #63
Win32 API. Урок 24. Windows-хуки
В этому туториале мы изучим хуки. Это очень мощная техника. С их помощью вы сможете вмешиваться в другие процессы и иногда менять их поведение.

Скачайте пример здесь.
Теория:
Хуки Windows можно считать одной из самых мощных техник. С их помощью вы можете перехватывать события, которые случатся внутри созданного вами или кем-то другим процесса. Перехватывая что-либо, вы сообщаете Windows о фильтрующей функции, также называющейся функцией перехвата, которая будет вызываться каждый раз, когда будет происходить интересующее вас событие. Есть два вида хуков: локальные и удаленные.
  • Локальные хуки перехватывают события, которые случаются в процессе, созданном вам.
  • Удаленные хуки перехватывают события, которые случаются в других процессах. Есть два вида удаленных хуков:
    • тредоспециализированные перехватывают события, которые случатся в определенном треде другого процесса. То есть, такой хук нужен вам, когда необходимо наблюдать за процессами, происходящими в определенном треде какого-то процесса.
    • системные перехватывают все события, предназначенные для всех тредов всех процессов в системе.
При установке хуков, помните, что они оказывают отрицательное воздействие на быстродействие системы. Особенно в этом отличаются системные. Так как все требуемые события будут проходить через вашу функцию, ваша система может значительно потерять в быстродействии.

Поэтому, если вы используете системный хук, вам следует использовать их только тогда, когда вам это действительно нужно. Также, существует высокая вероятность того, что другие процессы могут зависнуть, если что-нибудь неправильно в вашей функции. Помните: вместе с силой приходит ответственность.

Вы должны понимать, как работают хуки, чтобы использовать их эффективно. Когда вы создаете хук, Windows создает в памяти структуры данных, которая содержит информацию о хуке, и добавляет ее в связанный список уже существующих хуков. Новый хук добавляется перед всеми старыми хуками. Когда случается событие, то если вы установили локальный хук, вызывается фильтрующая функция в вашем процессе, поэтому тут все просто. Hо если вы установили удаленный хук, система должна вставить код хук-процедуры в адресное пространство другого процесса. Система может сделать это только, если функция находится в DLL. Таким образом, если вы хотите использовать удаленный хук, ваша хук-процедура должна находиться в DLL. Из этого правила есть два исключения:
  1. журнально-записывающие
  2. и журнально-проигрывающие хуки
. Хук-процедуры для этих типов хуков должны находиться в треде, который инсталлировал хуки. Причина этого кроется в том, что оба хука имеют дело с низкоуровневым перехватом хардварных входных событий. Эти события должны быть записаны/проиграны в том порядке, в котором они произошли. Если код такого хука находится в DLL, входные события могут быть "разбросаны" по нескольким тредам, что делает невозможным установления точной их последовательности.
Решение: процедуры таких хуков должна быть в одном треде, то есть в том треде, который устанавливает хуки.

Существует 14 типов хуков:
  1. WH_CALLWNDрROC ― хук вызывается при вызове SendMessage.
  2. WH_CALLWNDрROCRET ― хук вызывается, когда возвращается SendMessage.
  3. WH_GETMESSAGE ― хук вызывается, когда вызывается GetMessage или PeekMessage.
  4. WH_KEYBOARD ― хук вызывается, когда GetMessage или PeekMessage получают WM_KEYUP или WM_KEYDOWN из очереди сообщений.
  5. WH_MOUSE ― хук вызывается, когда GetMessage или PeekMessage получают сообщение от мыши из очереди сообщений.
  6. WH_HADRWARE ― хук вызывается, когда GetMessage или PeekMessage получают хардварное сообщение, не относящееся к клавиатуре или мыши.
  7. WH_MSGFILTER ― хук вызывается, когда диалоговое окно, меню или скролбар готовятся к обработке сообщения. Этот хук ― локальный. Он создан специально для тех объектов, у которых свой внутренний цикл сообщений.
  8. WH_SYSMSGFILTER ― то же самое что и WH_MSGFILTER, но системный.
  9. WH_JOURNALRECORD ― хук вызывается, когда Windows получает сообщение из очереди хардварных сообщений.
  10. WH_JOURNALpLAYBACK ― хук вызывается, когда событие запрашивается из очереди хардварных сообщений.
  11. WH_SHELL ― хук вызывается, когда происходит что-то интересное и связанное с оболочкой, например, когда таскбару нужно перерисовать кнопку.
  12. WH_CBN ― хук используется специально для CBT.
  13. WH_FOREGROUND ― такие хуки используются Windows. Обычным приложениям от них пользы немного.
  14. WH_DEBUG - хук используется для отладки хук-процедуры.
Теперь, когда мы немного подучили теорию, мы можем перейти к тому, как, собственно, устанавливать/снимать хуки.

Чтобы установить хук, вам нужно вызвать функцию SetWindowsHookEx, имеющую следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
       SetWindowsHookEx proto HookType:DWORD, pHookproc:DWORD, hInstance:DWORD, ThreadID:DWORD
  • HookTyрe ― это одно из значений, перечисленных выше (WH_MOUSE, WH_KEYBOARD и т.п.).
  • pHookProc ― это адрес хук-процедуры, которая будет вызвана для обработки сообщений от хука. Если хук является удаленным, он должен находиться в DLL. Если нет, то он должен быть внутри процесса.
  • hInstance ― это хэндл DLL, в которой находится хук-процедура. Если хук локальный, тогда это значения должно быть pавно NULL.
  • ThreadID ― это ID треда, на который вы хотите поставить хук. Этот параметр определяет является ли хук локальным или удаленным. Если этот параметр равен NULL, Windows будет считать хук системным и удаленным, который затрагивает все треды в системе. Если вы укажете ID одного из тредов вашего собственного процесса, хук будет локальным. Если вы укажете ID треда из другого процесса, то хук будет тредоспециализированным и удаленным. Из этого правила есть два исключения: WH_JOURNALRECORD и WH_JOURNALPLAYBACK ― это всегда локальные системные хуки, которым не нужно быть в DLL. Также WH_SYSMSGFILTER ― это всегда системный удаленный хук. Фактически он идентичен хуку WH_MSGFILTER при ThreadID равным 0.
Если вызов успешен, он возвращает хэндл хука в eax. Если нет, возвращается NULL. Вы должны сохранить хэндл хука, чтобы снять его в дальнейшем.

Вы можете деинсталлировать хук, вызвав UnhookWindowsHookEx, которая принимает только один параметр ― хэндл хука, который нужно деинсталлировать. Если вызов успешен, он возвращает ненулевое значение в eax. Иначе он возвратит NULL.

Хук-процедура будет вызываться каждый раз, когда будет происходить событие, ассоциированное с инсталлированным хуком. Например, если вы инсталлируете хук WH_MOUSE, когда происходит событие, связанное с мышью, ваша хук-процедура будет вызвана. Вне зависимости от типа установленного хука, хук-процедура всегда будет иметь один и тот же прототип:
Кликните здесь для просмотра всего текста
Assembler
1
 HookProc proto nCode:DWORD, wParam:DWORD, lParam:DWORD
  • nCode задает код хука.
  • wParam и lParam содержат дополнительную информацию о событие.
Вместо HookProc будет имя вашей хук-процедуры. Вы можете назвать ее как угодно, главное чтобы ее прототип совпадал с вышеприведенным. Интерпретация nCode, wParam и lParam зависит от типа установленного хука, так же, как и возвращаемое хук-процедурой значение. Например:
  • WH_CALLWNDPROC
    • nCode может иметь значение HC_ACTION - это означает, что окну было послано сообщение.
    • wParam содержит посланное сообщение, если он не равен нулю, lParam указывает на структуру CWPSTRUCT.
    • возвращаемое значение: не используется, возвращайте ноль.
    WH_MOUSE
    • nCode может быть равно HC_ACTION или HC_NOREMOVE.
    • wParam содержит сообщение от мыши.
    • lParam указывает на структуру MOUSEHOOKSTRUCT.
    • возвращаемое значение:
    • ноль, если сообщение должно быть обработано.
    • 1, если сообщение должно быть пропущено.
Вы должны обратиться к вашему справочнику по Win32 API за подробным описанием значение параметров и возвращаемых значений хука, который вы хотите установить.

Теперь еще один нюанс относительно хук-процедуры. Помните, что хуки соединены в связанный список, причем в его начале стоит хук, установленный последним. Когда происходит событие, Windows вызовет только первый хук в цепи. Вызов следующего в цепи хука остается на вашей ответственности. Вы можете и не вызывать его, но вам лучше знать, что вы делаете. Как правило, стоит вызвать следующую процедуру, чтобы другие хуки также могли обработать событие. Вы можете вызвать следующий хук с помощью функции CallNextHookEx:
Кликните здесь для просмотра всего текста
Assembler
1
 CallNextHookEx proto hHook:DWORD, nCode:DWORD, wParam:DWORD, lParam:DWORD
  • hHook - хэндл вашего хука. Функция использует этот хук для того, чтобы определить, какой хук надо вызвать следующим.
  • nCode, wParam и lParam ― вы передаете соответствующие параметры, полученные от Windows.
Важная деталь относительно удаленных хуков: хук-процедура должна находиться в DLL, которая будет промэппирована в другой процесс. Когда Windows мэппирует DLL в другой процесс, секция данных мэппироваться не будет. То есть, все процессы разделяют одну копию секции кода, но у них будет своя личная копия секции кода DLL! Это может стать большим сюрпризом для непредупрежденного человека. Вы можете подумать, что при сохранении значения в переменную в секции данных DLL, это значение получать все процессы, загрузившие DLL в свое адресное пространство. Hа самом деле, это не так. В обычной ситуации, такое поведение правильно, потому что это создает иллюзию, что у каждого процесса есть отдельная копия DLL. Hо не тогда, когда это касается хуков Windows. Нам нужно, чтобы DLL была идентична во всех процессах, включая данные. решение: вы должны пометить секцию данных как разделяемую. Это можно сделать, указав атрибуты секции линкеру. Если речь идет о MASM'е, это делается так:
Код
  /SECTION:, S
Имя секции инициализированных данных '.data', а неинициализированных ― '.bss'. Например, если вы хотите скомпилировать DLL, которая содержит хук-процедуру, и вам нужно, что секция неинициализированных данных разделялась между процессами, вы должны использовать следующую команду:
Код
 link /section:.bss,S  /DLL  /SUBSYSTEM:WINDOWS ..........
атрибут 'S' отмечает, что секция разделяемая.
Практика - сестра шизофрении
Есть два модуля: один ― это основная программа с GUI'ем, а другой модуль ― это DLL, которая устанавливает/снимает хук.
Исходный код основной программы
Кликните здесь для просмотра всего текста
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
.386
   .model flat,stdcall
   option casemap:none
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   include mousehook.inc
   includelib mousehook.lib
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
 
 
   wsprintfA proto C :DWORD,:DWORD,:VARARG
   wsprintf TEXTEQU 
 
   .const
   IDD_MAINDLG                   equ 101
   IDC_CLASSNAME              equ 1000
   IDC_HANDLE                     equ 1001
   IDC_WNDpROC                 equ 1002
   IDC_HOOK                         equ 1004
   IDC_EXIT                           equ 1005
   WM_MOUSEHOOK             equ WM_USER+6
 
   DlgFunc PROTO :DWORD,:DWORD,:DWORD,:DWORD
 
   .data
   HookFlag dd FALSE
   HookText db "&Hook",0
   UnhookText db "&Unhook",0
   template db "%lx",0
 
   .data?
   hInstance dd ?
   hHook dd ?
 
   .code
start: invoke GetModuleHandle,NULL
       mov hInstance,eax
       invoke DialogBoxParam,hInstance,IDD_MAINDLG,NULL,addr DlgFunc,NULL
       invoke ExitProcess,NULL
 
   DlgFunc proc hDlg:DWORD,uMsg:DWORD,wparam:DWORD,lparam:DWORD
       LOCAL hLib:DWORD
       LOCAL buffer[128]:byte
       LOCAL buffer1[128]:byte
       LOCAL rect:RECT
 
       .if uMsg==WM_CLOSE
           .if HookFlag==TRUE
               invoke UninstallHook
           .endif
           invoke EndDialog,hDlg,NULL
       .elseif uMsg==WM_INITDIALOG
           invoke GetWindowRect,hDlg,addr rect
           invoke SetWindowpos, hDlg, HWND_TOpMOST, rect.left, rect.top,
   rect.right, rect.bottom, SWp_SHOWWINDOW
       .elseif uMsg==WM_MOUSEHOOK
           invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128
           invoke wsprintf,addr buffer,addr template,wparam
           invoke lstrcmpi,addr buffer,addr buffer1
           .if eax!=0
               invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer
           .endif
           invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128
           invoke GetClassName,wparam,addr buffer,128
           invoke lstrcmpi,addr buffer,addr buffer1
           .if eax!=0
               invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer
           .endif
           invoke GetDlgItemText,hDlg,IDC_WNDpROC,addr buffer1,128
           invoke GetClassLong,wparam,GCL_WNDpROC
           invoke wsprintf,addr buffer,addr template,eax
           invoke lstrcmpi,addr buffer,addr buffer1
           .if eax!=0
               invoke SetDlgItemText,hDlg,IDC_WNDPROC,addr buffer
           .endif
       .elseif uMsg==WM_COMMAND
           .if lparam!=0
               mov eax,wParam
               mov edx,eax
               shr edx,16
               .if dx==BN_CLICKED
                   .if ax==IDC_EXIT
                       invoke SendMessage,hDlg,WM_CLOSE,0,0
                   .else
                       .if HookFlag==FALSE
                           invoke InstallHook,hDlg
                           .if eax!=NULL
                               mov HookFlag,TRUE
                               invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText
                           .endif
                       .else
                           invoke UninstallHook
                           invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText
                           mov HookFlag,FALSE
                           invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL
                           invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL
                           invoke SetDlgItemText,hDlg,IDC_WNDpROC,NULL
                       .endif
                   .endif
               .endif
           .endif
       .else
           mov eax,FALSE
           ret
       .endif
       mov eax,TRUE
       ret
   DlgFunc endp
   end start
Это исходный код DLL
Кликните здесь для просмотра всего текста
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
.386
   .model flat,stdcall
   option casemap:none
   include \masm32\include\windows.inc
   include \masm32\include\kernel32.inc
   includelib \masm32\lib\kernel32.lib
   include \masm32\include\user32.inc
   includelib \masm32\lib\user32.lib
 
   .const
   WM_MOUSEHOOK equ WM_USER+6
 
   .data
   hInstance dd 0
 
   .data?
   hHook dd ?
   hWnd dd ?
 
   .code
   DllEntry proc hInst:HINSTANCE, reason:DWORD, reserved1:DWORD
 
       .if reason==DLL_pROCESS_ATTACH
           push hInst
           pop hInstance
       .endif
       mov  eax,TRUE
       ret
   DllEntry Endp
 
   MouseProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD
       invoke CallNextHookEx,hHook,nCode,wParam,lParam
       mov edx,lParam
 
       assume edx:ptr MOUSEHOOKSTRUCT
       invoke WindowFrompoint,[edx].pt.x,[edx].pt.y
       invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0
       assume edx:nothing
       xor eax,eax
       ret
   MouseProc endp
   InstallHook proc hwnd:DWORD
       push hwnd
       pop hWnd
       invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL
       mov hHook,eax
       ret
   InstallHook endp
 
   UninstallHook proc
       invoke UnhookWindowsHookEx,hHook
       ret
   UninstallHook endp
 
   End DllEntry
Это makefile DLL
Кликните здесь для просмотра всего текста
Код
   NAME=mousehook

   $(N*ME).dll: $(NAME).obj
           Link /SECTION:.bss,S  /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS
   /LIBpATH:c:\masm\lib $(NAME).obj
   $(NAME).obj: $(NAME).asm

           ml /c /coff /Cp $(NAME).asm
Разбор полетов
Пример отобразит диалоговое окно с тремя edit control'ами, которые будут заполнены именем класса, хэндлом окна и адресом процедуры окна, ассоциированное с окном под курсором мыши. Есть две кнопки - Hook и Exit. Когда вы нажимаете кнопку Hook, программа перехватывает сообщения от мыши и текст на кнопке меняется на Unhook. Когда вы двигаете курсор мыши над каким-либо окном, информация о нем отобразится в окне программы. Когда вы нажмете кнопку Unhook, программа уберет установленный hook.

Основная программа использует диалоговое окно в качестве основного. Она определяет специальное сообщение - WM_MOUSEHOOK, которая будет использоваться между основной программой и DLL с хуком. Когда основная программа получает это сообщение, wрaram содержит хэндл окна, над которым находится курсор мыши. Конечно, это было сделано произвольно. Я решил слать хэндл в wрaram, чтобы было проще. Вы можете выбрать другой метод взаимодействия между основной программой и DLL с хуком.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
                       .if HookFlag==FALSE
                           invoke InstallHook,hDlg
                           .if eax!=NULL
                               mov HookFlag,TRUE
                               invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText
                           .endif
Программа пользуется флагом, HookFlag, чтобы отслеживать состояние хука. Он равен FALSE, если хук не установлен, и TRUE, если установлен.

Когда пользователь нажмет кнопку hook, программа проверяет, установлен ли уже хук. Если это так, она вызывает функцию InstallHook из DLL. Заметьте, что мы передаем хэндл основного диалогового окна в качестве параметра функции, чтобы хук-DLL могла посылать сообщения WM_MOUSEHOOK верному окну, то есть нашему.

Когда программа загружена, DLL с хуком также загружается. Фактически, DLL загружаются сразу после того, как программа оказывается в памяти. Входная функция DLL вызывается прежде, чем будет исполнена первая инструкция основной программы. Поэтому, когда основная программа запускается DLLки инициализируются. Мы помещаем следующий код во входную функцию хук-DLL:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
       .if reason==DLL_PROCESS_ATTACH
           push hInst
           pop hInstance
       .endif
Данный код всего лишь сохраняет хэндл процесса DLL в глобальную переменную, названную hInstance для использования внутри функции InstallHook. Так как входная функция вызывается прежде, чем будут вызваны другие функции в DLL, hInstance будет всегда верен. Мы помещаем hInstance в секцию .data, поэтому это значение будет различаться от процесса к процессу. Когда курсор мыши проходит над окном, хук-DLL мэппируется в процесс. Представьте, что уже есть DLL, которая занимает предполагаемый загрузочный адрес хук-DLL. Значение hInstance будет обновлено. Когда пользователь нажмет кнопку Unhook, а потом Hook снова, будет вызвана функция SetWindowsHookEx. Тем не менее, в этот pаз, она будет использовать новое значение hInstance, которое будет неверным, потому что в данном процессе загрузочный адрес DLL не измениться. Хук будет локальным, что нам не нужно.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
   InstallHook proc hwnd:DWORD
       push hwnd
       pop hWnd
       invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL
       mov hHook,eax
       ret
   InstallHook endp
Функция InstallHook сама по себе очень проста. Она сохраняет хэндл окна, переданный ей в качестве параметра, в глобальную переменную hWnd. Затем она вызывает SetWindowsHookEx, чтобы установить хук на мышь. Возвращенное значение сохраняется в глобальную переменную hHook, чтобы в будущем передать ее UnhookWindowsHookEx.

После того, как вызван SetWindowsHookEx, хук начинает pаботать. Всякий pаз, когда в системе случается мышиное событие, вызывается MouseProc (ваша хук-процедура).
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
MouseProc proc nCode:DWORD,wparam:DWORD,lparam:DWORD
       invoke CallNextHookEx,hHook,nCode,wParam,lParam
       mov edx,lParam
       assume edx:ptr MOUSEHOOKSTRUCT
       invoke WindowFromPoint,[edx].pt.x,[edx].pt.y
       invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0
       assume edx:nothing
       xor eax,eax
       ret
   MouseProc endp
Сначала вызывается CallNextHookEx, чтобы другие хуки также могли обработать событие мыши. После этого, она вызывает функцию WindowFromPoint, чтобы получить хэндл окна, находящегося в указанной координате экрана. Заметьте, что мы используем структуру POINT, являющуюся членом структуры MOUSEHOOKSTRUCT, на которую указывает lParam, то есть координату текущего местонахождения курсора. После этого, мы посылаем хэндл окна основной программы через сообщение WM_MOUSEHOOK. Вы должны помнить: вам не следует использовать SendMessage в хук-процедуре, так как это может вызвать "зависания", поэтому рекомендуется использовать PostMessage. Структура MOUSEHOOKSTRUCT определена ниже:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
MOUSEHOOKSTRUCT STRUCT DWORD
     pt            POINT <>
     hwnd          DWORD      ?
     wHitTestCode  DWORD      ?
     dwExtraInfo   DWORD      ?
   MOUSEHOOKSTRUCT ENDS
  • рt - это текущая координата курсора мыши.
  • hwnd - это хэндл окна, которое получает сообщения от мыши. Это обычно окно под курсором мыши, но не всегда. Если окно вызывает SetCapture, сообщения от мыши будут перенаправлены этому окну. По этой причине я не использую параметр hwnd этой структуры, а вызываю вместо этого WindowFromPoint.
  • wHitTestCode дает дополнительную информацию о том, где находится курсор мыши. Полный список значений вы можете получить в вашем справочнике по Win32 API в разделе сообщения WM_NCHITTEST.
  • dwExtraInfo содержит дополнительную информацию, ассоциированную с сообщением. Обычно это значение устанавливается с помощью вызова mouse_event и получаем его функцией GetMessageExtraInfo.
Когда основное окно получает сообщение WM_MOUSEHOOK, оно использует хэндл окна в wParam'е, чтобы получить информацию об окне.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
      .elseif uMsg==WM_MOUSEHOOK
           invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128
           invoke wsprintf,addr buffer,addr template,wparam
           invoke lstrcmpi,addr buffer,addr buffer1
           .if eax!=0
               invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer
           .endif
           invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128
           invoke GetClassName,wparam,addr buffer,128
           invoke lstrcmpi,addr buffer,addr buffer1
           .if eax!=0
               invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer
           .endif
           invoke GetDlgItemText,hDlg,IDC_WNDpROC,addr buffer1,128
           invoke GetClassLong,wparam,GCL_WNDpROC
           invoke wsprintf,addr buffer,addr template,eax
           invoke lstrcmpi,addr buffer,addr buffer1
           .if eax!=0
               invoke SetDlgItemText,hDlg,IDC_WNDpROC,addr buffer
           .endif
Чтобы избежать мерцания, мы проверяем, не идентичны ли текст в edit control'ах с текстом, который мы собираемся ввести. Если это так, то мы пропускаем этот этап.

Мы получаем имя класса с помощью вызова GetClassName, адрес процедуры с помощью вызова GetClassLong со значением GCL_WNDPROC, а затем форматируем их в строки и помещаем в соответствующие edit control'ы.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
                           invoke UninstallHook
                           invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText
                           mov HookFlag,FALSE
                           invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL
                           invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL
                           invoke SetDlgItemText,hDlg,IDC_WNDpROC,NULL
Когда юзер нажмет кнопку Unhook, программа вызовет функцию UninstallHook в хук-DLL. UninstallHook всего лишь вызывает UnhookWindowsHookEx. После этого, она меняет текст кнопки обратно на "Hook", HookFlag на FALSE и очищает содержимое edit control'ов.

Обратите внимание на опции линкера в makefile.
Кликните здесь для просмотра всего текста
Код
  Link /SECTION:.bss,S  /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS
Секции .bss помечается как разделяемая, чтобы все процессы разделяли секцию неинициализируемых данных хук-DLL. Без этой опции, ваша DLL функционировала бы неправильно.
_________________________________
© Iczelion, пер. Aquila.
4
Вложения
Тип файла: zip tut24.zip (6.8 Кб, 60 просмотров)
Mikl___
Заблокирован
Автор FAQ
22.01.2013, 11:34  [ТС] #64
Win32 API. Урок 24a. Windows-хуки
Скачайте пример здесь.
Теория - мать склероза
Кликните здесь для просмотра всего текста

Батник для сборки dll
Кликните здесь для просмотра всего текста
Код
@echo off
cls
set filename=tut24a
if exist %filename%.dll del %filename%.dll
ml /AT /c /Cp /Gz /I\masm32\include %filename%.asm
Link16 /t %filename%.obj ,%filename%.dll;
del %filename%.obj

Содержимое файла capito_dll1.asm
Кликните здесь для просмотра всего текста
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
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
dd 14 dup(0)
dd ntHeader
dd 16 dup(0)
;------------------------------------------------------------
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 3
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table0-optional_header;
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_DLL or IMAGE_FILE_EXECUTABLE_IMAGE or \
 IMAGE_FILE_LINE_NUMS_STRIPPED or IMAGE_FILE_LOCAL_SYMS_STRIPPED
;-------------------------------------
optional_header:
Magic_optional_header   dw IMAGE_NT_OPTIONAL_HDR32_MAGIC
Linker_version_major_and_minor dw 0 
Size_of_code        dd 0
Size_of_init_data   dd 0
Size_of_uninit_data dd 0
entry_point     dd 2000h
base_of_code        dd 0
base_of_data        dd 0
image_base      dd dllbase
section_alignment       dd 1000h
file_alignment      dd 200h
OS_version_major_minor  dd 1
image_version_major_minor dd 0
subsystem_version_major_minor dd 4
reserved1       dd 0
size_of_image       dd 4000h
size_of_header      dd start
checksum        dd 0
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 1000h
Stack_commit        dd 1000h
Heap_allocation     dd 10000h
Heap_commit     dd 0
loader_flag     dd 0
number_of_dirs      dd (section_table0-export_RVA)/8
export_RVA          dd export+delta
export_size         dd end_export-export
import_RVA          dd import+delta
import_size         dd end_import-import
resource_RVA        dd 0
resource_size       dd 0
exeption_RVA        dd 0
exeption_size       dd 0
security_RVA        dd 0
security_size       dd 0
fixup_RVA       dd 3000h
fixup_size      dd end_fixups-fixups
dd 20 dup(0)
;------------------------------------------------
section_table0      dd 'ads.','at'
virtual_size0       dd 0Ch
virtual_address0    dd 1000h
Physical_size0      dd 0h
Physical_offset0    dd 100h
Relocations0        dd 0
Linenumbers0        dd 0
Relocations_and_Linenumbers_count0 dd 0
Attributes0              dd 0D0000080h
;-----------------------------------------------------
section_table1      dd 'xet.','t'
virtual_size1       dd 200h
virtual_address1    dd start+delta
Physical_size1      dd fixups-start
Physical_offset1    dd start
Relocations1        dd 0
Linenumbers1        dd 0
Relocations_and_Linenumbers_count1 dd 0
Attributes1             dd 0E0000020h
;-----------------------------------------------------
section_table2      dd 'ler.','co'
virtual_size2       dd end_fixups-fixups
virtual_address2    dd 3000h
Physical_size2      dd end_fixups-fixups
Physical_offset2    dd 400h
Relocations2        dd 0
Linenumbers2        dd 0
Relocations_and_Linenumbers_count2 dd 0
Attributes2             dd 2000040h
;-----------------------------------------------------
dd 4 dup(0)
Содержимое tut24a.asm
Кликните здесь для просмотра всего текста
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
; masm dos com #
.686p
.model tiny
include windows.inc
;for WinXP - 1060 bytes
.code
dllbase equ 400000h
delta equ 2000h-200h
main:
include capito_dll1.asm
WM_MOUSEHOOK equ WM_USER+6
;----------------------------------
.code
hInstance equ dword ptr ds:[1000h]
hHook     equ dword ptr ds:[1004h]
hWnd      equ dword ptr ds:[1008h]
 
hInst equ dword ptr [esp+4]
 
start:  push hInst
    pop hInstance+dllbase
    push TRUE
    pop eax
    retn 0Ch
 
mouse_procedure proc nCode:DWORD,wParam:DWORD,lParam:DWORD
    push lParam
    push wParam
    push nCode
    push hHook+dllbase
    call CallNextHookEx+delta+dllbase
    mov edx,lParam
    assume edx:PTR MOUSEHOOKSTRUCT
    push [edx].pt.y
    push [edx].pt.x
    call WindowFromPoint+delta+dllbase
    push 0
    push eax
    push WM_MOUSEHOOK
    push hWnd+dllbase
    call PostMessage+delta+dllbase
    assume edx:nothing
    xor eax,eax
    leave
    retn 0Ch
mouse_procedure endp
 
mouse_hook_install proc 
hwnd equ dword ptr [esp+4]
    push hwnd
    pop hWnd+dllbase
    push NULL
    push hInstance+dllbase
    push offset mouse_procedure+dllbase+delta
    push WH_MOUSE
    call SetWindowsHookEx+delta+dllbase
    mov hHook+dllbase,eax
    retn 4
mouse_hook_install endp
 
mouse_hook_uninstall proc
    push hHook+dllbase
    call UnhookWindowsHookEx+delta+dllbase
    retn
mouse_hook_uninstall endp
;--------------------------------------------------
import:
dd 0,0,0,user32_dll+delta
dd user32_table+delta,0
user32_dll      db 'USER32',0,0
dd 0
user32_table:
CallNextHookEx      dd _CallNextHookEx+delta
WindowFromPoint     dd _WindowFromPoint+delta
PostMessage     dd _PostMessage+delta
SetWindowsHookEx    dd _SetWindowsHookEx+delta
UnhookWindowsHookEx dd _UnhookWindowsHookEx+delta
            dw 0
_CallNextHookEx     db 0,0,'CallNextHookEx'
_WindowFromPoint    db 0,0,'WindowFromPoint'
_PostMessage        db 0,0,'PostMessageA'
_SetWindowsHookEx   db 0,0,'SetWindowsHookExA'
_UnhookWindowsHookEx    db 0,0,'UnhookWindowsHookEx'
end_import:
;-------------------------------------------------
export:
dd 0,0,0,tut24a_dll+delta
dd 1,2,2,functions+delta
dd names+delta,ordinals+delta
functions   dd mouse_hook_install+delta
        dd mouse_hook_uninstall+delta
names       dd _mouse_hook_install+delta
        dd _mouse_hook_uninstall+delta
ordinals        dw 0,1
tut24a_dll  db 'TUT24A',0
_mouse_hook_install db 'mouse_hook_install',0
_mouse_hook_uninstall   db 'mouse_hook_uninstall'
end_export:
;-------------------------------------------------
db 0
dd 32 dup(0)
;----------------------------------------------------------
fixups:
dd 2000h,end_fixups-fixups
dw 3006h,301Eh,3024h,3032h,3040h,3046h,3056h,305Eh,3063h
dw 306Bh,3070h,3079h,307Fh
end_fixups:
dw 0
End main
Содержимое tut24b.asm
Кликните здесь для просмотра всего текста
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
.586p
.model tiny
include windows.inc
;for WinXP - 1864 bytes
exebase     equ 400000h
WMU_MOUSEHOOK   equ WM_USER + 6
BUTTON          equ 80h
EDIT            equ 81h
STATIC          equ 82h 
DLG_MAIN    equ 101
EDIT_CLSNAME    equ 1001
EDIT_HANDLE equ 1002
EDIT_WNDPROC    equ 1003
BTN_HOOK    equ 1004
BTN_EXIT    equ 1005
size_buf    equ 128
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:  invoke  DialogBoxParam,exebase,DLG_MAIN,eax,\
    offset dialog_procedure+exebase,eax
    retn
 
dialog_procedure:
hDlg    equ dword ptr [ebp+8]
uMsg    equ dword ptr [ebp+0Ch]
wParam  equ dword ptr [ebp+10h]
lParam  equ dword ptr [ebp+14h]
    xor ebx,ebx
    enter sizeof RECT,0
    lea edi,SetDlgItemText+exebase
    mov eax,uMsg
    mov esi,hDlg
    sub eax,WM_CLOSE;WM_CLOSE=10h
    je wmCLOSE
    sub eax,WM_INITDIALOG-WM_CLOSE;WM_INITDIALOG=110h
    je wmINITDIALOG
    dec eax;WM_COMMAND=111h
    je wmCOMMAND
    sub eax,WMU_MOUSEHOOK-WM_COMMAND;WMU_MOUSEHOOK=406h
    jne wmBYE
wmuMOUSEHOOK: invoke GetDlgItemText,esi,EDIT_HANDLE,\
    offset buf2+exebase,size_buf
    invoke wsprntf,offset buf1+exebase,offset f1+exebase,wParam
    mov esi,EDIT_HANDLE
    call proc1
    invoke  GetDlgItemText,esi,EDIT_CLSNAME,offset buf2+exebase,size_buf
    invoke  GetClassName,wParam,offset buf1+exebase,size_buf
    mov esi,EDIT_CLSNAME
    call proc1
    invoke  GetDlgItemText,esi,EDIT_WNDPROC,offset buf2+exebase,size_buf
    invoke  GetClassLong,wParam,GCL_WNDPROC
    invoke  wsprntf,offset buf1+exebase,offset f1+exebase,eax
    mov esi,EDIT_WNDPROC
    call proc1
    jmp  wmBYE
 
wmCLOSE: cmp hookFlag+exebase,TRUE
    jne @f
    invoke mouse_hook_uninstall
@@: invoke EndDialog,esi,ebx
    jmp wmBYE
 
wmINITDIALOG: mov edi,esp
    invoke GetWindowRect,esi,edi;rect
    assume edi: ptr RECT
    invoke SetWindowPos,esi,HWND_TOPMOST,[edi].left,\
    [edi].top,[edi].right,[edi].bottom,SWP_SHOWWINDOW
    jmp wmBYE
wmCOMMAND: mov eax,wParam
    test eax,eax
    je wmBYE
    cmp word ptr wParam+2,BN_CLICKED
    jne wmBYE
    cmp eax,BTN_EXIT
    jne wmCOMMAND_BTN_HOOK
wmCOMMAND_BTN_EXIT: invoke SendMessage,esi,WM_CLOSE,ebx,ebx
    jmp  wmBYE
BTN_HOOK_FALSE: invoke mouse_hook_install,esi
    test eax,eax
    je wmBYE
    push offset txtUnhook+exebase
    push BTN_HOOK
    push esi
    call dword ptr [edi]
    jmp  wmBYE      
wmCOMMAND_BTN_HOOK: xor hookFlag+exebase,1;cmp  [hookFlag],TRUE
    jne BTN_HOOK_FALSE
    invoke mouse_hook_uninstall
    push ebx
    push ebx
    push ebx
    push offset txtHook+exebase
    or ebx,4
@@: push [handlers+ebx*4-4+exebase]
    push esi
    call dword ptr [edi]
    dec ebx
    jnz @b
wmBYE:  leave
    xor eax,eax
    retn 10h
 
proc1 proc 
    invoke  lstrcmpi,offset buf1+exebase,offset buf2+exebase
    test eax,eax
    je @f
    push offset buf1+exebase
    push esi
    push hDlg
    call dword ptr [edi]
@@: retn
proc1 endp
handlers dd  EDIT_WNDPROC,EDIT_HANDLE,EDIT_CLSNAME,BTN_HOOK
txtUnhook db '&Unhook',0
txtHook db '&Hook',0
 
buf1    db size_buf dup(?)
buf2    db size_buf dup(?)
f1  db '0x%lX',0
align 4
;---------------------------------------------------------------------
resource:
dd 0,0,0
NumberOfNamedEntries0   dw 0;количество ресурсов с именами
NumberOfIdEntries0  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_DIALOG,0,d1-resource,8000h
d1:
dd 0,0,0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
dw DLG_MAIN,0,d2-resource,8000h
d2:
dd 0,0,0
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
dw 40Ah,0,d3-resource,0
d3: 
dd dialog,end_dialog-dialog,0,0
dialog: 
style0 dd WS_CAPTION or WS_POPUP or WS_SYSMENU or DS_MODALFRAME or 40h
dwExtendedStyle dd 0
 
cdit0 dw 9 ;число элементов управления, входящих в состав диалогового окна 
x0    dw 0;отступ левой границы окна от левой границы экрана
y0    dw 0;отступ верхней границы окна от верхней границы экрана
cx0   dw 229;ширина окна
cy0   dw 85;высота окна
      dw 0;есть меню у диалога (=FFFF) или меню нет (=0)
      dw 0
CAPTION: du <Iczelion Tutorial #24: Mouse Hook Demo>;заголовок диалога
font dw 8
du <MS Sans Serif>
dw 9090h
;------------------------------------------------------
;элементы управления диалога    
u1:
style1 dd WS_VISIBLE or BS_GROUPBOX or WS_CHILD
dwExtendedStyle1 dd 0
x1  dw 7;x-координаты верхнего левого угла
y1  dw 7;y-координаты верхнего левого угла
cx1 dw 214;ширина объекта управления
cy1 dw 67;высота объекта управления
id1 dw -1;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw BUTTON;тип объекта управления 
du <Window Information>;надпись на объекте управления
dw 0,0;терминатор
;---------------------------------------------------
u2:
style2 dd WS_VISIBLE or SS_LEFT or WS_CHILD
dwExtendedStyle2 dd 0
x2  dw 21;x-координаты верхнего левого угла
y2  dw 22;y-координаты верхнего левого угла
cx2 dw 42;ширина объекта управления
cy2 dw 8;высота объекта управления
id2 dw -1;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw STATIC;тип объекта управления 
du <Class Name :>;надпись на объекте управления
dw 0,0;терминатор
;----------------------------------------------------
u3:
style3 dd ES_AUTOHSCROLL or ES_READONLY or WS_VISIBLE or WS_BORDER \
or DS_3DLOOK or WS_TABSTOP or ES_LEFT or WS_CHILD
dwExtendedStyle3 dd 0
x3  dw 69;x-координаты верхнего левого угла
y3  dw 20
cx3 dw 139
cy3 dw 12
id3 dw EDIT_CLSNAME;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления 
dw 0,0;терминатор
;----------------------------------------------------
u4:
style4 dd WS_VISIBLE or SS_LEFT or WS_CHILD
dwExtendedStyle4 dd 0
x4  dw 36;x-координаты верхнего левого угла
y4  dw 37;y-координаты верхнего левого угла
cx4 dw 28;ширина объекта управления
cy4 dw 8;высота объекта управления
id4 dw -1;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw STATIC;тип объекта управления 
du <Handle :>;надпись на объекте управления
dw 0,0;терминатор
;---------------------------------------------------
u5:
style5 dd ES_AUTOHSCROLL or ES_READONLY or WS_VISIBLE or WS_BORDER \
or DS_3DLOOK or WS_TABSTOP or ES_LEFT or WS_CHILD
dwExtendedStyle5 dd 0
x5  dw 69;x-координаты верхнего левого угла
y5  dw 36;y-координаты верхнего левого угла
cx5 dw 76;ширина объекта управления
cy5 dw 12;высота объекта управления
id5 dw EDIT_HANDLE;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления
dw 0,0;терминатор
;----------------------------------------------------
u6:
style6 dd WS_VISIBLE or SS_LEFT or WS_CHILD
dwExtendedStyle6 dd 0
x6  dw 15;x-координаты верхнего левого угла
y6  dw 52
cx6 dw 48
cy6 dw 8
id6 dw -1;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw STATIC;тип объекта управления 
du <Window Proc :>;надпись на объекте управления    
dw 0;терминатор
;----------------------------------------------------
u7:
style7 dd ES_AUTOHSCROLL or ES_READONLY or WS_VISIBLE or WS_BORDER \
or DS_3DLOOK or WS_TABSTOP or ES_LEFT or WS_CHILD
dwExtendedStyle7 dd 0
x7  dw 69;x-координаты верхнего левого угла
y7  dw 52;y-координаты верхнего левого угла
cx7 dw 76;ширина объекта управления
cy7 dw 12;высота объекта управления
id7 dw EDIT_WNDPROC;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления
dw 0,0;терминатор
;---------------------------------------------------
u8:
style8 dd BS_DEFPUSHBUTTON  or  WS_VISIBLE  or  WS_TABSTOP or WS_CHILD
dwExtendedStyle8 dd 0
x8  dw 159;x-координаты верхнего левого угла
y8  dw 35;y-координаты верхнего левого угла
cx8 dw 50;ширина объекта управления
cy8 dw 14;высота объекта управления
id8 dw BTN_HOOK;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw BUTTON;тип объекта управления 
du <&Hook>;надпись на объекте управления
dw 0;терминатор
;----------------------------------------------------
u9:
style9 dd BS_PUSHBUTTON or WS_VISIBLE or WS_TABSTOP or WS_CHILD
dwExtendedStyle9 dd 0
x9  dw 159;x-координаты верхнего левого угла
y9  dw 51
cx9 dw 50
cy9 dw 15
id9 dw BTN_EXIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw BUTTON;тип объекта управления 
du <&Exit>;надпись на объекте управления    
;----------------------------------------------------
end_dialog:
end_resource:
import: 
dd 0
hookFlag dd FALSE
dd 0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0,0,tut24a_dll
dd tut24a_table
dd 0,0
kernel32_table:
lstrcmpi        dd _lstrcmpi,0
user32_table:
SetDlgItemText      dd _SetDlgItemText
SendMessage     dd _SendMessage
wsprntf         dd _wsprintf
DialogBoxParam      dd _DialogBoxParam
GetWindowRect       dd _GetWindowRect
GetClassName        dd _GetClassName
GetClassLong        dd _GetClassLong
GetDlgItemText      dd _GetDlgItemText
SetWindowPos        dd _SetWindowPos
EndDialog       dd _EndDialog,0
tut24a_table:
mouse_hook_install  dd _mouse_hook_install
mouse_hook_uninstall    dd _mouse_hook_uninstall
                        dw 0
_SendMessage        db 0,0,'SendMessageA'
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_wsprintf       db 0,0,'wsprintfA'
_DialogBoxParam     db 0,0,'DialogBoxParamA'
_GetWindowRect      db 0,0,'GetWindowRect'
_GetClassName       db 0,0,'GetClassNameA'
_GetClassLong       db 0,0,'GetClassLongA'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_SetWindowPos       db 0,0,'SetWindowPos'
_EndDialog      db 0,0,'EndDialog',0
user32_dll      db 'user32'
_lstrcmpi       db 0,0,'lstrcmpiA',0
kernel32_dll        db 'kernel32'
_mouse_hook_install db 0,0,'mouse_hook_install'
_mouse_hook_uninstall   db 0,0,'mouse_hook_uninstall',0
tut24a_dll      db 'tut24a'
end_import:
end main
___________________________
© Mikl___ 2013
4
Миниатюры
Сам себе Iczelion  
Вложения
Тип файла: zip tut24a.zip (7.5 Кб, 48 просмотров)
Mikl___
Заблокирован
Автор FAQ
22.01.2013, 12:59  [ТС] #65
Win32 API. Урок 25. Простой битмэп
На этом уроке мы научимся использовать битмэпы в своих программах. Если быть более точным, мы научимся отображать битмэп в клиентской области нашей программы.

Скачайте пример здесь.
Теория ― мать склероза
Битмэпы можно представлять себе как изображения, хранимые в компьютере. На компьютерах используется множество различных форматов изображений, но Windows естественным образом поддерживает только формат растровых изображений Windows (.bmр). На этом уроке, когда речь будет идти о битмэпах, будет подразумеваться именно этот формат. Самый простой способ использовать битмэп - это использовать его как ресурс. Есть два способа это выполнить. Можно включить битмэп в файл определения ресурсов (.rc) следующим образом:
Кликните здесь для просмотра всего текста
C
1
2
       #define IDB_MYBITMAp   100
       IDB_MYBITMAP  BITMAP  "c:\project\example.bmp"
В этом методе для представления битмэпа используется константа. В первой строчке просто задаётся константа с именем IDB_MYBITMAp и значением 100. По этому имени мы и будем обращаться к битмэпу в нашей программе. В следующей строке объявляется битмэп-ресурс. Таким образом, компилятор узнаёт, где ему искать собственно сам bmp-файл.

В другом методе для представления битмэпа используется имя, делается это следующим образом:
Кликните здесь для просмотра всего текста
Код
 MyBitMap  BITMAP "c:\project\example.bmp"
При использовании этого метода, в вашей программе вам придётся ссылаться на битмэп по строке "MyBitMaр", а не по значению.

Оба метода прекрасно работают, главное - определиться, какой именно вы будете использовать. После включения битмэпа в файл ресурсов, можно приступить к его отображению в клиентской области нашего окна:
  • Вызовите LoadBitmap чтобы узнать хэндл битмэпа. Функция LoadBitmaр имеет следующий прототип:
    Assembler
    1
    
     LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LpSTR
    Функция возвращает хэндл битмэпа.
  • hInstance есть хэндл инстанции вашей программы.
  • lрBitmaрName - это указатель на строку, содержащую имя битмэпа (необходимо при использовании 2-го метода). Если для обращения к битмэпу вы используете константу (например, IDB_MYBITMAP), то её значение вы и должны сюда поместить (в нашем случае это было бы значение 100).
Не помешает небольшой пример:
  • Первый метод:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    .386
               .model flat, stdcall
               ................
               .const
     
               IDB_MYBITMAP    equ 100
               ...............
               .data?
               hInstance  dd ?
     
               ..............
               .code
               .............
                   invoke GetModuleHandle,NULL
     
                   mov hInstance,eax
               ............
                   invoke LoadBitmap,hInstance,IDB_MYBITMAP
               ...........
  • Второй метод:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
               .386
               .model flat, stdcall
               ................
     
               .data
               BitmapName  db "MyBitMap",0
               ...............
               .data?
     
               hInstance  dd ?
               ..............
               .code
               .............
     
                   invoke GetModuleHandle,NULL
                   mov hInstance,eax
               ............
                   invoke LoadBitmap,hInstance,addr BitmapName
     
               ...........
  • Получите хэндл device context'a (DC). Это можно сделать либо вызовом функции BeginPaint в ответ на сообщение WM_PAINT, либо вызовом GetDC в любое время.

    Создайте device context в памяти (memory DC) с теми же атрибутами, что и device context, полученный на предыдущем шаге. Идея в том, чтобы создать некоторую "невидимую" поверхность, на которой мы можем отрисовать битмэп. После этого мы просто копируем содержимое невидимой поверхности в текущий device context с помощью вызова одной-единственной функции. Этот приём называется двойной буферизацией (double buffering) и используется для быстрого вывода изображений на экран. Создать "невидимую" поверхность можно вызовом CreateCompatibleDC:
    Assembler
    1
    
     CreateCompatibleDC  proto  hdc:HDC
    При успешном завершении функция возвращает через регистр eax хэндл device context'a в памяти. hdc - это хэндл device context'a, с которым должен быть совместим DC в памяти.
  • После создания невидимой поверхности вы можете отобразить на ней битмэп с помощью вызова SelectObject, передав ей в качестве первого параметра хэндл DC в памяти, а в качестве второго - хэндл битмэпа. Прототип этой функции следующий:
    Assembler
    1
    
     SelectObject   proto  hdc:HDC, hGdiObject:DWORD
  • Теперь битмэп отображен на device context'e в памяти. Единственное, что осталось сделать - это скопировать его на на устройство вывода, то есть на настоящий device context. Этого можно добиться с помощью таких функций, как BitBlt и StretchBlt. BitBlt просто копирует содержимое одного DC в другой, поэтому она работает быстро; StretchBlt может сжимать или растягивать изображение по размерам того DC, куда копирует. Для простоты здесь мы будем использовать BitBlt, имеющую следующий прототип:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    
    BitBlt proto hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD,\
               nWidth:DWORD, nHeight:DWORD, hdcSrc:DWORD, nxSrc:DWORD,\
               nySrc:DWORD, dwROp:DWORD
    • hdcDest это хэндл device context'a, в который копируется битмэп
    • nxDest, nyDest это координаты верхнего левого угла области вывода
    • nWidth, nHeight это ширина и высота области вывода
    • hdcSrc это хэндл device context'a, из которого копируется битмэп
    • nxSrc, nySrc это координаты левого верхнего угла исходной области
    • dwROр это код растровой операции (raster-oрeration code, ROp), указывающий, как совмещать пиксели исходного и конечного изображений. Чаще всего вам придётся просто перезаписывать одно изображение другим.
  • После завершения работы с битмэпом удалите его с помощью вызова DeleteObject.
Вот и всё! Если коротко, то сначала добавьте битмэп в файл ресурсов. После этого загрузите его из ресурсов с помощью LoadBitmap. Вы получите хэндл битмэпа. Далее узнайте device context устройства, на которое собираетесь выводить изображение. Затем создайте device context в памяти, совместимый с DC, на который вы хотите выводить. "Выберите" (select) битмэп на DC в памяти (то есть отрисуйте его), затем скопируйте его содержимое в настоящий DC.
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
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
.386
   .model flat,stdcall
   option casemap:none
   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
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
   IDB_MAIN   equ 1
 
   .data
   ClassName db "SimpleWin32ASMBitmapClass",0
   AppName  db "Win32ASM Simple Bitmap Example",0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LpSTR ?
   hBitmap dd ?
 
   .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  hInstance
    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 TranslateMessage, ADDR msg
     invoke DispatchMessage, ADDR msg
    .endw
    mov     eax,msg.wparam
    ret
   WinMain endp
 
   Wndproc proc hWnd:HWND, uMsg:UINT, wparam:WpARAM, lparam:LpARAM
      LOCAL ps:pAINTSTRUCT
      LOCAL hdc:HDC
      LOCAL hMemDC:HDC
      LOCAL rect:RECT
 
      .if uMsg==WM_CREATE
         invoke LoadBitmap,hInstance,IDB_MAIN
         mov hBitmap,eax
      .elseif uMsg==WM_pAINT
         invoke Beginpaint,hWnd,addr ps
         mov    hdc,eax
         invoke CreateCompatibleDC,hdc
         mov    hMemDC,eax
         invoke SelectObject,hMemDC,hBitmap
         invoke GetClientRect,hWnd,addr rect
         invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY
         invoke DeleteDC,hMemDC
         invoke Endpaint,hWnd,addr ps
    .elseif uMsg==WM_DESTROY
     invoke DeleteObject,hBitmap
     invoke postQuitMessage,NULL
    .ELSE
     invoke DefWindowproc,hWnd,uMsg,wparam,lparam
     ret
    .ENDIF
    xor eax,eax
    ret
   Wndproc endp
   end start
Файл ресурсов
Кликните здесь для просмотра всего текста
C
1
2
   #define IDB_MAIN 1
   IDB_MAIN BITMAP "tweety78.bmp"
Анализ:
Собственно, на этом уроке и анализировать нечего
Кликните здесь для просмотра всего текста
C
1
2
       #define IDB_MAIN 1
       IDB_MAIN BITMAp "tweety78.bmp"
Определите константу IDB_MAIN, присвоив ей значение 1. Затем используйте эту константу при определении битмэп-ресурса. Файл, который будет включен в ресурсы, называется "tweety78.bmр" и располагается в той же папке, что и файл ресурсов.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
      .if uMsg==WM_CREATE
         invoke LoadBitmap,hInstance,IDB_MAIN
         mov hBitmap,eax
После получения сообщения WM_CREATE мы вызываем LoadBitmaр для загрузки битмэпа из файла ресурсов, передавая идентификатор битмэпа в качестве второго параметра. По завершению работы функции мы получим хэндл битмэпа. Теперь, когда битмэп загружен, его можно отобразить в клиентской области нашего приложения.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
      .elseif uMsg==WM_PAINT
         invoke Beginpaint,hWnd,addr ps
         mov    hdc,eax
         invoke CreateCompatibleDC,hdc
         mov    hMemDC,eax
         invoke SelectObject,hMemDC,hBitmap
         invoke GetClientRect,hWnd,addr rect
         invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY
         invoke DeleteDC,hMemDC
         invoke Endpaint,hWnd,addr ps
Мы решили отрисовывать битмэп в ответ на сообщение WM_PAINT. Для этого мы сначала вызываем BeginPaint и получаем хэндл DC. Затем создаем совместимый memory DC вызовом CreateComрatibleDC. Далее "выбираем" битмэп в память с помощью SelectObject. Определяем размеры клиентской области окна через GetClientRect. Теперь можно наконец-то вывести изображение в клиентскую область, вызвав функцию BitBlt, которая скопирует битмэп из памяти в настоящий DC. По завершению рисования мы удаляем DC в памяти вызовом DeleteDC, так как он нам больше не нужен. Подаём сигнал о завершении отрисовки окна с помощью EndPaint.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
        .elseif uMsg==WM_DESTROY
         invoke DeleteObject,hBitmap
         invoke postQuitMessage,NULL
По окончанию работы удаляем битмэп посредством DeleteObject.
_______________________________
© Iczelion, пер. WD-40.
4
Вложения
Тип файла: zip tut25.zip (26.4 Кб, 57 просмотров)
Mikl___
Заблокирован
Автор FAQ
23.01.2013, 04:11  [ТС] #66
Урок 25a. Рисуем сами
На этом уроке мы научимся использовать битмэпы в своих программах. Если быть более точным, мы научимся отображать битмэп в клиентской области нашей программы.
Скачайте файл примера здесь.
Теория ― мать склероза
Итак, мы хотим вывести рисунок на окно, но как это сделать проще, не используя множество API-функций: BeginPaint и Endpaint, CreateCompatibleDC и DeleteDC, GetClientRect, BitBlt, SelectObject и DeleteObject... Открываем книгу отечественных классиков, исследователей недр MSDN, братьев Александра Вячеслововича и Григория Вячеслововича Фроловых «Graphic Device Interface»
Создание кисти
  1. Если нам понадобилось окрасить наше окно, то мы в WNDCLASSEX в поле hbrBackground указываем одну из 28 констант
Кликните здесь для просмотра всего текста
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
COLOR_SCROLLBAR                      equ 0
COLOR_BACKGROUND                     equ 1
COLOR_ACTIVECAPTION                  equ 2
COLOR_INACTIVECAPTION                equ 3
COLOR_MENU                           equ 4
COLOR_WINDOW                         equ 5
COLOR_WINDOWFRAME                    equ 6
COLOR_MENUTEXT                       equ 7
COLOR_WINDOWTEXT                     equ 8
COLOR_CAPTIONTEXT                    equ 9
COLOR_ACTIVEBORDER                   equ 10
COLOR_INACTIVEBORDER                 equ 11
COLOR_APPWORKSPACE                   equ 12
COLOR_HIGHLIGHT                      equ 13
COLOR_HIGHLIGHTTEXT                  equ 14
COLOR_BTNFACE                        equ 15
COLOR_BTNSHADOW                      equ 16
COLOR_GRAYTEXT                       equ 17
COLOR_BTNTEXT                        equ 18
COLOR_INACTIVECAPTIONTEXT            equ 19
COLOR_BTNHIGHLIGHT                   equ 20
COLOR_3DDKSHADOW                     equ 21
COLOR_3DLIGHT                        equ 22
COLOR_INFOTEXT                       equ 23
COLOR_INFOBK                         equ 24
COLOR_DESKTOP                        equ COLOR_BACKGROUND
COLOR_3DFACE                         equ COLOR_BTNFACE
COLOR_3DSHADOW                       equ COLOR_BTNSHADOW
COLOR_3DHIGHLIGHT                    equ COLOR_BTNHIGHLIGHT
COLOR_3DHILIGHT                      equ COLOR_BTNHIGHLIGHT
COLOR_BTNHILIGHT                     equ COLOR_BTNHIGHLIGHT
COLOR_HOTLIGHT                       equ 26
COLOR_GRADIENTACTIVECAPTION          equ 27
COLOR_GRADIENTINACTIVECAPTION        equ 28
  • Цвет соответствующего компонента можно изменить, если щелкнуть по пустой области экрана правой клавишей, выбрать раздел «Свойства http://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrowОформление» и выбрать цветовую схему соответствующему элементу.
    Кликните здесь для просмотра всего текста
  • Цвет кисти можно задать функцией GetStockBrush из нескольких типов системных кистей, которые можно использовать:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    
    WHITE_BRUSH                          equ 0;белый цвет заполнения
    LTGRAY_BRUSH                         equ 1;светло-серый
    GRAY_BRUSH                           equ 2;серый
    DKGRAY_BRUSH                         equ 3;темно-серый
    BLACK_BRUSH                          equ 4;черный
    NULL_BRUSH                           equ 5;прозрачная кисть
    HOLLOW_BRUSH                         equ NULL_BRUSH
  • Если предопределенный цвет вам не подходит, то с помощью функции CreateSolidBrush можно создать цветную кисть:
    C
    1
    
    HBRUSH WINAPI CreateSolidBrush(COLORREF clrref);
    В качестве параметра для этой функции необходимо указать цвет кисти. Для выбора цвета можно воспользоваться 32-битовым целым типа COLORREF. Windows позволяет задать цвет тремя различными способами.
    1. Первый и наиболее общий заключается в задании RGB-значений (Red, Green, Blue). RGB-значение комбинирует относительные интенсивности трех различных цветов, в результате чего получается реальный цвет.
      байтцвет
      байт 3 (старший)Должен быть равен нулю
      байт 2Синий
      байт 1Зеленый
      байт 0 (младший)Красный
      интенсивность каждого цвета в RGB-значении может задаваться в
      диапазоне от 0 до 0FFh(255), причем значение 0 определяет минимальную, а значение 0FFh ― максимальную интенсивность задаваемого цвета. Например, вот так задаются основные цвета
      ███ 00FFFFFFhбелый
      ███ 000000FFhкрасный
      ███ 000080FFhоранжевый
      ███ 0000FFFFhжелтый
      ███ 0000FF00hзеленый
      ███ 00D0D000hголубой
      ███ 00FF0000hсиний
      ███ 00FF00FFhфиолетовый
      ███ 00007070hкоричневый
      ███ 00000000hчерный
    2. Второй способ определения цвета предполагает задание индекса цвета в логической палитре.
    3. Третий заключается в определении RGB-значения относительно текущей логической палитры.
Windows может выбрать для кисти чистые или смешанные цвета, в зависимости от текущего цветового разрешения. После использования созданной кисти ее следует удалить, не забыв перед этим выбрать в контекст отображения старую кисть. Для удаления кисти используют макрокоманду DeleteBrush или функцию DeleteObject:
C
1
#define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
Можно заштриховать внутреннюю область замкнутой фигуры, создав одну из шести штриховых кистей созданной функцией CreateHatchBrush :
C
1
HBRUSH WINAPI CreateHatchBrush(int fnStyle, COLORREF clrref);
Параметр clrref определяет цвет линий штриховки, а параметр fnStyle задает стиль штриховки:
Стиль штриховкиВнешний вид
HS_BDIAGONAL
HS_CROSS
HS_DIAGCROSS
HS_FDIAGONAL
HS_HORIZONTAL
HS_VERTICAL
А вот самое главное, ради чего мы полезли в недра GDI ― «можно использовать свой собственный стиль штриховки, создав кисть из битового изображения размером 8х8 пикселей (можно использовать только такой размер)...» Если битовое изображение кисти определено в ресурсах приложения, его следует загрузить при помощи функции LoadBitmap, а если из файла ― то при помощи LoadImage. Эти функции возвратят идентификатор битового изображения. Затем для создания кисти этот идентификатор следует передать в качестве параметра функции CreatePatternBrush:
C
1
HBRUSH WINAPI CreatePatternBrush(HBITMAP hBitmap);
А что если братья Фроловы ошибаются и размер рисунка не ограничен 8 на 8 точек?
Загружаем изображение из файла при помощи LoadImage, передаем идентификатор функции CreatePatternBrush, создаем кисть и, с ее помощью, закрашиваем окно.
Кликните здесь для просмотра всего текста
И всё! Не нужно никаких BeginPaint и EndPaint, CreateCompatibleDC и DeleteDC, GetClientRect, BitBlt, SelectObject и DeleteObject... Никакой обработки WM_PAINT, ни каких дескрипторов и контекстов изображения, ни каких device context'ов
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
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
; masm dos com #
.586p
.model tiny
;for WinXP - 586 bytes
include windows.inc
.code
exebase         equ 400000h
main:
include capito.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase;400000h
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke LoadImage,esi,edi,ebx,ebx,ebx,LR_LOADFROMFILE,ebx,edi
    invoke CreatePatternBrush,eax
    invoke RegisterClass,esp,ebx,offset window_procedure+\
    exebase,ebx,ebx,esi,ebx,10011h,eax
;--------------------------+
; creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,WS_CAPTION or WS_SYSMENU or \
    WS_MINIMIZEBOX or WS_VISIBLE,esi,esi,286,305,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+08],WM_DESTROY
    je short wmDESTROY
    jmp DefWindowProc+exebase
wmDESTROY: invoke ExitProcess,ebx
;---------------------------------------------                         
wTitle db 'Images\tweety78.bmp';name of our window
;-------------------------------------------------
import:
dd 0,0,0,user32_dll,  user32_table
dd 0,0,0,gdi32_dll,   gdi32_table
dd 0,0,0,kernel32_dll,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
LoadImage       dd _LoadImage
DefWindowProc           dd _DefWindowProc,0
gdi32_table:
CreatePatternBrush  dd _CreatePatternBrush
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_LoadImage      db 0,0,'LoadImageA'
_DefWindowProc      db 0,0,'DefWindowProcA',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_CreatePatternBrush db 0,0,'CreatePatternBrush',0
gdi32_dll       db 'gdi32'
end_import:
end main


© Mikl___ 2013
3
Миниатюры
Сам себе Iczelion   Сам себе Iczelion  
Изображения
      
Вложения
Тип файла: zip tut25a.zip (13.9 Кб, 62 просмотров)
Mikl___
Заблокирован
Автор FAQ
23.01.2013, 04:56  [ТС] #67
Win32 API. Урок 26. Сплэш-экран
Теперь, когда мы знаем, как использовать битмап, мы можем применить его более творчески. Сплэш-экран.

Скачайте пример.
Теория ― мать склероза
Сплэш-экран - это окно, у которого нет заголовка, нет системных кнопок, нет border'а, которое отображает битмап на некоторое время и затем исчезает. Обычно оно используется во время загрузки программы, чтобы отображать логотип программы или отвлечь внимание пользователя, пока программа делает объемную инициализацию. В этом туториале мы создадим сплэш-экран.
Первый шаг ― это прописать битмап в файле ресурсов. Тем не менее, если это важно для вас, то загружать битмап, который будет использоваться только один раз, и держать его в памяти, пока программа не будет закрыта, пустая трата ресурсов. Лучшим решением является ресурсовую DLL, которая будет содержать битмап, и чьей целью является отображение сплэш-экрана. В этом случае вы сможете загрузить DLL, когда вам нужно отобразить сплэш-экран, и выгрузить ее, как только нужда в ней отпадает. Поэтому у нас будет два модуля: основная программа и сплэш-экран. Мы поместим битмап в файл ресурсов DLL.

Общая схема такова:
  • Поместить битмап в DLL как ресурс.
  • Основная программа вызывает LoadLibrary, чтобы загрузить dll в память.
  • Запускается входная функция DLL. Она создаст таймеp и установит время, в течении которого будет отображаться сплэш-экран. Затем она зарегистрирует и создаст окно без заголовка и бордера, после чего отобразит битмап в клиенсткой области.
  • Когда закончится указанный период времени, сплэш-экран будет убран с экрана и контроль будет передан главной программе.
  • Основная программа вызовет FreeLibrary, чтобы выгрузить DLL из памяти, а затем перейдет к выполнению того, к чему она предназначена.
Мы детально проанализируем описанную последовательность действий.
Загрузка/выгрузка DLL
Вы можете динамически загрузить DLL с помощью функции LoadLibrary, которая имеет следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
       LoadLibrary  proto lpDLLName:DWORD
Она принимает только один параметр: адрес имени DLL, который вы хотите загрузить в память. Если вызов пройдет успешно, он возвратит хэндл модуля DLL, в противном случае NULL.

Чтобы выгрузить DLL, вызовите FreeLibrary:
Кликните здесь для просмотра всего текста
Assembler
1
 FreeLibrary  proto  hLib:DWORD
Она получает один параметр: хэндл модуля DLL, которую вы хотите выгрузить.
Как использовать таймеp
Во-первых, мы должны создать таймер с помощью функции SetTimer:
Кликните здесь для просмотра всего текста
Assembler
1
 SetTimer  proto  hWnd:DWORD, TimerID:DWORD, uElapse:DWORD, lpTimerFunc:DWORD
  • hWnd ― хэндл окна, которое будет получать уведомительные сообщения от таймера. Этот параметр может быть равным NULL, если никакое окно не ассоциируется с таймером.
  • TimerID ― заданное пользователем значение, которое будет использоваться в качестве ID таймера.
  • uElaрse ― временной интервал в миллисекундах.
  • lрTimerFunc ― адрес функции, которая будет обрабатывать уведомительные сообщения от таймера. Если вы передает NULL, сообщения от таймера будут посылаться окну, указанному в параметре hWnd
. SetTimer возвращает ID таймера, если вызов прошел успешно, иначе она возвратит NULL. Поэтому лучше не использовать ноль в качестве ID таймера.

Вы можете создать таймеp двумя путями:
  1. Если у вас есть окно и вы хотите, чтобы сообщения от таймера посылались окну, вы должны передать все четыре параметра SetTimer (lpTimerFunc должен быть pавен NULL).
  2. Если у вас нет окна или вы не хотите обрабатывать сообщения таймера в процедуре окна, вы должны передать NULL функции вместо хэндла окна. Вы также должны указать адрес функции таймера, которая будет обрабатывать его сообщения.
В этом туториале мы используем первый подход.
Каждый раз за указанный вами временной интервал окну, ассоциированному с таймером, будет посылаться сообщение WM_TIMER. Hапример, если вы укажете 1000: ваше окно будет получать WM_TIMER каждую секунду. Когда вам больше не нужен таймеp, уничтожьте его с помощью KillTimer:
Кликните здесь для просмотра всего текста
Assembler
1
 KillTimer  proto  hWnd:DWORD, TimerID:DWORD
Практика ― сестра шизофрении
Основная программа
Кликните здесь для просмотра всего текста
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
   .386
   .model flat,stdcall
   option casemap:none
   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
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
 
   .data
   ClassName db "SplashDemoWinClass",0
   AppName  db "Splash Screen Example",0
   Libname db "splash.dll",0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LpSTR ?
   .code
start:    invoke LoadLibrary,addr Libname
    .if eax!=NULL
       invoke FreeLibrary,eax
    .endif
    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  hInstance
    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 TranslateMessage, ADDR msg
     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
    .ELSE
     invoke DefWindowproc,hWnd,uMsg,wparam,lparam
     ret
    .ENDIF
    xor eax,eax
    ret
Wndproc endp
end start
DLL с битмапом
Кликните здесь для просмотра всего текста
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
.386
   .model flat, stdcall
   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
   BitmapName db "MySplashBMp",0
   ClassName db "SplashWndClass",0
   hBitMap dd 0
   TimerID dd 0
 
   .data
   hInstance dd ?
 
   .code
DllEntry proc hInst:DWORD, reason:DWORD, reserved1:DWORD
      .if reason==DLL_pROCESS_ATTACH  ; When the dll is loaded
         push hInst
         pop hInstance
         call ShowBitMap
      .endif
      mov eax,TRUE
      ret
DllEntry Endp
ShowBitMap proc
           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  hInstance
           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,0
           invoke LoadCursor,NULL,IDC_ARROW
           mov   wc.hCursor,eax
           invoke RegisterClassEx, addr wc
           INVOKE CreateWindowEx,NULL,ADDR ClassName,NULL,WS_POPUP,\
           CW_USEDEFAULT,CW_USEDEFAULT,250,250,NULL,NULL,hInstance,NULL
           mov   hwnd,eax
           INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
           .WHILE TRUE
                   INVOKE GetMessage, ADDR msg,NULL,0,0
                   .BREAK .IF (!eax)
                   INVOKE TranslateMessage, ADDR msg
                   INVOKE DispatchMessage, ADDR msg
           .ENDW
           mov     eax,msg.wparam
           ret
ShowBitMap endp
Wndproc proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
           LOCAL ps:PAINTSTRUCT
           LOCAL hdc:HDC
           LOCAL hMemoryDC:HDC
           LOCAL hOldBmp:DWORD
           LOCAL bitmap:BITMAP
           LOCAL DlgHeight:DWORD
           LOCAL DlgWidth:DWORD
           LOCAL DlgRect:RECT
           LOCAL DesktopRect:RECT
 
           .if uMsg==WM_DESTROY
                   .if hBitMap!=0
                           invoke DeleteObject,hBitMap
                   .endif
                   invoke PostQuitMessage,NULL
           .elseif uMsg==WM_CREATE
                   invoke GetWindowRect,hWnd,addr DlgRect
                   invoke GetDesktopWindow
                   mov ecx,eax
                   invoke GetWindowRect,ecx,addr DesktopRect
                   push  0
                   mov  eax,DlgRect.bottom
                   sub  eax,DlgRect.top
                   mov  DlgHeight,eax
                   push eax
                   mov  eax,DlgRect.right
                   sub  eax,DlgRect.left
                   mov  DlgWidth,eax
                   push eax
                   mov  eax,DesktopRect.bottom
                   sub  eax,DlgHeight
                   shr  eax,1
                   push eax
                   mov  eax,DesktopRect.right
                   sub  eax,DlgWidth
                   shr  eax,1
                   push eax
                   push hWnd
                   call MoveWindow
                   invoke LoadBitmap,hInstance,addr BitmapName
                   mov hBitMap,eax
                   invoke SetTimer,hWnd,1,2000,NULL
                   mov TimerID,eax
           .elseif uMsg==WM_TIMER
                   invoke SendMessage,hWnd,WM_LBUTTONDOWN,NULL,NULL
                   invoke KillTimer,hWnd,TimerID
           .elseif uMsg==WM_pAINT
                   invoke Beginpaint,hWnd,addr ps
                   mov hdc,eax
                   invoke CreateCompatibleDC,hdc
                   mov hMemoryDC,eax
                   invoke SelectObject,eax,hBitMap
                   mov hOldBmp,eax
                   invoke GetObject,hBitMap,sizeof BITMAP,addr bitmap
                   invoke StretchBlt,hdc,0,0,250,250,\
                          hMemoryDC,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY
                   invoke SelectObject,hMemoryDC,hOldBmp
                   invoke DeleteDC,hMemoryDC
                   invoke Endpaint,hWnd,addr ps
           .elseif uMsg==WM_LBUTTONDOWN
                   invoke DestroyWindow,hWnd
           .else
                   invoke DefWindowproc,hWnd,uMsg,wparam,lparam
                   ret
           .endif
           xor eax,eax
           ret
   Wndproc endp
 
   End DllEntry
Разбор полетов
Сначала мы проанализируем код основной программы.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
        invoke LoadLibrary,addr Libname
        .if eax!=NULL
           invoke FreeLibrary,eax
        .endif
Мы вызовем LoadLibrary, чтобы загрузить DLL "splash.dll". После этого выгружаем ее из памяти функцией FreeLibrary. LoadLibrary не возвратится, пока DLL не закончит свою инициализацию. Это все, что делает основная программа. Интересующая нас часть находится в DLL.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
      .if reason==DLL_PROCESS_ATTACH  ; When the dll is loaded
         push hInst
         pop hInstance
         call ShowBitMap
После загрузки DLL в память, Windows вызывает ее входную функцию с флагом DLL_PROCESS_ATTACH. Мы пользуемся этой возможностью, чтобы отобразить сплэш-экран. Во-первых, мы сохраняем хэндл DLL на будущее. Потом вызываем функцию ShowBitmap, которая выполняет главную работу. ShowBitmap регистрирует класс окна, создает окно и входит в цикл обработки сообщений.
Следует обратить внимание на вызов CreateWindowEx:
Кликните здесь для просмотра всего текста
Assembler
1
2
 INVOKE CreateWindowEx,NULL,ADDR ClassName,NULL,\
              WS_POPUP,CW_USEDEFAULT,CW_USEDEFAULT,250,250,NULL,NULL,hInstance,NULL
Обратите внимание, что стиль окна WS_POPUP, что делает окно без бордюра и без заголовка. Мы также ограничиваем размер окна - 250x250. Теперь, когда окно создано, в обработчике WM_CREATE мы передвигаем окно в центр экрана следующим кодом.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
               invoke GetWindowRect,hWnd,addr DlgRect
                   invoke GetDesktopWindow
                   mov ecx,eax
                   invoke GetWindowRect,ecx,addr DesktopRect
                   push  0
                   mov  eax,DlgRect.bottom
                   sub  eax,DlgRect.top
                   mov  DlgHeight,eax
                   push eax
                   mov  eax,DlgRect.right
                   sub  eax,DlgRect.left
                   mov  DlgWidth,eax
                   push eax
                   mov  eax,DesktopRect.bottom
                   sub  eax,DlgHeight
                   shr  eax,1
                   push eax
                   mov  eax,DesktopRect.right
                   sub  eax,DlgWidth
                   shr  eax,1
                   push eax
                   push hWnd
                   call MoveWindow
Мы получаем размеры десктопа и окан, а затем вычисляем координаты левого верхнего угла окна, чтобы оно было в центре.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
                  invoke LoadBitmap,hInstance,addr BitmapName
                   mov hBitMap,eax
                   invoke SetTimer,hWnd,1,2000,NULL
                   mov TimerID,eax
Затем мы загружаем битмап из ресурса функцией LoadBitmap и создаем таймеp, указывая в качестве его ID 1, а в качестве временного интервала 2 секунды. Таймеp будет посылать сообщения WM_TIMER окну каждый две секунды.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
          .elseif uMsg==WM_PAINT
                   invoke BeginPaint,hWnd,addr ps
                   mov hdc,eax
                   invoke CreateCompatibleDC,hdc
                   mov hMemoryDC,eax
                   invoke SelectObject,eax,hBitMap
                   mov hOldBmp,eax
                   invoke GetObject,hBitMap,sizeof BITMAP,addr bitmap
                   invoke StretchBlt,hdc,0,0,250,250,\
                          hMemoryDC,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY
                   invoke SelectObject,hMemoryDC,hOldBmp
                   invoke DeleteDC,hMemoryDC
                   invoke Endpaint,hWnd,addr ps
Когда окно получить сообщение WM_рAINT, она создаст DC в памяти, выберет в него битмап, получит pазмеp битмапа функцией GetObject, а затем поместит битмап на окно, вызвав StretchBlt, которая действует как BitBlt, но адаптирует битмап к желаемым размерам. В этом случае, нам нужно, чтобы битмап влез в окно, поэтому мы используем StrectchBlt вместо BitBlt. Мы удаляем созданный в памяти DC.
Кликните здесь для просмотра всего текста
Assembler
1
2
           .elseif uMsg==WM_LBUTTONDOWN
                   invoke DestroyWindow,hWnd
Пользователя бы раздражало, если бы ему пришлось бы ждать, пока сплэш-экран не исчез. Мы можем предоставить пользователю выбор. Когда он кликнет на сплэш-экране, тот исчезнет. Вот почему нам нужно обрабатывать сообщение WM_LBUTTONDOWN. Когда мы получим это сообщение, окно будет уничтожено вызовом DestroyWindow.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
           .elseif uMsg==WM_TIMER
                   invoke SendMessage,hWnd,WM_LBUTTONDOWN,NULL,NULL
                   invoke KillTimer,hWnd,TimerID
Если пользователь решит подождать, сплэш-экран исчезнет, когда пройдет заданный период времени (в нашем примере, это две секунды). Мы можем сделать это обработкой сообщения WM_TIMER. После получения этого сообщения, мы закрываем окно, послав ему сообщение WM_LBUTTONDOWN, чтобы избежать повторения кода. Таймер нам больше не нужен, поэтому мы уничтожаем его KillTimer. Когда окно будет закрыто, DLL возвратит контроль основной программе.
_______________________________
© Iczelion, пер. Aquila.
3
Вложения
Тип файла: zip tut26.zip (159.0 Кб, 49 просмотров)
Mikl___
Заблокирован
Автор FAQ
23.01.2013, 05:55  [ТС] #68
Win32 API. Урок 26a. Сплэш-экран
Теперь, когда мы знаем, как использовать битмап, мы можем применить его более творчески. Сплэш-экран.

Скачайте пример.
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
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
; masm dos com #
.586p
.model tiny
;for WinXP - 849 bytes
include windows.inc
.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,esi
    push ebx
    push esi
    shl esi,9;esi=80000000h
    invoke CreateWindowEx,ebx,edi,edi,WS_OVERLAPPEDWINDOW,\
    esi,esi,esi,esi,ebx,ebx
    mov hwnd+exebase,eax
    pop esi
    invoke LoadImage,esi,offset wTitle+exebase,ebx,ebx,ebx,\
    LR_LOADFROMFILE,ebx,offset hwnd+exebase
    invoke CreatePatternBrush,eax
    invoke RegisterClass,esp,ebx,offset SplashProc+exebase,ebx,\
    ebx,esi,ebx,10011h,eax
    invoke GetSystemMetrics,SM_CYSCREEN,320,400,ebx,ebx,esi,ebx
    shr eax,1;Y - координата центра экрана
    sub ax,200;минус половина высоты картинки
    invoke GetSystemMetrics,ebx,eax
    shr eax,1;X - координата центра экрана
    sub eax,160;минус половина ширины картинки
    invoke CreateWindowEx,ebx,offset hwnd+exebase,ebx,\
    WS_POPUP+WS_VISIBLE,eax
      ;адpес функции, котоpая будет обpабатывать уведомительные сообщения от таймеpа
      ;вpеменной интеpвал в миллисекундах - через 2 секунды закроем splash
      ;TimerID=0 - заданное пользователем значение, котоpое будет использоваться в качестве ID таймеpа
      ;сообщения таймера пойдут splash-окну
    invoke SetTimer,eax,ebx,2000,ebx
    mov ebp,esp
   ;+---------------------------+
   ;| entering the message loop |
   ;+---------------------------+
window_message_loop_start:
    invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp window_message_loop_start
   ;+----------------------+
   ;| the window procedure |
   ;+----------------------+
window_procedure: cmp dword ptr [esp+8],WM_DESTROY
    je wmDESTROY
    jmp DefWindowProc+exebase
wmDESTROY: invoke ExitProcess,ebx
SplashProc:
hWnd   equ esp+4
uMsg   equ esp+8
wParam equ esp+0Ch
lParam equ esp+10h
    mov edi,[hWnd]
    mov eax,[uMsg]
    cmp eax,WM_TIMER
    je short wmTIMER
    cmp eax,WM_LBUTTONDOWN
    je short wmLBUTTONDOWN
;все сообщения, не обрабатываемые в функции SplashProc,
    jmp DefWindowProc+exebase;направляются на обработку по умолчанию
wmLBUTTONDOWN: ;по левому клику или по сигналу от таймера закрываем splash
wmTIMER: invoke KillTimer,edi,ebx;убираем таймер#0
    invoke DestroyWindow,edi;разрушаем splash
    invoke ShowWindow,hwnd+exebase,SW_SHOWNORMAL;показываем основное окно
    retn 10h
;---------------------------------------------------------------------------
hwnd    dd ?
wTitle  db 'Images\JourneyStart.bmp'
;-------------------------------------------------------------------------------------------
import:
dd 0,0,0,user32_dll  ,user32_table
dd 0,0,0,gdi32_dll   ,gdi32_table
dd 0,0,0,kernel32_dll,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
LoadImage       dd _LoadImage
GetSystemMetrics    dd _GetSystemMetrics
SetTimer        dd _SetTimer
KillTimer       dd _KillTimer
DestroyWindow       dd _DestroyWindow
ShowWindow      dd _ShowWindow,0
gdi32_table:
CreatePatternBrush  dd _CreatePatternBrush
                        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'
_GetSystemMetrics   db 0,0,'GetSystemMetrics'
_SetTimer       db 0,0,'SetTimer'
_KillTimer      db 0,0,'KillTimer'
_DestroyWindow      db 0,0,'DestroyWindow'
_ShowWindow     db 0,0,'ShowWindow'
_LoadImage      db 0,0,'LoadImageA',0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_CreatePatternBrush db 0,0,'CreatePatternBrush',0
gdi32_dll       db 'gdi32'
end_import:
end main
_______________________________________
© Mikl___ 2013
3
Вложения
Тип файла: zip tut26a.zip (81.3 Кб, 40 просмотров)
Mikl___
Заблокирован
Автор FAQ
24.01.2013, 05:07  [ТС] #69
Win32 API. Урок 27. Тултип-контрол
Мы изучим контроль tooltiр. Что это такое, как его создать и как им пользоваться.

Скачайте пример здесь
Теория ― мать склероза
Тултип ― это маленькая прямоугольное окно, которое отображается, когда курсор мыши находится над какой-то определенной областью. Окно тултипа содержит текст, заданный программистом. В этом отношении тултип играет ту же роль, что и окно статуса, но оно исчезает, когда пользователь кликает или убирает курсор мыши из заданной области. Вы, вероятно, знакомы с тултипами, ассоциированные с кнопками тулбара. Эти "тултипы" ― одно из удобств, предоставляемых тулбаром. Если вам нужны тултипы для других окон/контролов, вам необходимо создать собственный тултип контрол.

Теперь, когда вы знаете, что такое тултип, давайте перейдем к тому, как мы можем создать и использовать его. Ниже расписаны шаги:
  1. Создать тултип-контрол функцией CreateWindowEx.
  2. Определить регион, в котором он будет отслеживать передвижения мыши.
  3. Передать регион тултип-контролу.
  4. Передавать сообщения от мыши в указанном регионе тултип-контролу (этот шаг зависит от заданных флагов).
Ниже мы детально проанализируем каждый шаг.
Создание тултипа
Тултип ― это common control. Поэтому вам необходимо где-нибудь в программе вызвать функцию InitCommonControls, чтобы MASM подлинковал к выходнуму экзешнику comctl32.dll. Вы создаете тултип с помощью CreateWindowEx. Это будет выглядеть примерно так:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
.data
       TooltipClassName db "Tooltips_class32",0
 
       .code
      .....
       invoke InitCommonControls
       invoke CreateWindowEx, NULL, addr TooltipClassName, NULL,\
       TIS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,\
       CW_USEDEFAULT, NULL, NULL, hInstance, NULL
Обратите внимание на стиль окна: TIS_ALWAYSTIP. Этот стиль указывает, что тултип будет показываться, когда курсор мыши будет находиться над заданной областью вне зависимости от статуса окна. То есть, если вы будете использовать этот флага, тултип будет появляться (когда курсор мыши будет находиться над определенной областью), даже если окно, с которым ассоциирован тултип, неактивно.

Вам не нужно задавать слили WS_POPUP и WS_EX_TOOLWINDOW, потому что тултип определяет их автоматически. Вам также не нужно указывать координаты, ширину и высоту тултипа: он сам рассчитывает свои характеристики, поэтому в качестве всех четырех параметров мы указывает CW_USEDEFAULT. Оставшиеся параметры не играют роли.
Определение tool'ов
Тултип создается, но не отображается сразу. Нам нужно, чтобы он отображался только над определенной областью. Теперь пришло время задать ее. Мы называем такую область 'tool'. Tool ― это прямоугольная область клиентской части окна, в пределах которой тултип будет отслеживать передвижение мыши. Прямоугольная область может покрывать всю клиентскую часть окна или только некоторую долю от нее. Поэтому мы можем поделить 'tool' на два типа: один ― это, когда в качестве tool'а выступает целая клиентская область окна, а другой ― прямоугольная часть клиентской области окна. Оба типа находят свое применение.

Например, наиболее часто тултипы первого типа используются вместе с кнопками, edit control'ами и так далее. Вам не нужно указывать координаты и размерность tool'а: предполагается, что будет задействована вся клиентская область. Tool'ы второго типа полезны, когда вы хотите поделить клиентскую часть окна на несколько регионов без использования дочерних окон. В этом случае вам будет необходимо задать координату верхнего левого угла, ширину и высоту tool'а.

Вы определяете характеристики tool'а в структуре TOOLINFO, которая имеет следующее определение:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
       TOOLINFO STRUCT
         cbSize             DWORD      ?
         uFlags             DWORD      ?
         hWnd              DWORD      ?
         uId                DWORD      ?
         rect               RECT      <>
         hInst             DWORD      ?
         lpszText           DWORD      ?
         lparam             LPARAM     ?
       TOOLINFO ENDS
  • cbSize ― размер структуры TOOLINFO. Вы должны заполнить этот параметр. Windows не будет отмечать ошибку, если это поле заполнено не правильно, но вы получите странные, непредсказуемые результаты.
  • uFlags ― битовые флаги определяют характеристики tool'а.
    • TTF_IDISHWND ― "ID ― это hWnd". Если вы укажете этот флаг, вы должны заполнить параметр uId хэндлом окна, который вы хотите использовать. Если вы не укажете этот флаг, это будет означать, что вы хотите использовать второй тип tool'а. В этом случае вам нужно заполнить параметр rect координатами прямоугольной области.
    • TTF_CENTERTIP ― обычно окно тултипа появляется справа и ниже курсора мыши. Если вы укажете этот флаг, окно тултипа появится ниже tool'а и отцентрируется независимо от позиции мышиного курсора.
    • TTF_RTLREADING ― вы можете забыть об этом флаге, если ваша программа не специально предназначена для вывода надписей на арабском или иврите. Этот флаг отображает текст тултипа справа налево. Не работает под другими системами.
    • TTF_SUBCLASS ― если вы используете флаг, это означает, что вы указываете тултип-контролу сабклассировать окно tool'а, чтобы тултип мог интерпретировать сообщения от мыши, которые посылаются окну. Этот флаг очень удобен. Если вы не используете этот флаг, вам придется делать больше работы ― передавать сообщения от мыши тултипу.
  • hWnd ― Хэндл окна, который содержит tool. Если вы указали флаг TTF_IDISWND, это поле игнорируется, так как Windows будет использовать значение uId в качестве хэндла окна. Вам нужно заполнить это поле, если:
    • Вы не устанавливали флаг TTF_IDISHWND
    • Вы указываете значение LPSTR_TEXTCALLBACK в параметре lpszText. Это значение указывает тултипу, что когда ему необходимо отобразить свое окно, он должен уведомить об этом окно, которое содержит tool. Это вид динамического обновления текста тултипа. Если вы хотите изменять динамически текст тултипа, вам следует LPSTR_TEXTCALLBACK в качестве значения LPSTR_TEXTCALLBACK. Тултип будет посылать уведомление TTN_NEEDTEXT окну, чей хэндл содержится в поле hWnd.
  • uId ― это поле может иметь одно из двух значений, в зависимости от того, содержит ли uFlags флаг IIF_IDISHWND.
    • Определяемое приложением ID tool'а, если флаг TTF_IDISHWND. Так как это означает, что вы используете tool, покрывающее только часть клиентской области, то логично, что вы можете иметь несколько tool'ов на одной клиентской области (без пересечений). Тултип-контрол должен иметь какой-то путь отличать их друг от друга. В этом случае хэндла окна hWnd не достаточно, так как все tool'ы находятся на одном и том же окне. Определяемые приложением ID служат именно для этой цели. ID может быть любым значением, главное, чтобы оно было уникально по отношению к другим ID.
    • Хэндл окна, чья клиентская область полностью используется в качестве tool'а, если указан флаг TTF_IDISHWND. Вы можете задать вопрос ― Почему это поле используется для хранения хэндла окна, если есть hWnd? ― Ответ следующий: поле hWnd уже может быть заполнено, если в параметре lpszText указано значение LPSTR_TEXTCALLBACK. Окно, которое ответственно за предоставление текста тултипа, и окно, которое содержит tool, могут быть не одним и тем же.
  • rect ― структура RECT, которая указывает размерность tool'а. Эта структура определяет прямоугольник относительного верхнего левого угла клиентской области окна, указанного в параметре hWnd. То есть, вы должны заполнить эту структуру, если вы хотите указать tool, который покрывает только часть клиентской области. Тултип-контрол проигнорирует это поле, если вы укажете флаг TTF_IDISHWND (вы хотите использовать в качестве tool'а целое окно).
  • hInst ― это хэндл процесса, содержащий ресурс строки, которая будет использована в качестве текста, если значение lpszText равно ID строкового ресурса. Это может вас несколько смутить. Прочтите сначала описание параметра lpszText, и вы поймете, для чего используется это поле. Тултип-контрол игнорирует это поле, если lpszText не содержит ID ресурса.
  • lpszText ― это поле имеет несколько значений:
    • Если вы укажете в этом поле значение LPSTR_TEXTCALLBACK, тултип будет посылать уведомительное сообщение TTN_NEEDTEXT окну, которое идентифицируется хэндлом поля hWnd, чтобы то предоставило тултипу текстовую строку. Это наиболее динамичный метод обновления текста тултипа: вы можете менять его каждый раз, когда отображается окно тултипа.
    • Если вы укажете в этом поле ID строкового ресурса, тултип, когда ему потребуется отобразить текст в своем окне, будет искать строку в таблице строк процесса, заданного параметром hInst. Тултип-контрол идентифицирует ID ресурса следующим образом: так как ID ресурса ― это 16-битное значение, старшее слово этого поля всегда будет равно нулю. Этот метод полезен, если вы хотите портировать вашу программу на другие языки. Так как строковый ресурс определен в файле определения ресурсов, вам не нужно модифицировать исходный код. Вам только нужно изменить таблицу строк и текст тултипа изменится без риска внесения ошибок в программу.
    • Если значение в этом поле не равно LPSTR_TEXTCALLBACK и старшее слово не равно нулю, тултип-контрол интерпретирует значение как указатель на текстовую строку, которая будет использована в качестве текста тултипа. Этот метод самый простой, но наименее гибкий.
Резюме
Вы должны заполнить структуру TOOLINFO и передать ее тултипу. Эта структура задаст характеристики tool'а.
Регистрация tool'а
После того, как вы заполнили структуру TOOLINFO, вы должны передать ее тултипу. Тултип может обслуживать много tool'ов, поэтому обычно одно тултипа хватает на все окно. Чтобы зарегистрировать tool, вы посылаете тултипу сообщение TTM_ADDTOOL. wParam не используется, а lParam должен содержать адрес структуры TOOLINFO.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
.data?
       ti TOOLINFO <>
       .......
       .code
       .......
       [заполнение структуры TOOLINFO]
       .......
       invoke SendMessage, hwndTooltip, TTM_ADDTOOL, NULL, addr ti
SendMessage возвратит TRUE, если tool был успешно зарегистрирован тултипом или FALSE в случае неудачи. Вы можете удалить tool сообщением TTM_DELTOOL.
Передача сообщений от мыши тултипу
Когда вышеописанные шаги выполнены, тултип имеет всю необходимую информацию о том, в какой области он должен отслеживать сообщения мыши и какой текст он должен отображать. Единственное, что отстутсвует ― это триггер. Подумайте: область, указанная в качестве tool'а находится на клиентской части другого окна. Как может тултип перехватить сообщения от мыши для этого окна? Необходимо, чтобы он мог измерить количество времени, которое курсор мыши находится над tool'ом, чтобы вовремя отобразить окно тултипа. Есть два метода, чтобы достичь этой цели, один требует помощи со стороны окна, которое tool, а другой этого не требует.

Окно, которое содержит tool, должно переправлять сообщения от мыши тултипу с помощью сообщения TTM_RELAYEVENT. lParam должен содержать адрес структуры MSG, содержащую сообщение от мыши. Тултип обрабатывает только следующие сообщения от мыши:
  • WM_LBUTTONDOWN
  • WM_MOUSEMOVE
  • WM_LBUTTONUP
  • WM_RBUTTONDOWN
  • WM_MBUTTONDOWN
  • WM_RBUTTONUP
  • WM_MBUTTONUP
Все другие сообщения игнорируются. Таким образом, в процедуре окна, содержащего tool, должен быть обработчик вроде следующего:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
  Wndproc proc hWnd:DWORD, uMsg:DWORD, wparam:DWORD, lparam:DWORD
   .......
      if uMsg==WM_CREATE
           .............
       elseif uMsg==WM_LBUTTONDOWN || uMsg==WM_MOUSEMOVE || \
              uMsg==WM_LBUTTONUP || uMsg==WM_RBUTTONDOWN || \
              uMsg==WM_MBUTTONDOWN || uMsg==WM_RBUTTONUp || \
              uMsg==WM_MBUTTONUP
           invoke SendMessage, hwndTooltip, TTM_RELAYEVENT, NULL, addr msg
           ..........
Вы можете указать флаг TTF_SUBCLASS в параметре uFlags структуры TOOLINFO. Этот флаг указывает тултипу сабклассировать окно, которое содержит tool, чтобы перехватывать сообщения от мыши без участия сабклассированного окна. Этот метод проще использовать и он требует меньше усилий, так как тултип берет всю обработку сообщений на себя.

Вот и все. Теперь ваш тултип полностью функционален. Есть несколько полезных тултиповых сообщений, о которых вас следует знать.
  • TTM_ACTIVATE ― если вы хотите включать/выключать контрол динамически, это сообщение для вас. Если wparam равен TRUE, тултип включается, если wParam равен FALSE, тултип выключается. Тултип включается автоматически, как только он был создан, поэтому вам не надо посылать сообщение, чтобы активировать его.
  • TTM_GETTOOLINFO и TTM_SETTOOLINFO. Если вы хотите получить/изменить значения в структуре TOOLINFO после того, как она была отправлена тултипу, используйте данное сообщение. Вам потребуется указать tool, чьи характеристики вы хотите изменить, с помощью верных uId и hWnd. Если вы хотите изменить только параметр rect, используйте сообщение TTM_NEWTOOLRECT. Если вам нужно только изменить текст тултипа, используйте TTM_UPDATATIPEXT.
  • TTM_SETDELAYTIME. С помощью этого сообщения вы можете задать временную задержку, которую будет использовать тултип.
Практика ― сестра шизофрении
Следующий пример ― это простое диалоговое окно с двумя кнопками. Клиентская область диалогового окна поделена на 4 области:
  • верхняя левая,
  • верхняя правая,
  • нижняя левая
  • и нижняя правая.
Каждая область указана как tool с собственным текстом. Две кнопки также имеют свои собственные тексты подсказок.
Кликните здесь для просмотра всего текста
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
       .386
       .model flat,stdcall
       option casemap:none
       include \masm32\include\windows.inc
       include \masm32\include\kernel32.inc
       include \masm32\include\user32.inc
       include \masm32\include\comctl32.inc
       includelib \masm32\lib\comctl32.lib
       includelib \masm32\lib\user32.lib
       includelib \masm32\lib\kernel32.lib
       Dlgproc proto :DWORD,:DWORD,:DWORD,:DWORD
       EnumChild proto :DWORD,:DWORD
       SetDlgToolArea proto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
 
       .const
       IDD_MAINDIALOG equ 101
 
       .data
       ToolTipsClassName db "Tooltips_class32",0
       MainDialogText1 db "This is the upper left area of the dialog",0
       MainDialogText2 db "This is the upper right area of the dialog",0
       MainDialogText3 db "This is the lower left area of the dialog",0
       MainDialogText4 db "This is the lower right area of the dialog",0
 
       .data?
       hwndTool dd ?
       hInstance dd ?
 
       .code
start:   invoke GetModuleHandle,NULL
           mov hInstance,eax
           invoke DialogBoxparam,hInstance,IDD_MAINDIALOG,NULL,addr  Dlgproc,NULL
           invoke Exitprocess,eax
 
Dlgproc proc hDlg:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
           LOCAL ti:TOOLINFO
           LOCAL id:DWORD
           LOCAL rect:RECT
 
           .if uMsg==WM_INITDIALOG
               invoke InitCommonControls
               invoke CreateWindowEx,NULL,ADDR ToolTipsClassName,NULL,TTS_ALWAYSTIP,\
               CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
                   hInstance,NULL
               mov hwndTool,eax
               mov id,0
               mov ti.cbSize,sizeof TOOLINFO
               mov ti.uFlags,TTF_SUBCLASS
               push hDlg
               pop ti.hWnd
               invoke GetWindowRect,hDlg,addr rect
               invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText1,id,addr rect
               inc id
               invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText2,id,addr rect
               inc id
               invoke SetDlgToolArea,hDlg,addr ti,addr  MainDialogText3,id,addr rect
               inc id
               invoke SetDlgToolArea,hDlg,addr ti,addr  MainDialogText4,id,addr rect
               invoke EnumChildWindows,hDlg,addr EnumChild,addr ti
           .elseif uMsg==WM_CLOSE
               invoke EndDialog,hDlg,NULL
           .else
               mov eax,FALSE
               ret
           .endif
           mov eax,TRUE
           ret
       Dlgproc endp
EnumChild proc uses edi hwndChild:DWORD,lparam:DWORD
           LOCAL buffer[256]:BYTE
 
           mov edi,lparam
           assume edi:ptr TOOLINFO
           push hwndChild
           pop [edi].uId
           or [edi].uFlags,TTF_IDISHWND
           invoke GetWindowText,hwndChild,addr buffer,255
           lea eax,buffer
           mov [edi].lpszText,eax
           invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,edi
           assume edi:nothing
           ret
EnumChild endp
SetDlgToolArea proc uses edi esi hDlg:DWORD,lpti:DWORD,lpText:DWORD,id:DWORD,lprect:DWORD
           mov edi,lpti
           mov esi,lprect
           assume esi:ptr RECT
           assume edi:ptr TOOLINFO
           .if id==0
               mov [edi].rect.left,0
               mov [edi].rect.top,0
               mov eax,[esi].right
               sub eax,[esi].left
               shr eax,1
               mov [edi].rect.right,eax
               mov eax,[esi].bottom
               sub eax,[esi].top
               shr eax,1
               mov [edi].rect.bottom,eax
           .elseif id==1
               mov eax,[esi].right
               sub eax,[esi].left
               shr eax,1
               inc eax
               mov [edi].rect.left,eax
               mov [edi].rect.top,0
               mov eax,[esi].right
               sub eax,[esi].left
               mov [edi].rect.right,eax
               mov eax,[esi].bottom
               sub eax,[esi].top
               mov [edi].rect.bottom,eax
           .elseif id==2
               mov [edi].rect.left,0
               mov eax,[esi].bottom
               sub eax,[esi].top
               shr eax,1
               inc eax
               mov [edi].rect.top,eax
               mov eax,[esi].right
               sub eax,[esi].left
               shr eax,1
               mov [edi].rect.right,eax
               mov eax,[esi].bottom
               sub eax,[esi].top
               mov [edi].rect.bottom,eax
           .else
               mov eax,[esi].right
               sub eax,[esi].left
               shr eax,1
               inc eax
               mov [edi].rect.left,eax
               mov eax,[esi].bottom
               sub eax,[esi].top
               shr eax,1
               inc eax
               mov [edi].rect.top,eax
               mov eax,[esi].right
               sub eax,[esi].left
               mov [edi].rect.right,eax
               mov eax,[esi].bottom
               sub eax,[esi].top
               mov [edi].rect.bottom,eax
           .endif
           push lpText
           pop [edi].lpszText
           invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,lpti
           assume edi:nothing
           assume esi:nothing
           ret
SetDlgToolArea endp
end start
Анализ:
После того, как создано основное диалоговое окно, мы создает тултип-контрол функцией CreateWindowsEx.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
       invoke InitCommonControls
       invoke CreateWindowEx,NULL,ADDR ToolTipsClassName,NULL,TTS_ALWAYSTIP,\
              CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
              hInstance,NULL
       mov hwndTool,eax
После этого мы переходим к определению четырех tool'ов для каждого угла диалогового окна.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
       mov id,0        ; used as the tool ID
       mov ti.cbSize,sizeof TOOLINFO
       mov ti.uFlags,TTF_SUBCLASS   ; tell the tooltip control to subclass the dialog window.
       push hDlg
       pop ti.hWnd    ; handle to the window that contains the tool
       invoke GetWindowRect,hDlg,addr rect   ; получаем размерность клиентской области
       invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText1,id,addr rect
Мы инициализируем члены структуры TOOLINFO. Заметьте, что мы хотим поделить клиентскую область на 4 tool'а, поэтому нам нужно знать размерность клиентской области. Это то, для чего мы вызываем GetWindowsRect. Мы не хотим передавать сообщения мыши тултипу, поэтому мы указываем флаг TIF_SUBCLASS. SetDlgToolArea ― это функция, которая высчитывает координаты прямоугольной области каждого tool'а и регистрирует tool в тултипе. Я не хочу вдаваться в подробности относительно этого, достаточно сказать, что она делит клиентскую область на 4 области с одними и теми же размерами. Затем она посылает сообщение TTN_ADDTOOL тултипу, передавая адрес структуры TOOLINFO в lParam.
Кликните здесь для просмотра всего текста
Assembler
1
   invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,lpti
После того, как все 4 tool'а зарегистрированы, мы можем перейти к кнопкам на диалоговом окне. Мы можем обрабатывать каждую кнопку с помощью ее ID, но это утомительно. Вместо этого мы используем EnumChildWindows API, чтобы перечислить все контролы на диалоговом окне и затем зарегистрировать для каждого из них подсказку. EnumChildWindows имеет следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
 EnumChildWindows proto hWnd:DWORD, lpEnumFunc:DWORD, lParam:DWORD
hWnd ― хэндл родительского окна. lрEnumFunc ― адрес функции EnumChildproc, которая будет вызываться для каждого перечисленного контрола. lParam ― заданное приложением значение, которое будет передано EnumChildproc. У этой функции следующее определение:
Кликните здесь для просмотра всего текста
Assembler
1
  EnumChildproc proto hwndChild:DWORD, lParam:DWORD
hwndChild ― хэндл контрола, найденного EnumChildWindows. lParam ― это тоже значение, что вы передали EnumChildWindow. В нашем примере мы вызываем EnumChildWindows следующим образом:
Assembler
1
    invoke EnumChildWindows,hDlg,addr EnumChild,addr ti
Мы передаем адрес структуры TOOLINFO в параметре lParam, потому что мы будем регистрировать подсказки для каждого дочерний контрол в функции EnumChild. Если мы не будем использовать данный метода, нам придется объявить глобальную переменную, чтобы предотвратить баги.
Когда мы вызываем EnumchildWindows, Windows перечислит дочерние конролы нашего диалогового окна и вызовет для каждого из ни функцию Enumchild. То есть, если наше диалоговое окно имеет два контрола, EnumChild будет вызван дважды.
Функция EnumChild заполнит соответствующие поля структуры TOOLINFO и зарегистрирует tool.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  EnumChild proc uses edi hwndChild:DWORD,lParam:DWORD
           LOCAL buffer[256]:BYTE
 
           mov edi,lparam
           assume edi:ptr TOOLINFO
           push hwndChild
           pop [edi].uId   ; we use the whole client area of the control as the tool
           or [edi].uFlags,TTF_IDISHWND
           invoke GetWindowText,hwndChild,addr buffer,255
           lea eax,buffer    ; use the window text as the tooltip text
           mov [edi].lpszText,eax
           invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,edi
           assume edi:nothing
           ret
       EnumChild endp
Заметьте, что в этом случае мы используем другой тип tool'ов, покрывающий всю клиентскую область окна. Поэтому нам нужно заполнить поле uID хэндлом окна, которое содержит tool. Также мы указываем флаг TTF_IDISHWND в параметре uFlags.
_______________________________
© Iczelion, пер. Aquila.
3
Вложения
Тип файла: zip tut27.zip (12.3 Кб, 56 просмотров)
Mikl___
Заблокирован
Автор FAQ
24.01.2013, 05:37  [ТС] #70
Win32 API. Урок 27a. Тултип-контрол
Мы изучим контроль tooltiр. Что это такое, как его создать и как им пользоваться.
Скачайте пример здесь.
Кликните здесь для просмотра всего текста
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
;for WinXP - 1290 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
include windows.inc
.code
; -----------------------------------------------------------------
; Type of control
; -----------------------------------------------------------------
BUTTON              equ 80h 
EDIT                equ 81h 
STATIC              equ 82h 
LISTBOX             equ 83h 
SCROLLBAR           equ 84h 
COMBOBOX            equ 85h
; -----------------------------------------------------------------
; Equs for menus
; -----------------------------------------------------------------
POPUP       equ 0010h
MENUBREAK       equ 0040h
ENDMENU     equ 0080h
DS_SETFONT  equ 0040h
;--------------------------------------------------------------------------
exebase     equ 400000h
IDC_DIALOG  equ 101
main:
include capito_res.asm
;--------------------------------------------
start:  invoke DialogBoxParam,exebase,IDC_DIALOG,eax,offset DlgProc+exebase,eax
    retn
;-----------------------------------------------
DlgProc:
hdlg    equ dword ptr [ebp+8]
umsg    equ dword ptr [ebp+0Ch]
ti  equ TOOLINFO ptr [ebp-sizeof TOOLINFO]
 
    enter sizeof TOOLINFO+sizeof RECT,0
    mov eax,umsg
    mov edi,hdlg
    sub eax,WM_CLOSE    ;cmp umsg,WM_CLOSE
    je wmCLOSE
    sub eax,WM_INITDIALOG-WM_CLOSE;cmp umsg,WM_INITDIALOG
    je wmINITDIALOG
    xor eax,eax     ;eax = FALSE
    jmp wmBYE
wmINITDIALOG: invoke InitCommonControls
    xchg eax,ebx        ;ebx = 0
    mov esi,exebase
    push ebx
    push esi
    shl esi,9       ;esi = CW_USEDEFAULT
    invoke CreateWindowEx,ebx,offset ctlClsNameTips+exebase,\
    ebx,TTS_ALWAYSTIP,esi,esi,esi,esi,ebx,ebx
    mov tipsH+exebase,eax
    lea esi,ti
    assume esi: ptr TOOLINFO
    push sizeof TOOLINFO
    pop [esi].cbSize    ;ti.cbSize = sizeof TOOLINFO
    push TTF_SUBCLASS
    pop [esi].uFlags    ;ti.uFlags = TTF_SUBCLASS
    mov [esi].hWnd,edi  ;ti.hWnd = hdlg
    invoke GetWindowRect,edi,esp
    push 4
    pop ecx;ecx=4
@@: push ecx
;SetDlgToolArea--------------------------------
    mov [esi].rect.left,ebx
    mov [esi].rect.top,ebx
    mov [esi].rect.right,350
    mov [esi].rect.bottom,188
    jmp [handels+exebase+ecx*4-4]
id_0:   mov [esi].rect.right,165
    push 74
    pop [esi].rect.bottom
    jmp id_exit
id_1:   push 74
    pop [esi].rect.bottom
    mov [esi].rect.left,166
    jmp id_exit
id_2:   mov [esi].rect.right,165
    push 75
    pop [esi].rect.top
    jmp id_exit
id_3:   mov [esi].rect.left,166
    push 75
    pop [esi].rect.top
id_exit: push [handel+exebase+ecx*4-4];lpText
    pop [esi].lpszText
    assume esi:nothing
    invoke SendMessage,tipsH+exebase,TTM_ADDTOOL,ebx,esi
;-------------------------------------
    pop ecx
    loop @b
    invoke EnumChildWindows,edi,offset EnumChild+exebase,esi
    jmp wmBYE
wmCLOSE: invoke EndDialog,edi,eax
wmBYE:  leave
    retn 10h
;------------------------------------------------------------
EnumChild:
size_buffer = 70h
hwndChild equ dword ptr [ebp+8]
lParam    equ dword ptr [ebp+0Ch]
buffer    equ byte ptr [ebp-size_buffer]
 
    enter size_buffer,0
    mov ecx,lParam
    assume ecx: ptr TOOLINFO
    push hwndChild
    pop [ecx].uId
    or [ecx].uFlags,TTF_IDISHWND
    lea eax,buffer
    mov [ecx].lpszText,eax
    assume ecx:nothing
    invoke GetWindowText,hwndChild,eax,size_buffer-1,ecx
    invoke SendMessage,tipsH+exebase,TTM_ADDTOOL,ebx
    leave
    retn 8
;--------------------------------------------------------------
handels dd id_0+exebase, id_1+exebase, id_2+exebase, id_3+exebase
handel  dd tipsTxt1+exebase, tipsTxt2+exebase, tipsTxt3+exebase, tipsTxt4+exebase
ctlClsNameTips  db 'Tooltips_class32',0
tipsTxt1    db 'Это верхняя левая область',0
tipsTxt2    db 'Это верхняя правая область',0
tipsTxt3    db 'Это нижняя левая область',0
tipsTxt4    db 'Это нижняя правая область',0
;---------------------------------------------------------------------
align 4
resource:
dd 0,0,0
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_DIALOG,0,d1-resource,8000h
d1:
dd 0,0,0
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
dw IDC_DIALOG,0,d2-resource,8000h
d2:
dd 0,0,0
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
dw 40Ah,0,d3-resource,0;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
d3: 
dd dialog,end_dialog-dialog,0,0
dialog: 
style0 dd WS_VISIBLE or WS_CAPTION or DS_SETFONT or WS_POPUP or WS_SYSMENU 
dwExtendedStyle0 dd 0
 
cdit0 dw 4 ;число элементов управления, входящих в состав диалогового окна 
x0    dw 10;отступ левой границы окна от левой границы экрана
y0    dw 10;отступ верхней границы окна от верхней границы экрана
cx0   dw 229;ширина окна
cy0   dw 96;высота окна
      dw 0;есть меню у диалога (=FFFF) или меню нет (=0)
      dw 0;?
CAPTION: du <Iczelion Tutorial #27:Tooltip Example in MASM>;заголовок диалога
font dw 8
du <MS Sans Serif>
;------------------------------------------------------
;элементы управления диалога    
u1:
style1 dd WS_VISIBLE or BS_GROUPBOX
dwExtendedStyle1 dd 0
x1  dw 0;x-координаты верхнего левого угла
y1  dw -4;y-координаты верхнего левого угла
cx1 dw 115;ширина объекта управления
cy1 dw 51;высота объекта управления
id1 dw -1;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw BUTTON;тип объекта управления 
du <>;надпись на объекте управления
dw 0,0;терминатор
;---------------------------------------------------
u2:
style2 dd WS_VISIBLE or BS_GROUPBOX
dwExtendedStyle2 dd 0
x2  dw 114;x-координаты верхнего левого угла
y2  dw 43;y-координаты верхнего левого угла
cx2 dw 115;ширина объекта управления
cy2 dw 53;высота объекта управления
id2 dw -1;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw BUTTON;тип объекта управления 
du <>;надпись на объекте управления
dw 0,0;терминатор
;----------------------------------------------------
u3:
style3 dd BS_PUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle3 dd 0
x3  dw 55;x-координаты верхнего левого угла
y3  dw 68
cx3 dw 50
cy3 dw 14
id3 dw 1000;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw BUTTON;тип объекта управления 
du <&OK>;надпись на объекте управления  
dw 0;терминатор
;----------------------------------------------------
u4:
style4 dd BS_PUSHBUTTON or WS_CHILD  or  WS_VISIBLE  or  WS_TABSTOP
dwExtendedStyle4 dd 0
x4  dw 123;x-координаты верхнего левого угла
y4  dw 68
cx4 dw 50
cy4 dw 14
id4 dw 1001;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент управления
dw BUTTON;тип объекта управления 
du <E&xit>;надпись на объекте управления
end_dialog: 
;----------------------------------------------------
end_resource:
import: 
dd 0
tipsH dd 0
dd 0,user32_dll
dd user32_table
dd 0,0,0,comctl32_dll
dd comctl32_table
dd 0,0
comctl32_table:
InitCommonControls  dd _InitCommonControls,0
user32_table:
GetWindowRect       dd _GetWindowRect
EnumChildWindows    dd _EnumChildWindows
GetWindowText       dd _GetWindowText
CreateWindowEx      dd _CreateWindowEx
DialogBoxParam      dd _DialogBoxParam
SetDlgItemText      dd _SetDlgItemText
SendMessage     dd _SendMessage
GetDlgItemText      dd _GetDlgItemText
EndDialog       dd _EndDialog
            dw 0
_GetWindowRect      db 0,0,'GetWindowRect'
_EnumChildWindows   db 0,0,'EnumChildWindows'
_GetWindowText      db 0,0,'GetWindowTextA'
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_DialogBoxParam     db 0,0,'DialogBoxParamA'
_SendMessage        db 0,0,'SendMessageA'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_EndDialog      db 0,0,'EndDialog'
_CreateWindowEx     db 0,0,'CreateWindowExA',0
user32_dll      db 'user32'
_InitCommonControls db 0,0,'InitCommonControls',0
comctl32_dll        db 'comctl32'
end_import:
end main
______________________________________
© Mikl___ 2013
3
Миниатюры
Сам себе Iczelion  
Вложения
Тип файла: zip tut27a.zip (4.4 Кб, 42 просмотров)
Mikl___
Заблокирован
Автор FAQ
24.01.2013, 06:26  [ТС] #71
Win32 API. Урок 28.Debug API (часть 1-ая)
В этом туториале вы изучите, какие примитивные отладочные средства предлагает разработчику Win32. Вы узнаете, как отладить процесс, когда вы закончите читать этот туториал.
Скачайте пример здесь.
Теория ― мать склероза
Win32 имеет несколько функций API, которые позволяют программисту использовать некоторые возможности отладчика. Они называются Win32 Debug API. С помощью ни вы можете:
  • Загрузить программу и подсоединиться к запущенной программе для отладки
  • Получить низкоуровневую информацию о программе, которую вы отлаживаете, например, ID процесса, адрес входной точки, image base и так далее.
  • Быть уведомленным о событиях, связанных с отладкой, например, когда процесс запускается/заканчивает выполнение
  • Изменять отлаживаемый процесс/ветвь
Короче говоря, с помощью этих API вы можете написать простой отладчик. Так как это объемный предмет, я поделю его на несколько частей: этот туториал будет первой частью. Я объясню основные концепции, касающиеся Win32 Debug API, здесь.

Этапы использования Win32 Debug API следующие:
  • Создаем или присоединяемся к запущенному процессу. Это первый шаг. Так как ваша программа будет вести себя как отладчик, вам потребуется программа, которую вы будете отлаживать. Вы можете сделать следующее:
    • Создать специальный процесс для отладки с помощью CreateProcess. Чтобы создать процесс для отладки, вы можете указать флаг DEBUG_PROCESS. Этот флаг говорит Windows, что мы хотим отлаживать процесс. Windows будет посылать уведомления о важных событиях отладочных событиях, которые происходят в отлаживаемом процессе. Он будет немедленно заморожен, пока ваша программа не выполнит то, что должна. Если отлаживаемый процесс создаст дочерние процессы, Windows также будет посылать уведомления о происходящих в них отладочных событиях. Обычно это нежелательно, поэтому это можно отключить, указав кроме флага DEBUG_PROCESS флаг DEBUG_ONLY_THIS_PROCESS.
    • Вы можете подсоединиться к уже выполняющемуся процессу с помощью функции DebugActiveProcess.
  • Ждем отладочные события. Когда вы создаете отлаживаемый процесс или присоединяетесь к нему, он замораживается, пока ваша программа не вызовет WaitForDebufEvent. Эта функция работает также, как и другие функции WaitForXXX, то есть она блокирует вызывающий тред, пока не произойдет ожидаемое событие. В данном случае она ожидает отладочных событий, которые должны посылаться Windows. Давайте посмотрим ее определение:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    
     WaitForDebugEvent proto lpDebugEvent:DWORD, dwMilliseconds:DWORD
    • lpDebugEvent ― это адрес структуры DEBUG_EVENT, которая должна быть заполнена информации об отладочном событии, которое происходит внутри отлаживаемого процесса.
    • dwMilliseconds ― это временной интервал в миллисекундах, в течении которого эта функция будет ожидать отладочного события. Если этот период истечет и не произойдет никакого отладочного события, WaitForDebugEvent возвратит управления вызвавшему ее треду. С другой стороны, если вы укажете константу INFINITE, функция не возвратится, пока не произойдет отладочное событие.
  • Теперь давайте проанализируем структуру DEBUG_EVENT более подробно.
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    
    DEBUG_EVENT STRUCT
              dwDebugEventCode dd ?
              dwprocessId dd ?
              dwThreadId dd ?
              u DEBUGSTRUCT <>
    DEBUG_EVENT ENDS
    dwDebugEventCode содержит значение, которое указывает тип произошедшего отладочного события. Кратко говоря, есть много типов событий, ваша программа должна проверять значение в этом поле, чтобы знать, какого типа произошедшее событие и адекватно реагировать.
    Возможные значения следующие:
    • CREATE_PROCESS_DEBUG_EVENT ― процесс создан. Это событие будет послано, когда отлаживаемый процесс только что создан (и еще не запущен), или когда ваша программа присоединяет себя к запущенному процессу с помощью DebugActiveрrocess. Это первое событие, которое получит ваша программа.
    • EXIT_PROCESS_DEBUG_EVENT ― процесс прекращает выполнение.
    • CREATE_THEAD_DEBUG_EVENT ― в отлаживаемом процессе создан новый тред. Заметьте, что вы не получите это уведомление, когда будет создан основной тред отлаживаемой программы.
    • EXIT_THREAD_DEBUG_EVENT ― тред в отлаживаемом процессе прекращает выполнение. Ваша программа не получит это сообщение, если прекратит выполняться основная ветвь отлаживаемого процесса. Вы можете считать, что основная ветвь отлаживаемого процесса эквивалентна самому процессу. Таким образом, когда ваша программа видит CREATE_PROCESS_DEBUG_EVENT, это все равно, что CREATE_THREAD_DEBUG_EVENT по отношению к основному треду.
    • LOAD_DLL_DEBUG_EVENT ― отлаживаемый процесс загружает DLL. Вы получите это событие, когда PE-загрузчик установит связь с DLL'ями и когда отлаживаемый процесс вызовет LoadLibrary.
    • UNLOAD_DLL_DEBUG_EVENT ― в отлаживаемом процессе выгружена DLL.
    • EXCEPTION_DEBUG_EVENT ― в отлаживаемом процессе возникло исключение. Важно: это событие будет случится, как только отлаживаемый процесс выполнит свою первую инструкцию. Этим исключением является отладочный 'break' (int 3h). Когда вы хотите, чтобы отлаживаемый процесс продолжил выполнение, вызовите ContinueDebugEvent с флагом DBG_CONTINUE. Hе используйте DBG_EXCEPTION. Также не используйте DBG_EXCEPTION_NOT_HANDLED, иначе отлаживаемый процесс откажется выполняться дальше под NT (под Win98 все работает прекрасно).
    • OUTPUT_DEBUG_STRING_EVENT ― это событие генерируется, когда отлаживаемый процесс вызываем функцию DebugOutputString, чтобы послать строку с сообщением вашей программе.
    • RIP_EVENT ― произошла системная ошибка отладки.
    dwProcessId и dwThreadId ― это ID процесса и треда в этом процессе, где произошло отладочное событие. Помните, что если вы использовали CreateProcess для загрузки отлаживаемого процесса, эти ID вы получите через структуру PROCESS_INFO. Вы можете использовать эти значения, чтобы отличить отладочные события, произошедшие в отлаживаемом процессе, от событий, произошедших в дочерних процессах.
    u ― это объединение, которое содержит дополнительную информацию об отладочном событии. Это может быть одна из следующих структур, в зависимости от dwDebugEventCode.
    • CREATE_PROCESS_DEBUG_EVENT ― CREATE_PROCESS_DEBUG_INFO-структура под названием CreateProcessInfo
    • EXIT_PROCESS_DEBUG_EVENT ― EXIT_PROCESS_DEBUG_INFO-структура под названием ExitProcess
    • CREATE_THREAD_DEBUG_EVENT ― CREATE_THREAD_DEBUG_INFO-структура под названием CreateThread
    • EXIT_THREAD_DEBUG_EVENT ― EXIT_THREAD_DEBUG_EVENT-структура под названием ExitThread
    • LOAD_DLL_DEBUG_EVENT ― LOAD_DLL_DEBUG_INFO-структура под названием LoadDll
    • UNLOAD_DLL_DEBUG_EVENT ― UNLOAD_DLL_DEBUG_INFO-структура под названием UnloadDll
    • EXCEPTION_DEBUG_EVENT ― EXCEPTION_DEBUG_INFO-структура под названием Exception
    • OUTPUT_DEBUG_STRING_EVENT ― OUTPUT_DEBUG_STRING_INFO-структура под названием DebugString
    • RIP_EVENT ― RIP_INFO-структура под названием RipInfo
  • В этом туториале я не буду вдаваться в детали относительно всех структур, здесь будет рассказано только о CREATE_PROCESS_DEBUG_INFO.
    Предполагается, что наша программа вызывает WaitForDebugEvent и возвращает управление. Первая вещь, которую мы должны сделать, это проверить значение dwDebugEventCode, чтобы узнать тип отлаживаемого события в отлаживаемом процессе. Hапример, если значение dwDebugEventCode равно CREATE_PROCESS_DEBUG_EVENT, вы можете проинтерпретировать значение u как CreateProcessInfo и получить к ней доступ через u.CreateProcessInfo.
  • Делайте все, что нужно сделать в ответ на это событие. Когда WaitForDebugEvent возвратит управление, это будет означать, что произошло отлаживаемое событие или истек заданный временной интервал. Ваша программа должна проверить значение dwDebugEventCode, чтобы отреагировать на него соответствующим образом. В этом отношении это напоминает обработку Windows-сообщений: вы выбираете какие обрабатывать, а какие игнорировать.
  • Пусть отлаживаемый процесс продолжит выполнение. Когда вы закончите обработку события, вам нужно пнуть процесс, чтобы он продолжил выполнение. Вы можете сделать это с помощью ContinueDebugEvent.
    Кликните здесь для просмотра всего текста
    Assembler
    1
    
           ContinueDebugEvent proto dwProcessId:DWORD, dwThreadId:DWORD, dwContinueStatus:DWORD
    Эта функция продолжает выполнение треда, который был заморожен произошедшим отладочным событием. dwProcessId и dwThreadId ― это процесса и треда в нем, который должен быть продолжен. Обычно эти значения вы получаете из структуры DEBUG_EVENT.
    dwContinueStatus каким образом продолжить тред, который сообщил об отлаживаемом событии. Есть два возможных значения: DBG_CONTINUE и DBG_EXCEPTION_NOT_HANDLED. Практически для всех отладочных событий они значат одно: продолжить выполнение треда. Исключение составляет событие EXCEPTION_DEBUG_EVENT. Если тред сообщает об этом событии, значит в нем случилось исключение. Если вы указали DBG_CONTINUE, тред проигнорирует собственный обработчик исключение и продолжит выполнение. В этом случае ваша программа должна сама определить и ответить на исключение, прежде, чем позволить треду продолжить выполнение, иначе исключение произойдете еще pаз и еще и еще... Если вы указали DBG_EXCEPTION_NOT_HANDLED, ваша программа указывает Windows, что она не будет обрабатывать исключения: Windows должна использовать обработчик исключений по умолчанию.
  • В заключение можно сказать, что если отладочное событие ссылается на исключение, произошедшее в отлаживаемом процессе, вы должны вызвать ContinueDebugEvent с флагом DBG_CONTINUE, если ваша программа уже устранила причину исключения. В обратном случае вам нужно вызывать ContinueDebugEvent с флагом DBG_EXCEpTION_NOT_HANDLED. Только в одном случае вы должны всегда использовать флаг DBG_CONTINUE: первое событие EXCEPTION_DEBUG_EVENT, в параметре ExceptionCode которого содержится значение EXCEPTION_BREAKPOINT. Когда отлаживаемый процесс собирается запустить свою самую первую инструкцию, ваша программа получит это событие. Фактически это отладочный останов (int 3h).
    Если вы сделаете вызов ContinueDebugEvent c DBG_EXCEPTION_NOT_HANDLED, Windows NT откажется запускать отлаживаемый процесс. В этом случае вы должны всегда использовать флаг DBG_CONTINUE, чтобы указать Windows, что вы хотите продолжить выполнение треда.
  • Делается бесконечный цикл, пока отлаживаемый процесс не завершится.
    Цикл выглядит примерно так:
    Кликните здесь для просмотра всего текста
    Assembler
    1
    2
    3
    4
    5
    6
    7
    
           .while TRUE
               invoke WaitForDebugEvent, addr DebugEvent, INFINITE
              .break .if DebugEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
              [Handle the debug events]
              invoke ContinueDebugEvent, DebugEvent.dwprocessId, \
                     DebugEvent.dwThreadId, DBG_EXCEpTION_NOT_HANDLED
           .endw
  • Вот хинт: как только вы начинаете отладку программы, вы не можете отсоединиться от отлаживаемого процесса, пока тот не завершится.
Давайте кратко повторим шаги:
  • Создаем процесс или присоединяемся к уже выполняющемуся процессу.
  • Ожидаем отладочных событий
  • Ваша программа реагирует на отладочное событие
  • Продолжаем выполнение отлаживаемого процесса
  • Продолжаем этот бесконечный цикл, пока существует отлаживаемый процесс

Практика ― сестра шизофрении
Этот пример отлаживает win32-программу и показывает важную информацию, такую как хэндл процесса, его ID, image base и так далее.
Кликните здесь для просмотра всего текста
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
   .386
   .model flat,stdcall
   option casemap:none
   include \masm32\include\windows.inc
   include \masm32\include\kernel32.inc
   include \masm32\include\comdlg32.inc
   include \masm32\include\user32.inc
   includelib \masm32\lib\kernel32.lib
   includelib \masm32\lib\comdlg32.lib
   includelib \masm32\lib\user32.lib
   .data
   AppName db "Win32 Debug Example no.1",0
   ofn OpENFILENAME <>
   FilterString db "Executable Files",0,"*.exe",0
                db "All Files",0,"*.*",0,0
   Exitproc db "The debuggee exits",0
   NewThread db "A new thread is created",0
   EndThread db "A thread is destroyed",0
   processInfo db "File Handle: %lx ",0dh,0Ah
               db "process Handle: %lx",0Dh,0Ah
               db "Thread Handle: %lx",0Dh,0Ah
               db "Image Base: %lx",0Dh,0Ah
               db "Start Address: %lx",0
   .data?
   buffer db 512 dup(?)
   startinfo STARTUpINFO <>
   pi PROCESS_INFORMATION <>
   DBEvent DEBUG_EVENT <>
   .code
start: mov ofn.lStructSize,sizeof ofn
   mov ofn.lpstrFilter, offset FilterString
   mov ofn.lpstrFile, offset buffer
   mov ofn.nMaxFile,512
   mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_pATHMUSTEXIST or OFN_LONGNAMES or \
   OFN_EXPLORER or OFN_HIDEREADONLY
   invoke GetOpenFileName, ADDR ofn
   .if eax==TRUE
   invoke GetStartupInfo,addr startinfo
   invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ \
   DEBUG_ONLY_THIS_pROCESS, NULL, NULL, addr startinfo, addr pi
   .while TRUE
      invoke WaitForDebugEvent, addr DBEvent, INFINITE
      .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
          invoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK+MB_ICONINFORMATION
          .break
      .elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
          invoke wsprintf, addr buffer, addr processInfo, \
   DBEvent.u.CreateprocessInfo.hFile, DBEvent.u.CreateprocessInfo.hprocess, \
   DBEvent.u.CreateprocessInfo.hThread, \
   DBEvent.u.CreateprocessInfo.lpBaseOfImage, \
   DBEvent.u.CreateprocessInfo.lpStartAddress
          invoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION
      .elseif DBEvent.dwDebugEventCode==EXCEpTION_DEBUG_EVENT
          .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEpTION_BREAKpOINT
             invoke ContinueDebugEvent, DBEvent.dwprocessId, DBEvent.dwThreadId, DBG_CONTINUE
            .continue
          .endif
      .elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT
          invoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION
      .elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT
          invoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION
      .endif
      invoke ContinueDebugEvent, DBEvent.dwprocessId, DBEvent.dwThreadId, DBG_EXCEpTION_NOT_HANDLED
   .endw
   invoke CloseHandle,pi.hprocess
   invoke CloseHandle,pi.hThread
   .endif
   invoke Exitprocess, 0
   end start
Анализ:
Программа заполняет структуру OPENFILENAME, а затем вызывает GetOpenFileName, чтобы пользователь выбрал программу, которую нужно отладить.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
   invoke GetStartupInfo,addr startinfo
   invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, \
                         DEBUG_pROCESS+ DEBUG_ONLY_THIS_PROCESS, NULL, \
                         NULL, addr startinfo, addr pi
Когда пользователь выберет процесс, программа вызовет CreateProcess, чтобы загрузить его. Она вызывает GetStartuрInfo, чтобы заполнить структуру STARTUPINFO значениями по умолчанию. Обратите внимание, что мы комбинируем флаги DEBUG_PROCESS и DEBUG_ONLY_THIS_PROCESS, чтобы отладить только этот процесс, не включая его дочерние процессы.
Кликните здесь для просмотра всего текста
Assembler
1
2
   .while TRUE
      invoke WaitForDebugEvent, addr DBEvent, INFINITE
Когда отлаживаемый процесс загружен, мы входим в бесконечный цикл, вызывая WaitForDebugEvent. Эта функция не возвратит управление, пока не произойдет отладочное событие в отлаживаемом процессе, потому что мы указали INFINITE в качестве второго параметра. Когда происходит отладочное событие, WaitForDebugEvent возвращает управление и DBEvent заполняется информацией о произошедшем событии.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
    .if DBEvent.dwDebugEventCode==EXIT_pROCESS_DEBUG_EVENT
          invoke MessageBox, 0, addr Exitproc, addr AppName, MB_OK+MB_ICONINFORMATION
          .break
Сначала мы проверяем значение dwDebugEventCode. Если это EXIT_PROCESS_DEBUG_EVENT, мы отображаем message box с надписью "The debuggee exits", а затем выходим из бесконечного цикла.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
      .elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
          invoke wsprintf, addr buffer, addr processInfo, \
          DBEvent.u.CreateProcessInfo.hFile, DBEvent.u.CreateprocessInfo.hprocess, \
          DBEvent.u.CreateProcessInfo.hThread, \
          DBEvent.u.CreateProcessInfo.lpBaseOfImage, \
          DBEvent.u.CreateProcessInfo.lpStartAddress
          invoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION
Если значение в dwDebugEventCode равно CREATE_PROCESS_DEBUG_EVENT, мы отображаем некоторую интересную информацию об отлаживаемом процесс в message box'е. Мы получаем эту информацию из u.CreateProcessInfo. CreateProcessInfo ― это структура типа CREATE_PROCESS_DEBUG_INFO. Вы можете узнать об этой структуре более подробно из справочника по Win32 API.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
      .elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
          .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
             invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
            .continue
          .endif
Если значение dwDebugEventCode pавно EXCEPTION_DEBUG_EVENT, мы также должны определить точный тип исключения из параметра ExcePtionCode. Если значение в ExceptionCode pавно EXCEPTION_BREAKPOINT, и это случилось в первый раз, мы можем считать, что это исключение возникло при запуске отлаживаемым процессом своей первой инструкции. После обработки сообщения мы должны вызвать ContinueDebugEvent с флагом DBG_CONTINUE, чтобы позволить отлаживаемому процессу продолжать выполнение. Затем мы снова ждем следующего отлаживаемого события.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
   .elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT
          invoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION
      .elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT
          invoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION
      .endif
Если значение в dwDebugEventCode pавно CREATE_THREAD_DEBUG_EVENT или EXIT_THREAD_DEBUG_EVENT, мы отображаем соответствующий message box.
Кликните здесь для просмотра всего текста
Assembler
1
2
  invoke ContinueDebugEvent, DBEvent.dwprocessId, DBEvent.dwThreadId, DBG_EXCEpTION_NOT_HANDLED
   .endw
Исключая вышеописанный случай с EXCEpTION_DEBUG_EVENT, мы вызываем ContinueDebugEvent с флагом DBG_EXCEpTION_NOT_HANDLED.
Кликните здесь для просмотра всего текста
Assembler
1
2
   invoke CloseHandle,pi.hprocess
   invoke CloseHandle,pi.hThread
Когда отлаживаемый процесс завершает выполнение, мы выходим из цикла отладки и должны закрыть хэндлы отлаживаемого процесса и треда. Закрытие хэндлов не означает, что мы их прерываем. Это только значит, что мы больше не хотим использовать эти хэндлы для ссылки на соответствующий процесс/тред.
_________________________________________
© Iczelion, пер. Aquila.
3
Вложения
Тип файла: zip tut28.zip (2.7 Кб, 49 просмотров)
Mikl___
Заблокирован
Автор FAQ
24.01.2013, 09:09  [ТС] #72
Win32 API. Урок 28a. Виртуальный секс с Анфисой Чеховой
Скачайте пример здесь. Пример конечного автомата, заодно научимся выводить jpg-файлы на экран
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
.586p
.model tiny
include windows.inc
;for WinXP - 106398 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"    ;;  \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
;-------------------------------
exebase     equ 400000h
lang        equ 409h
ID_JPG1     equ 0
ID_JPG2     equ 1
ID_JPG3     equ 2
ID_JPG4     equ 3
ID_JPG5     equ 4
ID_JPG6     equ 5
ID_BTN_EXIT     equ 100
;-------------------------
.code
main:
include capito_res.asm
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
;------------------------------
; registering the window class 
;------------------------------
    mov edi,offset wTitle+exebase
        invoke LoadCursorFromFile,offset CursorFile+exebase
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,ebx,\
    ebx,esi,eax,eax,COLOR_BTNFACE+1,ebx,edi
    mov ecx,[Cpt+exebase]
    mov eax,[WinW+ecx*4+exebase]
    mov [x2Reg+exebase],eax
    mov eax,[WinH+ecx*4+exebase]
    mov [y2Reg+exebase],eax
 
    invoke GetSystemMetrics,SM_CYDLGFRAME
    mov [y1Reg+exebase],eax
    add [y2Reg+exebase],eax
    shl eax,1
    add [WinH+exebase],eax
    add [WinW+exebase],eax
    invoke GetSystemMetrics,SM_CXDLGFRAME
    mov [x1Reg+exebase],eax
    inc eax
    add [x2Reg+exebase],eax
    ; Hauteur du bandeau titre
    ; ------------------------
        invoke GetSystemMetrics,SM_CYCAPTION
        add [WinH+exebase],eax
        add [y1Reg+exebase],eax
        inc eax
        add [y2Reg+exebase],eax
    ; Obtenir la largeur en pixels de l'ecran
    ; ---------------------------------------
        invoke GetSystemMetrics,ebx;SM_CXSCREEN
        mov [WScreen+exebase],eax
        sub eax,[WinW+exebase]
        shr eax,1
        mov [WinX+exebase],eax
    ; Obtenir la hauteur en pixels de l'ecran
    ; ---------------------------------------
        invoke GetSystemMetrics,SM_CYSCREEN
        mov [HScreen+exebase],eax
        sub eax,[WinH+exebase]
        shr eax,1
        mov [WinY+exebase],eax
;--------------------------+
; creating the main window |
;--------------------------+
restart: mov eax,[Cpt+exebase]
        mov esi,exebase
    mov edi,offset wTitle+exebase
    invoke CreateWindowEx,WS_EX_LEFT,edi,edi,\
    WS_POPUP or WS_CAPTION or WS_SYSMENU,[WinX+exebase],[WinY+exebase],\
    [WinW+eax*4+exebase],[WinH+eax*4+exebase],ebx,ebx,esi,ebx
    mov [hWnd+exebase],eax
    mov ecx,[Cpt+exebase]
    mov eax,[WinW+ecx*4+exebase]
    mov [x2Reg+exebase],eax
    mov eax,[WinH+ecx*4+exebase]
    mov [y2Reg+exebase],eax
    invoke CreateRoundRectRgn,[x1Reg+exebase],[y1Reg+exebase],[x2Reg+exebase],[y2Reg+exebase],100,100
    invoke SetWindowRgn,[hWnd+exebase],eax,ebx
    invoke ShowWindow,[hWnd+exebase],SW_SHOWDEFAULT
    CALL BitmapFromResource
    mov [hBmp+exebase],eax
        mov eax,[Cpt+exebase]
    mov eax,[WinW+eax*4+exebase]
    sub eax,60
        invoke CreateWindowEx,ebx,offset btnClass+exebase,offset lpText+exebase,\
    WS_CHILD or WS_VISIBLE,eax,18,20,18,[hWnd+exebase],ID_BTN_EXIT,exebase,ebx
    mov ebp,esp
;---------------------------+
; entering the message loop |
;---------------------------+
window_message_loop_start: invoke GetMessage,ebp,ebx,ebx,ebx
        xchg eax,ecx
    jecxz ExitProgram
    invoke DispatchMessage,ebp
    jmp window_message_loop_start
ExitProgram: cmp [ClickMouse+exebase],ebx
       jz a0
       inc dword ptr [Cpt+exebase]
       mov eax,[Cpt+exebase]
       jmp dword ptr [handler+eax*4-4+exebase]
a1:    mov dword ptr [WinX+exebase],10
       jmp short a6
a2:    mov eax,[WScreen+exebase]
       sub eax,[WinW+exebase]
       sub eax,160
       mov [WinX+exebase],eax
       jmp short a6
a3:    mov dword ptr [WinX+exebase],10
       mov eax,[HScreen+exebase]
       sub eax,[WinH+exebase]
       sub eax,160
       jmp short a7
a4:    mov eax,[WScreen+exebase]
       sub eax,[WinW+3*4+exebase]
       shr eax,1
       mov [WinX+exebase],eax
       mov eax,[HScreen+exebase]
       sub eax,[WinH+3*4+exebase]
       shr eax,1
a7:    mov [WinY+exebase],eax
       jmp restart
a5:    mov eax,[WScreen+exebase]
       sub eax,[WinW+4*4+exebase]
       shr eax,1
       mov [WinX+exebase],eax
a6:    mov [WinY+exebase],ebx;0
       jmp restart
a0: invoke ExitProcess,ebx
;----------------------+
; the window procedure |
;----------------------+
window_procedure:
hWin    equ ebp+8
uMsg    equ hWin+4
wParam  equ uMsg+4
lParam  equ wParam+4
hOld    equ ebp-4
    enter 4+sizeof(PAINTSTRUCT),0
    mov eax,[uMsg]
    mov edi,[hWin]
    dec eax
    dec eax
    jz wmDESTROY;2
    sub eax,WM_PAINT-WM_DESTROY
    jz short wmPAINT
        sub eax,WM_COMMAND-WM_PAINT
    jz short wmCOMMAND
    sub eax,WM_LBUTTONDOWN-WM_COMMAND
    jz short wmLBUTTONDOWN
    leave
    jmp DefWindowProc+exebase
wmDESTROY: mov [ClickMouse+exebase],ebx
    invoke PostQuitMessage,ebx
    jmp wmBYE
wmCOMMAND: cmp dword ptr [wParam],ID_BTN_EXIT
    jne wmBYE
    invoke PostMessage,edi,WM_DESTROY,ebx,ebx
    jmp wmBYE
wmLBUTTONDOWN: invoke DestroyWindow,edi
    inc ClickMouse+exebase
    invoke PostQuitMessage,ebx
    jmp wmBYE
wmPAINT: invoke BeginPaint,edi,esp
    invoke CreateCompatibleDC,eax
    mov esi,eax;memDC
    invoke SelectObject,eax,[hBmp+exebase]
    mov [hOld],eax
        mov eax,[Cpt+exebase]
    invoke BitBlt,dword ptr [esp+8*4],ebx,1,[WinW+eax*4+exebase],[WinH+eax*4+exebase],esi,ebx,ebx,SRCCOPY
    invoke SetBkMode,dword ptr [esp+4],TRANSPARENT
        mov eax,[Cpt+exebase]
        invoke DrawText,dword ptr [esp+4*4],dword ptr [handler2+eax*4+exebase],-1,offset rectTxt+exebase,DT_SINGLELINE+DT_VCENTER+DT_CENTER
    invoke SelectObject,dword ptr [esp+4],[hOld]
    invoke DeleteDC,esi
    invoke EndPaint,edi,esp
wmBYE:  leave
    retn 10h
;---------------------------------------------------------------------
BitmapFromResource:
; get a resource handle (address) and resource length from the executable
        invoke FindResource,esi,[Cpt+exebase],offset aImage+exebase
        xchg eax,ecx;mov hResource, eax
        jecxz @f
    invoke LoadResource,esi,ecx,ecx;invoke LoadResource, hModule, eax
    invoke LockResource,eax
    mov edi,eax;mov hImage, eax 
        invoke SizeofResource,esi ;invoke SizeofResource, hModule, hResource
    xchg eax,ecx ;mov dwFileSize, eax
    jecxz @f
; we use the resource size to determine if we got a
; legit image file to open
        push ecx
    push edi
    CALL b0;invoke BitmapFromMemory, hImage, dwFileSize
    retn
@@:     invoke SetLastError,2;ERROR_FILE_NOT_FOUND
    xor eax,eax
    retn
;--------------BitmapFromResource endp
;BitmapFromMemory  PROC  pMemory:DWORD, dwFileSize:DWORD
 
;    LOCAL hResource:DWORD,  pGlobal:DWORD,      pStream:DWORD
;    LOCAL hImage:DWORD,     pPicture:DWORD,     hBitmap:DWORD
 
b0: enter 24,0
        mov [ebp-12],ebx;mov pStream, NULL
        mov [ebp-14h],ebx;mov pPicture, NULL    ; NULL pointers for later use
        invoke CoTaskMemAlloc,dword ptr [ebp+12];invoke CoTaskMemAlloc, dwFileSize   ; copy picture into task memory
        xchg eax,ecx
    jecxz @4
;.if !eax
; oops! we didn't get the memory
; the last error code was set for us, and EAX is zero, so just return
;        ret
;.endif
    mov [ebp-8],ecx;mov pGlobal, eax
    mov esi,[ebp+8]
    mov edi,ecx
    mov ecx,[ebp+12]
    rep movsb;invoke _MemCopy, pMemory, pGlobal, dwFileSize
; create a stream for the picture object's creator
;invoke CreateStreamOnHGlobal, pGlobal, TRUE, ADDR pStream
;    or eax,eax
;    jz @f 
;    invoke CoTaskMemFree,pGlobal
;    xor eax,eax
;    ret
        lea eax,[ebp-12]
        invoke CreateStreamOnHGlobal,dword ptr [ebp-8],1,eax
        xchg eax,ecx
        jecxz @f
        invoke CoTaskMemFree,dword ptr [ebp-8]
    jmp short @1
@@: lea eax,[ebp-14h]
;invoke OleLoadPicture, pStream, NULL, TRUE, ADDR IID_IPicture, ADDR pPicture
        invoke OleLoadPicture,dword ptr [ebp-12],ebx,1,offset d0+exebase,eax
        xchg eax,ecx
        jecxz @3
    mov eax,[ebp-12]
    push eax
    mov eax,[eax]
    CALL dword ptr [eax+8]
@1: xor eax,eax
    jmp short @4
@3:     push dword ptr [ebp-14h]
    CALL b1
    mov [ebp-18h],eax
        mov eax,[ebp-12]
    push eax
    mov eax,[eax]
    CALL dword ptr [eax+8]
        mov eax,[ebp-14h]
    push eax
    mov eax,[eax]
    CALL dword ptr [eax+8]
        mov eax,[ebp-18h]
@4: leave
    retn 8
;------------------------b0 endp
b1: enter 36,0
    cmp dword ptr [ebp+8],ebx
    je @11
    invoke GetDC,ebx
        mov [ebp-18h],eax
    invoke CreateCompatibleDC,dword ptr [ebp-18h]
        or eax,eax
    jne short @13
    invoke ReleaseDC,ebx,dword ptr [ebp-18h]
    jmp @17
@13:    mov [ebp-4],eax
    lea eax,[ebp-1Ch]
    push eax
    mov eax,[ebp+8]
    push eax
    mov eax,[eax]
    CALL dword ptr [eax+18h]
    lea eax,[ebp-20h]
    push eax
    mov eax,[ebp+8]
    push eax
    mov eax,[eax]
    CALL dword ptr [eax+1Ch]
    invoke GetDeviceCaps,dword ptr [ebp-18h],58h
    invoke MulDiv,dword ptr [ebp-1Ch],eax,9ECh
    mov [ebp-10h],eax
    invoke GetDeviceCaps,dword ptr [ebp-18h],5Ah
    invoke MulDiv,dword ptr [ebp-20h],eax,9ECh
    mov [ebp-14h],eax
    mov ecx,[ebp-20h]
    neg ecx
    mov [ebp-24h],ecx
        invoke CreateCompatibleBitmap,dword ptr [ebp-18h],dword ptr [ebp-10h],eax
    xchg eax,ecx
    jecxz @14
    mov [ebp-8],ecx
        invoke SelectObject,dword ptr [ebp-4],ecx
    or eax,eax
    jne short @15
        invoke DeleteObject,dword ptr [ebp-8]
@14:    invoke ReleaseDC,ebx,dword ptr [ebp-18h]
        invoke DeleteDC,dword ptr [ebp-4]
    jmp short @17
@11:    push 57h
    jmp short @12
@15:    mov [ebp-0Ch],eax
    push ebx
    push dword ptr [ebp-24h]
    push dword ptr [ebp-1Ch]
    push dword ptr [ebp-20h]
    push ebx
    push dword ptr [ebp-14h]
    push dword ptr [ebp-10h]
    push ebx
    push ebx
    push dword ptr [ebp-4]
    mov eax,[ebp+8]
    push eax
    mov eax,[eax]
        CALL dword ptr [eax+20h]
    or eax,eax
    jns short @16
        invoke ReleaseDC,ebx,dword ptr [ebp-18h],eax
        invoke DeleteDC,dword ptr [ebp-4]
        invoke DeleteObject,dword ptr [ebp-8]
    pop eax
    push eax
@12:    invoke SetLastError
@17:    xor eax,eax
    jmp short @10
@16:     invoke ReleaseDC,ebx,dword ptr [ebp-18h]
        invoke SelectObject,dword ptr [ebp-4],dword ptr [ebp-0Ch]
        invoke DeleteDC,dword ptr [ebp-4]
    mov eax,[ebp-8]
@10:    leave
    retn 4
;---------------------------------------------------------------------------
aImage db 'IMAGE',0
d0 GUID <7BF80980h,0BF32h,101Ah,{8Bh,0BBh,0,0AAh,0,30h,0Ch,0ABh}>
wTitle  db "SEX-Tamagochi",0
WinW    dd 247,535+5,396+5,326+5,335+5,600+5
WinH    dd 295,268+25,208+25,396+25,236+25,244+25
WScreen dd ?       
HScreen dd ?       
WinX    dd ?
WinY    dd ?
x1Reg   dd ?
y1Reg   dd ?
x2Reg   dd ?
y2Reg   dd ?
hBmp    dd ?
hWnd    dd ?
btnClass db 'BUTTON',0
ClickMouse dd 0
handler dd a1+exebase,a2+exebase,a3+exebase,a4+exebase,a5+exebase,a0+exebase
lpText  db 'X',0
Cpt     dd 0
Txt0    db 'oh! My Dear, click me!',0
Txt1    db 'hmmm! again, again...',0
Txt2    db "aaah! it's too much....",0
Txt3    db "iiih! You roast my circuits!...",0
Txt4    db "Stop Programmer, WORK!",0
Txt5    db "GoodBye My Dear...",0
handler2 dd Txt0+exebase,Txt1+exebase,Txt2+exebase,Txt3+exebase,Txt4+exebase,Txt5+exebase
rectTxt RECT <16,0,200,85>
CursorFile db 'Images\heart.cur';,0
;--------------------------------------------------------------------
resource:
dd 0,0,0
NumberOfNamedEntries1   dw 1;количество ресурсов с именами
NumberOfIdEntries1  dw 0;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw uImage1-resource,8000h,i1-resource,8000h
i1:
dd 0,0,0
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 6;количество ресурсов с идентификаторами
dw ID_JPG1,0,i21-resource,8000h
dw ID_JPG2,0,i22-resource,8000h
dw ID_JPG3,0,i23-resource,8000h
dw ID_JPG4,0,i24-resource,8000h
dw ID_JPG5,0,i25-resource,8000h
dw ID_JPG6,0,i26-resource,8000h
i21:
dd 0,0,0
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
dw lang,0,i31-resource,0
i31 dd i41,i42-i41,0,0
i22:
dd 0,0,0
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
dw lang,0,i32-resource,0
i32 dd i42,i43-i42,0,0
i23:
dd 0,0,0
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
dw lang,0,i33-resource,0
i33 dd i43,i44-i43,0,0
i24:
dd 0,0,0
NumberOfNamedEntries6   dw 0;количество ресурсов с именами
NumberOfIdEntries6  dw 1;количество ресурсов с идентификаторами
dw lang,0,i34-resource,0
i34 dd i44,i45-i44,0,0
i25:
dd 0,0,0
NumberOfNamedEntries7   dw 0;количество ресурсов с именами
NumberOfIdEntries7  dw 1;количество ресурсов с идентификаторами
dw lang,0,i35-resource,0
i35 dd i45,i46-i45,0,0
i26:
dd 0,0,0
NumberOfNamedEntries8   dw 0;количество ресурсов с именами
NumberOfIdEntries8  dw 1;количество ресурсов с идентификаторами
dw lang,0,i36-resource,0
i36 dd i46,end_resource-i46,0,0
uImage1 dw (i41 - uImage1 - 6)/2
du <IMAGE>
dw 0
i41:
; incbin "Images\1.jpg"
; D:\Aquila\MASM\MyProject\Lessons\new\Images\1.JPG is 12987 bytes long
db 255,216,255,224,0,16,74,70,73,70,0,1,1,1,0,96
db 0,96,0,0,255,219,0,67,0,8,6,6,7,6,5,8
db 7,7,7,9,9,8,10,12,20,13,12,11,11,12,25,18
db 19,15,20,29,26,31,30,29,26,28,28,32,36,46,39,32
db 34,44,35,28,28,40,55,41,44,48,49,52,52,52,31,39
db 57,61,56,50,60,46,51,52,50,255,219,0,67,1,9,9
db 9,12,11,12,24,13,13,24,50,33,28,33,50,50,50,50
db 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50
db 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50
db 50,50,50,50,50,50,50,50,50,50,50,50,50,50,255,192
db 0,17,8,1,41,0,249,3,1,34,0,2,17,1,3,17
db 1,255,196,0,31,0,0,1,5,1,1,1,1,1,1,0
db 0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9
db 10,11,255,196,0,181,16,0,2,1,3,3,2,4,3,5
db 5,4,4,0,0,1,125,1,2,3,0,4,17,5,18,33
db 49,65,6,19,81,97,7,34,113,20,50,129,145,161,8,35
db 66,177,193,21,82,209,240,36,51,98,114,130,9,10,22,23
db 24,25,26,37,38,39,40,41,42,52,53,54,55,56,57,58
db 67,68,69,70,71,72,73,74,83,84,85,86,87,88,89,90
db 99,100,101,102,103,104,105,106,115,116,117,118,119,120,121,122
db 131,132,133,134,135,136,137,138,146,147,148,149,150,151,152,153
db 154,162,163,164,165,166,167,168,169,170,178,179,180,181,182,183
db 184,185,186,194,195,196,197,198,199,200,201,202,210,211,212,213
db 214,215,216,217,218,225,226,227,228,229,230,231,232,233,234,241
db 242,243,244,245,246,247,248,249,250,255,196,0,31,1,0,3
db 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1
db 2,3,4,5,6,7,8,9,10,11,255,196,0,181,17,0
db 2,1,2,4,4,3,4,7,5,4,4,0,1,2,119,0
db 1,2,3,17,4,5,33,49,6,18,65,81,7,97,113,19
db 34,50,129,8,20,66,145,161,177,193,9,35,51,82,240,21
db 98,114,209,10,22,36,52,225,37,241,23,24,25,26,38,39
db 40,41,42,53,54,55,56,57,58,67,68,69,70,71,72,73
db 74,83,84,85,86,87,88,89,90,99,100,101,102,103,104,105
db 106,115,116,117,118,119,120,121,122,130,131,132,133,134,135,136
db 137,138,146,147,148,149,150,151,152,153,154,162,163,164,165,166
db 167,168,169,170,178,179,180,181,182,183,184,185,186,194,195,196
db 197,198,199,200,201,202,210,211,212,213,214,215,216,217,218,226
db 227,228,229,230,231,232,233,234,242,243,244,245,246,247,248,249
db 250,255,218,0,12,3,1,0,2,17,3,17,0,63,0,228
db 175,100,229,88,19,243,2,78,61,57,255,0,235,127,147,84
db 32,155,108,243,30,79,151,31,36,126,95,225,87,174,151,127
db 154,171,200,218,66,254,95,231,242,172,152,206,215,145,191,137
db 249,57,246,224,127,90,152,236,122,51,220,217,150,79,244,28
db 227,144,27,167,166,43,156,145,143,218,0,201,195,103,249,214
db 240,127,54,192,17,253,195,198,63,10,231,110,206,217,55,15
db 192,251,231,255,0,175,68,2,171,209,49,146,187,44,147,38
db 120,117,227,254,250,170,22,50,48,186,64,73,235,90,119,104
db 126,209,185,71,4,21,31,159,21,143,17,217,120,61,155,165
db 51,154,90,51,222,60,39,55,153,167,160,244,24,174,178,53
db 205,112,158,10,156,27,15,153,128,11,212,147,218,183,110,252
db 93,99,102,74,161,243,8,56,200,56,21,196,227,171,71,123
db 187,216,233,212,98,164,4,215,35,7,141,236,219,6,116,216
db 167,184,57,197,106,195,226,77,42,117,44,151,145,12,122,182
db 41,217,162,90,102,193,56,52,210,106,156,122,149,180,184,17
db 204,143,244,106,177,188,53,38,43,11,223,154,61,233,160,208
db 72,31,74,67,184,164,243,205,70,205,142,166,162,158,225,98
db 86,98,120,2,184,141,91,198,23,66,103,131,79,131,115,41
db 193,98,51,138,55,118,67,73,179,167,212,47,34,182,133,164
db 150,64,138,61,77,113,90,143,140,2,150,142,206,48,231,179
db 26,231,245,11,249,167,125,250,157,250,169,61,83,117,81,254
db 218,210,160,32,43,171,31,92,19,90,198,146,221,234,83,211
db 70,210,245,46,205,170,107,87,172,72,144,128,125,184,170,119
db 166,243,203,223,112,160,255,0,182,167,63,157,93,139,86,134
db 85,18,70,202,195,175,7,53,28,211,139,152,152,1,86,149
db 186,88,37,4,215,197,115,29,136,116,36,30,162,176,103,44
db 36,35,39,173,116,70,22,140,55,167,214,176,110,84,125,171
db 145,215,138,209,28,85,86,132,32,231,144,113,235,68,129,148
db 115,159,168,239,86,5,148,140,155,128,32,210,70,55,52,144
db 186,225,144,115,197,81,141,132,177,149,150,86,10,217,220,164
db 126,132,255,0,65,90,65,24,156,140,240,127,250,245,66,11
db 125,179,35,103,27,190,239,29,120,53,171,0,4,176,110,70
db 105,51,72,34,9,149,145,129,92,241,200,21,122,1,191,128
db 79,204,63,81,77,113,200,29,134,7,208,255,0,159,229,83
db 194,161,10,128,7,202,118,254,31,228,227,240,164,106,163,169
db 232,94,3,212,89,89,21,152,238,129,192,97,156,230,54,232
db 127,2,71,224,213,235,25,175,15,208,36,251,53,245,163,48
db 249,28,249,108,123,0,216,92,159,196,15,202,189,154,198,86
db 150,202,23,127,191,183,13,245,28,31,214,170,6,53,213,154
db 101,176,120,163,52,130,140,213,24,31,60,202,165,46,165,66
db 6,228,224,142,223,196,43,43,102,23,0,243,158,9,31,90
db 215,212,191,119,172,222,34,227,9,114,234,48,59,2,213,150
db 72,36,1,141,192,144,8,239,254,113,81,19,209,150,164,214
db 167,22,165,51,156,1,212,244,224,227,250,86,21,232,43,41
db 200,232,72,173,168,24,9,88,12,225,129,11,147,252,75,143
db 240,170,122,180,25,10,231,56,206,63,167,249,250,83,90,50
db 39,172,8,70,217,224,139,3,230,60,15,175,79,235,250,214
db 53,204,126,85,238,87,161,228,28,117,21,167,106,219,163,116
db 60,48,57,4,126,191,231,218,160,190,93,243,43,1,128,57
db 250,103,252,58,126,20,204,101,170,185,221,248,57,227,185,183
db 48,75,184,198,192,18,160,227,118,59,26,236,7,246,36,68
db 43,90,64,8,254,244,99,138,225,60,9,135,109,141,205,109
db 248,171,68,186,242,90,230,210,71,12,78,91,3,245,246,174
db 119,110,123,29,176,151,184,153,115,84,213,124,63,108,164,76
db 136,6,113,128,196,15,168,0,215,31,117,173,232,70,108,192
db 183,75,254,210,73,140,127,223,85,71,195,250,12,26,198,175
db 53,190,167,114,222,120,200,84,118,251,199,250,253,42,181,222
db 142,246,48,75,167,92,236,129,163,144,72,115,14,94,70,251
db 187,67,103,132,193,45,232,72,21,209,26,54,221,156,210,197
db 62,145,251,205,203,45,90,209,138,249,119,87,81,99,129,189
db 50,63,10,244,45,15,87,221,110,145,153,196,190,141,94,111
db 107,225,219,11,109,7,237,151,87,31,101,184,103,221,8,222
db 20,149,245,197,110,120,117,227,75,216,237,227,187,134,114,235
db 185,76,108,78,61,143,161,172,107,81,86,188,89,209,70,183
db 58,247,145,234,17,57,97,156,228,82,75,33,85,36,212,54
db 101,188,176,15,81,78,190,5,96,39,218,185,122,21,214,199
db 47,175,107,30,78,229,4,99,222,188,251,80,213,38,145,140
db 113,29,163,171,17,209,69,107,106,239,45,230,167,228,161,228
db 190,57,237,89,203,161,107,80,94,196,209,192,175,26,30,24
db 185,31,55,118,56,231,191,21,173,8,198,247,150,230,149,100
db 226,185,98,96,189,132,171,246,107,139,132,120,45,103,148,175
db 218,165,140,182,113,212,133,234,127,198,178,90,206,226,91,151
db 18,164,145,17,38,194,178,38,214,25,62,135,191,74,244,205
db 82,234,250,125,63,251,62,239,73,133,225,192,49,188,101,144
db 198,64,28,142,15,175,243,174,78,77,51,80,243,60,199,98
db 14,65,220,252,156,227,57,247,63,90,236,230,141,183,60,217
db 82,168,222,168,231,158,218,107,27,243,20,114,111,97,143,187
db 222,186,221,42,38,158,51,129,156,125,234,169,97,225,233,174
db 239,87,229,108,231,113,115,215,167,173,119,22,154,50,217,166
db 64,231,24,201,231,53,133,106,169,104,142,140,61,41,71,86
db 115,119,214,187,35,61,190,149,201,223,71,137,51,156,124,216
db 175,64,213,83,8,120,226,184,171,248,75,110,0,100,150,3
db 31,157,77,41,93,14,188,116,34,181,150,91,185,60,136,87
db 39,239,31,111,122,173,130,53,25,195,1,144,184,39,183,21
db 60,113,220,105,119,74,204,8,15,242,146,13,65,44,198,91
db 169,93,126,239,221,255,0,63,149,108,115,61,149,247,45,69
db 24,105,144,129,242,140,14,123,127,156,213,235,104,137,253,238
db 51,243,99,31,95,255,0,93,85,179,79,221,130,123,183,167
db 227,253,5,105,91,43,253,158,98,152,37,126,98,7,214,135
db 177,112,67,100,64,14,225,223,159,243,250,84,241,71,152,247
db 158,197,115,75,48,224,140,103,21,114,194,221,174,109,38,218
db 9,43,3,63,229,130,127,149,79,67,107,36,203,246,123,254
db 202,231,39,49,156,0,59,103,60,159,166,63,90,246,77,2
db 111,180,104,86,83,19,146,241,134,39,212,215,142,216,9,0
db 185,137,99,222,175,25,36,228,240,23,12,79,228,167,243,175
db 95,240,208,97,225,219,16,224,238,242,249,207,212,211,131,50
db 196,175,117,26,226,142,104,20,126,21,161,196,124,239,124,196
db 106,37,217,148,146,65,12,189,27,138,161,26,146,89,185,192
db 108,252,223,92,154,218,215,172,155,79,191,107,118,218,66,159
db 221,178,142,25,115,88,104,202,174,65,200,39,142,77,66,61
db 23,208,124,72,35,156,2,216,206,78,7,184,193,254,116,183
db 41,231,91,200,9,232,57,250,119,199,208,243,77,98,67,43
db 6,233,130,125,234,85,224,228,243,130,71,215,255,0,214,49
db 76,60,140,5,205,181,200,56,232,122,125,63,196,127,42,183
db 117,18,141,187,128,218,65,218,71,232,127,81,77,190,143,100
db 132,129,211,149,231,168,255,0,60,82,71,40,150,201,135,241
db 194,65,7,213,121,254,92,126,84,217,146,86,109,27,190,4
db 144,165,251,70,122,134,197,122,232,132,77,14,214,92,130,43
db 197,252,49,47,217,245,232,219,160,147,28,123,215,183,89,48
db 104,151,142,213,203,83,226,55,143,192,142,27,90,240,58,207
db 59,77,110,54,150,244,29,61,255,0,90,205,111,13,106,210
db 34,197,45,245,203,70,56,30,99,179,109,231,182,79,210,189
db 95,203,4,114,41,60,133,207,43,78,53,167,21,100,201,113
db 132,190,36,121,156,30,12,64,70,216,218,87,63,122,73,70
db 79,249,233,205,117,122,102,128,182,112,175,247,189,125,235,161
db 242,23,160,2,159,176,42,226,166,83,148,183,101,171,45,34
db 172,85,133,54,28,26,125,248,255,0,70,63,74,118,62,113
db 218,157,120,63,209,207,94,149,151,70,95,84,121,135,148,6
db 185,33,35,39,118,107,177,181,80,97,28,10,229,110,190,77
db 98,70,30,181,211,88,75,186,33,89,223,99,166,113,186,38
db 150,217,36,82,8,235,214,168,182,137,110,239,147,30,77,107
db 102,156,79,60,85,24,234,140,248,180,216,162,251,168,7,208
db 83,46,163,11,25,173,23,108,14,43,46,246,76,41,21,45
db 142,41,182,114,186,190,2,183,21,203,136,82,91,148,15,211
db 126,127,67,254,53,209,106,207,156,215,55,45,229,165,164,202
db 183,82,109,220,165,135,4,247,246,250,87,69,29,133,90,202
db 215,29,169,70,190,68,134,66,8,81,145,154,231,44,129,118
db 102,200,7,35,167,90,177,171,234,203,118,60,139,125,222,89
db 63,51,17,130,222,212,221,42,49,203,48,198,43,166,41,165
db 169,195,82,74,83,180,77,21,79,38,32,170,50,71,243,63
db 228,126,117,115,79,44,223,106,3,128,98,3,245,53,71,205
db 223,114,8,193,28,159,210,180,109,255,0,116,140,122,103,143
db 195,154,37,177,112,90,146,74,118,224,103,56,199,94,248,174
db 131,195,80,133,150,100,231,43,111,34,140,122,237,199,245,174
db 122,53,50,204,50,115,145,233,93,159,131,162,15,113,125,112
db 249,217,29,180,135,233,187,3,249,41,169,91,163,73,252,45
db 144,105,80,147,111,111,32,231,204,134,81,146,56,31,39,235
db 212,254,85,234,218,34,227,69,178,245,242,129,175,49,96,109
db 188,43,111,42,224,57,18,170,128,59,8,176,79,235,94,169
db 166,169,93,54,212,17,131,229,46,120,199,106,186,123,28,248
db 151,123,22,197,20,10,90,208,228,60,31,85,211,175,236,218
db 72,117,16,65,220,187,92,182,72,108,118,231,166,115,92,244
db 145,135,60,141,174,163,28,125,123,87,97,227,13,89,110,221
db 93,21,81,137,36,247,99,234,73,237,215,129,218,185,61,234
db 240,34,170,156,162,129,146,122,245,254,152,172,227,228,122,58
db 180,175,185,95,114,145,247,134,123,113,214,164,243,54,237,114
db 113,149,193,250,143,106,130,83,151,220,164,243,193,20,140,230
db 72,91,131,158,163,2,168,150,199,92,167,159,27,34,227,120
db 57,95,175,127,192,214,68,50,121,55,1,207,220,232,203,237
db 220,85,193,38,17,9,39,184,36,84,55,42,24,153,130,142
db 112,28,15,94,199,241,164,75,119,212,177,166,72,109,117,104
db 149,143,220,144,96,251,30,159,211,242,175,117,210,165,15,106
db 140,59,138,240,15,48,249,246,210,147,146,223,35,55,184,60
db 26,246,191,12,221,121,218,124,103,218,185,171,232,211,55,165
db 172,90,58,165,60,100,211,186,250,85,120,223,34,164,221,154
db 202,227,113,38,31,133,53,141,32,106,100,178,129,197,13,130
db 142,163,120,44,41,215,120,48,31,165,68,173,150,169,167,82
db 209,99,190,41,45,138,123,163,205,181,76,71,170,49,236,77
db 108,233,178,13,171,142,69,98,120,177,90,11,180,108,112,77
db 38,157,168,53,157,204,41,47,220,124,10,207,151,68,206,171
db 223,67,178,223,199,181,27,250,208,184,120,131,45,64,231,30
db 212,140,237,113,242,200,0,60,214,69,244,195,105,205,88,158
db 99,207,181,97,234,55,24,66,51,82,245,118,52,140,108,98
db 95,190,247,62,213,195,107,178,239,212,216,118,69,10,43,178
db 184,108,35,72,127,10,224,47,36,18,221,202,248,234,230,187
db 168,171,35,135,25,45,44,50,52,118,108,175,111,202,181,33
db 144,199,110,84,29,199,169,39,190,63,165,101,36,132,124,170
db 7,62,213,106,22,97,25,231,37,143,53,185,197,7,102,105
db 105,228,201,49,231,128,56,31,136,255,0,10,214,193,222,251
db 115,192,199,249,252,235,43,70,95,222,177,61,49,254,21,187
db 111,17,112,91,25,203,15,230,7,244,169,103,85,37,116,88
db 133,68,106,88,244,9,192,247,197,116,154,4,226,207,75,212
db 203,31,153,160,217,254,241,60,99,245,106,231,91,0,158,126
db 85,233,254,127,10,183,109,56,17,70,163,156,182,28,103,175
db 57,35,250,86,119,105,220,221,197,53,99,110,112,247,239,161
db 104,209,103,116,178,97,143,162,179,2,199,242,6,189,124,0
db 48,7,0,112,43,195,237,181,246,210,117,232,245,20,137,38
db 120,126,64,141,208,100,115,131,234,7,2,189,119,67,215,236
db 117,251,49,113,103,38,113,195,198,223,121,15,161,21,181,55
db 161,197,136,78,254,70,175,106,40,205,25,53,161,202,124,249
db 226,87,121,245,121,195,60,103,105,43,185,15,7,159,169,172
db 155,114,177,41,81,32,57,24,199,65,250,138,216,181,240,229
db 245,220,235,26,67,112,92,156,96,161,24,245,207,76,86,142
db 167,225,57,180,200,26,73,35,194,32,203,176,144,123,118,192
db 35,245,168,74,200,244,111,27,218,231,31,43,70,204,234,88
db 5,199,3,61,234,45,168,121,4,151,110,6,211,142,181,114
db 75,101,221,133,36,17,207,60,213,89,160,157,114,115,156,122
db 103,138,164,68,147,41,220,184,12,219,114,16,242,56,168,224
db 159,107,145,39,42,87,13,223,112,237,74,209,56,66,92,29
db 189,137,170,233,108,205,50,166,65,30,157,232,50,109,167,116
db 92,88,9,99,15,222,81,202,159,81,159,254,189,122,135,131
db 229,97,100,170,127,187,94,108,174,35,146,61,199,7,33,120
db 62,181,233,94,20,41,37,172,82,71,247,93,127,35,222,185
db 113,31,9,217,135,178,185,216,196,249,21,97,88,213,52,27
db 77,89,83,210,185,145,179,37,50,109,21,10,163,200,119,158
db 253,169,248,201,231,165,74,56,197,2,34,138,88,183,237,222
db 50,59,85,167,145,89,78,8,197,86,150,218,41,156,59,32
db 222,58,48,234,63,26,167,117,4,161,8,138,83,211,128,105
db 222,196,217,54,115,62,43,142,43,134,10,8,220,167,174,113
db 138,231,167,146,22,242,66,56,102,67,218,182,181,125,46,114
db 133,217,137,39,175,189,98,37,155,163,12,241,205,74,103,84
db 82,75,67,176,210,110,139,90,166,238,120,230,172,220,3,201
db 172,221,57,130,160,31,157,105,75,32,242,176,77,102,75,220
db 202,157,241,158,107,159,191,147,115,109,173,123,201,71,205,131
db 154,193,185,110,164,211,130,212,183,162,49,181,107,145,5,156
db 142,63,129,78,62,181,194,146,72,57,250,215,67,226,107,172
db 42,91,3,212,238,111,167,106,231,227,140,177,192,175,74,154
db 180,79,31,19,62,105,219,176,248,147,156,227,34,181,18,32
db 144,228,246,28,213,120,162,249,193,234,59,85,230,136,178,128
db 61,71,231,84,76,34,90,178,93,145,112,62,102,227,62,221
db 235,162,130,47,42,32,8,231,25,62,245,133,167,38,235,176
db 184,220,171,201,250,15,241,226,186,127,34,73,44,102,153,113
db 242,13,199,63,211,243,252,200,245,172,229,189,142,186,118,74
db 236,203,119,13,112,169,159,146,46,88,255,0,121,191,207,243
db 169,162,38,40,201,39,145,237,201,99,85,3,108,35,158,123
db 230,172,5,62,100,107,147,185,243,128,123,10,69,245,41,180
db 187,159,4,241,205,108,105,26,141,238,141,124,183,246,142,85
db 213,176,192,159,149,215,251,166,178,37,132,164,172,79,28,156
db 231,181,110,104,207,106,102,107,123,212,15,4,192,33,61,212
db 147,195,15,113,85,115,36,174,157,207,99,208,117,251,77,126
db 196,92,91,54,29,120,146,34,126,100,63,225,239,90,185,175
db 16,133,181,15,7,120,133,36,7,59,121,4,31,150,104,207
db 81,254,122,17,93,239,252,44,157,27,254,121,92,255,0,223
db 53,173,251,156,146,162,247,142,168,235,37,103,218,125,123,96
db 243,94,103,227,253,71,247,240,233,112,182,84,126,242,124,30
db 167,176,252,171,166,214,175,245,104,52,249,110,228,146,27,24
db 149,114,0,30,100,135,216,116,0,254,117,230,118,182,247,90
db 222,168,83,115,22,145,140,146,200,121,216,189,206,126,159,210
db 134,250,23,70,154,94,251,102,100,202,80,29,223,123,169,53
db 92,29,231,39,166,6,64,255,0,62,245,167,171,152,154,105
db 22,219,119,146,184,8,88,242,70,56,205,80,138,54,88,36
db 96,59,3,159,202,165,61,14,150,181,51,174,45,194,19,146
db 1,207,1,71,235,84,204,44,9,81,159,80,51,91,18,166
db 230,98,70,65,32,147,248,226,171,52,103,112,221,201,29,255
db 0,157,59,153,202,6,123,143,49,114,50,28,87,87,240,255
db 0,89,91,93,80,233,151,13,136,231,36,197,147,209,189,63
db 31,231,92,228,209,227,116,138,51,253,225,142,254,191,141,83
db 126,25,38,136,149,101,96,70,15,42,123,84,202,42,74,196
db 171,198,87,71,208,224,124,185,21,34,116,199,53,206,248,67
db 196,81,235,250,74,187,16,46,162,194,78,190,254,191,67,254
db 53,209,1,183,53,196,227,103,99,174,50,186,30,78,41,60
db 204,30,78,62,180,28,17,92,127,140,52,175,16,92,192,210
db 233,58,147,91,170,175,220,80,50,205,232,79,97,244,161,43
db 187,20,181,58,199,189,130,51,243,72,51,232,57,53,92,234
db 22,178,54,4,207,159,76,87,35,166,233,215,118,246,112,79
db 121,169,92,21,100,86,104,201,82,73,35,158,113,158,190,245
db 112,205,12,106,88,219,147,142,128,117,247,207,235,90,123,52
db 118,83,195,169,43,150,47,181,235,33,35,66,21,50,63,138
db 70,2,178,100,213,244,219,134,17,164,145,22,238,81,179,138
db 134,247,202,186,182,118,242,17,17,143,78,188,119,174,23,84
db 240,253,169,144,203,2,249,100,12,176,95,187,245,3,181,10
db 148,100,85,106,78,156,111,5,127,153,232,246,82,147,46,209
db 200,198,69,95,184,151,247,96,103,154,231,126,31,105,146,89
db 233,82,220,221,220,188,129,206,35,137,142,66,125,51,211,255
db 0,175,91,55,46,60,231,97,210,185,170,67,149,216,231,140
db 185,181,181,140,235,179,128,125,107,18,238,64,170,196,156,1
db 201,53,167,119,38,73,193,226,185,63,17,222,24,172,154,36
db 206,249,142,193,143,78,245,165,24,221,138,172,185,98,217,202
db 94,206,215,183,242,76,57,220,126,81,232,59,85,139,123,124
db 32,3,150,110,158,195,214,164,179,177,221,186,70,0,162,156
db 14,126,241,29,190,131,215,214,180,226,181,96,205,253,227,247
db 220,12,99,219,235,252,171,188,242,99,7,39,118,84,72,179
db 32,85,228,40,199,227,86,36,34,20,46,121,254,234,250,154
db 176,145,172,71,106,142,156,98,152,35,243,110,213,216,140,47
db 127,240,160,218,214,208,191,165,192,45,97,50,202,115,35,156
db 224,126,130,181,37,185,54,214,146,3,32,242,228,193,110,224
db 17,207,233,254,122,214,77,168,107,201,128,82,66,33,224,250
db 122,147,234,127,250,213,166,230,38,216,159,102,150,229,163,97
db 133,12,161,112,49,193,201,25,172,222,230,203,72,153,232,162
db 73,218,69,12,99,7,228,45,198,239,122,138,73,100,89,25
db 152,101,226,109,235,238,157,199,249,244,173,255,0,17,234,150
db 183,87,54,141,5,139,218,72,19,100,177,52,97,64,28,109
db 60,113,142,181,150,240,153,35,14,156,201,25,200,30,163,184
db 166,244,100,197,243,71,204,185,48,91,155,52,145,28,111,43
db 128,192,117,244,253,42,178,196,112,50,8,4,112,125,106,43
db 41,35,138,38,137,193,242,137,249,15,117,30,159,135,79,198
db 186,61,62,206,59,205,62,107,119,96,76,103,204,136,175,12
db 125,69,77,173,161,73,233,204,88,180,212,32,215,116,63,236
db 219,150,11,125,7,48,74,122,156,118,207,244,172,63,42,247
db 254,121,31,206,157,54,149,121,107,33,184,140,49,69,193,44
db 70,210,167,177,52,255,0,237,27,175,239,183,253,246,41,185
db 119,8,194,215,229,103,83,227,173,91,205,157,109,11,125,195
db 185,148,31,81,208,255,0,58,205,121,162,209,60,56,45,209
db 182,234,55,188,200,71,84,78,195,219,138,195,212,181,6,212
db 117,151,184,41,203,201,187,110,63,157,61,45,110,239,238,205
db 196,138,193,79,241,21,39,242,3,218,173,187,17,24,43,37
db 216,167,36,110,252,47,222,200,198,122,87,75,162,232,137,127
db 230,150,202,91,91,199,230,200,202,57,39,63,40,252,129,63
db 133,85,213,45,35,180,138,222,2,202,17,23,123,190,121,201
db 237,249,98,186,141,62,72,180,239,135,151,119,201,214,225,79
db 4,227,36,157,131,39,233,205,17,212,85,103,104,221,117,60
db 228,237,46,192,1,130,91,3,175,30,149,69,199,206,84,31
db 113,86,96,112,102,98,48,114,133,191,253,85,65,73,149,122
db 252,232,120,219,85,97,182,172,56,140,43,18,62,239,113,221
db 106,156,136,153,36,12,169,173,12,140,44,157,8,63,55,210
db 171,78,168,83,120,116,42,127,58,1,171,134,135,172,207,225
db 237,94,59,200,242,241,253,217,163,254,250,247,31,94,226,189
db 210,194,250,13,66,202,43,155,121,3,197,42,134,70,245,21
db 243,244,209,44,156,169,207,184,174,143,193,94,41,147,68,191
db 91,27,146,90,198,225,192,255,0,174,78,120,221,244,61,199
db 227,88,213,133,245,66,132,185,93,153,236,249,166,203,243,70
db 192,158,8,197,53,28,48,200,57,167,17,184,115,92,203,67
db 161,24,87,154,89,185,255,0,87,43,47,63,116,12,231,222
db 185,253,101,117,24,34,104,225,180,121,72,233,177,135,63,153
db 174,206,88,222,54,14,135,142,188,117,21,90,226,101,148,151
db 144,230,70,234,113,214,182,140,147,59,169,214,147,86,56,77
db 62,223,93,186,176,100,186,211,252,166,13,149,6,80,120,207
db 233,73,46,133,42,18,183,147,0,199,164,81,244,252,79,122
db 237,238,239,163,142,37,100,92,28,103,229,21,205,92,172,183
db 119,6,87,36,103,128,61,5,18,154,137,113,111,151,81,250
db 123,44,80,109,143,34,21,225,1,254,116,235,137,179,211,173
db 34,175,151,24,81,210,171,200,107,145,187,187,152,117,42,93
db 48,84,44,107,140,154,25,181,125,70,70,95,150,40,198,213
db 98,112,7,169,255,0,62,149,212,234,69,154,38,227,140,113
db 158,245,91,76,181,218,130,70,194,70,188,142,220,255,0,159
db 199,166,58,19,93,52,108,149,206,122,241,114,180,72,147,79
db 138,52,10,24,170,70,2,151,97,140,123,1,235,252,170,27
db 166,17,237,140,13,190,145,175,222,250,159,238,255,0,58,191
db 121,112,197,118,64,191,55,68,227,27,7,176,245,247,174,99
db 80,185,22,160,196,175,251,214,224,182,58,127,245,255,0,207
db 211,104,221,152,78,208,136,143,57,105,200,140,128,145,156,5
db 94,230,172,45,179,205,36,97,164,217,134,204,157,250,114,5
db 99,195,39,10,160,13,164,224,12,156,154,232,4,134,37,73
db 89,70,78,57,39,167,189,91,49,133,165,185,126,218,226,222
db 222,104,244,200,56,153,193,201,235,176,99,249,245,250,125,106
db 89,45,103,209,102,85,157,50,175,251,200,249,201,198,127,253
db 117,203,35,79,5,255,0,218,35,221,185,92,184,117,229,135
db 248,214,252,86,237,121,20,87,210,222,125,173,166,24,82,9
db 37,123,96,143,95,106,158,84,138,85,28,157,141,195,160,207
db 125,225,171,173,102,109,194,69,33,227,79,68,7,159,208,214
db 13,189,203,70,200,196,224,73,199,227,93,117,166,181,119,167
db 248,90,231,79,186,129,101,133,226,43,111,46,71,200,88,29
db 161,193,234,56,56,62,216,231,183,19,32,193,8,220,108,233
db 245,4,126,149,78,205,19,23,37,38,203,119,3,2,77,170
db 67,55,85,245,247,21,111,195,23,62,109,236,74,215,13,110
db 203,206,119,116,231,252,241,91,30,48,151,79,181,208,52,232
db 55,34,234,81,40,44,80,243,26,129,206,113,254,208,224,125
db 107,149,211,27,207,185,2,8,247,179,40,228,227,169,246,29
db 58,208,227,161,81,157,229,166,135,167,104,119,59,46,47,45
db 76,81,222,32,33,100,1,176,79,208,30,13,104,127,100,104
db 127,244,7,151,254,249,255,0,235,215,23,164,105,26,205,205
db 196,230,209,163,133,213,182,49,98,127,76,86,191,252,35,30
db 41,255,0,160,132,31,248,247,248,86,144,186,91,25,212,81
db 230,248,142,123,195,186,92,58,166,170,230,226,127,38,24,198
db 73,234,204,115,247,69,118,218,178,65,109,29,149,165,164,31
db 101,139,126,196,105,14,55,31,167,95,206,184,45,4,234,23
db 90,142,203,73,138,204,20,240,14,56,239,93,14,181,164,235
db 177,71,3,222,73,12,216,112,171,180,158,9,245,205,68,175
db 109,139,247,92,183,57,127,17,220,58,234,77,0,152,206,204
db 195,144,120,231,53,107,87,215,252,239,10,233,186,50,59,43
db 51,188,147,55,160,220,112,63,90,196,213,157,172,238,164,243
db 151,202,145,71,222,94,196,28,116,171,62,25,211,224,213,245
db 187,72,39,96,240,151,10,113,220,14,79,225,128,106,162,180
db 38,163,239,208,108,13,9,85,218,14,225,3,151,39,166,122
db 241,244,21,153,19,42,220,111,232,92,255,0,159,214,187,111
db 25,203,3,120,128,90,219,64,32,130,43,57,0,10,129,70
db 88,19,199,224,5,121,196,215,44,94,39,96,87,159,186,15
db 79,243,138,58,139,155,221,76,210,19,178,182,88,130,184,193
db 7,189,61,89,65,233,185,79,181,100,94,78,86,253,147,0
db 128,189,9,239,215,249,213,157,58,118,150,243,202,10,74,28
db 147,237,198,105,61,138,132,245,229,37,157,12,114,96,100,169
db 233,85,30,221,158,88,130,156,22,112,188,125,107,82,72,75
db 41,192,62,171,197,88,211,180,169,103,97,59,2,18,51,145
db 158,230,161,201,37,118,108,233,57,59,35,214,116,169,140,214
db 81,54,126,109,160,159,122,211,141,193,224,240,222,149,137,164
db 159,46,24,192,28,17,197,109,4,12,1,239,235,92,9,155
db 201,89,147,12,26,173,61,132,50,243,130,27,212,28,83,153
db 218,50,55,2,71,168,20,125,165,8,225,133,59,161,38,214
db 168,202,159,73,207,59,216,253,77,82,150,200,66,61,235,118
db 75,149,3,173,100,222,76,28,156,28,253,42,37,99,104,202
db 76,200,155,11,159,74,129,45,204,135,115,12,175,101,245,250
db 213,198,133,156,242,56,244,166,203,27,44,123,70,84,30,56
db 172,156,187,27,37,99,7,83,147,107,54,208,9,7,169,232
db 42,152,152,32,93,228,201,35,16,21,79,115,254,127,42,181
db 170,176,141,138,140,103,35,165,99,195,46,200,218,242,65,243
db 0,66,131,219,177,255,0,62,245,217,73,123,166,53,94,165
db 173,74,116,180,181,104,163,109,215,14,185,119,7,145,236,43
db 137,158,67,56,103,110,74,158,84,118,250,214,193,189,50,202
db 38,147,130,199,7,218,177,238,34,251,53,211,12,124,185,200
db 247,21,213,5,99,205,174,249,189,8,236,230,217,112,25,198
db 112,58,85,251,123,188,77,38,236,152,228,57,25,61,255,0
db 200,172,233,45,240,60,232,249,78,252,112,41,145,179,7,4
db 243,143,90,179,157,73,199,67,126,84,123,103,18,47,205,30
db 114,140,6,120,162,199,89,26,62,164,151,112,4,150,50,75
db 60,13,198,27,212,86,106,223,204,173,129,32,10,121,42,221
db 51,82,53,228,50,12,50,109,62,195,138,70,156,201,236,122
db 111,134,181,189,63,83,130,45,83,86,190,181,50,89,17,29
db 190,152,64,194,71,209,216,231,239,185,28,140,113,192,29,235
db 157,213,238,52,249,181,139,164,211,202,189,161,148,249,78,128
db 133,199,208,224,215,37,25,145,230,67,10,174,224,192,228,183
db 248,214,195,143,34,121,37,83,140,147,242,158,132,147,154,36
db 238,58,122,106,89,241,45,161,211,180,216,210,120,37,91,203
db 137,88,203,35,182,85,215,0,174,211,249,231,240,173,31,5
db 233,198,230,219,237,7,118,216,216,116,28,177,192,0,126,117
db 207,234,183,113,93,197,110,141,43,31,41,122,117,0,255,0
db 147,94,131,225,13,115,195,218,70,129,20,179,234,22,171,42
db 177,34,18,75,54,239,83,142,149,81,183,82,101,38,155,104
db 244,29,23,77,143,66,210,212,76,67,76,114,204,125,88,246
db 168,255,0,182,164,255,0,159,155,111,251,236,87,153,120,147
db 226,108,154,130,155,61,45,24,171,146,12,236,48,196,30,48
db 160,116,250,245,250,87,47,253,157,174,127,208,58,235,254,253
db 31,240,173,57,210,49,228,114,213,179,78,206,250,125,11,89
db 142,227,203,34,75,119,33,227,60,18,58,16,127,90,246,176
db 182,222,36,208,68,123,212,249,145,130,29,78,126,134,176,252
db 105,224,116,214,131,94,233,165,34,191,234,234,120,89,127,192
db 255,0,58,243,189,55,196,218,223,129,238,205,141,253,172,130
db 223,60,198,195,105,95,116,110,159,135,67,75,161,82,124,222
db 242,220,147,226,6,144,109,45,196,251,78,93,202,56,63,194
db 192,114,62,157,235,83,225,37,172,50,75,45,201,0,203,20
db 111,130,123,116,95,229,154,131,197,62,56,208,117,253,2,69
db 18,72,46,216,175,238,222,28,3,239,144,120,53,141,224,175
db 25,90,248,113,174,148,196,29,103,80,185,44,70,49,207,96
db 125,106,118,27,188,151,153,163,48,155,196,94,42,190,184,141
db 182,165,164,14,236,58,130,7,203,253,127,74,225,47,34,104
db 175,222,28,146,16,244,7,185,233,252,235,210,60,47,115,21
db 149,174,163,114,97,195,94,169,88,218,88,200,28,231,191,227
db 222,153,109,225,104,166,2,241,130,22,144,110,59,142,121,172
db 103,90,49,103,84,104,74,74,219,28,20,26,21,221,253,214
db 240,152,76,1,187,183,74,236,52,143,11,36,106,90,89,56
db 198,55,31,215,21,210,219,232,56,117,86,153,118,227,162,173
db 110,91,233,176,67,130,70,242,7,25,174,121,214,148,182,58
db 97,74,20,245,221,156,180,30,22,132,156,224,148,236,79,90
db 211,254,202,72,98,17,160,227,62,149,208,50,46,220,84,76
db 138,77,98,238,247,102,170,69,75,104,118,68,190,213,165,11
db 228,12,212,40,184,167,15,145,179,75,97,110,91,218,8,228
db 85,73,173,21,178,64,199,210,174,35,100,113,67,10,76,22
db 140,203,251,39,227,81,75,110,48,56,173,66,162,161,146,47
db 202,161,196,209,72,204,242,148,14,149,86,238,60,129,198,43
db 96,67,156,213,91,168,70,51,138,150,134,165,169,198,107,214
db 68,219,249,131,160,24,111,161,239,88,115,36,114,177,129,254
db 86,117,202,143,86,234,107,187,158,4,117,100,113,149,35,24
db 246,174,67,80,180,138,11,198,181,155,62,91,42,152,228,238
db 8,232,127,90,232,163,61,44,42,138,250,156,204,240,249,14
db 82,80,48,120,207,168,246,170,242,69,28,200,98,36,28,125
db 214,207,233,91,243,41,7,200,186,81,187,179,227,229,127,240
db 53,84,105,145,156,144,48,79,28,87,98,153,197,58,78,250
db 24,118,235,37,180,165,29,72,7,142,71,4,123,251,85,153
db 52,132,152,135,136,108,99,201,67,208,253,13,108,38,140,100
db 143,110,119,122,3,82,195,163,94,192,164,34,9,23,209,142
db 40,117,35,220,149,134,125,81,132,52,113,147,184,184,199,81
db 180,241,67,233,1,88,24,148,177,238,89,72,31,173,117,35
db 79,189,100,7,236,210,43,103,175,14,71,208,130,13,72,154
db 101,196,174,63,208,174,88,250,148,198,106,93,100,90,194,163
db 159,179,211,213,24,49,59,187,124,188,254,191,208,83,53,155
db 105,99,133,165,98,34,115,141,161,219,146,61,0,255,0,57
db 175,64,211,116,25,209,214,73,109,144,50,140,40,99,194,254
db 29,205,113,62,49,138,39,214,6,203,177,51,130,21,227,64
db 65,31,78,221,169,82,159,60,236,21,169,198,20,221,142,126
db 211,76,146,242,88,33,93,197,229,96,51,216,15,90,244,75
db 31,8,105,118,80,226,91,117,154,78,236,228,241,88,190,13
db 178,142,243,196,1,183,46,200,87,119,3,150,35,144,15,249
db 237,94,128,241,227,57,21,56,170,142,50,229,136,176,180,163
db 203,204,214,165,61,58,24,116,167,221,101,107,111,11,255,0
db 124,66,165,191,50,51,91,31,240,144,234,159,243,248,127,33
db 254,21,69,97,205,63,236,230,185,125,164,187,157,110,149,55
db 209,27,87,62,36,190,108,132,49,167,251,171,254,53,145,123
db 171,234,23,214,237,111,43,195,36,44,48,82,72,81,129,252
db 8,164,100,227,158,181,31,150,65,60,86,190,222,125,204,214
db 30,154,232,114,62,38,211,224,147,72,112,186,109,140,82,69
db 150,19,67,14,199,60,116,56,56,63,149,113,54,127,232,205
db 12,232,133,155,35,0,113,154,245,125,78,1,37,156,168,71
db 37,122,87,149,136,219,236,210,43,41,86,7,24,219,223,252
db 254,85,217,134,159,58,119,57,49,52,213,54,165,29,15,104
db 210,138,220,105,81,59,162,237,43,180,12,118,28,84,139,12
db 40,223,187,249,65,236,15,21,83,194,57,159,195,240,153,38
db 89,37,42,9,32,231,182,51,250,86,133,205,187,117,2,184
db 106,43,73,163,182,46,236,150,2,23,131,142,42,215,153,145
db 218,176,13,196,144,185,220,14,42,196,119,153,94,181,23,41
db 192,212,50,98,141,253,235,63,237,57,61,105,222,126,234,46
db 62,83,73,79,31,90,112,228,16,106,140,119,4,112,79,21
db 97,101,201,205,23,23,43,45,66,219,78,15,74,176,195,34
db 169,7,7,158,245,113,24,50,1,77,18,198,99,29,168,42
db 15,106,27,33,168,237,214,129,13,96,22,168,207,202,156,117
db 171,206,42,188,137,214,166,72,168,152,178,198,67,100,214,70
db 171,167,45,228,67,160,145,57,66,71,31,67,237,93,44,144
db 230,160,54,123,143,61,234,21,211,186,54,186,234,121,228,246
db 238,128,195,44,101,72,232,174,115,249,30,226,172,233,214,13
db 42,246,227,215,130,43,182,151,72,130,225,54,200,160,138,170
db 190,28,130,38,221,20,146,169,250,241,91,251,86,213,136,180
db 111,115,58,223,79,116,110,35,46,125,136,171,177,219,252,219
db 4,71,119,113,145,197,95,93,41,152,0,110,38,0,117,10
db 113,154,179,6,151,28,17,132,86,108,125,107,39,118,62,116
db 138,240,219,168,35,130,43,78,4,85,28,40,197,49,96,84
db 192,192,226,157,156,30,41,173,12,164,238,79,47,150,177,151
db 108,40,0,156,158,213,225,122,236,48,31,18,221,125,150,85
db 158,54,144,158,1,4,30,132,15,83,250,87,178,95,74,77
db 164,131,204,242,254,94,28,156,109,35,189,120,114,163,36,247
db 64,178,72,99,83,202,54,120,245,7,61,43,187,11,171,108
db 227,196,233,20,142,235,225,238,158,162,59,221,69,219,115,31
db 149,114,121,32,247,63,151,235,93,75,159,152,140,86,63,130
db 236,158,203,195,101,228,251,210,176,200,206,122,127,250,235,105
db 99,103,124,246,174,108,68,175,81,157,116,99,203,20,133,69
db 29,77,73,197,61,97,197,59,202,62,149,129,165,198,58,15
db 74,174,195,7,145,87,164,92,118,170,114,140,102,168,22,165
db 91,180,89,97,101,245,21,229,15,110,240,222,92,199,33,4
db 239,109,164,146