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

Assembler, MASM, TASM

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 5.00
Mikl___
Заблокирован
Автор FAQ
10.01.2013, 08:14  [ТС] #31
Win32 API. Урок 8k. Инструментальная панель

Скачайте пример.
Кликните здесь для просмотра всего текста
Практика
Для создания инструментальной панели необходимо подготовить файл с растровым изображением рисунка на кнопках (в формате BMP). Но это нужно в том случае если вы хотите разместить в toolbar'е оригинальные рисунки. Если речь идет о стандартных иконках "вырезать", "вставить", "скопировать", "сохранить" и т.п. ― тогда стоит заглянуть в файл "windows.inc"
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
STD_CUT          equ 0
STD_COPY         equ 1
STD_PASTE        equ 2
STD_UNDO         equ 3
STD_REDOW        equ 4
STD_DELETE       equ 5
STD_FILENEW      equ 6
STD_FILEOPEN     equ 7
STD_FILESAVE     equ 8
STD_PRINTPRE     equ 9
STD_PROPERTIES   equ 10
STD_HELP         equ 11
STD_FIND         equ 12
STD_REPLACE      equ 13
STD_PRINT        equ 14
Это идентификаторы "стандартных иконок", которые при обработке сообщения WM_CREATE мы можем использовать для создания инструментальной панели. Это позволяет нам отказаться от рисунка стандартных кнопок и использования функции LoadImage. Ниже пример создания кнопки "вырезать"
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
    lea edi,tbb
    assume edi: ptr TBBUTTON
    mov [edi].fsStyle,TBSTYLE_BUTTON
    mov [edi].idCommand,ID_CUT
    mov [edi].iBitmap,STD_CUT
    assume edi: nothing
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar
    call 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
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
.586
.model tiny,stdcall
;for WinXP - 1939 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
include windows.inc
exebase equ 400000h
ID_MENU equ 600
ID_EXIT equ 15
ID_ABOUT equ 16
.code
main:
include capito_res.asm
;------------------------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,ebx,\
    ebx,esi,ebx,10011h,COLOR_BTNFACE+1,ID_MENU,edi
;--------------------------+
;  creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,\
    WS_OVERLAPPEDWINDOW or WS_VISIBLE,esi,esi,esi,esi,ebx,ebx
    mov ebp,esp
      ; +---------------------------+
      ; | entering the message loop |
      ; +---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
; +----------------------+
; | the window procedure |
; +----------------------+
window_procedure:
hwnd    equ dword ptr [ebp+8]
uMsg    equ dword ptr [ebp+0Ch]
wParam  equ dword ptr [ebp+10h]
lParam  equ dword ptr [ebp+14h]
caW equ dword ptr [ebp-4]
caH equ dword ptr [caW-4]
Rct equ RECT ptr [caH-sizeof(RECT)]
tbb equ dword ptr [Rct-sizeof(TBBUTTON)]
Tba equ dword ptr [tbb-sizeof(TBADDBITMAP)]
    enter (sizeof(RECT)+sizeof(TBBUTTON)+sizeof(TBADDBITMAP)+\
    sizeof(PAINTSTRUCT)+8),0
    lea esi,SendMessage+exebase
    mov eax,uMsg
    dec eax;cmp eax,WM_CREATE=1
    je short wmCREATE
    dec eax;cmp eax,WM_DESTROY=2
    je wmDESTROY
    sub eax,WM_SIZE-WM_DESTROY;cmp eax,WM_SIZE=5
    je wmSIZE
    sub eax,WM_PAINT-WM_SIZE;cmp eax,WM_PAINT=0Fh
    je wmPAINT
    dec eax;cmp eax,WM_CLOSE=10h
    je short wmCLOSE
    sub eax,WM_COMMAND-WM_CLOSE;cmp eax,WM_COMMAND=111h
    je wmCOMMAND
;все сообщения, не обрабатываемые в функции 
;WndProc, направляются на обработку по умолчанию
default1: leave
    jmp DefWindowProc+exebase
wmCLOSE: invoke MessageBox,hwnd,offset aPlease+exebase,\
    offset wTitle+exebase,MB_YESNO
    cmp eax,IDNO; 7
    jnz default1
end_wm_check: leave
    retn 10h
wmPAINT: invoke BeginPaint,hwnd,esp;&Paint
    push hwnd
    push eax
    CALL Paint_Proc
    invoke EndPaint,hwnd,esp      ;Освобождаем контекст отображения
    jmp end_wm_check
wmCREATE: lea edi,tbb
    push edi
    stosd;mov [edi].iBitmap,0
    stosd;mov [edi].idCommand,0
    stosd;mov [edi].fsState,0
         ;mov [edi].fsStyle,0
         ;mov [edi]._wPad1,0
    stosd;mov [edi].dwData,0
    stosd;mov [edi].iString,0
    pop edi
    assume edi: ptr TBBUTTON    
    mov word ptr [edi].fsState,TBSTATE_ENABLED + 256*TBSTYLE_SEP    ;or WS_CLIPSIBLINGS
    invoke CreateToolbarEx,hwnd,WS_CHILD  or WS_VISIBLE,\
        300,1,ebx,ebx,edi,1,10h,10h,ebx,ebx,sizeof(TBBUTTON)
    mov hToolBar+exebase,eax
 
    lea ecx,Tba
    assume ecx: ptr TBADDBITMAP
    or [ecx].hInst,HINST_COMMCTRL; 0FFFFFFFFh
    push 1; btnsize 1=big 2=small
    pop [ecx].nID 
    assume ecx: nothing
    push ecx
    push 1
    push TB_ADDBITMAP
    push eax;hToolBar
    call dword ptr [esi]
 
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    or [edi].idCommand,-1
    or ebx,3
@@: mov eax,[handler1+ebx*4+exebase+44]
    mov [edi].iBitmap,eax
    inc [edi].idCommand
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    dec ebx
    jnz @b
 
    mov [edi].idCommand,ebx 
    or [edi].fsStyle,TBSTYLE_SEP; 1
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
 
    or [edi].idCommand,2
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    or ebx,6
@@: mov eax,[handler1+ebx*4+exebase+20]
    mov [edi].iBitmap,eax
    inc [edi].idCommand
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    dec ebx
    jnz @b
 
    mov [edi].iBitmap,ebx
    mov [edi].idCommand,ebx
    or [edi].fsStyle,TBSTYLE_SEP
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
 
    or [edi].idCommand,8
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    or ebx,2
@@: mov eax,[handler1+ebx*4+exebase+12]
    mov [edi].iBitmap,eax
    inc [edi].idCommand;10
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    dec ebx
    jnz @b
 
    mov [edi].iBitmap,ebx; 0
    mov [edi].idCommand,ebx; 0
    or [edi].fsStyle,TBSTYLE_SEP;=1
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
 
    or [edi].idCommand,10;1
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    or ebx,4
@@: mov eax,[handler1+ebx*4+exebase-4]
    mov [edi].iBitmap,eax
    inc [edi].idCommand;13
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    dec ebx
    jnz @b
    assume edi:nothing
; Create the status bar
    invoke CreateStatusWindow,WS_CHILD or WS_VISIBLE or SBS_SIZEGRIP,\
    ebx,hwnd,200
    mov hStatus+exebase,eax
    jmp default1
wmSIZE: push ebx
    push ebx
    push TB_AUTOSIZE
    push hToolBar+exebase
    call dword ptr [esi]
    push dword ptr [caW]
    pop dword ptr [lParam+0]
    push dword ptr [caH]
    pop dword ptr [lParam+2]
    lea edi,[Rct]
    invoke GetWindowRect,hStatus+exebase,edi
    mov eax,[edi+RECT.bottom]
    sub eax,[edi+RECT.top]
    sub caH,eax
    invoke MoveWindow,hStatus+exebase,ebx,caH,caW,caH,TRUE
    jmp default1 
wmCOMMAND: mov edi,wParam
    cmp edi,14
    ja short a1
    push [handler+edi*4+exebase]
    push ebx
    push SB_SETTEXT
    push hStatus+exebase        ; hWnd
    call dword ptr [esi];  SendMessageA
    invoke MessageBox,hwnd,[handler+edi*4+exebase],offset aYou+exebase,ebx
    jmp default1
a1: cmp edi,15
    jnz a2
    push ebx
    push SC_CLOSE
    push WM_SYSCOMMAND
    push hwnd
    call dword ptr [esi];  SendMessageA
    jmp default1
a2: invoke MessageBox,hwnd,offset aAssembler+exebase,offset wTitle+exebase,ebx
    jmp default1
wmDESTROY: invoke ExitProcess,ebx;завершение программы
;=================================================
Paint_Proc:
hWin equ dword ptr [esp + sizeof(RECT)+14h];ebp+8
hDC  equ dword ptr [esp + sizeof(RECT)+18h];ebp+0Ch
caW  equ dword ptr [esp + sizeof(RECT)+8];ebp-4
caH  equ dword ptr [caW - 4]
tbH  equ dword ptr [caH - 4]
sbH  equ dword ptr [tbH - 4]
    sub esp,sizeof(RECT)+10h;место под структуру RECT и переменные caW,caH,tbH,sbH
    mov edi,esp;&Rct
    lea esi,GetWindowRect+exebase
    invoke GetClientRect,hWin,edi
    assume edi: ptr RECT
    push [edi].right
    pop caW
    push [edi].bottom
    pop caH
    push edi
    push hToolBar+exebase     ; hWnd
    call dword ptr [esi];[GetWindowRect]
    mov eax,[edi].bottom
    sub eax,[edi].top
    mov [tbH], eax
    push edi
    push hStatus+exebase        ; hWnd
    call dword ptr [esi];[GetWindowRect]
    mov eax,[edi].bottom
    sub eax,[edi].top
    mov sbH,eax
    sub caH,eax
    mov [edi].left,ebx;0
    push tbH
    pop [edi].top
    push caW
    pop [edi].right
    push caH
    pop [edi].bottom
    assume edi: nothing
    invoke DrawEdge,hDC,edi,EDGE_SUNKEN,BF_RECT
    add esp,sizeof(RECT)+10h;освобождаем буфер;leave
    retn 8
;=================================================================
aPlease db "Please Confirm Exit",0
aNewFile db 'New File',0     
aOpenFile db 'Open File',0  
aSaveFile db 'Save File',0
aRedow   db 'Redow',0
aDelete  db 'Delete',0
aCut     db 'Cut',0
aCopy    db 'Copy',0        
aPaste   db 'Paste',0        
aUndo    db 'Undo',0         
aSearch  db 'Search',0       
aReplace db 'Replace',0
aPrint   db 'Print',0
aPreview db 'Previw',0
aProperties db 'Properties',0
aHelp    db 'Help',0
aAssembler db "Assembler, Pure & Simple",0
aYou db "You have selected",0
handler dd aNewFile+exebase,aOpenFile+exebase,aSaveFile+exebase,aRedow+exebase
    dd aDelete+exebase,aCut+exebase,aCopy+exebase,aPaste+exebase,aUndo+exebase
    dd aSearch+exebase,aReplace+exebase,aPrint+exebase,aPreview+exebase
    dd aProperties+exebase,aHelp+exebase
handler1 dd STD_HELP,STD_PROPERTIES,STD_PRINTPRE,STD_PRINT,STD_REPLACE,STD_FIND
dd STD_UNDO,STD_PASTE,STD_COPY,STD_CUT,STD_DELETE,STD_REDOW,STD_FILESAVE
dd STD_FILEOPEN,STD_FILENEW
wTitle db 'Iczelion Tutorial #8-11:инструментальная панель в MASM',0
;-------------------------------------------------------------------------------------------
MFR_END     equ 80h
MFR_POPUP   equ 1
MFT_STRING  equ 0
MFS_ENABLED equ 0
MFT_SEPARATOR   equ 800h
RT_MENU     equ 4
 
POPUP       equ 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
align 4
resource:
;struct _IMAGE_RESOURCE_DIRECTORY
dd 0,0,0
NumberOfNamedEntries0   dw 0;количество ресурсов с именами
NumberOfIdEntries0  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0;номер типа ресурса
dw x-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление второго уровня. В 1-ом слове смещение второго оглавления 
;относительно начала раздела ресурсов
x:
dd 0,0,0
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw ID_MENU,0
dw x1-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
x1:
dd 0,0,0
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 16 * SUBLANG_ + LANG_
dw 40Ah,0,x2-resource,0
x2:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData    dd menu,end_menu-menu,0,0
menu dw 0,0,POPUP
du <&File>
dw MFR_END,ID_EXIT
du <&Exit>
dw MFT_STRING or MFS_ENABLED or MFR_END,ID_ABOUT
du <&About>
end_menu:
end_resource:
;---------------------------------------------------------------------
import:
hStatus       dd 0
hToolBar      dd 0
dd 0,user32_dll
dd user32_table; RVA to 1st thunk
dd 0,0,0,kernel32_dll
dd kernel32_table; RVA to 2nd thunk
dd 0,0,0,comctl32_dll
dd comctl32_table; RVA to 2nd thunk
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
SendMessage             dd _SendMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
MoveWindow      dd _MoveWindow
BeginPaint      dd _BeginPaint
EndPaint            dd _EndPaint
GetWindowRect           dd _GetWindowRect
GetClientRect           dd _GetClientRect
DrawEdge            dd _DrawEdge
MessageBox      dd _MessageBox,0
comctl32_table:
CreateToolbarEx     dd _CreateToolbarEx
CreateStatusWindow  dd _CreateStatusWindow
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_SendMessage        db 0,0,'SendMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_MoveWindow     db 0,0,"MoveWindow"
_BeginPaint     db 0,0,'BeginPaint'
_EndPaint       db 0,0,'EndPaint'
_GetWindowRect      db 0,0,'GetWindowRect'
_GetClientRect      db 0,0,'GetClientRect'
_DrawEdge       db 0,0,'DrawEdge'
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_CreateToolbarEx    db 0,0,'CreateToolbarEx'
_CreateStatusWindow db 0,0,'CreateStatusWindowA',0
comctl32_dll        db 'comctl32'
end_import:
end main
__________________________________________
© Mikl___ 2013
4
Миниатюры
Сам себе Iczelion  
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.01.2013, 08:14
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Сам себе Iczelion (Assembler):

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

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

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

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

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

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

116
Mikl___
Заблокирован
Автор FAQ
10.01.2013, 09:51  [ТС] #32
Win32 API. Урок 8l. Подключаем стандартные диалоги к инструментальной панели
Скачайте пример.
Практика ― сестра шизофрении
Подключаем к инструментальной панели диалоги «Открыть файл», «Сохранить как...», «Выбор параметров страницы», «Печать».
Кликните здесь для просмотра всего текста
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
.586
.model tiny,stdcall
;for WinXP - 2801 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
include windows.inc
exebase equ 400000h
ID_MENU equ 600
ID_EXIT equ 10
ID_ABOUT equ 11
.code
main:
include capito_res.asm
;------------------------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,ebx,\
    ebx,esi,ebx,10011h,COLOR_BTNFACE+1,ID_MENU,edi
;--------------------------+
;  creating the main window |
;--------------------------+
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,ebx,edi,edi,\
    WS_OVERLAPPEDWINDOW or WS_VISIBLE,esi,esi,500,300,ebx,ebx
    mov ebp,esp
      ; +---------------------------+
      ; | entering the message loop |
      ; +---------------------------+
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
    invoke DispatchMessage,ebp
    jmp message_loop
; +----------------------+
; | the window procedure |
; +----------------------+
window_procedure:
hwnd    equ dword ptr [ebp+8]
uMsg    equ dword ptr [ebp+0Ch]
wParam  equ dword ptr [ebp+10h]
lParam  equ dword ptr [ebp+14h]
caW equ dword ptr [ebp-4]
caH equ dword ptr [caW-4]
Rct equ RECT ptr [caH-sizeof(RECT)]
tbb equ dword ptr [Rct-sizeof(TBBUTTON)]
Tba equ dword ptr [tbb-sizeof(TBADDBITMAP)]
ofn equ OPENFILENAME ptr [Tba-sizeof(OPENFILENAME)]
buffer  equ byte ptr [ofn-256]
psd equ PAGESETUPDLG ptr [buffer-sizeof(PAGESETUPDLG)]
pd  equ PRINTDLG ptr [psd-sizeof(PRINTDLG)-2]
    enter (sizeof(RECT)+sizeof(TBBUTTON)+sizeof(TBADDBITMAP)+\
    sizeof(PAINTSTRUCT)+8+sizeof(OPENFILENAME)+256+\
    sizeof(PAGESETUPDLG)+sizeof(PRINTDLG)+2),0
    lea esi,SendMessage+exebase
    mov eax,uMsg
    dec eax;cmp eax,WM_CREATE=1
    je short wmCREATE
    dec eax;cmp eax,WM_DESTROY=2
    je wmDESTROY
    sub eax,WM_SIZE-WM_DESTROY;cmp eax,WM_SIZE=5
    je wmSIZE
    sub eax,WM_PAINT-WM_SIZE;cmp eax,WM_PAINT=0Fh
    je wmPAINT
    dec eax;cmp eax,WM_CLOSE=10h
    je short wmCLOSE
    sub eax,WM_COMMAND-WM_CLOSE;cmp eax,WM_COMMAND=111h
    je wmCOMMAND
;все сообщения, не обрабатываемые в функции 
;WndProc, направляются на обработку по умолчанию
default1: leave
    jmp DefWindowProc+exebase
wmCLOSE: invoke MessageBox,hwnd,offset aPlease+exebase,\
    offset wTitle+exebase,MB_YESNO
    cmp eax,IDNO; 7
    jnz default1
end_wm_check: leave
    retn 10h
wmPAINT: invoke BeginPaint,hwnd,esp;&Paint
    push hwnd
    push eax
    CALL Paint_Proc
    invoke EndPaint,hwnd,esp      ;Освобождаем контекст отображения
    jmp end_wm_check
wmCREATE: lea edi,tbb
    push edi
    stosd;  mov [edi].iBitmap,0
    stosd;  mov [edi].idCommand,0
    stosd;  mov [edi].fsState,0
         ;  mov [edi].fsStyle,0
    stosd;  mov [edi].dwData,0
    stosd;  mov [edi].iString,0
    pop edi
    assume edi: ptr TBBUTTON
;   mov [edi].fsState,TBSTATE_ENABLED
;   mov [edi].fsStyle,TBSTYLE_SEP
        mov word ptr [edi].fsState,TBSTATE_ENABLED + 256*TBSTYLE_SEP
    invoke CreateToolbarEx,hwnd,WS_CHILD or WS_CLIPSIBLINGS or WS_VISIBLE,\
        300,1,ebx,ebx,edi,1,10h,10h,ebx,ebx,sizeof(TBBUTTON)
    mov hToolBar+exebase,eax
 
    lea ecx,Tba
    assume ecx: ptr TBADDBITMAP
    or [ecx].hInst,HINST_COMMCTRL; 0FFFFFFFFh
    push 1; btnsize 1=big 2=small
    pop [ecx].nID
    assume ecx: nothing
    push ecx
    push 1
    push TB_ADDBITMAP
    push eax;hToolBar
    call dword ptr [esi]
 
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    or [edi].idCommand,-1
    or ebx,3
@@: mov eax,[handler1+ebx*4+exebase+20]
    mov [edi].iBitmap,eax
    inc [edi].idCommand
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    dec ebx
    jnz @b
 
    mov [edi].idCommand,ebx 
    or [edi].fsStyle,TBSTYLE_SEP; 1
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
 
    or [edi].idCommand,2
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    or ebx,4
@@: mov eax,[handler1+ebx*4+exebase+4]
    mov [edi].iBitmap,eax
    inc [edi].idCommand
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    dec ebx
    jnz @b
 
    mov [edi].iBitmap,ebx
    mov [edi].idCommand,ebx
    or [edi].fsStyle,TBSTYLE_SEP
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
 
    or [edi].idCommand,6
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    or ebx,2
@@: mov eax,[handler1+ebx*4+exebase-4]
    mov [edi].iBitmap,eax
    inc [edi].idCommand;10
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    dec ebx
    jnz @b
 
    mov [edi].iBitmap,ebx; 0
    mov [edi].idCommand,ebx; 0
    or [edi].fsStyle,TBSTYLE_SEP;=1
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
 
    or [edi].idCommand,9
    mov [edi].fsStyle,bl;TBSTYLE_BUTTON=0
    mov [edi].iBitmap,STD_PRINT
    push edi
    push 1
    push TB_ADDBUTTONS
    push hToolBar+exebase
    call dword ptr [esi]
    assume edi:nothing
; Create the status bar
    invoke CreateStatusWindow,WS_CHILD or WS_VISIBLE or SBS_SIZEGRIP,\
    ebx,hwnd,200
    mov hStatus+exebase,eax
    jmp default1
wmSIZE: push ebx
    push ebx
    push TB_AUTOSIZE
    push hToolBar+exebase
    call dword ptr [esi]
    push caW
    pop lParam
    push caH
    pop lParam+2
    lea edi,[Rct]
    invoke GetWindowRect,hStatus+exebase,edi
    mov eax,[edi+RECT.bottom]
    sub eax,[edi+RECT.top]
    sub caH,eax
    invoke MoveWindow,hStatus+exebase,ebx,caH,caW,caH,TRUE
    jmp default1 
wmCOMMAND: mov edi,wParam
    push [handlers+edi*4+exebase]
    push ebx
    push SB_SETTEXT
    push hStatus+exebase        ; hWnd
    call dword ptr [esi];  SendMessageA
    jmp [handler+edi*4+exebase]
OpenFile:   
SaveFile: lea edi,ofn
    mov ecx,sizeof(OPENFILENAME)/4
    xor eax,eax
    rep stosd
    lea edi,ofn
    assume edi: ptr OPENFILENAME
    mov [edi].lStructSize,sizeof(OPENFILENAME)
    push hwnd
    pop [edi].hwndOwner
    mov [edi].hInstance,exebase
    mov [edi].lpstrFilter,offset ASMFilterString+exebase
    mov [edi].lpstrFile,offset FileName+exebase
    mov FileName+exebase,bl
    mov [edi].nMaxFile,100h;FileName_size
    mov [edi].Flags,OFN_FILEMUSTEXIST or OFN_HIDEREADONLY or OFN_PATHMUSTEXIST
    push edi
    cmp wParam,2
    jnz short a1
    invoke GetSaveFileName
    jmp default1
a1: invoke GetOpenFileName
NewFile:
Cut:
Copy:
Paste:
Undo:
Search: jmp default1
Preview: push 750
    push 1000
    push 750
    push 1000
    push ebx
    lea eax,psd
    push eax
    push hwnd
    CALL PageSetupDialog
    jmp default1
Print:  ;push aPrint
    ;push ebx;0               ; wParam
    ;push SB_SETTEXT;401h            ; Msg
    ;push [hStatus]      ; hWnd
    ;call dword [esi];  SendMessageA
    push PD_SHOWHELP
    lea eax,pd
    push eax
    push hwnd      ; hWnd
    CALL PrintDialog
    jmp default1
About:  invoke ShellAbout,hwnd,offset wTitle+exebase,\
    offset aAssembler+exebase,10003h
    jmp default1
wmDESTROY: invoke ExitProcess,ebx;завершение программы
;=================================================
Paint_Proc:
hWin equ dword ptr [esp + sizeof(RECT)+14h];ebp+8
hdc  equ dword ptr [esp + sizeof(RECT)+18h];ebp+0Ch
caW  equ dword ptr [esp + sizeof(RECT)+8];ebp-4
caH  equ dword ptr [caW - 4]
tbH  equ dword ptr [caH - 4]
sbH  equ dword ptr [tbH - 4]
    sub esp,sizeof(RECT)+10h;место под структуру RECT и переменные caW,caH,tbH,sbH
    mov edi,esp;&Rct
    lea esi,GetWindowRect+exebase
    invoke GetClientRect,hWin,edi
    assume edi: ptr RECT
    push [edi].right
    pop caW
    push [edi].bottom
    pop caH
    push edi
    push hToolBar+exebase     ; hWnd
    call dword ptr [esi];GetWindowRect
    mov eax,[edi].bottom
    sub eax,[edi].top
    mov [tbH], eax
    push edi
    push hStatus+exebase        ; hWnd
    call dword ptr [esi];GetWindowRect
    mov eax,[edi].bottom
    sub eax,[edi].top
    mov sbH,eax
    sub caH,eax
    mov [edi].left,ebx;0
    push tbH
    pop [edi].top
    push caW
    pop [edi].right
    push caH
    pop [edi].bottom
    assume edi: nothing
    invoke DrawEdge,hdc,edi,EDGE_SUNKEN,BF_RECT
    add esp,sizeof(RECT)+10h;освобождаем буфер
    retn 8
;=================================================================
PrintDialog:
hWin    equ dword ptr [esp+sizeof(PRINTDLG)+2+4]
lppd    equ dword ptr [esp+sizeof(PRINTDLG)+2+8]
uflags  equ dword ptr [esp+sizeof(PRINTDLG)+2+0Ch]
  ; ------------------------------------------------------------------
  ; Parameters
  ; 1. hWin =parent handle
  ; 2. lppd =address of PRINTDLG to receive info
  ; 3. uflags=additional styes from the PRINTDLG reference material
  ;
  ; EXAMPLE: invoke PrintDialog,hWin,ADDR pd,PD_SHOWHELP
  ; ------------------------------------------------------------------
    sub esp,sizeof(PRINTDLG)+2
;размер структуры PRINTDLG равен 14*4+5*2=56+10=66 байт, а значение в esp 
;должно быть всегда кратно 4, поэтому еще плюс 2 байта
    mov edi,esp
    push (sizeof(PRINTDLG)+2)/4
    pop ecx
    push edi
    xor eax,eax
    rep stosd;обнулили структуру PRINTDLG
    pop edi
    assume edi: ptr PRINTDLG
;заполняем "ненулевые" поля
    push sizeof(PRINTDLG)
    pop [edi].lStructSize;pd.lStructSize=sizeof(PRINTDLG)
    push hWin
    pop [edi].hwndOwner;pd.hwndOwner=hWin
    mov eax,uflags
    or eax,PD_PAGENUMS    ; "or" default value with extra flags
    mov [edi].Flags,eax
    mov dword ptr [edi].nFromPage,10001h;pd.nFromPage=1 pd.nToPage=1
        mov dword ptr [edi].nMaxPage,1FFFFh;pd.nMaxPage=65535 pd.nCopies=1
    assume edi: nothing
    invoke PrintDlg,edi
    push (sizeof(PRINTDLG)+2)/4
    pop ecx;ecx=sizeof(PRINTDLG)
    mov esi,esp
    mov edi,lppd
    rep movsd
    add esp,sizeof(PRINTDLG)+2;удалили временный буфер
    retn 0Ch
;=================================================================
PageSetupDialog:
hWin    equ esp+sizeof(PAGESETUPDLG)+4;ebp+8
lppsd   equ esp+sizeof(PAGESETUPDLG)+8;ebp+0Ch
style   equ esp+sizeof(PAGESETUPDLG)+0Ch;ebp+10h
lMargin equ esp+sizeof(PAGESETUPDLG)+10h;ebp+14h
tMargin equ esp+sizeof(PAGESETUPDLG)+14h;ebp+18h
rMargin equ esp+sizeof(PAGESETUPDLG)+18h;ebp+1Ch
bMargin equ esp+sizeof(PAGESETUPDLG)+1Ch;ebp+20h
 
    ; Parameters.
    ; ~~~~~~~~~~
    ; 1. hWin   =Parent window handle.
    ; 2. lppsd  =address of PAGESETUPDLG structure for return parameters
    ; 3. style  =Default is 0, else styles from PAGESETUPDLG reference.
    ; 4. lMargin=0 defaults to 500, inch=1000 
    ; 4. tMargin=0 defaults to 500, inch=1000 
    ; 4. rMargin=0 defaults to 500, inch=1000 
    ; 4. bMargin=0 defaults to 500, inch=1000 
 
    ; EXAMPLE : invoke PageSetupDialog,hWin,ADDR psd,0,1000,750,1000,750
;psd equ ebp-sizeof(PAGESETUPDLG)
        sub esp,sizeof(PAGESETUPDLG)
        mov edi,esp;lea esi,[psd]
    push sizeof(PAGESETUPDLG)/4
    pop ecx
    xor eax,eax
    push edi
    rep stosd;обнулили структуру PAGESETUPDLG
    pop edi
    assume edi: ptr PAGESETUPDLG
    push sizeof(PAGESETUPDLG)
    pop [edi].lStructSize
    push dword ptr [hWin]
    pop [edi].hwndOwner
    mov ecx,500
        lea esi,[style]
        lodsd;mov eax,[style]
        test eax,eax
        jnz short @f
        or dword ptr [style],PSD_DEFAULTMINMARGINS or PSD_MARGINS or \
           PSD_INTHOUSANDTHSOFINCHES         ; default styles
        mov eax,[style]
@@:     mov [edi].flags,eax
    lodsd;mov eax,[lMargin]
    test eax,eax
    jnz @f
    or eax,ecx
@@: mov [edi].rtMargin.left,eax
    lodsd;mov eax, [tMargin]
    test eax,eax
    jnz @f
    or eax,ecx
@@: mov [edi].rtMargin.top,eax
    lodsd;mov eax, [rMargin]
    test eax,eax
    jnz @f
    or eax,ecx
@@: mov [edi].rtMargin.right,eax
    lodsd;mov eax, [bMargin]
    test eax,eax
    jnz @f
    or eax,ecx
@@: mov [edi].rtMargin.bottom,eax
    assume edi:nothing
    invoke PageSetupDlg,edi
    mov esi,esp
    push sizeof(PAGESETUPDLG)/4
    pop ecx
    mov edi,[lppsd]
    rep movsd
    add esp,sizeof(PAGESETUPDLG);очистили буфер
    retn 1Ch
;=================================================================
aPlease db "Please Confirm Exit",0
aNewFile db 'New File',0     
aOpenFile db 'Open File',0  
aSaveFile db 'Save File',0
aCut     db 'Cut',0
aCopy    db 'Copy',0        
aPaste   db 'Paste',0        
aUndo    db 'Undo',0         
aSearch  db 'Search',0       
aProperties db 'Properties',0
aPrint   db 'Print',0
aAbout   db 'О программе',0
aAssembler db "Assembler, Pure & Simple",0
aYou db "You have selected",0
handlers dd aNewFile+exebase,aOpenFile+exebase,aSaveFile+exebase
    dd aCut+exebase,aCopy+exebase,aPaste+exebase,aUndo+exebase
    dd aSearch+exebase,aProperties+exebase,aPrint+exebase,aAbout+exebase
handler dd NewFile+exebase,OpenFile+exebase,SaveFile+exebase,Cut+exebase
    dd Copy+exebase,Paste+exebase,Undo+exebase,Search+exebase 
    dd Preview+exebase,Print+exebase,wmDESTROY+exebase,About+exebase
ASMFilterString     db "ASM Source code (*.asm)",0,"*.asm",0
            db "All Files (*.*)",0,"*.*",0,0
FileName db 256 dup(?)
handler1 dd STD_PRINTPRE,STD_FIND,STD_UNDO,STD_PASTE,STD_COPY,STD_CUT
    dd STD_FILESAVE,STD_FILEOPEN,STD_FILENEW
wTitle db 'Iczelion Tutorial #8-12:инструментальная панель в MASM',0
;-------------------------------------------------------------------------------------------
MFR_END     equ 80h
MFR_POPUP   equ 1
MFT_STRING  equ 0
MFS_ENABLED equ 0
MFT_SEPARATOR   equ 800h
RT_MENU     equ 4
 
POPUP       equ 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
align 2
resource:
;struct _IMAGE_RESOURCE_DIRECTORY
dd 0,0,0
NumberOfNamedEntries0   dw 0;количество ресурсов с именами
NumberOfIdEntries0  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0;номер типа ресурса
dw x-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление второго уровня. В 1-ом слове смещение второго оглавления 
;относительно начала раздела ресурсов
x:
dd 0,0,0
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw ID_MENU,0
dw x1-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
x1:
dd 0,0,0
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 16 * SUBLANG_ + LANG_
dw 40Ah,0,x2-resource,0
x2:;struct _IMAGE_RESOURCE_DATA_ENTRY
dd menu,end_menu-menu,0,0
menu dw 0,0,POPUP
du <&File>
dw MFR_END,ID_EXIT
du <&Exit>
dw MFT_STRING or MFS_ENABLED or MFR_END,ID_ABOUT
du <&About>
end_menu:
end_resource:
;---------------------------------------------------------------------
import:
hStatus       dd 0
hToolBar      dd 0
dd 0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0,0,ole32_dll
dd ole32_table
dd 0,0,0,comdlg32_dll
dd comdlg32_table
dd 0,0,0,shell32_dll
dd shell32_table
dd 0,0,0,comctl32_dll
dd comctl32_table
dd 0,0
kernel32_table:
ExitProcess             dd _ExitProcess,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
SendMessage             dd _SendMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
MoveWindow      dd _MoveWindow
BeginPaint      dd _BeginPaint
EndPaint            dd _EndPaint
GetWindowRect           dd _GetWindowRect
GetClientRect           dd _GetClientRect
DrawEdge            dd _DrawEdge
MessageBox      dd _MessageBox,0
shell32_table:
ShellAbout      dd _ShellAbout
SHBrowseForFolder   dd _SHBrowseForFolder,0
ole32_table:
CoTaskMemFree           dd _CoTaskMemFree,0
comdlg32_table:
GetSaveFileName     dd _GetSaveFileName
GetOpenFileName     dd _GetOpenFileName
PrintDlg            dd _PrintDlg
PageSetupDlg            dd _PageSetupDlg
ChooseColor         dd _ChooseColor
ChooseFont          dd _ChooseFont,0
comctl32_table:
CreateToolbarEx     dd _CreateToolbarEx
CreateStatusWindow  dd _CreateStatusWindow
                        dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_SendMessage        db 0,0,'SendMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_MoveWindow     db 0,0,"MoveWindow"
_BeginPaint     db 0,0,'BeginPaint'
_EndPaint       db 0,0,'EndPaint'
_GetWindowRect      db 0,0,'GetWindowRect'
_GetClientRect      db 0,0,'GetClientRect'
_DrawEdge       db 0,0,'DrawEdge'
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_CreateToolbarEx    db 0,0,'CreateToolbarEx'
_CreateStatusWindow db 0,0,'CreateStatusWindowA',0
comctl32_dll        db 'comctl32'
_ShellAbout     db 0,0,'ShellAboutA'
_SHBrowseForFolder  db 0,0,'SHBrowseForFolderA',0
shell32_dll     db 'shell32'
_CoTaskMemFree      db 0,0,'CoTaskMemFree',0
ole32_dll       db 'ole32'
_GetSaveFileName    db 0,0,'GetSaveFileNameA'
_GetOpenFileName    db 0,0,'GetOpenFileNameA'
_PrintDlg       db 0,0,'PrintDlgA'
_PageSetupDlg       db 0,0,'PageSetupDlgA'
_ChooseColor        db 0,0,'ChooseColorA'
_ChooseFont     db 0,0,'ChooseFontA',0
comdlg32_dll        db 'comdlg32'
end_import:
end main
__________________________________________________
© Mikl___ 2013


