; int __stdcall GenericBox(DLGTEMPLATE* dlg, void* DlgProc); ; int __stdcall DlgProc(DLGTEMPLATE* dlg, int msg, int param1, int param2); virtual at 0 dlgtemplate: ; Флаги: ; бит 0: использовать стандартные цвета диалога ; бит 1: использовать стандартные цвета предупреждения/ошибки ; (если любой из этих битов установлен, поля main_color,border_color,header_color ; игнорируются) ; бит 2: не рисовать тень .flags dd ? .x dd ? .y dd ? .width dd ? .height dd ? .border_size_x dd ? .border_size_y dd ? .title dd ? .main_color db ? .border_color db ? .header_color db ? db ? ; align .dataptr dd ? ; used internally, ignored on input .size = $ end virtual align 16 GenericBox: push [cursor_x] push [cursor_y] push dword [esp+8+8] push dword [esp+8+8] call ShowGenericBox test eax, eax jz @f pop [cursor_y] pop [cursor_x] ret @@: pushad ; message loop .event: ; call get_event push SF_WAIT_EVENT pop eax int 40h dec eax jz .redraw dec eax jz .key sub eax,4 jz .mouse jmp exit .redraw: call draw_window jmp .event .key: mov al, SF_GET_KEY int 40h shr eax, 8 cmp al, 0xE0 jnz @f mov [bWasE0], 1 jmp .event @@: xchg ah, [bWasE0] cmp al, 0x1D jz .ctrl_down cmp al, 0x9D jz .ctrl_up cmp al, 0x2A jz .lshift_down cmp al, 0xAA jz .lshift_up cmp al, 0x36 jz .rshift_down cmp al, 0xB6 jz .rshift_up cmp al, 0x38 jz .alt_down cmp al, 0xB8 jz .alt_up mov ebx, [esp+24h+8] mov ecx, [esp+28h+8] push 0 push eax push 2 push ebx call ecx ;DlgProc test eax, eax jz .event mov [esp+28], eax jmp .exit .ctrl_down: test ah, ah jnz .rctrl_down or [ctrlstate], 4 jmp .event .rctrl_down: or [ctrlstate], 8 jmp .event .ctrl_up: test ah, ah jnz .rctrl_up and [ctrlstate], not 4 jmp .event .rctrl_up: and [ctrlstate], not 8 jmp .event .lshift_down: test ah, ah jnz @f or [ctrlstate], 1 @@: jmp .event .lshift_up: test ah, ah jnz @b and [ctrlstate], not 1 jmp @b .rshift_down: or [ctrlstate], 2 jmp .event .rshift_up: and [ctrlstate], not 2 jmp .event .alt_down: test ah, ah jnz .ralt_down or [ctrlstate], 0x10 jmp .event .ralt_down: or [ctrlstate], 0x20 jmp .event .alt_up: test ah, ah jnz .ralt_up and [ctrlstate], not 0x10 jmp .event .ralt_up: and [ctrlstate], not 0x20 jmp .event align 4 .mouse: mov eax,SF_MOUSE_GET mov ebx,SSF_BUTTON_EXT int 0x40 bt eax,8 ;left but. down jnc .event mov eax,SF_MOUSE_GET mov ebx,SSF_WINDOW_POSITION int 0x40 cmp ax, word[skinh] jl .event sub ax, word[skinh] xor dx,dx mov bx, font_height div bx movzx edx,ax shr eax,16 sub eax, 5 ;window border push edx xor dx,dx mov bx, font_width div bx movzx eax,ax pop edx mov ebx, [esp+24h+8] ;DLGTEMPLATE* dlg cmp dword[ebx+dlgtemplate.size], 0 jne .event ;если диалоговое окно не стандартное (список значений) cmp edx, [ebx+dlgtemplate.y] jl .event cmp eax, [ebx+dlgtemplate.x] jl .event sub edx, [ebx+dlgtemplate.y] sub eax, [ebx+dlgtemplate.x] cmp edx, [ebx+dlgtemplate.height] jge .event cmp eax, [ebx+dlgtemplate.width] jge .event add ebx, dlgtemplate.size+12 mov ecx, [ebx-4] or ecx, ecx jz .event push ebx ecx .m_loop: cmp [ebx+dlgitemtemplate.type], 2 ;button je .m_comp cmp [ebx+dlgitemtemplate.type], 3 ;edit je .m_comp ;cmp [ebx+dlgitemtemplate.type], 5 ;check ;je .m_comp jmp .m_next align 4 .m_comp: cmp [ebx+dlgitemtemplate.x1], eax jg .m_next cmp [ebx+dlgitemtemplate.y1], edx jg .m_next cmp [ebx+dlgitemtemplate.x2], eax jl .m_next cmp [ebx+dlgitemtemplate.y2], edx jl .m_next cmp [ebx+dlgitemtemplate.type], 2 ;button jne @f mov [esp+28+8], ebx ;save to eax pop ecx ebx jmp .exit @@: mov eax, [ebx+dlgitemtemplate.flags] and eax, 4 jnz .m_old_focus mov eax, ebx jmp .m_new_focus align 4 .m_next: add ebx, sizeof.DlgBtn loop .m_loop .m_old_focus: pop ecx ebx jmp .event align 4 .m_new_focus: pop ecx ebx call DlgClearFocus or dword[eax+dlgitemtemplate.flags], 4 sub ebx, dlgtemplate.size+12 push ebp mov ebp, ebx call ManagerDlgProc.dodraw pop ebp call draw_image jmp .event align 4 .exit: popad push eax push 0 push dword [esp+12+8] call HideGenericBox pop eax pop [cursor_y] pop [cursor_x] pushad call draw_image popad ret 8 ;input: ; ebx - pointer to first item ; ecx - count items align 4 DlgClearFocus: push ebx ecx @@: and byte [ebx+dlgitemtemplate.flags], not 4 add ebx, sizeof.DlgBtn loop @b pop ecx ebx ret ; int __stdcall ShowGenericBox(DLGTEMPLATE* dlg, void* DlgProc); align 16 ShowGenericBox: pushad mov ebx, [esp+20h+4] ; center window if required push [ebx+dlgtemplate.x] push [ebx+dlgtemplate.y] cmp [ebx+dlgtemplate.x], -1 jnz @f mov eax, [cur_width] sub eax, [ebx+dlgtemplate.width] shr eax, 1 mov [ebx+dlgtemplate.x], eax @@: cmp [ebx+dlgtemplate.y], -1 jnz @f mov eax, [cur_height] sub eax, [ebx+dlgtemplate.height] shr eax, 1 mov [ebx+dlgtemplate.y], eax @@: ; some checks mov eax, [ebx+dlgtemplate.x] cmp eax, 1 jl .sizeerr add eax, [ebx+dlgtemplate.width] cmp eax, [cur_width] jge .sizeerr mov eax, [ebx+dlgtemplate.y] cmp eax, 1 jl .sizeerr add eax, [ebx+dlgtemplate.height] cmp eax, [cur_height] jge .sizeerr cmp [ebx+dlgtemplate.border_size_x], 1 jl .sizeerr cmp [ebx+dlgtemplate.border_size_y], 1 jge .sizeok .sizeerr: pop [ebx+dlgtemplate.y] pop [ebx+dlgtemplate.x] popad or eax, -1 ret 8 .sizeok: ; set color if required test byte [ebx+dlgtemplate.flags], 1 jz @f mov edi, dialog_colors jmp .setcolor @@: test byte [ebx+dlgtemplate.flags], 2 jz @f mov edi, warning_colors .setcolor: mov al, [edi + dialog_main_color-dialog_colors] mov [ebx+dlgtemplate.main_color], al mov al, [edi + dialog_border_color-dialog_colors] mov [ebx+dlgtemplate.border_color], al mov al, [edi + dialog_header_color-dialog_colors] mov [ebx+dlgtemplate.header_color], al @@: ; allocate memory for data under dialog ; for 'No memory' dialog use static data area mov eax, nomem_dlgsavearea cmp ebx, nomem_dlgdata jz .allocated mov eax, [ebx+dlgtemplate.width] add eax, [ebx+dlgtemplate.border_size_x] add eax, [ebx+dlgtemplate.border_size_x] inc eax inc eax mov edx, [ebx+dlgtemplate.height] add edx, [ebx+dlgtemplate.border_size_y] add edx, [ebx+dlgtemplate.border_size_y] inc edx mul edx lea ecx, [eax*2+8] call xpgalloc test eax, eax jnz @f pop [ebx+dlgtemplate.y] pop [ebx+dlgtemplate.x] popad or eax, -1 ret 8 @@: .allocated: mov [ebx+dlgtemplate.dataptr], eax pop dword [eax+4] pop dword [eax] lea ebp, [eax+8] ; save data mov eax, [ebx+dlgtemplate.y] add eax, [ebx+dlgtemplate.height] add eax, [ebx+dlgtemplate.border_size_y] inc eax push eax mov eax, [ebx+dlgtemplate.x] add eax, [ebx+dlgtemplate.width] add eax, [ebx+dlgtemplate.border_size_x] inc eax inc eax push eax mov eax, [ebx+dlgtemplate.y] sub eax, [ebx+dlgtemplate.border_size_y] push eax mov eax, [ebx+dlgtemplate.x] sub eax, [ebx+dlgtemplate.border_size_x] push eax call save_console_data ; draw shadow test byte [ebx+dlgtemplate.flags], 4 jnz .noshadow call draw_dialog_shadow .noshadow: popad push dword [esp+8] push dword [esp+8] call DrawGenericBox xor eax, eax ret 8 draw_dialog_shadow: mov eax, [ebx+dlgtemplate.x] sub eax, [ebx+dlgtemplate.border_size_x] ja @f xor eax, eax @@: inc eax inc eax mov edx, [ebx+dlgtemplate.y] sub edx, [ebx+dlgtemplate.border_size_y] ja @f xor edx, edx @@: inc edx call get_console_ptr mov ecx, [ebx+dlgtemplate.y] add ecx, [ebx+dlgtemplate.height] add ecx, [ebx+dlgtemplate.border_size_y] inc ecx cmp ecx, [cur_height] jb @f mov ecx, [cur_height] @@: sub ecx, edx mov edx, ecx mov ecx, [ebx+dlgtemplate.x] add ecx, [ebx+dlgtemplate.width] add ecx, [ebx+dlgtemplate.border_size_x] inc ecx inc ecx cmp ecx, [cur_width] jb @f mov ecx, [cur_width] @@: sub ecx, eax mov eax, ecx .shadow_loop: mov ecx, eax push edi .sl1: inc edi test byte [edi], 0x0F jnz @f or byte [edi], 8 @@: and byte [edi], 0x0F inc edi loop .sl1 pop edi add edi, [cur_width] add edi, [cur_width] dec edx jnz .shadow_loop ret ; void __stdcall DrawGenericBox(DLGDATA* dlg, void* DlgProc) align 16 DrawGenericBox: pushad mov ebx, [esp+24h] ; draw area background mov eax, [ebx+dlgtemplate.x] sub eax, [ebx+dlgtemplate.border_size_x] ja @f xor eax, eax @@: mov edx, [ebx+dlgtemplate.y] sub edx, [ebx+dlgtemplate.border_size_y] ja @f xor edx, edx @@: call get_console_ptr mov ecx, [ebx+dlgtemplate.x] add ecx, [ebx+dlgtemplate.width] add ecx, [ebx+dlgtemplate.border_size_x] cmp ecx, [cur_width] jb @f mov ecx, [cur_width] @@: sub ecx, eax mov esi, ecx mov ecx, [ebx+dlgtemplate.y] add ecx, [ebx+dlgtemplate.height] add ecx, [ebx+dlgtemplate.border_size_y] cmp ecx, [cur_height] jb @f mov ecx, [cur_height] @@: sub ecx, edx mov edx, ecx mov al, ' ' mov ah, [ebx+dlgtemplate.border_color] .1: mov ecx, esi push edi rep stosw pop edi add edi, [cur_width] add edi, [cur_width] dec edx jnz .1 ; draw border mov eax, [ebx+dlgtemplate.x] dec eax mov edx, [ebx+dlgtemplate.y] dec edx call get_console_ptr mov edx, [ebx+dlgtemplate.height] inc edx inc edx mov ah, [ebx+dlgtemplate.border_color] push ebx mov ebx, [ebx+dlgtemplate.width] inc ebx inc ebx call draw_border pop ebx ; draw header mov esi, [ebx+dlgtemplate.title] test esi, esi jz .noheader cmp byte [esi], 0 jz .noheader push esi @@: lodsb test al, al jnz @b mov eax, esi pop esi sub eax, esi inc eax ; eax = длина заголовка + 2 mov ecx, [ebx+dlgtemplate.width] cmp eax, ecx jbe .fullhea sub ecx, 5 jb .noheader xor edx, edx jmp .drawhea .fullhea: mov edx, ecx sub edx, eax shr edx, 1 .drawhea: mov eax, [ebx+dlgtemplate.x] add eax, edx mov edx, [ebx+dlgtemplate.y] dec edx call get_console_ptr mov ah, [ebx+dlgtemplate.header_color] mov al, ' ' stosw .2: dec ecx jz .3 lodsb test al, al jz .4 stosw jmp .2 .3: mov al, '.' stosw stosw stosw .4: mov al, ' ' stosw .noheader: ; draw window background mov eax, [ebx+dlgtemplate.x] mov edx, [ebx+dlgtemplate.y] call get_console_ptr mov ah, [ebx+dlgtemplate.main_color] mov al, ' ' mov edx, [ebx+dlgtemplate.height] @@: mov ecx, [ebx+dlgtemplate.width] push edi rep stosw pop edi add edi, [cur_width] add edi, [cur_width] dec edx jnz @b ; send redraw message mov eax, [esp+28h] push 0 push 0 push 1 push ebx call eax call draw_image popad ret 8 ; void __stdcall HideGenericBox(DLGTEMPLATE* dlg, int bRedrawWindow); align 16 HideGenericBox: ; void __stdcall HideDialogBox(DLGDATA* dlg, int bRedrawWindow); HideDialogBox: pushad mov ebx, [esp+24h] mov ebp, [ebx+dlgtemplate.dataptr] add ebp, 8 ; restore data mov eax, [ebx+dlgtemplate.y] add eax, [ebx+dlgtemplate.height] add eax, [ebx+dlgtemplate.border_size_y] inc eax push eax mov eax, [ebx+dlgtemplate.x] add eax, [ebx+dlgtemplate.width] add eax, [ebx+dlgtemplate.border_size_x] inc eax inc eax push eax mov eax, [ebx+dlgtemplate.y] sub eax, [ebx+dlgtemplate.border_size_y] push eax mov eax, [ebx+dlgtemplate.x] sub eax, [ebx+dlgtemplate.border_size_x] push eax call restore_console_data call draw_keybar lea ecx, [ebp-8] push dword [ecx] push dword [ecx+4] pop [ebx+dlgtemplate.y] pop [ebx+dlgtemplate.x] cmp ebx, nomem_dlgdata jz @f call pgfree @@: or [cursor_x], -1 or [cursor_y], -1 cmp dword [esp+28h], 0 jz @f call draw_image @@: popad ret 8 save_console_data: cmp dword [esp+4], 0 jge @f and dword [esp+4], 0 @@: cmp dword [esp+8], 0 jge @f and dword [esp+8], 0 @@: mov eax, [esp+12] cmp eax, [cur_width] jbe @f mov eax, [cur_width] @@: sub eax, [esp+4] ja @f ret 16 @@: mov [esp+12], eax mov eax, [esp+16] cmp eax, [cur_height] jbe @f mov eax, [cur_height] @@: sub eax, [esp+8] ja @f ret 16 @@: mov [esp+16], eax mov eax, [esp+4] mov edx, [esp+8] call get_console_ptr mov esi, edi mov edi, ebp .l: mov ecx, [esp+12] push esi shr ecx, 1 rep movsd adc ecx, ecx rep movsw pop esi add esi, [cur_width] add esi, [cur_width] dec dword [esp+16] jnz .l ret 16 restore_console_data: cmp dword [esp+4], 0 jge @f and dword [esp+4], 0 @@: cmp dword [esp+8], 0 jge @f and dword [esp+8], 0 @@: mov eax, [esp+12] cmp eax, [cur_width] jbe @f mov eax, [cur_width] @@: sub eax, [esp+4] ja @f ret 16 @@: mov [esp+12], eax mov eax, [esp+16] cmp eax, [cur_height] jbe @f mov eax, [cur_height] @@: sub eax, [esp+8] ja @f ret 16 @@: mov [esp+16], eax mov eax, [esp+4] mov edx, [esp+8] call get_console_ptr mov esi, ebp .l: mov ecx, [esp+12] push edi shr ecx, 1 rep movsd adc ecx, ecx rep movsw pop edi add edi, [cur_width] add edi, [cur_width] dec dword [esp+16] jnz .l ret 16 ; int __stdcall menu(void* variants, const char* title, unsigned flags); ; variants указывает на текущий элемент в двусвязном линейном списке align 16 menu: pop eax push [cur_height] push [cur_width] push 0 push 0 push eax ; int __stdcall menu_centered_in(unsigned left, unsigned top, unsigned width, unsigned height, ; void* variants, const char* title, unsigned flags); menu_centered_in: pushad mov ecx, 60 ; 40 bytes for dlgtemplate + additional: ; +40: dd cur_variant - [???] ; +44: dd num_variants - сколько элементов влазит в окно ; +48: dd begin_variant - [dd ..,..,???] ; +52: dd end_variant - [dd ..,..,???] ; +56: dd cur_variant_idx - ??? call xpgalloc test eax, eax jnz @f .ret_bad: popad or eax, -1 ret 28 @@: mov ebx, eax mov eax, 1 test byte [esp+20h+28], 1 ;unsigned flags jz @f mov al, 3 @@: mov [ebx+dlgtemplate.border_size_x], eax inc eax shr eax, 1 mov [ebx+dlgtemplate.border_size_y], eax ; Находим ширину и высоту окна xor eax, eax xor ecx, ecx mov esi, [esp+20h+20] ;void* variants mov [ebx+40], esi mov dword [ebx+56], eax @@: cmp dword [esi+4], eax jz .find_width mov esi, [esi+4] inc dword [ebx+56] jmp @b .find_width: mov [ebx+48], esi add esi, 8 push esi xor edx, edx .fw1: cmp byte [esi], '&' jnz @f mov dl, 1 @@: inc esi cmp byte [esi-1], 0 jnz .fw1 sub esi, [esp] sub esi, edx dec esi cmp eax, esi ja @f mov eax, esi @@: inc ecx pop esi mov esi, [esi-8] test esi, esi jnz .find_width add eax, 3 add eax, [ebx+dlgtemplate.border_size_x] add eax, [ebx+dlgtemplate.border_size_x] cmp eax, [cur_width] jb @f mov eax, [cur_width] @@: sub eax, [ebx+dlgtemplate.border_size_x] sub eax, [ebx+dlgtemplate.border_size_x] mov [ebx+dlgtemplate.width], eax mov [ebx+dlgtemplate.height], ecx mov [ebx+44], ecx sub eax, [esp+20h+12] neg eax sar eax, 1 add eax, [esp+20h+4] cmp eax, [ebx+dlgtemplate.border_size_x] jge @f mov eax, [ebx+dlgtemplate.border_size_x] @@: push eax add eax, [ebx+dlgtemplate.width] add eax, [ebx+dlgtemplate.border_size_x] cmp eax, [cur_width] jbe @f pop eax mov eax, [cur_width] sub eax, [ebx+dlgtemplate.width] sub eax, [ebx+dlgtemplate.border_size_x] push eax @@: pop [ebx+dlgtemplate.x] sub ecx, [esp+20h+16] neg ecx sar ecx, 1 add ecx, [esp+20h+8] cmp ecx, [ebx+dlgtemplate.border_size_y] jge @f mov ecx, [ebx+dlgtemplate.border_size_y] @@: push ecx add ecx, [ebx+dlgtemplate.height] add ecx, [ebx+dlgtemplate.border_size_y] cmp ecx, [cur_height] jbe @f pop ecx mov ecx, [cur_height] sub ecx, [ebx+dlgtemplate.height] sub ecx, [ebx+dlgtemplate.border_size_y] push ecx @@: pop [ebx+dlgtemplate.y] mov eax, [cur_height] sub eax, 6 cmp [ebx+dlgtemplate.height], eax jbe .small_height mov [ebx+dlgtemplate.height], eax mov [ebx+dlgtemplate.y], 3 .small_height: mov ecx, [ebx+dlgtemplate.height] mov eax, [ebx+40] mov [ebx+48], eax dec ecx jz .skip push ecx @@: cmp dword [eax+4], 0 jz @f mov eax, [eax+4] loop @b @@: mov [ebx+48], eax pop ecx .loop: mov eax, [eax] loop .loop .skip: mov [ebx+52], eax mov eax, [esp+20h+24] mov [ebx+dlgtemplate.title], eax mov al, [menu_normal_color] mov [ebx+dlgtemplate.main_color], al mov al, [menu_border_color] mov [ebx+dlgtemplate.border_color], al mov al, [menu_header_color] mov [ebx+dlgtemplate.header_color], al push MenuDlgProc push ebx call GenericBox mov [esp+28], eax mov ecx, ebx call pgfree popad ret 28 align 16 MenuDlgProc: mov eax, [esp+8] cmp al, 1 jz .draw cmp al, 2 jz .key ret 16 .draw: call .dodraw ret 16 .prev: mov eax, [ebx+40] cmp dword [eax+4], 0 jz .end call .line_prev .posret: mov [ebx+40], eax .redraw: call .dodraw call draw_image xor eax, eax ret 16 .next: mov eax, [ebx+40] cmp dword [eax], 0 jz .home call .line_next jmp .posret .pgdn: mov eax, [ebx+40] mov ecx, [ebx+dlgtemplate.height] .pgdnl: cmp dword [eax], 0 jz .posret call .line_next loop .pgdnl jmp .posret .key: mov al, [esp+12] cmp al, 0x48 jz .prev cmp al, 0x4B jz .prev cmp al, 0x4D jz .next cmp al, 0x50 jz .next cmp al, 0x1C jz .enter cmp al, 1 jz .esc cmp al, 0x47 jz .home cmp al, 0x4F jz .end cmp al, 0x51 jz .pgdn cmp al, 0x49 jz .pgup cmp al, 0x52 jz .ins cmp al, 0x53 jz .del mov edx, [ebx+40] @@: cmp dword [edx+4], 0 jz @f mov edx, [edx+4] jmp @b @@: .l: lea esi, [edx+7] @@: inc esi cmp byte [esi], 0 jz .n cmp byte [esi], '&' jnz @b movzx ecx, byte [esi+1] cmp [ascii2scan+ecx], al jnz .n mov eax, edx ret 16 .n: mov edx, [edx] test edx, edx jnz .l .ret: xor eax, eax ret 16 .pgup: mov eax, [ebx+40] mov ecx, [ebx+dlgtemplate.height] .pgupl: cmp dword [eax+4], 0 jz .posret call .line_prev loop .pgupl jmp .posret .home: mov eax, [ebx+40] @@: cmp dword [eax+4], 0 jz @f mov eax, [eax+4] jmp @b @@: mov [ebx+48], eax push eax mov ecx, [ebx+dlgtemplate.height] dec ecx jz .h1 .h2: mov eax, [eax] loop .h2 .h1: mov [ebx+52], eax pop eax and dword [ebx+56], 0 jmp .posret .end: mov eax, [ebx+40] @@: cmp dword [eax], 0 jz @f mov eax, [eax] jmp @b @@: mov [ebx+52], eax push eax mov ecx, [ebx+dlgtemplate.height] dec ecx jz .e1 .e2: mov eax, [eax+4] loop .e2 .e1: mov [ebx+48], eax mov eax, [ebx+44] dec eax mov [ebx+56], eax pop eax jmp .posret .esc: or eax, -1 ret 16 .enter: mov eax, [ebx+40] ret 16 .ins: push 5 pop edx jmp @f .del: push 4 pop edx @@: mov eax, [ebx+40] cmp byte [eax+8], '/' jnz @f cmp word [eax+9], 'cd' jnz @f movzx ecx, byte [eax+11] sub ecx, '0' push SF_CD pop eax mov ebx, edx int 40h @@: xor eax, eax ret 16 .line_prev: cmp eax, [ebx+48] jnz @f mov edx, [ebx+48] mov edx, [edx+4] mov [ebx+48], edx mov edx, [ebx+52] mov edx, [edx+4] mov [ebx+52], edx @@: mov eax, [eax+4] dec dword [ebx+56] ret .line_next: cmp eax, [ebx+52] jnz @f mov edx, [ebx+48] mov edx, [edx] mov [ebx+48], edx mov edx, [ebx+52] mov edx, [edx] mov [ebx+52], edx @@: mov eax, [eax] inc dword [ebx+56] ret .dodraw: mov eax, [ebx+dlgtemplate.x] mov edx, [ebx+dlgtemplate.y] call get_console_ptr mov esi, [ebx+48] .0: xor edx, edx mov ah, [menu_selected_color] cmp esi, [ebx+40] jz @f mov ah, [menu_normal_color] @@: push edi mov ecx, [ebx+dlgtemplate.width] mov al, ' ' stosw dec ecx stosw dec ecx dec ecx push esi add esi, 8 @@: lodsb test al, al jz @f cmp al, '&' jnz .noamp test dl, dl jnz .noamp mov dl, 1 lodsb push eax mov ah, [menu_selected_highlight_color] push ecx mov ecx, [esp+8] cmp ecx, [ebx+40] pop ecx jz .amp1 mov ah, [menu_highlight_color] .amp1: stosw pop eax jmp .amp2 .noamp: stosw .amp2: loop @b mov al, ' ' cmp byte [esi], 0 jnz .1 lodsb jmp .1 @@: mov al, ' ' .1: stosw mov al, ' ' rep stosw pop esi edi add edi, [cur_width] add edi, [cur_width] cmp esi, [ebx+52] jz @f mov esi, [esi] test esi, esi jnz .0 @@: ; Линейка прокрутки mov ecx, [ebx+dlgtemplate.height] cmp ecx, [ebx+44] jz .noscrollbar sub ecx, 2 jbe .noscrollbar mov eax, [ebx+56] mul ecx div dword [ebx+44] push eax mov eax, [ebx+dlgtemplate.x] add eax, [ebx+dlgtemplate.width] mov edx, [ebx+dlgtemplate.y] call get_console_ptr pop edx inc edx mov al, 0x1E mov ah, [menu_scrollbar_color] mov [edi], ax add edi, [cur_width] add edi, [cur_width] .2: mov al, 0xB2 dec edx jz @f mov al, 0xB0 @@: mov [edi], ax add edi, [cur_width] add edi, [cur_width] loop .2 mov al, 0x1F stosw .noscrollbar: ret get_ascii_char: ; query keyboard layout pushad mov al, [ctrlstate] and al, 3 xor ecx, ecx cmp al, 1 sbb ecx, -2 push SF_SYSTEM_GET pop eax push SSF_KEYBOARD_LAYOUT pop ebx mov edx, layout int 0x40 popad ; translate scancode to ASCII movzx eax, byte [layout+eax] ret struct DlgLbl type dd 1 x1 dd ? y1 dd ? x2 dd ? y2 dd ? text dd ? flags dd ? ends struct DlgBtn type dd 2 x1 dd ? y1 dd ? x2 dd ? y2 dd ? text dd ? flags dd ? ends struct DlgEdit type dd 3 x1 dd ? y1 dd ? x2 dd ? y2 dd ? text dd ? flags dd ? ends struct DlgLine type dd 4 x1 dd ? y1 dd ? x2 dd ? y2 dd ? dq 0 ends struct DlgCheck type dd 5 x1 dd ? y1 dd ? x2 dd ? y2 dd ? text dd ? flags dd ? ends struct DlgList type dd 6 x1 dd ? y1 dd ? x2 dd ? y2 dd ? text dd ? flags dd ? ends virtual at 0 dlgitemtemplate: ; Элементы: ; 1 = статический текст ; 2 = кнопка ; 3 = поле редактирования ; 4 = горизонтальный разделитель ; 5 = флажок ; 6 = список .type dd ? .x1 dd ? .y1 dd ? .x2 dd ? .y2 dd ? ; Данные: ; для текста: const char* data - ASCIIZ-строка ; для кнопки и флажка: const char* data - заголовок ; для редактора: struct {unsigned maxlength; unsigned pos; unsigned start; ; char data[maxlength+1];}* data; ; для списка: struct {listitem* curitemptr; unsigned numitems; ; listitem *head; unsigned curitem;}* data; ; head = указатель на первый отображаемый элемент, ; curitemptr = указатель на выделенный элемент, curitem = его индекс в списке (от 0) ; (где struct listitem {listitem* next; listitem* prev; char text[];};) .data dd ? .flags dd ? ; Флаги: ; 0 = выравнивание влево ; 1 = выравнивание по центру ; 2 = выравнивание вправо ; 4 = элемент имеет фокус ввода ; 8 = элемент может иметь фокус ввода ; 10h: для кнопки = кнопка по умолчанию (Enter на не-кнопке) ; для поля ввода = данные были модифицированы ; для флажка = флажок установлен ; 20h: для поля ввода = не отображать вводимые данные (показывать '*') .size = $ end virtual ; struct DLGDATA ; { ; DLGTEMPLATE dialog; /* window description */ ; void* DlgProc; /* dialog procedure */ ; /* int __stdcall DlgProc(DLGDATA* dlg, int msg, int param1, int param2); */ ; void* user_data; /* arbitrary user data */ ; unsigned num_items; /* number of items in the following array */ ; DLGITEMTEMPLATE items[]; /* array of dialog items */ ; } ; int __stdcall DialogBox(DLGDATA* dlg); align 16 DialogBox: push ManagerDlgProc push dword [esp+8] call GenericBox ret 4 ; int __stdcall ShowDialogBox(DLGDATA* dlg); ShowDialogBox: push ManagerDlgProc push dword [esp+8] call ShowGenericBox ret 4 ; void __stdcall DrawDialogBox(DLGDATA* dlg); DrawDialogBox: push ManagerDlgProc push dword [esp+8] call DrawGenericBox ret 4 align 16 ManagerDlgProc: mov ebp, ebx mov eax, [esp+8] dec eax jz .draw dec eax jz .key xor eax, eax ret 16 .draw: call .dodraw ret 16 .key: ; find item with focus add ebx, dlgtemplate.size+12 mov ecx, [ebx-4] jecxz .nobtns @@: test [ebx+dlgitemtemplate.flags], 4 jnz @f add ebx, dlgitemtemplate.size loop @b @@: .nobtns: mov al, [esp+12] cmp al, 1 jz .esc cmp al, 0x1C jz .enter cmp al, 0xF jz .tab cmp al, 0x48 jz .up cmp al, 0x50 jz .down jecxz .nobtns2 cmp [ebx+dlgitemtemplate.type], 3 jz .key_edit cmp [ebx+dlgitemtemplate.type], 5 jnz @f cmp al, 0x39 jnz @f xor [ebx+dlgitemtemplate.flags], 10h jmp .ret_draw @@: .nobtns2: cmp al, 0x4B jz .left cmp al, 0x4D jz .right .ret0: xor eax, eax ret 16 .esc: or eax, -1 ret 16 .enter: cmp [ebx+dlgitemtemplate.type], 2 jnz @f .enter_found: mov eax, ebx ret 16 @@: lea ebx, [ebp+dlgtemplate.size+12] mov ecx, [ebx-4] .enter_find: cmp [ebx+dlgitemtemplate.type], 2 jnz @f test [ebx+dlgitemtemplate.flags], 0x10 jnz .enter_found @@: add ebx, dlgitemtemplate.size loop .enter_find jmp .enter_found .tab: test [ctrlstate], 3 jnz .shift_tab .right: .down: jecxz .ret0 and byte [ebx+dlgitemtemplate.flags], not 4 dec ecx jz .find_first_btn @@: add ebx, dlgitemtemplate.size test [ebx+dlgitemtemplate.flags], 8 jnz .btn_found loop @b .find_first_btn: lea ebx, [ebp+dlgtemplate.size+12] @@: test [ebx+dlgitemtemplate.flags], 8 jnz .btn_found add ebx, dlgitemtemplate.size jmp @b .btn_found: or byte [ebx+dlgitemtemplate.flags], 4 .ret_draw: mov ebx, ebp call .dodraw call draw_image xor eax, eax ret 16 .shift_tab: .left: .up: jecxz .ret0 and byte [ebx+dlgitemtemplate.flags], not 4 sub ecx, [ebp+dlgtemplate.size+8] neg ecx jz .find_last_btn @@: sub ebx, dlgitemtemplate.size test [ebx+dlgitemtemplate.flags], 8 loopz @b jnz .btn_found .find_last_btn: mov ebx, [ebp+dlgtemplate.size+8] imul ebx, dlgitemtemplate.size lea ebx, [ebx+ebp+dlgtemplate.size+12] @@: sub ebx, dlgitemtemplate.size test [ebx+dlgitemtemplate.flags], 8 jz @b jmp .btn_found .key_edit: ; обработка клавиш в поле ввода test al, 0x80 jnz .ret0 or [ebx+dlgitemtemplate.flags], 0x10 mov edx, [ebx+dlgitemtemplate.data] cmp al, 0x4B jz .editor_left cmp al, 0x4D jz .editor_right cmp al, 0x47 jz .editor_home cmp al, 0x4F jz .editor_end cmp al, 0x0E jz .editor_backspace cmp al, 0x53 jnz .editor_char .editor_del: mov ecx, [edx+4] lea edi, [ecx+edx+12] lea esi, [edi+1] cmp byte [edi], 0 jz .ret_test jmp .copy_and_ret_test .editor_left: mov ecx, [edx+4] jecxz @f dec dword [edx+4] @@: jmp .ret_test .editor_right: mov ecx, [edx+4] cmp byte [edx+ecx+12], 0 jz @b inc dword [edx+4] jmp @b .editor_home: and dword [edx+4], 0 jmp @b .editor_end: lea edi, [edx+12] xor eax, eax or ecx, -1 repnz scasb not ecx dec ecx mov [edx+4], ecx .ret_test: mov eax, [edx+4] cmp [edx+8], eax jl .ret_test.l1 mov [edx+8], eax jmp .ret_test.l2 .ret_test.l1: add eax, [ebx+dlgitemtemplate.x1] sub eax, [ebx+dlgitemtemplate.x2] cmp [edx+8], eax jge .ret_test.l2 mov [edx+8], eax .ret_test.l2: jmp .ret_draw .editor_backspace: mov ecx, [edx+4] jecxz .ret_test dec dword [edx+4] lea esi, [edx+ecx+12] lea edi, [esi-1] .copy_and_ret_test: @@: lodsb stosb test al, al jnz @b jmp .ret_test .editor_char: test [ctrlstate], 0x3C jnz .ret_draw movzx eax, al call get_ascii_char push eax ; insert entered symbol xor eax, eax lea edi, [edx+12] or ecx, -1 repnz scasb not ecx pop eax cmp ecx, [edx] ja .ret_test ; buffer capacity exceeded lea edi, [edx+ecx+12-1] mov esi, [edx+4] lea esi, [edx+esi+12] @@: mov cl, [edi] mov [edi+1], cl dec edi cmp edi, esi jae @b mov [esi], al inc dword [edx+4] @@: jmp .ret_test align 4 .dodraw: or [cursor_x], -1 or [cursor_y], -1 add ebx, dlgtemplate.size+8 mov ecx, [ebx] add ebx, 4 jecxz .done_draw .draw_loop: push ecx mov eax, [ebx+dlgitemtemplate.type] cmp eax, draw_functions_num jae .draw_loop_continue call [draw_functions + eax*4] .draw_loop_continue: pop ecx add ebx, dlgitemtemplate.size loop .draw_loop .done_draw: ret iglobal align 4 label draw_functions dword dd ManagerDlgProc.done_draw dd draw_static_text dd draw_button dd draw_editbox dd draw_h_separator dd draw_checkbox dd draw_listbox draw_functions_num = ($ - draw_functions) / 4 endg align 4 draw_static_text: ; рисуем статический текст mov ah, [dialog_main_color] test byte [ebp+dlgtemplate.flags], 2 jz draw_text mov ah, [warning_main_color] draw_text: ; определяем длину строки mov esi, [ebx+dlgitemtemplate.data] draw_text_esi: test esi, esi jz .ret2 push eax push -1 pop ecx @@: inc ecx cmp byte [ecx+esi], 0 jnz @b ; в ecx длина строки xor eax, eax mov edx, [ebx+dlgitemtemplate.x2] sub edx, [ebx+dlgitemtemplate.x1] inc edx cmp ecx, edx jae .text_draw mov al, byte [ebx+dlgitemtemplate.flags] and al, 3 jz .text_align_left cmp al, 1 jz .text_align_center ; текст выровнен вправо mov eax, edx sub eax, ecx jmp .text_draw .text_align_center: mov eax, edx sub eax, ecx shr eax, 1 jmp .text_draw .text_align_left: xor eax, eax .text_draw: push ecx push eax push edx call dlgitem_get_console_ptr pop edx pop ecx mov ah, [esp+5] mov al, ' ' rep stosw pop ecx cmp ecx, edx jbe .text_copy cmp [ebx+dlgitemtemplate.type], 3 jnz @f mov ecx, edx jmp .text_copy @@: cmp edx, 3 jb .ret mov al, '.' stosw stosw stosw add esi, ecx mov ecx, edx sub ecx, 3 sub esi, ecx .text_copy: jecxz .ret ; check for password editboxes cmp [ebx+dlgitemtemplate.type], 3 jnz @f test [ebx+dlgitemtemplate.flags], 20h jz @f mov al, '*' rep stosw jmp .ret @@: lodsb stosw loop @b .ret: mov eax, [ebp+dlgtemplate.x] mov edx, [ebp+dlgtemplate.y] add eax, [ebx+dlgitemtemplate.x2] inc eax add edx, [ebx+dlgitemtemplate.y1] mov ecx, edi call get_console_ptr xchg ecx, edi sub ecx, edi shr ecx, 1 pop eax mov al, ' ' rep stosw .ret2: ret align 4 draw_button: mov ecx, dialog_colors test byte [ebp+dlgtemplate.flags], 2 jz @f mov ecx, warning_colors @@: mov ah, [dialog_normal_btn_color-dialog_colors+ecx] test [ebx+dlgitemtemplate.flags], 4 jz @f mov ah, [dialog_selected_btn_color-dialog_colors+ecx] @@: jmp draw_text align 4 draw_editbox: mov edx, [ebx+dlgitemtemplate.data] test [ebx+dlgitemtemplate.flags], 4 jz @f mov eax, [ebx+dlgitemtemplate.x1] add eax, [edx+4] sub eax, [edx+8] add eax, [ebp+dlgtemplate.x] mov [cursor_x], eax mov eax, [ebx+dlgitemtemplate.y1] add eax, [ebp+dlgtemplate.y] mov [cursor_y], eax @@: mov ecx, dialog_colors test byte [ebp+dlgtemplate.flags], 2 jz @f mov ecx, warning_colors @@: mov ah, [dialog_edit_color-dialog_colors+ecx] test [ebx+dlgitemtemplate.flags], 10h jnz @f mov ah, [dialog_unmodified_edit_color-dialog_colors+ecx] @@: mov esi, [ebx+dlgitemtemplate.data] add esi, [edx+8] add esi, 12 jmp draw_text_esi align 4 dlgitem_get_console_ptr: mov eax, [ebx+dlgitemtemplate.x1] mov edx, [ebx+dlgitemtemplate.y1] mov ecx, eax add eax, [ebp+dlgtemplate.x] add edx, [ebp+dlgtemplate.y] jmp get_console_ptr align 4 draw_h_separator: ; рисуем горизонтальный разделитель call dlgitem_get_console_ptr .scan: mov al, 0xC7 test ecx, ecx js @f mov al, 0xB6 cmp ecx, [ebp+dlgtemplate.width] jz @f mov al, 0xC4 @@: stosb jz .done inc ecx inc edi cmp ecx, [ebx+dlgitemtemplate.x2] jb .scan .done: ret align 4 draw_checkbox: ; рисуем флажок call dlgitem_get_console_ptr test byte [ebx+dlgitemtemplate.flags], 4 jz @f inc eax mov [cursor_x], eax mov [cursor_y], edx @@: mov ah, [dialog_main_color] test byte [ebp+dlgtemplate.flags], 2 jz @f mov ah, [warning_main_color] @@: mov al, '[' stosw mov al, 'x' test byte [ebx+dlgitemtemplate.flags], 10h jnz @f mov al, ' ' @@: stosw mov al, ']' stosw mov al, ' ' stosw mov ecx, [ebx+dlgitemtemplate.x2] sub ecx, [ebx+dlgitemtemplate.x1] jb .ret sub ecx, 3 jbe .ret mov esi, [ebx+dlgitemtemplate.data] @@: lodsb test al, al jz .ret stosw loop @b .ret: ret align 4 draw_listbox: ; рисуем список call dlgitem_get_console_ptr mov edx, [ebx+dlgitemtemplate.data] mov esi, [edx+8] mov eax, [ebx+dlgitemtemplate.y2] sub eax, [ebx+dlgitemtemplate.y1] push eax push eax .0: test esi, esi jz .listdone push esi edi push edx or edx, -1 mov ecx, [ebx+dlgitemtemplate.x2] sub ecx, [ebx+dlgitemtemplate.x1] inc ecx xor eax, eax @@: inc edx cmp byte [esi+8+edx], al jnz @b @@: cmp ecx, edx jae .text_draw mov al, byte [ebx+dlgitemtemplate.flags] and al, 3 jz .text_align_left cmp al, 1 jz .text_align_center ; текст выровнен вправо mov eax, edx sub eax, ecx jmp .text_draw .text_align_center: mov eax, edx sub eax, ecx shr eax, 1 jmp .text_draw .text_align_left: ; xor eax, eax .text_draw: pop edx cmp esi, [edx] lea esi, [esi+8+eax] mov ah, [dialog_selected_list_color] jz @f mov ah, [dialog_list_color] @@: jecxz .next @@: lodsb test al, al jz @f stosw loop @b @@: mov al, ' ' rep stosw .next: pop edi esi add edi, [cur_width] add edi, [cur_width] mov esi, [esi] dec dword [esp] jns .0 .listdone: pop eax ; Линейка прокрутки pop ecx inc ecx mov esi, [edx+4] cmp ecx, esi jae .noscrollbar sub ecx, 2 jbe .noscrollbar mov eax, [edx+12] mul ecx div esi push eax mov eax, [ebx+dlgitemtemplate.x2] add eax, [ebp+dlgtemplate.x] mov edx, [ebx+dlgitemtemplate.y1] add edx, [ebp+dlgtemplate.y] call get_console_ptr pop edx inc edx mov al, 0x1E mov ah, [dialog_scroll_list_color] mov [edi], ax add edi, [cur_width] add edi, [cur_width] .2: mov al, 0xB1 dec edx jz @f mov al, 0xB0 @@: mov [edi], ax add edi, [cur_width] add edi, [cur_width] loop .2 mov al, 0x1F stosw .noscrollbar: ret align 4 listbox_key: mov edx, [ebx+dlgitemtemplate.data] cmp al, 0x48 jz .prev cmp al, 0x50 jz .next cmp al, 0x47 jz .home cmp al, 0x4F jz .end cmp al, 0x51 jz .pgdn cmp al, 0x49 jz .pgup ret .next: call .calc_last_line mov eax, [edx] cmp dword [eax], 0 jz @f call .line_next @@: mov [edx], eax ret .pgdn: call .calc_last_line mov eax, [edx] mov ecx, [ebx+dlgitemtemplate.y2] sub ecx, [ebx+dlgitemtemplate.y1] .pgdnl: cmp dword [eax], 0 jz @f call .line_next loop .pgdnl @@: mov [edx], eax ret .prev: mov eax, [edx] cmp dword [eax+4], 0 jz @f call .line_prev @@: mov [edx], eax ret .pgup: mov eax, [edx] mov ecx, [ebx+dlgitemtemplate.y2] sub ecx, [ebx+dlgitemtemplate.y1] ; inc ecx .pgupl: cmp dword [eax+4], 0 jz @f call .line_prev loop .pgupl @@: mov [edx], eax ret .home: mov eax, [edx] @@: cmp dword [eax+4], 0 jz @f mov eax, [eax+4] jmp @b @@: mov [edx], eax mov [edx+8], eax and dword [edx+12], 0 ret .end: mov eax, [edx] @@: cmp dword [eax], 0 jz @f mov eax, [eax] jmp @b @@: mov [edx], eax mov ecx, [ebx+dlgitemtemplate.y2] sub ecx, [ebx+dlgitemtemplate.y1] jz .e1 .e2: mov eax, [eax+4] loop .e2 .e1: mov [edx+8], eax mov eax, [edx+4] dec eax mov [edx+12], eax ret .line_prev: cmp eax, [edx+8] mov eax, [eax+4] jnz @f mov [edx+8], eax @@: dec dword [edx+12] ret .calc_last_line: mov esi, [edx+8] mov ecx, [ebx+dlgitemtemplate.y2] sub ecx, [ebx+dlgitemtemplate.y1] jz .clldone @@: mov esi, [esi] test esi, esi jz @f loop @b .clldone: ret .line_next: cmp eax, esi mov eax, [eax] jnz @f push eax mov eax, [edx+8] mov eax, [eax] mov [edx+8], eax pop eax mov esi, eax @@: inc dword [edx+12] ret ; void __stdcall SayNoMem(void); SayNoMem: or dword [nomem_dlgdata+4], -1 or dword [nomem_dlgdata+8], -1 push nomem_dlgdata call DialogBox ret ; int __stdcall ConfirmCancel(void); ; return value: 0 = the user is sure, nonzero = the user wants to continue ConfirmCancel: push YesOrNoBtn push 2 push ConfirmCancelMsg push 1 push aCancelled call SayErrTitle test eax, eax ret ; int __stdcall SayErr(int num_strings, const char* strings[], ; int num_buttons, const char* buttons[]); SayErr: pop eax push aError push eax ; int __stdcall SayErrTitle(const char* title, ; int num_strings, const char* strings[], ; int num_buttons, const char* buttons[]); SayErrTitle: push 2 jmp @f ; int __stdcall Message(const char* title, ; int num_strings, const char* strings[], ; int num_buttons, const char* buttons[]); align 16 Message: push 1 @@: pop eax ; [esp+4] = title ; [esp+8] = num_strings ; [esp+12] = strings ; [esp+16] = num_buttons ; [esp+20] = buttons pushad mov ecx, [esp+32+8] add ecx, [esp+32+16] imul ecx, dlgitemtemplate.size add ecx, dlgtemplate.size+12 call xpgalloc test eax, eax jnz @f popad or eax, -1 ret 28 @@: mov ebx, eax mov edi, eax mov eax, [esp+28] stosd ; dlgtemplate.flags or eax, -1 stosd ; dlgtemplate.x stosd ; dlgtemplate.y ; calculate width mov ecx, [esp+32+8] mov esi, [esp+32+12] xor edx, edx .calcwidth: lodsd @@: inc eax cmp byte [eax-1], 0 jnz @b sub eax, [esi-4] inc eax cmp edx, eax ja @f mov edx, eax @@: loop .calcwidth mov ecx, [esp+32+16] mov esi, [esp+32+20] xor ebp, ebp .calcwidth2: lodsd @@: inc eax cmp byte [eax-1], 0 jnz @b sub eax, [esi-4] inc eax add ebp, eax loop .calcwidth2 inc ebp inc ebp cmp edx, ebp ja @f mov edx, ebp @@: mov eax, [cur_width] sub eax, 8 cmp edx, eax jb @f mov edx, eax @@: mov eax, edx stosd ; dlgtemplate.width mov eax, [esp+32+8] inc eax stosd ; dlgtemplate.height mov eax, 3 stosd ; dlgtemplate.border_size_x mov al, 2 stosd ; dlgtemplate.border_size_y mov eax, [esp+32+4] stosd ; dlgtemplate.title xor eax, eax stosd ; (ignored) stosd ; (ignored) stosd ; DlgProc stosd ; userdata mov eax, [esp+32+8] add eax, [esp+32+16] stosd ; num_items ; fill strings xor ecx, ecx mov esi, [esp+32+12] @@: mov eax, 1 stosd ; dlgitemtemplate.type dec eax stosd ; dlgitemtemplate.x1 mov eax, ecx stosd ; dlgitemtemplate.y1 lea eax, [edx-1] stosd ; dlgitemtemplate.x2 mov eax, ecx stosd ; dlgitemtemplate.y2 movsd ; dlgitemtemplate.data mov eax, 1 stosd ; dlgitemtemplate.flags inc ecx cmp ecx, [esp+32+8] jb @b ; fill buttons mov ecx, [esp+32+16] mov esi, [esp+32+20] sub edx, ebp jc .big shr edx, 1 inc edx jmp .fillbtns .big: xor edx, edx .fillbtns: mov eax, 2 stosd ; dlgitemtemplate.type mov eax, edx stosd ; dlgitemtemplate.x1 mov eax, [ebx+dlgtemplate.height] dec eax stosd ; dlgitemtemplate.y1 push eax lodsd sub eax, edx @@: inc edx cmp byte [eax+edx-1], 0 jnz @b mov eax, edx inc edx stosd ; dlgitemtemplate.x2 pop eax stosd ; dlgitemtemplate.y2 mov eax, [esi-4] stosd ; dlgitemtemplate.data mov eax, 9 cmp ecx, [esp+32+16] jnz @f or al, 4 @@: stosd ; dlgitemtemplate.flags loop .fillbtns push ebx call DialogBox cmp eax, -1 jz @f sub eax, ebx sub eax, dlgtemplate.size+12 xor edx, edx mov ecx, dlgitemtemplate.size div ecx sub eax, [esp+32+8] @@: mov [esp+28], eax mov ecx, ebx call pgfree popad ret 20