; Cb-n#%li.-# @l$i Lkbnbe convert_color: bswap eax shr eax, 8 ret draw_window_base: mov al, byte [ebp+tls.color_main+3] and eax, 0xF dec eax js .type1 jz .nodraw dec eax jz .type2 ; window with skin push 1 call draw_border call draw_caption_skinned movzx eax, [ebp+tls.y_size] cmp eax, 21+5 jle @f test byte [ebp+tls.color_main+3], 40h jnz @f push 1 push [ebp+tls.color_main] movzx ecx, [ebp+tls.y_size] sub ecx, 5 push ecx movzx ecx, [ebp+tls.x_size] sub ecx, 5 push ecx push [_skinh] push 5 call rectangle_gradient @@: ; close button mov edx, 40000001h ; id=1, no draw xor ebx, ebx cmp [skin_btn_close.left], ebx jge @f mov ebx, dword [ebp+tls.x_size] @@: add ebx, [skin_btn_close.left] shl ebx, 16 mov bx, word [skin_btn_close.width] dec ebx mov ecx, [skin_btn_close.top] shl ecx, 16 mov cx, word [skin_btn_close.height] dec ecx call add_button ; minimize button mov edx, 4000FFFFh ; id=65535, no draw xor ebx, ebx cmp [skin_btn_minimize.left], ebx jge @f mov ebx, dword [ebp+tls.x_size] @@: add ebx, [skin_btn_minimize.left] shl ebx, 16 mov bx, word [skin_btn_minimize.width] dec ebx mov ecx, [skin_btn_minimize.top] shl ecx, 16 mov cx, word [skin_btn_minimize.height] dec ecx call add_button jmp .nodraw .type1: ; border mov eax, [ebp+tls.color_border] call create_select_pen push eax xor esi, esi call rect_wnd call select_delete ; caption call draw_caption_type1 ; work area test byte [ebp+tls.color_main+3], 40h jnz .nodraw push 1 push [ebp+tls.color_main] movzx eax, [ebp+tls.y_size] dec eax push eax movzx eax, [ebp+tls.x_size] dec eax push eax push 21 push 1 call rectangle_gradient jmp .nodraw .type2: ; border push eax call draw_border ; caption call draw_caption_type2 ; work area test byte [ebp+tls.color_main+3], 40h jnz .nodraw push 1 push [ebp+tls.color_main] movzx eax, [ebp+tls.y_size] sub eax, 5 push eax movzx eax, [ebp+tls.x_size] sub eax, 5 push eax push 20 push 5 call rectangle_gradient .nodraw: ; caption string call draw_caption_string ; draw buttons pushad mov esi, [ebp+tls.buttons] @@: test esi, esi jz @f push [esi+button_desc.next] mov ebx, dword [esi+button_desc.xsize] mov ecx, dword [esi+button_desc.ysize] test byte [esi+button_desc.id+3], 0x40 mov esi, [esi+button_desc.color] jnz .sk call draw_button .sk: pop esi jmp @b @@: popad ret draw_caption_type1: push 040404h push [ebp+tls.color_capt] movzx eax, [ebp+tls.y_size] dec eax cmp eax, 21 jb @f mov eax, 21 @@: push eax movzx eax, [ebp+tls.x_size] dec eax push eax push 1 push 1 call rectangle_gradient ret draw_caption_type2: mov eax, [ebp+tls.color_capt] mov ecx, 0x040404 test eax, 0x40000000 jz @f or ecx, 0x80000000 xor eax, 0xC0000000 @@: push ecx push eax movzx eax, [ebp+tls.y_size] sub eax, 4 cmp eax, 20 jb @f mov eax, 20 @@: push eax movzx eax, [ebp+tls.x_size] sub eax, 4 push eax push 4 push 4 call rectangle_gradient ret draw_caption_skinned: xor ebx, ebx mov eax, [left_bmp] cmp [ebp+tls.bActive], bl jnz @f mov eax, [left1_bmp] @@: xor ecx, ecx call putbmp movzx esi, [ebp+tls.x_size] mov ecx, [eax+4] sub esi, ecx mov eax, [oper_bmp] cmp [ebp+tls.bActive], bl jnz @f mov eax, [oper1_bmp] @@: sub esi, [eax+4] mov eax, [base_bmp] cmp [ebp+tls.bActive], bl jnz @f mov eax, [base1_bmp] @@: cmp esi, [eax+4] jle .nobase @@: call putbmp add ecx, [eax+4] sub esi, [eax+4] jg @b .nobase: movzx ecx, [ebp+tls.x_size] mov eax, [oper_bmp] cmp [ebp+tls.bActive], bl jnz @f mov eax, [oper1_bmp] @@: sub ecx, [eax+4] putbmp: ; in: eax=bmpinfo,ecx=y*65536+x,edi=hDC push eax ecx lea edx, [eax+40] push ebx ; fuColorUse = DIB_RGB_COLORS push eax ; lpbmi push edx ; lpBits push dword [eax+8] ; cScanLines push ebx ; uStartScan push ebx ; YSrc push ebx ; XSrc push dword [eax+8] ; dwHeight push dword [eax+4] ; dwWidth movzx eax, cx shr ecx, 10h push ecx ; YDest push eax ; XDest push edi ; hDC call [SetDIBitsToDevice] pop ecx eax ret draw_caption_string: test byte [ebp+tls.color_main+3], 0x10 jnz @f .ret: .nodraw: ret @@: mov esi, [ebp+tls.caption] test esi, esi jz .ret add esi, [base] mov al, byte [ebp+tls.color_main+3] and eax, 0xF dec eax js .type1 jz .nodraw dec eax jz .type2 ; caption for skinned windows ; determine maximum caption length mov ax, [ebp+tls.x_size] sub ax, [margins+2] sub ax, [margins] js .ret cwd push 6 pop ebx div bx mov ecx, eax ; determine coordinates mov ebx, dword [margins] mov bx, word [_skinh] sub bx, [margins+6] sub bx, [margins+4] sar bx, 1 adc bx, 0 add bx, [margins+6] add bx, -3 .common: mov edx, esi @@: lodsb test al, al loopnz @b jnz @f dec esi @@: sub esi, edx mov ecx, dword [common_colors+16] jmp i40_writetext_l2 .type1: .type2: ; caption for windows without skin movzx eax, [ebp+tls.x_size] sub eax, 16 js .ret cdq push 6 pop ebx div ebx mov ecx, eax mov ebx, 0x00080007 jmp .common i40_draw_window: mov [ebp+tls.color_main], edx mov [ebp+tls.color_capt], esi mov [ebp+tls.color_border], edi mov [ebp+tls.curdraw], 0 cmp [ebp+tls.showwnd], 0 jnz .wasshown ; real size is 1 pixel more inc ebx mov dword [ebp+tls.x_size], ebx inc ecx mov dword [ebp+tls.y_size], ecx test edx, 0x10000000 jz @f mov [ebp+tls.caption], edi @@: push 0 movzx eax, cx push eax movzx eax, bx push eax shr ecx, 10h push ecx shr ebx, 10h push ebx push [ebp+tls.hWnd] call [MoveWindow] push 5 ; SW_SHOW push [ebp+tls.hWnd] call [ShowWindow] mov [ebp+tls.showwnd], 1 cmp [ebp+tls.lpShapeData], 0 jz @f call set_window_shape @@: .wasshown: ; define client box test byte [ebp+tls.color_main+3], 0x20 jnz .client_relative and [ebp+tls.client_left], 0 and [ebp+tls.client_top], 0 movzx eax, [ebp+tls.x_size] mov [ebp+tls.client_width], eax movzx eax, [ebp+tls.y_size] mov [ebp+tls.client_height], eax jmp .client_set .client_relative: mov eax, [_skinh] mov [window_topleft+8*3+4], eax mov [window_topleft+8*4+4], eax mov al, byte [ebp+tls.color_main+3] and eax, 0xF mov edx, [eax*8+window_topleft] mov [ebp+tls.client_left], edx neg edx movzx ecx, [ebp+tls.x_size] lea ecx, [ecx+edx*2] mov [ebp+tls.client_width], ecx mov eax, [eax*8+window_topleft+4] mov [ebp+tls.client_top], eax movzx ecx, [ebp+tls.y_size] sub ecx, eax add ecx, edx mov [ebp+tls.client_height], ecx .client_set: push 0 push [ebp+tls.hWnd] call [ValidateRect] push [ebp+tls.hWnd] call [GetDC] xchg eax, edi call draw_window_base push edi push [ebp+tls.hWnd] call [ReleaseDC] ret i40_put_pixel: test edx, 1000000h jnz .negate mov eax, edx call convert_color push eax add ebx, [ebp+tls.client_left] add ecx, [ebp+tls.client_top] push ecx push ebx push [ebp+tls.hWnd] call [GetDC] xchg eax, edi .1: push edi call [SetPixel] push edi push [ebp+tls.hWnd] call [ReleaseDC] ret .negate: push ecx push ecx push ebx push [ebp+tls.hWnd] call [GetDC] xchg eax, edi push edi call [GetPixel] pop ecx not eax push eax push ecx push ebx jmp .1 i40_getkey: movzx ecx, [ebp+tls.keybuflen] jecxz .empty lea esi, [ebp+tls.keybuffer] mov edi, esi lodsb shl eax, 8 mov [esp+20h], ax dec ecx mov [ebp+tls.keybuflen], cl rep movsb ret .empty: mov byte [esp+20h], 1 ret i40_get_sys_time: sub esp, 10h push esp call [GetLocalTime] movzx eax, word [esp+12] aam shl ax, 4 shr ah, 4 shl eax, 16-4 mov ax, [esp+10] aam shl ax, 4 shr ah, 4 shr ax, 4 mov bl, al mov ax, [esp+8] aam shl ax, 4 shr ah, 4 shr ax, 4 mov ah, bl add esp, 10h mov [esp+20h], eax ret i40_writetext: add edx, [base] i40_writetext_l1: add bx, word [ebp+tls.client_top] ror ebx, 16 add bx, word [ebp+tls.client_left] ror ebx, 16 i40_writetext_l2: push edi push ecx push edx push [ebp+tls.hWnd] call [GetDC] mov ecx, esi pop esi pop edi push eax ; ecx=length, esi=pointer, ebx=x*65536+y, edi=font&color .loop: xor eax, eax lodsb test edi, edi js .test_asciiz dec ecx js .done jmp @f .test_asciiz: test eax, eax jz .done @@: push esi push ecx mov esi, [char_mt] lea esi, [esi + eax*8] add esi, eax mov ecx, 6 test edi, 10000000h jz @f sub esi, [char_mt] add esi, [char2_mt] add esi, eax lodsb mov ecx, eax @@: mov edx, 9 .intloop: lodsb push ebx push ecx .intintloop: shr al, 1 pushad jnc .nopix mov eax, edi @@: call convert_color push eax movzx eax, bx push eax shr ebx, 16 push ebx push dword [esp+3Ch] ; hDC call [SetPixel] jmp @f .nopix: mov eax, [esp+34h] test edi, 0x40000000 jnz @b @@: popad add ebx, 10000h loop .intintloop pop ecx pop ebx inc ebx dec edx jnz .intloop sub ebx, 9 shl ecx, 16 add ebx, ecx pop ecx pop esi jmp .loop .done: push [ebp+tls.hWnd] call [ReleaseDC] pop edi ret i40_delay: imul ebx, ebx, 10 push ebx call [Sleep] ret ramdisk2win32: push edi add ebx, [base] mov esi, ramdisk_path push esi call [lstrlenA] xchg eax, ecx rep movsb push edi push edi mov ecx, 8 @@: mov al, [ebx] inc ebx cmp al, '.' jz @f stosb loop @b @@: dec edi cmp byte [edi], ' ' jz @b inc edi mov al, '.' stosb cmp [ebx], al jnz @f inc ebx @@: mov ecx, 3 @@: mov al, [ebx] inc ebx stosb loop @b @@: dec edi cmp byte [edi], ' ' jz @b inc edi xor eax, eax stosb call [OemToCharA] xor eax, eax pop edi ret i40_read_floppy_file: sub esp, 512 mov edi, esp push esi call ramdisk2win32 pop ebx push eax push eax push 3 push eax push 1 push 80000000h push edi call [CreateFileA] add esp, 512 inc eax jz .err_ret dec eax xchg eax, esi push 0 push esi call [GetFileSize] xchg eax, edi push eax mov ecx, esp push 0 push ecx push edi add ebx, [base] push ebx push esi call [ReadFile] pop eax push esi call [CloseHandle] mov [esp+20h], edi ret .err_ret: or dword [esp+20h], -1 ret pad_bmp: pushad movzx eax, cx shr ecx, 10h lea ecx, [ecx+ecx*2] add ecx, 3 and ecx, not 3 mul ecx push eax call malloc mov [esp+1Ch], eax popad push eax mov edi, eax push ecx mov esi, ebx .extloop: push ecx shr ecx, 10h lea ecx, [ecx+ecx*2] mov eax, ecx shr ecx, 2 rep movsd mov ecx, eax and ecx, 3 rep movsb mov al, 0 @@: test edi, 3 jz @f stosb jmp @b @@: pop ecx dec cx jnz .extloop pop ecx pop edi jmp pad_cont i40_putimage: add ebx, [base] ; Windows requires that all scanlines are DWORD-padded mov edi, ebx test ecx, 30000h jnz pad_bmp pad_cont: xor esi, esi ; BITMAPINFO push esi ; biClrImportant push esi ; biClrUsed push esi ; biYPelsPerMeter push esi ; biXPelsPerMeter push esi ; biSizeImage push esi ; biCompression push 180001h ; biPlanes, biBitCount movzx eax, cx neg eax push eax ; biHeight neg eax shr ecx, 10h push ecx ; biWidth push 40 ; biSize push ebx lea ebx, [esp+4] ; SetDIBitsToDevice push esi ; fuColorUse = DIB_RGB_COLORS push ebx ; lpbmi push edi ; lpvBits push eax ; cScanLines dec eax push eax ; uStartScan push eax ; YSrc inc eax push esi ; XSrc push eax ; dwHeight push ecx ; dwWidth movzx ecx, dx add ecx, [ebp+tls.client_top] push ecx ; YDest shr edx, 10h add edx, [ebp+tls.client_left] push edx ; XDest push [ebp+tls.hWnd] call [GetDC] xchg eax, ebx push ebx ; hdc call [SetDIBitsToDevice] xchg eax, ebx pop ebx add esp, 40 push eax push [ebp+tls.hWnd] call [ReleaseDC] cmp edi, ebx jz @f push edi call free @@: ret draw_button: push ebx push ecx push ebp mov ebp, esp ; word [ebp+4]=y_size, word [ebp+6]=y_start, word [ebp+8]=x_size, word [ebp+10]=x_start ; button body push esi cmp [buttontype], 0 jz .flatbtn or esi, 80000000h push esi mov edx, 2 .l2: cmp byte [esp+edx], 0xEB jbe @f mov byte [esp+edx], 0xEB @@: add byte [esp+edx], 0x14 dec edx jns .l2 pop esi mov eax, 010101h cmp cx, 20 ja @f mov eax, 020202h @@: sub esi, eax .flatbtn: push eax push esi movzx eax, word [ebp+6] add ax, cx push eax movzx eax, word [ebp+10] add ax, bx push eax shr ecx, 16 push ecx shr ebx, 16 push ebx call rectangle_gradient ; button frames pop eax push eax push eax xor ecx, ecx .l1: cmp byte [esp+ecx], 0xDF jbe @f mov byte [esp+ecx], 0xDF @@: inc ecx cmp ecx, 3 jb .l1 pop eax add eax, 202020h call create_select_pen push eax push 0 movzx eax, word [ebp+6] add ax, [ebp+4] push eax push ebx push edi call [MoveToEx] movzx eax, word [ebp+6] push eax push ebx push edi call [LineTo] movzx eax, word [ebp+6] push eax movzx eax, word [ebp+8] add ax, bx push eax push edi call [LineTo] call select_delete cmp byte [ebp-4], 20h jae @f mov byte [ebp-4], 20h @@: cmp byte [ebp-3], 20h jae @f mov byte [ebp-3], 20h @@: cmp byte [ebp-2], 20h jae @f mov byte [ebp-2], 20h @@: mov eax, [ebp-4] sub eax, 202020h call create_select_pen push eax movzx eax, word [ebp+4] add ax, [ebp+6] push eax movzx eax, word [ebp+8] add ax, bx push eax push edi call [LineTo] movzx eax, word [ebp+4] add ax, [ebp+6] push eax push ebx push edi call [LineTo] call select_delete pop eax pop ebp pop ecx pop ebx ret add_button: push esi lea esi, [ebp+tls.buttons] @@: mov eax, [esi] test eax, eax jz .end xchg esi, eax jmp @b .end: push ecx push edx push button_desc.size call malloc mov [esi], eax mov [eax+button_desc.next], 0 pop [eax+button_desc.id] mov dword [eax+button_desc.xsize], ebx pop dword [eax+button_desc.ysize] pop [eax+button_desc.color] ret i40_define_button: test edx, 0x80000000 jnz .delete rol ebx, 16 add bx, word [ebp+tls.client_left] rol ebx, 16 rol ecx, 16 add cx, word [ebp+tls.client_top] rol ecx, 16 test edx, 0x40000000 jnz .nodraw push ecx push edx push [ebp+tls.hWnd] call [GetDC] xchg eax, edi pop edx pop ecx pushad call draw_button push edi push [ebp+tls.hWnd] call [ReleaseDC] popad .nodraw: call add_button .ret: ret .delete: and edx, not 0x80000000 lea esi, [ebp+tls.buttons] @@: mov eax, [esi] test eax, eax jz @f ; The kernel checks only low word of button ID! cmp word [eax+button_desc.id], dx jz .found xchg eax, esi jmp @b @@: ret .found: ; if active button is deleting, there is no more active button cmp eax, [ebp+tls.active_button] jnz @f and [ebp+tls.active_button], 0 @@: push [eax+button_desc.next] push eax call free pop [esi+button_desc.next] ret invalid_slot_msg db 'Emulated program has requested information on non-existent slot' db ' and will be terminated',0 invalid_slot: call release_shared push 0 push 0 push invalid_slot_msg push 0 call [MessageBoxA] jmp i40_terminate get_os_process_info: pushad mov ebx, 5 call i40_sys_service popad stosd ; .cpu_usage xor eax, eax inc eax stosw ; .window_stack_position stosw ; .window_stack_value dec eax stosw ; .not_used1 mov eax, 'OS/I' stosd mov eax, 'DLE ' stosd mov eax, ' ' stosd xor eax, eax stosd ; .memory_start mov eax, 0x01000000-1 stosd ; .used_memory xor eax, eax inc eax stosd ; .PID dec eax stosd stosd stosd stosd stosw ; .slot_state scasw stosd stosd stosd stosd stosb jmp got_process_info i40_get_process_info: cmp ecx, -1 jnz @f mov ecx, [ebp+tls.cur_slot] inc ecx @@: add ebx, [base] mov edx, [shared_data] ; cmp ecx, [edx+shared_data_struc.alloc_threads] ; too many programs will fail cmp ecx, 256 ja invalid_slot dec ecx call acquire_shared mov eax, ecx call get_slot_ptr mov esi, edi mov edi, ebx jecxz get_os_process_info xor eax, eax stosd ; .cpu_usage mov eax, [edx+shared_data_struc.alloc_threads] stosw ; .window_stack_position stosw ; .window_stack_value xor eax, eax stosw ; .not_used1 push esi add esi, 28 movsd movsd movsd pop esi stosd ; .memory_start mov eax, [esi+24] stosd ; .used_memory mov eax, [esi] stosd ; .PID push ecx xor eax, eax push eax push eax push eax push eax push esp push dword [esi+20] call [GetWindowRect] pop eax stosd pop eax stosd pop eax sub eax, [edi-8] sub eax, 1 adc eax, 0 stosd pop eax sub eax, [edi-8] sub eax, 1 adc eax, 0 stosd pop ecx and word [edi], 0 ; .slot_state cmp dword [esi], 0 jnz @f mov byte [edi], 9 @@: scasd ; client area coordinates push esi ; for my window, return true coordinates from tls cmp ecx, [ebp+tls.cur_slot] jnz .notmy lea esi, [ebp+tls.client_left] movsd movsd lodsd dec eax stosd lodsd dec eax stosd jmp @f .notmy: ; for other windows, return copy of window coordinates add esi, 0x22 movsd movsd movsd movsd @@: pop esi ; window state sub esp, 40 push 44 push esp push dword [esi+20] call [GetWindowPlacement] test eax, eax jnz @f add esp, 44 jmp .normal @@: mov eax, [esp+8] ; showCmd add esp, 44 cmp eax, 3 jz .maximized cmp eax, 2 jz .minimized test eax, eax jz .minimized push dword [esi+20] call [IsWindowVisible] test eax, eax jz .minimized .normal: xor eax, eax jmp @f .minimized: mov al, 2 jmp @f .maximized: mov al, 1 @@: stosb got_process_info: mov eax, [shared_data] mov eax, [eax+shared_data_struc.alloc_threads] mov dword [esp+20h], eax ; number of processes call release_shared ret test_button_mouse: cmp al, 86h jnz @f mov al, 6 test [ebp+tls.message_mask], 4 jz @f mov [ebp+tls.translated_msg_code], al ; mouse mov al, 3 ; button @@: ret event_test_redraw: ; if function 0 has not been called, then redraw message is present ; cmp [ebp+tls.showwnd], 0 ; jnz @f cmp [ebp+tls.curdraw], 0 jz @f test [ebp+tls.message_mask], 1 jz @f pop eax mov dword [esp+20h], 1 @@: ret i40_wait_event: call event_test_redraw sub esp, 20h xor eax, eax xchg al, [ebp+tls.translated_msg_code] test eax, eax jnz @f mov al, 2 test byte [ebp+tls.message_mask], al jz .nokey cmp [ebp+tls.keybuflen], ah jnz @f .nokey: inc eax test [ebp+tls.message_mask], 4 jz .nobut cmp [ebp+tls.butbuflen], ah jnz @f .nobut: mov ebx, esp push 0 push 0 push 0 push ebx call [GetMessageA] test eax, eax jz i40_terminate push ebx call [TranslateMessage] push ebx call [DispatchMessageA] add esp, 20h jmp i40_wait_event @@: add esp, 20h cmp al, 6 jnz @f test [ebp+tls.message_mask], 20h jz i40_wait_event @@: call test_button_mouse mov [esp+20h], eax ret i40_check_event: call event_test_redraw sub esp, 20h xor eax, eax xchg al, [ebp+tls.translated_msg_code] or eax, eax jnz .event mov al, 2 test byte [ebp+tls.message_mask], al jz .nokey cmp [ebp+tls.keybuflen], ah jnz .event .nokey: inc eax test [ebp+tls.message_mask], 4 jz .nobut cmp [ebp+tls.butbuflen], ah jnz .event .nobut: @@: mov ebx, esp push 1 push 0 push 0 push 0 push ebx call [PeekMessageA] test eax, eax jz .noevent cmp dword [ebx+4], 0x12 ; WM_QUIT jz i40_terminate push ebx call [TranslateMessage] push ebx call [DispatchMessageA] xor eax, eax cmp [ebp+tls.curdraw], al jnz .redraw xchg al, [ebp+tls.translated_msg_code] or eax, eax jz @b .event: add esp, 20h cmp al, 6 jnz @f test [ebp+tls.message_mask], 20h jz i40_check_event @@: call test_button_mouse mov [esp+20h], eax ret .redraw: inc eax add esp, 20h test [ebp+tls.message_mask], eax jz i40_check_event mov [esp+20h], eax ret .noevent: add esp, 20h and dword [esp+20h], 0 ret i40_redraw_status: dec ebx jz .fn1 dec ebx jnz not_supported_i40_fn ret .fn1: ; delete all defined buttons xor ebx, ebx mov [ebp+tls.active_button], ebx ; no more active buttons xchg ebx, [ebp+tls.buttons] @@: test ebx, ebx jz .done push ebx mov ebx, [ebx] call free jmp @b .done: ret i40_drawrect: push ecx push edx push [ebp+tls.hWnd] call [GetDC] pop edx pop ecx xchg eax, edi push 1 push edx movzx eax, cx shr ecx, 16 add ecx, [ebp+tls.client_top] add eax, ecx push eax movzx eax, bx shr ebx, 16 add ebx, [ebp+tls.client_left] add eax, ebx push eax push ecx push ebx call rectangle_gradient push edi push [ebp+tls.hWnd] call [ReleaseDC] ret get_screen_size: call [GetDesktopWindow] push eax push eax call [GetDC] xchg eax, esi push 8 ; HORZRES push esi call [GetDeviceCaps] dec eax xchg ebx, eax shl ebx, 16 push 10 ; VERTRES push esi call [GetDeviceCaps] dec eax or ebx, eax pop eax push esi push eax call [ReleaseDC] ret i40_get_screen_size: call get_screen_size mov [esp+20h], ebx ret i40_set_background: pushad push 1 call init_background popad mov eax, [bgr_section] test eax, eax jnz @f ret @@: dec ebx jz .setsize dec ebx jz .setpixel dec ebx jz .redraw dec ebx jz .method dec ebx jz .setblock dec ebx jz .map dec ebx jnz not_supported_i40_fn .unmap: push ecx mov esi, ecx add esi, [base] lea edi, [eax+10h] mov ecx, [eax] imul ecx, [eax+4] lea ecx, [ecx*3] mov edx, ecx shr ecx, 2 rep movsd mov ecx, edx and ecx, 3 rep movsb mov byte [eax+12], 1 mov byte [eax+13], 0 pop ecx jmp i40_sys_services.free_heap .map: mov cl, 1 xchg cl, [eax+13] test cl, cl jz @f push eax ecx edx push 100 call [Sleep] pop edx ecx eax jmp .map @@: lea esi, [eax+10h] mov ecx, [eax] imul ecx, [eax+4] lea ecx, [ecx*3] pushad call i40_sys_services.allocate_heap popad mov [esp+20h], eax test eax, eax jnz @f mov byte [esi-10h+13], 0 ret @@: mov edi, eax add edi, [base] mov edx, ecx shr ecx, 2 rep movsd mov ecx, edx and ecx, 3 rep movsb ret .setblock: xchg esi, ecx add esi, [base] lea edi, [eax+edx+10h] rep movsb mov byte [eax+12], 1 ret .setsize: push ecx @@: mov cl, 1 xchg cl, [eax+13] test cl, cl jz @f push eax ecx edx push 100 call [Sleep] pop edx ecx eax jmp @b @@: pop ecx mov [eax], ecx mov [eax+4], edx mov byte [eax+12], 1 mov byte [eax+13], 0 ret .method: mov [eax+8], ecx mov byte [eax+12], 1 ret .setpixel: and edx, 0x00FFFFFF and dword [eax+ecx+10h], 0xFF000000 or [eax+ecx+10h], edx mov byte [eax+12], 1 @@: ret .redraw: cmp byte [eax+12], 0 jz @b .redraw_force: mov byte [eax+12], 0 mov ebx, 2 mov eax, [shared_data] cmp [eax+shared_data_struc.vk], 0 jnz .settmp mov eax, [SetBgrQuestion] dec eax js .ask jz .permanent dec eax jz .settmp ; don't set ret .ask: push 123h push aConfirm push BgrQuestionText push 0 call [MessageBoxA] cmp al, 6 jz .permanent cmp al, 7 jz .settmp ret .permanent: inc ebx .settmp: push eax push esp push 3 ; KEY_QUERY_VALUE | KEY_SET_VALUE push 0 push bgrkeyname push 80000001h call [RegOpenKeyExA] test eax, eax pop esi jnz .nopos ; save old reg values push '0' push '0' push 2 mov eax, esp push eax ; lpcbData add eax, 4 push eax ; lpData push 0 ; lpType push 0 ; lpReserved push bgrstylevalue ; lpValueName push esi ; hKey call [RegQueryValueExA] mov eax, esp mov dword [eax], 2 push eax ; lpcbData add eax, 8 push eax ; lpData push 0 ; lpType push 0 ; lpReserved push bgrtilevalue ; lpValueName push esi ; hKey call [RegQueryValueExA] pop eax mov ecx, '0' mov eax, [bgr_section] cmp byte [eax+8], 1 jz @f mov cl, '2' @@: push ecx mov eax, esp push 2 push eax push 1 push 0 push bgrstylevalue push esi call [RegSetValueExA] pop ecx cmp cl, '0' jnz .stretch push '1' ; tile jmp @f .stretch: push '0' @@: mov eax, esp push 2 push eax push 1 push 0 push bgrtilevalue push esi call [RegSetValueExA] pop ecx push esi call [RegCloseKey] .nopos: mov edi, win32_path push startcurdir push edi call [lstrcpyA] push bgrfilename test bl, 1 jnz @f mov dword [esp], bgrtempfilename @@: push edi call [lstrcatA] push 0 push 80h push 2 push 0 push 0 push 40000000h push edi call [CreateFileA] inc eax jnz @f push 10h push 0 push BgrFileErrorMsg push 0 call [MessageBoxA] pop ecx pop ecx ret @@: dec eax xchg eax, esi ; bmp header mov ecx, [bgr_section] mov eax, [ecx+4] mov [bgr_bmp_header+16h], eax mov eax, [ecx] mov [bgr_bmp_header+12h], eax add eax, eax add eax, [ecx] add eax, 3 and al, not 3 mul dword [ecx+4] ; eax=size of image mov [bgr_bmp_header+22h], eax add eax, 36h mov [bgr_bmp_header+2], eax push eax mov eax, esp push 0 push eax push 36h push bgr_bmp_header push esi call [WriteFile] pop eax ; bmp data mov eax, [bgr_section] mov ecx, [eax+4] lea edi, [eax+10h] mov eax, [eax] mul ecx imul eax, 3 add edi, eax .putline: push ecx mov ecx, [bgr_section] mov eax, [ecx] add eax, eax add eax, [ecx] sub edi, eax push eax push eax mov ecx, esp push 0 push ecx push eax push edi push esi call [WriteFile] pop eax pop ecx and ecx, 3 jz .nopad .padloop: push ecx push 0 push eax mov eax, esp push 0 push eax add eax, 4 push 1 push eax push esi call [WriteFile] pop eax pop eax pop ecx loop .padloop .nopad: pop ecx loop .putline push esi call [CloseHandle] mov eax, [shared_data] mov [eax+shared_data_struc.dwNewBgrTime], -1 ;or [dwNewBgrTime], -1 push ebx push win32_path push 0 push 14h call [SystemParametersInfoA] cmp bl, 2 jnz @f push eax push esp push 500 push 0 push 0 push 0 push 0x1A push 0xFFFF call [SendMessageTimeoutA] pop eax ; restore key values push eax push esp push 2 ; KEY_SET_VALUE push 0 push bgrkeyname push 80000001h call [RegOpenKeyExA] test eax, eax pop esi jnz @f mov eax, esp push 2 push eax push 1 push 0 push bgrstylevalue push esi call [RegSetValueExA] lea eax, [esp+4] push 2 push eax push 1 push 0 push bgrtilevalue push esi call [RegSetValueExA] push esi call [RegCloseKey] @@: mov esi, [shared_data] call [GetTickCount] add eax, 3000 ;mov [dwNewBgrTime], eax mov [esi+shared_data_struc.dwNewBgrTime], eax pop ecx pop ecx ret i40_getbutton: movzx ecx, [ebp+tls.butbuflen] jecxz .empty lea edi, [ebp+tls.butbuffer] mov eax, [edi] and al, not 1 mov [esp+20h], eax lea esi, [edi+4] dec ecx mov [ebp+tls.butbuflen], cl rep movsd ret .empty: mov byte [esp+20h], 1 ret i40_sys_service: cmp ebx, 1 jz .19 cmp ebx, 2 jz .kill cmp ebx, 18 jnz .not2 .kill: call acquire_shared xchg eax, ecx cmp eax, 1 jbe release_shared ; invalid PID/slot - ignore mov esi, [shared_data] mov edi, esi mov ecx, [esi] add esi, shared_data_struc.threads cmp ebx, 2 jz .slot @@: cmp [esi], eax jz .found add esi, 64 loop @b jmp release_shared ; no such PID - ignore .slot: dec eax cmp eax, ecx jae release_shared shl eax, 6 add esi, eax cmp dword [esi], 0 jz release_shared .found: ; terminate self? call get_cur_slot_ptr cmp esi, edi jnz @f call release_shared jmp i40_terminate @@: ; get thread and process handles mov eax, [esi+shared_data_struc.win32_hThread-shared_data_struc.threads] call server_convert mov edi, eax call release_shared ; target thread is suspended? if so, do not wait push edi call [SuspendThread] test eax, eax jnz .suspended push edi call [ResumeThread] ; send WM_CLOSE to thread window push 0 push 0 push 0x10 ; WM_CLOSE push [esi+shared_data_struc.hWnd-shared_data_struc.threads] call [PostMessageA] ; wait no more than 1 second push 1000 push edi call [WaitForSingleObject] cmp eax, 258 ; WAIT_TIMEOUT jnz .ret_close ; let target thread to terminate itself push edi call [SuspendThread] .suspended: mov ebx, [esi+shared_data_struc.win32_stack-shared_data_struc.threads] sub esp, 0xB2*4 push 1000Fh mov esi, esp push esp push edi call [GetThreadContext] mov ax, ss cmp [esi+0xC8], ax jz @f mov [esi+0xC8], ss mov [esi+0xC4], ebx @@: mov [esi+0xBC], cs mov [esi+0x98], ds mov [esi+0x94], es mov [esi+0xB8], dword i40_terminate push esi push edi call [SetThreadContext] add esp, 0xB3*4 @@: push edi call [ResumeThread] cmp eax, 1 ja @b .ret_close: push edi call [CloseHandle] ret .not2: cmp ebx, 3 jnz .not3 cmp ecx, 2 jb .noactivate_ret call acquire_shared mov eax, [shared_data] cmp ecx, [eax+shared_data_struc.alloc_threads] ja .noactivate_release lea eax, [ecx-1] call get_slot_ptr cmp dword [edi], 0 jz .noactivate_release mov esi, [edi+shared_data_struc.hWnd-shared_data_struc.threads] call release_shared .restore_given_window: sub esp, 40 push 44 push esp push esi call [GetWindowPlacement] mov eax, [esp+8] add esp, 44 mov ecx, 5 ; SW_SHOW cmp al, 2 ; SW_SHOWMINIMIZED jnz @f mov cl, 9 ; SW_RESTORE @@: push ecx push esi call [ShowWindow] ; push esi ; call [BringWindowToTop] push esi call [SetForegroundWindow] ret .noactivate_release: call release_shared .noactivate_ret: ret .not3: cmp ebx, 4 jnz .not4 ; get idle time - current implementation on NT simply returns cpuspeed cmp [bIs9x], 0 jz .5 idletime_via_ring0 = 1 if ~idletime_via_ring0 mov eax, [shared_data] cmp [eax+shared_data_struc.b9xPerfInited], 0 jnz .perfinited call acquire_shared cmp [eax+shared_data_struc.b9xPerfInited], 0 jnz @f push eax push esp ; phkResult push 1 ; samDesired = KEY_QUERY_VALUE push 0 ; ulOptions push perfstart ; lpSubKey push 80000006h ; hKey = HKEY_DYN_DATA call [RegOpenKeyExA] pop esi test eax, eax jnz .perfinitfail push eax mov eax, esp push 4 push esp ; lpcbData push eax ; lpData push 0 ; lpType push 0 ; lpReserved push perfval ; lpValueName push esi ; hKey call [RegQueryValueExA] pop ecx pop ecx push eax push esi call [RegCloseKey] pop eax test eax, eax jnz .perfinitfail push 200 call [Sleep] ; give chance to collect data @@: mov eax, [shared_data] mov [eax+shared_data_struc.b9xPerfInited], 1 call release_shared .perfinited: push 100 pop ebx push eax push esp ; phkResult push 1 ; samDesired = KEY_QUERY_VALUE push 0 ; ulOptions push perfget ; lpSubKey push 80000006h ; hKey = HKEY_DYN_DATA call [RegOpenKeyExA] pop esi test eax, eax jnz @f push ebx mov eax, esp push 4 push esp ; lpcbData push eax ; lpData push 0 ; lpType push 0 ; lpReserved push perfval ; lpValueName push esi ; hKey call [RegQueryValueExA] pop ecx pop ebx push esi call [RegCloseKey] @@: pushad call .5 popad push 100 pop ecx sub ebx, ecx neg ebx mul ebx div ecx mov [esp+20h], eax ret .perfinitfail: call release_shared push 40h push 0 push aPerfInitFailed push 0 call [MessageBoxA] jmp .5 else mov eax, [shared_data] cmp [eax+shared_data_struc.b9xPerfInited], 0 jnz @f .idlecount_init: div edx @@: mov ebx, [eax+shared_data_struc.idlecount] pushad call .5 popad mul ebx mov ecx, 1000 div ecx mov [esp+20h], eax ret end if .not4: cmp ebx, 5 jnz .not5 .5: mov eax, [shared_data] mov ebx, [eax+shared_data_struc.cpuspeed] test ebx, ebx jnz @f ; determine cpu speed ; 1) check for value in registry push eax push esp push 1 ; KEY_QUERY_VALUE push 0 push keycpu push 80000002h call [RegOpenKeyExA] test eax, eax pop eax jnz .nokey xchg eax, esi push eax push 4 push esp lea eax, [esp+8] push eax push 0 push 0 push keymhz push esi call [RegQueryValueExA] push eax push esi call [RegCloseKey] pop eax test eax, eax pop eax pop eax jnz .nokey imul eax, 1000000 jmp .speed_found .nokey: ; 2) sleep for 1/4 sec and read TSC rdtsc push eax edx push 250 call [Sleep] rdtsc pop ecx ebx sub eax, ebx sbb edx, ecx shl eax, 2 .speed_found: xchg ebx, eax mov eax, [shared_data] mov [eax+shared_data_struc.cpuspeed], ebx @@: mov [esp+20h], ebx ret .not5: cmp ebx, 7 jnz .not7 mov eax, [shared_data] mov eax, [eax+shared_data_struc.active_process] mov [esp+20h], eax ret .not7: cmp ebx, 8 jnz .not8 dec ecx jnz @f mov eax, [shared_data] movzx eax, [eax+shared_data_struc.sound_flag] mov [esp+20h], eax ret @@: dec ecx jnz not_supported_i40_fn mov eax, [shared_data] lock xor [eax+shared_data_struc.sound_flag], 1 ret .not8: cmp ebx, 9 jnz .not9 .19: mov eax, [shared_data] cmp [eax+shared_data_struc.vk], 0 jz not_supported_i40_fn .server_terminate: div edx ret .not9: cmp ebx, 10 ; jnz .not10 ; call minimize_window ; ret jz minimize_window .not10: cmp ebx, 11 jnz .not11 dec ecx jnz not_supported_i40_fn xor eax, eax mov edi, edx add edi, [base] ; floppy is not supported yet => return "no floppy installed" stosb ; IDEx configuration ; CD is not supported yet. On IDEx there may be only HD (or nothing) xor edx, edx mov esi, hd_partitions_num push esi .idex: lodsd shl edx, 2 test eax, eax jz @f inc edx @@: cmp esi, hd_partitions_num+4*4 jc .idex mov [edi], dl inc edi ; number of partitions pop esi mov cl, 4 @@: lodsd stosb loop @b ; reserved bytes and dword [edi], 0 ret .not11: cmp ebx, 12 jnz .not12 .return0: and dword [esp+20h], 0 ret .not12: cmp ebx, 13 jnz .not13 mov edi, ecx add edi, [base] mov esi, version_inf mov ecx, version_end - version_inf rep movsb ret .not13: cmp ebx, 14 jz .return0 cmp ebx, 15 jnz .not15 call get_screen_size movzx eax, bx inc eax shr eax, 1 push eax shr ebx, 16 inc ebx shr ebx, 1 push ebx call [SetCursorPos] ret .not15: cmp ebx, 16 jnz .not16 sub esp, 20h push esp call [GlobalMemoryStatus] mov eax, [esp+12] add esp, 20h shr eax, 10 mov [esp+20h], eax ret .not16: cmp ebx, 17 jnz .not17 sub esp, 20h push esp call [GlobalMemoryStatus] mov eax, [esp+8] add esp, 20h shr eax, 10 mov [esp+20h], eax ret .not17: cmp ebx, 19 jnz .not19 jecxz .19_0 dec ecx jz .19_1 dec ecx jz .19_2 dec ecx jz .19_3 dec ecx jnz not_supported_i40_fn movzx eax, dx push eax shr edx, 16 push edx call [SetCursorPos] ret .19_0: mov eax, [shared_data] movzx eax, [eax+shared_data_struc.mouse_speed_factor] mov [esp+20h], eax ret .19_1: mov eax, [shared_data] mov [eax+shared_data_struc.mouse_speed_factor], dx ret .19_2: mov eax, [shared_data] mov eax, [eax+shared_data_struc.mouse_delay] mov [esp+20h], eax ret .19_3: mov eax, [shared_data] mov [eax+shared_data_struc.mouse_delay], edx ret .not19: cmp ebx, 21 jnz .not21 xchg eax, ecx call get_slot_num mov [esp+20h], edx ret .not21: cmp ebx, 22 jnz not_supported_i40_fn cmp ecx, 4 jae not_supported_i40_fn shr ecx, 1 jnc @f xchg eax, edx call get_slot_num @@: dec edx jz .22err mov esi, [shared_data] cmp edx, [esi] jae .22err shl edx, 6 mov esi, [esi+edx+shared_data_struc.hWnd] and dword [esp+20h], 0 dec ecx js minimize_given_window jmp .restore_given_window .22err: or dword [esp+20h], -1 ret get_slot_num: push ecx mov esi, [shared_data] mov ecx, [esi] add esi, shared_data_struc.threads xor edx, edx @@: inc edx cmp [esi], eax jz @f add esi, 64 loop @b xor edx, edx @@: pop ecx ret minimize_window: mov esi, [ebp+tls.hWnd] minimize_given_window: mov [ebp+tls.butbuflen], 0 xor eax, eax ; SW_HIDE mov ecx, [shared_data] cmp [ecx+shared_data_struc.vk], 0 jnz @f mov al, 6 ; SW_MINIMIZE @@: push eax push esi call [ShowWindow] ret server_convert: div edx ret i40_sys_setup: mov eax, [shared_data] and dword [esp+20h], 0 dec ebx jnz .nomidi cmp ecx, 100h jb .nomidi cmp ecx, 0xFFFF ja .nomidi mov [eax+shared_data_struc.midi_base], cx ret .nomidi: dec ebx jnz .not2 mov edi, keymap dec ecx jz .settable mov edi, keymap_shift dec ecx jz .settable mov edi, keymap_alt dec ecx jnz .nosettable .settable: add edx, [base] mov esi, edx mov ecx, 80h/4 rep movsd ret .nosettable: cmp ecx, 9-3 jnz .nosetkeyboard mov [eax+shared_data_struc.keyboard], dx ret .nosetkeyboard: inc dword [esp+20h] ret .not2: dec ebx jnz .not3 mov [eax+shared_data_struc.cd_base], cl ret .not3: dec ebx jnz .not4 cmp ecx, 0x100 jb .not4 cmp ecx, 0xFFFF ja .not4 mov word [eax+shared_data_struc.sb16], cx ret .not4: dec ebx jnz .not5 mov [eax+shared_data_struc.syslang], ecx ret .not5: dec ebx jnz .not6 cmp ecx, 0x100 jb .not6 mov [eax+shared_data_struc.wss], ecx ret .not6: dec ebx jnz .not7 mov [eax+shared_data_struc.hd_base], cl ret .not7: dec ebx jnz .not8 mov [eax+shared_data_struc.fat32part], ecx ret .not8: dec ebx dec ebx jnz .not10 mov [eax+shared_data_struc.sound_dma], ecx ret .not10: dec ebx jnz .not11 and ecx, 1 mov [eax+shared_data_struc.lba_read_enabled], ecx ret .not11: dec ebx jnz .not12 and ecx, 1 jz .okcheck11 cmp [eax+shared_data_struc.bAllowReadPCI], 0 jnz .okcheck11 ; be silent, because in loading process (of VirtualKolibri) SETUP will try this anyway ; push 40h ; push 0 ; push aPciDisabled ; push 0 ; call [MessageBoxA] ret .okcheck11: mov [eax+shared_data_struc.pci_access_enabled], ecx ret .not12: mov byte [esp+20h], 21 ; restore eax jmp not_supported_i40_fn i40_wait_event_timeout: ; call event_test_redraw ; imul ebx, ebx, 10 sub esp, 20h mov esi, esp jmp .M .L: push 2 pop eax test byte [ebp+tls.message_mask], al jz .nokey cmp [ebp+tls.keybuflen], ah jnz .event .nokey: inc eax test [ebp+tls.message_mask], 4 jz .nobut cmp [ebp+tls.butbuflen], ah jnz .event .nobut: push 1 ; PM_REMOVE push 0 push 0 push 0 push esi call [PeekMessageA] test eax, eax jz .notfound cmp dword [esi+4], 0x12 ; WM_QUIT jz i40_terminate push esi call [TranslateMessage] push esi call [DispatchMessageA] .M: xor eax, eax cmp [ebp+tls.curdraw], al jz @f test [ebp+tls.message_mask], 1 jz @f inc eax add esp, 20h mov dword [esp+20h], eax ret @@: xchg al, [ebp+tls.translated_msg_code] test eax, eax jz .L cmp al, 6 jnz .event test [ebp+tls.message_mask], 20h jz .L .event: add esp, 20h call test_button_mouse mov [esp+20h], eax ret .notfound: push 10 call [Sleep] dec ebx jnz .L .timeout: add esp, 20h and dword [esp+20h], 0 ret i40_getsetup: mov eax, [shared_data] dec ebx jnz .not_midi_base movzx eax, [eax+shared_data_struc.midi_base] mov [esp+20h], eax ret .not_midi_base: dec ebx jnz .not_keyboard mov esi, keymap dec ecx jz .getmap mov esi, keymap_shift dec ecx jz .getmap mov esi, keymap_alt dec ecx jnz .nobase .getmap: mov ecx, 128/4 mov edi, edx add edi, [base] rep movsd ret .nobase: cmp ecx, 9-3 jnz not_supported_i40_fn movzx eax, [eax+shared_data_struc.keyboard] mov [esp+20h], eax ret .not_keyboard: dec ebx jnz .not_cd_base movzx eax, [eax+shared_data_struc.cd_base] mov [esp+20h], eax ret .not_cd_base: dec ebx jnz .not_sb16 mov eax, [eax+shared_data_struc.sb16] mov [esp+20h], eax ret .not_sb16: dec ebx jnz .not_lang mov eax, [eax+shared_data_struc.syslang] mov [esp+20h], eax ret .not_lang: dec ebx jnz .not_wss mov eax, [eax+shared_data_struc.wss] mov [esp+20h], eax ret .not_wss: dec ebx jnz .not_hdbase movzx eax, [eax+shared_data_struc.hd_base] mov [esp+20h], eax ret .not_hdbase: dec ebx jnz .not_fat32part mov eax, [eax+shared_data_struc.fat32part] mov [esp+20h], eax ret .not_fat32part: dec ebx jnz .not_timer_ticks call [GetTickCount] push 10 pop ecx xor edx, edx div ecx mov [esp+20h], eax ret .not_timer_ticks: dec ebx jnz .not_sound_dma mov eax, [eax+shared_data_struc.sound_dma] mov [esp+20h], eax ret .not_sound_dma: dec ebx jnz .not_lba_enabled mov eax, [eax+shared_data_struc.lba_read_enabled] mov [esp+20h], eax ret .not_lba_enabled: dec ebx jnz .not_pci_enabled mov eax, [eax+shared_data_struc.pci_access_enabled] mov [esp+20h], eax ret .not_pci_enabled: mov dword [esp+20h], 1 ; this is kernel rule, not my ret i40_get_sys_date: sub esp, 10h push esp call [GetLocalTime] movzx eax, word [esp+6] aam shl ax, 4 shr ah, 4 shl eax, 16-4 mov ax, [esp+2] aam shl ax, 4 shr ah, 4 shr ax, 4 mov bl, al mov ax, [esp] sub ax, 2000 aam shl ax, 4 shr ah, 4 shr ax, 4 mov ah, bl add esp, 10h mov [esp+20h], eax ret i40_current_folder: add ecx, [base] dec ebx jz .set dec ebx jnz not_supported_i40_fn mov edi, ecx mov esi, [ebp+tls.cur_dir] push edx push esi call [lstrlenA] pop ecx inc eax cmp ecx, eax jb @f mov ecx, eax @@: rep movsb mov byte [edi-1], 0 mov [esp+20h], eax ret .set: mov esi, ecx cmp byte [ecx], '/' jnz .relative push [ebp+tls.cur_dir] call free push esi call [lstrlenA] inc eax ; (for terminating zero) inc eax ; '/sys' -> '/rd/1' requires one additional byte push eax push eax call malloc mov [ebp+tls.cur_dir], eax mov edi, eax pop ecx mov eax, [esi] or eax, ' ' cmp eax, '/sys' jnz @f mov eax, '/rd/' stosd mov al, '1' stosb sub ecx, 4 add esi, 4 @@: rep movsb ret .relative: push [ebp+tls.cur_dir] call [lstrlenA] push eax push esi call [lstrlenA] mov edi, eax inc eax add [esp], eax push [ebp+tls.cur_dir] push 0 push [hHeap] call [HeapReAlloc] mov [ebp+tls.cur_dir], eax add edi, eax .l1: cmp word [esi], '.' jz .ret cmp word [esi], './' jnz @f inc esi inc esi jmp .l1 @@: cmp word [esi], '..' jnz .copy cmp byte [esi+2], 0 jz @f cmp byte [esi+2], '/' jnz .copy @@: dec edi cmp edi, [ebp+tls.cur_dir] jbe @f cmp byte [edi], '/' jnz @b @@: inc esi inc esi cmp byte [esi], 0 jz .ret inc esi jmp .l1 .copy: lodsb stosb test al, al jnz .copy ret .ret: mov byte [edi], 0 ret i40_delete_ramdisk_file: sub esp, 512 mov edi, esp call ramdisk2win32 push edi call [DeleteFileA] add esp, 512 ret i40_write_ramdisk_file: test esi, esi jnz not_supported_i40_fn sub esp, 512 mov edi, esp push ecx edx call ramdisk2win32 push 0 push 80h push 2 push 0 push 0 push 40000000h push edi call [CreateFileA] inc eax jz .ret dec eax xchg eax, esi pop edx ecx add ecx, [base] push eax mov eax, esp push 0 push eax push edx push ecx push esi call [WriteFile] pop eax push esi call [CloseHandle] .ret: add esp, 512 and dword [esp+20h], 0 ret i40_screen_getpixel: push 0 call [GetDC] xchg eax, esi push 8 push esi call [GetDeviceCaps] xchg eax, ebx xor edx, edx div ebx push eax push edx push esi call [GetPixel] push eax push esi push 0 call [ReleaseDC] pop eax call convert_color mov [esp+20h], eax ret i40_screen_getarea: add ebx, [base] push ecx ebx edx mov edi, ecx movsx ebx, cx sar edi, 16 cmp ebx, 0 jle .nodata cmp edi, 0 jg .okdata .nodata: pop edx ebx ecx ret .okdata: xor eax, eax push eax call [GetDC] push eax push eax call [CreateCompatibleDC] xchg eax, esi push ebx push edi push dword [esp+8] call [CreateCompatibleBitmap] push eax push esi call [SelectObject] push eax movzx eax, word [esp+8] movzx ecx, word [esp+8+2] push 0xCC0020 push eax push ecx push dword [esp+16] push ebx push edi push 0 push 0 push esi call [BitBlt] push esi call [SelectObject] push ebp xchg eax, ebp ; esi=hDC, ebp=hBitmap, ebx=height, edi=width xor eax, eax push eax ; biClrImportant push eax ; biClrUsed push eax ; biYPelsPerMeter push eax ; biXPelsPerMeter push eax ; biSizeImage push eax ; biCompression push 180001h ; biBitCount, biPlanes push ebx ; biHeight neg dword [esp] push edi ; biWidth push 40 ; biSize mov ecx, esp push eax ; uUsage push ecx ; lpbi mov eax, [ecx+52] test edi, 3 jz .width_aligned_1 lea eax, [3*edi+3] and al, not 3 mul ebx call malloc_big .width_aligned_1: push eax ; lpvBits push ebx ; cScanLines push 0 ; uStartScan push ebp ; hbmp push esi ; hdc xchg eax, edi call [GetDIBits] add esp, 40 push ebp call [DeleteObject] pop ebp push esi call [DeleteDC] push 0 call [ReleaseDC] pop edx eax edx cmp eax, edi jz .ret ; edi -> bits from Windows [dword-aligned scanlines], eax -> bits for Kolibri [no spaces], shr edx, 16 ; ebx = height, edx = width push 8000h push 0 push edi xchg eax, edi lea edx, [edx*3] xchg eax, esi @@: mov ecx, edx shr ecx, 2 rep movsd mov ecx, edx and ecx, 3 rep movsb add esi, 3 and esi, not 3 sub ebx, 1 jnz @b call [VirtualFree] .ret: ret i40_read_mouse_pos: dec ebx js .get_coord jz .get_coord dec ebx jnz .ifcursor cmp [bIs9x], 0 jnz read_9x_mouse_buttons xor ebx, ebx push 6 ; VK_XBUTTON2 call .aks push 5 ; VK_XBUTTON1 call .aks push 4 ; VK_MBUTTON call .aks push 2 ; VK_RBUTTON call .aks push 1 ; VK_LBUTTON call .aks mov [esp+20h], ebx ret .get_coord: push eax push eax push esp call [GetCursorPos] pop eax ; x pop ecx ; y test ebx, ebx js @f sub ax, [ebp+tls.x_start] sub ax, word [ebp+tls.client_left] sub cx, [ebp+tls.y_start] sub cx, word [ebp+tls.client_top] @@: shl eax, 16 add eax, ecx mov [esp+20h], eax ret .ifcursor: dec ebx dec ebx jz .load_cursor dec ebx jz .set_cursor dec ebx jnz .not_cursor .delete_cursor: jecxz .delete_invalid call acquire_shared mov eax, ecx mov ecx, num_cursors mov edi, [shared_data] add edi, shared_data_struc.cursors @@: add edi, 8 cmp [edi-8], eax loopnz @b jnz .delete_invalid_release mov ecx, [ebp+tls.cur_slot] cmp [edi-4], ecx jnz .delete_invalid_release and dword [edi-8], 0 and dword [edi-4], 0 call release_shared push eax call [DestroyCursor] ; the current kernel implementation returns garbage ! mov dword [esp+20h], 0xBAADF00D ; is it garbage? :-) ret .delete_invalid_release: call release_shared .delete_invalid: push 10h push 0 push aInvalidCursor push 0 call [MessageBoxA] ; the current kernel implementation returns 6 !? mov dword [esp+20h], 6 ret .set_cursor: ; set_cursor for invalid handle reverts to standard arrow call acquire_shared mov eax, ecx jecxz .setarrow mov ecx, num_cursors mov edi, [shared_data] add edi, shared_data_struc.cursors @@: add edi, 8 cmp [edi-8], eax loopnz @b jz @f .setarrow: mov eax, [hArrow] @@: ; N.B. I don't check process field, because the kernel allows to set ; cursors, loaded by another process call release_shared mov [ebp+tls.hCursor], eax push eax call [SetCursor] mov [esp+20h], eax ret .load_cursor: test dx, dx jz .fromfile dec dx jz .frommem dec dx jz .indirect jmp not_supported_i40_fn .fromfile: mov esi, ecx add esi, [base] sub esp, 204h mov edi, esp call i40_file_system_lfn.parse test eax, eax jz @f add esp, 204h and dword [esp+20h], 0 ret @@: push 10h ; LR_LOADFROMFILE push 32 push 32 push 2 ; IMAGE_CURSOR push edi push 0 call [LoadImageA] add esp, 204h test eax, eax jnz .addcursor push 10h push 0 push aCursorFailed jmp .mberr .addcursor: call acquire_shared mov ecx, num_cursors mov edi, [shared_data] add edi, shared_data_struc.cursors @@: add edi, 8 cmp dword [edi-8], 0 loopnz @b jz @f call release_shared push 10h push 0 push aCursorLimitExceeded jmp .mberr @@: mov [edi-8], eax mov edx, [ebp+tls.cur_slot] mov [edi-4], edx call release_shared mov [esp+20h], eax ret .frommem: add ecx, [base] cmp dword [ecx], 0x020000 jz @f push 10h push 0 push aInvCursorData .mberr: push 0 call [MessageBoxA] .reterr: and dword [esp+20h], 0 ret @@: cmp word [ecx+4], 1 jz @f push 10h push 0 push aOnlyOneCursor jmp .mberr @@: cmp word [ecx+6], 0x2020 jz @f push 10h push 0 push aInvCursorDim jmp .mberr @@: mov eax, [ecx+0Ah] add ecx, [ecx+12h] sub ecx, 4 push dword [ecx] mov [ecx], eax push ecx push 0 push 32 push 32 push 0x00030000 push 0 push 0x2E8+4 push ecx call [CreateIconFromResourceEx] pop ecx pop dword [ecx] test eax, eax jnz .addcursor .gen_failed: push 10h push 0 push aCursorFailed jmp .mberr .indirect: mov ebx, edx shr ebx, 16 ; bl = y, bh = x mov esi, ecx add esi, [base] push 32*32*4 call malloc mov edi, eax mov ecx, 32*32 push esi edi @@: lodsd and eax, 0xFFFFFF stosd loop @b pop edi esi push edi ; lpvBits push 32 ; cBitsPerPel push 1 ; cPlanes push 32 ; nHeight push 32 ; nWidth call [CreateBitmap] test eax, eax jnz @f .free_edi: push edi call free jmp .gen_failed @@: push eax ; ICONINFO.hbmColor mov ecx, 32*4 push esi edi .1: push ecx mov cl, 8 xor edx, edx @@: lodsd shr eax, 24 setz al lea edx, [edx*2+eax] loop @b mov al, dl stosb pop ecx loop .1 pop edi esi push edi ; lpvBits push 1 ; cBitsPerPel push 1 ; cPlanes push 32 ; nHeight push 32 ; nWidth call [CreateBitmap] test eax, eax jnz @f call [DeleteObject] jmp .free_edi @@: push eax ; ICONINFO.hbmMask movzx eax, bl push eax ; ICONINFO.yHotSpot movzx eax, bh push eax ; ICONINFO.xHotSpot push 0 ; ICONINFO.fIcon push esp call [CreateIconIndirect] mov ebx, eax add esp, 12 call [DeleteObject] call [DeleteObject] test ebx, ebx jz .free_edi push edi call free mov eax, ebx jmp .addcursor .not_cursor: dec ebx jnz not_supported_i40_fn mov eax, [ebp+tls.scroll] cdq mov ecx, 120 ; WHEEL_DELTA idiv ecx mov [ebp+tls.scroll], edx movzx eax, ax mov [esp+20h], eax ret .aks: push dword [esp+4] call [GetAsyncKeyState] cmp ah, 80h cmc adc ebx, ebx ret 4 read_9x_mouse_buttons: call [jmp_temp_int33] movzx eax, bl mov [esp+20h], eax ret use16 temp_code: mov eax, esp mov ss, [temp_ss] mov sp, temp_stack_size push eax mov ax, 3 int 33h pop eax push ds pop ss mov esp, eax db 66h retf temp_code_int1A: mov esi, esp mov ss, [temp_ss] mov sp, temp_stack_size push esi int 1Ah pop esi push ds pop ss mov esp, esi db 66h retf temp_code_size = $ - temp_code use32 i40_draw_line: push edx mov esi, ecx mov eax, edx call convert_color push eax push eax push 1 push 0 call [CreatePen] push eax push [ebp+tls.hWnd] call [GetDC] xchg eax, edi push edi call [SelectObject] push eax push 0 test byte [esp+12+3], 0x01 jz @f push 6 ; R2_NOT push edi call [SetROP2] mov [esp], eax @@: push 0 mov eax, esi shr eax, 16 add eax, [ebp+tls.client_top] push eax mov eax, ebx shr eax, 16 add eax, [ebp+tls.client_left] push eax push edi call [MoveToEx] movzx esi, si add esi, [ebp+tls.client_top] push esi movzx ebx, bx add ebx, [ebp+tls.client_left] push ebx push edi call [LineTo] pop eax test byte [esp+8+3], 0x01 jz @f push eax push edi call [SetROP2] push esi push ebx push edi call [GetPixel] xor eax, 0xFFFFFF mov [esp+4], eax @@: pop eax pop ecx push eax push ecx push esi push ebx push edi call [SetPixel] push edi call [SelectObject] push eax call [DeleteObject] push edi push [ebp+tls.hWnd] call [ReleaseDC] pop edx ret i40_get_background: pushad push 0 call init_background popad mov eax, [bgr_section] dec ebx jz .1 dec ebx jz .2 dec ebx dec ebx jnz not_supported_i40_fn test eax, eax mov ecx, 2 jz @f mov ecx, [eax+8] @@: mov [esp+20h], ecx ret .1: test eax, eax jz @f mov ecx, [eax] shl ecx, 16 mov cx, [eax+4] jmp @b @@: call get_screen_size add ebx, 10001h @@: mov [esp+20h], ebx .ret: ret .2: ; cmp ecx, 0x160000-16 ; jae .ret xor ebx, ebx test eax, eax jz @b mov ebx, [eax+ecx+10h] and ebx, 0x00FFFFFF jmp @b i40_set_event_mask: test ebx, not 1F7h jnz not_supported_i40_fn mov [ebp+tls.message_mask], ebx ret i40_reserve_free_ports: cmp ebx, 1 ja not_supported_i40_fn cmp edx, 0xFFFF ja .inv_range cmp ecx, edx jbe .range_ok .inv_range: push 30h push aWarning push PortsRangeErr push 0 call [MessageBoxA] mov dword [esp+20h], 1 ret .range_ok: call acquire_shared mov esi, [shared_data] mov eax, ecx test ebx, ebx jnz .free ; reserve ports @@: mov edi, PortsNotEnabledErr bt dword [esi+shared_data_struc.DisabledPorts], eax jc .err_release mov edi, PortsUsedErr bt dword [esi+shared_data_struc.UsedIoMap], eax jnc .err_release inc eax cmp eax, edx jbe @b mov eax, ecx @@: btr dword [esi+shared_data_struc.UsedIoMap], eax inc eax cmp eax, edx jbe @b jmp .update_iomap .free: mov edi, PortsNotUsedErr bt dword [esi+shared_data_struc.UsedIoMap], eax jc .err_release inc eax cmp eax, edx jbe .free mov eax, ecx @@: bts dword [esi+shared_data_struc.UsedIoMap], eax inc eax cmp eax, edx jbe @b .update_iomap: cmp [bIs9x], 0 jz .nt call release_shared and dword [esp+20h], 0 ret .nt: mov eax, [shared_data] push 0 push 0 add eax, shared_data_struc.UsedIoMap push 2000h push eax push 0x22203C call send_driver_request mov edi, DrvOpenErr jnz @f .err_release: call release_shared push 30h push aWarning push edi push 0 call [MessageBoxA] mov dword [esp+20h], 1 ret @@: call release_shared ; push 0 ; call [Sleep] ; force task switch and dword [esp+20h], 0 ret i40_display_number: cmp bl, 1 ja not_supported_i40_fn push ebx esi and ebx, not 0xC0000000 xor esi, esi cmp bl, 1 jb .noptr mov eax, [base] test byte [esp+7], 0x40 jz @f mov esi, [eax+ecx+4] @@: mov ecx, [eax+ecx] .noptr: mov eax, 10 cmp bh, 1 jb @f mov eax, 16 jz @f mov eax, 2 @@: shr ebx, 16 cmp ebx, 64 jbe @f pop esi ebx jmp not_supported_i40_fn @@: push edi mov edi, esp sub esp, 64 dec edi std push edx push ebx xchg eax, ecx test ebx, ebx jz .done .digit: xor edx, edx test esi, esi jz .dig0 push eax mov eax, esi div ecx pop esi xchg eax, esi .dig0: div ecx xchg eax, edx cmp al, 10 sbb al, 69h das stosb xchg eax, edx dec ebx jnz .digit .done: cld mov edx, edi inc edx pop esi pop ebx lea edi, [esp+40h] test byte [esp+48h+3], 80h jz .okleadzero @@: cmp byte [edx], '0' jnz .okleadzero inc edx dec esi cmp edx, edi jb @b dec edx inc esi mov byte [edx], '0' .okleadzero: mov ecx, [edi+4] and ecx, not 0x80000000 mov edi, [edi] call i40_writetext_l1 add esp, 4Ch ret i40_display_settings: dec ebx jnz @f set_button_style: div edx ret @@: dec ebx jnz @f add ecx, [base] set_wnd_colors: div edx ret @@: dec ebx jnz @f add ecx, [base] get_wnd_colors: div edx ret @@: dec ebx jnz @f mov eax, [_skinh] mov [esp+20h], eax ret @@: dec ebx jnz @f call acquire_shared mov eax, [shared_data] mov ecx, [eax+shared_data_struc.workarea_right] mov [esp+20h], ecx mov ecx, [eax+shared_data_struc.workarea_left] mov [esp+22h], cx mov ecx, [eax+shared_data_struc.workarea_bottom] mov [esp+14h], ecx mov ecx, [eax+shared_data_struc.workarea_top] mov [esp+16h], cx call release_shared ret @@: dec ebx jnz @f call acquire_shared mov eax, [shared_data] mov bx, cx mov [eax+shared_data_struc.workarea_right], ebx shr ecx, 10h mov [eax+shared_data_struc.workarea_left], ecx mov bx, dx mov [eax+shared_data_struc.workarea_bottom], ebx shr edx, 10h mov [eax+shared_data_struc.workarea_top], edx call release_shared ret @@: dec ebx jnz not_supported_i40_fn mov eax, dword [margins] mov [esp+20h], eax mov eax, dword [margins+4] mov [esp+14h], eax ret i40_set_window_shape: test ebx, ebx jnz @f mov [ebp+tls.lpShapeData], ecx jmp .common @@: dec ebx jnz not_supported_i40_fn inc ebx shl ebx, cl mov [ebp+tls.scale], ebx .common: cmp [ebp+tls.showwnd], 0 jz .done call set_window_shape .done: ret set_window_shape: mov esi, [ebp+tls.lpShapeData] add esi, [base] movzx ebx, [ebp+tls.y_size] mov eax, ebx inc eax inc eax shl eax, 4 push eax call malloc push eax xchg eax, edi push 20h pop eax stosd ; RGNDATAHEADER.dwSize push 1 pop eax stosd ; .iType xor eax, eax stosd ; .nCount stosd ; .nRgnSize stosd ; RGNDATAHEADER.rcBound.left stosd ; .top movzx eax, [ebp+tls.x_size] stosd ; .right movzx eax, [ebp+tls.y_size] stosd ; .bottom xor edx, edx ; edx=number of rects, ebp=allocated number of rects xor ecx, ecx .yloop: push ecx xor ecx, ecx .1: lodsb cmp al, 0 jnz .2 add ecx, [ebp+tls.scale] cmp cx, [ebp+tls.x_size] jae .3 jmp .1 .2: inc edx cmp edx, ebx ja .realloc_rects .realloc_cont: mov [edi], ecx pop eax mov [edi+4], eax push eax add eax, [ebp+tls.scale] mov [edi+12], eax add ecx, [ebp+tls.scale] .4: lodsb cmp al, 0 jz .5 add ecx, [ebp+tls.scale] cmp cx, [ebp+tls.x_size] jb .4 .5: mov [edi+8], ecx add edi, 10h add ecx, [ebp+tls.scale] cmp cx, [ebp+tls.x_size] jb .1 .3: pop ecx add ecx, [ebp+tls.scale] cmp cx, [ebp+tls.y_size] jb .yloop pop edi mov [edi+8], edx push edi inc edx inc edx shl edx, 4 push edx push 0 call [ExtCreateRegion] push 1 push eax push [ebp+tls.hWnd] call [SetWindowRgn] push edi call free ret .realloc_rects: push ecx push edx add ebx, ebx ; multiply size by 2 mov eax, ebx inc eax inc eax shl eax, 4 push eax push dword [esp+10h] push 0 push [hHeap] call [HeapReAlloc] sub edi, [esp+0xC] add edi, eax mov [esp+0xC], eax pop edx pop ecx jmp .realloc_cont i40_create_thread: dec ebx jnz not_supported_i40_fn push ecx push edx push 16 call malloc xchg eax, ebx pop dword [ebx+4] ; esp pop dword [ebx] ; eip push 0 push 0 push 0 push 0 call [CreateEventA] mov [ebx+8], eax mov eax, [ebp+tls.cur_dir] mov [ebx+12], eax push eax push esp push 0 push ebx push KolibriThreadProc push 10000h push 0 call [CreateThread] pop ecx test eax, eax jnz @f or dword [esp+20h], -1 ret @@: push eax call [CloseHandle] push -1 push dword [ebx+8] call [WaitForSingleObject] push dword [ebx+8] call [CloseHandle] mov esi, [ebx] push ebx call free ; esi = slot; get PID call acquire_shared xchg eax, esi call get_slot_ptr mov eax, [edi] mov dword [esp+20h], eax push edi call get_cur_slot_ptr lea esi, [edi+24] pop edi add edi, 24 movsd movsd movsd movsd call release_shared ret KolibriThreadProc: mov ebp, [tls_index] mov eax, [fs:2Ch] mov ebp, [eax+ebp*4] mov ebx, [esp+4] mov ecx, [ebx] mov edx, [ebx+4] mov [ebp+tls._cs], cs mov [ebp+tls._ds], ds mov [ebp+tls._fs], fs mov [ebp+tls._esp], edx mov [ebp+tls._eip], ecx mov esi, [ebx+12] push esi call [lstrlenA] inc eax push eax push eax call malloc pop ecx mov [ebp+tls.cur_dir], eax mov edi, eax rep movsb lock inc [NumThreads] call acquire_shared server_new_thread: div edx call release_shared mov [ebp+tls.cur_slot], ecx mov [ebx], ecx push dword [ebx+8] call [SetEvent] xor ebx, ebx push ebx push 400000h push ebx push ebx mov eax, 80000000h push eax push eax push eax push eax push eax push [process_name] push classname push ebx call [CreateWindowExA] mov [ebp+tls.hWnd], eax mov [ebp+tls.bActive], 1 mov [ebp+tls.bFirstMouseMove], 1 call acquire_shared call get_cur_slot_ptr mov [edi+shared_data_struc.hWnd-shared_data_struc.threads], eax call release_shared xor eax, eax xor ecx, ecx xor edx, edx xor esi, esi xor edi, edi push 202h pushad and dword [esp+8], 0 jmp i40_done ; initialize_winsock: ; push ecx edx ; cmp [WinSockDLL], -1 ; jz .failed_ret ; cmp [WinSockDLL], 0 ; jnz .ok ; push winsock_name ; call [LoadLibraryA] ; mov [WinSockDLL], eax ; test eax, eax ; jz .failed ; push esi ; mov esi, winsock_imports ; .import: ; lodsd ; test eax, eax ; jz .importok ; push eax ; push [WinSockDLL] ; call [GetProcAddress] ; mov [esi-4], eax ; test eax, eax ; jnz .import ; pop esi ; jmp .failed ; .importok: ; sub esp, 190h ; push esp ; push 101h ; call [WSAStartup] ; add esp, 190h ; test eax, eax ; jz .ok ; .failed: ; or [WinSockDLL], -1 ; push 10h ; push 0 ; push aWinsockInitErr ; push 0 ; call [MessageBoxA] ; .failed_ret: ; stc ; .ok: ; pop edx ecx ; ret ; i40_socket: ; call initialize_winsock ; jnc @f ; or dword [esp+20h], -1 ; ret ; @@: ; cmp ebx, 9 ; jnz not_supported_i40_fn ; .is_localport_unused: ; mov esi, ecx ; ; destroy old tcp socket ; mov eax, [ebp+tls.cursocket] ; test eax, eax ; jz @f ; dec eax ; push eax ; call [closesocket] ; @@: ; xor ebx, ebx ; mov [ebp+tls.curport], bx ; ; create new tcp socket ; push ebx ; protocol - unspecified ; push 1 ; SOCK_STREAM aka TCP ; push 2 ; AF_INET ; call [socket] ; inc eax ; mov [ebp+tls.cursocket], eax ; jnz @f ; push 10h ; push ebx ; push aSocketErr ; push ebx ; call [MessageBoxA] ; mov dword [esp+20h], ebx ; ret ; @@: ; push ebx ; push ebx ; sockaddr_in.sin_zero ; push 0x0100007F ; sockaddr_in.sin_addr = 127.0.0.1 ; shl esi, 16 ; inc esi ; inc esi ; sockaddr_in.sin_family = 2 = AF_INET ; push esi ; sockaddr_in.sin_port ; mov ecx, esp ; push 10h ; namelen ; push ecx ; name ; dec eax ; push eax ; s ; call [bind] i40_sound_interface: cmp ebx, 55 jnz not_supported_i40_fn mov eax, [shared_data] cmp [eax+shared_data_struc.sound_flag], 0 jz @f ret @@: ; prepare wave-block push 800h call malloc push eax lea ebx, [eax+800h] xchg eax, edi push esi mov esi, wave_block_begin mov ecx, wbb_size/4 rep movsd stosd pop esi add esi, [base] .mainloop: lodsb test al, al jz .done cmp al, 81h jae .note movzx edx, al xor eax, eax lodsw jmp .doit .note: sub al, 81h movzx edx, al lodsb cmp al, 0xFF jz .pause mov cl, al and eax, 0xF movzx eax, word [kontrOctave+eax+eax] shr cl, 4 shr eax, cl .doit: ; eax=divider (freq=1193180/divider), edx=time (in 1/100 sec) mov ecx, edx mul [wave_r] div [_1193180] push eax mov eax, ecx mul [wave_r] div [_100] mov ecx, eax pop edx .doit2: ; ecx=number of bytes required for this note lea eax, [edi+ecx] cmp eax, ebx ja .realloc ; mov al, 0xFF ; cmp edx, ecx ; jbe @f ; mov al, 0 ; this is for pause ;@@: mov al, 80h ; if edx is zero, make it 1 cmp edx, 1 adc edx, 0 .writeloop: push ecx cmp ecx, edx jb @f mov ecx, edx @@: rep stosb pop ecx xor al, [sound_vol] sub ecx, edx ja .writeloop jmp .mainloop .pause: mov eax, edx mul [wave_r] div [_100] mov ecx, eax mov edx, eax inc edx jmp .doit2 .realloc: pop eax sub ebx, eax add ebx, ebx ; ebx=new size sub edi, eax ; edi=delta push ecx edx push ebx push eax push 0 push [hHeap] call [HeapReAlloc] pop edx ecx push eax add ebx, eax add edi, eax jmp .doit2 .done: pop ebx sub edi, ebx sub edi, 8 mov [ebx+4], edi sub edi, 24h mov [ebx+28h], edi ; because we use asynchronous call of PlaySoundA, we can not free used memory, ; but we can free previous wave-block push 0 push 0 push 0 call [PlaySoundA] ; force previous sound terminate push 5 ; SND_ASYNC|SND_MEMORY push 0 push ebx call [PlaySoundA] xchg ebx, [ebp+tls.prev_snd_block] test ebx, ebx jz @f push ebx call free @@: and dword [esp+20h], 0 ret i40_file_system: add ebx, [base] lea esi, [ebx+0x14] cmp dword [ebx], 0 jnz not_supported_i40_fn emul_read_file: ; read 0 bytes - OK cmp dword [ebx+8], 0 jnz @f and dword [esp+20h], 0 ret @@: ; check for root dir cmp byte [esi], 0 jz .root cmp byte [esi+1], 0 jnz .noroot .root: mov esi, dir0 mov edi, [ebx+12] add edi, [base] mov ecx, 12 push ecx rep movsb add edi, 32-12 pop ecx rep movsb and dword [esp+20h], 0 ; eax=0: read ok mov dword [esp+14h], 64 ; ebx=size ret .noroot: sub esp, 200h call convert_path jc emul_path_err dec eax jz .ramdisk sub al, 3 jae .harddisk add esp, 200h jmp not_supported_i40_fn .ramdisk: lodsb cmp al, 0 jz .give_dir1 ; must be {/RD | /RAMDISK}{/1 | /FIRST}/... lodsw cmp ax, '1\' jz .ramdisk_ok cmp ax, '1' jz .ramdisk_readdir cmp ax, 'FI' jnz emul_path_err lodsd cmp eax, 'RST\' jz .ramdisk_ok cmp eax, 'RST' jnz emul_path_err .ramdisk_readdir: add esp, 200h mov esi, ramdisk_path push 0 ; read /rd/1 call read_directory mov [esp+20h], eax mov [esp+14h], ebx ret .ramdisk_ok: ; now esi points to filename, relative from ramdisk sub esp, 200h mov edi, esp push ramdisk_path .doit1: push edi call [lstrcpyA] cmp byte [esi], 0 setz al push eax push esi push edi call [lstrcatA] pop eax lea esi, [esp+200h] xchg esi, edi mov ecx, 200h/4 rep movsd add esp, 200h mov esi, esp ; now esi contains full Win32 name of requested file push eax push esi call [GetFileAttributesA] inc eax pop ecx jz emul_filenotfound dec eax test al, 10h ; FILE_ATTRIBUTE_DIRECTORY jnz .read_dir push 0 push 0 push 3 push 0 push 1 push 80000000h push esi call [CreateFileA] inc eax jz emul_filenotfound dec eax xchg eax, esi mov eax, [ebx+4] xor edx, edx shld edx, eax, 9 shl eax, 9 push edx mov edi, esp push 0 push edi push eax push esi call [SetFilePointer] push 0 push edi mov eax, [ebx+8] shl eax, 9 ; check limits mov ecx, [limit] inc ecx sub ecx, [ebx+0xC] cmp eax, ecx jbe @f mov eax, ecx @@: push eax mov eax, [ebx+0xC] add eax, [base] push eax push esi call [ReadFile] pop eax push 0 push esi call [GetFileSize] add esp, 200h mov [esp+14h], eax push esi call [CloseHandle] and dword [esp+20h], 0 ret .read_dir: inc ecx push ecx ; 2 for exclude '..', 1 for all call read_directory add esp, 200h mov [esp+20h], eax mov [esp+14h], ebx ret .harddisk: movzx edx, al lodsb test al, al jnz @f add esp, 200h mov dword [esp+20h], 10 ; access denied ret @@: xor ecx, ecx ; partition @@: lodsb cmp al, '\' jz @f cmp al, 0 jz @f sub al, '0' cmp al, 9 ja emul_path_err imul ecx, 10 add cl, al jmp @b @@: test al, al jnz @f dec esi @@: test ecx, ecx jz emul_path_err cmp ecx, [hd_partitions_num+edx*4] jbe @f add esp, 200h mov dword [esp+20h], 4 ; partition not defined ret @@: sub esp, 200h mov edi, esp mov eax, [hd_partitions_array+edx*4] dec ecx shl ecx, 9 add eax, ecx push eax jmp .doit1 .give_dir1: add esp, 200h mov esi, dir1 mov edi, [ebx+12] add edi, [base] mov ecx, 12 push ecx rep movsb and dword [esp+20h], 0 ; eax=0: read ok mov dword [esp+14h], 32 ; ebx=size ret emul_path_err: push 0 push aWarning push aPathIsInvalid push 0 call [MessageBoxA] emul_filenotfound: add esp, 200h mov dword [esp+20h], 5 ; file not found cmp dword [ebx], 10h jnz @f neg dword [esp+20h] @@: ret aWarning db 'Warning',0 aPathIsInvalid db 'Requested path is invalid',0 convert_path: lea edi, [esp+4] push ebx lea ebx, [edi + 511] .1: lodsb cmp al, '/' jz .1 dec esi mov ecx, 11 sub ebx, ecx cmp edi, ebx ja .5 mov edx, edi mov al, ' ' add ebx, ecx rep stosb mov edi, edx .2: lodsb cmp al, '/' jz .3 cmp al, '.' jz .4 cmp al, 0 jz .3 cmp edi, ebx jae .5 cmp al, 'a' jb @f cmp al, 'z' ja @f sub al, ' ' @@: stosb jmp .2 .4: lea edi, [edx+8] jmp .2 .3: lea edi, [edx+7] mov ecx, 8 std mov al, ' ' repz scasb cld jz .5 mov ecx, [edx+8] mov [edi+3], ecx mov byte [edi+2], '.' add edi, 5 mov ecx, 3 std repz scasb cld jz @f inc edi inc edi @@: mov al, '\' stosb cmp byte [esi-1], 0 jnz .1 mov byte [edi-1], 0 mov esi, path_begin xor eax, eax xor ecx, ecx .6: add esi, ecx lodsb test al, al jz .5 xchg eax, ecx lodsb xchg ecx, eax lea edi, [esp+8] repz cmpsb jnz .6 cmp byte [edi], 0 jz .7 cmp byte [edi], '\' jnz .6 .7: mov esi, edi pop ebx push eax push esi push esi call [OemToCharA] pop eax ; convert /hd to /hdx cmp al, 3 jnz @f mov eax, [shared_data] movzx eax, [eax+shared_data_struc.hd_base] add eax, 3 @@: clc ret .5: stc pop ebx ret read_directory: ; in: ebx->fileinfo block, esi->mask ; byte [esp+4] = 0 for /rd/1, 1 for normal call, 2 for exclude '..' ; out: eax,ebx according to kernel fn58 read /rd/1 ; note that all returned values have been taken from kernel code mov ecx, [ebx+8] ; number of blocks mov edi, [ebx+12] ; output memory add edi, [base] mov ebx, [ebx+4] ; start block ; /rd/1 = 14 clusters cmp byte [esp+4], 0 jnz .ok2 cmp ebx, 14 ; 14 clusters = root dir jae .err1 cmp ecx, 14 jbe .ok1 .err1: mov eax, 5 ; out of range or ebx, -1 ret 4 .ok1: lea edx, [ebx+ecx] cmp edx, 14 pushfd jbe @f sub edx, 14 sub ecx, edx jz .doret2 @@: popfd .ok2: pushfd shl ebx, 9 shl ecx, 9 xor edx, edx sub esp, 200h pushad lea edi, [esp+20h] push esi call [lstrlenA] mov ecx, eax rep movsb mov al, '\' cmp [edi-1], al jz @f stosb @@: mov eax, '*.*' stosd popad push 0 sub esp, 400h .loop: mov esi, esp push ecx lea eax, [esi+404h] call get_next_file ; if no file => zero record test eax, eax jnz .still push edi mov edi, esi mov ecx, 0x20/4 rep stosd pop edi mov al, 0x20 add [esi+400h], eax .still: pop ecx cmp byte [esp+60Ch], 1 jz @f cmp word [esi], '..' jz .loop @@: push ecx cmp ebx, eax jae .skip add esi, ebx mov ecx, eax sub ecx, ebx cmp ecx, [esp] jb @f mov ecx, [esp] @@: sub [esp], ecx rep movsb .skip: sub ebx, eax jae @f xor ebx, ebx @@: pop ecx test ecx, ecx jnz .loop call done_find_file .doret: add esp, 400h pop ecx add esp, 200h .doret2: xor ebx, ebx xor eax, eax cmp byte [esp+8], 0 jz .check_rd1 popfd ; cmp edx, -1 ; jz .eof cmp ecx, 0x200 jae .eof jmp .ret .check_rd1: popfd jb .ret .eof: mov al, 6 ; EOF .ret: ret 4 get_next_file: ; in: eax=mask, edx=hFindData, edx=0 or edx=-1, esi->buffer ; out: buffer filled, eax=length cmp edx, -1 jnz @f xor eax, eax ret @@: sub esp, 0x140 ; sizeof(WIN32_FIND_DATA) pushad lea ecx, [esp+0x20] push ecx test edx, edx jnz .inited push eax call [FindFirstFileA] mov edx, eax mov [esp+0x14], edx inc eax jmp .cmn .inited: push edx call [FindNextFileA] mov edx, [esp+0x14] .cmn: test eax, eax jnz .ok cmp edx, -1 jz @f push edx call [FindClose] @@: popad add esp, 0x140 xor eax, eax or edx, -1 ret .ok: popad ; Long File Names are not supported yet ; file name push edi lea edi, [esp+4+0x130] ; WIN32_FIND_DATA.cAlternateFileName cmp byte [edi], 0 jnz .shortname push esi lea esi, [esp+8+0x2C] ; WIN32_FIND_DATA.cFileName push edi .l2s: lodsb cmp al, 'a' jb @f cmp al, 'z' ja @f sub al, 0x20 @@: stosb cmp al, 0 jnz .l2s pop edi esi .shortname: pushad push edi push edi call [CharToOemA] popad ; file name mov ecx, 10 @@: mov byte [esi+ecx], ' ' dec ecx jns @b inc ecx @@: cmp byte [edi], '.' jnz @f inc edi mov byte [esi+ecx], '.' inc ecx jmp @b @@: mov al, [edi] inc edi cmp al, 0 jz .namedone cmp al, '.' jz .dot mov [esi+ecx], al inc ecx jmp @b .dot: mov cl, 8 jmp @b .namedone: pop edi ; attributes mov eax, [esp] ; WIN32_FIND_DATA.dwFileAttributes and al, 0x3F mov [esi+11], al and word [esi+12], 0 ; creation file and date pushad lea eax, [esi+14] push eax inc eax inc eax push eax lea eax, [esp+8+20h+4] push eax call [FileTimeToDosDateTime] ; last access date lea eax, [esp+1Ch] push eax lea eax, [esi+18] push eax lea eax, [esp+8+20h+0xC] push eax call [FileTimeToDosDateTime] ; high word of cluster and word [esi+20], 0 ; last write file and date lea eax, [esi+22] push eax inc eax inc eax push eax lea eax, [esp+8+20h+0x14] push eax call [FileTimeToDosDateTime] ; low word of cluster mov word [esi+26], 0xBAD ; random value ; file size popad mov eax, [esp+0x20] mov [esi+28], eax ; return add esp, 0x140 mov eax, 0x20 ret done_find_file: test edx, edx jz .ret cmp edx, -1 jz .ret push edx push edx call [FindClose] pop edx .ret: ret notify_run_prg: test esi, esi jz @f add esi, [base] @@: call acquire_shared push eax esi edi mov esi, [ebp+tls.cur_dir] mov edi, process_curdir @@: lodsb stosb test al, al jz @f cmp edi, process_curdir+4096 jb @b mov byte [edi-1], 0 @@: pop edi esi eax server_run_prg: div edx call release_shared push ecx push -1 push ecx call [WaitForSingleObject] call [CloseHandle] server_get_run_result: div edx jecxz .ret push eax ecx edx push 24 call malloc mov [eax+16], esi mov [eax+20], edi mov esi, [ebp + tls.debuggees] mov [eax], esi mov [ebp + tls.debuggees], eax pop dword [eax+12] pop dword [eax+8] pop dword [eax+4] mov eax, [eax+4] .ret: ret i40_ipc: dec ebx jnz @f ; set IPC memory call acquire_shared call get_cur_slot_ptr add ecx, [base] mov [edi+4], ecx mov [edi+8], edx call release_shared and dword [esp+20h], 0 ret @@: dec ebx jnz not_supported_i40_fn add edx, [base] call acquire_shared server_send_ipc: div edx call release_shared test eax, eax jnz @f push 0 push 0 push 400h ; WM_USER push ecx call [PostMessageA] xor eax, eax @@: mov [esp+20h], eax ret i40_direct_scr_access: cmp [ColorDepth], 0 jnz @f push 10h push 0 push DSADisabled push 0 call [MessageBoxA] jmp i40_terminate @@: dec ebx jz .1 dec ebx jz .2 dec ebx jz .3 jmp not_supported_i40_fn .1: call get_screen_size add ebx, 10001h mov [esp+20h], ebx ret .2: mov eax, [ColorDepth] mov [esp+20h], eax ret .3: call get_screen_size shr ebx, 16 lea eax, [ebx+1] mul [ColorDepth] shr eax, 3 add eax, 3 and eax, not 3 mov [esp+20h], eax ret i40_pci: mov eax, [shared_data] cmp [eax+shared_data_struc.pci_access_enabled], 0 jnz @f .reterr: or dword [esp+20h], -1 ; PCI access disabled ret @@: cmp bl, 2 ja .noinit cmp [eax+shared_data_struc.pci_data_init], 0 jnz @f push eax ebx call pci_data_init pop ebx eax @@: test bl, bl jnz .not0 xor ecx, ecx cmp [eax+shared_data_struc.pci_data_init], 1 jnz .unsupp0 ; emulate "unsupported" behavior mov ch, [eax+shared_data_struc.pci_bios_mj] mov cl, [eax+shared_data_struc.pci_bios_mn] .unsupp0: mov [esp+20h], ecx ret .not0: dec bl mov ecx, ebx jnz .not1 cmp [eax+shared_data_struc.pci_data_init], 1 jnz .unsupp1 mov cl, [eax+shared_data_struc.pci_bios_lb] .unsupp1: .retecx: mov [esp+20h], ecx ret .not1: test [eax+shared_data_struc.pci_bios_pc], 1 jnz @b test [eax+shared_data_struc.pci_bios_pc], 2 jz @b inc ecx jmp @b .noinit: sub bl, 4 cmp bl, 2 ja not_supported_i40_fn cmp [bIs9x], 0 jz .read_nt mov ah, 0xB1 mov al, bl add al, 8 mov bl, ch movzx di, cl mov ecx, ebx call [jmp_temp_int1A] jc .reterr jmp .retecx .read_nt: push cx push bx mov eax, esp push ecx mov ecx, esp push 4 push ecx push 4 push eax push 0x222004 call send_driver_request pop ecx edx test eax, eax jnz .retecx push 30h push aWarning push DrvOpenErr push 0 call [MessageBoxA] jmp .reterr pci_data_init: call acquire_shared cmp [bIs9x], 0 jz .nt ; On 9x systems, just do "int 1Ah" from 16-bit code mov ax, 0xB101 call [jmp_temp_int1A] test ah, ah jnz .err cmp edx, 'PCI ' jnz .err mov edx, [shared_data] mov [edx+shared_data_struc.pci_bios_mj], bh mov [edx+shared_data_struc.pci_bios_mn], bl mov [edx+shared_data_struc.pci_bios_lb], cl mov [edx+shared_data_struc.pci_bios_pc], al mov [edx+shared_data_struc.pci_data_init], 1 jmp .ok .nt: ; On NT systems, there is 'HKLM\HARDWARE\DESCRIPTION\System\MultifunctionAdapter' key, ; with some subkeys '0','1',..., which hold information on periphery. ; Each PCI bus has its own subkey with 'Identifier'="PCI". ; For first PCI bus 'Configuration Data' holds 4 additional bytes = info on PCI BIOS. .loop: push eax push esp ; phkResult push 1 ; samDesired = KEY_QUERY_VALUE push 0 ; ulOptions push keymfa ; lpSubKey push 80000002h ; hKey = HKEY_LOCAL_MACHINE call [RegOpenKeyExA] pop esi ; key handle test eax, eax jnz .err ; subkeys are done, and we do not find required push eax mov eax, esp push 4 push esp ; lpcbData push eax ; lpData push 0 ; lpType push 0 ; lpReserved push aIdentifier ; lpValueName push esi ; hKey call [RegQueryValueExA] pop ecx pop edx test eax, eax jnz .cont cmp ecx, 4 jnz .cont cmp edx, 'PCI' jnz .cont sub esp, 24h mov eax, esp push 24h push esp push eax push 0 push 0 push aConfigurationData push esi call [RegQueryValueExA] pop ecx test eax, eax jnz .err3 cmp ecx, 24h jnz .err3 mov eax, [shared_data] add esp, 20h pop dword [eax+shared_data_struc.pci_bios_mj] dec [eax+shared_data_struc.pci_bios_lb] js .err2 mov [eax+shared_data_struc.pci_data_init], 1 push esi call [RegCloseKey] .ok: call release_shared ret .cont: push esi call [RegCloseKey] inc [idxmfa] cmp [idxmfa], '9' jbe .loop jmp .err .err3: add esp, 24h .err2: push esi call [RegCloseKey] .err: mov eax, [shared_data] mov [eax+shared_data_struc.pci_data_init], 2 call release_shared push 40h push 0 push aCannotGetPci push 0 call [MessageBoxA] ret i40_debug_board: dec ebx jz .write dec ebx jnz not_supported_i40_fn .read: call acquire_shared mov eax, [shared_data] mov ecx, [eax+shared_data_struc.msg_board_count] test ecx, ecx jnz @f mov [esp+20h], ecx ; zero eax mov [esp+14h], ecx ; zero ebx jmp .ret @@: dec [eax+shared_data_struc.msg_board_count] lea edi, [eax+shared_data_struc.msg_board_data] lea esi, [edi+1] movzx edx, byte [edi] mov [esp+20h], edx mov dword [esp+14h], 1 dec ecx rep movsb .ret: jmp release_shared .write: call acquire_shared mov eax, [shared_data] mov edx, [eax+shared_data_struc.msg_board_count] mov [eax+shared_data_struc.msg_board_data+edx], cl inc edx and edx, 511 mov [eax+shared_data_struc.msg_board_count], edx jmp .ret i40_resize_app_memory: dec ebx jnz not_supported_i40_fn cmp [heap_status], 0 jz @f push 30h push aWarning push aInvFn64Call push 0 call [MessageBoxA] mov dword [esp+20h], 1 ret @@: cmp [NumThreads], 1 jnz not_supported_i40_fn push ecx push 40h ; PAGE_EXECUTE_READWRITE push 1000h ; MEM_COMMIT push ecx push 0 call [VirtualAlloc] pop ecx test eax, eax jnz .ok mov dword [esp+0x20], 1 ret .ok: mov edi, eax mov esi, [base] push ecx cmp ecx, [limit] jbe @f mov ecx, [limit] inc ecx @@: push eax rep movsb call acquire_shared call get_cur_slot_ptr mov ecx, [edi+4] jecxz @f sub ecx, [base] add ecx, [esp] mov [edi+4], ecx @@: call release_shared push 8000h ; MEM_RELEASE push 0 push [base] call [VirtualFree] pop eax pop ecx mov [base], eax dec ecx mov [limit], ecx mov [fn9limit], ecx call get_cur_slot_ptr mov [edi+24], ecx mov esi, selector_data mov [esi+2], ax shr eax, 10h mov [esi+4], al mov [esi+7], ah shr ecx, 0Ch mov [esi], cx shr ecx, 10h or cl, 11000000b mov [esi+6], cl mov byte [esi+5], 11110010b lea edi, [esi+8] movsd movsd mov byte [esi+5], 11111010b cmp [bIs9x], 0 jnz .9x push dword [esi-4] push dword [esi-8] push 17h push dword [esi+4] push dword [esi] push 0Fh call [NtSetLdtEntries] mov esi, ldterr test eax, eax js fail .d: and dword [esp+20h], 0 ret .9x: mov eax, sl0p call CallRing0 jmp .d convert_2bpp: mov esi, edi add esi, [base] movzx eax, word [esp] pushad add ecx, 7 shr ecx, 1 and ecx, not 3 mul ecx push eax call malloc mov [esp+1Ch], eax popad push eax edx esi mov edi, eax movzx eax, word [esp+12] mov esi, ebx .extloop: push eax push ecx .innloop: lodsb mov dl, al push eax shr al, 6 shr dl, 4 shl al, 4 and dl, 3 or al, dl stosb pop eax mov dl, al shl al, 2 and dl, 3 and al, 0x30 or al, dl stosb sub ecx, 4 ja .innloop test edi, 3 jz @f stosw @@: pop ecx pop eax add esi, [esp+16+0Ch] dec eax jnz .extloop pop esi edx edi jmp pad_cont8 pad_bmp8: movzx eax, word [esp] pushad add ecx, 3 and ecx, not 3 mul ecx push eax call malloc mov [esp+1Ch], eax popad push eax esi mov edi, eax movzx eax, word [esp+8] mov esi, ebx .extloop: push eax push ecx mov eax, ecx shr ecx, 2 rep movsd mov ecx, eax and ecx, 3 rep movsb mov ecx, eax neg ecx and ecx, 3 mov al, 0 rep stosb pop ecx pop eax add esi, [esp+4*3+0Ch] dec eax jnz .extloop pop esi edi jmp pad_cont8 i40_putimage_palette: add ebx, [base] push ecx shr ecx, 16 cmp esi, 1 jz .1 cmp esi, 4 jz .4 cmp esi, 8 jz .8 cmp esi, 15 jz .15 cmp esi, 16 jz .16 cmp esi, 32 jz .32 cmp esi, 2 jz convert_2bpp cmp esi, 24 jz .24 pop ecx jmp not_supported_i40_fn .24: lea ecx, [ecx*3] jmp @f .1: add ecx, 7 shr ecx, 3 jmp @f .2: add ecx, 3 shr ecx, 2 jmp @f .4: inc ecx shr ecx, 1 jmp @f .32: add ecx, ecx .15: .16: add ecx, ecx .8: @@: add edi, [base] mov esi, edi ; Windows requires that all scanlines are DWORD-padded mov edi, ebx test cl, 3 jnz pad_bmp8 cmp dword [esp+10h], 0 jnz pad_bmp8 pad_cont8: pop ecx mov eax, [esp+8] ; palette sub esp, 256*4 push ecx edi lea edi, [esp+8] cmp al, 8 jnz @f mov ecx, 256 rep movsd @@: cmp al, 4 jnz @f mov ecx, 16 rep movsd @@: cmp al, 2 jnz @f movsd movsd movsd movsd add eax, eax @@: cmp al, 1 jnz @f movsd movsd @@: cmp al, 16 jnz @f mov dword [edi+0], 0xF800 mov dword [edi+4], 0x07E0 mov dword [edi+8], 0x001F @@: pop edi ecx xor esi, esi ; BITMAPINFO push esi ; biClrImportant push esi ; biClrUsed push esi ; biYPelsPerMeter push esi ; biXPelsPerMeter push esi ; biSizeImage cmp al, 15 jnz .no15 push esi ; biCompression push 100001h ; biPlanes, biBitCount jmp @f .no15: cmp al, 16 jnz .no16 push 3 ; biCompression push 100001h ; biPlanes, biBitCount jmp @f .no16: push esi ; biCompression ; push 80001h ; biPlanes, biBitCount shl eax, 16 inc eax push eax ; biPlanes, biBitCount @@: movzx eax, cx neg eax push eax ; biHeight neg eax shr ecx, 10h push ecx ; biWidth push 40 ; biSize push ebx lea ebx, [esp+4] ; SetDIBitsToDevice push esi ; fuColorUse = DIB_RGB_COLORS push ebx ; lpbmi push edi ; lpvBits push eax ; cScanLines dec eax push eax ; uStartScan push eax ; YSrc inc eax push esi ; XSrc push eax ; dwHeight push ecx ; dwWidth movzx ecx, dx add ecx, [ebp+tls.client_top] push ecx ; YDest shr edx, 10h add edx, [ebp+tls.client_left] push edx ; XDest push [ebp+tls.hWnd] call [GetDC] xchg eax, ebx push ebx ; hdc call [SetDIBitsToDevice] xchg eax, ebx pop ebx add esp, 40+256*4 push eax push [ebp+tls.hWnd] call [ReleaseDC] cmp edi, ebx jz @f push edi call free @@: ret i40_process_def: dec ebx jz .setmode dec ebx jz .getmode dec ebx jz .get_control dec ebx jz .add_hotkey dec ebx jz .del_hotkey jmp not_supported_i40_fn .setmode: mov [ebp+tls.usescancode], cl ret .getmode: movzx eax, [ebp+tls.usescancode] mov [esp+20h], eax ret .get_control: mov esi, .vkeycodes mov edi, 1 .gcloop: xor eax, eax lodsb push eax call [GetAsyncKeyState] test ax, ax jns @f or ebx, edi @@: add edi, edi cmp esi, .vkeycodes_end jb .gcloop mov [esp+20h], ebx ret .add_hotkey: .del_hotkey: and dword [esp+20h], 0 ret .vkeycodes: db 0xA0 ; VK_LSHIFT db 0xA1 ; VK_RSHIFT db 0xA2 ; VK_LCONTROL db 0xA3 ; VK_RCONTROL db 0xA4 ; VK_LMENU db 0xA5 ; VK_RMENU db 0x14 ; VK_CAPITAL db 0x90 ; VK_NUMLOCK db 0x91 ; VK_SCROLL .vkeycodes_end: i40_move_resize: cmp ebx, -1 jnz @f movzx ebx, [ebp+tls.x_start] @@: cmp ecx, -1 jnz @f movzx ecx, [ebp+tls.y_start] @@: cmp edx, -1 jnz @f movzx edx, [ebp+tls.x_size] dec edx @@: cmp esi, -1 jnz @f movzx esi, [ebp+tls.y_size] dec esi @@: inc edx mov [ebp+tls.x_start], bx inc esi mov [ebp+tls.y_start], cx mov [ebp+tls.x_size], dx mov [ebp+tls.y_size], si push 1 push esi push edx push ecx push ebx push [ebp+tls.hWnd] call [MoveWindow] push 0 push 0 push [ebp+tls.hWnd] call [InvalidateRect] ret i40_sys_services: cmp ebx, 3 jnz .not3 mov esi, [shared_data] cmp [esi+shared_data_struc.bAllowReadMSR], 0 mov edi, aReadMSRDisabled jz .err cmp [bIs9x], 0 jz .nt mov ecx, edx mov eax, rdmsrp call CallRing0 test ebx, ebx jnz .nomsr mov [esp+20h], eax mov [esp+14h], edx ret .nt: push 0 push edx push edx mov eax, esp push 9 push eax push 4 push eax push 0x222000 call send_driver_request pop ecx pop edx pop esi mov edi, DrvOpenErr test eax, eax jz .err test esi, esi jnz .nomsr mov [esp+20h], ecx mov [esp+14h], edx ret .err: push 30h push aWarning push edi push 0 call [MessageBoxA] and dword [esp+20h], 0 and dword [esp+14h], 0 ret .nomsr: push 10h push 0 push aNoMsr push 0 call [MessageBoxA] jmp i40_terminate .not3: cmp ebx, 11 jnz .not11 .initialize_heap: ; initialize heap cmp [heap_status], 0 jz .create_heap @@: cmp [heap_status], 1 jnz @f push 5 call [Sleep] jmp @b @@: .heap_ret_size: mov eax, 0x5FC00000-0x1000 sub eax, [heap_start] mov [esp+20h], eax ret .create_heap: cmp [NumThreads], 1 jnz not_supported_i40_fn mov [heap_status], 1 xor ebx, ebx ; reserve needed big region mov esi, 0x40000000 @@: push 40h ; PAGE_EXECUTE_READWRITE push 2000h ; MEM_RESERVE push esi push ebx call [VirtualAlloc] test eax, eax jnz @f shr esi, 1 cmp esi, 0x01000000 jae @b .nomem_fatal: xor ebx, ebx mov esi, memerr jmp fail @@: mov [heap_region_size], esi push eax mov ecx, [limit] inc ecx push 40h ; PAGE_EXECUTE_READWRITE push 1000h ; MEM_COMMIT push ecx push eax call [VirtualAlloc] test eax, eax jz .nomem_fatal mov esi, [base] pop edi push edi mov edi, eax mov ecx, [limit] inc ecx rep movsb push 8000h ; MEM_RELEASE push ebx push [base] call [VirtualFree] pop eax mov [base], eax mov ecx, [heap_region_size] dec ecx mov [limit], ecx mov esi, selector_data mov [esi+2], ax shr eax, 10h mov [esi+4], al mov [esi+7], ah shr ecx, 0Ch mov [esi], cx shr ecx, 10h or cl, 11000000b mov [esi+6], cl mov byte [esi+5], 11110010b lea edi, [esi+8] movsd movsd mov byte [esi+5], 11111010b cmp [bIs9x], bl jnz .9x push dword [esi-4] push dword [esi-8] push 17h push dword [esi+4] push dword [esi] push 0Fh call [NtSetLdtEntries] mov esi, ldterr test eax, eax js fail jmp .heap_created .9x: mov eax, sl0p call CallRing0 xor ebx, ebx .heap_created: mov eax, [fn9limit] or eax, 0xFFF inc eax mov [heap_start], eax mov eax, [heap_region_size] sub eax, [heap_start] shr eax, 10 call malloc_big mov [heap_control_block], eax test eax, eax jz .nomem_fatal mov ecx, [heap_region_size] sub ecx, [heap_start] or ecx, 4 mov [eax], ecx push heap_critical_sec call [InitializeCriticalSection] mov [heap_status], 2 jmp .heap_ret_size .not11: cmp ebx, 12 jnz .not12 ; allocate memory block in heap .allocate_heap: cmp [heap_status], 0 jnz @f push 30h push aWarning push aHeapNotInited push 0 call [MessageBoxA] and dword [esp+20h], 0 ret @@: lea edi, [ecx+0x1FFF] and edi, not 0xFFF @@: cmp [heap_status], 1 jnz @f push 5 call [Sleep] jmp @b @@: push heap_critical_sec call [EnterCriticalSection] xor esi, esi mov ecx, [heap_region_size] sub ecx, [heap_start] mov edx, [heap_control_block] .l_0: cmp esi, ecx jae .m_exit mov ebx, esi shr ebx, 12 mov eax, [edx+ebx*4] test al, 4 jz .test_used and eax, not 0xFFF cmp eax, edi jb .m_next jz @f push esi add esi, edi sub eax, edi or al, 4 shr esi, 12 mov [edx+esi*4], eax pop esi mov eax, edi @@: or al, 8 mov [edx+ebx*4], eax mov eax, [heap_start] lea eax, [eax+esi+0x1000] push eax sub edi, 0x1000 ; now do real allocate at eax with size edi push 40h ; PAGE_EXECUTE_READWRITE push 1000h ; MEM_COMMIT push edi add eax, [base] push eax call [VirtualAlloc] test eax, eax jz .nomem_fatal jmp .allocated .m_next: add esi, eax jmp .l_0 .test_used: test al, 8 jnz @f .fail_internal: xor ebx, ebx mov esi, aInternalError jmp fail @@: and eax, not 0xFFF jmp .m_next .m_exit: push 0 .allocated: push heap_critical_sec call [LeaveCriticalSection] cmp dword [esp], 0 jnz @f push 30h push aWarning push aMallocFailed push 0 call [MessageBoxA] @@: pop eax mov [esp+20h], eax ret .not12: cmp ebx, 13 jnz .not13 ; free memory block in heap .free_heap: cmp [heap_status], 0 jnz @f push 30h push aWarning push aHeapNotInited push 0 call [MessageBoxA] and dword [esp+20h], 0 ret @@: test ecx, ecx jnz @f ; free(NULL) is OK mov dword [esp+20h], 1 ret @@: mov esi, ecx cmp [heap_status], 1 jnz @f push 5 call [Sleep] jmp @b @@: cmp esi, [heap_region_size] jae .inv_exit sub esi, [heap_start] jb .inv_exit cmp esi, 0x1000 jae @f .inv_exit: mov dword [esp+20h], 1 .inv_exit_cmn: push 30h push aWarning push aFreeInvalid push 0 call [MessageBoxA] ret .inv_exit_realloc: and dword [esp+20h], 0 jmp .inv_exit_cmn @@: push heap_critical_sec call [EnterCriticalSection] mov eax, esi shr esi, 12 dec esi mov edx, [heap_control_block] test byte [edx+esi*4], 10h jnz .inv_exit_realloc test byte [edx+esi*4], 8 jz .inv_wrn test eax, 0xFFF jz @f .inv_wrn: push edx push 30h push aWarning push aFreeInvalid push 0 call [MessageBoxA] pop edx @@: mov eax, [edx+esi*4] test al, 8 jz .freed push edx and eax, not 0xFFF push 0x4000 ; MEM_DECOMMIT sub eax, 0x1000 push eax lea eax, [esi+1] shl eax, 12 add eax, [heap_start] add eax, [base] push eax call [VirtualFree] pop edx mov eax, [edx+esi*4] and eax, not 0xFFF push eax or al, 4 mov [edx+esi*4], al shr eax, 12 add eax, esi test byte [edx+eax*4], 4 jz @f xor ecx, ecx xchg ecx, [edx+eax*4] and ecx, not 0xFFF add [edx+esi*4], ecx add [esp], ecx @@: pop eax test esi, esi jz .freed xor edi, edi .findprev: cmp edi, esi jz .foundprev mov ecx, edi mov ebx, [edx+ecx*4] shr ebx, 12 add edi, ebx jmp .findprev .foundprev: test byte [edx+ecx*4], 4 jz .freed and dword [edx+esi*4], 0 add [edx+ecx*4], eax .freed: push heap_critical_sec call [LeaveCriticalSection] mov dword [esp+20h], 1 ret .not13: cmp ebx, 16 jnz .not16 add ecx, [base] mov esi, ecx push esi push aSound call [lstrcmpA] test eax, eax jnz @f and dword [esp+20h], 0 ret @@: push esi push aInfinity call [lstrcmpA] test eax, eax jnz @f and dword [esp+20h], 0 ret @@: push 10h push 0 push aUnknownDriver push 0 call [MessageBoxA] and dword [esp+20h], 0 ret .not16: cmp ebx, 19 jnz .not19 ; load DLL sub esp, 40 mov eax, esp sub eax, [base] push 0 push 0 push eax push 0 push 0 push 0 push 5 mov ebx, esp mov [ebx+21], ecx pushad call i40_file_system_lfn.noadd popad test eax, eax jz @f .err1: add esp, 28+40 and dword [esp+20h], 0 ret @@: pop eax push 0 mov ebx, esp cmp dword [ebx+28+36], 0 jnz .err1 mov eax, [ebx+28+32] mov [ebx+12], eax call malloc_big test eax, eax jnz @f .nomem_dll: push 10h push memerr push aCannotLoadDll push 0 call [MessageBoxA] jmp .err1 @@: sub eax, [base] mov [ebx+16], eax push ebx pushad call i40_file_system_lfn.noadd popad pop ebx test eax, eax jnz .err1 mov eax, [ebx+16] add eax, [base] mov [ebx+16], eax cmp dword [eax], 'KPCK' jnz .notpacked mov eax, [eax+4] call malloc_big test eax, eax jnz @f push dword [ebx+16] call free_big jmp .nomem_dll @@: push eax push eax push dword [ebx+16] call unpack push dword [ebx+16] call free_big pop eax mov [ebx+16], eax .notpacked: add esp, 28+40 ; eax contains pointer to loaded file mov ebx, eax ; 1. Calculate image size & allocate memory for image movzx ecx, word [eax+2] lea edx, [eax+20+16] xor esi, esi @@: add esi, [edx] add esi, 0xF and esi, not 0xF add edx, 40 loop @b pushad call .initialize_heap mov ecx, [esp+4] call .allocate_heap popad test eax, eax jnz @f ; no memory in user space, user has already been notified and dword [esp+20h], 0 ret @@: ; eax = base addr in user space ; ebx = pointer to loaded DLL data ; 2. Copy image data mov edi, eax add edi, [base] movzx ecx, word [ebx+2] lea edx, [ebx+20+16] @@: mov [edx+12-16], edi mov esi, [edx+20-16] test esi, esi jnz .copy add edi, [edx+16-16] jmp .next .copy: add esi, ebx push ecx mov ecx, [edx+16-16] rep movsb pop ecx .next: add edi, 0xF and edi, not 0xF add edx, 40 loop @b ; 3. Fixup COFF symbols ; symbols table = ebx + [ebx+8] ; strings ptr = (symbols table)+[ebx+12]*18 mov ecx, [ebx+12] mov edx, ebx add edx, [ebx+8] lea esi, [ecx+ecx*8] lea esi, [edx+esi*2] .fix_sym: movsx edi, word [edx+12] test edi, edi jnz .internal ; current implementation does not support exports ; this is kernel limitation, not my and dword [edx+8], 0 jmp .next_sym .internal: js .next_sym dec edi shl edi, 3 lea edi, [edi+edi*4] mov edi, [ebx+20+edi+12] sub edi, [base] add [edx+8], edi .next_sym: add edx, 18 loop .fix_sym ; 4. Fixup COFF relocations movzx ecx, word [ebx+2] lea esi, [ebx+20] .fix_sec_reloc: mov edi, [esi+24] add edi, ebx push ecx movzx ecx, word [esi+32] jecxz .next_sec_reloc .fix_reloc: mov edx, [edi+4] lea edx, [edx+edx*8] lea edx, [ebx+edx*2] add edx, [ebx+8] mov edx, [edx+8] mov eax, [edi] add eax, [esi+12] cmp word [edi+8], 6 jz .dir32 cmp word [edi+8], 20 jz .rel32 pushad push 30h push aWarning push aUnknownReloc push 0 call [MessageBoxA] popad jmp .next_reloc .rel32: sub edx, eax sub edx, 4 .dir32: add [eax], edx .next_reloc: add edi, 10 loop .fix_reloc .next_sec_reloc: add esi, 40 pop ecx loop .fix_sec_reloc ; 5. Lookup 'EXPORTS' symbol mov eax, ebx add eax, [ebx+8] mov ecx, [ebx+12] .find_exp: cmp dword [eax], 'EXPO' jnz @f cmp dword [eax+4], 'RTS' jz .found_exp @@: add eax, 18 loop .find_exp ; 5b. Lookup '_EXPORTS' symbol mov eax, ebx add eax, [ebx+8] mov ecx, [ebx+12] .find__exp: cmp dword [eax], '_EXP' jnz @f cmp dword [eax+4], 'ORTS' jz .found_exp @@: add eax, 18 loop .find__exp push 30h push aWarning push aExportsNotFound push 0 call [MessageBoxA] xor eax, eax jmp @f .found_exp: mov eax, [eax+8] @@: mov [esp+20h], eax push ebx call free_big ret .not19: cmp ebx, 20 jnz .not20 ; reallocate memory block in heap cmp [heap_status], 0 jnz @f push 30h push aWarning push aHeapNotInited push 0 call [MessageBoxA] and dword [esp+20h], 0 ret @@: cmp [heap_status], 1 jnz @f push ecx edx push 5 call [Sleep] pop edx ecx jmp @b @@: ; realloc(NULL,sz) = malloc(sz) test edx, edx jz .allocate_heap cmp edx, [heap_region_size] jae .inv_exit_realloc sub edx, [heap_start] jb .inv_exit_realloc cmp edx, 0x1000 jb .inv_exit_realloc push ecx edx push heap_critical_sec call [EnterCriticalSection] pop edx ecx test edx, 0xFFF jnz @f shr edx, 12 dec edx mov esi, [heap_control_block] mov eax, [esi+edx*4] test al, 10h jnz @f test al, 8 jnz .realloc_valid @@: push heap_critical_sec call [LeaveCriticalSection] jmp .inv_exit_realloc .realloc_valid: add ecx, 0x1FFF and ecx, not 0xFFF and eax, not 0xFFF cmp eax, ecx jb .realloc_inc jz .realloc_done sub eax, ecx push eax ecx edx push 0x4000 ; MEM_DECOMMIT push eax shl edx, 12 add edx, ecx add edx, [heap_start] add edx, [base] push edx call [VirtualFree] test eax, eax jz $ pop edx ecx mov eax, ecx cmp eax, 0x1000 jz .realloc_freeall or al, 8 mov [esi+edx*4], eax pop eax shr ecx, 12 add edx, ecx mov edi, [heap_region_size] sub edi, [heap_start] shr edi, 12 push edx mov edx, eax shr edx, 12 add edx, [esp] @@: cmp edx, edi jae @f mov ecx, [esi+edx*4] test cl, 4 jz @f and dword [esi+edx*4], 0 and ecx, not 0xFFF add eax, ecx shr ecx, 12 add edx, ecx jmp @b @@: pop edx or al, 4 mov [esi+edx*4], eax .realloc_done: push heap_critical_sec call [LeaveCriticalSection] mov eax, [esp+18h] mov [esp+20h], eax ret .realloc_freeall: pop eax xor ecx, ecx xor eax, eax @@: cmp ecx, edx jae @f mov eax, [esi+ecx*4] shr eax, 12 add ecx, eax jmp @b @@: test eax, eax jz @f sub ecx, eax test byte [esi+ecx*4], 4 jz @f xor eax, eax xchg eax, [esi+edx*4] and eax, not 0xFFF add [esi+ecx*4], eax mov edx, ecx @@: mov eax, [esi+edx*4] shr eax, 12 add eax, edx mov edi, [heap_region_size] sub edi, [heap_start] shr edi, 12 cmp eax, edi jae @f test byte [esi+eax*4], 4 jz @f xor ecx, ecx xchg ecx, [esi+eax*4] and ecx, not 0xFFF add [esi+edx*4], ecx @@: mov byte [esi+edx*4], 4 push heap_critical_sec call [LeaveCriticalSection] and dword [esp+20h], 0 ret .realloc_inc: mov edi, [heap_region_size] sub edi, [heap_start] shr edi, 12 push eax shr eax, 12 add eax, edx cmp eax, edi jae .realloc_realloc mov eax, [esi+eax*4] test al, 4 jz .realloc_realloc and eax, not 0xFFF add eax, [esp] sub eax, ecx jb .realloc_realloc ; reallocate in place jz @f push ecx edx shr ecx, 12 add edx, ecx or al, 4 mov [esi+edx*4], eax pop edx ecx @@: pop eax sub ecx, eax add [esi+edx*4], ecx mov edi, edx inc edi shl edi, 12 add edi, [heap_start] mov [esp+20h], edi push 40h ; PAGE_EXECUTE_READWRITE push 1000h ; MEM_COMMIT push ecx shl edx, 12 add edx, eax add edx, [heap_start] add edx, [base] push edx call [VirtualAlloc] test eax, eax jz .nomem_fatal push heap_critical_sec call [LeaveCriticalSection] ret .realloc_realloc: pop esi push ecx push heap_critical_sec call [LeaveCriticalSection] pop ecx pushad call .allocate_heap popad mov [esp+20h], eax mov edi, eax test edi, edi jnz @f ret @@: lea ecx, [esi-0x1000] mov esi, [esp+18h] push esi add esi, [base] add edi, [base] shr ecx, 2 rep movsd pop ecx pushad call .free_heap popad ret .not20: cmp ebx, 22 jnz .not22 ; open/create named memory area test esi, not 0xD jnz not_supported_i40_fn add ecx, [base] mov edi, ecx ..server_create_shmem: div edx test eax, eax jz @f .shmem.err: and dword [esp+20h], 0 mov [esp+18h], eax ret @@: pushad call .allocate_heap popad test eax, eax jnz @f mov ecx, edi call ..server_destroy_shmem mov al, 30 jmp .shmem.err @@: mov [esp+20h], eax mov [esp+18h], edx mov ecx, eax sub ecx, [heap_start] shr ecx, 12 mov edx, [heap_control_block] or byte [edx+(ecx-1)*4], 10h add eax, [base] ..server_notify_shmem: div edx push eax push esp push 1 ; PAGE_NOACCESS push ecx push eax call [VirtualProtect] pop eax ret .not22: cmp ebx, 23 jnz not_supported_i40_fn add ecx, [base] call ..server_destroy_shmem jecxz @f sub ecx, [base] mov eax, ecx sub eax, [heap_start] shr eax, 12 mov edx, [heap_control_block] and byte [edx+(eax-1)*4], not 10h pushad call .free_heap popad jmp .ret22 @@: push 30h push aWarning push aCannotDestroyShMem push 0 call [MessageBoxA] .ret22: mov dword [esp+20h], 0x87654320 ret ..server_destroy_shmem: div edx ret include 'unpacker.inc' align 4 debug_services_table: dd i40_debug_services.set_event_data dd i40_debug_services.getcontext dd i40_debug_services.setcontext dd not_supported_i40_fn ;i40_debug_services.detach dd i40_debug_services.suspend dd i40_debug_services.resume dd i40_debug_services.read_process_memory dd i40_debug_services.write_process_memory dd i40_debug_services.terminate ; dd i40_debug_services.set_drx .size = ($ - debug_services_table)/4 i40_debug_services: cmp ebx, debug_services_table.size jae not_supported_i40_fn jmp dword [debug_services_table+ebx*4] .set_event_data: call get_cur_slot_ptr ; atomic operation, no synchronization required mov [edi+shared_data_struc.debugger_mem-shared_data_struc.threads], ecx ret .m1pop2: pop eax .m1pop: pop eax .m1: or dword [esp+20h], -1 .ret: ret .getcontext: call find_debuggee test ebx, ebx jz .ret cmp edx, 40 jnz .ret push dword [ebx+12] call suspend_safe sub esp, 0xB2*4 push 1000Fh mov edi, esp push edi push dword [ebx+12] call [GetThreadContext] add esi, [base] mov ax, cs cmp word [edi+0xBC], ax jz .context_win mov eax, [edi+0xB8] mov [esi], eax mov eax, [edi+0xC0] mov [esi+4], eax mov eax, [edi+0xB0] mov [esi+8], eax mov eax, [edi+0xAC] mov [esi+12], eax mov eax, [edi+0xA8] mov [esi+16], eax mov eax, [edi+0xA4] mov [esi+20], eax mov eax, [edi+0xC4] mov [esi+24], eax mov eax, [edi+0xB4] mov [esi+28], eax mov eax, [edi+0xA0] mov [esi+32], eax mov eax, [edi+0x9C] mov [esi+36], eax jmp .gotcontext .context_win: mov eax, [ebx+16] add eax, tls._esp sub esp, 2Ch mov ecx, esp push 0 push esp push 8 push ecx push eax push dword [ebx+8] call [ReadProcessMemory] pop eax pop dword [esi+24] pop dword [esi] mov ecx, esp push 0 push esp push 24h push ecx push dword [ebx+20] push dword [ebx+8] call [ReadProcessMemory] pop eax pop dword [esi+36] pop dword [esi+32] pop dword [esi+28] pop eax pop dword [esi+20] pop dword [esi+16] pop dword [esi+12] pop dword [esi+8] pop dword [esi+4] .gotcontext: add esp, 0xB3*4 @@: push dword [ebx+12] call [ResumeThread] ret .resume: call find_debuggee test ebx, ebx jz .ret jmp @b .suspend: call find_debuggee test ebx, ebx jz .ret push dword [ebx+12] call suspend_safe ret .setcontext: call find_debuggee test ebx, ebx jz .ret cmp edx, 40 jnz .ret push dword [ebx+12] call suspend_safe sub esp, 0xB2*4 push 1000Fh mov edi, esp push edi push dword [ebx+12] call [GetThreadContext] add esi, [base] mov ax, cs cmp word [edi+0xBC], ax jz .context_win_set lodsd mov [edi+0xB8], eax lodsd mov [edi+0xC0], eax lodsd mov [edi+0xB0], eax lodsd mov [edi+0xAC], eax lodsd mov [edi+0xA8], eax lodsd mov [edi+0xA4], eax lodsd mov [edi+0xC4], eax lodsd mov [edi+0xB4], eax lodsd mov [edi+0xA0], eax lodsd mov [edi+0x9C], eax push edi push dword [ebx+12] call [SetThreadContext] jmp .setcontextdone .context_win_set: mov edx, [ebx+16] add edx, tls._esp lodsd push eax push dword [esi-4+24] mov ecx, esp push 0 push esp push 8 push ecx push eax push dword [ebx+8] call [WriteProcessMemory] pop eax pop eax pop eax push 9 pop ecx @@: lodsd push eax loop @b mov ecx, esp push 0 push esp push 24h push ecx push dword [ebx+20] push dword [ebx+8] call [WriteProcessMemory] add esp, 4+24h .setcontextdone: add esp, 0xB3*4 push dword [ebx+12] call [ResumeThread] ret .write_process_memory: push [WriteProcessMemory] jmp @f .read_process_memory: push [ReadProcessMemory] @@: call find_debuggee test ebx, ebx jz .m1pop ; get base and limit of target process push eax push eax mov eax, esp push edx push 0 push esp push 8 push eax push base push dword [ebx+8] call [ReadProcessMemory] pop eax pop edx pop ecx ; ecx = [base] for target process cmp eax, 8 jnz .m1pop2 pop eax ; eax = [limit] for target process push edx inc eax add edx, esi sub edx, eax jc @f sub dword [esp], edx jnc @f and dword [esp], 0 @@: add esi, ecx pop edx pop ecx xor eax, eax test edx, edx jz @f push -1 push esp add edi, [base] push edx push edi push esi push dword [ebx+8] call ecx pop eax @@: mov [esp+20h], eax ret .terminate: call find_debuggee test ebx, ebx jnz i40_sys_service.kill ret .set_drx: sub esp, 0xB2*4 push 1001Fh call find_debuggee test ebx, ebx jz .ret1 mov edi, esp push ecx edx push edi push dword [ebx+12] call [GetThreadContext] pop edx ecx test dh, dh js .clear ; set hardware breakpoint, dl=index (0..3), dh=(length*4)+(condition), esi=address cmp esi, 0x80000000 jae .ret1 cmp dl, 4 jae .ret1 test dh, 0xF0 jnz .ret1 mov al, dh and al, 3 cmp al, 2 jz .ret1 movzx eax, dh shr al, 2 cmp al, 2 jz .ret1 test esi, eax jnz .ret1 push edx push 0 mov eax, esp push eax push esp push 4 push eax push base push dword [ebx+8] call [ReadProcessMemory] pop eax pop eax pop edx add esi, eax or byte [edi+18h+1], 3 ; set GE and LE flags movzx eax, dh movzx ecx, dl add ecx, ecx bts dword [edi+18h], ecx ; set L flag mov [edi+4+ecx*2], esi ; set DR shl eax, cl mov edx, 0xF shl edx, cl not edx and [edi+18h+2], dx or [edi+18h+2], ax ; set R/W and LEN fields jmp .set_and_ret .clear: movzx ecx, dl add ecx, ecx btr dword [edi+18h], ecx ; clear L flag .set_and_ret: push edi push dword [ebx+12] call [SetThreadContext] add esp, 0xB3*4 and dword [esp+20h], 0 ret .ret1: add esp, 0xB3*4 push 30h push aWarning push aInvalidDataForDR push 0 call [MessageBoxA] mov dword [esp+20h], 1 ret find_debuggee: lea ebx, [ebp+tls.debuggees] @@: mov ebx, [ebx] test ebx, ebx jz @f cmp dword [ebx+4], ecx jnz @b @@: ret suspend_safe: xchg ebx, [esp+4] .redo: push ebx call [SuspendThread] sub esp, 0xB2*4 push 1000Fh push esp push ebx call [GetThreadContext] mov ax, cs cmp word [context+0xBC], ax jnz .ok cmp dword [context+0xB8], i40_nt jz .wait cmp dword [context+0xB8], i40_9x jb .test2 cmp dword [context+0xB8], safe_to_suspend ja .test2 .wait: add esp, 0xB3*4 push ebx call [ResumeThread] push 50 call [Sleep] jmp .redo .test2: cmp dword [context+0xB8], i40_done jb .ok cmp dword [context+0xB8], not_supported_i40_fn jb .wait .ok: add esp, 0xB3*4 xchg ebx, [esp+4] ret 4 rootdirs: db 2,'rd' dd fs_OnRamdisk dd fs_NextRamdisk db 7,'ramdisk' dd fs_OnRamdisk dd fs_NextRamdisk ; db 2,'fd' ; dd fs_OnFloppy ; dd fs_NextFloppy ; db 10,'floppydisk' ; dd fs_OnFloppy ; dd fs_NextFloppy db 3,'hd0' dd fs_OnHd0 dd fs_NextHd0 db 3,'hd1' dd fs_OnHd1 dd fs_NextHd1 db 3,'hd2' dd fs_OnHd2 dd fs_NextHd2 db 3,'hd3' dd fs_OnHd3 dd fs_NextHd3 db 0 virtual_root_query: dd fs_HasRamdisk db 'rd',0 ; dd fs_HasFloppy ; db 'fd',0 dd fs_HasHd0 db 'hd0',0 dd fs_HasHd1 db 'hd1',0 dd fs_HasHd2 db 'hd2',0 dd fs_HasHd3 db 'hd3',0 dd 0 i40_file_system_lfn: add ebx, [base] .noadd: push 0 ; parse file name lea esi, [ebx+20] lodsb test al, al jnz @f mov esi, [esi] add esi, [base] lodsb jmp @f .parse: push edi lodsb @@: push 0 cmp al, '/' jz @f dec esi mov dword [esp], esi mov esi, [ebp+tls.cur_dir] inc esi jmp @f .notfound: pop eax pop eax test eax, eax mov eax, 5 ; file not found jnz .notfound_retparse mov [esp+20h], eax .notfound_retparse: ret @@: mov eax, [esi] or eax, ' ' cmp eax, 'sys' jz .sys1 cmp eax, 'sys/' jnz @f inc esi .sys1: mov eax, ramdisk_path add esi, 3 jmp fs_common @@: cmp byte [esi], 0 jz .rootdir mov edi, rootdirs-8 xor ecx, ecx push esi .scan1: pop esi add edi, ecx scasd scasd mov cl, byte [edi] jecxz .notfound inc edi push esi @@: lodsb or al, 20h scasb loopz @b jnz .scan1 lodsb cmp al, '/' jz .found1 test al, al jnz .scan1 pop eax ; directory /xxx .maindir: pop eax pop eax test eax, eax jz @f .parse_access_denied: mov eax, 10 ; access denied ret @@: cmp dword [ebx], 1 jnz .access_denied xor eax, eax push dword [ebx+12] mov edx, [ebx+16] add edx, [base] push dword [ebx+4] ; first block mov ebx, [ebx+8] ; flags and ebx, 1 mov esi, [edi+4] ; [esp]=first block, [esp+4]=number of blocks, ebx=flags, edx=return area, esi='Next' handler mov edi, edx mov ecx, 32/4 rep stosd mov byte [edx], 1 ; version .maindir_loop: call esi jc .maindir_done inc dword [edx+8] dec dword [esp] jns .maindir_loop dec dword [esp+4] js .maindir_loop inc dword [edx+4] mov dword [edi], 0x10 ; attributes: folder mov dword [edi+4], ebx ; name type push eax xor eax, eax add edi, 8 mov ecx, 40/4-2 rep stosd pop eax push eax edx ; convert number in eax to decimal ANSI/UNICODE string push edi push -'0' mov cl, 10 @@: xor edx, edx div ecx push edx test eax, eax jnz @b @@: pop eax add al, '0' stosb pushf test bl, 1 jz .ansi_name xor eax, eax stosb .ansi_name: popf jnz @b pop edi add edi, 520 test bl, 1 jnz @f sub edi, 520-264 @@: pop edx eax jmp .maindir_loop .maindir_done: mov ebx, [edx+4] xor eax, eax pop ecx ecx dec ecx js @f mov al, 6 @@: mov [esp+20h], eax mov [esp+14h], ebx ret ; directory / .rootdir: pop eax pop eax test eax, eax jnz .parse_access_denied cmp dword [ebx], 1 ; read folder? jz .readroot .access_denied: mov dword [esp+20h], 10 ; access denied ret .readroot: ; virtual root folder - special handler mov esi, virtual_root_query push dword [ebx+12] mov edx, [ebx+16] add edx, [base] push dword [ebx+4] mov ebx, [ebx+8] xor eax, eax ; eax=0, [esp]=first block, [esp+4]=number of blocks, ebx=flags, edx=return area mov edi, edx mov ecx, 32/4 rep stosd mov byte [edx], 1 ; version .readroot_loop: cmp dword [esi], eax jz .readroot_done call dword [esi] add esi, 4 test eax, eax jnz @f .readroot_next: or ecx, -1 xchg esi, edi repnz scasb xchg esi, edi jmp .readroot_loop @@: xor eax, eax inc dword [edx+8] dec dword [esp] jns .readroot_next dec dword [esp+4] js .readroot_next inc dword [edx+4] mov dword [edi], 0x10 ; attributes: folder mov dword [edi+4], ebx ; name type add edi, 8 push 40/4-2 pop ecx rep stosd push edi @@: lodsb stosb test bl, 1 jz .ansi_name2 mov byte [edi], 0 inc edi .ansi_name2: test eax, eax jnz @b pop edi add edi, 520 test bl, 1 jnz @f sub edi, 520-264 @@: jmp .readroot_loop .readroot_done: mov ebx, [edx+4] xor eax, eax pop ecx ecx dec ecx js @f mov al, 6 @@: mov [esp+20h], eax mov [esp+14h], ebx ret .found1: pop eax cmp byte [esi], 0 jz .maindir ; read partition number xor ecx, ecx xor eax, eax @@: lodsb cmp al, '/' jz .done1 test al, al jz .done1 sub al, '0' cmp al, 9 ja .notfound imul ecx, 10 add ecx, eax jmp @b .done1: test ecx, ecx jz .notfound test al, al jnz @f dec esi @@: ; now [edi] contains handler address, ecx - partition number, ; esi points to ASCIIZ string - rest of name jmp dword [edi] fs_NextRamdisk: test eax, eax stc jnz @f mov al, 1 clc @@: ret fs_NextHd0: push 0 jmp fs_NextHd fs_NextHd1: push 1 jmp fs_NextHd fs_NextHd2: push 2 jmp fs_NextHd fs_NextHd3: push 3 fs_NextHd: pop ecx mov ecx, [hd_partitions_num+ecx*4] cmp eax, ecx jae .no inc eax clc ret .no: stc ret fs_HasRamdisk: mov al, 1 ret fs_HasHd0: cmp [hd_partitions_num], 0 setnz al ret fs_HasHd1: cmp [hd_partitions_num+4], 0 setnz al ret fs_HasHd2: cmp [hd_partitions_num+8], 0 setnz al ret fs_HasHd3: cmp [hd_partitions_num+12], 0 setnz al ret fs_OnRamdisk: cmp ecx, 1 jnz i40_file_system_lfn.notfound mov eax, ramdisk_path jmp fs_common fs_OnHd0: push 0 jmp fs_OnHd fs_OnHd1: push 1 jmp fs_OnHd fs_OnHd2: push 2 jmp fs_OnHd fs_OnHd3: push 3 fs_OnHd: pop eax cmp ecx, [hd_partitions_num+eax*4] jbe @f pop eax eax test eax, eax mov eax, 5 .hderr: jnz .ret mov dword [esp+20h], eax .ret: ret @@: dec ecx mov eax, [hd_partitions_array+eax*4] shl ecx, 9 add eax, ecx cmp byte [eax+511], 0 jz fs_common ; readonly disk - allow only subfunctions 0,1,5,7 cmp dword [ebx], 0 jz fs_common cmp dword [ebx], 1 jz fs_common cmp dword [ebx], 5 jz fs_common cmp dword [ebx], 7 jz fs_common ; access denied! pop eax eax test eax, eax mov eax, 10 jmp .hderr fs_common: pop ecx pop edi test edi, edi jnz @f sub esp, 204h mov edi, esp @@: push ecx push eax push edi call [lstrcpyA] push edi call [lstrlenA] pop ecx push edi add edi, eax sub eax, 204h neg eax push ecx push eax push esi push edi call [lstrcpynA] pop ecx jecxz .slash_pass cmp byte [ecx], 0 jz .slash_pass mov esi, ecx push edi call [lstrlenA] add edi, eax mov eax, edi sub eax, [esp] sub eax, 204h neg eax push eax push esi push edi call [lstrcpynA] .slash_pass: mov al, [edi] test al, al jz .slash_pass_done cmp al, '\' jz .invalid cmp al, '/' jnz @f mov al, '\' @@: stosb jmp .slash_pass .slash_pass_done: ; delete trailing slashes, if present dec edi cmp byte [edi], '\' jz .slash_pass_done inc edi stosb ; but do not delete one slash in X:\ pop edi cmp byte [edi+1], ':' jnz @f cmp byte [edi+2], 0 jnz @f mov word [edi+2], '\' @@: push edi push edi call [OemToCharA] ; now edi -> Win32 path cmp edi, esp jz fs_do xor eax, eax ret .invalid: pop edi cmp edi, esp jnz @f add esp, 204h mov dword [esp+20h], 5 ; file not found ret @@: push 5 pop eax ret fs_do: cmp dword [ebx], 10 jb @f fs_unsupported: add esp, 204h jmp not_supported_i40_fn @@: push edi call [GetFileAttributesA] mov ecx, dword [ebx] jmp dword [i40_fs_subfunctions + ecx*4] i40_fs_subfunctions: dd fs_read dd fs_read_folder dd fs_rewrite dd fs_write dd fs_setsize dd fs_getattr dd fs_setattr dd fs_execute dd fs_delete dd fs_makedir fs_read: inc eax jnz @f add esp, 204h mov dword [esp+20h], 5 ; file not found or dword [esp+14h], -1 ret @@: dec eax test al, 10h ; FILE_ATTRIBUTE_DIRECTORY jz @f add esp, 204h .access_denied: mov dword [esp+20h], 10 ; access denied or dword [esp+14h], -1 ret @@: push 0 push 0 push 3 push 0 push 1 push 80000000h push edi call [CreateFileA] add esp, 204h inc eax jz .access_denied dec eax xchg eax, esi push dword [ebx+8] mov eax, esp push 0 push eax push dword [ebx+4] push esi call [SetFilePointer] inc eax jnz @f call [GetLastError] test eax, eax jz @f pop eax mov dword [esp+20h], 6 ; EOF and dword [esp+14h], 0 ; no bytes read push esi call [CloseHandle] ret @@: mov eax, esp push 0 push eax ; mov eax, [limit] ; inc eax ; sub eax, [ebx+16] ; cmp eax, [ebx+12] ; jb @f ; mov eax, [ebx+12] ;@@: ; push eax push dword [ebx+12] mov eax, [ebx+16] add eax, [base] push eax push esi call [ReadFile] pop ecx xor eax, eax cmp ecx, [ebx+12] jz @f mov al, 6 ; EOF @@: mov [esp+20h], eax mov [esp+14h], ecx ; bytes read push esi call [CloseHandle] ret fs_read_folder: inc eax jnz @f add esp, 204h mov dword [esp+20h], 5 ; file not found or dword [esp+14h], -1 ret @@: push edi call [lstrlenA] cmp eax, 202h jb @f add esp, 204h mov dword [esp+20h], 5 or dword [esp+14h], -1 ret @@: cmp byte [edi+eax-1], '/' jz @f cmp byte [edi+eax-1], '\' jz @f mov byte [edi+eax], '/' inc eax @@: mov word [edi+eax], '*' cmp byte [esi], 0 mov esi, 2 jz @f xor esi, esi @@: sub esp, 140h ; sizeof(WIN32_FIND_DATAA) push esp push edi call [FindFirstFileA] inc eax jnz @f add esp, 140h+204h mov dword [esp+20h], 10 ; access denied or dword [esp+14h], -1 ret @@: dec eax push dword [ebx+8] ; flags push dword [ebx+4] ; 1st block push dword [ebx+12] ; number of blocks mov edi, [ebx+16] ; buffer add edi, [base] push edi xchg eax, ebx mov ecx, 32/4 xor eax, eax rep stosd mov byte [edi-32], 1 ; version .loop: test esi, 2 jz .noroot cmp word [esp+16+44], '.' jz .cont cmp word [esp+16+44], '..' jnz .noroot cmp byte [esp+16+46], 0 jz .cont .noroot: pop eax push eax inc dword [eax+8] ; new file found dec dword [esp+8] jns .cont dec dword [esp+4] js .cont inc dword [eax+4] ; new file copied mov eax, [esp+16] ; attributes and eax, 3Fh stosd mov al, [esp+12] ; name type and eax, 1 stosd lea eax, [esp+16+4] call get_bdfe_time lea eax, [esp+16+12] call get_bdfe_time lea eax, [esp+16+20] call get_bdfe_time mov eax, [esp+16+32] stosd mov eax, [esp+16+28] stosd lea eax, [esp+16+44] test byte [esp+12], 1 jz .name_ansi push 260 push edi push -1 push eax push 0 push 0 call [MultiByteToWideChar] add edi, 260*2 jmp .cont .name_ansi: push edi push eax call [CharToOemA] add edi, 264 .cont: lea eax, [esp+16] push eax push ebx call [FindNextFileA] test eax, eax jnz .loop push ebx call [FindClose] pop edx mov ebx, [edx+4] xor eax, eax pop ecx dec ecx js @f mov al, 6 @@: add esp, 140h+204h+8 mov [esp+20h], eax mov [esp+14h], ebx ret get_bdfe_time: sub esp, 10h push esp push eax call [FileTimeToSystemTime] mov ax, [esp+8] shl eax, 16 mov ah, [esp+10] mov al, [esp+12] stosd mov ax, [esp+0] shl eax, 16 mov ah, [esp+2] mov al, [esp+6] stosd add esp, 10h ret from_bdfe_time: sub esp, 10h xor eax, eax lodsb mov [esp+12], ax lodsb mov [esp+10], ax lodsw mov [esp+8], ax mov ah, 0 lodsb mov [esp+6], ax lodsb mov [esp+2], ax lodsw mov [esp+0], ax mov eax, esp push edi push eax call [SystemTimeToFileTime] add esp, 10h add edi, 8 ret fs_rewrite: push 0 push 80h push 2 push 0 push 0 push 40000000h push edi call [CreateFileA] add esp, 204h inc eax jnz @f mov dword [esp+20h], 10 and dword [esp+14h], 0 ret @@: dec eax xchg eax, esi push eax mov eax, esp push 0 push eax push dword [ebx+12] mov eax, [ebx+16] add eax, [base] push eax push esi call [WriteFile] pop ebx push esi call [CloseHandle] and dword [esp+20h], 0 mov [esp+14h], ebx ret fs_write: inc eax jnz @f add esp, 204h mov dword [esp+20h], 5 ; file not found or dword [esp+14h], -1 ret @@: dec eax test al, 10h ; FILE_ATTRIBUTE_DIRECTORY jz @f add esp, 204h .access_denied: mov dword [esp+20h], 10 ; access denied or dword [esp+14h], -1 ret @@: push 0 push 0 push 3 push 0 push 1 push 40000000h push edi call [CreateFileA] add esp, 204h inc eax jz .access_denied dec eax xchg eax, esi push dword [ebx+8] mov eax, esp push 0 push eax push dword [ebx+4] push esi call [SetFilePointer] inc eax jnz @f call [GetLastError] test eax, eax jz @f pop eax mov dword [esp+20h], 6 ; EOF and dword [esp+14h], 0 ; no bytes read push esi call [CloseHandle] ret @@: mov eax, esp push 0 push eax mov eax, [limit] inc eax sub eax, [ebx+16] cmp eax, [ebx+12] jb @f mov eax, [ebx+12] @@: push eax mov eax, [ebx+16] add eax, [base] push eax push esi call [WriteFile] pop ecx xor eax, eax cmp ecx, [ebx+12] jz @f mov al, 6 ; EOF @@: mov [esp+20h], eax mov [esp+14h], ecx ; bytes read push esi call [CloseHandle] ret fs_setsize: inc eax jnz @f add esp, 204h mov dword [esp+20h], 5 ; file not found or dword [esp+14h], -1 ret @@: dec eax test al, 10h ; FILE_ATTRIBUTE_DIRECTORY jz @f add esp, 204h .access_denied: mov dword [esp+20h], 10 ; access denied or dword [esp+14h], -1 ret @@: push 0 push 0 push 3 push 0 push 1 push 40000000h push edi call [CreateFileA] add esp, 204h inc eax jz .access_denied dec eax xchg eax, esi push dword [ebx+8] mov eax, esp push 0 push eax push dword [ebx+4] push esi call [SetFilePointer] inc eax jnz @f call [GetLastError] test eax, eax jz @f pop eax mov dword [esp+20h], 6 ; EOF mov dword [esp+14h], 1234567h ; destroy ebx push esi call [CloseHandle] ret @@: pop ecx push esi call [SetEndOfFile] and dword [esp+20h], 0 mov dword [esp+14h], 234567h ; destroy ebx push esi call [CloseHandle] ret fs_getattr: inc eax jnz @f .notfound: add esp, 204h mov dword [esp+20h], 5 ; file not found .ret_destroy_ebx: mov dword [esp+14h], 12345678h ret @@: ; Win32 does not allow to read attributes of root directories through FindFirstFile. ; Moreover, on FAT systems the root directory simply does not contain attributes. ; The current kernel implementation in Kolibri returns error eax = 2. ; Let it be. cmp word [edi+1], ':\' jnz @f cmp byte [edi+3], 0 jnz @f ; The program requests root directory. Return eax=2. ; N.B. All previous words are related to the case when Kolibri-disk is mapped to ; real disk, /hdi/j = N:\. Otherwise, it is possible to get real attributes ; of root directory, and emulator will do so (in another branch). add esp, 204h mov dword [esp+20h], 2 jmp .ret_destroy_ebx @@: sub esp, 140h ; sizeof(WIN32_FIND_DATAA) push esp push edi call [FindFirstFileA] inc eax jnz @f add esp, 140h+204h mov dword [esp+20h], 10 ; access denied mov dword [esp+14h], 12345678h ret @@: dec eax push eax call [FindClose] mov edi, [ebx+16] add edi, [base] pop eax ; attributes and eax, 3Fh stosd xor eax, eax stosd mov eax, esp call get_bdfe_time lea eax, [esp+12-4] call get_bdfe_time lea eax, [esp+20-4] call get_bdfe_time mov eax, [esp+32-4] stosd mov eax, [esp+28-4] stosd add esp, 140h-4+204h and dword [esp+20h], 0 mov dword [esp+14h], 12345678h ret fs_setattr: inc eax jz fs_getattr.notfound mov esi, [ebx+16] add esi, [base] lodsd push eax ; remember attributes push 80h ; FILE_ATTRIBUTE_NORMAL push edi call [SetFileAttributesA] push 0 push 0 push 3 ; OPEN_EXISTING push 0 push 3 ; FILE_SHARE_READ | FILE_SHARE_WRITE push 0x40000000 ; GENERIC_WRITE push edi call [CreateFileA] mov ebx, eax inc eax jnz @f push edi call [SetFileAttributesA] add esp, 204h mov dword [esp+20h], 10 ret @@: lodsd sub esp, 8*3 mov edi, esp call from_bdfe_time call from_bdfe_time call from_bdfe_time lea eax, [esp+16] push eax sub eax, 8 push eax sub eax, 8 push eax push ebx call [SetFileTime] add esp, 8*3 push ebx call [CloseHandle] push edi call [SetFileAttributesA] add esp, 204h and dword [esp+20h], 0 ret fs_execute: inc eax jnz @f add esp, 204h mov dword [esp+20h], -5 ; file not found or dword [esp+14h], -1 ret @@: mov eax, [ebx+4] mov esi, [ebx+8] call notify_run_prg add esp, 204h mov [esp+20h], eax mov dword [esp+14h], 23456789h ret fs_delete: inc eax jnz @f add esp, 204h mov dword [esp+20h], 5 ; file not found .ret: mov dword [esp+14h], 0x12345678 ret @@: dec eax test al, 10h jnz .directory push edi call [DeleteFileA] @@: add esp, 204h and dword [esp+20h], 0 test eax, eax jnz .ret mov byte [esp+20h], 10 ; access denied jmp .ret .directory: push edi call [RemoveDirectoryA] jmp @b fs_makedir: push 0 push edi call [CreateDirectoryA] add esp, 204h and dword [esp+20h], 0 test eax, eax jnz @f call [GetLastError] cmp eax, 183 ; ERROR_ALREADY_EXISTS jz @f mov byte [esp+20h], 10 @@: ret i40_window_settings: cmp ebx, 1 jnz not_supported_i40_fn mov [ebp+tls.caption], ecx or byte [ebp+tls.color_main+3], 10h push [ebp+tls.hWnd] call [GetDC] push eax push [ebp+tls.hWnd] mov edi, eax ; redraw caption mov al, byte [ebp+tls.color_main+3] and eax, 0xF dec eax js .type1 jz .nodraw dec eax jz .type2 call draw_caption_skinned .str: call draw_caption_string .nodraw: call [ReleaseDC] ret .type1: call draw_caption_type1 jmp .str .type2: call draw_caption_type2 jmp .str