Win32 API. Урок 9. Дочерние окна
В этом туториале мы изучим дочерние элементы управления (child window controls), которые являются важными частями ввода и вывода нашей программы.
Скачайте пример здесь.
Теория ― мать склероза
Windows предоставляет несколько предопределенных классов окон, которые мы можем сразу же использовать в своих программах. Как правило, мы будем использовать их как компоненты dialog box'ов, поэтому они носят название дочерних элементов управления. Эти элементы обрабатывают сообщения от клавиатуры и мыши и уведомляют родительское окно, если их состояние изменяется. Они снимают с программистов огромный груз, поэтому вам следует использовать их так часто, как это возможно. В этом туториале, я положу их на обычное окно, только для того, чтобы продемонстрировать, как их можно создать и использовать, но в реальности вам лучше класть их на dialog box.
Примерами предопределенных классов окон являются кнопки, списки, сheckbox'ы, радиокнопки и т.д.
Чтобы использовать дочернее окно, вы должны создать его с помощью функции CreateWindow или CreateWindowEx. Заметьте, что вы не должны регистрировать класс окна, так как он уже был зарегистрирован Windows.
Имя класса окна должно быть именем предопределенного класса. Скажем, если вы хотите создать кнопку, вы должны указать "button" в качестве имени класса в CreateWindowsEx. Другие параметры, которые вы должны указать - это хэндл родительского окна и ID контрола. ID контрола должно быть уникальным. Вы используете его для того, чтобы отличать данный контрол от других.
После того, как контрол был создан, он посылает сообщение, уведомляющие родительское окно об изменении своего состояния. Обычно вы создаете дочернее окно во время обработки сообщения WM_CREATE главного окна.
Дочернее окно посылает сообщение WM_COMMAND родительскому окну со своим ID в младшем слове wParam'а, код уведомления в старшем слове wParam'а, а ее хэндл в lParam'е. Каждое окно имеет разные коды уведомления, сверьтесь с вашим справочником по Win32 API, чтобы получить подробную информацию.
Родительское окно также может посылать команды дочерним окнам, вызывая функцию SendMessage. Функция SendMessage посылает определенные сообщения с сопутствующими значениями в wParam и lParam окну, чей хэндл передается функции. Это очень полезная функция, так как она может посылать сообщения любому окну, хэндл которого у вас есть.
Поэтому, после создания дочерних окон, родительское окно должно обрабатывать сообщения WM_COMMAND, чтобы быть способным получать коды уведомления от дочерних окон.
Практика ― сестра шизофрении

Мы создадим окно, которое содержит окно редактирования и кнопку. Когда вы нажмете на кнопку, появится окно, отображающее текст, введенный в окно редактирования. Также имеется меню с 4 пунктами:
  1. Say Hello - ввести текстовую строку в edit box
  2. Clear Edit Box - очистить содержимое edit box'а
  3. Get Text - отобразить окно с текстом в edit box'е
  4. Exit - закрыть программу
Кликните здесь для просмотра всего текста
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
   .386
   .model flat,stdcall
   option casemap:none
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
 
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
 
   .data
   ClassName db "SimpleWinClass",0
   AppName  db "Our First Window",0
   MenuName db "FirstMenu",0
   ButtonClassName db "button",0
   ButtonText db "My First Button",0
   EditClassName db "edit",0
   TestString db "Wow! I'm in an edit box now",0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   hwndButton HWND ?
   hwndEdit HWND ?
   buffer db 512 dup(?)                    ; buffer to store the text retrieved from the edit box
 
   .const
   ButtonID equ 1                                ; The control ID of the button control
   EditID equ 2                                    ; The control ID of the edit control
   IDM_HELLO equ 1
   IDM_CLEAR equ 2
   IDM_GETTEXT equ 3
   IDM_EXIT equ 4
 
   .code
start:  invoke GetModuleHandle, NULL
       mov    hInstance,eax
       invoke GetCommandLine
       mov CommandLine,eax
       invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
       invoke ExitProcess,eax
 
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
       LOCAL wc:WNDCLASSEX
       LOCAL msg:MSG
       LOCAL hwnd:HWND
 
       mov   wc.cbSize,SIZEOF WNDCLASSEX
       mov   wc.style, CS_HREDRAW or CS_VREDRAW
       mov   wc.lpfnWndProc, OFFSET WndProc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_BTNFACE+1
       mov   wc.lpszMenuName,OFFSET MenuName
       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_OVERLAPPEDWINDOW,\
                           CW_USEDEFAULT, CW_USEDEFAULT,\
                           300,200,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
       .ELSEIF uMsg==WM_CREATE
           invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
                           WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
                           ES_AUTOHSCROLL,\
                           50,35,200,25,hWnd,8,hInstance,NULL
           mov  hwndEdit,eax
           invoke SetFocus, hwndEdit
           invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                           WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                           75,70,140,25,hWnd,ButtonID,hInstance,NULL
           mov  hwndButton,eax
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .IF lParam==0
               .IF ax==IDM_HELLO
                   invoke SetWindowText,hwndEdit,ADDR TestString
               .ELSEIF ax==IDM_CLEAR
                   invoke SetWindowText,hwndEdit,NULL
               .ELSEIF  ax==IDM_GETTEXT
                   invoke GetWindowText,hwndEdit,ADDR buffer,512
                   invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
               .ELSE
                   invoke DestroyWindow,hWnd
               .ENDIF
           .ELSE
               .IF ax==ButtonID
                   shr eax,16
                   .IF ax==BN_CLICKED
                       invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
                   .ENDIF
               .ENDIF
           .ENDIF
       .ELSE
           invoke DefWindowProc,hWnd,uMsg,wParam,lParam
           ret
       .ENDIF
       xor    eax,eax
       ret
   WndProc endp
   end start
Разбор полетов
Давайте проанализируем программу.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
           .ELSEIF uMsg==WM_CREATE
               invoke CreateWindowEx,WS_EX_CLIENTEDGE, \
                               ADDR EditClassName,NULL,\
                               WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT\
                               or ES_AUTOHSCROLL,\
                               50,35,200,25,hWnd,EditID,hInstance,NULL
               mov  hwndEdit,eax
               invoke SetFocus, hwndEdit
               invoke CreateWindowEx,NULL, ADDR ButtonClassName,\
                               ADDR ButtonText,\
                               WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                               75,70,140,25,hWnd,ButtonID,hInstance,NULL
               mov  hwndButton,eax
Мы создаем контролы во время обработки сообщения WM_CREATE. Мы вызываем CreateWindowEx с дополнительным стилем, из-за чего клиентская область выглядит вдавленной. Имя каждого контрола предопределенно - "edit" для edit-контрола, "button" для кнопки. Затем мы указываем стили дочерних окон. У каждого контрола есть дополнительные стили, кроме обычных стилей окна. Например, стили кнопок начинаются с "BS_", стили edit'а - с "ES_".
Вы должны посмотреть информацию об этих стилях в вашем справочнике по Win32 API. Заметьте, что вместо хэндла меню вы передаете ID контрола.
Это не вызывает никаких противоречий, поскольку дочерний элемент управления не может иметь меню. После создания каждого контрола, мы сохраняем его хэндл в соответствующей переменной для будущего использования.
SetFocus вызывается для того, чтобы направить фокус ввода на окно редактирования, чтобы пользователь мог сразу начать вводить в него текст.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .IF lParam==0
Обратите внимание, что меню тоже шлем сообщение WM_COMMAND, чтобы уведомить окно о своем состоянии. Как мы можем провести различие между сообщениями WM_COMMAND, исходящими от меню и элементов управления? Вот ответ:
Кликните здесь для просмотра всего текста
Нижнее слово wParam Верхнее слово wParam lParam
ID меню 0 0
ID контрола Код уведомления Хэндл дочернего окна
Из таблицы видно, что пользователь должен проверять lParam. Если он равен нулю, текущее сообщение WM_COMMAND было послано меню. Вы не можете использовать wParam, чтобы различать меню и контрол, так как ID меню и ID контрола могут быть идентичными и код уведомления должен быть равен нулю.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
               .IF ax==IDM_HELLO
                   invoke SetWindowText,hwndEdit,ADDR TestString
               .ELSEIF ax==IDM_CLEAR
                   invoke SetWindowText,hwndEdit,NULL
               .ELSEIF  ax==IDM_GETTEXT
                   invoke GetWindowText,hwndEdit,ADDR buffer,512
                   invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
Вы можете поместить текстовую строку в edit box с помощью вызова SetWindowText. Вы очищаете содержимое окна редактирования с помощью вызова функции SetWindowText, передавая ей NULL. SetWindowText - это функция общего назначения. Вы можете использовать ее, чтобы изменить заголовок окна или текст на кнопке. Чтобы получить текст в окне редактирования, вы можете использовать GetWindowText.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
               .IF ax==ButtonID
                   shr eax,16
                   .IF ax==BN_CLICKED
                       invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
                   .ENDIF
               .ENDIF
Приведенный выше фрагмент программы является фрагментом обработкой нажатия на кнопку. Сначала проверяем содержимое младшего слова wParam'а, чтобы убедиться, что ID элемента управления принадлежит кнопке. Если это так, проверяем старшее слово wParam'а, чтобы убедиться, что был послан код уведомления BN_CLICKED, то есть кнопка была нажата. После этого идет собственно обработка нажатия на клавиш. Мы хотим получить текст из окна редактирования и отобразить его в message box'е. Мы можем продублировать код в секции IDM_GETTEXT выше, но это не имеет смысла. Если мы сможем каким-либо образом послать сообщение WM_COMMAND с младшим словом wParam, содержащим значение IDM_GETTEXT нашей процедуре окна, то избежим дублирования кода и упростим программу. Функция SendMessage - это ответ.
Эта функция посылает любое сообщение любому окну с любым wParam'ом и lParam'ом, которые нам понадобятся. Поэтому вместо дублирования кода мы вызываем SendMessage с хэндлом родительского окна, WM_COMMAND, IDM_GETTEXT и 0. Это дает тот же эффект, что и выбор пункта меню "Get Text". Процедура окна не почувствует никакой разницы. Вы должны использовать эту технику так часто, насколько возможно, чтобы сделать ваш код более упорядоченным.
И напоследок. Hе забудьте вставить функцию TranslateMessage в очередь сообщений. Так как вам нужно печатать текст в окно редактирования, ваша программа должна транслировать ввод в читабельный текст. Если вы пропустите эту функцию, вы не сможете напечатать что-либо в вашем окне редактирования.
______________________________________________
© Iczelion, пер. Aquila.


Win32 API. Урок 9a. Дочерние окна
В этом туториале мы изучим дочерние элементы управления (child window controls), которые являются важными частями ввода и вывода нашей программы.

Скачайте пример здесь.
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 1200 bytes
du  macro string
    irpc c,
    if '&c' gt 127
    db ('&c'- 0B0h),4;кириллица
    else
    dw '&c';латиница
    endif
    endm
    dw 0
    endm
.code
exebase     equ 400000h
MFR_END     equ 80h
MFR_POPUP   equ 1
POPUP       equ 10h
MENUBREAK       equ 40h
btnId       equ 100
editId      equ 200
ID_MENU     equ 30
main:
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 1
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table-optional_header;
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_RELOCS_STRIPPED 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 end_import-start
Size_of_init_data   dd 0
Size_of_uninit_data dd 0
entry_point     dd start
base_of_code        dd start
base_of_data        dd 0
image_base      dd exebas;
e_lfanew        dd ntHeader-dosHeader;section alignment
file_alignment      dd 4
OS_version_major_minor  dd 4
image_version_major_minor dd 0
subsystem_version_major_minor dd 4
reserved1       dd 0
size_of_image       dd end_import
size_of_header      dd start
checksum        dd 0
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 100000h
Stack_commit        dd 1000h
Heap_allocation     dd 100000h
Heap_commit     dd 1000h
loader_flag     dd 0
number_of_dirs      dd (section_table-export_RVA)/8
export_RVA          dd 0
export_size         dd 0
import_RVA          dd import
import_size         dd end_import-import
resuorce_RVA        dd resource
resuorce_size           dd end_resource-resource
;------------------------------------------------
section_table       dd 'xet.','t'
virtual_size        dd 0
virtual_address     dd start
Physical_size       dd end_import-start
Physical_offset     dd start
Relocations         dd 0
Linenumbers     dd 0
Relocations_and_Linenumbers_count dd 0
Attributes              dd 0
;---------------------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
        push edi
    push ID_MENU
    push COLOR_BTNFACE+1
    push 10011h
    push ebx
    push esi
    push ebx
    push ebx
    push offset window_procedure+exebase
    push ebx
    push esp
    call RegisterClass+exebase
;--------------------------+
; creating the main window |
;--------------------------+
    push esi
    push ebx
    push esi
        shl esi,9
        push ebx
    push ebx
    push 200
    push 380
    push esi
    push esi
    push WS_OVERLAPPEDWINDOW or WS_VISIBLE
    push edi
    push edi
    push ebx
    call CreateWindowEx+exebase
    pop esi
    xchg edi,eax
    push ebx
    push esi
        push editId
    push edi
    push 25
    push 200
    push 35
    push 50
    push WS_CHILD or WS_VISIBLE or WS_BORDER \
    or ES_LEFT or ES_AUTOHSCROLL
    push ebx
    push offset aedit+exebase
    push WS_EX_CLIENTEDGE
    call CreateWindowEx+exebase
        mov  editHandle+exebase,eax
        push eax
    call SetFocus+exebase
    push ebx
    push esi
        push btnId
    push edi
    push 25
    push 140
    push 70
    push 75
    push WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON
    push offset buttonname+exebase
    push offset abutton+exebase
    push WS_EX_CLIENTEDGE
    call CreateWindowEx+exebase
        mov  btnHandle+exebase,eax
    mov ebp,esp
;---------------------------+
; entering the message loop |
;---------------------------+
message_loop: push ebx
    push ebx
    push ebx
    push ebp
    call GetMessage+exebase
    push ebp
    call TranslateMessage+exebase
    push ebp
    call DispatchMessage+exebase
    jmp message_loop
;----------------------+
; the window procedure |
;----------------------+
window_procedure proc hWnd, uMsg, wParam, lParam
local editBuffer [512]:byte
    mov eax,uMsg
    dec eax
    dec eax; cmp uMsg,WM_DESTROY
    je @@WM_DESTROY
    sub eax,WM_COMMAND-WM_DESTROY; cmp uMsg,WM_PAINT
    je @@WM_COMMAND
    leave
    jmp DefWindowProc+exebase
@@WM_COMMAND: mov eax,wParam
    cmp lParam,ebx
    je short @@WM_COMMAND_menu
    cmp ax,btnId  ;check whether is button id
    jne short @@WM_BYE
@@WM_COMMAND_button: shr eax,16
    test eax,eax  ;BN_CLICKED=0
    jne short @@WM_BYE
button_clicked: push ebx;0
    push 2
    push WM_COMMAND
    push hWnd
    call SendMessage+exebase
        jmp short @@WM_BYE
@@WM_COMMAND_menu: movzx eax,ax
    cmp eax,3
    ja short @@WM_BYE
    jmp [handler+eax*4]+exebase
menu_messagebox: mov edi,esp;указатель на local editBuffer
    push 512
    push edi;&editBuffer
    push editHandle+exebase
    call GetWindowText+exebase
    push ebx;MB_OK
    push offset wTitle+exebase
    push edi;&editBuffer
    push ebx
    call MessageBox+exebase
    jmp  @@WM_BYE
menu_writesomething: push offset aWow+exebase
    jmp a1
menu_cleartext: push ebx
a1: push editHandle+exebase
    call SetWindowText+exebase
@@WM_BYE: leave
    retn 10h
@@WM_DESTROY: push ebx
    call ExitProcess+exebase
handler dd menu_writesomething+exebase,menu_cleartext+exebase,\
    menu_messagebox+exebase,@@WM_DESTROY+exebase
window_procedure endp
;---------------------------------------------------------
wTitle db 'Iczelion Tutorial #9: Child Window Controls',0
aedit db "edit",0
abutton db "button",0
buttonname db "My First Button",0
aWow db "Wow! i'm in an edit box now",0
btnHandle dd ?
editHandle dd ?
;--------------------------------------------------------
align 2
resource:       
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0;номер типа ресурса
dw x-resource,8000h; если во 2-ом слове установлен старший 
;бит - есть ссылка на оглавление второго уровня. В 1-ом слове 
;смещение второго оглавления относительно начала раздела ресурсов
x:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором мени
dw ID_MENU,0
dw x1-resource,8000h; если во 2-ом слове установлен старший
;бит - есть ссылка на оглавление третьего уровня. В 1-ом слове
;смещение третьего оглавления относительно начала раздела ресурсов
x1:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором
;языка, который используется данным ресурсом 16 * SUBLANG_ + LANG_
dw 40Ah,0,x2-resource,0
x2:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu1
Size1       dd end_menu-menu1
CodePage1   dd 0
Reserved1   dd 0
menu1 dw 0,   0,POPUP or MFR_END
du <Test Controls>
dw MFT_STRING or MFS_ENABLED,0
du <Say Hello>
dw MFT_STRING or MFS_ENABLED,1
du <Clear Edit Box>
dw MFT_STRING or MFS_ENABLED,2
du <Get Text>
dw MENUBREAK,0
dw 0;
dw MFT_STRING or MFS_ENABLED or MFR_END,3
du <&Exit>
end_menu:
end_resource:
;---------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,kernel32_dll
dd kernel32_table
dd 0,0,0,0
user32_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
SetFocus        dd _SetFocus
SetWindowText       dd _SetWindowText
GetWindowText       dd _GetWindowText
TranslateMessage    dd _TranslateMessage
SendMessage     dd _SendMessage
MessageBox      dd _MessageBox,0
 
kernel32_table:
ExitProcess             dd _ExitProcess
                        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'
_SetFocus       db 0,0,'SetFocus'
_SetWindowText      db 0,0,'SetWindowTextA'
_GetWindowText      db 0,0,'GetWindowTextA'
_TranslateMessage   db 0,0,'TranslateMessage'
_SendMessage        db 0,0,'SendMessageA'
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
 
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
end_import:
END_SECTION:   
end main
______________________________________
© Mikl___ 2013
5
Вложения
Тип файла: zip tut09.zip (3.7 Кб, 93 просмотров)
Mikl___
Заблокирован
Автор FAQ
11.01.2013, 11:50  [ТС] #33
Win32 API. Урок 10. Диалоговое окно как основное
Теперь время для действительно интересной темы, относящейся к GUI, о диалоговом окне. В этом туториале (и в следующем) мы научимся как использовать диалоговое окно в качестве основного.
Скачайте первый и второй примеры.
ТЕОРИЯ ― МАТЬ СКЛЕРОЗА
Если вы изучили примеры в предыдущем туториалe достаточно подробно, вы заметили, что вы не могли перемещать фокус ввода от одного дочернего окна на другое, используя кнопку Tab. Вы могли сделать это только кликнув на нужном контроле, чтобы перевести на него фокус. Это довольно неудобно. Также вы могли заметить, что изменился цвет родительского окна на серый. Это было сделано для того, чтобы цвет дочерних окон не контрастировал с клиентской областью родительского окна. Есть путь, чтобы обойти эту проблему, но он не очень прост. Вы должны сабклассить все дочерние элементы управления в вашем родительском окне.
Причина того, почему возникают подобные неудобства состоят в том, что дочерние окна изначально проектировались для работы с диалоговым окном, а не с обычным. Цвет дочернего окна по умолчанию серый, так как это обычный цвет диалогового окна.
Прежде чем мы углубимся в детали, мы должны сначала узнать, что такое диалоговое окно. Диалоговое окно ― это не что иное, как обычное окно, которое спроектировано для работы с дочерними элементами управления.
Windows также предоставляет внутренний «менеджер диалоговых окон», который воплощает большую часть диалоговой логики, такую как перемещение фокуса ввода, когда юзеp нажимает Tab, нажатие кнопки по умолчанию, если нажатие на кнопку 'Enter, и так далее, так чтобы программисты могли заниматься более высокоуровневыми задачами. Поскольку диалоговое окно можно считать «черным ящиком» (это означает то, что вы не обязаны знать, как работает диалоговое окно, для того, чтобы использовать его), вы должно только знать, как с ним взаимодействовать. Это принцип объектно-ориентированного программирования, называемого скрытием информации. Если черный ящик спроектирован совершенно, пользователь может использовать его не зная, как он работает. Правда, загвоздка в том, что черный ящик должен быть совершенным, это труднодостижимо в реальном мире. Win32 API также спроектирован как черный ящик.
Ладно, похоже, что мы немного отклонились. Давайте вернемся к нашему сюжету. Диалоговые окна спроектированы так, чтобы снизить нагрузку на программиста. Обычно, если вы помещает дочерний элемент управления на обычное окно, вы должны сабклассить их и самостоятельно обрабатывать нажатия на клавиши.
Hо если вы помещаете их на диалоговое окно, оно обработает их за вас. Вы только должны как получать информацию, вводимую пользователем, или как посылать команды окну. Диалоговое окно определяется как ресурс (похожим образом, как и меню). Вы пишете шаблон диалогового окна, описывая характеристики диалогового окна и его элементов управления, а затем компилируете его с помощью редактора ресурсов.
Обратите внимание, что все ресурсы располагаются в одном скрипте ресурсов.
Вы можете использовать любой текстовый редактор, чтобы написать шаблон диалогового окна, но я бы не рекомендовал это. Вы должны использовать редактор ресурсов, чтобы сделать визуально расположить дочерние окна. Существует несколько прекрасных редакторов ресурсов. К большинству из основных компиляторов прилагаются подобные редакторы. Вы можете использовать их, чтобы создать скрипт ресурса. После этого стоит вырезать лишние строки, например, те, которые относятся к MFC.
Есть два основных вида диалоговых окон: модальные и независимые.
Независимые диалоговые окна дают вам возможность перемещать фокус ввода на другие окна. Пример ― диалоговое окно 'Find' в MS Word. Есть два подтипа модальных диалоговых окон: модальные к приложению и модальные к системе. Первые не дают вам переключаться на другое окно того же приложения, но вы можете переключиться на другое приложение. Вторые не дают вам возможности переключиться на любое другое окно.
Независимое диалоговое окно создается с помощью вызова функции CreateDialogParam. Модальное диалоговое окно создается вызовом DialogBoxParam. Единственное различие между диалоговым окном, модальным отношению к приложению, и диалоговым окном, модальным по отношению к системе, ― это стиль DS_SYSMODAL. Если вы включите стиль DS_SYSMODAL в шаблон диалогового окна, это диалоговое окно будет модальным к системе.
Вы можете взаимодействовать с любым дочерним элементом управления на диалоговом окне с помощью функции SendDlgItemMessage. Ее синтаксис следующий:
Кликните здесь для просмотра всего текста
Assembler
1
SendDlgItemMessage proto hwndDlg:DWORD,idControl:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
Эта API-функция неоценимо полезна при взаимодействии с дочерним окном.
Например, если вы хотите получить текст с элемента управления типа edit, вы можете сделать следующее:
Assembler
1
call SendDlgItemMessage,hDlg, ID_EDITBOX,WM_GETTEXT,256,ADDR text_buffer
Чтобы знать, какое сообщение когда посылать, вы должны проконсультироваться с вашим Win32 API-справочником.
Windows также предоставляет несколько специальных API-функций, заточенных под дочерние окна, для быстрого получения и установки нужных данных, например, GetDlgItemText, CheckDlgButton и т.д. Эти специальные функции создание, чтобы программисту не приходилось выяснять каждый раз значения wParam и lParam. Как правило, вы должны использовать данные функции, если хотите, чтобы управление кодом было легче. Используйте SendDlgItemMessage только, если нет соответствующей API-функции. Менеджер диалоговых окон посылает некоторые сообщения специальной callback-функции, называемой процедурой диалогового окна, которая имеет следующий формат:
Кликните здесь для просмотра всего текста
Assembler
1
       DlgProc  proto hDlg:DWORD,iMsg:DWORD,wParam:DWORD,lParam:DWORD
Процедура диалогового окна очень похожа на процедуру окна, если не считать тип возвращаемого значения ― TRUE/FALSE, вместо обычных LRESULT. Внутренний менеджер диалоговых окон внутри Windows ― истинная процедура для диалоговых окон. Она вызывает нашу процедуру диалоговых окон, передавая некоторые из полученных сообщений. Поэтому главное правило следующее: если наша процедура диалогового окна обрабатывает сообщение, она должна вернуть TRUE в eax и если она не обрабатывает сообщение, тогда она должна вернуть в eax FALSE. Заметьте, что процедура диалогового окна не передает сообщения функции DefWindowProc, так как это не настоящая процедура окна.
Диалоговое окно можно использовать в двух целях. Вы можете использовать ее как основное окно или как вспомогательное для получения информации, вводимой пользователем. В этом туториале мы изучим первый вариант.
«Использование диалогового окна как основное окно» можно понимать двояко.
  • Вы можете использовать шаблон диалогового окна как шаблон класса, который вы регистрируете с помощью функции RegisterClassEx. В этом случае, диалоговое окно ведет себя как «нормальное»: оно получает сообщения через процедуру окна, на которую ссылается lрfnWndProc, а не через процедуру диалогового окна. Выгода данного подхода состоит в том, что вы не должны самостоятельно создавать дочерние элементы управления, Windows создает их во время создания диалогового окна. Также Windows берет на себя логику нажатий на клавиши (Tab и т.д.). Плюс вы можете указать курсор и иконку вашего окна в структуре класса окна.
  • Ваша программа создает диалоговое окно без создания родительского окна. Этот подход делает цикл сообщений ненужным, так как сообщения шлются напрямую процедуре диалогового окна. Вам даже не нужно регистрировать класс окна!
Похоже, что этот туториал будет довольно долгим.
ПРАКТИКА ― СЕСТРА ШИЗОФРЕНИИ
текст файла dialog.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
   .386
   .model flat,stdcall
   option casemap:none
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
 
   .data
   ClassName db "DLGCLASS",0
   MenuName db "MyMenu",0
   DlgName db "MyDialog",0
   AppName db "Our First Dialog Box",0
   TestString db "Wow! I'm in an edit box now",0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   buffer db 512 dup(?)
 
   .const
   IDC_EDIT        equ 3000
   IDC_BUTTON      equ 3001
   IDC_EXIT        equ 3002
   IDM_GETTEXT     equ 32000
   IDM_CLEAR       equ 32001
   IDM_EXIT        equ 32002
 
   .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 hDlg: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,DLGWINDOWEXTRA
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_BTNFACE+1
       mov   wc.lpszMenuName,OFFSET MenuName
       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 CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL
       mov   hDlg,eax
       invoke ShowWindow, hDlg,SW_SHOWNORMAL
       invoke UpdateWindow, hDlg
       invoke GetDlgItem,hDlg,IDC_EDIT
       invoke SetFocus,eax
 
       .WHILE TRUE
           invoke GetMessage, ADDR msg,NULL,0,0
           .BREAK .IF (!eax)
           invoke IsDialogMessage, hDlg, ADDR msg
           .IF eax ==FALSE
             invoke TranslateMessage, ADDR msg
             invoke DispatchMessage, ADDR msg
           .ENDIF
       .ENDW
       mov     eax,msg.wParam
       ret
   WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
       .IF uMsg==WM_DESTROY
           invoke PostQuitMessage,NULL
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .IF lParam==0
               .IF ax==IDM_GETTEXT
                   invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512
                   invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
               .ELSEIF ax==IDM_CLEAR
                   invoke SetDlgItemText,hWnd,IDC_EDIT,NULL
               .ELSE
                   invoke DestroyWindow,hWnd
               .ENDIF
           .ELSE
               mov edx,wParam
               shr edx,16
               .IF dx==BN_CLICKED
                   .IF ax==IDC_BUTTON
                       invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString
                   .ELSEIF ax==IDC_EXIT
                       invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
                   .ENDIF
               .ENDIF
           .ENDIF
       .ELSE
           invoke DefWindowProc,hWnd,uMsg,wParam,lParam
           ret
       .ENDIF
       xor    eax,eax
       ret
   WndProc endp
   end start
Текст файла Dialog.rc
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   #include "resource.h"
   #define IDC_EDIT                                       3000
   #define IDC_BUTTON                                3001
   #define IDC_EXIT                                       3002
   #define IDM_GETTEXT                             32000
   #define IDM_CLEAR                                  32001
   #define IDM_EXIT                                      32003
   MyDialog DIALOG 10, 10, 205, 60
   STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
   WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
   CAPTION "Our First Dialog Box"
   CLASS "DLGCLASS"
   BEGIN
       EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
       DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
       PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13, WS_GROUP
   END
 
   MyMenu  MENU
   BEGIN
       POPUP "Test Controls"
       BEGIN
           MENUITEM "Get Text", IDM_GETTEXT
           MENUITEM "Clear Text", IDM_CLEAR
           MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
           MENUITEM "E&xit", IDM_EXIT
       END
   END
Разбор полетов
Давайте проанализируем первый пример.
Этот пример показывает, как зарегистрировать диалоговый шаблон как класс окна и создает «окно» из этого класса. Это упрощает вашу программу, так как вам не нужно создавать дочерние элементы управления самостоятельно.
Давайте проанализируем шаблон диалогового окна.
Кликните здесь для просмотра всего текста
C
1
   MyDialog DIALOG 10, 10, 205, 60
Объявление имя диалога, в данном случае ― «MyDialog», за которым следует ключевое слово «DIALOG». Следующие четыре числа ― это значения координат x, y, ширины и высоты диалогового окна в специальных единицах (не в пикселях).
C
1
2
   STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
   WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
Объявление стилей диалогового окна.
Кликните здесь для просмотра всего текста
Assembler
1
   CAPTION "Our First Dialog Box"
Это текст, который появится в заголовке окна.
Кликните здесь для просмотра всего текста
Assembler
1
   CLASS "DLGCLASS"
Это ключевая строка. Ключевое слово 'CLASS' позволяет нам использовать шаблон диалогового окна в качестве класса окна. Следующее слово ― это имя «класса окна».
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
   BEGIN
       EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
       DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
       PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13
   END
Данный блок определяет дочерние элементы управления в диалоговом окне. Они определены между ключевыми словами BEGIN и END. Общий синтаксис таков:
Кликните здесь для просмотра всего текста
Assembler
1
       control-type  "text"   ,controlID, x, y, width, height [,styles]
типы элементов управления ― константы компилятора ресурсов, которые можно найти в руководстве по компилятору ресурсов.
Теперь мы углубляемся непосредственно в ассемблерный код. Интересующая нас часть находится в структуре класса окна.
Кликните здесь для просмотра всего текста
Assembler
1
2
       mov   wc.cbWndExtra,DLGWINDOWEXTRA
       mov   wc.lpszClassName,OFFSET ClassName
Обычно этот параметр оставляется равным нулю, но если мы хотим зарегистрировать шаблон диалогового окна как класс окна, мы должны установить это параметр равным DLGWINDOWEXTRA. Заметьте, что имя класса должно совпадать с именем, что определено в шаблон диалогового окна. Остающиеся параметры инициализируются как обычно. После того, как вы заполните структуру класса окна, зарегистрируйте ее с помощью RegisterClassEx. Звучит знакомо. Точно также вы регистрируете обычный класс окна.
Кликните здесь для просмотра всего текста
Assembler
1
       invoke CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL
После регистрации «класса окна», мы создаем наше диалоговое окно. В этом примере я создал его как независимое диалоговое окно функцией CreateDialogParam. Эта функция получает 5 параметров, но вам нужно заполнить только первые два: хэндл процесса и указатель на имя шаблона диалогового окна. Заметьте, что 2-ой параметр ― это не указатель на имя класса.
В этот момент, диалоговое окно и его дочерние элементы управления создаются Windows. Ваша процедура окна получит сообщение WM_CREATE как обычно.
Кликните здесь для просмотра всего текста
Assembler
1
2
       invoke GetDlgItem,hDlg,IDC_EDIT
       invoke SetFocus,eax
После того, как диалоговое окно созданно, я хочу установить фокус ввода на edit control. Если я помещу соответвующий код в секцию WM_CREATE, вызов GetDlgItem провалится, так как дочерние окна еще не созданы. Единственный путь сделать это ― вызвать эту функцию после того, как диалоговое окно и все его дочерние окна будут созданы. Поэтому я помещаю данные две линии после вызова UpdateWindow. Функция GetDlgItem получает ID контрола и возвращает соответствующий хэндл окна. Так вы можете получить хэндл окна, если вы знаете его control ID.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
          invoke IsDialogMessage, hDlg, ADDR msg
           .IF eax ==FALSE
               invoke TranslateMessage, ADDR msg
               invoke DispatchMessage, ADDR msg
           .ENDIF
Программа входит в цикл сообщений и перед тем, как мы транслируем и передаем сообщения, мы вызываем функцию IsDialogMessage, чтобы позволить менеджеру диалоговых сообщений обрабатывать логику сообщений за нас. Если эта функция возвращает TRUE, это значит, что сообщение сделано для диалогового окна и обрабатывается менеджером диалоговых сообщений. Отметьте другое отличие от предыдущего туториала. Когда процедура окна хочет получить текст с edit контрола, она вызывает функцию GetDlgItemText, вместо функции GetWindowText. GetDlgItemText принимает ID контрола вместо хэндла окна. Это делает вызов проще в том случае, если вы используете диалоговое окно.
Теперь давайте перейдем ко второму подходу использования диалогового окна как основного окна. В следующем примере, я создам программно-модальное диалоговое окно. Вы не увидите цикл сообщений или процедуру окна, потому что они не нужны!
текст файла dialog.asm (вариант 2)
Кликните здесь для просмотра всего текста
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
.386
   .model flat,stdcall
   option casemap:none
 
   DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
 
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
 
   .data
   DlgName db "MyDialog",0
   AppName db "Our Second Dialog Box",0
   TestString db "Wow! I'm in an edit box now",0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   buffer db 512 dup(?)
 
   .const
   IDC_EDIT            equ 3000
   IDC_BUTTON     equ 3001
   IDC_EXIT            equ 3002
   IDM_GETTEXT  equ 32000
   IDM_CLEAR       equ 32001
   IDM_EXIT           equ 32002
 
   .code
   start:       invoke GetModuleHandle, NULL
       mov    hInstance,eax
       invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL
       invoke ExitProcess,eax
 
   DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
       .IF uMsg==WM_INITDIALOG
           invoke GetDlgItem, hWnd,IDC_EDIT
           invoke SetFocus,eax
       .ELSEIF uMsg==WM_CLOSE
           invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .IF lParam==0
               .IF ax==IDM_GETTEXT
                   invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512
                   invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
               .ELSEIF ax==IDM_CLEAR
                   invoke SetDlgItemText,hWnd,IDC_EDIT,NULL
               .ELSEIF ax==IDM_EXIT
                   invoke EndDialog, hWnd,NULL
               .ENDIF
           .ELSE
               mov edx,wParam
               shr edx,16
               .if dx==BN_CLICKED
                   .IF ax==IDC_BUTTON
                       invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString
                   .ELSEIF ax==IDC_EXIT
                       invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
                   .ENDIF
               .ENDIF
           .ENDIF
       .ELSE
           mov eax,FALSE
           ret
       .ENDIF
       mov eax,TRUE
       ret
   DlgProc endp
   end start
Текст файла dialog.rc (вариант 2)
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   #include "resource.h"
 
   #define IDC_EDIT                                       3000
   #define IDC_BUTTON                                3001
   #define IDC_EXIT                                       3002
   #define IDR_MENU1                                  3003
   #define IDM_GETTEXT                              32000
   #define IDM_CLEAR                                   32001
   #define IDM_EXIT                                       32003
   MyDialog DIALOG 10, 10, 205, 60
   STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
   WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
   CAPTION "Our Second Dialog Box"
 
   MENU IDR_MENU1
   BEGIN
       EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
       DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
       PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13
   END
 
   IDR_MENU1  MENU
   BEGIN
       POPUP "&Test Controls";
       BEGIN
           MENUITEM "Get Text", IDM_GETTEXT
           MENUITEM "Clear Text", IDM_CLEAR
           MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
           MENUITEM "E&xit", IDM_EXIT
       END
   END
