COMMENT ` ---------------------------------------------------------------- )=- -=( Natural Selection Issue #1 ------------------------------------ Viewer )=- -=( ---------------------------------------------------------------------- )=- -=( 0 : Viewer Design Goals ---------------------------------------------- )=- Every zine needs a viewer, right? Well no, but we figured that it would look better if we made one anyways. To make the experience informative, the choice was made to code it in pure asm. The result came out well. With the source published, it'll also help for those of you who are implicity distrustful of running anything in a zine and maybe you'll enjoy the viewer too. The viewer is a window with a bmp background with vertical scroll bar and menus. The menu will open and display the appropriate text file. That's all the viewer does - no hidden games or anything. The actual implementation of a viewer under Windows is a trying experience. A lot of the APIs have subtle bugs. For example, the API CreatePatternBrush doesn't always work (seems to be a memory thing) but decides to return success anyways (resulting in a last minute work around). Special thanks to our offical beta-tester for catching this one. -=( 1 : Viewer Compile Instructions -------------------------------------- )=- TASM32 5.0 & TLINK32 1.6.71.0 tasm32 /m /ml viewer.asm brc32 -r viewer.rc tlink32 /Tpe /aa /x viewer.obj, viewer.exe,, import32.lib,, viewer.res -=( 2 : Viewer ----------------------------------------------------------- ) ` .386 .model flat, stdcall warn include viewer.inc ; lots of struct and constant definitions MYPAGESIZE = 36 MAXLINESPERPAGE = 38 TEXTCOLOR = 00C0C0C0h ICONNUM = 101 BITMAPNUM= 102 .data? MenuHnd dd ? hdc dd ? msg MSGSTRUCT ? ps PAINTSTRUCT ? rect RECT ? bmphnd dd ? .data ;the data area WinName db 'Natural Selection #1',0 classname db 'ClassName',0 MenuName db 'Todays_Menu',0 filename db 'ns#1-0_0.txt',0 ErrorMsg db 'Bad command or file name',0 FileHnd dd 0 MapHnd dd 0 MemMap dd 0 FileSize dd 0 FileLines dd 0 DisplayPos dd 0 wc WNDCLASSEX <30h, \ ; size of WNDCLASSEX CS_HREDRAW or CS_VREDRAW, \ ; Window style offset Winproc, \ ; Window event handler 0, \ ; # bytes after WinClass struct 0, \ ; # bytes after Window Instance 0, \ ; hInstance 0, \ ; hIcon 0, \ ; hCursor COLOR_WINDOW+1, \ ; background color (1-19) 0, \ ; Menu Name offset classname, \ ; Class Name 0> ; Handle to small Icon _si SCROLLINFO .CODE ; executable code starts here start: call FileOpen ; Open default file and MemMap it call GetModuleHandleA, 0 ; Get the handle of this program ; NULL returns handle used to create ; process (usually the param is a ; string to a lib name [dll]) ; Register a Parent Window mov wc._hInstance,eax xchg eax,ebx call LoadIconA, ebx, ICONNUM mov wc.hIcon, eax call LoadCursorA, dword ptr 0, IDC_ARROW mov wc.hCursor,eax call LoadBitmapA, ebx, BITMAPNUM mov bmphnd, eax call GetStockObject, BLACK_BRUSH ; Work around another Win bug mov wc.hbrBackground, eax RegIt: call RegisterClassExA, offset wc ; Create Menu call LoadMenuA, ebx, offset MenuName mov MenuHnd, eax ; Create Parent Window call CreateWindowExA, dword ptr 0 \ ; Ex_Win_style , offset classname \ ; Class Name , offset WinName \ ; Window Name , WS_SYSMENU or WS_DLGFRAME or WS_VSCROLL or WS_MINIMIZEBOX \ , CW_USEDEFAULT \ ; Horiz Pos. , CW_USEDEFAULT \ ; Vert. Pos. , 664 \ CW_USEDEFAULT \ ; Width , 500 \ CW_USEDEFAULT \ ; Height , dword ptr 0 \ ; Parent Handle , eax \ ; Menu Handle , ebx \ ; hinst , dword ptr 0 ; Addr(WinCreationData) xchg eax,ebx call SetScrollInfo, ebx, SB_VERT, offset _si, 0 call GetStockObject, OEM_FIXED_FONT ; Display Window call ShowWindow, ebx, dword ptr SW_SHOW call UpdateWindow, ebx MainLoop: call GetMessageA, offset msg, dword ptr 0, dword ptr 0, dword ptr 0 test eax,eax jz short ProgDone call TranslateMessage, offset msg call DispatchMessageA, offset msg jmp MainLoop ProgDone: call DeleteObject, bmphnd call ExitProcess, 0 ;ends the program ; -=( --------------------------------------------------------------------- )=- ; ; Event Handler ; ; -=( --------------------------------------------------------------------- )=- Winproc proc hWnd:dword, uMsg:dword, wParam:dword, lParam:dword mov eax, uMsg cmp eax, WM_PAINT ; Redraw Screen? je WinRedraw cmp eax, WM_COMMAND ; Menu Item Picked je PickMenu cmp eax, WM_VSCROLL ; Scroll? je DoVScroll cmp eax, WM_KEYDOWN ; Key pressed? je short WinChar cmp eax, WM_DESTROY ; End Prog? je WinQuit WinDefault: call DefWindowProcA, hWnd, uMsg, wParam, lParam ExitWinProc: ret GotoBegin: mov eax, MemMap mov DisplayPos, eax lea esi, _si mov [esi].SInPos, ecx ; set to 0 jmp ResumeScroll WinChar: mov eax,wParam cmp al,'Q' ; q= quit je WinQuit cmp eax, VK_ESCAPE ; as does Esc je WinQuit xor ecx, ecx ; mov ecx, SB_LINEUP cmp MemMap, ecx je WinDefault cmp eax, VK_HOME je GotoBegin cmp eax, VK_UP je short ScrollUpMsg inc ecx ; mov ecx, SB_LINEDOWN cmp eax, VK_DOWN je short ScrollUpMsg inc ecx ; mov ecx, SB_PAGEUP cmp eax, VK_PRIOR je short ScrollUpMsg inc ecx ; mov ecx, SB_PAGEDOWN cmp eax, VK_NEXT jne WinDefault ScrollUpMsg: call SendMessageA, hWnd, WM_VSCROLL, ecx, 0 jmp WinDefault PickMenu: ; Menu Choices mov ecx, MemMap jecxz ResetFile call UnmapViewOfFile, ecx call CloseHandle, MapHnd call CloseHandle, FileHnd ResetFile: movzx eax, word ptr wParam cmp eax, 1 je short MenuExit mov ebx, eax shr ebx, 4 and eax, 7 add eax, '0' add ebx, '0'-1 mov filename+5, bl mov filename+7, al call FileOpen call SetScrollInfo, hWnd, SB_VERT, esi, 1 call InvalidateRect, hWnd, 0, 1 ; Refresh screen jmp WinDefault MenuExit: call DestroyWindow, hWnd jmp ExitWinProc WinQuit: call PostQuitMessage, dword ptr 0 xor eax,eax jmp ExitWinProc WinRedraw: call GetClientRect, hWnd, offset rect ; Draw Text inc rect.rcTop call BeginPaint, hWnd, offset ps xchg eax,ebx call CreateCompatibleDC, ebx xchg esi, eax call SelectObject, esi, bmphnd xor ecx,ecx call BitBlt, ebx, ecx, ecx, 664, 500, esi, ecx, ecx, SRCCOPY call DeleteDC, esi call SetBkMode, ebx, TRANSPARENT call SetTextColor, ebx, TEXTCOLOR call GetStockObject, OEM_FIXED_FONT call SelectObject, ebx, eax mov ecx, DisplayPos jecxz DispError mov eax, MemMap sub eax, ecx add eax, FileSize cmp eax, 10000h ; Work around windows bug jb short WillFit ; (uses only bottom 16 bits) mov eax, 0FFFFh WillFit: call DrawTextA, ebx, ecx, eax, offset rect, DT_NOPREFIX jmp short FinishRedraw DispError: call DrawTextA, ebx, offset ErrorMsg, -1, offset rect, DT_NOPREFIX FinishRedraw: call EndPaint, hWnd, offset ps jmp ExitWinProc DoVScroll: mov edi, DisplayPos test edi, edi je short ExitScroll lea esi, _si call GetScrollInfo, hWnd, SB_VERT, esi movzx eax, word ptr wParam cmp eax, SB_LINEDOWN je short LineDown cmp eax, SB_LINEUP je short LineUp cmp eax, SB_PAGEUP je short PageUp cmp eax, SB_PAGEDOWN je PageDown jmp short ExitScroll ResumeScroll: mov [esi].SIfMask, SIF_POS call SetScrollInfo, hWnd, SB_VERT, esi, 1 call InvalidateRect, hWnd, 0, 1 ExitScroll: xor eax, eax ret LineDown: mov eax, [esi].SInPos cmp eax, [esi].SInMax jae ExitScroll inc [esi].SInPos mov ecx, MemMap sub ecx, edi add ecx, FileSize NextLineLoop: jz short NextLineLoopDone cmp byte ptr [edi],0Ah je short NextLineLoopDone2 inc edi dec ecx jmp NextLineLoop NextLineLoopDone2: inc edi NextLineLoopDone: mov DisplayPos, edi jmp ResumeScroll LineUp: cmp [esi].SInPos, 0 jle ExitScroll dec [esi].SInPos mov ecx, MemMap dec edi LineUpLoop: dec edi cmp ecx, edi jg NextLineLoopDone2 cmp byte ptr [edi], 0Ah je NextLineLoopDone2 jmp LineUpLoop PageUp: mov ecx, [esi].SInPos cmp ecx, 0 jle ExitScroll cmp ecx, MYPAGESIZE jb short UseMinPageUp mov ecx, MYPAGESIZE UseMinPageUp: sub [esi].SInPos, ecx mov edx, MemMap dec edi PageUpLoop: dec edi cmp edx, edi jg NextLineLoopDone2 cmp byte ptr [edi], 0Ah jne PageUpLoop dec ecx jz NextLineLoopDone2 jmp PageUpLoop PageDown: mov ecx, [esi].SInMax sub ecx, [esi].SInPos jle ExitScroll cmp ecx, MYPAGESIZE jb short UseMinPageDown mov ecx, MYPAGESIZE UseMinPageDown: add [esi].SInPos, ecx mov edx, MemMap sub edx, edi add edx, FileSize PageDownLoop: jz NextLineLoopDone cmp byte ptr [edi],0Ah je short PageDownTestDone PageDownNotDone: inc edi dec edx jmp PageDownLoop PageDownTestDone: dec ecx jz NextLineLoopDone2 jmp PageDownNotDone Winproc endp FileOpen PROC ; returns vars set and esi = offset _si xor ebx, ebx mov FileHnd, ebx mov MapHnd, ebx mov MemMap, ebx mov FileSize, ebx mov FileLines, ebx mov DisplayPos, ebx call CreateFileA, offset filename, GENERIC_READ, FILE_SHARE_READ, \ ebx, OPEN_EXISTING, ebx, ebx cmp eax,-1 je short OpenFile_exit mov FileHnd, eax call CreateFileMappingA, eax, ebx, PAGE_READONLY, ebx, ebx, ebx mov MapHnd, eax call MapViewOfFile, eax, FILE_MAP_READ, ebx, ebx, ebx mov MemMap, eax mov DisplayPos, eax mov edi, eax call GetFileSize, FileHnd, ebx mov FileSize, eax xor ecx, ecx CountLines: cmp ecx, eax jae short CountDone cmp byte ptr [edi+ecx], 0Ah lea ecx, [ecx+1] jne CountLines inc FileLines jmp CountLines CountDone: inc FileLines OpenFile_exit: lea esi, _si mov eax, -36 add eax, FileLines mov [esi].SInMax, eax xor eax, eax mov [esi].SInMin, eax mov [esi].SInPos, eax mov [esi].SInPage, eax mov [esi].SIfMask, SIF_ALL ret endp end start COMMENT ` ---------------------------------------------------------------- )=- -=( Natural Selection Issue #1 --------------- (c) 2002 Feathered Serpents )=- -=( ---------------------------------------------------------------------- ) `