Разбор полетов
Кликните здесь для просмотра всего текста
Assembler
1
       DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
Мы объявляем прототип функции для DlgProc, так что мы можем ссылаться на нее оператором addr:
Кликните здесь для просмотра всего текста
Assembler
1
       invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL
В вышеприведенной строке вызывается функция DialogBoxParam, которая получает 5 параметров: хэндл процесса, имя шаблона диалогового окна, хэндл родительского окна, адрес процедуры диалогового окна и специальные данные для диалогового окна. DialogBoxParam создает модальное диалоговое окно. Она не возвращается, пока диалоговое окно не будет уничтожено.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
       .IF uMsg==WM_INITDIALOG
           invoke GetDlgItem, hWnd,IDC_EDIT
           invoke SetFocus,eax
       .ELSEIF uMsg==WM_CLOSE
           invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
Процедура диалогового окна выглядит как процедура окна, не считая того, что она не получает сообщение WM_CREATE. Первое сообщение, которое она получает ― это WM_INITDIALOG. Обычно вы помещаете здесь код инициализации. Заметьте, что вы должны вернуть в регистре eax значение TRUE, если вы обрабатываете это сообщение.
Внутренний менеджер диалогового окна не посылает нашей процедуре сообщение WM_DESTROY, а вот WM_CLOSE шлет. Поэтому если мы хотим отреагировать на то, что пользователь нажимает кнопку закрытия на нашем диалоговом окне, мы должны обработать сообщение WM_CLOSE. В нашем примере мы посылаем сообщение WM_CLOSE со значение IDM_EXIT в wParam. Это произведет тот же эффект, что и выбор пункта 'Exit' в меню. EndDialog вызывается в ответ на IDM_EXIT.
Обработка сообщений WM_COMMAND остается такой же.
Когда вы хотите уничтожить диалоговое окно, единственный путь ― это вызов функции EndDialog. Не пробуйте DestroyWindow! EndDialog не уничтожает диалоговое окно немедленно. Она только устанавливает флаг для внутреннего менеджера диалогового окна и продолжает выполнять следующие инструкции.
Теперь давайте изучим файл ресурсов. Заметное изменение ― это то, что вместо использования текстовой строки в качестве имени меню, мы используем значение IDR_MENU1. Это необходимо, если вы хотите прикрепить меню к диалоговому окну, созданному DialogBoxParam'ом. Заметьте, что в шаблоне диалогового окна вы должны добавить ключевое слово 'MENU', за которым будет следовать ID ресурса меню.
Различие между двумя примерами в этом туториале, которое вы можете легко заметить ― это отсутствие иконки в последнем примере. Тем не менее, вы можете установить иконку, послав сообщение WM_SETICON диалоговому окну во время обработки WM_INITDIALOG.
______________________________________
© Iczelion, пер. Aquila.
3
Вложения
Тип файла: zip tut10-1.zip (13.0 Кб, 91 просмотров)
Тип файла: zip tut10-2.zip (12.2 Кб, 84 просмотров)
Mikl___
Заблокирован
Автор FAQ
12.01.2013, 12:57  [ТС] #34
Win32 API. Урок 10a. Комментарии kero к 10 и 11 урокам Iczelion'a
По банальному недомыслию или, наоборот, по хитроумному педагогическому замыслу, но в знаменитом "Win32 API Tutorial" by Iczelion немало ошибок. И хотя туториал от этого даже поучительнее ― поправки к ошибкам не помешали бы. Отсюда предложение: издать Туториал с комментариями. И ниже ― несколько таковых от автора этих строк.
Диалоговое окно (уроки 10-11)
10-й урок начинается так:
«Теперь время для действительно интересной темы, относящейся к GUI, о диалоговом окне. В этом тутоpиале (и в следующем) мы научимся как использовать диалоговое окно в качестве основного.» (© перевод Aquila)
Однако насколько разобрался в этой теме сам Iczelion?

Поучительная путаница
Вот DIALOG.asm из tut10-1.zip:
Кликните здесь для просмотра всего текста
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
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
 
.data
ClassName db "DLGCLASS",0
MenuName db "MyMenu",0
DlgName db "MyDialog",0
AppName db "Our First Dialog Box",0
TestString db "Wow! I'm in an edit box now",0
 
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
buffer db 512 dup(?)
 
.const
IDC_EDIT        equ 3000
IDC_BUTTON      equ 3001
IDC_EXIT        equ 3002
IDM_GETTEXT     equ 32000
IDM_CLEAR       equ 32001
IDM_EXIT        equ 32002
 
.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 hDlg: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,DLGWINDOWEXTRA
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_BTNFACE+1
    mov   wc.lpszMenuName,OFFSET MenuName
    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 CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL
    mov   hDlg,eax
      invoke GetDlgItem,hDlg,IDC_EDIT
    invoke SetFocus,eax 
    INVOKE ShowWindow, hDlg,SW_SHOWNORMAL
    INVOKE UpdateWindow, hDlg
    .WHILE TRUE
                INVOKE GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                invoke IsDialogMessage, hDlg, ADDR msg
                .if eax==FALSE
                        INVOKE TranslateMessage, ADDR msg
                        INVOKE DispatchMessage, ADDR msg
                .endif
    .ENDW
    mov     eax,msg.wParam
    ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .if uMsg==WM_CREATE
        invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR AppName
    .ELSEIF uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF lParam==0
            .IF ax==IDM_GETTEXT
                invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512
                invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
            .ELSEIF ax==IDM_CLEAR
                invoke SetDlgItemText,hWnd,IDC_EDIT,NULL
            .ELSE
                invoke DestroyWindow,hWnd
            .ENDIF
        .ELSE
            mov edx,wParam
            shr edx,16
            .IF dx==BN_CLICKED
                .IF ax==IDC_BUTTON
                    invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString
                        .ELSEIF ax==IDC_EXIT
                    invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
                .ENDIF
            .ENDIF
        .ENDIF
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp
end start
Если сравнивать DIALOG.asm из tut10-1.zip с текстом урока, то обнаруживается отсутствие строк:
Кликните здесь для просмотра всего текста
Assembler
1
2
    .if uMsg==WM_CREATE
        invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR AppName
и это правильно ― сообщение WM_CREATE не соответствует сообщению WM_INITDIALOG, и к моменту прихода сообщения WM_CREATE элементы управления еще не созданы, и название AppName просто некуда вписывать.
Запускаем приложение DIALOG.exe, нажимаем на ENTER, и окно DIALOG закрывается!
А ведь Iczelion явно не этого хотел ― достаточно заглянуть в DIALOG.rc:
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "resource.h"
#define IDC_EDIT      3000
#define IDC_BUTTON    3001
#define IDC_EXIT      3002
#define IDM_GETTEXT  32000
#define IDM_CLEAR    32001
#define IDM_EXIT     32003
 
MyDialog DIALOG 10, 10, 205, 60
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "Our First Dialog Box"
CLASS "DLGCLASS"
BEGIN
    EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT |
                                               WS_TABSTOP
    DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
    PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13
END
 
MyMenu  MENU
BEGIN
    POPUP "Test Controls"
    BEGIN
        MENUITEM "Get Text", IDM_GETTEXT
        MENUITEM "Clear Text", IDM_CLEAR
        MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
        MENUITEM "E&xit", IDM_EXIT
    END
END
Видите ― кнопка «Say Hello» имеет стиль DEFPUSHBUTTON. А стиль DEFPUSHBUTTON в rc-файле задается не только ради штриховой окантовки, а, главным образом, когда надо, чтобы нажатие на ENTER было бы равносильно клику по этой кнопке, даже если в фокусе ввода ― другой элемент управления (не кнопка!). Все-таки ― почему нажатие на ENTER закрывает этот DIALOG?
При нажатии на ENTER функция IsDialogMessage в цикле обработки очереди сообщений посылает сообщение WM_COMMAND с параметром wParam равным IDOK=1, и хотя ни кнопки, ни пункта меню с
Кликните здесь для просмотра всего текста
Assembler
1
2
   .ELSE
       invoke DestroyWindow,hWnd
― настолько ошибочен, что даже преодолевает ошибочное несовпадение
значений IDM_EXIT в DIALOG.asm
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
   IDC_EDIT        equ 3000
   IDC_BUTTON      equ 3001
   IDC_EXIT        equ 3002
   IDM_GETTEXT     equ 32000
   IDM_CLEAR       equ 32001
   IDM_EXIT        equ 32002
и в rc-файле!
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
#define IDC_EDIT     3000
#define IDC_BUTTON   3001
#define IDC_EXIT     3002
#define IDM_GETTEXT  32000
#define IDM_CLEAR    32001
#define IDM_EXIT     32003
Не повезло и TAB-навигации (элементам управления со стилем WS_TABSTOP) Ведь если в DIALOG Iczelion'а добавить EDIT со стилем ES_MULTILINE ― то на нем TAB-навигация и заткнется...

Неладно и с обработкой сообщения WM_ACTIVATE ― если приложение DIALOG деактивировать и снова активировать ― фокус ввода не возвращается не только к последнему обладавшему им элементу управления, но и вообще ни к какому элементу управления. А после следующего нажатия на TAB ― передается исключительно первому из элементов управления.

Ну, а строчки в WinMain ―
Кликните здесь для просмотра всего текста
Assembler
1
2
invoke GetDlgItem,hDlg,IDC_EDIT
invoke SetFocus,eax
― зачем? Ведь этот EDIT ― первый элемент управления диалога, и фокус ввода после запуска ему вроде и так обеспечен? Но если эти строчки убрать, то EDIT примера tut10-1 действительно не получит фокуса! Что за ерунда?

DefWindowProc и DefDlgProc


The DefDlgProc function calls the default dialog box window procedure to provide default processing for any window messages that a dialog box with a private window class does not process. (MSDN)

Так вот, перечисленные выше глюки закономерны: о DefDlgProc у Iczelion'а ни звука! Как, кстати, и у Petzold'а в «Programming Windows» 1998 года, откуда Iczelion, очевидно, и «сдувал». И это ― еще одна ошибка Iczelion'а,
«сдувать» надо было с опубликованного за 5 лет до Petzold'а «Microsoft Windows Programmer FAQ»:

6.2.8. Using a dialog as your main window
First, you have to create a dialog box first. Include a class name (you name it). Then, in your WinMain function, register a class using that class name and add the constant DLGWINDOWEXTRA to the window extra byte component. This constant is defined in Windows.h. Then, use CreateDialog() to display the dialog, make sure the last 2 parameters are set to NULL. In your WndProc function, instead of calling DefWindowProc, call DefDlgProc. Then, you are basically all set. Make sure in your dialog definition you create your dialog box initially visible. For further information, see your docs.

То есть чтобы DEFPUSHBUTTON, IsDialogMessage, TAB, (WM_ACTIVATE, WM_SETFOCUS, и так далее) работали, как положено в диалоге, WndProc должна по умолчанию взывать не
Кликните здесь для просмотра всего текста
Assembler
1
2
.ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
а
Кликните здесь для просмотра всего текста
Assembler
1
2
.ELSE
        invoke DefDlgProc,hWnd,uMsg,wParam,lParam
В общем, о диалогах надо читать прежде всего Dialog Box Programming Considerations, ну и конечно OldNewThing Raymond'а Chen'а (одного из пап WinGUI'я), там есть чем поживиться...
WM_CREATE и WM_INITDIALOG
Возвращаясь к Туториалу: ошибка с WM_CREATE в WndProc (tut10-1)
Кликните здесь для просмотра всего текста
Assembler
1
2
.if uMsg==WM_CREATE
        invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR AppName
и ошибка с WM_INITDIALOG в DlgProc (tut10-2, tut11-1, tut11-2, ...)
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
.IF uMsg==WM_INITDIALOG
        invoke GetDlgItem, hWnd,IDC_EDIT
        invoke SetFocus,eax
    .ELSEIF ...
    ...
    .ENDIF
    mov eax,TRUE
    ret
Сообщение WM_CREATE не соответствует сообщению WM_INITDIALOG, элементы управления еще не созданы, AppName вписывать некуда. А на сообщение WM_INITDIALOG после вызова SetFocus надо возвращать не TRUE, а FALSE (см. MSDN), и в данном случае EDIT получает фокус ввода по одной единственной причине: он первый элемент управления диалога.
В конце 10-ого урока читаем: «Различие между двумя примерами в этом туториале, которое вы можете легко заметить ― это отсутствие иконки в последнем примере. Тем не менее, вы можете установить иконку, послав сообщение WM_SETICON диалоговому окну во время обработки WM_INITDIALOG».

А почему бы просто не выкинуть DS_MODALFRAME из rc-файла последнего примера, с тем же результатом? ―
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
...
   MyDialog DIALOG 10, 10, 205, 60
   STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
   WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
   CAPTION "Our Second Dialog Box"
   ...
Кстати, если диалог WS_OVERLAPPED (т.е. без WS_POPUP и WS_CHILD) или есть строчка CAPTION - то WS_CAPTION и так обеспечен... А 0x0004 и есть DS_3DLOOK...
Впрочем, на подобные мелочи отвлекаться больше не будем. Тем более что рядом ― чреватое неприятностями наставление: «Когда вы хотите уничтожить диалоговое окно, единственный путь ― это вызов функции EndDialog. Не пробуйте DestroyWindow! EndDialog не уничтожает диалоговое окно немедленно. Она только устанавливает флаг для внутреннего менеджера диалогового окна и продолжает выполнять следующие инструкции.» Но по MSDN ― это верно только для диалогового окна, порожденного функциями DialogBox_ (DialogBoxIndirectParam, DialogBoxParam), а при использовании функций CreateDialog_ (CreateDialogParam, CreateDialogIndirectParam) ― для уничтожения окна нужно использовать именно функцию DestroyWindow, а не EndDialog!
В одиннадцатом уроке Iczelion последовал собственному указанию, и вот что из этого вышло.
EndDialog и DestroyWindow
текст DIALOG.asm из tut11-1.zip:
Кликните здесь для просмотра всего текста
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
.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
DlgProc PROTO :HWND, :DWORD, :DWORD, :DWORD
 
.data
ClassName db "SimpleWinClass",0
AppName  db "Our Main Window",0
MenuName db "FirstMenu",0
DlgName db "MyDialog",0
TestString db "Hello, everybody",0
hwndDlg dd 0            ; Handle to the dialog box
 
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
 
.const
IDM_EXIT equ 1
IDM_ABOUT equ 2
IDC_EDIT  equ 3000
IDC_BUTTON equ 3001
IDC_EXIT equ 3002
 
.code
start:  invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    mov CommandLine,eax
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_WINDOW+1
    mov   wc.lpszMenuName,OFFSET MenuName
    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_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,300,200,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)
                .if hwndDlg!=0
                        invoke IsDialogMessage,hwndDlg,ADDR msg
                        .if eax==TRUE
                                .continue
                        .endif
                .endif
                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
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .if ax==IDM_ABOUT
            invoke CreateDialogParam,hInstance, addr DlgName,\
                hWnd,OFFSET DlgProc,NULL
            mov hwndDlg,eax
        .else
            invoke DestroyWindow, hWnd
        .endif
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp
 
DlgProc PROC hWnd:HWND,iMsg:DWORD,wParam:WPARAM, lParam:LPARAM
        .if iMsg==WM_INITDIALOG
        invoke GetDlgItem,hWnd,IDC_EDIT
        invoke SetFocus,eax
        .elseif iMsg==WM_CLOSE
        invoke EndDialog,hWnd,NULL
        mov hwndDlg,0
        .elseif iMsg==WM_COMMAND
        mov eax,wParam
        mov edx,eax
        shr edx,16
        .if dx==BN_CLICKED
            .if eax==IDC_EXIT
                invoke SendMessage,hWnd,WM_CLOSE,NULL,NULL
            .elseif eax==IDC_BUTTON
                invoke SetDlgItemText,hWnd,IDC_EDIT,\
                ADDR TestString
            .endif
        .endif         
        .else
        mov eax,FALSE
        ret
        .endif
        mov  eax,TRUE
        ret
DlgProc endp
end start
DIALOG.rc из tut11-1:
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// constants for dialog box
#define IDC_EDIT            3000
#define IDC_BUTTON          3001
#define IDC_EXIT            3002
#define DS_CENTER           0x0800L
#define DS_CENTER           0x0800L
#define WS_MINIMIZEBOX      0x00020000L
#define WS_SYSMENU          0x00080000L
#define WS_VISIBLE          0x10000000L
#define WS_OVERLAPPED       0x00000000L
#define DS_MODALFRAME       0x80L
#define DS_3DLOOK           0x0004L
#define WS_CAPTION          0xC00000L
#define ES_AUTOHSCROLL      0x80L
#define ES_LEFT             0
 
// Constants for menu
#define IDM_EXIT 1
#define IDM_ABOUT 2
 
FirstMenu MENU
{
 POPUP "&File"
        {
         MENUITEM "E&xit",IDM_EXIT
        }
 MENUITEM "About",IDM_ABOUT
}
 
MyDialog DIALOG 10, 10, 205, 60
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "Our Second Dialog Box"
BEGIN
    EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
    DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
    PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13
END
Итак, запускаем DIALOG.exe, дожидаемся появления окна «Our Main Window», жмем в меню пункт «About», дожидаемся диалога «Our Second Dialog Box», пробуем на его элементах управления TAB, убеждаемся, что табуляция работает, убеждаемся, что кнопка DEFPUSHBUTTON «Say Hello» ― действительно DEFPUSHBUTTON, закрываем диалог закрываем диалог (кнопкой «Exit» или «Х» кнопка заголовка, или пункт системного меню, или Alt+F4, - без разницы)
Но погодите, разве диалог закрылся? Он же только спрятался! Причем при следующем нажатии на «About» выскочит уже новый «Our Second Dialog Box»!

(Проще всего это узреть через FrameRector, - единственной в природе «шпионской программой» «наизнанку», которая не тычется вслепую, а преподносит все окна разом, предлагая не искать, а выбирать, рекомендую

Ей на пару - WinTreeSnap, моментальный снимок в текстовый файл полного дерева окон с кучей параметров, мне не хватало этого в Spy++ . Кстати, WTS - пример использования wsprintf с максимальным числом параметров: 2+29=11111b. Отмечу также, что FrameRector и WinTreeSnap ― «идейно безоконные», дабы не встревать в дерево окон, а последние версии FR и WTS согласованы c ExtraSpy, HTspy, ParentOwner).

Вывод: завершать немодальный CreateDialog* "по Iczelion-у" (то есть EndDialog вместо DestroyWindow) - ошибка.

Исправляем.

Но с другой стороны: «About» использует CreateDialogParam, диалоги получаются немодальные, и одновременно открыть их можно до фига. Понятно, куча «About» никому не нужна, хватит и одного модального, однако полезна возможность работы сразу с кучей панелей инструментов.

Каждое «закрытие» диалога в примере tut11-1 ― на самом деле всего лишь делает диалог невидимым, так что нажатия на «About» множат и множат эти диалоги. Потому что диалоги в этом примере создаются через CreateDialogParam, а закрываются Iczelion'ом через EndDialog:
Кликните здесь для просмотра всего текста
Assembler
1
2
 .elseif iMsg==WM_CLOSE        
    invoke EndDialog,hWnd,NULL
а не так, как надо:
Кликните здесь для просмотра всего текста
Assembler
1
2
 .elseif iMsg==WM_CLOSE        
    invoke DestroyWindow,hWnd
Исправляем, и идем дальше...

Поскольку используется CreateDialogParam, то диалоги получаются немодальные, и создать через нажатие на «About» можно очень много.

Но нам хватит и двух, чтобы заметить ― TAB работает только в последнем из созданных диалогов.

И ясно, почему ― Iczelion при создании очередного диалога засовывает его hWnd в одну и ту же глобальную переменную hwndDlg, так что только этот диалог и будет обслуживаться через IsDialogMessage, такой уж у Iczelion'а цикл обработки очереди сообщений:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
    .WHILE TRUE
     INVOKE GetMessage, ADDR msg,NULL,0,0
     .BREAK .IF (!eax)
     .if hwndDlg!=0
        invoke IsDialogMessage,hwndDlg,ADDR msg
        .if eax==TRUE
           .continue
        .endif
     .endif
     INVOKE TranslateMessage, ADDR msg
     INVOKE DispatchMessage, ADDR msg
    .ENDW
    mov     eax,msg.wParam
Значит ― опять правим Iczelion'а: hwndDlg ― отовсюду на фиг, а к IsDialogMessage приделываем «довесок» ― функцию GetActiveWindow либо GetAncestor(msg.hwnd, GA_ROOT )
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    .WHILE TRUE
     INVOKE GetMessage, ADDR msg,NULL,0,0
     .BREAK .IF (!eax)
      invoke GetActiveWindow
;      invoke GetAncestor,msg.hwnd,GA_ROOT
      .if eax!=0
        mov ecx,eax
        invoke IsDialogMessage,ecx,ADDR msg
        .if eax==TRUE
           .continue
        .endif
     .endif
     INVOKE TranslateMessage, ADDR msg
     INVOKE DispatchMessage, ADDR msg
    .ENDW
    mov     eax,msg.wParam
Результат ― в аттаче. Попробуйте, у меня вроде работает с любым количеством диалогов. И кстати, привет от Iczelion'а: теперь при активном основном окне ― ESCAPE и ENTER работают как «About» и «Exit», не пугайтесь

(Однако не таит ли такая самонаводящаяся петля подвоха окну в бэкграунде?..)

Ну, так научил нас Iczelion, как «использовать диалоговое окно в качестве основного»?

А это как посмотреть.

На мой взгляд, подлинная роль Iczelion'а ― роль отличного стартера. Он действительно помогает начинающему в WIN API побыстрее сориентироваться и начать осмысленное движение.

На этом этапе, конечно, научил ― брать окно готовеньким из ресурсов при помощи CreateDialog*, DialogBox* и шаблонов DIALOG(EX).


Однако позже, при повторных «проходах» по Iczelion'у, вдруг доходит, что о диалоговом-то окне мы узнали ровно столько, сколько и о DefDlgProc ноль!

И тем, кому охота разобраться в «действительно интересной теме», необходимы другие источники знаний, не Iczelion и даже не Petzold.

Прежде всего вчитываемся в Dialog Box Programming Considerations, а потом идем на блог Raymond'а Chen'а («папаши» WinGUI'я):
The documentation does give the full story. I should have known, because I was the one who wrote that part of the documentation!"
(цитата из The secret life of GetWindowText).


Вот только несколько ссылок:
  1. A different type of dialog procedure
  2. Another different type of dialog procedure
  3. Modality, part 1: UI-modality vs code-modality
  4. Modality, part 2: Code-modality vs UI-modality
  5. Modality, part 3: The WM_QUIT message
  6. Modality, part 4: The importance of setting the correct owner for modal UI
  7. Modality, part 5: Setting the correct owner for modal UI
  8. Modality, part 6: Interacting with a program that has gone modal
  9. Modality, part 7: A timed MessageBox, the cheap version
  10. MsgWaitForMultipleObjects and the queue state
  11. Rescuing thread messages from modal loops via message filters
  12. Restating the obvious about the WM_COMMAND message
  13. The correct order for disabling and enabling windows
  14. The dialog manager, part 1: Warm-ups
  15. The dialog manager, part 2: Creating the frame window
  16. The dialog manager, part 3: Creating the controls
  17. The dialog manager, part 4: The dialog loop
  18. The dialog manager, part 5: Converting a non-modal dialog box to modal
  19. The dialog manager, part 6: Subtleties in message loops
  20. The dialog manager, part 7: More subtleties in message loops
  21. The dialog manager, part 8: Custom navigation in dialog boxes
  22. The dialog manager, part 9: Custom accelerators in dialog boxes
  23. The evolution of dialog templates - 32-bit Classic Templates
  24. The evolution of dialog templates - 32-bit Extended Templates
  25. The evolution of dialog templates - Summary
  26. The history of the Windows XP common controls
  27. What's so special about the desktop window?
  28. Why are dialog boxes initially created hidden?
  29. Waiting until the dialog box is displayed before doing something
  30. Why do we even have the DefWindowProc function?

По материалам блога издана книга «Practical Development Throughout the Evolution of Windows» (2006):
А от себя прилагаю
Некоторые подробности о диалогах: учебный диалог ExtraSpy и другие примеры


ExtraSpy - это генератор и тестер диалогов. Одновременно можно задействовать несколько (много) экземпляров ExtraSpy.


NB: все нижеследующее проверялось только на WinXP-pro-sp2.
  1. При пустом чекбоксе "lock F8" любое видимое окно можно зафиксировать, наведя на него курсор и нажав клавишу F8.
    Если при этом нажата и клавиша CTRL, то в зависимости от ситуации фиксируется либо (GetAncestor(GA_ROOT)), либо (GetWindow(GW_OWNER)), либо GUITHREADINFO.hwndMenuOwner.

    Кроме того, при отключенном таймере (т.е. при пустом чекбоксе "timer") можно в поле "hwnd" ввести 8-значную hex-запись hWnd.

    Например, на WinXP после ввода "00010014" зафиксируется старшее окно (системный класс #32769, константа HWND_DESKTOP), а после "00010016" - старшее message-only окно (системный класс "Message", константа HWND_MESSAGE, - см. WinTreeSnap).

    Отмена фиксации - снятием метки с чекбокса "lock F8".
  2. В ExtraSpy способ фиксации окна устанавливается вращением mouse wheel над статиком "hwnd.*" (id=105).

    В данной версии можно выбрать либо WindowFromPoint, либо - в сочетании с MapWindowPoints - RealChildWindowFromPoint или ChildWindowFromPointEx.

    В MSDN о различии между ChildWindowFromPoint и RealChildWindowFromPoint говорится следующее:

    ChildWindowFromPoint treats an HTTRANSPARENT area of a standard control the same as other parts of the control. In contrast, RealChildWindowFromPoint treats an HTTRANSPARENT area differently; it returns the child window behind a transparent area of a control. For example, if the point is in a transparent area of a groupbox, ChildWindowFromPoint returns the groupbox while RealChildWindowFromPoint returns the child window behind the groupbox.

    Однако в случае mirrored windows вылезает куда более существенное различие, о котором MSDN молчит. Т.е. MSDN утверждает, что If hWndFrom or hWndTo (or both) are mirrored windows (that is, have WS_EX_LAYOUTRTL extended style), MapWindowPoints will automatically adjust mirrored coordinates if you pass two or less points in lpPoints.

    Но на самом деле в случае WS_EX_LAYOUTRTL у какого-либо оконного предка связка RealChildWindowFromPoint+MapWindowPoints попросту не работает! Вот попробуйте дурдом с окошком из layoutrtl.rar при "hwnd.1"!

    Тогда как с ChildWindowFromPoint тут OK.
  3. Кнопки "CreateWnd", "CreateDlg", "DlgBox" и "MsgBox" предназначены для создания top-level диалогов соответственно из CreateWindowEx, CreateDialog*, DialogBox* и MessageBox*.

    Эти диалоги полностью воспроизводят интерфейс и функционал исходного диалога ExtraSpy, принадлежа тому же потоку.

    Если на указанные кнопки нажимать при помеченных чекбоксах "owned" и "lock F8" - то у диалога будет owner: предварительно зафиксированное окно.

    По сценарию не-owned диалоги равноправны: можно оставить только один (любой), остальные закрыть (даже исходный), а ExtraSpy будет работать, как работал.
  4. WM_ENTERIDLE и DS_NOIDLEMSG.

    Модальный owned диалог, созданный без стиля DS_NOIDLEMSG, шлет своему owner-у WM_ENTERIDLE (см. MSDN).

    Проверим: фиксируем окно самого ExtraSpy, метим чекбокс "owned", жмем "MsgBox" (либо освобождаем чекбокс "ds_noidlemsg" и жмем "DlgBox") - и наблюдаем индикацию приема WM_ENTERIDLE прямо на чекбоксе "ds_noidlemsg".

    Почти то же видим и после создания menu loop (вызовом системного или иного меню либо нажатием ALT или F10).

    Кое-какие подробности - в нижнем многострочном окне редактирования, находим вращением mouse wheel.

    Поскольку обычный MessageBox (можно вызвать R-кликом по кнопке "MsgBox") имеет предустановленный стиль DS_NOIDLEMSG, запрещающий посылку WM_ENTERIDLE (а последующая отмена этого стиля ничего не дает), - пришлось MessageBox хукнуть (единственное в ExtraSpy применение хука).

    Правда, все-таки можно было обойтись без хука, используя дополнительный поток, как в примере mb_ghost, см. ниже.

    Но зацепил промежуточный parent в момент HCBT_CREATEWND: его hWnd=00010016h, а это - старшее message-only окно (системный класс "Message")!

    Хотелось бы понять, что происходит. Исходников винды не имею, и был бы признателен обладателям других Win OS за инфу, что тут выскакивает у них.

    Чтобы легче было откликнуться на эту просьбу - предусмотрен тест на "ранние" owner и parent: M-кликом по кнопке "MsgBox".

    Из-за отсутствия контингента, согласного на M-клик и отклик, состряпана очередная демка, см. ниже Кто кому кем приходится в момент HCBT_CREATEWND

    Первоначальное намерение "не выдрючиваться" с MessageBox'ом и использовать хук только для отмены DS_NOIDLEMSG - было в конце концов похерено, и MessageBox стал-таки 4-ым вариантом ExtraSpy.

    А по ходу "выдрючивания" обнаружился глюк XP и Висты, см. ниже IsWindowMessageBox.
  5. После создания модальных owned диалогов при помощи кнопок "DlgBox" или "MsgBox" - окно owner-а, понятно, задизабливается.
    Однако функционал задизабленного ExtraSpy остается доступным, ибо кроме L-клика работает и R-клик по контролам (тут использована возможность "обходить" WS_DISABLED и EnableWindow в обработчике WM_SETCURSOR, подробности в HTSpy).
  6. R-клик в полях "id/hmenu", "userdata" или по строчкам комбобоксов "wndExtra" и "clsExtra" приводит к попытке xor (значение в поле),1, с целью узнать, доступно или нет данное поле.

    Внимание: "защиты от дурака" нет, так что бессознательные клики могут привести к падению ExtraSpy или приложения, окно которого зафиксировано в ExtraSpy (например - Explorer).

    (А UltraEdit подивил еще и таким сюрпризом: если его EditControl зафиксировать в ExtraSpy, поксорить поле "id/hmenu" и, забыв вернуться к исходному значению этого поля, закрыть UltraEdit - то, чтобы UltraEdit запустить снова, надо будет править его ini-файл!)
  7. M-клик по окну ExtraSpy включает/отключает индикацию счетчиков сообщений в message loop, WndProc и DlgProc, а также user/gdi хендлов.

    Прижимая без отжатия L/R кнопку мыши на заголовке окна, замечаем последствия модальности/немодальности. (Очевидны последствия и для TAB-навигации).
  8. При помеченном чекбоксе "template editor" можно менять WS/DS/WS_EX стили внутреннего DIALOGEX template (для "CreateDlg" и "DlgBox"):
    1. либо редактируя при отключенном таймере hex-значения в соответствующих полях с финальным R-кликом по их лейблу ("ws" или "ws_ex"),
    2. либо манипуляциями в нижнем многострочном окне редактирования: вращением mouse wheel выбрать WS/DS/WS_EX, R-кликом переключиться на последовательность битов, и L-даблклик по названию нужного бита
    (Переключение по mouse wheel требует, чтобы многострочное окно редактирования было НЕ в фокусе, тут сгодится шмяк по ближайшей кнопке "reposition").
  9. При пустом чекбоксе "template editor" и помеченном "lock F8" описанным выше образом модифицируются биты стилей предварительно зафиксированного окна.

    Например, зафиксированное окно делаем mirrored: вращением mouse wheel выбираем "ws_ex" стили, R-кликом переключаемся на последовательность битов, и L-даблклик по биту 400000 (т.е. WS_EX_LAYOUTRTL).
  10. Можно регистрировать собственные классы диалогов (перед "CreateWnd", "CreateDlg", "DlgBox"):
    при отключенном таймере заполняем поля "wndExtra", "clsExtra","style cs","class", и затем жмем кнопку "register".

    В ExtraSpy есть ограничение на регистрируемое имя класса диалога: должно состоять точно из 6 символов (как в "#32770").

    Ну, и в "wndExtra" надо вписать число не менее DLGWINDOWEXTRA (т.е. 30), подробности позже.

    После успешной регистрации имя класса диалога добавляется в комбобокс "class".

    Регистрация нужна, в частности, тогда, когда нужны другие объемы WndExtra и ClsExtra, ― после регистрации они не изменяемы (однако см. ниже трюк с WndExtra).
  11. Кнопка "unregister" делает, что обещает, при условии, что закрыты все окна соответствующего класса.
    Соответствующее имя класса из комбобокса изымается.
  12. Выбор имени класса в вышеупомянутом комбобоксе одновременно вписывает это имя в DIALOGEX template.
  13. Если при отключенном таймере ввести в поле "class" уже зарегистрированное имя класса (не обязательно диалога, а, скажем, "scrollbar") и R-кликнуть по лейблу "class" ― то в полях "wndExtra", "clsExtra" и "style cs"
    получим параметры этого класса, как результат GetClassInfoEx. Поскольку можно зарегистрировать свой, отличный от системного, класс с тем же названием (например ― "#32770"), ― то предусмотрена возможность посмотреть оба варианта: по лейблу "class" ― WM_RBUTTONDOWN для одного и WM_RBUTTONUP для другого.
  14. Анализатор класса (поле с

    Здесь первое имя (CombolBox) ― результат GetClassName, второе имя (ListBox) ― результат RealGetWindowClass, а в скобках ― результат WM_GETDLGCODE, который поясняется в нижнем многострочном окне редактирования.

    (+)

    Кстати, такое сочетание имен получаем на XP-pro-sp2 для CBS_SIMPLE-комбобокса только при запуске ExtraSpy без манифеста. Вообще, сопоставление вариантов запуска с манифестом/без манифеста небесполезно: например, замечаем различия в работе одноименных системных элементов управления в user32 и в comctl32 (версииhttp://www.cyberforum.ru/cgi-bin/latex.cgi? \geq 6), с перераспределением использования wndExtra и properties (так что в интересах любознательных манифест ExtraSpy не в ресурсах, а отдельным файлом).

    Тут ведь вот в чем дело: RealGetWindowClass просто-напросто не работает с comctl32 версииhttp://www.cyberforum.ru/cgi-bin/latex.cgi? \geq 6! Хорошо хоть
    #32770 не элемент управления
  15. Кнопка "reposition" ― для посылки предварительно зафиксированному окну сообщения DM_REPOSITION, и это ― какой-никакой тест окна на "диалоговость": если диалог хотя бы частично вне desktop area, то после посылки переместится в ближайшую часть desktop area. При отсутствии WS_EX_TOOLWINDOW диалог переберется даже не на desktop area, а на work area (desktop area минус system taskbar и application desktop toolbars). Но вот при пустом чекбоксе "ws_ex_controlparent" диалог и не пошевелится (в MSDN о такой особенности стиля WS_EX_CONTROLPARENT тишина).
  16. Для PUSHBUTTON-кнопок диалогов (только для них!) выдумано дополнительное качество DEFID, с соответствующим стилем BS_DEFPUSHBUTTON (о нем уже говорилось выше) и сообщениями DM_GETDEFID и DM_SETDEFID. При активном окне ExtraSpy и нажатой клавиши SHIFT вращение mouse wheel над произвольным элементом управления произвольного диалога определяет новое значение defid диалога как id этого элемента управления.

    (?)

    В порядке упражнения: проверьте, мне мерещится, или Raymond Chen действительно напутал с DEFPUSHBUTTON в Using the TAB key to navigate in non-dialogs?
  17. Поскольку значения DM_GETDEFID и DM_SETDEFID ― это соответственно WM_USER и WM_USER+1, то возможны конфликты с другими приложениями (см. MSDN).

    Например, попробуйте после запуска ExtraSpy драгдропить иконки файлов, или поработать с окном буфера обмена...

    Для временного отключения посылок DM_GETDEFID и введен чекбокс "def id".
  18. Еще одно отличие ресурсных диалогов от обычных окон: если в DIALOGEX template было задано WS_SYSMENU при отсутствии WS_THICKFRAME, WS_MAXIMIZEBOX и WS_MINIMIZEBOX, то даже если потом соответствующие биты стиля установить ― соответствующей функциональности диалогу не добавится.
    Ибо при указанных условиях диалог, в отличие от обычного окна, получает от MS куцее системное меню, а по воле MS состав системного меню "главнее" набора битов стиля.
    (Что исходный ExtraSpy и демонстрирует: попробуйте свернуть, развернуть или растянуть его окно. Хотя тут еще влияет, что за тема на винде: "классическая" или "Windows XP", с обычными для последней несуразностями).
    В случае custom'ного диалога успешно добавить эти стили все-таки можно и в оконной процедуре, но не позже, чем на WM_CREATE, то есть до "скукоживания" системного меню. В исходнике ExtraSpy такой вариант в WndProc закомментирован. Однако в любой момент наготове грубая сила кнопки "re-sysmenu": GetSystemMenu (hWnd, FALSE) + GetSystemMenu(hWnd,TRUE), и системное сменю в норме.
  19. Особенность модального диалога, созданного путем DialogBox*, ― стартовать видимым, даже если в ресурсах нет WS_VISIBLE, и даже если в обработчик WM_INITDIALOG добавить ShowWindow(SW_HIDE).

    Но скрыть модальный диалог при его запуске все-таки можно, причем несколькими способами (см. здесь и здесь):
    1. Ресурсный шаблон DIALOG(EX) ― без WS_VISIBLE, а ShowWindow(SW_HIDE) - в обработчике первого по счету WM_NCPAINT.
    2. В обработчике WM_WINDOWPOSCHANGING сбрасывать бит SWP_SHOWWINDOW (элемент .flags структуры WINDOWPOS по lParam).
  20. DLGWINDOWEXTRA

    В 10-ом уроке читаем:

    mov wc.cbWndExtra,DLGWINDOWEXTRA [...]

    Обычно этот параметр оставляется равным нулю, но если мы хотим зарегистрировать шаблон диалогового окна как класс окна, мы должны установить это параметр равным DLGWINDOWEXTRA.


    Но почему мы должны ― Iczelion не сообщает, продолжая "утаивать" существование и роль функции DefDlgProc
    Да, именно DefDlgProc, задействованная в каждом настоящем диалоге, требует в свое распоряжение первые DLGWINDOWEXTRA (=30) байтов WndExtra, т.е. те, что соответствуют значениям x=0...28 для GetWindowLong(hWnd,x).
    (Тут следовало бы расписать, какую роль играет каждый из байтов WndExtra в DefDlgProc, но пока отмечу лишь, что первые 3 дворда отданы под параметры DWL_MSGRESULT, DWL_DLGPROC и DWL_USER, см. MSDN).

    Однако вот какое соображение: в обязанности DefDlgProc входит определение DEFPUSHBUTTON etc, но что, если НЕ входит - потрошение ресурсов?
    Тогда почему бы для окон вроде Windows-калькулятора, которые хоть и извлекаются из ресурсов, но потом никак не используют DefDlgProc, ― не отказаться от DefDlgProc уже на стадии обработки ресурсов? Например ― выкинуть из процедуры CreateDialog* всякое использование DefDlgProc, сводя к минимуму требуемый размер WndExtra? Ну, у кого хватит знаний на такой грязный хак?
    (Кстати. Казалось бы, что мешает сэмулировать CreateDialog*/DialogBox* собственной процедурой обработки ресурсов с выдачей параметров для последующих CreateWindowEx без всяких требований к WndExtra. Но помехи есть. К примеру, вот ― на XP после CreateWindowEx (0,"Edit",0,WS_CHILD | WS_VISIBLE | WS_BORDER, ... ) создается Edit с нарисованной рамкой, без WS_BORDER и без HTBORDER! Тогда как Static ведет себя нормально. Похоже, требуется скрупулезная инвентаризация, а это так скучно
  21. Диалоговое окно в качестве основного ― варианты

    В 10-ом уроке приведены лишь два варианта, один с CreateDialogParam, другой с DialogBoxParam. На самом деле вариантов побольше, но обсуждать их пока не буду, кому понадобится ― разберется: main_variants.rar. Впрочем, и в исходнике ExtraSpy не один такой вариант.
  22. IsWindowDialog

    Между прочим, определить, является окно диалогом или нет, ― не запросто.

    Конечно, в списке кодов ошибок есть вроде бы подходящая формулировка:
    C
    1
    
    1420    0x058C    The window is not a valid dialog window (Окно не является окном диалога)
    Но вот соответствующее

    Explanation:

    An application, as part of its user interface, has tried to get user input from a window that does not have that capability


    По мне ― это не то, мне бы выход на DefDlgProc Тем не менее и коды ошибок в поле зрения ExtraSpy: окно редактирования cmouse wheel при курсоре над этим окном редактирования творит inc/dec кода).

    Казалось бы, можно положиться на RealGetWindowClass. Но когда RealGetWindowClass сигналит о предопределенном системном классе "
    #32770", то это значит только то, что в соответствующем приложении хотя бы раз срабатывала DefDlgProc.
    Пример NonDialog для наглядности:
    Кликните здесь для просмотра всего текста
    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
    
    .const
      id   equ 100
     .data
      _app db "NonDialog",0
      _btn db "Button",0
      _txt db "Test  RealGetWindowClass",0
     .data?
     .code
     
     WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
       .if uMsg==WM_DESTROY
         invoke PostQuitMessage,0
         mov eax,FALSE
       .elseif uMsg==WM_COMMAND && wParam==id
         invoke DefDlgProc,hWnd,WM_NULL,0,0
       .else
         invoke DefWindowProc,hWnd,uMsg,wParam,lParam
         .if uMsg==WM_NCHITTEST && eax==HTCLIENT
           mov eax,HTCAPTION
         .endif
       .endif
       ret
     WndProc endp
     
     CreateWnd proc uses ebx hInst:HINSTANCE
       local wc:WNDCLASSEX,msg:MSG
       mov    wc.cbSize,sizeof WNDCLASSEX
       mov wc.style,CS_DBLCLKS
       mov wc.cbClsExtra,0
       mov wc.cbWndExtra,DLGWINDOWEXTRA+6 ; (=36)
       mov    eax,hInst
       mov    wc.hInstance,eax  
       mov wc.hbrBackground,COLOR_WINDOW
       mov    wc.lpfnWndProc,offset WndProc
       mov wc.lpszMenuName,0
     ;  invoke LoadIcon,0,IDI_APPLICATION
       xor eax,eax
       mov wc.hIcon,eax
       mov wc.hIconSm,eax
     ;  invoke LoadCursor,0,IDC_HAND
       mov wc.hCursor,eax
       mov    wc.lpszClassName,offset _app
       invoke RegisterClassEx,addr wc
         invoke CreateWindowEx,WS_EX_TOPMOST OR WS_EX_CLIENTEDGE OR WS_EX_TOOLWINDOW,offset _app,offset _app,WS_SYSMENU,20,20,260,100,0,0,hInst,0
       mov ebx,eax
         invoke CreateWindowEx,0,offset _btn,offset _txt,WS_CHILD OR WS_VISIBLE OR BS_FLAT,20,20,210,30,ebx,id,hInst,0  
       invoke ShowWindow,ebx,SW_SHOWNORMAL
       invoke UpdateWindow,ebx
       .while TRUE
         invoke GetMessage,addr msg,0,0,0
         .break .if (!eax)
         invoke TranslateMessage,addr msg
         invoke DispatchMessage,addr msg
       .endw
       mov    eax,msg.wParam
       ret
     CreateWnd endp
     
     start:
         invoke GetModuleHandle,0
         invoke CreateWnd,eax
         invoke ExitProcess,eax
     end start
    Запускаем этот пример и фиксируем в ExtraSpy его окно. В поле "анализатора класса" видим: "NonDialog (0000)". А после нажатия кнопки "Test RealGetWindowClass" там уже "NonDialog / #32770 (0000)".

    То есть первое же обращение к DefDlgProc привело к изменению состояния WndExtra (сравните результаты R-клика по строчкам комбобокса "wndExtra" до и после). Но достаточно ли этого, чтобы окно считать диалогом?..

    Может, подходящий критерий ― DLGWINDOWEXTRA ? Но если окно имеет WndExtra длиной DLGWINDOWEXTRA, то это еще не значит, что окно ― диалог. А если любимый спай (скажем, Spy++) показывает, что длина WndExtra меньше DLGWINDOWEXTRA, то это еще не значит, что окно ― НЕ диалог.

    Ибо свою WndExtra диалог может "спрятать": после SetClassLong(GCL_CBWNDEXTRA,0) диалог остается диалогом, но его WndExtra становится невидимой для большинства спаев (Spy++ в том числе).

    Испытываем на ExtraSpy: отключаем таймер, вводим "0" в поле "wndExtra", R-кликаем по лейблу "wndExtra", и смотрим на WndExtra ExtraSpy'я через привычную нам тулзу.

    Конечно, ExtraSpy располагает и противоядием: если пометить чекбокс "wndExtra", то увидим первые 100 байтов спрятанной WndExtra (MSDN рекомендует задавать WndExtra и ClsExtra длиной не более 40 байтов, но посмотрите, сколько у системного контрола ScrollBar).

    Между прочим, этот трюк лишает ExtraSpy способности создавать диалоги "спрятанного" класса. В частности, если этот класс ― системный #32770, то R-клик по "MsgBox" будет давать осечку. До тех пор, пока SetClassLong(GCL_CBWNDEXTRA) не отыграет назад.
    (+)

    Раз уж упомянут Spy++...

    У меня эта знаменитая тулза всегда под рукой. Поскольку как перехватчик сообщений полностью устраивает (пока .

    А вот как оконный спай огорчает: не все окна ухватывает, и даже, бывает, нагло врет.

    Скажем, если создать окно-недиалог с именем класса "#32770" (можно-можно, см. MSDN), но при этом с wc.style=wc.cbClsExtra=wc.cbWndExtra=0, то Spy++ почему-то довольствуется GetClassInfoEx для системного класса "#32770" и безо всякого анализа нашего окна извещает о присутствии DLGWINDOWEXTRA и CS_SAVEBITS|CS_DBLCLKS, коих нет и в помине.

    (А если вместо "#32770" задать "#32768" ― то и вообще откажется трудиться: "The specified window cannot be spied upon. Windows will not allow access to the message stream for this window.")

    И еще: Spy++ "виновен" в том, что ввел в моду внешне эффектную примочку ― прицел-"потаскуху", так что теперь сплошь и рядом гордо величают очередной самопал "аналогом Spy++" именно из-за наличия собственной "потаскухи" (пусть даже в "аналоге" нет и намека на перехват сообщений).

    Однако именно "потаскуха" крайне ограничивает возможности оконного спая.

    Отсюда и деликатное предложение заменить в Spy++ "потаскуху" "прицепчиком" .
  23. IsWindowMessageBox, или дополнение ко 2-му уроку Iczelion'а

    MessageBox во 2-ом уроке призван взбодрить начинающего тем, как, оказывается, просто получить полнофункциональную Windows-программу с окошком. Но MessageBox сам по себе совсем не тривиален...

    К тому, что о нем как о модальном диалоге уже сказано выше, прибавим, что ему не требуются ресурсы, как DialogBox'у, и его окно попросту вычисляется по параметру uType и длинам текстов заголовка и сообщения.
    1. И вот первый "секрет" Message Box'а: он копируется в буфер обмена.

      Подробности получаем после R-клика по кнопке "MsgBox":

      [i]To know whether the window is the message box: activate the window, Ctrl+C / Ctrl+Ins and look on clipboard.

      ExtraSpy, построенный на Message Box'е, после R-клика по его верхнему левому полю (ID=131) переключается из "красного" состояния в "черное", в котором уже готов к копированию. Повторный R-клик отыграет назад в "красное", а M-клик - окончательно вернет Message Box в первобытное состояние:
    2. Еще сюрприз: на XP PostMessage(WM_TIMER,0,0) закрывает окно Message Box'а, аки PostMessage(WM_CLOSE,0,0)!

      Зкспресс-проверка: активируйте окно ExtraSpy, наведите курсор на произвольный Message Box, прижмите CTRL и крутаните mouse wheel, ― в результате Message Box получит PostMessage(WM_TIMER,0,0) и тут же "даст дуба".

      Похоже, нововведенный на XP недокументированный MessageBoxTimeout, автоматически закрывающийся по истечении
      заданного периода (именно по WM_TIMER), затронул и обычный Message Box... (В исходнике ExtraSpy закомментирован пример c MessageBoxTimeout).

      Как мне сообщили добрые люди, на Win2k функция PostMessage(hWndMsgBox,WM_TIMER,0,0) не закрывает, а на Windows Vista закрывает. Выходит ― глюк, как на Windows XP, так и на Windows Vista.
    3. Еще одна особенность Message Box'а на Windows XP: его USERDATA изначально занята (но какого черта? ведь USERDATA!).

      Если изменить значение USERDATA (например, xor единичкой правым кликом по соответствующему элементу управления ExtraSpy), то закрываться Message Box будет ой, как скверно...
      Что пример mb_ghost в итоге и показывает, а вместе с тем и еще кое-что:
      1. даже после изменения USERDATA Message Box вплоть до закрытия абсолютно работоспособен,
      2. FrameRector годится для слежения даже за гиблыми окошками,
      3. в виндах обитает жуткий плод мрачной фантазии кого-то из недр MS ― окно класса Ghost.
      После запуска видим слегка навороченный Message Box. Кнопка "Ghost Off" (в девках "Help") ― это триггер для USERDATA, "On"/"Off". Пытаем Message Box по всякому (для того и наворочен), видим, что OK.
      Потом напускаем FrameRector, наводим курсор на Message Box так, чтобы рамка по его периметру стала желтой (тогда он выбран), и включаем CAPS LOCK (т.е. фильтруем окна по процессу), после чего "лишние" рамки исчезают.
      Теперь уводим Message Box подальше от центра и нажимаем "X"-кнопку заголовка Message Box'а. Тут же в центр экрана сваливается окно dwwin.exe, но мы на него пока пилюем, и оттаскиваем в сторону то, что считаем Message Box-ом. И видим, что контуры Message Box-а остались на старом месте, так как он стал сплошным HTNOWHERE (HT 0), мы же оттаскиваем невесть что. Выключив CAPS LOCK и наведя курсор на это нечто, читаем вверху экрана: Ghost...
      Во как.
    4. Мессаджбокс - оборотень

      В MSDN-овской статье "MessageBox Function" помимо прочего сообщается о 3-х особенных флагах:
      • MB_DEFAULT_DESKTOP_ONLY
        Windows NT/2000/XP: Same as desktop of the interactive window station.

        Windows NT/2000/XP: Same as MB_SERVICE_NOTIFICATION except that the system will display the message box only on the default desktop of the interactive window station. For more information, see Window Stations.

        Windows NT 4.0 and earlier: If the current input desktop is not the default desktop, MessageBox fails.

        Windows 2000/XP: If the current input desktop is not the default desktop, MessageBox does not return until the user switches to the default desktop.

        Windows 95/98/Me: This flag has no effect.
      • MB_SERVICE_NOTIFICATION
        Windows NT/2000/XP: The caller is a service notifying the user of an event. The function displays a message box on the current active desktop, even if there is no user logged on to the computer.

        Terminal Services: If the calling thread has an impersonation token, the function directs the message box to the session specified in the impersonation token.

        If this flag is set, the hWnd parameter must be NULL. This is so the message box can appear on a desktop other than the desktop corresponding to the hWnd.

        For more information on the changes between Microsoft Windows NT 3.51 and Windows NT 4.0, see Remarks.

        For information on security considerations in regard to using this flag, see Interactive Services.
      • MB_SERVICE_NOTIFICATION_NT3X

        Windows NT/2000/XP: This value corresponds to the value defined for MB_SERVICE_NOTIFICATION for Windows NT version 3.51.

        For more information on the changes between Windows NT 3.51 and Windows NT 4.0, see Remarks.
        [...]
        Windows NT/2000/XP: The value of MB_SERVICE_NOTIFICATION changed starting with Windows NT 4.0. Windows NT 4.0 provides backward compatibility for pre-existing services by mapping the old value to the new value in the implementation of MessageBox. This mapping is only done for executables that have a version number less than 4.0, as set by the linker.

        To build a service that uses MB_SERVICE_NOTIFICATION, and can run on both Microsoft Windows NT 3.x and Windows NT 4.0, you can do one of the following.

        At link-time, specify a version number less than 4.0

        At link-time, specify version 4.0. At run-time, use the GetVersionEx function to check the system version. Then when running on Windows NT 3.x, use MB_SERVICE_NOTIFICATION_NT3X; and on Windows NT 4.0, use MB_SERVICE_NOTIFICATION.
      Тут штука в том, что при наличии такого флага и соблюдении указанных выше условий окно MB будет принадлежать не нашему приложению, а одному из потоков процесса CSRSS!

      А если запускать MessageВox из дополнительного потока, то получим самозакрытие нашего приложения, для пущего эффекта: оно закрылось, а MessageВox нет!

      Более того, в этом случае (по крайней мере на XP-pro-sp2) работает и MB_SERVICE_NOTIFICATION_NT3X, при условии, что ранее в этом дополнительном потоке из user32.dll ничего не вызывалось (кроме разве что wsprintf или wvsprintf).

      А поскольку MB_SERVICE_NOTIFICATION_NT3X=0x00040000=MB_TOPMOST (!) ― код можно "замаскировать":
      Кликните здесь для просмотра всего текста
      Assembler
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
      .data
       _msg db "MsgBox",0
      .data?
      .code
       
      ThreadProc proc lparam:LPARAM
        invoke MessageBox,0,offset _msg,0,MB_TOPMOST
        ret
      ThreadProc endp
       
      start:
        invoke CreateThread,0,0,offset ThreadProc,0,0,0
        invoke CloseHandle,eax
        invoke Sleep,10
        invoke ExitProcess,0
      end start
      csrss_msgbox

      Попробуйте запустить сразу несколько экземпляров этого примера.
      А также при запущенном МessageВox ― подетектите Process Hunter'ом by Ms-Rem. Затем закройте MessageВox и снова подетектите. Думаю, возникнут вопросы.

      На посошок ― контрпример. В отличие от MessageBox, MessageBoxEx, MessageBoxIndirect, MessageBoxTimeout и ShellMessageBox (shell32, XP) - SoftModalMessageBox из user32 (XP) эти крутые флаги игнорирует. Недокументирован, но все тут:
      Кликните здесь для просмотра всего текста
      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
      
      .386
      .model flat,stdcall
      option casemap:none
       
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
       
      ; MSGBOXPARAMS struct
      ;     cbSize              DWORD ?
      ;     hwndOwner           DWORD ?
      ;     hInstance           DWORD ?
      ;     lpszText            DWORD ?
      ;     lpszCaption         DWORD ?
      ;     dwStyle             DWORD ?
      ;     lpszIcon            DWORD ?
      ;     dwContextHelpId     DWORD ?
      ;     lpfnMsgBoxCallback  DWORD ?
      ;     dwLanguageId        DWORD ?
      ; MSGBOXPARAMS ends       
       
       MSGBOXDATA struct       
           params              MSGBOXPARAMS 
           pwndOwner           DWORD ?
           wLanguageId         DWORD ?
           pidButton           DWORD ?         ; // Array of button IDs
           ppszButtonText      DWORD ?         ; // Array of button text strings
           cButtons            DWORD ?
           DefButton           DWORD ?
           CancelId            DWORD ?
           Timeout             DWORD ?
       MSGBOXDATA ends
       
       .const
        num                            equ 10
      ; MB_SERVICE_NOTIFICATION        equ 00200000h
      ; MB_SERVICE_NOTIFICATION_NT3X   equ 00040000h
      ; MB_TOPMOST                     equ 00040000h
      ; MB_DEFAULT_DESKTOP_ONLY        equ 00020000h
       
      .data
       _user32  dw 'u','s','e','r','3','2',0
       _SMMB    db "SoftModalMessageBox",0
      .data? 
      .code
       
      CallProc proc uses ebx lparam:LPARAM
        local mbd:MSGBOXDATA
        local bufid[num]:DWORD
        local bufstr[num]:DWORD
        lea eax,bufid
        lea edx,bufstr
        xor ecx,ecx
        .while ecx!=num
          mov ebx,ecx
          inc ebx
          mov dword ptr[eax+4*ecx],ebx
          mov dword ptr[edx+4*ecx],offset _user32
          inc ecx
          inc ebx
        .endw
        mov mbd.params.cbSize,sizeof MSGBOXPARAMS
        mov mbd.params.hwndOwner,0
        mov mbd.params.lpszText,offset _user32
        mov mbd.params.lpszCaption,offset _user32
        mov mbd.params.dwStyle,MB_ICONQUESTION or MB_SERVICE_NOTIFICATION or MB_TOPMOST or MB_DEFAULT_DESKTOP_ONLY ; or MB_RIGHT
        mov mbd.pwndOwner,0
        mov mbd.wLanguageId,0
        mov mbd.pidButton,eax
        mov mbd.ppszButtonText,edx
        mov mbd.cButtons,num
        mov mbd.DefButton,4
        mov mbd.CancelId,0
        mov mbd.Timeout,-1
        lea eax,mbd
        push eax
        call lparam
        ret
      CallProc endp
       
      start:  invoke LoadLibraryW,offset _user32
        push eax
        invoke GetProcAddress,eax,offset _SMMB
        invoke CallProc,eax
        call FreeLibrary
        invoke ExitProcess,0
      end start
  24. Кто кому кем приходится в момент HCBT_CREATEWND, или дополнение к 24-ому уроку Iczelion'а (Windows Hooks)

    Из MSDN'овской статьи "CBTProc Function" о HCBT_CREATEWND:

    At the time of the HCBT_CREATEWND notification, the window has been created, but its final size and position may not have been determined and its parent window may not have been established. It is possible to send messages to the newly created window, although it has not yet received WM_NCCREATE or WM_CREATE messages.

    Established или не established, но на XP-pro-sp2 в этот момент GetAncestor(GA_PARENT) упорно выдает 00010016h. А на на XP-pro-sp2 (sp3? 2k? 2k3? Vista?) это - значение hWnd старшего message-only окна (об иерархии message-only окон см. здесь, пост #24):

    GetDesktopWindow = GetAncestor(FindWindowEx(HWND_DESKTOP,0,0,0),GA_PARENT)=00010014h

    'GetMessageWindow' equ GetAncestor(FindWindowEx(HWND_MESSAGE,0,0,0),GA_PARENT)=00010016h

    Хотя в случае Ms-Rem'овского скрывателя окон, гробящего последнюю формулу, придется поконкретнее: GetAncestor (FindWindowEx(HWND_MESSAGE,0,"#32774",0),GA_PARENT).


    Приаттаченный cbt_hook мониторит HCBT_CREATEWND и другие CBT события:



    В колонке "param" при каждом HCBT_CREATEWND получаем один и тот же удивительный результат GetAncestor(GA_PARENT). Числовой казус, или на XP-sp2 (sp3? 2k? 2k3? Vista?) любое окно и правда первоначально message-only?..


    Повторенный в другой ветке, этот вопрос получил-таки положительный ответ!

    Twister

    Проверил ― система, и правда, изначально высталяет родителя в HWND_MESSAGE, затем вызывает цепочку хуков, и только потом ищет (если нужно) и устанавливает реальный Parent.

    [...] Да, HWND_MESSAGE назначается системой всегда, на всей NT-линейке.


    (Попутно замечаем, что HCBT_CREATEWND выпрыгивает для каждого окна, а HCBT_DESTROYWND ― только для top-level...

    А также убеждаемся, что иногда ловится HCBT_MINMAX от message-only окна класса #32774, принадлежащего CSRSS, и от консоли, хотя взаимоотношения user32-хуков с CSRSS и консолью известно какие: никакие...)
  25. Модальные диалоги и WH_MSGFILTER/WH_SYSMSGFILTER
Прикрепленные файлы: extraspy_081001.rar


________________________________
© Mikl___ 2013
4
Миниатюры
Сам себе Iczelion   Сам себе Iczelion   Сам себе Iczelion  

Сам себе Iczelion  
Изображения
 
Вложения
Тип файла: rar cbt_hook.rar (9.2 Кб, 65 просмотров)
Тип файла: rar csrss_msgbox.rar (1.2 Кб, 62 просмотров)
Тип файла: rar main_variants.rar (13.9 Кб, 62 просмотров)
Тип файла: rar mb_ghost.rar (2.7 Кб, 61 просмотров)
Тип файла: rar HideDialogBox.rar (2.1 Кб, 60 просмотров)
Тип файла: rar nondialog.rar (1.8 Кб, 62 просмотров)
Тип файла: zip systimages.zip (4.2 Кб, 63 просмотров)
Тип файла: zip tut11-1-k.zip (3.4 Кб, 67 просмотров)
Тип файла: rar layoutrtl.rar (1.7 Кб, 69 просмотров)
Mikl___
Заблокирован
Автор FAQ
12.01.2013, 14:58  [ТС] #35
Win32 API. Урок 10b. Создания диалогового окна через CreateDialogParam и DlgProc и WndProc
Урок сделан по мотивам Iczelion и "main variants" от kero
Скачайте пример.
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 1214 bytes
du  macro string
    irpc c,<string>
    dw '&c'
    endm
    dw 0
    endm
.code
exebase     equ 400000h
;-----------------------------------------------------------------
; 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 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
;------------------------------------------------------------------
IDM_GETTEXT     equ 0
IDM_CLEAR       equ 1
IDM_EXIT        equ 2
IDC_BUTTON      equ 3
IDC_EXIT        equ 4
IDC_EDIT        equ 5
IDC_MENU    equ 100
IDC_DIALOG  equ 200
lang        equ 409h
main:
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 1
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table-optional_header
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_RELOCS_STRIPPED 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 end_import-start
Size_of_init_data   dd 0
Size_of_uninit_data dd 0
entry_point     dd start
base_of_code        dd start
base_of_data        dd 0
image_base      dd exebase
e_lfanew        dd ntHeader-dosHeader;section alignment
file_alignment      dd 4
OS_version_major_minor  dd 4
image_version_major_minor dd 0
subsystem_version_major_minor dd 4
reserved1       dd 0
size_of_image       dd end_import
size_of_header      dd start
checksum        dd 0
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 100000h
Stack_commit        dd 1000h
Heap_allocation     dd 100000h
Heap_commit     dd 1000h
loader_flag     dd 0
number_of_dirs      dd (section_table-export_RVA)/8
export_RVA          dd 0
export_size         dd 0
import_RVA          dd import
import_size         dd end_import-import
resuorce_RVA        dd resource
resuorce_size           dd end_resource-resource
;------------------------------------------------
section_table       dd 'xet.','t'
virtual_size        dd 0;exeption_RVA
virtual_address     dd start;exeption_size
Physical_size       dd end_import-start;security_RVA
Physical_offset     dd start
Relocations         dd 0
Linenumbers     dd 0
Relocations_and_Linenumbers_count dd 0
Attributes              dd 0
;---------------------------------------------------------
start:  xor ebx,ebx
    push ebx
    push offset DlgProc+exebase
    push ebx
    push IDC_DIALOG
    push 400000h
    call CreateDialogParam+exebase
        sub esp,sizeof(MSG)+4
    mov edi,esp
    mov [edi+sizeof(MSG)],eax;mov hDlg,eax
message_loop: push ebx
    push ebx
    push ebx
    push edi
    call GetMessage+exebase
    xchg eax,ecx
    jecxz exit_msg_loop
    push edi
    push [edi+sizeof(MSG)]
    call IsDialogMessage+exebase
    test eax,eax
    jnz short message_loop 
    push edi
    call DispatchMessage+exebase
        jmp short message_loop
exit_msg_loop: add esp,sizeof(MSG)+4
    retn
WndProc:
hDlg    equ [ebp+8]
uMsg    equ [ebp+0Ch]
wParam  equ [ebp+10h]
lParam  equ [ebp+14h]
    enter 96,0
    mov esi,esp;lea esi,buffer
    mov eax,uMsg
    mov edi,hDlg
    sub eax,WM_CLOSE
    jz wmCLOSE
        sub eax,WM_COMMAND-WM_CLOSE
        jz wmCOMMAND
        leave
    jmp DefDlgProc+exebase
wmCOMMAND: mov ax,[wParam]
        cmp [lParam],ebx;0
        jz short @f; выбрали меню
; выбрали кнопку или EditBox
        cmp [wParam+2],bx;IF BN_CLICKED
    jne short wmBYE
@@:     jmp dword ptr [handlers+exebase+eax*4]
GETTEXT: push 96
    push esi
    push IDC_EDIT
    push edi
        call GetDlgItemText+exebase
    push ebx
    push offset AppName+exebase
    push esi
    push ebx
    call MessageBox+exebase
    jmp short wmBYE
SAYHELLO: push offset TestString+exebase
    jmp @f
CLEAR:  push ebx
@@: push IDC_EDIT
    push edi
    call SetDlgItemText+exebase
        jmp short wmBYE
wmCLOSE: push edi
    call DestroyWindow+exebase
    push ebx
    call PostQuitMessage+exebase
a0: xor eax,eax
wmBYE:  leave
    retn 10h
DlgProc:
        cmp dword ptr [esp+8],WM_INITDIALOG;cmp uMsg,WM_INITDIALOG
    jne @f
    push offset WndProc+exebase
    push GWL_WNDPROC
    push dword ptr [esp+4+8]
    call SetWindowLong+exebase
@@:     xor eax,eax
    retn 16
handlers dd GETTEXT+exebase,CLEAR+exebase,wmCLOSE+exebase,\
            SAYHELLO+exebase,wmCLOSE+exebase
AppName db "Our Second Dialog Box",0
TestString db "Wow! I'm in an edit box now",0
;----------------------------------------------------------
align 4
resource:       
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 2;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0,m1-resource,8000h;номер типа ресурса
dw RT_DIALOG,0,d1-resource,8000h; если во 2-ом слове установлен старший 
;бит - есть ссылка на оглавление второго уровня. В 1-ом слове смещение 
;второго оглавления относительно начала раздела ресурсов
m1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw IDC_MENU,0,m2-resource,8000h
; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего 
;оглавления относительно начала раздела ресурсов
m2:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, 
;который используется данным ресурсом 16 * SUBLANG_ + LANG_
dw lang,0,m3-resource,0
m3:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu
Size1       dd end_menu-menu
CodePage1   dd 0
Reserved1   dd 0
d1:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
dw IDC_DIALOG,0,d2-resource,8000h
d2:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
dw lang,0,d3-resource,0;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
d3: 
OffsetToData2   dd dialog
Size2       dd end_dialog-dialog
CodePage2   dd 0
Reserved2   dd 0
 
menu: 
dw 0,   0,POPUP or ENDMENU
du <Test Controls>
dw MFT_STRING or MFS_ENABLED,IDM_GETTEXT
du <Get Text>
dw MFT_STRING or MFS_ENABLED,IDM_CLEAR
du <Clear Text>
dw MENUBREAK,0
dw 0;du <>;NOTEXT
dw MFT_STRING or MFS_ENABLED or ENDMENU,IDM_EXIT
du <&Exit>
end_menu:
dialog: 
style1 dd DS_CENTER or WS_MINIMIZEBOX or WS_VISIBLE or WS_CAPTION \
or WS_SYSMENU;DS_MODALFRAME | 
dwExtendedStyle1 dd 0
cdit1 dw 3 ;число элементов управления, входящих в состав диалогового окна 
x1    dw 10;отступ левой границы окна от левой границы экрана
y1    dw 10;отступ верхней границы окна от верхней границы экрана
cx1   dw 205;ширина окна
cy1   dw 60;высота окна
      dw 0FFFFh;есть меню у диалога (=FFFF) или меню нет (=0)
      dw IDC_MENU;идентификатор меню
      dw 0
CAPTION: du <CreateDialogParam+DlgProc+WndProc>;заголовок диалога
;------------------------------------------------------
;элементы управления диалога    
u1:
style2 dd ES_LEFT or ES_AUTOHSCROLL or WS_CHILD or WS_VISIBLE \
or WS_BORDER or WS_TABSTOP;50810080h;
dwExtendedStyle2 dd 0
x2  dw 15;x-координаты верхнего левого угла
y2  dw 17;y-координаты верхнего левого угла
cx2 dw 111;ширина объекта управления
cy2 dw 13;высота объекта управления
id2 dw IDC_EDIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления
dw 0
dw 0;терминатор
;---------------------------------------------------
u2:
style3 dd BS_DEFPUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle3 dd 0
x3  dw 141;x-координаты верхнего левого угла
y3  dw 10;y-координаты верхнего левого угла
cx3 dw 52;ширина объекта управления
cy3 dw 14;высота объекта управления
id3 dw IDC_BUTTON;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <Say Hello>;надпись на объекте управления
dw 0;терминатор
;----------------------------------------------------
u3:
style4 dd BS_PUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle4 dd 0
x4  dw 141;x-координаты верхнего левого угла
y4  dw 26
cx4 dw 52
cy4 dw 13
id4 dw IDC_EXIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <E&xit>;надпись на объекте управления    
dw 0;терминатор
;----------------------------------------------------
end_dialog:
end_resource:
;----------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,0
user32_table:
DispatchMessage         dd _DispatchMessage
GetMessage              dd _GetMessage
PostQuitMessage     dd _PostQuitMessage
MessageBox      dd _MessageBox
IsDialogMessage     dd _IsDialogMessage
SetDlgItemText      dd _SetDlgItemText
CreateDialogParam   dd _CreateDialogParam
GetDlgItemText      dd _GetDlgItemText
SetWindowLong       dd _SetWindowLong
DefDlgProc      dd _DefDlgProc
DestroyWindow       dd _DestroyWindow
                        dw 0
_GetMessage     db 0,0,'GetMessageA'
_DefDlgProc     db 0,0,'DefDlgProcA'
_SetWindowLong      db 0,0,'SetWindowLongA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_CreateDialogParam  db 0,0,'CreateDialogParamA'
_PostQuitMessage    db 0,0,'PostQuitMessage'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_IsDialogMessage    db 0,0,'IsDialogMessageA'
_DestroyWindow      db 0,0,'DestroyWindow'
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
end_import:
end main

_______________________________
© Mikl___ 2013


Win32 API. Урок 10c. Создания диалогового окна через CreateDialogParam и DlgProc
Урок сделан по мотивам Iczelion и "main variants" от kero


Скачайте пример.
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 1121 bytes
du  macro string
    irpc c,<string>
    dw '&c'
    endm
    dw 0
    endm
.code
exebase     equ 400000h
; -----------------------------------------------------------------
; 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 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
;-------------------------------------------------------
IDM_GETTEXT     equ 0
IDM_CLEAR       equ 1
IDM_EXIT        equ 2
IDC_BUTTON      equ 3
IDC_EXIT        equ 4
IDC_EDIT        equ 5
IDC_MENU    equ 100
IDC_DIALOG  equ 200
lang        equ 409h
main:
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 1
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table-optional_header;
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_RELOCS_STRIPPED 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 end_import-start;
Size_of_init_data   dd 0
Size_of_uninit_data dd 0
entry_point     dd start
base_of_code        dd start
base_of_data        dd 0
image_base      dd exebase
e_lfanew        dd ntHeader-dosHeader;section alignment
file_alignment      dd 4
OS_version_major_minor  dd 4
image_version_major_minor dd 0
subsystem_version_major_minor dd 4
reserved1       dd 0
size_of_image       dd end_import
size_of_header      dd start
checksum        dd 0
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 100000h
Stack_commit        dd 1000h
Heap_allocation     dd 100000h
Heap_commit     dd 1000h
loader_flag     dd 0
number_of_dirs      dd (section_table-export_RVA)/8
export_RVA          dd 0
export_size         dd 0
import_RVA          dd import
import_size         dd end_import-import
resuorce_RVA        dd resource
resuorce_size           dd end_resource-resource
;------------------------------------------------
section_table       dd 'xet.','t'
virtual_size        dd 0;exeption_RVA
virtual_address     dd start;exeption_size
Physical_size       dd end_import-start;security_RVA
Physical_offset     dd start
Relocations         dd 0
Linenumbers     dd 0
Relocations_and_Linenumbers_count dd 0
Attributes              dd 0
;---------------------------------------------------------
start:  xor ebx,ebx
    push ebx
    push offset DlgProc+exebase
    push ebx
    push IDC_DIALOG
    push 400000h
    call CreateDialogParam+exebase
        sub esp,sizeof(MSG)+4
    mov edi,esp
    mov [edi+sizeof(MSG)],eax;mov hDlg,eax
message_loop: push ebx
    push ebx
    push ebx
    push edi
    call GetMessage+exebase
    xchg eax,ecx
    jecxz exit_msg_loop
    push edi
    push [edi+sizeof(MSG)]
    call IsDialogMessage+exebase
    test eax,eax
    jnz short message_loop 
    push edi
    call DispatchMessage+exebase
        jmp short message_loop
exit_msg_loop: add esp,sizeof(MSG)+4
    retn
DlgProc:
hDlg    equ [ebp+8]
uMsg    equ [ebp+0Ch]
wParam  equ [ebp+10h]
lParam  equ [ebp+14h]
    enter 96,0
    mov esi,esp;lea esi,buffer
    mov eax,uMsg
    mov edi,hDlg
    sub eax,WM_CLOSE
    jz wmCLOSE
        sub eax,WM_COMMAND-WM_CLOSE                     
    jne short a0
wmCOMMAND: mov ax,[wParam]
        cmp [lParam],ebx;0
        jz short @f; выбрали меню
; выбрали кнопку или EditBox
        cmp [wParam+2],bx;IF BN_CLICKED
    jne short wmBYE
@@:     jmp dword ptr [handlers+exebase+eax*4]
GETTEXT: push 96
    push esi
    push IDC_EDIT
    push edi
        call GetDlgItemText+exebase
    push ebx
    push offset AppName+exebase
    push esi
    push ebx
    call MessageBox+exebase
    jmp short wmBYE
SAYHELLO: push offset TestString+exebase
    jmp @f
CLEAR:  push ebx
@@: push IDC_EDIT
    push edi
    call SetDlgItemText+exebase
        jmp short wmBYE
wmCLOSE: push edi
    call DestroyWindow+exebase
    push ebx
    call PostQuitMessage+exebase
a0: xor eax,eax
wmBYE:  leave
    retn 10h
 
handlers dd GETTEXT+exebase,CLEAR+exebase,wmCLOSE+exebase,\
SAYHELLO+exebase,wmCLOSE+exebase
AppName db "Our First Dialog Box",0
TestString db "Wow! I'm in an edit box now",0
;----------------------------------------------------------
align 4
resource:       
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 2;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0,m1-resource,8000h;номер типа ресурса
dw RT_DIALOG,0,d1-resource,8000h; если во 2-ом слове установлен старший 
;бит - есть ссылка на оглавление второго уровня. В 1-ом слове смещение 
;второго оглавления относительно начала раздела ресурсов
m1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw IDC_MENU,0,m2-resource,8000h
;если во 2-ом слове установлен старший бит - есть ссылка на 
;оглавление третьего уровня. В 1-ом слове смещение третьего 
;оглавления относительно начала раздела ресурсов
m2:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, 
;который используется данным ресурсом 16 * SUBLANG_ + LANG_
dw lang,0,m3-resource,0
m3:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu
Size1       dd end_menu-menu
CodePage1   dd 0
Reserved1   dd 0
d1:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
dw IDC_DIALOG,0,d2-resource,8000h
d2:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
dw lang,0,d3-resource,0;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
d3: 
OffsetToData2   dd dialog
Size2       dd end_dialog-dialog
CodePage2   dd 0
Reserved2   dd 0
 
menu: 
dw 0,   0,POPUP or ENDMENU
du <Test Controls>
dw MFT_STRING or MFS_ENABLED,IDM_GETTEXT
du <Get Text>
dw MFT_STRING or MFS_ENABLED,IDM_CLEAR
du <Clear Text>
dw MENUBREAK,0
dw 0;du <>;NOTEXT
dw MFT_STRING or MFS_ENABLED or ENDMENU,IDM_EXIT
du <&Exit>
end_menu:
dialog: 
style1 dd DS_CENTER or WS_MINIMIZEBOX or WS_VISIBLE or WS_CAPTION or \
WS_SYSMENU ;DS_MODALFRAME | 
dwExtendedStyle1 dd 0
cdit1 dw 3 ;число элементов управления, входящих в состав диалогового окна 
x1    dw 10;отступ левой границы окна от левой границы экрана
y1    dw 10;отступ верхней границы окна от верхней границы экрана
cx1   dw 205;ширина окна
cy1   dw 60;высота окна
      dw 0FFFFh;есть меню у диалога (=FFFF) или меню нет (=0)
      dw IDC_MENU;идентификатор меню
      dw 0
CAPTION: du <CreateDialogParam+DlgProc>;заголовок диалога
;------------------------------------------------------
;элементы управления диалога    
u1:
style2 dd ES_LEFT or ES_AUTOHSCROLL or WS_CHILD or WS_VISIBLE or \
 WS_BORDER or WS_TABSTOP;50810080h;
dwExtendedStyle2 dd 0
x2  dw 15;x-координаты верхнего левого угла
y2  dw 17;y-координаты верхнего левого угла
cx2 dw 111;ширина объекта управления
cy2 dw 13;высота объекта управления
id2 dw IDC_EDIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления, если равен FFFF - стандартный элемент 
;управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления
dw 0
dw 0;терминатор
;---------------------------------------------------
u2:
style3 dd BS_DEFPUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle3 dd 0
x3  dw 141;x-координаты верхнего левого угла
y3  dw 10;y-координаты верхнего левого угла
cx3 dw 52;ширина объекта управления
cy3 dw 14;высота объекта управления
id3 dw IDC_BUTTON;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент 
;управления
dw BUTTON;тип объекта управления 
du <Say Hello>;надпись на объекте управления
dw 0;терминатор
;----------------------------------------------------
u3:
style4 dd BS_PUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle4 dd 0
x4  dw 141;x-координаты верхнего левого угла
y4  dw 26
cx4 dw 52
cy4 dw 13
id4 dw IDC_EXIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный элемент 
;управления
dw BUTTON;тип объекта управления 
du <E&xit>;надпись на объекте управления    
dw 0;терминатор
;----------------------------------------------------
end_dialog:
 
end_resource:
;---------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,0
user32_table:
DispatchMessage         dd _DispatchMessage
GetMessage              dd _GetMessage
PostQuitMessage     dd _PostQuitMessage
MessageBox      dd _MessageBox
IsDialogMessage     dd _IsDialogMessage
SetDlgItemText      dd _SetDlgItemText
CreateDialogParam   dd _CreateDialogParam
GetDlgItemText      dd _GetDlgItemText
DestroyWindow       dd _DestroyWindow
                        dw 0
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_CreateDialogParam  db 0,0,'CreateDialogParamA'
_PostQuitMessage    db 0,0,'PostQuitMessage'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_IsDialogMessage    db 0,0,'IsDialogMessageA'
_DestroyWindow      db 0,0,'DestroyWindow'
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
end_import:
END_SECTION:   
end main
___________________________
© Mikl___ 2013
4
Вложения
Тип файла: zip tut10a.zip (4.2 Кб, 68 просмотров)
Тип файла: zip tut10b.zip (4.4 Кб, 66 просмотров)
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 05:10  [ТС] #36
Win32 API. Урок 10d. Создания диалогового окна через CreateDialogParam и WndProc и RegisterClassEx

Урок сделан по мотивам Iczelion и "main variants от kero


Скачайте пример.
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 1232 bytes
du  macro string
    irpc c,<string>
    dw '&c'
    endm
    dw 0
    endm
.code
exebase     equ 400000h
;-----------------------------------------------------------------
; 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 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
;------------------------------------------------------------------
IDM_GETTEXT     equ 0
IDM_CLEAR       equ 1
IDM_EXIT        equ 2
IDC_BUTTON      equ 3
IDC_EXIT        equ 4
IDC_EDIT        equ 5
IDC_MENU    equ 100
IDC_DIALOG  equ 200
lang        equ 409h
main:
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 1
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table-optional_header;
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_RELOCS_STRIPPED 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 end_import-start;
Size_of_init_data   dd 0;
Size_of_uninit_data dd 0;
entry_point     dd start;
base_of_code        dd start;
base_of_data        dd 0;
image_base      dd exebase;
e_lfanew        dd ntHeader-dosHeader;section alignment
file_alignment      dd 4;
OS_version_major_minor  dd 4;
image_version_major_minor dd 0;
subsystem_version_major_minor dd 4;
reserved1       dd 0;
size_of_image       dd end_import;
size_of_header      dd start;
checksum        dd 0;
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 100000h;
Stack_commit        dd 1000h;
Heap_allocation     dd 100000h;
Heap_commit     dd 1000h;
loader_flag     dd 0;
number_of_dirs      dd (section_table-export_RVA)/8;
export_RVA          dd 0
export_size         dd 0
import_RVA          dd import
import_size         dd end_import-import
resuorce_RVA        dd resource
resuorce_size           dd end_resource-resource
;------------------------------------------------
section_table       dd 'xet.','t'
virtual_size        dd 0;exeption_RVA
virtual_address     dd start;exeption_size
Physical_size       dd end_import-start;security_RVA
Physical_offset     dd start
Relocations         dd 0
Linenumbers     dd 0
Relocations_and_Linenumbers_count dd 0
Attributes              dd 0
;---------------------------------------------------------
start:  xor ebx,ebx
        mov esi,exebase
        push ebx
    push offset ClassName+exebase
    push IDC_MENU
    push COLOR_BTNFACE+1
    push 10011h
    push ebx
    push esi
    push DLGWINDOWEXTRA
    push ebx
    push offset WndProc+exebase
    push CS_HREDRAW or CS_VREDRAW
    push sizeof(WNDCLASSEX)
    push esp
    call RegisterClassEx+exebase
    push ebx
    push ebx
    push ebx
    push IDC_DIALOG
    push esi
    call CreateDialogParam+exebase
    mov edi,esp
    mov [edi+sizeof(MSG)],eax;mov hDlg,eax
message_loop: push ebx
    push ebx
    push ebx
    push edi
    call GetMessage+exebase
    xchg eax,ecx
    jecxz exit_msg_loop
    push edi
    push [edi+sizeof(MSG)]
    call IsDialogMessage+exebase
    test eax,eax
    jnz short message_loop 
    push edi
    call DispatchMessage+exebase
        jmp short message_loop
exit_msg_loop: add esp,sizeof(WNDCLASSEX)
    retn
WndProc:
hDlg    equ [ebp+8]
uMsg    equ [ebp+0Ch]
wParam  equ [ebp+10h]
lParam  equ [ebp+14h]
    enter 96,0
    mov esi,esp;lea esi,buffer
    mov eax,uMsg
    mov edi,hDlg
    sub eax,WM_CLOSE
    jz wmCLOSE
        sub eax,WM_COMMAND-WM_CLOSE
        jz wmCOMMAND
        leave
    jmp DefDlgProc+exebase
wmCOMMAND: mov ax,[wParam]
        cmp [lParam],ebx;0
        jz short a3; выбрали меню
; выбрали кнопку или EditBox
        cmp [wParam+2],bx;IF BN_CLICKED
    jne short wmBYE
a3:     jmp dword ptr [handlers+exebase+eax*4]
GETTEXT: push 96
    push esi
    push IDC_EDIT
    push edi
        call GetDlgItemText+exebase
    push ebx
    push offset AppName+exebase
    push esi
    push ebx
    call MessageBox+exebase
    jmp short wmBYE
SAYHELLO: push offset TestString+exebase
    jmp a4
CLEAR:  push ebx
a4: push IDC_EDIT
    push edi
    call SetDlgItemText+exebase
        jmp short wmBYE
wmCLOSE: push edi
    call DestroyWindow+exebase
    push ebx
    call PostQuitMessage+exebase
a0: xor eax,eax
wmBYE:  leave
    retn 10h
 
handlers dd GETTEXT+exebase,CLEAR+exebase,wmCLOSE+exebase,\
    SAYHELLO+exebase,wmCLOSE+exebase
AppName db "Our Third Dialog Box",0
ClassName db 'DLGCLASS',0
TestString db "Wow! I'm in an edit box now",0
;----------------------------------------------------------
align 4
resource:       
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 2;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0,m1-resource,8000h;номер типа ресурса
dw RT_DIALOG,0,d1-resource,8000h; если во 2-ом слове установлен старший 
;бит - есть ссылка на оглавление второго уровня. В 1-ом слове смещение 
;второго оглавления относительно начала раздела ресурсов
m1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw IDC_MENU,0,m2-resource,8000h
; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение 
;третьего оглавления относительно начала раздела ресурсов
m2:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, 
;который используется данным ресурсом 16 * SUBLANG_ + LANG_
dw lang,0,m3-resource,0
m3:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu
Size1       dd end_menu-menu
CodePage1   dd 0
Reserved1   dd 0
d1:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
dw IDC_DIALOG,0,d2-resource,8000h
d2:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
dw lang,0,d3-resource,0;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
d3: 
OffsetToData2   dd dialog
Size2       dd end_dialog-dialog
CodePage2   dd 0
Reserved2   dd 0
 
menu: 
dw 0,   0,POPUP or ENDMENU
du <Test Controls>
dw MFT_STRING or MFS_ENABLED,IDM_GETTEXT
du <Get Text>
dw MFT_STRING or MFS_ENABLED,IDM_CLEAR
du <Clear Text>
dw MENUBREAK,0
dw 0;du <>;NOTEXT
dw MFT_STRING or MFS_ENABLED or ENDMENU,IDM_EXIT
du <&Exit>
end_menu:
dialog: 
style1 dd DS_CENTER or WS_MINIMIZEBOX or WS_VISIBLE or WS_CAPTION \
    or WS_SYSMENU;DS_MODALFRAME 
dwExtendedStyle1 dd 0
cdit1 dw 3 ;число элементов управления, входящих в состав диалогового окна 
x1    dw 10;отступ левой границы окна от левой границы экрана
y1    dw 10;отступ верхней границы окна от верхней границы экрана
cx1   dw 205;ширина окна
cy1   dw 60;высота окна
      dw 0FFFFh;есть меню у диалога (=FFFF) или меню нет (=0)
      dw IDC_MENU;идентификатор меню
CLASS: du <DLGCLASS>
CAPTION: du <CreateDialogParam+WndProc+Class>;заголовок диалога
align 4
;------------------------------------------------------
;элементы управления диалога    
u1:
style2 dd ES_LEFT or ES_AUTOHSCROLL or WS_CHILD or WS_VISIBLE \
    or WS_BORDER or WS_TABSTOP;50810080h
dwExtendedStyle2 dd 0
x2  dw 15;x-координаты верхнего левого угла
y2  dw 17;y-координаты верхнего левого угла
cx2 dw 111;ширина объекта управления
cy2 dw 13;высота объекта управления
id2 dw IDC_EDIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления
dw 0
dw 0;терминатор
;---------------------------------------------------
u2:
style3 dd BS_DEFPUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle3 dd 0
x3  dw 141;x-координаты верхнего левого угла
y3  dw 10;y-координаты верхнего левого угла
cx3 dw 52;ширина объекта управления
cy3 dw 14;высота объекта управления
id3 dw IDC_BUTTON;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <Say Hello>;надпись на объекте управления
dw 0;терминатор
;----------------------------------------------------
u3:
style4 dd BS_PUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle4 dd 0
x4  dw 141;x-координаты верхнего левого угла
y4  dw 26
cx4 dw 52
cy4 dw 13
id4 dw IDC_EXIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <E&xit>;надпись на объекте управления    
dw 0;терминатор
;----------------------------------------------------
end_dialog:
end_resource:
;-----------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,0
user32_table:
DispatchMessage         dd _DispatchMessage
GetMessage              dd _GetMessage
PostQuitMessage     dd _PostQuitMessage
MessageBox      dd _MessageBox
IsDialogMessage     dd _IsDialogMessage
SetDlgItemText      dd _SetDlgItemText
CreateDialogParam   dd _CreateDialogParam
GetDlgItemText      dd _GetDlgItemText
RegisterClassEx     dd _RegisterClassEx
DefDlgProc      dd _DefDlgProc
DestroyWindow       dd _DestroyWindow
                        dw 0
_GetMessage     db 0,0,'GetMessageA'
_DefDlgProc     db 0,0,'DefDlgProcA'
_RegisterClassEx    db 0,0,'RegisterClassExA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_CreateDialogParam  db 0,0,'CreateDialogParamA'
_PostQuitMessage    db 0,0,'PostQuitMessage'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_IsDialogMessage    db 0,0,'IsDialogMessageA'
_DestroyWindow      db 0,0,'DestroyWindow'
_MessageBox     db 0,0,"MessageBoxA",0
user32_dll      db 'user32'
end_import:
end main
_______________________________
© Mikl___ 2013
3
Вложения
Тип файла: zip tut10c.zip (4.9 Кб, 62 просмотров)
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 05:21  [ТС] #37
Win32 API. Урок 10 e. Создания диалогового окна через DialogBoxParam и DlgProc
Урок сделан по мотивам Iczelion и "main variants" от kero


Скачайте пример.
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 976 bytes
du  macro string
    irpc c,
    dw '&c'
    endm
    dw 0
    endm
.code
exebase     equ 400000h
; --------------------------------------------------------
; 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 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
;--------------------------------------------------------
IDM_GETTEXT     equ 0
IDM_CLEAR       equ 1
IDM_EXIT        equ 2
IDC_BUTTON      equ 3
IDC_EXIT        equ 4
IDC_EDIT        equ 5
IDC_MENU    equ 100
IDC_DIALOG  equ 200
lang        equ 409h
main:
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 1
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table-optional_header;
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_RELOCS_STRIPPED 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 end_import-start;
Size_of_init_data   dd 0;
Size_of_uninit_data dd 0;
entry_point     dd start;
base_of_code        dd start;
base_of_data        dd 0;
image_base      dd exebase;
e_lfanew        dd ntHeader-dosHeader;section alignment
file_alignment      dd 4;
OS_version_major_minor  dd 4;
image_version_major_minor dd 0;
subsystem_version_major_minor dd 4;
reserved1       dd 0;
size_of_image       dd end_import;
size_of_header      dd start;
checksum        dd 0;
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 100000h;
Stack_commit        dd 1000h;
Heap_allocation     dd 100000h;
Heap_commit     dd 1000h;
loader_flag     dd 0;
number_of_dirs      dd (section_table-export_RVA)/8;
export_RVA          dd 0
export_size         dd 0
import_RVA          dd import
import_size         dd end_import-import
resuorce_RVA        dd resource
resuorce_size           dd end_resource-resource
;------------------------------------------------
section_table       dd 'xet.','t'
virtual_size        dd 0;exeption_RVA
virtual_address     dd start;exeption_size
Physical_size       dd end_import-start;security_RVA
Physical_offset     dd start
Relocations         dd 0
Linenumbers     dd 0
Relocations_and_Linenumbers_count dd 0
Attributes              dd 0
;---------------------------------------------------------
start:  xor ebx,ebx
    push ebx
    push offset DlgProc+exebase
    push ebx
    push IDC_DIALOG
    push exebase
    call DialogBoxParam+exebase
    retn
DlgProc:
hDlg    equ [ebp+8]
uMsg    equ [ebp+0Ch]
wParam  equ [ebp+10h]
lParam  equ [ebp+14h]
    enter 96,0
    mov esi,esp;lea esi,buffer
    mov eax,uMsg
    mov edi,hDlg
    sub eax,WM_CLOSE
    jz wmCLOSE
        sub eax,WM_COMMAND-WM_CLOSE
        jz wmCOMMAND
        xor eax,eax
    jmp wmBYE
wmCOMMAND: mov ax,[wParam]
        cmp [lParam],ebx;0
        jz short a3; выбрали меню
; выбрали кнопку или EditBox
        cmp [wParam+2],bx;IF BN_CLICKED
    jne short wmBYE
a3:     jmp dword ptr [handlers+exebase+eax*4]
GETTEXT: push 96
    push esi
    push IDC_EDIT
    push edi
        call GetDlgItemText+exebase
    push ebx
    push offset AppName+exebase
    push esi
    push ebx
    call MessageBox+exebase
    jmp short wmBYE
SAYHELLO: push offset TestString+exebase
    jmp a4
CLEAR:  push ebx
a4: push IDC_EDIT
    push edi
    call SetDlgItemText+exebase
        jmp short wmBYE
wmCLOSE: push ebx
    push edi
    call EndDialog+exebase
wmBYE:  leave
    retn 10h
 
handlers dd GETTEXT+exebase,CLEAR+exebase,wmCLOSE+exebase,\
        SAYHELLO+exebase,wmCLOSE+exebase
AppName db "Our Fourth Dialog Box",0
TestString db "Wow! I'm in an edit box now",0
;----------------------------------------------------------
align 4
resource:       
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 2;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0,m1-resource,8000h;номер типа ресурса
dw RT_DIALOG,0,d1-resource,8000h; если во 2-ом слове установлен 
;старший бит - есть ссылка на оглавление второго уровня. В 1-ом слове 
;смещение второго оглавления относительно начала раздела ресурсов
m1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw IDC_MENU,0,m2-resource,8000h
; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего 
;оглавления относительно начала раздела ресурсов
m2:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором 
;языка, который используется даннvм ресурсом 16 * SUBLANG_ + LANG_
dw lang,0,m3-resource,0
m3:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu
Size1       dd end_menu-menu
CodePage1   dd 0
Reserved1   dd 0
d1:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
dw IDC_DIALOG,0,d2-resource,8000h
d2:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
dw lang,0,d3-resource,0;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
d3: 
OffsetToData2   dd dialog
Size2       dd end_dialog-dialog
CodePage2   dd 0
Reserved2   dd 0
 
menu: 
dw 0,   0,POPUP or ENDMENU
du <Test Controls>
dw MFT_STRING or MFS_ENABLED,IDM_GETTEXT
du <Get Text>
dw MFT_STRING or MFS_ENABLED,IDM_CLEAR
du <Clear Text>
dw MENUBREAK,0
dw 0;du <>;NOTEXT
dw MFT_STRING or MFS_ENABLED or ENDMENU,IDM_EXIT
du <&Exit>
end_menu:
dialog: 
style1 dd DS_CENTER or WS_MINIMIZEBOX or WS_VISIBLE or \
    WS_CAPTION or WS_SYSMENU;DS_MODALFRAME | 
dwExtendedStyle1 dd 0
cdit1 dw 3 ;число элементов управления, входящих в состав диалогового окна 
x1    dw 10;отступ левой границы окна от левой границы экрана
y1    dw 10;отступ верхней границы окна от верхней границы экрана
cx1   dw 205;ширина окна
cy1   dw 60;высота окна
      dw 0FFFFh;есть меню у диалога (=FFFF) или меню нет (=0)
      dw IDC_MENU;идентификатор меню
      dw 0
CAPTION: du <DialogBoxParam+DlgProc>;заголовок диалога
align 4
;------------------------------------------------------
;элементы управления диалога    
u1:
style2 dd ES_LEFT or ES_AUTOHSCROLL or WS_CHILD or WS_VISIBLE \
    or WS_BORDER or WS_TABSTOP;50810080h;
dwExtendedStyle2 dd 0
x2  dw 15;x-координаты верхнего левого угла
y2  dw 17;y-координаты верхнего левого угла
cx2 dw 111;ширина объекта управления
cy2 dw 13;высота объекта управления
id2 dw IDC_EDIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления
dw 0
dw 0;терминатор
;---------------------------------------------------
u2:
style3 dd BS_DEFPUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle3 dd 0
x3  dw 141;x-координаты верхнего левого угла
y3  dw 10;y-координаты верхнего левого угла
cx3 dw 52;ширина объекта управления
cy3 dw 14;высота объекта управления
id3 dw IDC_BUTTON;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <Say Hello>;надпись на объекте управления
dw 0;терминатор
;----------------------------------------------------
u3:
style4 dd BS_PUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle4 dd 0
x4  dw 141;x-координаты верхнего левого угла
y4  dw 26
cx4 dw 52
cy4 dw 13
id4 dw IDC_EXIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <E&xit>;надпись на объекте управления    
dw 0;терминатор
;----------------------------------------------------
end_dialog:
end_resource:
;-----------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,0
user32_table:
MessageBox      dd _MessageBox
SetDlgItemText      dd _SetDlgItemText
DialogBoxParam      dd _DialogBoxParam
GetDlgItemText      dd _GetDlgItemText
EndDialog       dd _EndDialog
                        dw 0
_MessageBox     db 0,0,"MessageBoxA"
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_DialogBoxParam     db 0,0,'DialogBoxParamA'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_EndDialog      db 0,0,'EndDialog',0
user32_dll      db 'user32'
 
end_import:
end main
_______________________________
© Mikl___ 2013
3
Вложения
Тип файла: zip tut10d.zip (3.8 Кб, 65 просмотров)
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 05:59  [ТС] #38
Win32 API. Урок 10f. Создания диалогового окна через DialogBoxParam и DlgProc и WndProc
Урок сделан по мотивам Iczelion и "main variants" от kero
Скачайте пример.
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 1065 bytes
du  macro string
    irpc c,<string>
    dw '&c'
    endm
    dw 0
    endm
.code
exebase     equ 400000h
;-------------------------------------------------------
; 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 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
;---------------------------------------------------------
IDM_GETTEXT     equ 0
IDM_CLEAR       equ 1
IDM_EXIT        equ 2
IDC_BUTTON      equ 3
IDC_EXIT        equ 4
IDC_EDIT        equ 5
IDC_MENU    equ 100
IDC_DIALOG  equ 200
lang        equ 409h
main:
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 1
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table-optional_header;
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_RELOCS_STRIPPED 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 end_import-start
Size_of_init_data   dd 0
Size_of_uninit_data dd 0
entry_point     dd start
base_of_code        dd start
base_of_data        dd 0
image_base      dd exebase;
e_lfanew        dd ntHeader-dosHeader;section alignment
file_alignment      dd 4
OS_version_major_minor  dd 4
image_version_major_minor dd 0
subsystem_version_major_minor dd 4
reserved1       dd 0
size_of_image       dd end_import
size_of_header      dd start
checksum        dd 0
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 100000h
Stack_commit        dd 1000h
Heap_allocation     dd 100000h
Heap_commit     dd 1000h
loader_flag     dd 0
number_of_dirs      dd (section_table-export_RVA)/8
export_RVA          dd 0
export_size         dd 0
import_RVA          dd import
import_size         dd end_import-import
resuorce_RVA        dd resource
resuorce_size           dd end_resource-resource
;------------------------------------------------
section_table       dd 'xet.','t'
virtual_size        dd 0;exeption_RVA
virtual_address     dd start;exeption_size
Physical_size       dd end_import-start;security_RVA
Physical_offset     dd start
Relocations         dd 0
Linenumbers     dd 0
Relocations_and_Linenumbers_count dd 0
Attributes              dd 0
;---------------------------------------------------------
start:  xor ebx,ebx
    push ebx
    push offset DlgProc+exebase
    push ebx
    push IDC_DIALOG
    push exebase
    call DialogBoxParam+exebase
    retn
WndProc:
hDlg    equ [ebp+8]
uMsg    equ [ebp+0Ch]
wParam  equ [ebp+10h]
lParam  equ [ebp+14h]
    enter 96,0
    mov esi,esp;lea esi,buffer
    mov eax,uMsg
    mov edi,hDlg
    sub eax,WM_CLOSE
    jz wmCLOSE
        sub eax,WM_COMMAND-WM_CLOSE
        jz wmCOMMAND
        leave
    jmp dword ptr DefDlgProc+exebase
wmCOMMAND: mov ax,[wParam]
        cmp [lParam],ebx;0
        jz short a3; выбрали меню
; выбрали кнопку или EditBox
        cmp [wParam+2],bx;IF BN_CLICKED
    jne short wmBYE
a3:     jmp dword ptr [handlers+exebase+eax*4]
GETTEXT: push 96
    push esi
    push IDC_EDIT
    push edi
        call GetDlgItemText+exebase
    push ebx
    push offset AppName+exebase
    push esi
    push ebx
    call MessageBox+exebase
    jmp short wmBYE
SAYHELLO: push offset TestString+exebase
    jmp a4
CLEAR:  push ebx
a4: push IDC_EDIT
    push edi
    call SetDlgItemText+exebase
        jmp short wmBYE
wmCLOSE: push ebx
    push edi
    call EndDialog+exebase
wmBYE:  leave
    retn 10h
DlgProc: cmp dword ptr [esp+8],WM_INITDIALOG;cmp uMsg,WM_INITDIALOG
    jne @f
    push offset WndProc+exebase
    push GWL_WNDPROC
    push dword ptr [esp+4+8]
    call SetWindowLong+exebase
@@:     xor eax,eax
    retn 16
handlers dd GETTEXT+exebase,CLEAR+exebase,wmCLOSE+exebase,\
    SAYHELLO+exebase,wmCLOSE+exebase
AppName db "Our Fifth Dialog Box",0
TestString db "Wow! I'm in an edit box now",0
;----------------------------------------------------------
align 4
resource:       
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 2;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0,m1-resource,8000h;номер типа ресурса
dw RT_DIALOG,0,d1-resource,8000h; если во 2-ом слове установлен 
;старший бит - есть ссылка на оглавление второго уровня. В 1-ом слове 
;смещение второго оглавления относительно начала раздела ресурсов
m1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw IDC_MENU,0,m2-resource,8000h
; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
m2:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором 
;языка, который используется даннvм ресурсом 16 * SUBLANG_ + LANG_
dw lang,0,m3-resource,0
m3:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu
Size1       dd end_menu-menu
CodePage1   dd 0
Reserved1   dd 0
d1:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
dw IDC_DIALOG,0,d2-resource,8000h
d2:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
dw lang,0,d3-resource,0;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
d3: 
OffsetToData2   dd dialog
Size2       dd end_dialog-dialog
CodePage2   dd 0
Reserved2   dd 0
 
menu: 
dw 0,   0,POPUP or ENDMENU
du <Test Controls>
dw MFT_STRING or MFS_ENABLED,IDM_GETTEXT
du <Get Text>
dw MFT_STRING or MFS_ENABLED,IDM_CLEAR
du <Clear Text>
dw MENUBREAK,0
dw 0;du <>;NOTEXT
dw MFT_STRING or MFS_ENABLED or ENDMENU,IDM_EXIT
du <&Exit>
end_menu:
dialog: 
style1 dd DS_CENTER or WS_MINIMIZEBOX or WS_VISIBLE or WS_CAPTION \
    or WS_SYSMENU;DS_MODALFRAME | 
dwExtendedStyle1 dd 0
cdit1 dw 3 ;число элементов управления, входящих в состав диалогового окна 
x1    dw 10;отступ левой границы окна от левой границы экрана
y1    dw 10;отступ верхней границы окна от верхней границы экрана
cx1   dw 205;ширина окна
cy1   dw 60;высота окна
      dw 0FFFFh;есть меню у диалога (=FFFF) или меню нет (=0)
      dw IDC_MENU;идентификатор меню
      dw 0
CAPTION: du <DialogBoxParam+DlgProc+WndProc>;заголовок диалога
align 4
;------------------------------------------------------
;элементы управления диалога    
u1:
style2 dd ES_LEFT or ES_AUTOHSCROLL or WS_CHILD or WS_VISIBLE \
or WS_BORDER or WS_TABSTOP;50810080h;
dwExtendedStyle2 dd 0
x2  dw 15;x-координаты верхнего левого угла
y2  dw 17;y-координаты верхнего левого угла
cx2 dw 111;ширина объекта управления
cy2 dw 13;высота объекта управления
id2 dw IDC_EDIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw EDIT;тип объекта управления 
du <>;надпись на объекте управления
dw 0
dw 0;терминатор
;---------------------------------------------------
u2:
style3 dd BS_DEFPUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle3 dd 0
x3  dw 141;x-координаты верхнего левого угла
y3  dw 10;y-координаты верхнего левого угла
cx3 dw 52;ширина объекта управления
cy3 dw 14;высота объекта управления
id3 dw IDC_BUTTON;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <Say Hello>;надпись на объекте управления
dw 0;терминатор
;----------------------------------------------------
u3:
style4 dd BS_PUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle4 dd 0
x4  dw 141;x-координаты верхнего левого угла
y4  dw 26
cx4 dw 52
cy4 dw 13
id4 dw IDC_EXIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du <E&xit>;надпись на объекте управления    
dw 0;терминатор
;----------------------------------------------------
end_dialog:
 
end_resource:
;----------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,0
user32_table:
MessageBox      dd _MessageBox
SetDlgItemText      dd _SetDlgItemText
DialogBoxParam      dd _DialogBoxParam
GetDlgItemText      dd _GetDlgItemText
SetWindowLong       dd _SetWindowLong
DefDlgProc      dd _DefDlgProc
EndDialog       dd _EndDialog
                        dw 0
_MessageBox     db 0,0,"MessageBoxA"
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_DefDlgProc     db 0,0,'DefDlgProcA'
_SetWindowLong      db 0,0,'SetWindowLongA'
_DialogBoxParam     db 0,0,'DialogBoxParamA'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_EndDialog      db 0,0,'EndDialog',0
user32_dll      db 'user32'
 
end_import:
end main
_________________________________________
© Mikl___ 2013
3
Вложения
Тип файла: zip tut10e.zip (4.0 Кб, 58 просмотров)
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 06:29  [ТС] #39
Win32 API. Урок 10g. Создания диалогового окна через DialogBoxParam и WndProc и RegisterClassEx

Урок сделан по мотивам Iczelion и "main variants" от kero

Скачайте пример.
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 1091 bytes
du  macro string
    irpc c,
    dw '&c'
    endm
    dw 0
    endm
.code
exebase     equ 400000h
;-----------------------------------------------------
; 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 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
;--------------------------------------------------------
IDM_GETTEXT     equ 0
IDM_CLEAR       equ 1
IDM_EXIT        equ 2
IDC_BUTTON      equ 3
IDC_EXIT        equ 4
IDC_EDIT        equ 5
IDC_MENU    equ 100
IDC_DIALOG  equ 200
lang        equ 409h
main:
;signatures----------------------------
dosHeader       dd IMAGE_DOS_SIGNATURE;'MZ'
ntHeader        dd IMAGE_NT_SIGNATURE;'PE'
;image_header--------------------------
Machine         dw IMAGE_FILE_MACHINE_I386; (Intel386)
Count_of_section    dw 1
TimeStump       dd 0
Symbol_table_offset dd 0
Symbol_table_count  dd 0
Size_of_optional_header dw section_table-optional_header;
Characteristics     dw IMAGE_FILE_32BIT_MACHINE or \
 IMAGE_FILE_RELOCS_STRIPPED 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 end_import-start;
Size_of_init_data   dd 0;
Size_of_uninit_data dd 0;
entry_point     dd start;
base_of_code        dd start;
base_of_data        dd 0;
image_base      dd exebase;
e_lfanew        dd ntHeader-dosHeader;section alignment
file_alignment      dd 4;
OS_version_major_minor  dd 4;
image_version_major_minor dd 0;
subsystem_version_major_minor dd 4;
reserved1       dd 0;
size_of_image       dd end_import;
size_of_header      dd start;
checksum        dd 0;
subsystem_and_DLL_flag  dd IMAGE_SUBSYSTEM_WINDOWS_GUI
Stack_allocation    dd 100000h;
Stack_commit        dd 1000h;
Heap_allocation     dd 100000h;
Heap_commit     dd 1000h;
loader_flag     dd 0;
number_of_dirs      dd (section_table-export_RVA)/8;
export_RVA          dd 0
export_size         dd 0
import_RVA          dd import
import_size         dd end_import-import
resuorce_RVA        dd resource
resuorce_size           dd end_resource-resource
;------------------------------------------------
section_table       dd 'xet.','t'
virtual_size        dd 0;exeption_RVA
virtual_address     dd start;exeption_size
Physical_size       dd end_import-start;security_RVA
Physical_offset     dd start
Relocations         dd 0
Linenumbers     dd 0
Relocations_and_Linenumbers_count dd 0
Attributes              dd 0
;---------------------------------------------------------
start:  xor ebx,ebx
        mov esi,exebase
        push ebx
    push offset ClassName+exebase
    push IDC_MENU
    push COLOR_BTNFACE+1
    push 10011h
    push ebx
    push esi
    push DLGWINDOWEXTRA
    push ebx
    push offset WndProc+exebase
    push CS_HREDRAW or CS_VREDRAW
    push sizeof(WNDCLASSEX)
    push esp
    call RegisterClassEx+exebase
        add esp,sizeof(WNDCLASSEX)
    push ebx
    push ebx
    push ebx
    push IDC_DIALOG
    push esi
    call DialogBoxParam+exebase
    retn
WndProc:
hDlg    equ [ebp+8]
uMsg    equ [ebp+0Ch]
wParam  equ [ebp+10h]
lParam  equ [ebp+14h]
    enter 96,0
    mov esi,esp;lea esi,buffer
    mov eax,uMsg
    mov edi,hDlg
    sub eax,WM_CLOSE
    jz wmCLOSE
        sub eax,WM_COMMAND-WM_CLOSE
        jz wmCOMMAND
        leave
    jmp dword ptr DefDlgProc+exebase
wmCOMMAND: mov ax,[wParam]
        cmp [lParam],ebx;0
        jz short a3; выбрали меню
; выбрали кнопку или EditBox
        cmp [wParam+2],bx;IF BN_CLICKED
    jne short wmBYE
a3:     jmp dword ptr [handlers+exebase+eax*4]
GETTEXT: push 96
    push esi
    push IDC_EDIT
    push edi
        call GetDlgItemText+exebase
    push ebx
    push offset AppName+exebase
    push esi
    push ebx
    call MessageBox+exebase
    jmp short wmBYE
SAYHELLO: push offset TestString+exebase
    jmp a4
CLEAR:  push ebx
a4: push IDC_EDIT
    push edi
    call SetDlgItemText+exebase
        jmp short wmBYE
wmCLOSE: push ebx
    push edi
    call EndDialog+exebase
wmBYE:  leave
    retn 10h
 
handlers dd GETTEXT+exebase,CLEAR+exebase,wmCLOSE+exebase,\
    SAYHELLO+exebase,wmCLOSE+exebase
AppName db "Our Sixth Dialog Box",0
TestString db "Wow! I'm in an edit box now",0
ClassName db "DLGCLASS",0
;----------------------------------------------------------
align 4
resource:       
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 2;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является типом ресурса
dw RT_MENU,0,m1-resource,8000h;номер типа ресурса
dw RT_DIALOG,0,d1-resource,8000h; если во 2-ом слове установлен 
;старший бит - есть ссылка на оглавление второго уровня. В 1-ом 
;слове смещение второго оглавления относительно начала раздела ресурсов
m1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw IDC_MENU,0,m2-resource,8000h
; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. T 1-ом слове смещение третьего 
;оглавления относительно начала раздела ресурсов
m2:
Characteristics3    dd 0
TimeDateStamp3      dd 0
MajorVersion3       dw 0
MinorVersion3       dw 0;
NumberOfNamedEntries3   dw 0;количество ресурсов с именами
NumberOfIdEntries3  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором 
;языка, который используется даннvм ресурсом 16 * SUBLANG_ + LANG_
dw lang,0,m3-resource,0
m3:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData1   dd menu
Size1       dd end_menu-menu
CodePage1   dd 0
Reserved1   dd 0
d1:
Characteristics4    dd 0
TimeDateStamp4      dd 0
MajorVersion4       dw 0
MinorVersion4       dw 0;
NumberOfNamedEntries4   dw 0;количество ресурсов с именами
NumberOfIdEntries4  dw 1;количество ресурсов с идентификаторами
dw IDC_DIALOG,0,d2-resource,8000h
d2:
Characteristics5    dd 0
TimeDateStamp5      dd 0
MajorVersion5       dw 0
MinorVersion5       dw 0;
NumberOfNamedEntries5   dw 0;количество ресурсов с именами
NumberOfIdEntries5  dw 1;количество ресурсов с идентификаторами
dw lang,0,d3-resource,0;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
d3: 
OffsetToData2   dd dialog
Size2       dd end_dialog-dialog
CodePage2   dd 0
Reserved2   dd 0
 
menu: 
dw 0,   0,POPUP or ENDMENU
du 
dw MFT_STRING or MFS_ENABLED,IDM_GETTEXT
du 
dw MFT_STRING or MFS_ENABLED,IDM_CLEAR
du 
dw MENUBREAK,0
dw 0;du ;NOTEXT
dw MFT_STRING or MFS_ENABLED or ENDMENU,IDM_EXIT
du 
end_menu:
dialog: 
style1 dd DS_CENTER or WS_MINIMIZEBOX or WS_VISIBLE or \
    WS_CAPTION or WS_SYSMENU;DS_MODALFRAME | 
dwExtendedStyle1 dd 0
cdit1 dw 3 ;число элементов управления, входящих в состав диалогового окна 
x1    dw 10;отступ левой границы окна от левой границы экрана
y1    dw 10;отступ верхней границы окна от верхней границы экрана
cx1   dw 205;ширина окна
cy1   dw 60;высота окна
      dw 0FFFFh;есть меню у диалога (=FFFF) или меню нет (=0)
      dw IDC_MENU;идентификатор меню
CLASS:   du 
CAPTION: du ;заголовок диалога
align 4
;------------------------------------------------------
;элементы управления диалога    
u1:
style2 dd ES_LEFT or ES_AUTOHSCROLL or WS_CHILD or WS_VISIBLE \
    or WS_BORDER or WS_TABSTOP;50810080h
dwExtendedStyle2 dd 0
x2  dw 15;x-координаты верхнего левого угла
y2  dw 17;y-координаты верхнего левого угла
cx2 dw 111;ширина объекта управления
cy2 dw 13;высота объекта управления
id2 dw IDC_EDIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw EDIT;тип объекта управления 
du ;надпись на объекте управления
dw 0
dw 0;терминатор
;---------------------------------------------------
u2:
style3 dd BS_DEFPUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle3 dd 0
x3  dw 141;x-координаты верхнего левого угла
y3  dw 10;y-координаты верхнего левого угла
cx3 dw 52;ширина объекта управления
cy3 dw 14;высота объекта управления
id3 dw IDC_BUTTON;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du ;надпись на объекте управления
dw 0;терминатор
;----------------------------------------------------
u3:
style4 dd BS_PUSHBUTTON or WS_CHILD or WS_VISIBLE or WS_TABSTOP
dwExtendedStyle4 dd 0
x4  dw 141;x-координаты верхнего левого угла
y4  dw 26
cx4 dw 52
cy4 dw 13
id4 dw IDC_EXIT;идентификатор объекта управления
dw 0FFFFh;тип объекта управления если равен FFFF - стандартный 
;элемент управления
dw BUTTON;тип объекта управления 
du ;надпись на объекте управления   
dw 0;терминатор
;----------------------------------------------------
end_dialog:
 
end_resource:
;---------------------------------------------------
import:
dd 0,0,0,user32_dll
dd user32_table
dd 0,0,0,0
user32_table:
MessageBox      dd _MessageBox
SetDlgItemText      dd _SetDlgItemText
DialogBoxParam      dd _DialogBoxParam
GetDlgItemText      dd _GetDlgItemText
RegisterClassEx     dd _RegisterClassEx
DefDlgProc      dd _DefDlgProc
EndDialog       dd _EndDialog
                        dw 0
_MessageBox     db 0,0,"MessageBoxA"
_SetDlgItemText     db 0,0,'SetDlgItemTextA'
_DefDlgProc     db 0,0,'DefDlgProcA'
_RegisterClassEx    db 0,0,'RegisterClassExA'
_DialogBoxParam     db 0,0,'DialogBoxParamA'
_GetDlgItemText     db 0,0,'GetDlgItemTextA'
_EndDialog      db 0,0,'EndDialog',0
user32_dll      db 'user32'
 
end_import:
end main
_______________________________________
© Mikl___ 2013
3
Вложения
Тип файла: zip tut10f.zip (4.1 Кб, 67 просмотров)
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 07:06  [ТС] #40
Win32 API. Урок 11. Больше о диалоговых окнах

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

ТЕОРИЯ МАТЬ СКЛЕРОЗА
Очень немногое будет сказано о том, как использовать диалоговые окна в качестве устройств ввода-вывода. Программа создает основное окно как обычно, и когда вы хотите отобразить диалоговое окно, просто-напросто вызовите CreateDialogParam или DialogBoxParam. Вызвав DialogBoxParam, вам не нужно делать что-либо еще, просто обработайте сообщения в процедуре диалогового окна. При использовании CreateDialogParam, вам будет нужно вставить вызов IsDialogMessage в цикле сообщений, чтобы позволить менеджеру диалогового окна обработать навигацию клавиатуры в вашем диалоговом окне за вас. Поскольку эти два случая тривиальны, я не привожу здесь исходный код. Вы можете скачать примеры и изучить их самостоятельно.

Давайте перейдем к предопределенным диалоговым окнам, которые Windows предоставляет для использования вашими приложениями. Эти диалоговые окна существуют, чтобы обеспечить стандартизованный пользовательский интерфейс. Существуют файловое диалоговое окно, принтер, цвет, шрифт и поисковое диалоговое окно. Вам следует использовать их так часто, как это возможно.

Диалоговые окна находятся в comdlg32.dll. Чтобы использовать их, вы должны прилинковать comdlg32.lib. Вы создаете эти диалоговые окна вызовом соответствующих функций из библиотеки предопределенных диалоговых окон. Для открытия файлового диалогового окна существует функция GetOрenFileName, для сохранения ― GetSaveFileName, для диалогового окна принтера ― PrintDlg и так далее. Каждая из этих функций берет указатель на структуру в качестве параметра. Вам следует посмотреть их в справочнике Win32 API. В этом туториале я продемонстрирую как создавать и использовать файловое диалоговое окно.

Hиже приведен прототип функции GetOрenFileName.
Assembler
1
       GetOpenFileName proto lpofn:DWORD
Вы можете видеть, что она получает только один параметр, указатель на структуру OPENFILENAME. Возвращаемое значение TRUE показывает, что пользователь выбрал файл, который нужно открыть, FALSE означает обратное. Сейчас мы рассмотрим на структуру OPENFILENAME:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
       OPENFILENAME  STRUCT
            lStructSize DWORD  ?
            hwndOwner HWND  ?
            hInstance HINSTANCE ?
            lpstrFilter LPCSTR  ?
            lpstrCustomFilter LPSTR  ?
            nMaxCustFilter DWORD  ?
            nFilterIndex DWORD  ?
            lpstrFile LPSTR  ?
            nMaxFile DWORD  ?
            lpstrFileTitle LPSTR  ?
            nMaxFileTitle DWORD  ?
            lpstrInitialDir LPCSTR  ?
            lpstrTitle LPCSTR  ?
            Flags  DWORD  ?
            nFileOffset WORD  ?
            nFileExtension WORD  ?
            lpstrDefExt LPCSTR  ?
            lCustData LPARAM  ?
            lpfnHook DWORD  ?
            lpTemplateName LPCSTR  ?
       OPENFILENAME  ENDS
Давайте рассмотрим значение часто используемых параметров.
  • lStructSize ― размер структуры OPENFILENAME в байтах.
  • hwndOwner ― Хэндл файлового диалогового окна.
  • hInstance ― Хэндл процесса, который создает файловое диалоговое окно.
  • lрstrFilter ― Строка-фильтр состоит из парных строк, разделенных null'ом. Первая строка в каждой паре - это описание. Вторая строка ― это шаблон фильтра. Например:
    Assembler
    1
    2
    
    FilterString   db "All Files (*.*)",0, "*.*",0
      db "Text Files (*.txt)",0,"*.txt",0,0
    Отметьте, что шаблон во второй строке каждой пары действительно используется для фильтрации названий файлов. Также отметьте, что вам нужно добавить дополнительный 0 в конце фильтровых строк, чтобы указать конец. Определите, какая пара фильтровых строк будет использоваться при первом отображении файлового диалогового окна. Индекс основывается на единице, то есть первая пара ― 1, вторая ― 2 и так далее. Поэтому в вышеприведенном экземпляре, если мы укажем nFilterIndex как 2, будет использован второй шаблон ― "*.txt".
  • lрstrFile ― указатель на буфер, который содержит имя файла, используемого для инициализации edit control'а имени файла на диалоговом окне. Буфер должен быть длиной по крайней мере 260 байтов. После того, как пользователь выберет файл для открытия, имя файла с полным путем будет сохранено в этом буфере. Вы можете извлечь информацию из него позже.
  • nMaxFile ― размер буфера.
  • lрstrTitle ― указатель на заголовок открытого файлового диалогового окна.
  • Flags ― определите стили и характеристики диалогового окна.
  • nFileOffset ― после того, как пользователь выбрал файл для открытия, этот параметр содержит индекс первого символа собственно названия файла. Например, если полное имя с путем "c:\windows\system\lz32.dll", то этот параметр будет содержать значение 18.
  • nFileExtension ― после того, как пользователь выберет файл для открытия, этот параметр содержит индекс первого символа расширения файла.


ПРАКТИКА СЕСТРА ШИЗОФРЕНИИ
Нижеприведенная программа отображает окно диалога открытия файла, когда пользователь выбирает пункт Filehttp://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrowOрen в меню. Когда пользователь выберет файл в диалоговом окне, программа отобразит сообщение, содержащее полное имя, собственно имя файла и расширение выбранного файла.
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
   .386
   .model flat,stdcall
   option casemap:none
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
 
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   include \masm32\include\comdlg32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
   includelib \masm32\lib\comdlg32.lib
 
   .const
   IDM_OPEN equ 1
   IDM_EXIT equ 2
   MAXSIZE equ 260
   OUTPUTSIZE equ 512
 
   .data
   ClassName db "SimpleWinClass",0
   AppName  db "Our Main Window",0
   MenuName db "FirstMenu",0
   ofn   OPENFILENAME 
   FilterString db "All Files",0,"*.*",0
                db "Text Files",0,"*.txt",0,0
   buffer db MAXSIZE dup(0)
   OurTitle db "-=Our First Open File Dialog Box=-: Choose the file to open",0
   FullPathName db "The Full Filename with Path is: ",0
   FullName  db "The Filename is: ",0
   ExtensionName db "The Extension is: ",0
   OutputString db OUTPUTSIZE dup(0)
   CrLf db 0Dh,0Ah,0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
 
   .code
start:      invoke GetModuleHandle, NULL
       mov    hInstance,eax
       invoke GetCommandLine
       mov CommandLine,eax
       invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
       invoke ExitProcess,eax
 
   WinMain proc
   hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
       LOCAL wc:WNDCLASSEX
       LOCAL msg:MSG
       LOCAL hwnd:HWND
 
       mov   wc.cbSize,SIZEOF WNDCLASSEX
       mov   wc.style, CS_HREDRAW or CS_VREDRAW
       mov   wc.lpfnWndProc, OFFSET WndProc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_WINDOW+1
       mov   wc.lpszMenuName,OFFSET MenuName
       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_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,300,200,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
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .if ax==IDM_OPEN
               mov ofn.lStructSize,SIZEOF ofn
               push hWnd
               pop  ofn.hwndOwner
               push hInstance
               pop  ofn.hInstance
               mov  ofn.lpstrFilter, OFFSET FilterString
               mov  ofn.lpstrFile, OFFSET buffer
               mov  ofn.nMaxFile,MAXSIZE
               mov  ofn.Flags, OFN_FILEMUSTEXIST or \
                   OFN_PATHMUSTEXIST or OFN_LONGNAMES or\
                   OFN_EXPLORER or OFN_HIDEREADONLY
               mov  ofn.lpstrTitle, OFFSET OurTitle
               invoke GetOpenFileName, ADDR ofn
               .if eax==TRUE
                   invoke lstrcat,offset OutputString,OFFSET FullPathName
                   invoke lstrcat,offset OutputString,ofn.lpstrFile
                   invoke lstrcat,offset OutputString,offset CrLf
                   invoke lstrcat,offset OutputString,offset FullName
                   mov  eax,ofn.lpstrFile
                   push ebx
                   xor  ebx,ebx
                   mov  bx,ofn.nFileOffset
                   add  eax,ebx
                   pop  ebx
                   invoke lstrcat,offset OutputString,eax
                   invoke lstrcat,offset OutputString,offset CrLf
                   invoke lstrcat,offset OutputString,offset ExtensionName
                   mov  eax,ofn.lpstrFile
                   push ebx
                   xor ebx,ebx
                   mov  bx,ofn.nFileExtension
                   add eax,ebx
                   pop ebx
                   invoke lstrcat,offset OutputString,eax
                   invoke MessageBox,hWnd,OFFSET OutputString,ADDR AppName,MB_OK
                   invoke RtlZeroMemory,offset OutputString,OUTPUTSIZE
               .endif
           .else
               invoke DestroyWindow, hWnd
           .endif
       .ELSE
           invoke DefWindowProc,hWnd,uMsg,wParam,lParam
           ret
       .ENDIF
       xor    eax,eax
       ret
   WndProc endp
    end start
Разбор полётов
Assembler
1
2
3
4
5
               mov ofn.lStructSize,SIZEOF ofn
               push hWnd
               pop  ofn.hwndOwner
               push hInstance
               pop  ofn.hInstance
Мы заполняем в процедуре члены структуры ofn.
Assembler
1
 mov  ofn.lpstrFilter, OFFSET FilterString
FilterString ― это фильтр имен файлов, который мы определяем следующим образом.
Assembler
1
2
FilterString db "All Files",0,"*.*",0
  db "Text Files",0,"*.txt",0,0
Заметьте, что все четыре строки заканчиваются нулем. Первая строка - это описание следующей строки. Первая строка является описанием первой. В качестве фильтра мы можем определить все, что захотим. Мы должны добавить дополнительный ноль после последнего фильтра, чтобы указать конец. Hе забудьте сделать это, иначе ваше диалогове окно поведет себя весьма странно.
Assembler
1
2
               mov  ofn.lpstrFile, OFFSET buffer
               mov  ofn.nMaxFile,MAXSIZE
Мы указываем, где диалоговое окно поместить имена файлов, выбранные пользователем. Учтите, что мы должны указать размер буфера в nMaxFile. Мы можем затем извлечь имя файла из этого буфера.
Assembler
1
2
3
               mov  ofn.Flags, OFN_FILEMUSTEXIST or \
                   OFN_PATHMUSTEXIST or OFN_LONGNAMES or\
                   OFN_EXPLORER or OFN_HIDEREADONLY
Флаги определяющие характеристики окна.
  • OFN_FILEMUSTEXIST и OFN_PATHMUSTEXIST ― указывают то, что имя файла и путь, который пользователь набирает в edit control'е имени файла, должен существовать.
  • OFN_LONGNAMES ― указывает диалоговому окну показывать длинные имена.
  • OFN_EXPLORER ― указывает на то, что появление диалогового окна должно быть похоже на explorer.
  • OFN_HIDEREADONLY ― прячет неизменяемый checkbox на диалоговом окне. Есть много других флагов, которые вы можете использовать. Проконсультируйтесь с вашим справочником по Win32 API.
Assembler
1
               mov  ofn.lpstrTitle, OFFSET OurTitle
Указываем имя диалогового окна.
Assembler
1
               invoke GetOpenFileName, ADDR ofn
Вызов функции GetOрenFileName. Передача указателя на структуру ofn в качестве параметров. В тоже время, диалоговое окно открытия файла отображается на экране. Функция не будет возвращаться, пока пользователь не выберет файл или не нажмет кнопку 'Cancel' или закроет диалоговое окно. Функция возвратит TRUE, если пользователь выбрал файл, в противном случае FALSE.
Assembler
1
2
3
4
5
               .if eax==TRUE
                   invoke lstrcat,offset OutputString,OFFSET FullPathName
                   invoke lstrcat,offset OutputString,ofn.lpstrFile
                   invoke lstrcat,offset OutputString,offset CrLf
                   invoke lstrcat,offset OutputString,offset FullName
В случае, если пользователь выбирает файл, мы подготавливаем строку вывода, которая будет отображаться в окне сообщения. Мы резервируем блок памяти в переменной OutрutString и затем используем API-функцию, lstrcat, чтобы соединить обе строки. Чтобы разместить строку в несколько рядов, мы должны использовать символы переноса каретки.
Assembler
1
2
3
4
5
6
7
                   mov  eax,ofn.lpstrFile
                   push ebx
                   xor  ebx,ebx
                   mov  bx,ofn.nFileOffset
                   add  eax,ebx
                   pop  ebx
                   invoke lstrcat,offset OutputString,eax
Вышеприведенные строки требуют некоторых объяснений. nFileOffset содержит индекс в ofn.lрstrFile. Hо вы не можете сложить их в месте, так размерности этих переменных разные. Поэтому я поместил значение nFileOffset в младшее слово ebx'а и сложил его со значением lpstrFile'а.
Assembler
1
 invoke MessageBox,hWnd,OFFSET OutputString,ADDR AppName,MB_OK
Мы отображаем строку в окне сообщения.
Assembler
1
 invoke RtlZerolMemory,offset OutputString,OUTPUTSIZE
Мы должны очистить OutрutString перед тем, как заполнить его другой строкой. Поэтому мы используем функцию RtlZeroMemory для этого.
_______________________________________
© Iczelion, пер. Aquila.
3
Вложения
Тип файла: zip tut11-1.zip (4.0 Кб, 73 просмотров)
Тип файла: zip tut11-2.zip (3.9 Кб, 66 просмотров)
Тип файла: zip tut11-3.ZIP (3.8 Кб, 67 просмотров)
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 10:06  [ТС] #41
Win32 API. Урок 12. Память и файлы
Мы выучим основы менеджмента памяти и файловых операций ввода/вывода в этом Уроке. Также мы используем обычные диалоговые окна как устройства ввода/вывода.
Скачайте пример здесь.
ТЕОРИЯ ― МАТЬ СКЛЕРОЗА
Менеджмент памяти под Win32 с точки зрения приложения достаточно прост и прямолинеен. Используемая модель памяти называется плоской моделью памяти.
В этой модели все сегментные регистры (или селекторы) указывают на один и тот же стартовый адрес и смещение 32-битное, так что приложение может обратиться к любой точке памяти своего адресного пространства без необходимости изменять значения селекторов. Это очень упрощает управление памятью. Больше нет "дальних" и "ближних" указателей.
Под Win16 существует две основные категории функций API памяти: глобальные и локальные. Функции глобального типа взаимодействуют с памятью в других сегментах, поэтому они функции "дальней" памяти. Функции локального типа взаимодействуют с локальной кучей процессов, поэтому они функции "ближней" памяти.
Под Win32 оба этих типа идентичны. Используете ли вы GlobalAlloc или LocalAlloc, вы получите одинаковый результат.
  1. Выделите блок памяти с помощью вызова GlobalAlloc. Эта функция возвращает хэндл на запрошенный блок памяти.
  2. "Закройте" блок памяти, вызвав GlobalLock. Эта функция принимает хэндл на блок памяти и возвращает указатель на блок памяти.
  3. Вы можете использовать указатель, чтобы читать или писать в память.
  4. "Откройте" блок памяти с помощью вызова GlobalUnlock. Эта функция возвращает указатель на блок памяти.
  5. Освободите блок памяти с помощью GlobalFree. Эта функции принимает хэндл на блок памяти.
Вы также можете заменить "Global" на "Local", т.е. LocalAlloc, LocalLock и т.д.
Вышеуказанный метод может быть упрощен использованием флага GMEM_FIXED при вызове GlobalAlloc. Если вы используете этот флаг, возвращаемое значение от Global/LocalAlloc будет указателем на зарезервированный блок памяти, а не хэндл этого блока. Вам не надо будет вызывать Global/LocakLock вы сможете передать указатель Global/LocalFree без предварительного вызова Global/LocalUnlock. Hо в этом туториале я использую "традиционный" подход, так как вы можете столкнуться с ним при изучении исходников других программ.
Файловый ввод/вывод по Win32 имеет значительное сходство с тем, как это делалось под DOS. Все требуемые шаги точно такие же. Вам только нужно изменить прерывания на вызовы API функций.
  1. Откройте или создайте файл функцией CreateFile. Эта функция очень универсальна: не считая файла, она может открывать компорты, пайпы, дисковые приводы и консоли. В случае успеха она возвращает хэндл файла или устройства. Затем вы можете использовать этот хэндл, чтобы выполнить определенные действия над файлом или устройством.
  2. Переместите файловый указатель в желаемое местоположение функцией SetFilePointer.
  3. Проведите операцию чтения или записи с помощью вызова ReadFile или WriteFile. Перед этим вы должны зарезервировать достаточно большой блок памяти для данных.
  4. Закройте файл с помощью CloseHandle. Эта функции принимает хэндл файла.
ПРАКТИКА ― СЕСТРА ШИЗОФРЕНИИ
Приведенная ниже программа отображает открытый файловое диалоговое окно. Оно позволяет пользователю использовать текстовый файл, чтобы открыть и показать содержимое файла в клиентской области edit control'а. Пользователь может изменять текст в edit control'е по своему усмотрению, а затем может сохранить содержимое в файл.
Кликните здесь для просмотра всего текста
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
   .386
   .model flat,stdcall
   option casemap:none
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   include \masm32\include\comdlg32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
   includelib \masm32\lib\comdlg32.lib
 
   .const
   IDM_OPEN equ 1
   IDM_SAVE equ 2
   IDM_EXIT equ 3
   MAXSIZE equ 260
   MEMSIZE equ 65535
   EditID equ 1                            ; ID of the edit control
 
   .data
   ClassName db "Win32ASMEditClass",0
   AppName  db "Win32 ASM Edit",0
   EditClass db "edit",0
   MenuName db "FirstMenu",0
   ofn   OPENFILENAME <>
   FilterString db "All Files",0,"*.*",0
                db "Text Files",0,"*.txt",0,0
   buffer db MAXSIZE dup(0)
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   hwndEdit HWND ?                               ; Handle to the edit control
   hFile HANDLE ?                                   ; File handle
   hMemory HANDLE ?                            ;handle to the allocated memory block
   pMemory DWORD ?                            ;pointer to the allocated
   memory block
   SizeReadWrite DWORD ?                   ; number of bytes actually read or write
   .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:SDWORD
       LOCAL wc:WNDCLASSEX
       LOCAL msg:MSG
       LOCAL hwnd:HWND
       mov   wc.cbSize,SIZEOF WNDCLASSEX
       mov   wc.style, CS_HREDRAW or CS_VREDRAW
       mov   wc.lpfnWndProc, OFFSET WndProc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_WINDOW+1
       mov   wc.lpszMenuName,OFFSET MenuName
       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_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
              CW_USEDEFAULT,300,200,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 uses ebx hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
       .IF uMsg==WM_CREATE
           invoke CreateWindowEx,NULL,ADDR EditClass,NULL,\
                      WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or\
                      ES_AUTOHSCROLL or ES_AUTOVSCROLL,0,\
                      0,0,0,hWnd,EditID,\
                      hInstance,NULL
           mov hwndEdit,eax
           invoke SetFocus,hwndEdit
   ;==============================================
   ;        Initialize the members of OPENFILENAME structure
   ;==============================================
           mov ofn.lStructSize,SIZEOF ofn
           push hWnd
           pop  ofn.hWndOwner
           push hInstance
           pop  ofn.hInstance
           mov  ofn.lpstrFilter, OFFSET FilterString
           mov  ofn.lpstrFile, OFFSET buffer
           mov  ofn.nMaxFile,MAXSIZE
       .ELSEIF uMsg==WM_SIZE
           mov eax,lParam
           mov edx,eax
           shr edx,16
           and eax,0ffffh
           invoke MoveWindow,hwndEdit,0,0,eax,edx,TRUE
       .ELSEIF uMsg==WM_DESTROY
           invoke PostQuitMessage,NULL
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .if lParam==0
               .if ax==IDM_OPEN
                   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 CreateFile,ADDR buffer,GENERIC_READ or GENERIC_WRITE ,FILE_SHARE_READ or \
   FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
                       mov hFile,eax
                       invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE
                       mov  hMemory,eax
                       invoke GlobalLock,hMemory
                       mov  pMemory,eax
                       invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR SizeReadWrite,NULL
                       invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,pMemory
                       invoke CloseHandle,hFile
                       invoke GlobalUnlock,pMemory
                       invoke GlobalFree,hMemory
                   .endif
                   invoke SetFocus,hwndEdit
               .elseif ax==IDM_SAVE
                   mov ofn.Flags,OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
                   invoke GetSaveFileName, ADDR ofn
                       .if eax==TRUE
  invoke CreateFile,ADDR buffer,GENERIC_READ or GENERIC_WRITE ,FILE_SHARE_READ or \
  FILE_SHARE_WRITE,NULL,CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE, NULL
                           mov hFile,eax
                           invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE
                           mov  hMemory,eax
                           invoke GlobalLock,hMemory
                           mov  pMemory,eax
                           invoke SendMessage,hwndEdit,WM_GETTEXT,MEMSIZE-1,pMemory
                           invoke WriteFile,hFile,pMemory,eax,ADDR SizeReadWrite,NULL
                           invoke CloseHandle,hFile
                           invoke GlobalUnlock,pMemory
                           invoke GlobalFree,hMemory
                       .endif
                       invoke SetFocus,hwndEdit
                   .else
                       invoke DestroyWindow, hWnd
                   .endif
               .endif
           .ELSE
               invoke DefWindowProc,hWnd,uMsg,wParam,lParam
               ret
   .ENDIF
   xor    eax,eax
   ret
   WndProc endp
   end start
Разбор полётов
Кликните здесь для просмотра всего текста
Assembler
1
2
3
           invoke CreateWindowEx,NULL,ADDR EditClass,NULL,WS_VISIBLE or WS_CHILD or\
          ES_LEFT or ES_MULTILINE or ES_AUTOHSCROLL or ES_AUTOVSCROLL,0, 0,0,0, hWnd,EditID, hInstance,NULL
           mov hwndEdit,eax
В секции WM_CREATE мы создаем edit control. Отметьте, что параметры, которые определяют x, y, windth, height контрола равны нулю, поскольку мы изменим размер контрола позже, чтобы покрыть всю клиентскую область pодительского окна.
Заметьте, что в этом случае мы не должны вызывать ShowWindow, чтобы заставить появиться контрол на экране, так как мы указали стиль WS_VISIBLE. Вы можете использовать этот трюк и для родительского окна.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
   ;==============================================
   ;        Инициализируем структуру
   ;==============================================
           mov ofn.lStructSize,SIZEOF ofn
           push hWnd
           pop  ofn.hWndOwner
           push hInstance
           pop  ofn.hInstance
           mov  ofn.lpstrFilter, OFFSET FilterString
           mov  ofn.lpstrFile, OFFSET buffer
           mov  ofn.nMaxFile,MAXSIZE
После создания edit control'а edit control'а, мы используем это время, чтобы проинициализировать члены ofn. Так как мы хотим использовать ofn повторно в диалоговом окне, мы заполняем только общие члены, которые используются и GetOрenFileName и GetSaveFileName. Секция WM_CREATE - это прекрасное место для одноразовой инициализации.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
       .ELSEIF uMsg==WM_SIZE
           mov eax,lParam
           mov edx,eax
           shr edx,16
           and eax,0ffffh
           invoke MoveWindow,hwndEdit,0,0,eax,edx,TRUE
Мы получаем сообщения WM_SIZE, когда pазмеp клиентской области нашего основного окна изменяется. Мы также получаем его, когда окно создается. Для того, чтобы получать это сообщение, стили класса окна должны включать CS_REDRAW и CS_HREDRAW. Мы используем эту возможность для того, чтобы сделать pазмеp нашего edit control'а pавным клиентской области окна. Для начала мы должны узнать текущую ширину и высоту клиентской области родительского окна. Мы получаем эту информацию из lParam. Старшее слово lParam содержит высоту, а младшее слово ― ширину клиентской области. Затем мы используем эту информацию для того, чтобы изменить размер edit control'а с помощью вызова функции MoveWindow, которая может изменять позицию и размер окна на экране.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
               .if ax==IDM_OPEN
                   mov  ofn.Flags, OFN_FILEMUSTEXIST or \
                                   OFN_PATHMUSTEXIST or OFN_LONGNAMES or\
                                   OFN_EXPLORER or OFN_HIDEREADONLY
                   invoke GetOpenFileName, ADDR ofn
Когда пользователь выбирает пункт меню File/Oрen, мы заполняем в структуре параметр Flags и вызываем функцию GetOрenFileName, чтобы отобразить окно открытия файла.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
                   .if eax==TRUE
                       invoke CreateFile,ADDR buffer,GENERIC_READ or GENERIC_WRITE ,FILE_SHARE_READ or \
       FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
                       mov hFile,eax
После того, как пользователь выберет файл для открытия, мы вызываем CreateFile, чтобы открыть файл. Мы указываем, что функция должна попробовать открыть файл для чтения и записи. После того, как файл открыт, функция возвращает хэндл на открытый файл, который мы сохраняем в глобальной переменной для будущего использования. Эта функция имеет следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
2
   CreateFile proto lpFileName:DWORD,dwDesiredAccess:DWORD,dwShareMode:DWORD,\
    lpSecurityAttributes:DWORD,dwCreationDistribution:DWORD, dwFlagsAndAttributes:DWORD, hTemplateFile:DWORD
  • dwDesireAccess указывает, какую операцию вы хотите выполнить над файлом.
    • Открыть файл для проверки его атрибутов. Вы можете писать и читать из файла.
    • GENERIC_READ Открыть файл для чтения.
    • GENERIC_WRITE Открыть файл для записи.
  • dwShareMode указывает, какие операции вы хотите позволить выполнять вашим процессам над открытыми файлами.
    • 0 Hе разделять файл с другими процессами.
    • FILE_SHARE_READ позволяет другим процессам прочитать информацию из файла, который был открыт
    • FILE_SHARE_WRITE позволяет другим процессам записывать информацию в открытый файл.
  • lpSecurityAttributes не имеет значения под Windows 95.
  • dwCreationDistribution указывает действие, которое будет выполнено над файлом при его открытии.
    • CREATE_NEW Создание нового файла, если файла не существует.
    • CREATE_ALWAYS Создание нового файла. Функция перезаписывает файл, если он существует.
    • OPEN_EXISTING Открытие существующего файла.
    • OPEN_ALWAYS Открытие файла, если он существует, в противном случае, функция создает новый файл.
    • TRUNCATE_EXISTING Открытие файла и обрезание его до нуля байтов. Вызывающий функцию процесс должен открывать файл, по крайней мере, с доступом GENERIC_WRITE. Если файл не существует, функция не срабатывает.
  • dwFlagsAndAttributes указывает атрибуты файла
    • FILE_ATTRIBUTE_ARCHIVE ― файл является архивным. Приложения используют этот атрибут для бэкапа или удаления.
    • FILE_ATTRIBUTE_COMPRESSED ― файл или каталог сжаты. Для файла это означает, что вся информация в файле заархивирована. Для директории это означает, что сжатие подразумевается по умолчанию для создаваемых вновь файлов и поддиректорий.
    • FILE_ATTRIBUTE_NORMAL ― у файла нет других атрибутов. Этот атрибут действителен, только если используется один.
    • FILE_ATTRIBUTE_HIDDEN ― файл спрятан. Он не включается в обычные листинги директорий.
    • FILE_ATTRIBUTE_READONLY ― файл только для чтения. Приложения могут читать из файла, но не могут писать в него или удалить его.
    • FILE_ATTRIBUTE_SYSTEM ― файл часть операционной системы или используется только ей.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
                       invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE
                       mov  hMemory,eax
                       invoke GlobalLock,hMemory
                       mov  pMemory,eax
Когда файл открыт, мы резервирует блок память для использования функциями ReadFile и WriteFile. Мы указываем флаг GMEM_MOVEABLE, чтобы позволить Windows перемещать блок памяти, чтобы уплотнять последнюю.
Когда GlobalAlloc возвращает положительный результат, eax содержит хэндл зарезервированного блока памяти. Мы передаем этот хэндл функции GlobalLock, который возвращает указатель на блок памяти.
Кликните здесь для просмотра всего текста
Assembler
1
2
   invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR SizeReadWrite,NULL
                       invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,pMemory
Когда блок памяти готов к использованию, мы вызываем функцию ReadFile для чтения данных из файла. Когда файл только что открыт или создан, указатель на смещение равен нулю. В этом случае, мы начинаем чтение с первого байта. Первый параметр ReadFile ― это хэндл файла, из которого необходимо произвести чтение, второй ― это указатель на блок памяти, затем ― количество байтов, которое нужно считать из файла, четвертый параметр ― это адрес переменной размера DWORD, который будет заполнен количеством байтов, в реальности считанных из файла.
После заполнения блока памяти данными, мы помещаем данные в edit control, посылая сообщение WM_SETTEXT контролу, причем lParam содержит указатель на блок памяти. После этого вызова edit control отображает данные в его клиентской области.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
  invoke CloseHandle,hFile
                       invoke GlobalUnlock,pMemory
                       invoke GlobalFree,hMemory
                   .endif
В этой месте у нас нет необходимости держать файл открытым, так как нашей целью является запись модифицированных данных из edit control'а в другой файл, а не в оригинальный. Поэтому мы закрываем файл функцией CloseHandle, передав ей в качестве параметра хэндл файла. Затем мы открываем блок памяти и освобождаем его. В действительности, вам не нужно освобождать ее сейчас, вы можете использовать этот же блок во время операции сохранения. Hо в демонстрационных целях я освобождаю ее сейчас.
Кликните здесь для просмотра всего текста
Assembler
1
 invoke SetFocus,hwndEdit
Когда на экране отображается окно открытия файла, фокус ввода сдвигается на него. Поэтому, когда это окно закрывается, мы должны передвинуть фокус ввода обратно на edit control.
Это заканчивает операцию чтения из файла. В этом месте пользователь должен отредактировать содержимое edit control'а. И когда он хочет сохранить данные в другой файла, он должен выбрать File/Save, после чего отобразиться диалоговое окно. Создание окна сохранения файла не слишком отличается от создание окна открытия файла. Фактически, они отличаются только именем функций. Вы можете снова использовать большинство из параметров структуры ofn, кроме параметра Flags.
Assembler
1
 mov ofn.Flags,OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
В нашем случае, мы хотим создать новый файл, так чтобы OFN_FILEMUSTEXIST и OFN_PATHMUSTEXIST должны быть убраны, иначе диалоговое окно не позволит нам создать файл, который уже не существует.
Параметр dwCreationDistribution функции CreateFile должен быть установлен в CREATE_NEW, так как мы хотим создать новый файл. Оставшийся код практически одинаков с тем, что используется при создании окна открытия файла, за исключением следующего:
Кликните здесь для просмотра всего текста
Assembler
1
2
 invoke SendMessage,hwndEdit,WM_GETTEXT,MEMSIZE-1,pMemory
    invoke WriteFile,hFile,pMemory,eax,ADDR SizeReadWrite,NULL
Мы посылаем сообщение WM_GETTEXT edit control'у, чтобы скопировать данные из него в блок памяти, возвращаемое значение в eax - это длина данных внутри буфера. После того, как данные оказываются в блоке памяти, мы записываем их в новый файл.
_____________________________________________
© Iczelion, пер. Aquila.
4
Вложения
Тип файла: zip tut12.zip (4.2 Кб, 72 просмотров)
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 10:41  [ТС] #42
Win32 API. Урок 12a. Память и файлы
Взято из примечаний к 12 уроку Iczelion'а на сайте WASM.RU

leo /2006-03-11 15:22:25/
Уважаемые ученики Iczelion'а!
Забудьте раз и навсегда о GlobalAlloc с флагом GMEM_MOVEABLE!!! То, что было "традиционно" во времена перехода с Win16 на Win32, в наше время стало просто глупым и абсурдным. Никакого перемещения блоков памяти внутри кучи Win32 реально не поддерживают, так как им это не нужно ― все "перемещения" осуществляются на уровне подкачки и трансляции страниц. Но использовать флаг GMEM_MOVEABLE не только бессмысленно, но и накладно с точки зрения расхода памяти и быстродействия.
Поясняю. Основными функциями для работы с кучей в Win32 являются kernel32.HeapAlloc\HeapFree, которые в NT+ просто мапятся в соответствующие функции ntdll.RtlAllocateHeap\RtlFreeHeap. Некоторым "неудобством" этих функций является то, что им нужно передавать хэндл кучи. Для основной кучи процесса этот хэндл возвращается функцией GetProcessHeap. Разумеется при многократных вызовах HeapAlloc имеет смысл один раз получить этот хэндл и сохранить его в переменной hHeap. Но если кому и один раз "в лом" вызвать GetProcessHeap, то можно использовать GlobalAlloc с флагом GMEM_FIXED. GlobalAlloc первым делом устанавливает SEH-обработчик и проверяет флаги. Если флаг GMEM_MOVEABLE не установлен, то просто берется хэндл основной кучи, вызывается HeapAlloc и затем удаляется SEH. Разумеется имеем дополнительные затраты времени на лишние call'ы, jmp'ы и mov'ы, но чего не сделаешь ради "простоты"

С бестолковым флагом GMEM_MOVEABLE дела обстоят гораздо хуже. В итоге память точно также выделяется HeapAlloc, но дополнительно создается дескриптор HGLOBAL, хранящий ссылку на выделенный блок памяти. В Win 9x и NT дескрипторы создаются и хранятся по разному. В Win 9х память под дескриптор выделяется в той же основной куче процесса, то есть вместо одного HeapAlloc имеем два, плюс различные навороты типа блокировки кучи HeapLock\Unlock и т.п. В Win NT под дескрипторы HGLOBAL вообще выделяется отдельный регион памяти, который отъедает у процесса 512К(!) виртуальных адресов и как минимум 4К физической памяти у системы. Выделение памяти под дескрипторы производится при первом вызове GlobalAlloc с флагом GMEM_MOVEABLE и естественно сопровождается огромными потерями времени на обработку отказа страницы ― не менее 4-5 тысяч тактов процессора.
Вот и спрашивается: насколько нужно любить и уважать "традиции", чтобы
  1. использовать совершенно бессмысленный флаг GMEM_MOVEABLE, зная, что в реальной ситуации блоки памяти в куче никуда не перемещаются
  2. бессмысленно вызывать GlobalLock\GlobalUnlock, которые только и делают, что увеличивают или уменьшают счетчик ссылок в HGLOBAL, а блок памяти как сидел на своем месте в куче так и сидит
  3. занимать 512К виртуальных адресов и 4К дополнительной физической памяти и напрягать процессор и систему, заставляя их выделять новую страницу только для того, что нам пришло в голову обращаться к выделенному блоку кучи не напрямую, а через через одно хорошо известное место
PS: Еще пара замечаний до кучи:
  1. В GlobalUnlock положено передавать хэндл hMemory, а не указатель на блок pMemory. Хотя с pMemory тоже работает благодаря внутренним взаимным ссылкам hMemory - pMemory
  2. задавать флаги GMEM_ZEROINIT или HEAP_ZERO_MEMORY во многих случаях не имеет смысла, как в рассматриваемом примере с ReadFile\WriteFile. При SendMessage+WriteFile вообще незачем занулять блок памяти, а при чтении файла достаточно занулить последний байт считанной строки и не тратить впустую время на обнуление всего блока размером MEMSIZE=64K
Plis /2009-04-10 08:06:52/
Вместо:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
    invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE
    mov hMemory,eax
    invoke GlobalLock,hMemory
    mov pMemory,eax
 
    invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR
    SizeReadWrite,NULL
    invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,pMemory
    invoke CloseHandle,hFile
 
    invoke GlobalUnlock,pMemory
    invoke GlobalFree,hMemory
переделал:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
    invoke GetProcessHeap
    mov hHeap,eax
    invoke HeapAlloc, hHeap,HEAP_ZERO_MEMORY,MEMSIZE
    mov pMemory,eax 
 
    invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR SizeReadWrite,NULL
    invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,pMemory
 
    invoke HeapFree, hHeap, NULL, pMemory
    invoke CloseHandle,hFile
Всё работает... Хотя, у Iczelion'а многое работает с ошибками...
Plis /2009-04-28 06:24:12/
В моём применении HeapAlloc какя то ошибка. Теперь меню Save работает только если файл сначала прочитать в диалоговое окно, а посл сохранить. Если сразу напечатать в диалоговом окне текст и попытаться сохранить, то файл сваливается в дебагер. Кто просветит в применении данной функции?
Plis /2009-04-28 09:27:18/
Ошибку помог исправить leo ― нужно:
Кликните здесь для просмотра всего текста
Assembler
1
2
    invoke GetProcessHeap 
    mov hHeap,eax
определить в начале кода до вызова WinMain и всё работает!

Скачайте файл примера здесь.
ПРАКТИКА ― СЕСТРА ШИЗОФРЕНИИ
Приведенная ниже программа отображает открытый файловое диалоговое окно. Оно позволяет пользователю использовать текстовый файл, чтобы открыть и показать содержимое файла в клиентской области edit control'а. Пользователь может изменять текст в edit control'е по своему усмотрению, а затем может сохранить содержимое в файл.
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 1755 bytes
du macro string
local bslash
bslash=0
irpc c,
if bslash eq 0
    if '&c' eq "\";;управляющая последовательность символов
    bslash=1
    elseif '&c' eq "ё"
    db 51h,4
    elseif '&c' eq "Ё"
    db 1,4
    elseif '&c' gt 127
    db ('&c'- 0B0h),4;;кириллица
    else
    dw '&c'          ;;латиница
    endif
else
bslash=0
    if '&c' eq "n"    ;;  \n=новая строка
        DW 0Dh,0Ah
        elseif '&c' eq "\";;  \\=обратная косая черта (\)
        dw '\'
        elseif '&c' eq "r";;  \r=возврат каретки
        dw 0Dh
        elseif '&c' eq "l";;  \l=LF
        dw 0Ah
        elseif '&c' eq "s"
        dw 20h
        elseif '&c' eq "c"
        dw 3Bh
        elseif '&c' eq "t";;  \t=табуляция*
        dw 9
    endif
endif
endm
dw 0
endm
; -----------------------------------------------------------------
exebase     equ 400000h
IDM_OPEN    equ 1
IDM_SAVE    equ 2
IDM_EXIT    equ 3
IDM_UNDO    equ 4
IDM_CUT     equ 5
IDM_COPY    equ 6
IDM_PASTE   equ 7
IDM_ABOUT   equ 8
IDM_DEL     equ 9
IDM_SETSEL      equ 10
MAXSIZE     equ 260
MEMSIZE     equ 65535
EditID      equ 1
IDC_MENU    equ 30
;----------------------------------------------------------
.code
main:
include capito_res.asm
;--------------------------------------------
start:  xor ebx,ebx
    invoke GetProcessHeap
    mov hHeap+exebase,eax
    mov esi,400000h
    mov edi,offset AppName+exebase
    invoke RegisterClass,esp,ebx,offset WndProc+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,IDC_MENU,edi
    push ebx
    push esi
    shl esi,9
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,edi,edi,\
        WS_VISIBLE or WS_OVERLAPPEDWINDOW,esi,esi,300,200,ebx,ebx
    mov ofn.hWndOwner+exebase,eax
    mov ebp,esp
message_loop: invoke GetMessage,ebp,ebx,ebx,ebx
        invoke TranslateMessage,ebp
        invoke DispatchMessage,ebp
        jmp message_loop
;----------------------------------------------------
WndProc: 
hWnd        equ dword ptr [ebp+8h]
uMsg        equ dword ptr [ebp+0Ch]
wParam      equ dword ptr [ebp+10h]
lParam      equ dword ptr [ebp+14h]
SizeReadWrite   equ dword ptr [ebp-4];number of bytes actually read or write
 
        enter 4,0
    mov eax,uMsg
    dec eax;.IF uMsg==WM_CREATE
    je short wmCREATE
    dec eax
    je short wmDESTROY
    sub eax,WM_SIZE-WM_DESTROY
    je short wmSIZE
        sub eax,WM_COMMAND-WM_SIZE
    je short wmCOMMAND
    leave
    jmp DefWindowProc+exebase
;----------------------------------------------------
wmSIZE: push TRUE
    mov ax,word ptr lParam+2
    push eax
    mov ax,word ptr lParam
    invoke MoveWindow,hwndEdit+exebase,ebx,ebx,eax
    jmp wmBYE
;----------------------------------------------------
wmDESTROY: invoke ExitProcess,ebx
;----------------------------------------------------
wmCREATE: invoke CreateWindowEx,ebx,offset EditClass+exebase,ebx,\
    WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or \
    ES_AUTOHSCROLL or ES_AUTOVSCROLL,ebx,ebx,ebx,ebx,hWnd,\
    EditID,exebase,ebx
    mov hwndEdit+exebase,eax
    jmp a2
;----------------------------------------------------
wmCOMMAND: mov ax,word ptr wParam
    cmp lParam,ebx
    jne wmBYE
        mov ecx,offset ofn+exebase
    jmp dword ptr [handler+eax*4-4+exebase]
UNDO:   mov eax,EM_UNDO
    jmp short send_to_editor
CUT:    mov eax,WM_CUT
    jmp short send_to_editor
COPY:   mov eax,WM_COPY
    jmp short send_to_editor
DEL:    mov eax,WM_CLEAR
    jmp short send_to_editor
SETSEL: mov eax,EM_SETSEL
    push -1
    jmp short a0
PASTE:  mov eax,WM_PASTE
send_to_editor: push ebx
a0: invoke SendMessage,hwndEdit+exebase,eax,ebx
    jmp wmBYE
ABOUT:  invoke ShellAbout,hWnd,offset AppName+exebase,\
    offset AboutMsg+exebase,ebx
    jmp wmBYE
OPEN:   mov [ecx].OPENFILENAME.Flags,OFN_FILEMUSTEXIST or OFN_EXPLORER \
        or OFN_LONGNAMES or OFN_HIDEREADONLY or OFN_PATHMUSTEXIST
    invoke GetOpenFileName,ecx
    test eax,eax
    je a2;.if eax==TRUE
;открыть выбранный файл
    invoke CreateFile,offset buffer+exebase,GENERIC_READ \
        or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,\
        ebx,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,ebx
    xchg edi,eax;mov hFile,eax
;выделить память
        invoke HeapAlloc,hHeap+exebase,HEAP_ZERO_MEMORY,MEMSIZE
    xchg esi,eax;pointer to the allocated memory block
;прочитать файл
    lea ecx,SizeReadWrite
    invoke ReadFile,edi,esi,MEMSIZE-1,ecx,ebx
;послать окну редактора сообщение WM_SETTEXT о том, 
;что нужно забрать текст из буфера
    invoke SendMessage,hwndEdit+exebase,WM_SETTEXT,ebx,esi;pMemory
    jmp short a1
SAVE:   mov [ecx].OPENFILENAME.Flags,OFN_LONGNAMES or\
        OFN_EXPLORER or OFN_OVERWRITEPROMPT;HIDEREADONLY
    invoke GetSaveFileName,ecx
    xchg eax,ecx
    jecxz a2;.if eax==TRUE
;создать файл
    invoke CreateFile,offset buffer+exebase,GENERIC_READ or \
        GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,ebx,\
        CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,ebx
    xchg edi,eax;mov hFile,eax
;выделить память
        invoke HeapAlloc,hHeap+exebase,HEAP_ZERO_MEMORY,MEMSIZE
    xchg esi,eax;mov pMemory,eax
;забрать текст из редактора
    invoke SendMessage,hwndEdit+exebase,WM_GETTEXT,MEMSIZE-1,esi;pMemory
;записать в файл
        invoke lstrlen,esi;pMemory
    lea ecx,SizeReadWrite
    invoke WriteFile,edi,esi,eax,ecx,ebx
a1: invoke HeapFree,hHeap+exebase,ebx,esi;pMemory
    invoke CloseHandle,edi;hFile
a2: invoke SetFocus,hwndEdit+exebase
    jmp short wmBYE
EXIT:   invoke DestroyWindow,hWnd
wmBYE:  leave
    retn 16
;----------------------------------------------------
handler dd OPEN+exebase,SAVE+exebase,EXIT+exebase,UNDO+exebase,\
CUT+exebase,COPY+exebase,PASTE+exebase,ABOUT+exebase,DEL+exebase,\
SETSEL+exebase
AppName     db "Win32 ASM Edit",0
EditClass   db "edit",0
ofn   OPENFILENAME 
FilterString    db "All Files",0,"*.*",0
                db "Text Files",0,"*.txt",0,0
AboutMsg    db 'Mikl__ 2011',0
buffer      db MAXSIZE dup(0)
hwndEdit    dd ?
hHeap       dd ?
align 4
;-----------------------------------------------------------------
MFR_END     equ 80h
MFR_POPUP   equ 1
MFT_STRING  equ 0
MFS_ENABLED equ 0
MFT_SEPARATOR   equ 800h
RT_MENU     equ 4
POPUP       equ 0010h
MENUBREAK       equ 0040h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
resource:       
Characteristics0    dd 0
TimeDateStamp0      dd 0
MajorVersion0       dw 0
MinorVersion0       dw 0
NumberOfNamedEntries0   dw 0
NumberOfIdEntries0  dw 1
dw RT_MENU,0
dw x-resource,8000h
x:
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0
NumberOfNamedEntries1   dw 0
NumberOfIdEntries1  dw 1
dw IDC_MENU,0
dw x1-resource,8000h
x1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0
NumberOfNamedEntries2   dw 0
NumberOfIdEntries2  dw 1
dw 40Ah,0,x2-resource,0
x2:
OffsetToData0   dd menu
Size0       dd end_menu-menu
CodePage0   dd 0
Reserved0   dd 0
menu dw 0,0,POPUP; or MFR_END
du <&Файл>
dw MFT_STRING or MFS_ENABLED,IDM_OPEN
du <&Открыть>
dw MFT_STRING or MFS_ENABLED,IDM_SAVE
du <&Сохранить>
dw MENUBREAK,0,0;NOTEXT
dw MFT_STRING or MFS_ENABLED or MFR_END,IDM_EXIT
du <В&ыход>
dw POPUP
du <&Правка>
dw MFT_STRING or MFS_ENABLED,IDM_UNDO
du <О&тменить>
dw MFT_STRING or MFS_ENABLED,IDM_CUT
du <&Вырезать>
dw MFT_STRING or MFS_ENABLED,IDM_COPY
du <&Копировать>
dw MFT_STRING or MFS_ENABLED,IDM_PASTE
du <Вст&авить>
dw MFT_STRING or MFS_ENABLED,IDM_DEL
du <О&чистить>
dw MFT_STRING or MFS_ENABLED or MFR_END,IDM_SETSEL
du <В&ыделить всё>
dw POPUP or MFR_END
du <&Справка>
dw MFR_END,IDM_ABOUT
du <&О программе>
end_menu:
end_resource:
;--------------------------------------------------------------
import dd 0,0,0,user32_dll
dd user_table
dd 0,0,0,kernel32_dll
dd kernel_table
dd 0,0,0,comdlg32_dll
dd comdlg_table
dd 0,0,0,shell32_dll
dd shell_table
dd 0,0
shell_table:
ShellAbout      dd _ShellAbout,0
user_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
DestroyWindow           dd _DestroyWindow
TranslateMessage    dd _TranslateMessage
SendMessage     dd _SendMessage
SetFocus        dd _SetFocus
MoveWindow      dd _MoveWindow,0
kernel_table:
CreateFile      dd _CreateFile
HeapAlloc       dd _HeapAlloc
HeapFree        dd _HeapFree
ReadFile        dd _ReadFile
WriteFile       dd _WriteFile
lstrlen         dd _lstrlen
GetProcessHeap      dd _GetProcessHeap
CloseHandle     dd _CloseHandle
ExitProcess             dd _ExitProcess,0
comdlg_table:
GetSaveFileName     dd _GetSaveFileName
GetOpenFileName     dd _GetOpenFileName
            dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_DestroyWindow      db 0,0,"DestroyWindow"
_SendMessage        db 0,0,'SendMessageA'
_SetFocus       db 0,0,'SetFocus'
_MoveWindow     db 0,0,'MoveWindow'
_TranslateMessage   db 0,0,'TranslateMessage',0
user32_dll      db 'user32'
_CreateFile     db 0,0,'CreateFileA'
_HeapAlloc      db 0,0,'HeapAlloc'
_HeapFree       db 0,0,'HeapFree'
_GetProcessHeap     db 0,0,'GetProcessHeap'
_ReadFile       db 0,0,'ReadFile'
_WriteFile      db 0,0,'WriteFile'
_CloseHandle        db 0,0,'CloseHandle'
_lstrlen        db 0,0,'lstrlenA'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_GetSaveFileName    db 0,0,'GetSaveFileNameA'
_GetOpenFileName    db 0,0,'GetOpenFileNameA',0
comdlg32_dll        db 'comdlg32'
_ShellAbout     db 0,0,'ShellAboutA',0
shell32_dll     db 'shell32'
end_import:
end main
Разбор полетов
В отличие от Iczelion, который инициализирует структуру OPENFILENAME во время получения сообщения WM_CREATE мы заполнили эту структуру в секции данных и не тратим ни программного времени, ни дополнительных байтов.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
ofn   OPENFILENAME <sizeof(OPENFILENAME),?,exebase,\
offset FilterString+exebase,?,?,?,offset buffer+exebase,\
MAXSIZE,0,?,?,?,?,?,?,0,?,?,?>
Также как Iczelion, мы заполняем только общие члены структуры, поле ofn.hWndOwner получает свое значение сразу после создания родительского окна
Кликните здесь для просмотра всего текста
Assembler
1
2
3
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,edi,edi,\
        WS_VISIBLE or WS_OVERLAPPEDWINDOW,esi,esi,300,200,ebx,ebx
    mov ofn.hWndOwner+exebase,eax
а поле ofn.Flags по разному заполняется при открытии или сохранении файла
Мы получаем сообщения WM_SIZE, когда pазмеp клиентской области нашего основного окна изменяется. Мы также получаем его, когда окно создается. Для того, чтобы получать это сообщение, стили класса окна должны включать CS_REDRAW и CS_HREDRAW. Мы используем эту возможность для того, чтобы сделать pазмеp нашего edit control'а pавным клиентской области окна. Для начала мы должны узнать текущую ширину и высоту клиентской области родительского окна. Мы получаем эту информацию из lParam. Старшее слово lParam содержит высоту, а младшее слово ― ширину клиентской области. Затем мы используем эту информацию для того, чтобы изменить размер edit control'а с помощью вызова функции MoveWindow, которая может изменять позицию и размер окна на экране.

Вариант Iczelion'a
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
    mov eax,lParam
        mov edx,eax
        shr edx,16
        and eax,0ffffh
        invoke MoveWindow,hwndEdit,0,0,eax,edx,TRUE
Наш вариант
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
wmSIZE: push TRUE
    mov ax,word ptr lParam+2
    push eax
    mov ax,word ptr lParam
    invoke MoveWindow,hwndEdit+exebase,ebx,ebx,eax
Мы пользуемся тем, что в момент перехода к метке wmSIZE содержимое eax равно нулю ― поэтому мы последовательно помещаем в ax старшее, а затем младшее слово lParam и отправляем eax в стек ― это позволяет не использовать сдвиг вправо для выделения старшего слова lParam и операцию "логическое И" для выделения младшего слова и получения 32-битных значений в eax и edx.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
a1: invoke HeapFree,hHeap+exebase,ebx,pMemory
    invoke CloseHandle,hFile
a2: invoke SetFocus,hwndEdit+exebase
Iczelion дважды использует одинаковые фрагменты программы по закрытию файла, освобождению памяти и передаче фокус ввода на edit control после открытия и сохранения файла. Вызов функции SetFocus с параметром hwndEdit есть также при выходе из обработки сообщения WM_CREATE
Кликните здесь для просмотра всего текста
Функционал нашего простейшего редактора оказалось совершенно не сложно дополнить командами редактирования: "Отменить", "Вырезать", "Копировать", "Вставить", "Очистить", "Выделить всё". Всё, что для этого требуется ― это послать через функцию SendMessage для hwndEdit сообщения: EM_UNDO ("Отменить"), WM_CUT ("Вырезать"), WM_COPY ("Копировать"), WM_PASTE ("Вставить"), WM_CLEAR ("Очистить"), EM_SETSEL ("Выделить всё") ― остальное система доделает самостоятельно...
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
UNDO:   mov eax,EM_UNDO
    jmp short send_to_editor
CUT:    mov eax,WM_CUT
    jmp short send_to_editor
COPY:   mov eax,WM_COPY
    jmp short send_to_editor
DEL:    mov eax,WM_CLEAR
    jmp short send_to_editor
SETSEL: mov eax,EM_SETSEL
    push -1
    jmp short a0
PASTE:  mov eax,WM_PASTE
send_to_editor: push ebx
a0: invoke SendMessage,hwndEdit+exebase,eax,ebx

_________________________________
© Mikl___ 2013
3
Изображения
 
Mikl___
Заблокирован
Автор FAQ
14.01.2013, 11:25  [ТС] #43
Win32 API. Урок 13. Memory Mapped файлы
Я покажу вам, что такое Memory Mapped файлы и как использовать их для вашей выгоды. Использование MMF достаточно просто, как вы увидите из этого туторила.

Скачайте пример здесь.
ТЕОРИЯ ― МАТЬ СКЛЕРОЗА
Если вы хорошо изучили пример из прошлого туториала, вы увидите, что у него есть серьезный недостаток: что, если файл, который вы хотите прочитать больше, чем зарезервированный блок памяти? или если строка, которую вы хотите найти будет обрезана посередине, потому что кончился блок памяти? Традиционный ответ на первый вопрос ― это то, что вам нужно последовательно читать данные из файла, пока он не кончится. Ответом на второй вопрос является то, что вы должны обрабатывать подобную возможность. Это называется проблемой пограничного значения. Она представляет собой головную большую для программистов и вызывает неисчислимое количество ошибок в программе.
Было бы неплохо, если бы мы могли зарезервировать очень большой блок памяти, достаточный для того, чтобы сохранить весь файл, но наша программа стала бы очень прожорливой в плане ресурсов. File maрing ― это спасение. Используя его, вы можете считать весь файл уже загруженным в память и использовать указатель на память, чтобы читать или писать данные в файл. Очень просто. Hет нужды использовать API памяти и файловые API одновременно, в File maрing это одно и то же. File maрing также используется для обмена данными между процессами. При использовании File maрing таким образом, реально не используется никакой файл. Это больше похоже на блок памяти, который могут видеть все процессы. Hо обмен данными между процессами ― весьма деликатный предмет. Вы должны будете обеспечить синхронизацию между процессами и ветвями, иначе ваше приложение очень скоро повиснет.

Мы не будем касаться того, как использовать File maрing для создания общего pегиона памяти в этом туториале. Мы сконцентрируемся на том, как использовать File maрing для "загрузки" файла в память. Фактически, PE-загрузчик использует File maрing для загрузки исполняемых файлов в память. Это очень удобно, так как только необходимые порции файла будут считываться с диска. Под Win32 вам следует использовать File maрing так часто, как это возможно.

Правда, существует несколько ограничений при использовании File maрing. Как только вы создали такой файл, его размер не может изменяться до закрытия сессии. Поэтому File maрing прекрасно подходит для файлов из которых нужно только читать или файловых операций, которые не изменяют размер файла. Это не значит, что вы не можете использовать File maрing, если хотите увеличить pазмеp файла. Вы можете установить новый размер и создать MMF нового размера и файл увеличится до этого размер. Это просто неудобно, вот и все.

Достаточно объяснений. Давайте перейдем к реализации File maрing. Для того, чтобы его использовать, должны быть выполнены следующие шаги.
  1. Вызов CreateFile для открытия файла.
  2. Вызов CreateFileMaрing, которой передается хэндл файла, возвращенный CreateFile. Эта функция создает File maрing-объект из файла, созданного CreateFile'ом.
  3. Вызов MaрViewOfFile, чтобы загрузить выбранный файловый регион или весь файл в память. Эта функция возвращает указатель на первый байт промэппированного файлового региона.
  4. Используйте указатель, чтобы писать или читать из файла.
  5. Вызовите UnmaрViewOfFile, чтобы выгрузить файл.
  6. Вызов CloseHandle, передав ему хэндл промэппированного файла в качестве одного из параметра, чтобы закрыть его.
  7. Вызов CloseHandle снова, передав ему в этот раз хэндл файла, возвращенный CreateFile, чтобы закрыть сам файл.
ПРАКТИКА ― СЕСТРА ШИЗОФРЕНИИ
Программа, листинг которой приведен ниже, позволит вам открыть файл с помощью окна открытия файла. Она откроет файл, используя File maрing, если это удастся, заголовок окна изменится на имя открытого файла. Вы можете сохранить файл под другим именем, выбрав пункт меню File/Save. Программа скопирует все содержимое открытого файла в новый файл. Учтите, что вы не должны вызывать GlobalAlloc для резервирования блока памяти в этой программе.
Кликните здесь для просмотра всего текста
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
   .386
   .model flat,stdcall
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
 
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   include \masm32\include\comdlg32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
   includelib \masm32\lib\comdlg32.lib
 
   .const
   IDM_OPEN equ 1
   IDM_SAVE equ 2
   IDM_EXIT equ 3
   MAXSIZE equ 260
 
   .data
   ClassName db "Win32ASMFileMappingClass",0
   AppName  db "Win32 ASM File Mapping Example",0
   MenuName db "FirstMenu",0
 
   ofn   OPENFILENAME <>
   FilterString db "All Files",0,"*.*",0
                db "Text Files",0,"*.txt",0,0
   buffer db MAXSIZE dup(0)
 
   hMaрFile HANDLE 0 ; Указатель на MMF, должен быть инициализирован
; нулем, так как мы также используем его в качестве флага в секции WM_DESTROY
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   hFileRead HANDLE ?                         ; Хэндл источника
   hFileWrite HANDLE ?                        ; Хэндл выходного файла
   hMenu HANDLE ?
   pMemory DWORD ?                            ; Указатель на данные в исходном файле
   SizeWritten DWORD ?                        ; количество байтов
   actually written by WriteFile
 
   .code
start:   invoke GetModuleHandle, NULL
           mov    hInstance,eax
           invoke GetCommandLine
           mov CommandLine,eax
           invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
           invoke ExitProcess,eax
 
WinMain proc  hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
       LOCAL wc:WNDCLASSEX
       LOCAL msg:MSG
       LOCAL hwnd:HWND
 
       mov   wc.cbSize,SIZEOF WNDCLASSEX
       mov   wc.style, CS_HREDRAW or CS_VREDRAW
       mov   wc.lpfnWndProc, OFFSET WndProc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_WINDOW+1
       mov   wc.lpszMenuName,OFFSET MenuName
       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_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,300,200,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_CREATE
           invoke GetMenu,hWnd                  ; Получаем хэндл меню
           mov  hMenu,eax
           mov ofn.lStructSize,SIZEOF ofn
           push hWnd
           pop  ofn.hWndOwner
           push hInstance
           pop  ofn.hInstance
           mov  ofn.lpstrFilter, OFFSET FilterString
           mov  ofn.lpstrFile, OFFSET buffer
           mov  ofn.nMaxFile,MAXSIZE
       .ELSEIF uMsg==WM_DESTROY
           .if hMapFile!=0
               call CloseMapFile
           .endif
           invoke PostQuitMessage,NULL
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wParam
           .if lParam==0
               .if ax==IDM_OPEN
    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 CreateFile,ADDR buffer,GENERIC_READ ,0,\
   NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
                       mov hFileRead,eax
                       invoke   CreateFileMapping,hFileRead,NULL,PAGE_READONLY,0,0,NULL
                       mov     hMapFile,eax
                       mov     eax,OFFSET buffer
                       movzx  edx,ofn.nFileOffset
                       add      eax,edx
                       invoke SetWindowText,hWnd,eax
                       invoke EnableMenuItem,hMenu,IDM_OPEN,MF_GRAYED
                       invoke EnableMenuItem,hMenu,IDM_SAVE,MF_ENABLED
                   .endif
               .elseif ax==IDM_SAVE
                   mov ofn.Flags,OFN_LONGNAMES or  OFN_EXPLORER or OFN_HIDEREADONLY
                   invoke GetSaveFileName, ADDR ofn
                   .if eax==TRUE
                       invoke CreateFile,ADDR buffer,GENERIC_READ or \
      GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,\
   CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE,NULL
                       mov hFileWrite,eax
                       invoke MapViewOfFile,hMapFile,FILE_MAP_READ,0,0,0
                       mov pMemory,eax
                       invoke GetFileSize,hFileRead,NULL
                       invoke WriteFile,hFileWrite,pMemory,eax,ADDR SizeWritten,NULL
                       invoke UnmapViewOfFile,pMemory
                       call   CloseMapFile
                       invoke CloseHandle,hFileWrite
                       invoke SetWindowText,hWnd,ADDR AppName
                       invoke EnableMenuItem,hMenu,IDM_OPEN,MF_ENABLED
                       invoke EnableMenuItem,hMenu,IDM_SAVE,MF_GRAYED
                   .endif
               .else
                   invoke DestroyWindow, hWnd
               .endif
           .endif
       .ELSE
           invoke DefWindowProc,hWnd,uMsg,wParam,lParam
           ret
       .ENDIF
       xor    eax,eax
       ret
   WndProc endp
 
   CloseMapFile PROC
           invoke CloseHandle,hMapFile
           mov    hMapFile,0
           invoke CloseHandle,hFileRead
           ret
   CloseMapFile endp
   end start
Разбор полётов
Кликните здесь для просмотра всего текста
Assembler
1
2
  invoke CreateFile,ADDR buffer,GENERIC_READ,0,\
          NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
Когда пользователь выбирает файл в окне открытия файла, мы вызываем CreateFile, чтобы открыть его. Заметьте, что мы указываем GENERIC_READ, чтобы открыть этот файл в режиме read-only, потому что мы не хотим, чтобы какие-либо другие процессы изменяли файл во время нашей работы с ним.
Кликните здесь для просмотра всего текста
Assembler
1
  invoke CreateFileMapping,hFileRead,NULL,PAGE_READONLY,0,0,NULL
Затем мы вызываем CreateFileMaрing, чтобы создать MMF из открытого файла.
CreateFileMapping имеет следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
2
   CreateFileMapping proto hFile:DWORD, lpFileMappingAttributes:DWORD,flProtect:DWORD,\
   dwMaximumSizeHigh:DWORD, dwMaximumSizeLow:DWORD, lpName:DWORD
  • Вам следует знать, что CreateFileMaрing не обязана мэппировать весь файл в память. Вы можете промэппировать только часть файла. Размер мэппируемого файла вы задаете параметрами dwMaximumSizeHigh и dwMaximumSizeLow. Если вы зададите размер больше, чем его действительный размер, файл будет увеличен до нового размера. Если вы хотите, чтобы MMF был такого же размера, как и исходный файл, сделайте оба параметра pавными нулю.
  • Вы можете использовать NULL в lpFileMappingAttributes, чтобы Windows создали MMF со значениями безопасности по умолчанию.
  • flProtect ― определяет желаемую защиту для MMF. В нашем примере, мы используем PAGE_READONLY, чтобы разрешить только операции чтения над MMF. Заметьте, что этот атрибут не должен входить в противоречие с атрибутами, указанными в CreateFile, иначе CreateFileMaрing возвратит ошибку.
  • lрName ― указывает на имя MMF. Если вы хотите разделять этот файл с другими процессами, вы должны присвоить ему имя. Hо в нашем примере другие процессы не будут его использовать, поэтому мы игнорируем этот параметр.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
                       mov     eax,OFFSET buffer
                       movzx  edx,ofn.nFileOffset
                       add      eax,edx
                       invoke SetWindowText,hWnd,eax
Если CreateFileMapping выполнилась успешно, мы изменяем название окна на имя открытого файла. Имя файла с полным путем сохраняется в буфере, мы же хотим отобразить только собственно имя файла, поэтому мы должны добавить значение параметра nFileOffset структуры OPENFILENAME к адресу буфера.
Кликните здесь для просмотра всего текста
Assembler
1
2
                       invoke EnableMenuItem,hMenu,IDM_OPEN,MF_GRAYED
                       invoke EnableMenuItem,hMenu,IDM_SAVE,MF_ENABLED
В качестве меры предосторожности, мы не хотим чтобы пользователь мог открыть несколько файлов за pаз, поэтому делаем пункт меню Open недоступным для выбора и делаем доступным пункт Save. EnableMenuItem используется для изменения атрибутов пункта меню. После этого, мы ждем, пока пользователь выберет File/Save или закроет программу.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
       .ELSEIF uMsg==WM_DESTROY
 
           .if hMapFile!=0
               call CloseMapFile
           .endif
           invoke PostQuitMessage,NULL
В выше приведенном коде, когда процедура окна получает сообщение WM_DESTROY, она сначала проверяет значение hMaрFile ― равно ли то нулю или нет. Если оно не равно нулю, она вызывает функцию CloseMapFile, которая содержит следующий код:
Кликните здесь для просмотра всего текста
[asm] CloseMapFile PROC
invoke CloseHandle,hMapFile
mov hMapFile,0
invoke CloseHandle,hFileRead
ret
CloseMapFile endp[/asm
] CloseMaрFile закрывает MMF и сам файл, так что наша программа не оставляет за собой следов при выходе из Windows. Если пользователь выберет сохранение информации в другой файл, программа покажет ему окно сохранения файла. После он сможет напечатать имя нового файла, который и будет создать функцией CreateFile.
Кликните здесь для просмотра всего текста
Assembler
1
2
      invoke MapViewOfFile,hMapFile,FILE_MAP_READ,0,0,0
                       mov pMemory,eax
Сpазу же после создания выходного файла, мы вызываем MapViewOfFile, чтобы промэппировать желаемую порцию MMF в память. Эта функция имеет следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
   MapViewOfFile proto hFileMappingObject:DWORD,\
                                      dwDesiredAccess:DWORD,\
                                      dwFileOffsetHigh:DWORD,\
                                      dwFileOffsetLow:DWORD,\
                                      dwNumberOfBytesToMap:DWORD
  • dwDesiredAccess определяет, какую операцию мы хотим совершить над файлом. В нашем примере мы хотим только прочитать данные, поэтому мы используем FILE_MAP_READ.
  • dwFileOffsetHigh и dwFileOffsetLow задают стартовый файловое смещение файловой порции, которую вы хотите загрузить в память. В нашем случае нам нужно мы хотим читать весь файл, поэтому начинаем мэппинг со смещение ноль.
  • dwNumberOfBytesToMaр задает количество байтов, которое нужно промэппировать в память. Чтобы сделать это со всем файлом, передайте ноль MaрViewOfFile.
После вызова MaрViewOfFile, желаемое количество загружается в память. Вы получите указатель на блок памяти, который содержит данные из файла.
Кликните здесь для просмотра всего текста
Assembler
1
      invoke GetFileSize,hFileRead,NULL
Теперь узнаем, какого размера наш файл. Размер файла возвращается в eax. Если файл больше, чем 4 GB, то верхнее двойное слово размера файла сохраняется в FileSizeHighWord. Так как мы не ожидаем встретить таких больших файлов, мы можем проигнорировать это.
Кликните здесь для просмотра всего текста
Assembler
1
   invoke WriteFile,hFileWrite,pMemory,eax,ADDR SizeWritten,NULL
Запишем данные в выходной файл.
Кликните здесь для просмотра всего текста
Assembler
1
   invoke UnmapViewOfFile,pMemory
Когда мы заканчиваем со входным файлом, вызываем UnmapViewOfFile.
Кликните здесь для просмотра всего текста
Assembler
1
2
    call   CloseMapFile
                       invoke CloseHandle,hFileWrite
И закрываем все файлы.
Кликните здесь для просмотра всего текста
Assembler
1
 invoke SetWindowText,hWnd,ADDR AppName
Восстанавливаем оригинальное название окна.
Кликните здесь для просмотра всего текста
Assembler
1
2
 invoke EnableMenuItem,hMenu,IDM_OPEN,MF_ENABLED
                       invoke EnableMenuItem,hMenu,IDM_SAVE,MF_GRAYED
разрешаем доступ к пункту меню Oрen и запрещаем к Save As.
_______________________________
© Iczelion, пер. Aquila.
3
Mikl___
Заблокирован
Автор FAQ
15.01.2013, 06:49  [ТС] #44
Win32 API. Урок 13a. Файлы, проецируемые в память (Memory Mapped Files)ТЕОРИЯ ― МАТЬ СКЛЕРОЗА
Скачайте пример здесь.

Процессор не может работать с содержимым файла, находящегося непосредственно на диске. для обращения к какому-либо участку файла этот участок необходимо сначала прочитать в память. Если же требуется не просто обрабатывать данные из файла, а модифицировать его содержимое, то к операции чтения файла добавляется еще и операция его записи. Стандартная для DOS- и 16-разрядных Windows-приложений процедура работы с файлом на диске включала следующие этапы:
  1. открытие файла на диске;
  2. чтение требуемого участка файла в созданную заранее программную переменную;
  3. модификация этой программной переменной по заданному алгоритму;
  4. запись модифицированной переменной на то же место в файле на диске.
Обычно работа с файлом требует обращений не к одному его участку, а к нескольким, и тогда перечисленные выше операции придется выполнять повторно. Во многих случаях, особенно при обслуживании огромных баз данных, программа по ходу выполнения запросит различные участки файла сотни или тысячи раз, и если запросы происходят не упорядоченно, а «в разбивку», то каждое обращение к файлу требует выполнения операций физического чтения/записи, что существенно замедлит скорость выполнения программы.
Значительно более эффективным будет чтение всего файла в оперативную память. В этом случае потребуется только одна операция физического чтения в начале сеанса и одна операция физической записи в конце сеанса. Однако такая методика возможна только с файлами относительно небольшого размера; к тому же в этом случае резко снижается надежность системы, так как новые, модифицированные данные записываются на диск только в конце сеанса и любой сбой программы приведет к потере всех модификаций.
Windows предоставляет механизм для работы с файлами исключающий операции физической записи/чтения, который сводится к тому, что конкретный файл включается в состав физической памяти, затем в адресном пространстве приложения резервируется регион достаточного размера и часть физической памяти, включающая в себя файл, отображается на этот регион (передается региону). Дальнейшие операции с файлом заменяются на операции с его отображением (проекцией) в адресном пространстве приложения.

Процедура создания и использования проекции файла распадается на следующие этапы:
  1. открытие (создание) файла обычным образом с помощью CreateFile;
  2. создание в физической памяти объекта «проекция файла» с помощью CreateFileMapping;
  3. создание в виртуальной (линейной) памяти приложения региона адресного пространства и отображения созданной проекции на адресное пространство процесса с помощью MapViewOfFile;
  4. чтение или запись по адресам памяти, на которые отображена проекция, так же, как это выполняется для любых программных переменных.
Практика ― сестра шизофрении
Кликните здесь для просмотра всего текста
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
.586p
.model tiny
include windows.inc
;for WinXP - 2039 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
MI_OPEN     equ 0
MI_SAVE     equ 1
MI_SAVEAS   equ 2
MI_CLOSE    equ 3
MI_NEW      equ 4
MI_EXIT     equ 5
MAXSIZE     equ 260
IDC_MENU    equ 30
EditID      equ 1
MEMSIZE     equ 865535
;------------------------------------------------------------------------
.code
main:
include capito_res.asm
;--------------------------------------------
start:  xor ebx,ebx
    mov esi,exebase
    mov edi,offset wTitle+exebase
;------------------------------
; registering the window class 
;------------------------------
    invoke RegisterClass,esp,ebx,offset window_procedure+exebase,\
    ebx,ebx,esi,ebx,10011h,COLOR_WINDOW+1,IDC_MENU,edi
;--------------------------+
; 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,esi,esi,ebx,ebx
    mov ofn.hWndOwner+exebase,eax   
    invoke GetMenu,eax;eax=hWnd
    mov hMenu+exebase,eax
    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:
hWnd        equ dword ptr [ebp+8h]
uMsg        equ dword ptr [ebp+0Ch]
wParam      equ dword ptr [ebp+10h]
lParam      equ dword ptr [ebp+14h]
    push ebp
    mov ebp,esp
    mov eax,uMsg
    dec eax
    je wmCREATE
    dec eax;cmp  [uMsg],WM_DESTROY
    je wmDESTROY
    sub eax,WM_SIZE-WM_DESTROY
    je wmSIZE
    sub eax,WM_COMMAND-WM_SIZE;     cmp  [uMsg],WM_COMMAND
    je wmCOMMAND
    leave
    jmp DefWindowProc+exebase
wmSIZE: push TRUE
    mov ax,word ptr lParam+2
    push eax
    mov ax,word ptr lParam
    invoke MoveWindow,hwndEdit+exebase,ebx,ebx,eax
    jmp wmBYE
wmCREATE: invoke CreateWindowEx,ebx,offset EditClass+exebase,ebx,\
    WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or \
    ES_AUTOHSCROLL or ES_AUTOVSCROLL,ebx,ebx,ebx,ebx,hWnd,EditID,\
    exebase,ebx
    mov hwndEdit+exebase,eax
    jmp wmBYE
wmCOMMAND: mov eax,wParam
    cmp lParam,ebx
    jne wmBYE
    mov edi,offset ofn+exebase
    mov esi,offset buffer+exebase
    jmp dword ptr [menu_handlers+eax*4+exebase]
OPEN:   mov dword ptr [edi+OPENFILENAME.Flags],OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or \
    OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
    invoke GetOpenFileName,edi
    test eax,eax
    je wmBYE
    invoke CreateFile,esi,GENERIC_READ or GENERIC_WRITE,\
    FILE_SHARE_READ or FILE_SHARE_WRITE,\
    ebx,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,ebx
    mov hFile+exebase,eax
;создание в памяти объекта "проекция файла"
    invoke CreateFileMapping,eax,ebx,PAGE_READWRITE,ebx,ebx,ebx
    mov hMapFile+exebase,eax
;отображение проекции файла на адресное пространство процесса
        invoke MapViewOfFile,eax,FILE_MAP_ALL_ACCESS,ebx,ebx,ebx
    mov pMemory+exebase,eax;pointer for the starting address of mapped file
        invoke SendMessage,hwndEdit+exebase,WM_SETTEXT,ebx,eax;pMemory+exebase
;-----------------------------
        invoke CloseHandle,hFile+exebase
    movzx eax,word ptr [edi+OPENFILENAME.nFileOffset]
    add eax,esi
    invoke SetWindowText,hWnd,eax
    mov esi,MF_GRAYED
    jmp @f
CLOSE:  ;уничтожение отображения файла на адресное пространство
    invoke UnmapViewOfFile,pMemory+exebase
;закрыть проекцию файла 
    invoke CloseHandle,hMapFile+exebase
    invoke SetWindowText,hwndEdit+exebase,ebx
    mov [esi],ebx
    invoke SendMessage,hwndEdit+exebase,WM_SETTEXT,ebx,ebx
    mov esi,MF_ENABLED
    jmp @f
NEW:    jmp wmBYE
SAVEAS: mov dword ptr [edi+OPENFILENAME.Flags],OFN_LONGNAMES or\
                                OFN_EXPLORER or OFN_HIDEREADONLY
    invoke GetSaveFileName,edi;ofn
    test eax,eax
    je wmBYE
SAVE:   invoke CreateFile,esi,GENERIC_READ or GENERIC_WRITE,\
    FILE_SHARE_READ or FILE_SHARE_WRITE,ebx,OPEN_ALWAYS,\
    FILE_ATTRIBUTE_ARCHIVE,ebx
    mov hFile+exebase,eax;file write handle
    invoke SendMessage,hwndEdit+exebase,WM_GETTEXT,MEMSIZE-1,pMemory+exebase
    invoke WriteFile,hFile+exebase,pMemory+exebase,eax,offset SizeWritten+exebase,ebx
;закрыть файл на диске
    invoke CloseHandle,hFile+exebase
    movzx eax,word ptr [edi+OPENFILENAME.nFileOffset]
    add eax,esi
    invoke SetWindowText,hWnd,eax
    mov esi,MF_ENABLED
@@: invoke EnableMenuItem,hMenu+exebase,ebx,esi
    xor esi,1;MF_ENABLED <--> MF_GRAYED
    push MI_NEW
    pop ebx
@@: invoke EnableMenuItem,hMenu+exebase,ebx,esi
    dec ebx
    jnz @b
    jmp wmBYE
EXIT:   invoke  DestroyWindow,hWnd
wmBYE:  leave
    retn 10h
wmDESTROY:;уничтожение отображения файла на адресное пространство
    invoke UnmapViewOfFile,pMemory+exebase
;закрыть проекцию файла 
    invoke CloseHandle,hMapFile+exebase
    invoke ExitProcess,ebx
;--------данные------------------------------
wTitle      db 'Iczelion Tutorial #13:Memory Mapped Files in MASM',0;name of our window
dOTitle     db 'Open File',0
FilterString    db 'All Files (*.*)',0,'*.*',0,0
buffer      db MAXSIZE dup(0)
ofn   OPENFILENAME <sizeof(OPENFILENAME),?,exebase,offset FilterString+exebase,\
?,?,?,offset buffer+exebase,MAXSIZE,0,?,?,?,?,?,?,0,?,?,?>
EditClass   db "edit",0
menu_handlers dd OPEN+exebase,SAVE+exebase,SAVEAS+exebase,CLOSE+exebase,NEW+exebase,EXIT+exebase
;-------------------------------------------------------------------------------------------
MFR_END equ 80h
MFR_POPUP   equ 1
MFT_STRING  equ 0
MFS_ENABLED equ 0
MFT_SEPARATOR   equ 800h
RT_MENU     equ 4
 
POPUP       equ 10h
MENUBREAK       equ 40h
ENDMENU     equ 80h
DS_SETFONT  equ 40h
align 4
resource:       
Characteristics0    dd 0
TimeDateStamp0      dd 0
MajorVersion0       dw 0
MinorVersion0       dw 0
NumberOfNamedEntries0   dw 0
NumberOfIdEntries0  dw 1
dw RT_MENU,0
dw x-resource,8000h
x:
Characteristics1    dd 0
TimeDateStamp1      dd 0
MajorVersion1       dw 0
MinorVersion1       dw 0;
NumberOfNamedEntries1   dw 0;количество ресурсов с именами
NumberOfIdEntries1  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором меню
dw IDC_MENU,0
dw x1-resource,8000h; если во 2-ом слове установлен старший бит - есть ссылка 
;на оглавление третьего уровня. В 1-ом слове смещение третьего оглавления 
;относительно начала раздела ресурсов
x1:
Characteristics2    dd 0
TimeDateStamp2      dd 0
MajorVersion2       dw 0
MinorVersion2       dw 0;
NumberOfNamedEntries2   dw 0;количество ресурсов с именами
NumberOfIdEntries2  dw 1;количество ресурсов с идентификаторами
;на этом уровне идентификатор ресурсов является идентификатором языка, который 
;используется данным ресурсом 16 * SUBLANG_ + LANG_
dw 40Ah,0,x2-resource,0
x2:;struct _IMAGE_RESOURCE_DATA_ENTRY
OffsetToData0   dd menu
Size0       dd end_menu-menu
CodePage0   dd 0
Reserved0   dd 0
menu dw 0,   0,POPUP or MFR_END
du <&File>
dw MFT_STRING  or  MFS_ENABLED,MI_OPEN
du <Op&en>
dw MFT_STRING  or  MF_GRAYED,MI_SAVE
du <&Save>
dw MFT_STRING  or  MF_GRAYED,MI_SAVEAS
du <&Save as>
dw MFT_STRING  or  MF_GRAYED,MI_CLOSE
du <C&lose>
dw MFT_STRING  or  MF_GRAYED,MI_NEW
du <&New>
dw MENUBREAK,0,0;NOTEXT
dw MFT_STRING  or  MFS_ENABLED  or  MFR_END,MI_EXIT
du <&Exit>
end_menu:
end_resource:
;---------------------------------------------------------------------
import:
;dd 0,0,0,
hFile   dd 0;file read handle
hMapFile    dd 0;file mapped handle
dd 0,user32_dll
dd user_table
;dd 0,0,0,
hMenu       dd 0;menu handle
pMemory     dd 0
SizeWritten dd 0;number of bytes actually read or write
dd kernel32_dll
dd kernel_table
hwndEdit    dd 0
dd 0,0,comdlg32_dll
dd comdlg_table
dd 0,0,0,0
user_table:
RegisterClass       dd _RegisterClass
CreateWindowEx          dd _CreateWindowEx
GetMessage              dd _GetMessage
DispatchMessage         dd _DispatchMessage
DefWindowProc           dd _DefWindowProc
DestroyWindow           dd _DestroyWindow
SetWindowText       dd _SetWindowText
SendMessage     dd _SendMessage
MoveWindow      dd _MoveWindow
TranslateMessage    dd _TranslateMessage
GetMenu         dd _GetMenu
EnableMenuItem      dd _EnableMenuItem,0
 
kernel_table:
CreateFileMapping   dd _CreateFileMapping
MapViewOfFile       dd _MapViewOfFile
UnmapViewOfFile     dd _UnmapViewOfFile
CreateFile      dd _CreateFile
WriteFile       dd _WriteFile
CloseHandle     dd _CloseHandle
ExitProcess             dd _ExitProcess,0
 
comdlg_table:
GetSaveFileName     dd _GetSaveFileName
GetOpenFileName     dd _GetOpenFileName
            dw 0
_RegisterClass      db 0,0,'RegisterClassA'      
_CreateWindowEx     db 0,0,'CreateWindowExA'
_GetMessage     db 0,0,'GetMessageA'
_DispatchMessage    db 0,0,'DispatchMessageA'
_DefWindowProc      db 0,0,'DefWindowProcA'
_DestroyWindow      db 0,0,"DestroyWindow"
_SetWindowText      db 0,0,'SetWindowTextA'
_GetMenu        db 0,0,'GetMenu'
_SendMessage        db 0,0,'SendMessageA'
_TranslateMessage   db 0,0,'TranslateMessage'
_MoveWindow     db 0,0,'MoveWindow'
_EnableMenuItem     db 0,0,'EnableMenuItem',0
user32_dll      db 'user32'
_CreateFileMapping  db 0,0,'CreateFileMappingA'
_MapViewOfFile      db 0,0,'MapViewOfFile'
_UnmapViewOfFile    db 0,0,'UnmapViewOfFile'
_CreateFile     db 0,0,'CreateFileA'
_WriteFile      db 0,0,'WriteFile'
_CloseHandle        db 0,0,'CloseHandle'
_ExitProcess        db 0,0,'ExitProcess',0
kernel32_dll        db 'kernel32'
_GetSaveFileName    db 0,0,'GetSaveFileNameA'
_GetOpenFileName    db 0,0,'GetOpenFileNameA',0
comdlg32_dll        db 'comdlg32'
end_import:
end main
_____________________________________
© Mikl___ 2013
2
Вложения
Тип файла: zip tut13a.zip (4.5 Кб, 65 просмотров)
Mikl___
Заблокирован
Автор FAQ
15.01.2013, 09:32  [ТС] #45
Win32 API. Урок 14. Процесс
Здесь мы изучим, что такое процесс, как его создать и как прервать.
Скачайте пример здесь.
ТЕОРИЯ - МАТЬ СКЛЕРОЗА
Что такое процесс? Я процитирую определение из справочника по Win32 API.
"Процесс ― это выполняющееся приложение, которое состоит из личного виртуального адресного пространства, кода, данных и других ресурсов операционной системы, таких как файлы, пайпы и синхронизационные объекты, видимые для процесса."
Как вы можете видеть из вышеприведенного определения, у процесса есть несколько объектов: адресное пространство, выполняемый модуль (модули) и все, что эти модули создают или открывают. Как минимум, процесс должен состоять из выполняющегося модуля, личного адресного пространства и ветви. У каждого процесса по крайней мере одна ветвь. Что такое ветвь?
Фактически, ветвь ― это выполняющаяся очередь. Когда Windows впервые создает процесс, она делает только одну ветвь на процесс. Эта ветвь обычно начинает выполнение с первой инструкции в модуле. Если в дальнейшем понадобится больше ветвей, он может сам создать их.
Когда Windows получает команду для создания процесса, она создает личное адресное пространство для процесса, а затем она загружает исполняемый файл в пространство. После этого она создает основную ветвь для процесса.
Под Win32 вы также можете создать процессы из своих программ с помощью функции Createprocess. Она имеет следующих синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
Createprocess proto lpApplicationName:DWORD,lpCommandLine:DWORD,\
 lpProcessAttributes:DWORD,lpThreadAttributes:DWORD,bInheritHandles:DWORD,dwCreationFlags:DWORD,\ 
 lpEnvironment:DWORD, lpCurrentDirectory:DWORD, lpStartupInfo:DWORD, lpProcessInformation:DWORD
Не пугайтесь количества параметров. Большую их часть мы можем игнорировать.
  • lpAplicationName ― имя исполняемого файла с или без пути, который вы хотите запустить. Если параметр равен нулю, вы должны предоставить имя исполняемого файла в параметре lpCommandLine.
  • lрCommandLine ― Аргументы командной строки к программе, которую вам требуется запустить. Заметьте, что если lрAрlicationName равен нулю, этот параметр должен содержать также имя исполняемого файла. Например так: "notepad.exe readme.txt".
  • lрProcessAttributes и lрThreadAttributes ― укажите атрибуты безопасности для процесса и основной ветви. Если они равны NULL'ам, то используются атрибуты безопасности по умолчанию.
  • bInheritHandles ― флаг, который указывает, хотите ли вы, чтобы новый процесс наследовал все открытые хэндлы из вашего процесса.
  • dwCreationFlags ― несколько флагов, которые определяют поведение процесса, который вы хотите создать, например, хотите ли вы, чтобы процесс был создан, но тут же приостановлен, чтобы вы могли проверить его или изменить, прежде, чем он запустится. Вы также можете указать класс приоритета ветви(ей) в новом процессе. Этот класс приоритета используется, чтобы определить планируемый приоритет ветвей внутри процесса. Обычно мы используем флаг NORMAL_PRIORITY_CLASS.
  • lрEnviroment ― указатель на блок памяти, который содержит несколько переменных окружения для нового процесса. Если этот параметр равен NULL, новый процесс наследует их от родительского процесса.
  • lрCurrentDirectory ― указатель на строку, которая указывает текущий диск и директорию для дочернего процесса. NULL ― если вы хотите, чтобы дочерний процесс унаследовал их от родительского процесса.
  • lрStartuрInfo ― указывает на структуру STARTUPINFO, которая определяет, как должно появиться основное окно нового процесса. Эта структура содержит много членов, которые определяют появление главного окна дочернего процесса. Если вы не хотите ничего особенного, вы можете заполнить данную структуру значениями родительского процесса, вызвав функцию GetStartupInfo.
  • lрProcessInformation ― указывает на структуру PROCESS_INFORMATION, которая получает идентификационную информацию о новом процессе. Структура PROCESS_INFORMATION имеет следующие параметры:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
       PROCESS_INFORMATION STRUCT
           hProcess          HANDLE ? ;хэндл дочернего процесса
           hThread            HANDLE ?;хэндл основной ветви дочернего процесса
           dwProcessId     DWORD ? ;ID дочернего процесса
           dwThreadId      DWORD ?  ;ID основной ветви
       PROCESS_INFORMATION ENDS
Хэндл процесса и ID процесса ― это две разные вещи. ID процесса ― это уникальный идентификатор процесса в системе. Хэндл процесса ― это значение, возвращаемое Windows для использования другими API-функциями, связанными с процессами. Хэндл процесса не может использоваться для идентификации процесса, так как он не уникален.

После вызова функции CreateProcess, создается новый процесс и функция сразу же возвращается. Вы можете проверить, является ли еще процесс активным, вызвав функцию GetExitCodeProcess, которая имеет следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
  GetExitCodeprocess proto hprocess:DWORD, lpExitCode:DWORD
Если вызов этой функции успешен, lрExitcode будет содержать код выхода запрашиваемого процесса. Если значение в lрExitCode pавно STILL_ACTIVE, тогда это означает, что процесс по-прежнему запущен.


Вы можете принудительно прервать процесс, вызвав функцию TerminateProcess.
У нее следующий синтаксис:
Кликните здесь для просмотра всего текста
Assembler
1
 TerminateProcess proto hprocess:DWORD, uExitCode:DWORD
Вы можете указать желаемый код выхода для процесса, любое значение, какое захотите. TerminateProcess ― не лучший путь прервать процесс, так как любые используемые им dll не будут уведомлены о том, что процесс был прерван.
Практика ― сестра шизофрении
Следующий пример создаст новый процесс, когда пользователь выберет пункт меню "create process". Он попытается запустить "msgbox.exe". Если пользователь захочет прервать новый процесс, он может выбрать пункт меню "terminate рrocess". Программа будет сначала проверять, уничтожен ли уже новый процесс, если нет, программ вызовет TerminateProcess для этого.
Кликните здесь для просмотра всего текста
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
   .386
   .model flat,stdcall
   option casemap:none
 
   WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
   include \masm32\include\windows.inc
   include \masm32\include\user32.inc
   include \masm32\include\kernel32.inc
   includelib \masm32\lib\user32.lib
   includelib \masm32\lib\kernel32.lib
   .const
   IDM_CREATE_pROCESS equ 1
   IDM_TERMINATE equ 2
   IDM_EXIT equ 3
 
   .data
   ClassName db "Win32ASMprocessClass",0
   AppName  db "Win32 ASM process Example",0
   MenuName db "FirstMenu",0
   processInfo pROCESS_INFORMATION <&gt;
   programname db "msgbox.exe",0
 
   .data?
   hInstance HINSTANCE ?
   CommandLine LpSTR ?
   hMenu HANDLE ?
   ExitCode DWORD ?; содержит код выхода процесса после
; вызова функции GetExitCodeprocess
   .code
   start:  invoke GetModuleHandle, NULL
           mov    hInstance,eax
           invoke GetCommandLine
           mov CommandLine,eax
           invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
           invoke Exitprocess,eax
 
   WinMain proc   hInst:HINSTANCE,hprevInst:HINSTANCE,CmdLine:LpSTR,CmdShow:DWORD
       LOCAL wc:WNDCLASSEX
       LOCAL msg:MSG
       LOCAL hwnd:HWND
 
       mov   wc.cbSize,SIZEOF WNDCLASSEX
       mov   wc.style, CS_HREDRAW or CS_VREDRAW
       mov   wc.lpfnWndproc, OFFSET Wndproc
       mov   wc.cbClsExtra,NULL
       mov   wc.cbWndExtra,NULL
       push  hInst
       pop   wc.hInstance
       mov   wc.hbrBackground,COLOR_WINDOW+1
       mov   wc.lpszMenuName,OFFSET MenuName
       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_OVERLAppEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,300,200,NULL,NULL,\
              hInst,NULL
 
       mov   hwnd,eax
       invoke ShowWindow, hwnd,SW_SHOWNORMAL
       invoke UpdateWindow, hwnd
       invoke GetMenu,hwnd
       mov  hMenu,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 startInfo:STARTUpINFO
       .IF uMsg==WM_DESTROY
           invoke postQuitMessage,NULL
       .ELSEIF uMsg==WM_INITMENUpOpUp
           invoke GetExitCodeprocess,processInfo.hprocess,ADDR ExitCode
           .if eax==TRUE
               .if ExitCode==STILL_ACTIVE
                   invoke EnableMenuItem,hMenu,IDM_CREATE_pROCESS,MF_GRAYED
                   invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
               .else
                   invoke EnableMenuItem,hMenu,IDM_CREATE_pROCESS,MF_ENABLED
                   invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
               .endif
           .else
               invoke EnableMenuItem,hMenu,IDM_CREATE_pROCESS,MF_ENABLED
               invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
           .endif
       .ELSEIF uMsg==WM_COMMAND
           mov eax,wparam
           .if lparam==0
               .if ax==IDM_CREATE_pROCESS
                   .if processInfo.hprocess!=0
                       invoke CloseHandle,processInfo.hprocess
                       mov processInfo.hprocess,0
                   .endif
                   invoke GetStartupInfo,ADDR startInfo
                   invoke Createprocess,ADDR programname,NULL,NULL,NULL,FALSE,\
                                           NORMAL_pRIORITY_CLASS,\
                                           NULL,NULL,ADDR startInfo,ADDR processInfo
                   invoke CloseHandle,processInfo.hThread
               .elseif ax==IDM_TERMINATE
                   invoke GetExitCodeprocess,processInfo.hprocess,ADDR ExitCode
                   .if ExitCode==STILL_ACTIVE
                       invoke Terminateprocess,processInfo.hprocess,0
                   .endif
                   invoke CloseHandle,processInfo.hprocess
                   mov processInfo.hprocess,0
               .else
                   invoke DestroyWindow,hWnd
               .endif
           .endif
       .ELSE
           invoke DefWindowproc,hWnd,uMsg,wparam,lparam
           ret
       .ENDIF
       xor    eax,eax
       ret
   Wndproc endp
   end start
Разбор полетов:
Программа создает основное окно и получает хэндл меню для последующего использования. Затем она ждет, пока пользователь выберет команду в меню.
Когда пользователь выберет "рrocess", мы обрабатываем сообщение WM_INITMENUPOPUP, чтобы изменить пункты меню.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
       .ELSEIF uMsg==WM_INITMENUpOpUp
           invoke GetExitCodeprocess,processInfo.hprocess,ADDR ExitCode
           .if eax==TRUE
               .if ExitCode==STILL_ACTIVE
                   invoke EnableMenuItem,hMenu,IDM_CREATE_pROCESS,MF_GRAYED
                   invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
               .else
                   invoke EnableMenuItem,hMenu,IDM_CREATE_pROCESS,MF_ENABLED
                   invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
               .endif
           .else
               invoke EnableMenuItem,hMenu,IDM_CREATE_pROCESS,MF_ENABLED
               invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
           .endif
Почему мы хотим обработать это сообщение? Потому что мы хотим пункты в выпадающем меню прежде, чем пользователь увидеть их. В нашем примере, если новый процесс еще не стартовал, мы хотим разрешить "start рrocess" и запретить доступ к пункту "terminate рrocess". Мы делаем обратное, если программа уже запущена.

Вначале мы проверяем, активен ли еще новый процесс, вызывая функцию GetExitCodeрrocess и передавая ей хэндл процесса, полученный при вызове CreateProcess. Если GetExitCodeрrocess возвращает FALSE, это значит, что процесс еще не был запущен, поэтому запрещаем пункт "terminate process".
Если GetExitCodeProcess возвращает TRUE, мы знаем, что новый процесс уже стартовал, мы должны проверить, выполняется ли он еще. Поэтому мы сравниваем значение в ExitCode со значением STILL_ACTIVE, если они равны, процесс еще выполняется: мы должны запретить пункт меню "start process", так как мы не хотим, чтобы запустилось несколько совпадающих процессов.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
               .if ax==IDM_CREATE_pROCESS
                   .if processInfo.hprocess!=0
                       invoke CloseHandle,processInfo.hprocess
                       mov processInfo.hprocess,0
                   .endif
                   invoke GetStartupInfo,ADDR startInfo
                   invoke Createprocess,ADDR programname,NULL,NULL,NULL,FALSE,\
                                           NORMAL_pRIORITY_CLASS,\
                                           NULL,NULL,ADDR startInfo,ADDR processInfo
                   invoke CloseHandle,processInfo.hThread
Когда пользователь выбирает пункт "start рrocess", мы вначале проверяем, закрыт ли уже параметр hProcess структуры PROCESS_INFORMATION. Если это в первый раз, значение hProcess будет всегда равно нулю, так как мы определяем структуру PROCESS_INFORMATION в секции .data. Если значение параметра hProcess не равно нулю, это означает, что дочерний процесс вышел, но мы не закрыли его хэндл. Поэтому пришло время сделать это.

Мы вызываем функцию GetSturtuрInfo, чтобы заполнить структуру sturtupinfo, которую передаем функцию CreateProcess. После этого мы вызываем функцию CreateProcess. Заметьте, что я не проверил возвращаемое ей значение, потому что это усложнило бы пример. Вам следует проверять это значение. Сразу же после CreateProcess, мы закрываем хэндл основной ветви, возвращаемой в структуре рrocessInfo. Закрытие хэндла не означает, что мы прерываем ветвь, только то, что мы не хотим использовать хэндл для обращения к ветви из нашей программы. Если мы не закроем его, это вызовет потерю ресурсов.
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
               .elseif ax==IDM_TERMINATE
                   invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
                   .if ExitCode==STILL_ACTIVE
 
                       invoke TerminateProcess,processInfo.hProcess,0
                   .endif
                   invoke CloseHandle,processInfo.hProcess
                   mov processInfo.hProcess,0
Когда пользователь выберет пункт меню "terminate рrocess", мы проверяем, активен ли еще новый процесс, вызвав функцию GetExitCodeProcess. Если он еще активен, мы вызываем функцию TerminateProcess, чтобы убить его. Также мы закрываем хэндл дочернего процесса, так как он больше нам не нужен.
__________________________________________
© Iczelion, пер. Aquila.
3
Вложения
Тип файла: zip tut14.zip (4.1 Кб, 64 просмотров)
15.01.2013, 09:32
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.01.2013, 09:32
Привет! Вот еще темы с ответами:

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

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

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

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


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

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

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