| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# viewwing.htm
Data
Data
Procedures
CreateLstIndex
FileIndexReopen
FileWriteOutput
Main
ReadFileIni
SaveViewIndex
ViewEpilogue
ViewPrologue
WndCreateMain
WndFont
WndPaintMain
WndProcMain
WndResizeMain
WndTitle

This is a module of EuroTool program EuroView for Windows.

         EUROASM CPU=X64,SIMD=Yes, Unicode=No, MaxInclusions=128, Debug=no
    viewwing PROGRAM Format=COFF, Width=64 ,MaxExpansions=128K
         %DROPMACRO *
         INCLUDEHEAD argument.htm, viewmain.htm
         INCLUDE1 winabi.htm,winsgui.htm,winsdlg.htm,winsfile.htm,winf64.htm, \
                  cpuext64.htm,cpuext.htm,status32.htm,memory64.htm,string64.htm,fastcall.htm,
         LINK winapi.lib
         PUBLIC BufferCreate@RT

Data

                     ; Constants.
    OptimalWidth     = 640
    MinimalWidth     = 500
    MinimalHeight    = 440
    FontSizeMax      = 48
    FontSizeDef      = 16  ; Standard font height to begin with.
    FontSizeMin      = 10
    CtrlStep         =  5  ; Cursor keys move the screen by 1, or by CtrlStep characters when Ctrl is pressed.
    WheelPerLine     = 120 ; wParamHigh = 120 or -120 to scroll 1 row up or down.
    ColorDump        = 0x00D0D0D0 ; Dump.
    ColorRem         = 0x00D0FFFF ; Remark.
    Color1           = 0x00D0FFD0 ; Level 1.
    Color2           = 0x0030FFFF ; Level 2.
    Color3           = 0x00D0D0FF ; Level 3.
    Color4           = 0x00FFD0D0 ; Level 4.
    TopLine          = ScrollInfo.nPos   ; Ordinal of the listing line displayed in the top row of the window.
    Rows             = ScrollInfo.nPage  ; Number of rows in the current window.
    Lines            = ScrollInfo.nMax   ; Number of physical lines in listing.

    [.rodata]        ; Constant texts.
    Help:
     DB 13,10
     DB "EuroView version %^DATE",13,10
     DB "can be used to inspect binary, object, library or executable ""InputFile"":",13,10
     DB 9,"euroview.exe ""InputFile""",13,10,10
     DB " It also accepts arguments from the command-line:",13,10
     DB 9,"/InputFile=       ",9,9,"Input file name to be inspected.",13,10
     DB 9,"/FileFormat=      ",9,9,"Default is Autodetect. /FF=? for the list of accepted formats.",13,10
     DB 9,"/OutputFile=      ",9,9,"Temporary file; default is ""%%TEMP%%\InputFile.lst"".",13,10
     DB 9,"/LeaveTemporary=no",9,9,"Do not erase OutputFile when EuroView terminates.",13,10
     DB 9,"/CodeWidth=       ",9,9,"Set to 16|32|64 if not autodetected.",13,10
     DB 9,"/CodeBegin=       ",9,9,"File address where to begin the disassembly.",13,10
     DB 9,"/CodeEnd=         ",9,9,"File address where to end the disassembly.",13,10
     DB 9,"/DataBegin=       ",9,9,"File address where to begin the dumping as data.",13,10
     DB 9,"/DataEnd=         ",9,9,"File address where to end the dumping as data.",13,10
     DB 10
     DB " Accepted file formats:",13,10
     %i %SETA 1
     %WHILE "%FileFormats{%i}"
     DB 9,"%FileFormats{%i+0}"
     DB 9," %FileFormats{%i+1}"
     DB 9," %FileFormats{%i+2}"
     DB 9," %FileFormats{%i+3}"
     DB 9," %FileFormats{%i+4}"
     DB 9," %FileFormats{%i+5}"
     %i %SETA %i+6
     DB 13,10
     %ENDWHILE
    EndHelp:
     DB 13,10," Keys:",13,10
     DB 9,"F1  ",9,9,9,"this help",10
     DB 9,"O   ",9,9,9,"open another file",10
     DB 9,"Shift Tab | Right button",9," increase nesting level (more compact)",10
     DB 9,"Tab | Left button",9,9,"decrease nesting level (more detailed)",10
     DB 9,"Ctrl + ",9,9,9,"increase font size",10
     DB 9,"Ctrl - ",9,9,9,"decrease font size",10
     DB 9,"Ctrl 0 ",9,9,9,"default font size",10
     DB 9,"Home   ",9,9,9,"beginning of the document",10
     DB 9,"End    ",9,9,9,"end of the document",10
     DB 9,"PgUp | PgDn ",9,9,"page up | down",10
     DB 9,"Up | Dn | Mouse scroll",9,"line up | down",10
     DB 9,"Esc",9,9,9,"close window",10
     DB 0
    FormatNames:
    FF %FOR %FileFormats
         DB "%FF",0
       %ENDFOR FF
    EndFormatNames:

    [.bss]           ; Variable data.
    Msg              DS MSG          ; Window message.
    WndClassEx       DS WNDCLASSEX   ; Window class structure.
    InpFileDlg       DS OPENFILENAME
    PaintStruct      DS PAINTSTRUCT
    RectMainWindow   DS RECT
    TextMetric       DS TEXTMETRICA
    ScrollInfo       DS SCROLLINFO
    LstIndex:        DS LST_INDEX
    FileIni          DS FILE64
    FileInput        DS FILE64
    FileOutput::     DS FILE64
    FileIndex::      DS FILE64
    hWindowMain      D QWORD         ; Window handles.
    hWindowHelp      D QWORD
    hFont            D QWORD
    hDC              D QWORD         ; Handle of device context.
    cxWindow         D QWORD         ; Horizontal coordinate in px.
    cyWindow         D QWORD         ; Vertical coordinate in px.
    WindowWidth      D DWORD         ; Client area width  in px.
    WindowHeight     D DWORD         ; Client area height in px.
    cxChar           D DWORD         ; Width  of one character in px.
    cyChar           D DWORD         ; Height of one character in px.
    FontSize         D DWORD         ; Height of font in px.
    Cols             D DWORD         ; Number of cols in current window.
    WheelCnt         D DWORD         ; Accumulated WheelPerLine value when mouse wheel is rolled.
    Level            D DWORD         ; What level of headers to display (0..4).
    LevelPrevious    D DWORD
    Spaces           D 800 * B
    NameUTF16::      D 800 * UNICHAR ; Temporary working space for file names in UTF-16.
    NameUTF8::       D 800 * BYTE    ; Temporary working space for file names in UTF-8.

    [.text]          ; Program code.

Main
  Program entry in console subsystem.

    Main:: PROC
        StdOutput EuroView::, Version::, Eol=yes
        ; Try to load arguments from the configuration file "%AppData%\eurotool\euroview.ini".
        WinABI GetEnvironmentVariableW,=U'AppData',NameUTF16,SIZE# NameUTF16
        TEST RAX
        JZ .10:
        LEA RBX,[FileIni]
        FileAssign RBX,NameUTF16,=U'\eurotool\euroview.ini',Unicode=yes
        FileExists? RBX
        JC .10:
        CALL ReadFileIni                   ; Read arguments from the configuration file.
    .10:; Read arguments from the command-line.
        MOV EAX,[ArgNr::]
        INC EAX                  ; The next argument.
        MOV [ArgNr::],EAX
        GetArg RAX, Unicode=yes  ; RSI,RCX gets the line with one argument in UTF-16.
        JC .40:                  ; When they are no more arguments.
        SHR ECX,1                ;  Size in bytes.
        LEA RDI,[NameUTF8]
        WinABI WideCharToMultiByte,65001,0,RSI,RCX,RDI,SIZE#NameUTF8/2,0,0 ; Convert to UTF-8 in NameUTF8.
        MOVB [RDI+RAX],0
        MOV RSI,RDI
        GetLength$ RSI
        CALL ArgParse::          ; Use ArgParse to translate UTF-8 string RSI,RCX to a public symbol Arg***.
        JNC .10:                 ; Parse the next argument when no error.
        LEA RSI,[ErrorMessage::] ; Error in arguments.
        GetLengthUTF8 RSI
        WinABI MultiByteToWideChar,65001,0,RSI,RCX,NameUTF16,MAX_PATH_SIZE
        StdOutput NameUTF16,Console=yes,Unicode=yes
        JSt [Status::],ArgEnc?|ArgLoc?|ArgFF?,.30:
        LEA RCX,[EndHelp::]
        LEA RAX,[Help:]
        SUB RCX,RAX
        StdOutput Help, Size=RCX, Unicode=no                 ; On error write help and terminate.
    .30:TerminateProgram 8
    .40:; All arguments are accepted..
        BufferCreate Size=256K                               ; Create five level buffers.
        JC ErrorAlloc
        MOV [Level0Buffer::],RAX
    lvl %FOR 1..4
          BufferCreate Size=64K
          JC ErrorAlloc:
          MOV [Level%lvl{}Buffer::],RAX
        %ENDFOR
        LEA RAX,[FileIndexReopen:]
        MOV [FileIndexReopenProc::],RAX
        LEA RAX,[FileWriteOutput:]
        MOV [FileWriteOutputProc::],RAX
        MOVD [Level],0
        MOVD [TopLine],1
        CMPB [ArgInputFile::],0
        JZ .50:                 ; Skip when no file was specified on the command line.
        CALL ViewPrologue:      ; Read the ArgInputFile, prepare output files.
        JC ErrorFileInput:      ; If error, InputFile not found etc.
        CALL ViewCreate::       ; Generate FileIndex and write FileOutput.
        CALL ViewEpilogue:
    .50:CALL WndCreateMain      ; Input file was indexed to buffers, start viewing it in a Window.
        CALL WndResizeMain
        CMPB [ArgInputFile::],0
        JNZ .60:
        WinABI PostMessage,[hWindowMain],WM_KEYDOWN,VK_F1,0 ; Display Help when no file specified.
    .60:WinABI ShowWindow,[hWindowMain],SW_SHOW
        WinABI UpdateWindow,[hWindowMain]
        CALL WndTitle
    .MsgLoop:
         WinABI GetMessage, Msg,0,0,0
         TEST RAX
         JZ .MsgQuit:                                 ; ZF signalizes message WM_QUIT - request for termination.
         WinABI TranslateMessage, Msg                 ; Remap character keys from national keyboards.
         WinABI DispatchMessage,  Msg                 ; Let Windows call our WndProc.
         JMP .MsgLoop:                                ; Wait for another message.
    ErrorHelp::
         StdOutput Help:,Eol=yes
         JMP .90:
    ErrorFileOutput:
         LEA RSI,[FileOutput.Name]
         JMP ErrorFile:
    ErrorFileInput:
         LEA RSI,[FileInput.Name]
         JMP ErrorFile:
    ErrorFileIndex:
         LEA RSI,[FileOutput.Name]
    ErrorFile:
         StdOutput =U'File "',RSI,=U'" not found or empty.',Eol=yes,Unicode=yes,Console=yes
         JMP .MsgQuit:
    ErrorAlloc::
         StdOutput =B"Error on memory allocation.",Eol=yes
    .MsgQuit:
         BufferDestroy [Level0Buffer::],[Level1Buffer::],[Level2Buffer::],[Level3Buffer::],[Level4Buffer::]
         FileClose FileInput, FileOutput, FileIndex
         JSt [Status::],ArgLeaveTemporary,.90:
         FileDelete FileOutput, FileIndex         ; Delete temporary files.
    .90: TerminateProgram 0
       ENDP Main

ViewPrologue
  Windows function which will read ArgInputFile, memory-map it to InputPtr..InputEnd, then create so far empty files FileOutput and FileIndex with filenames ArgOutputFile (if not empty) or %TEMP%\ArgInputFileName.lst, %TEMP%\ArgInputFileName.lst.index (if ArgOutputFile= is empty).
Input
  ArgInputFile, ArgOutputFile, ArgFileFormat
Output
  CF=0, ArgOutputFile, ArgFileFormat (detected), FileOutput, FileIndex.
Error
  CF=1 when ArgInputFile is empty or unable to read.

    ViewPrologue: PROC
        LEA RSI,[ArgInputFile::]           ; Name of memory-maped FileInput.
        CMPB [RSI],0
        STC
        JE .90:
        FileClose FileInput, FileIndex, FileOutput
        JSt [Status::],ArgLeaveTemporary, .10:
        FileDelete FileIndex, FileOutput   ; Delete temporary file from previous run.
    .10:LEA RDI,[NameUTF16]
        WinABI MultiByteToWideChar,65001,0,RSI,-1,RDI,SIZE# NameUTF16/2
        LEA RBX,[FileInput]
        FileAssign RBX, RDI, Unicode=yes
        FileLoad RBX
        JC .90:
        TEST RAX
        STC
        JZ .90:                           ; Zero size of input file.
        MOV [InputPtr::],RSI
        MOV [InputSize::],RAX
        LEA RDX,[RSI+RAX]
        MOV [InputEnd::],RDX
        BSR ECX,EAX                       ; Compute AddressDigits (4..8) from input file size in EAX.
        SHR ECX,2
        INC ECX
        CMP ECX,4
        JAE .20:
        MOV ECX,4
    .20:MOV [AddressDigits::],ECX
        MOV EDX,[ArgFileFormat::]          ; Find file format.
        TEST EDX
        JNZ .30:
        CALL AutodetectFileFormat::
        MOV [FormatProcPtr::],RAX          ; Pointer to procedure FormatELF32, FormatBIN etc.
        MOV [ArgFileFormat::],ECX          ; Ordinal format number.
    .30:MOV EDX,[ArgFileFormat::]          ; Set by AutodetectFormat or by cmd-line argument.
        LEA RDI,[FormatNames:]
        MOV ECX,EndFormatNames-FormatNames
        XOR EAX,EAX
    .45:DEC EDX
        JZ .40:
        REPNE SCASB
        JMP .45:
    .40:MOV [FormatNamePtr::],RDI
        LEA RDI,[NameUTF16]                ; Create output and index files.
        LEA RSI,[ArgOutputFile::]
        WinABI MultiByteToWideChar,65001,0,RSI,RCX,RDI,SIZE# NameUTF16 /2
        CMPW [RDI],0
        JNZ .80:                           ; When ArgFileOutput is not empty, use it as is.
        ; If ArgOutputFile is not specified (default), use %TEMP% and filename without path for temporary names.
        WinABI GetEnvironmentVariableW, =U"Temp", RDI, SIZE# NameUTF16
        SAL EAX,1                          ; Size in characters.
        ADD RDI,RAX
        MOV AX,'\'
        CMP [RDI-2],AX
        JE .50:
        STOSW
    .50:LEA RSI,[FileInput.Name]
        MOV EAX,[FileInput.NameOffs]
        ADD RSI,RAX                        ; Use the plain filename without path.
    .60:LODSW
        CMP AX,0
        JE .70:
        STOSW
        JMP .60:
    .70:LEA RSI,[=U".lst"]
        MOV ECX,4+1
        REP MOVSW
        LEA RDI,[NameUTF16]
    .80:FileAssign FileOutput, RDI, Unicode=yes
        FileExists? FileOutput
        JC .85:
    n %FOR 1..9
        FileAssign FileOutput,RDI,=U".lst", Unicode=yes
        FileExists? FileOutput
        JC .85:
      %ENDFOR n
    .85:FileCreate FileOutput
        JC .90:
        LEA RDX,[FileOutput.Name]
        FileAssign FileIndex, RDX, =U".index", Unicode=yes
        FileCreate FileIndex
    .90:RET
       ENDP ViewPrologue

ViewEpilogue
  Windows function which will convert indexes written to FileIndex to listing lines and store the lines to FileOutput. Then it will close FileInput and FileIndex, reopen FileOutput, memory-map it to OutputPtr..OutputEnd, sort it, store indexes of listing lines to LevelnBuffer.
Input
  OutputPtr..OutputEnd
Output
  CF=0 LevelnBuffer (n=0..4)
Error
  CF=1

    ViewEpilogue: PROC
         FileClose FileOutput, FileIndex
         FileMapOpen FileOutput
         JC ErrorFileOutput
         MOV [OutputPtr::],RSI
         MOV [OutputSize::],RAX
         ADD RAX,RSI
         MOV [OutputEnd::],RAX
         FileMapOpen FileIndex
         JC ErrorFileIndex
         MOV [IndexPtr::],RSI
         ADD RAX,RSI
         MOV [IndexEnd::],RAX
         CALL CreateLstIndex::   ; Toss the index to five memory buffers for levels 0..4.
         MOVD [Level],0
         MOVD [TopLine],1
         RET
      ENDP ViewEpilogue

FileIndexReopen
  OS dependent proxy function.

    FileIndexReopen: PROC
        LEA RBX,[FileIndex]
        FileClose RBX
        FileMapCreate RBX                ; Close and reopen FileIndex. Returns the contents in RDI,RAX.
        JC ErrorFileIndex:
        RET
      ENDP FileIndexReopen:

FileWriteOutput
  OS dependent proxy function.

    FileWriteOutput: PROC
        FileWrite FileOutput,RSI,RCX
        JC ErrorFileOutput:
        RET
      ENDP FileWriteOutput:

WndCreateMain
  Register window class and create the main window.
Called by
  Main.

    WndCreateMain: PROC
        MOV EAX,'    '
        LEA RDI,[Spaces]
        MOV ECX,SIZE# Spaces / 4
        REP STOSD
        ; Register WndClassEx for the main window.
        MOVD [WndClassEx.cbSize],SIZE# WndClassEx
        LEA RSI,[EuroView::]
        MOVQ [WndClassEx.lpszClassName],RSI
        MOVD [WndClassEx.style],CS_HREDRAW|CS_VREDRAW
        MOVQ [WndClassEx.lpfnWndProc],WndProcMain
        WinABI GetModuleHandle,0
        MOVQ [WndClassEx.hInstance],RAX
        WinABI LoadIcon,RAX,1             ; The 1st and only icon from [.rsrc] section.
        MOVQ [WndClassEx.hIcon],RAX
        WinABI LoadCursor,0,IDC_ARROW
        MOVQ [WndClassEx.hCursor],RAX
        MOVQ [WndClassEx.hbrBackground],COLOR_BTNFACE+1
        WinABI RegisterClassExA, WndClassEx

        ; Create the main window.
        WinABI CreateWindowExA,0,                                         \
               RSI,RSI,WS_OVERLAPPEDWINDOW|WS_VSCROLL,                    \
               CW_USEDEFAULT,CW_USEDEFAULT,OptimalWidth*2,MinimalHeight*2,\
               0, 0, [WndClassEx.hInstance], 0
        MOV [hWindowMain],RAX
        MOV RBX,RAX
        MOV [ScrollInfo.cbSize], SIZE# SCROLLINFO
        MOV [ScrollInfo.fMask], SIF_RANGE | SIF_PAGE
        MOV [ScrollInfo.nMin],1
        WinABI SetScrollInfo, RBX,SB_VERT,ScrollInfo,1
        MOV [FontSize], FontSizeDef
        CALL WndFont

        ; Initialize InpFileDlg.
        MOV [InpFileDlg.lStructSize],SIZE# OPENFILENAME
        MOV RAX,[WndClassEx.hInstance]
        MOV RDX,[hWindowMain]
        LEA RDI,[NameUTF16:]
        MOVW [RDI],0
        MOV [InpFileDlg.hInstance],RAX
        MOV [InpFileDlg.hwndOwner],RDX
        MOV [InpFileDlg.lpstrFile],RDI
        MOV [InpFileDlg.nMaxFile],SIZE# NameUTF16 /2
        SetSt [InpFileDlg.Flags],OFN_FILEMUSTEXIST+OFN_HIDEREADONLY
        LEA RCX,[Help:]           ; Create Help window but don't show it yet.
        WinABI CreateWindowExA,WS_EX_OVERLAPPEDWINDOW  + WS_EX_TOPMOST + WS_EX_TRANSPARENT,  \
               =B"STATIC",RCX, WS_CHILD, \
               40,80,640,520, \
               [hWindowMain], 0, [WndClassEx.hInstance], 0
        MOV [hWindowHelp],RAX
        RET
       ENDP WndCreateMain

WndProcMain, hWnd, uMsg, wParam, lParam
  This is a callback procedure which receives and handles messages for the MainWindow. Message parameters are by FastCall convention provided in registers RCX, RDX, R8, R9, we'll save them to shadow space with macro SaveToShadow . Thanks to this their contents will be available by formal names ( `[%hWnd], [%uMsg], [%wParam], [%lParam]`), too, in the entire WndProc body.

  Messages obtained from Windows are dispatched by WndProcMain to their handlers.
  Unhandled messages are passed to DefWindowProc.

  Window hWindowMain displays the lines from listing (output file). In this example we have window height 5 Rows, file length 10 Lines and Level 0. In Level 1..4 only lines with those number of `#` are selected.
Handler input
  RCX=[%hWnd] is the main window handle (the same as static [hWindowMain].
  RDX=[%uMsg] is message identifier,
  R8=[%wParam] is message w-parameter,
  R9=[%lParam] is message l-parameter.
Handler output
  RAX=0 if the message was completely processed by the handler. Otherwise the message is processed by WinAPI DefWindowProc and RAX outputs its return value.
  Scratch registers RCX,RDX,R8..R11 may be destroyed in the handlers.
  Callee-save registers RBX,RSI,RDI,R12..R15 must be restored, if used in the handlers. This provides macro Uses.
Invoked by
  WinAPI DispatchMessage.

    WndProcMain Procedure hWnd, uMsg, wParam, lParam ; These parameters are provided in RCX,RDX,R8,R9.
        Uses RBX,RBP,RSI,RDI ; It's only necessary if some of callee-save registers was used in this fastcalled procedure.
        SaveToShadow
        MOV RBX,RCX
        MOV RAX,RDX
        MOV RSI,R8
        MOV RDI,R9 ; Preload msg attributes for handler's convenience.
        ; Fork message uMsg=RAX to its handler using macro Dispatch:
         MOV RSI,R8
         Dispatch EDX, WM_VSCROLL,WM_LBUTTONUP,WM_RBUTTONUP,WM_PAINT,WM_SIZE,WM_MOUSEWHEEL,WM_KEYDOWN,WM_DESTROY
    .Def:WinABI DefWindowProc,[%hWnd],[%uMsg],[%wParam],[%lParam] ; Pass ignored event to DefWindowProc with unchanged arguments.
         JMP .Ret:     ; Go to EndProcedure with result value RAX as returned from DefWindowProc.
         ; All message handlers terminate with a jump to label .Def: or .Ret0:.
         ; Here are two helper subprocedures for keyboard and scrollbox event handlers:
    .GetCtrl2ECX: PROC  ; Returns RCX=1 when Ctrl is pressed, otherwise RCX=0. RAX,RDX clobbered.
         WinABI GetKeyState,VK_CONTROL ; Returns bit 15 of RAX set when Ctrl was pressed.
         XOR ECX,ECX
         SAL AX,1      ; Shift MSbit to CF.
         RCL ECX,1     ; Virtual key handlers receive RCX=1 when Ctrl was pressed, otherwise RCX=0.
         RET
        ENDP .GetCtrl2ECX:
    .GetShift2ECX: PROC ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
         WinABI GetAsyncKeyState,VK_SHIFT, Lib=user32.dll  ; Returns bit 15 of RAX set when Shift was pressed.
         XOR ECX,ECX
         SAL AX,1      ; Shift MSbit to CF.
         RCL ECX,1     ; Virtual key handlers receive RCX=1 when Shift was pressed, otherwise RCX=0.
         RET
        ENDP .GetShift2ECX:
    .ScrollVer: PROC   ; Scroll vertically until TopLine=ESI.
         TEST ESI      ; Saturate proposed TopLine=ESI to the acceptable range 1..Lines.
         JS .v1:
         CMP ESI,1
         JAE .v2:
     .v1:MOV ESI,1
     .v2:CMP ESI,[Lines]
         JB .v5:
         MOV ESI,[Lines]
     .v5:MOV [TopLine],ESI
         WinABI SetScrollPos,[hWindowMain],SB_VERT,RSI,1
         WinABI InvalidateRect,[hWindowMain],0,0
         RET
        ENDP .ScrollVer:

        ; Handle messages for the main window:
    .WM_PAINT:
         CALL WndPaintMain
         JMP .Ret0:
    .WM_SIZE:
         CALL WndResizeMain
         JMP .Def:
    .VK_TAB:                     ; Tab pressed.
         CALL .GetShift2ECX
         JRCXZ .WM_LBUTTONUP:
    .WM_RBUTTONUP:               ; Increase level.
         MOV EAX,[Level]
         CMP EAX,4
         JAE .Ret0:
         INC EAX
         JMPS .LB:
    .WM_LBUTTONUP:               ; Decrease level.
         MOV EAX,[Level]
         TEST EAX
         JZ .Ret0:
         DEC EAX
     .LB:MOV [Level],EAX
         CALL WndTitle:
         WinABI InvalidateRect,[hWindowMain],0,0
         JMP .Ret0:
    .WM_MOUSEWHEEL:              ; Rolled.
         SAR ESI,16              ; RSI is now +40 or -40 on mouse-wheel roll.
         ADD [WheelCnt],ESI      ; Accumulate scroll requests.
         MOV EDI,[WheelCnt]
     .RollUp:
         CMP EDI,WheelPerLine
         JL  .RollDown:
         SUB EDI,WheelPerLine
         MOV [WheelCnt],EDI
         WinABI SendMessage,RBX,WM_VSCROLL,SB_LINEUP,0
         JMP .RollUp:
     .RollDown:
         CMP EDI,0
         JGE .Ret0:
         ADD EDI,WheelPerLine
         MOV [WheelCnt],EDI
         WinABI SendMessage,RBX,WM_VSCROLL,SB_LINEDOWN,0
         JMP .RollDown:
    .WM_VSCROLL:                 ; User scrolled the window vertically.
         CALL .GetCtrl2ECX
         MOV EAX,0x0000_FFFF
         AND EAX,ESI             ; EAX is now scroll box action (clicked on the scrollbox).
         SHR ESI,16              ; ESI is now scroll box position.
         Dispatch EAX,SB_LINEUP,SB_LINEDOWN,SB_PAGEUP,SB_PAGEDOWN,SB_THUMBTRACK
         JMP .Def:
    .WM_KEYDOWN:                 ; Non-character hot key ESI=R8D=wParam was pressed.
         CALL .GetCtrl2ECX       ; Test if [Ctrl] was pressed. Set RCX=0 when not pressed.
         Dispatch ESI,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT,VK_HOME,VK_END,VK_TAB, \
                  VK_NUMPAD0,VK_ADD,VK_SUBTRACT,'O',VK_ESCAPE
         CMP ESI,VK_F1
         JB .Def:
         CMP ESI,VK_F12
         JNA .VK_F1:
         JMP .Def:               ; Pass unhandled keys to WinABI DefWindowProc.
    .SB_LINEDOWN:                ; Vertical scrollbox line down.
    .VK_DOWN:                    ; Down arrow.
         MOV ESI,[TopLine]
         INC ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         ADD ESI,CtrlStep
         JMP .SB_THUMBTRACK:
    .SB_LINEUP:                  ; Vertical scrollbox line up.
    .VK_UP:                      ; Up arrow.
         MOV ESI,[TopLine]
         DEC ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         SUB ESI,CtrlStep
         JMP .SB_THUMBTRACK:
    .SB_THUMBTRACK:              ; User dragged the tumbtrack to the position ESI.
         CALL .ScrollVer:
         JMP .Ret0:
    .SB_PAGEUP:                  ; Vertical scrollbox page up.
    .VK_PRIOR:
         MOV ESI,[TopLine]
         SUB ESI,[Rows]
         INC ESI,ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         SUB ESI,[Rows]
         SUB ESI,[Rows]
         SUB ESI,[Rows]
         JMP .SB_THUMBTRACK:
    .VK_HOME:
         MOV ESI,1
         JMP .SB_THUMBTRACK:
    .SB_PAGEDOWN:                ; Vertical scrollbox page down.
    .VK_NEXT:
         MOV ESI,[TopLine]
         ADD ESI,[Rows]
         DEC ESI,ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         ADD ESI,[Rows]
         ADD ESI,[Rows]
         ADD ESI,[Rows]
         JMP .SB_THUMBTRACK:
    .VK_END:
         MOV ESI,[Lines]
         JMP .SB_THUMBTRACK:
    .VK_NUMPAD0:                 ; Ctrl 0 restore font size.
         MOV EDI,FontSizeDef
    .SetFontEDI:
         MOV [FontSize],EDI
         CALL WndFont            ; Get new [cxChar],[cyChar].
         CALL WndResizeMain      ; Recalculate Rows, Cols.
         JMP .Ret0:
    .VK_ADD:                     ; Ctrl + increase font size.
         MOV EDI,[FontSize]
         INC EDI
         CMP EDI,FontSizeMax
         JG .Ret0:
         JMP .SetFontEDI:
    .VK_SUBTRACT:                ; Ctrl - decrease font size.
         MOV EDI,[FontSize]
         DEC EDI
         CMP EDI,FontSizeMin
         JL .Ret0:
         JMP .SetFontEDI:
    .O:  MOV RDI,[InpFileDlg.lpstrFile]
         MOVW [RDI],0
         WinABI GetOpenFileNameW, InpFileDlg  ; Open another input file.
         TEST RAX
         JZ .Ret0:               ; If cancelled in the common dialogue or other error.
         LEA RSI,[NameUTF16]     ; InputFile selected from the common dialogue.
         GetLength$ RSI, Unicode=yes
         TEST ECX
         JZ .Ret0:               ; If nothing selected.
         MOVD [ArgFileFormat::],0 ; Start with Autodetect file format.
         LEA RDI,[ArgInputFile::]
         WinABI WideCharToMultiByte,65001,0,RSI,RCX,RDI,SIZE#NameUTF8/2,0,0 ; Convert to UTF-8 in ArgInputFile.
         CALL ViewPrologue:      ; Read the input file, prepare output files.
         JC .Ret0:               ; If error, InputFile not found etc.
         CALL ViewCreate::       ; Generate FileIndex and write FileOutput.
         CALL ViewEpilogue:
         CALL WndTitle:
         WinABI InvalidateRect,[hWindowMain],0,0
         JMP .Ret0:

    .VK_F1:                                ; Show help window.
         WinABI IsWindowVisible,[hWindowHelp]
         TEST RAX
         JNZ .Ret0:                        ; Ignore F1 when it is visible.
         WinABI ShowWindow, [hWindowHelp], SW_SHOW
         JMP .Ret0:
    .VK_ESCAPE:                  ; Terminate window or program.
         WinABI IsWindowVisible,[hWindowHelp]
         TEST RAX
         JZ .WM_DESTROY:
         WinABI ShowWindow, [hWindowHelp], SW_HIDE
         JMP .Ret0:
    .WM_DESTROY:                 ; Program terminates.
         WinABI DeleteObject,[hFont]
         WinABI PostQuitMessage,0; Tell Windows to quit this program with errorlevel 0.
    .Ret0:XOR EAX,EAX            ; RAX=0 signalizes that the message was processed here.
    .Ret:EndProcedure WndProcMain

WndResizeMain
  Dimensions of the MainWindow changed.
Output
  cxChar, cyChar, Rows, Cols
Called from
  WndProcMain.WM_SIZE.

    WndResizeMain: PROC
        LEA RBX,[RectMainWindow]
        WinABI GetWindowRect,[hWindowMain],RBX
        MOV ESI,[RBX+RECT.left]
        MOV ECX,[RBX+RECT.right]
        SUB ECX,ESI
        CMP ECX,MinimalWidth
        JA .10:
        MOV ECX,MinimalWidth
    .10:MOV [WindowWidth],ECX
        MOV EDI,[RBX+RECT.top]
        MOV EDX,[RBX+RECT.bottom]
        SUB EDX,EDI
        CMP EDX,MinimalHeight
        JA .20:
        MOV EDX,MinimalHeight
    .20:MOV [WindowHeight],EDX
        WinABI MoveWindow,[hWindowMain],RSI,RDI,RCX,RDX,-1
        MOV EAX,[WindowWidth]
        XOR EDX,EDX
        MOV ECX,[cxChar]
        TEST ECX
        JZ .90:
        DIV RCX
        MOV [Cols],EAX                     ; Number of columns visible in window.
        MOV EAX,[WindowHeight]
        XOR EDX,EDX
        MOV ECX,[cyChar]
        JRCXZ .90:
        DIV RCX
        MOV [Rows],EAX                     ; Number of rows visible in window.
        WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,1
        WinABI InvalidateRect,[hWindowMain],0,1
    .90:RET
    ENDP WndResizeMain

WndPaintMain
  Display lines of the listing file mapped between [OutputPtr]..[OutputEnd].
  Indexes (LST_INDEX) are in LevelXBuffers.
  View of lines on the monitor are manipulated with cursor keys by changing the variable `TopLine`.
  |#### line 1 |## line 2 | line 3 `Level` = 0 ┌──────────────┐ │| line 4 │row 1 `TopLine` = 4 │| line 5 │row 2 │|## line 6 │row 3 │| line 7 │row 4 │| line 8 │row 5 `Rows` on screen = 5 └──────────────┘ | line 9 | line 10 `Lines` of listing = 10
[TopLine]
is saturated to the range 1..Lines-Rows+1.
Called from
  WndProcMain.WM_PAINT.

    WndPaintMain: PROC
        XOR EAX,EAX
        MOV [cxWindow],RAX
        MOV [cyWindow],RAX
        WinABI BeginPaint, [hWindowMain], PaintStruct
        MOV [hDC],RAX
        WinABI SelectObject, RAX, [hFont]
    .10:MOV R12,[OutputPtr::]
        TEST R12
        JZ .90:
        MOV EAX,[Level]                    ; 0..4
        MOV EDX,[LevelPrevious]
        CMP EAX,EDX
        MOV [LevelPrevious],EAX
        JE .50:
        JB .35:
        ; Level is increasing from EDX to EAX. Calculate the new value of TopLine.
        ADD R12,RAX
        BufferRetrieve [Level0Buffer::+8*RDX] ; RSI,RCX are old LST_INDEX records.
        XOR EDX,EDX
        MOV EDI,[TopLine]
    .15:DEC EDI
        JZ .20:
        LODSD
        CMPB [R12+RAX],'#'                 ; Is the line in new level?
        LODSD
        JNE .15:
        INC EDX
        JMP .15:
    .20:TEST EDX
        JNZ .25:
        INC EDX
    .25:CMP EDX,[TopLine]
        JB  .30:
        INC EDX
    .30:MOV [TopLine],EDX
        JMP .10:
    .35:; Level is decreasing from EDX to EAX. Calculate the new value of TopLine.
        ADD R12,RDX
        BufferRetrieve [Level0Buffer::+8*RAX] ; RSI,RCX are new LST_INDEX records.
        SHR ECX,3
        JZ .90:
        XOR EDI,EDI                        ; Line counter in new buffer.
        MOV EDX,[TopLine]
    .40:INC EDI
        LODSD
        CMPB [R12+RAX],'#'
        LODSD
        JNE .40:
        DEC EDX
        JNZ .40:
        MOV [TopLine],EDI
        JMP .10:
    .50:; Level EAX is unchanged.
        BufferRetrieve [Level0Buffer::+8*RAX] ; RSI,RCX are LST_INDEX records.
        SHR ECX,3                          ; SIZE# LST_INDEX = 8
        MOV [Lines],ECX
        MOV EDI,[TopLine]
        CMP EDI,[Lines]
        JBE .55:
        MOV EDI,[Lines]
    .55:MOV [TopLine],EDI
        WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,-1
        SUB RSI,SIZE# LST_INDEX
        XOR EDX,EDX
    .60:INC EDX                            ; Line number 1,2,3,,,Lines.
        ADD RSI,SIZE# LST_INDEX
        CMP EDX,EDI                        ; Reached TopLine?
        JB .60:
        MOV R14D,[Rows]                    ; Number of rows on screen.
        CMP EDX,[Lines]                    ; Reached the end of lines?
        JA .80:
        MOV R15D,[AddressDigits::]
        ADD R15D,38                        ; R15 is the number of gray characters in dump, including address and |.
    .65:; Display lines indexed by RSI until EDX>[Lines] (out of lines) or until R14=0 (all rows displayed).
        LODSD                              ; LST_INDEX.FA
        LEA RBX,[R12+RAX]                  ; RBX is pointer to the line in mapped listing.
        LODSD                              ; LST_INDEX.Size
        MOV ECX,EAX
        MOV EDX,[cxChar]
        MUL RDX
        MOV R13,RAX                        ; R13=cxWindow at the start of spaces.
        MOV EDI,[Cols]                     ; Columns in the window.
        SUB EDI,ECX                        ; EDI is the number of spaces after the listing line.
        MOV EAX,Color4
        CMPD [RBX+1],'####'
        JE .70:
        MOV EAX,Color3
        CMPB [RBX+3],'#'
        JE .70
        MOV EAX,Color2
        CMPW [RBX+1],'##'
        JE .70:
        MOV EAX,Color1
        CMPB [RBX+1],'#'
        JE .70:
        ; Current line is dump line Level0 , 38+AddressDigits chars wide, plus Remark.
        PUSH RCX                           ; Number of characters in this listing line.
         WinABI SetBkColor,[hDC],ColorDump ; Level0
         WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,R15
         WinABI SetBkColor,[hDC],ColorRem
         ADD RBX,R15                       ; Add the width of the dump column.
         MOV EAX,[cxChar]                  ; Width of one character.
         MUL R15                           ; Let RAX=width of already displayed characters.
        POP RCX
        SUB RCX,R15                        ; Subtract the number of already displayed characters.
        JNA .75:
        WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX ; Print the remark.
        JMP .75:
    .70:WinABI SetBkColor,[hDC],RAX        ; LevelX.
        WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,RCX
    .75:WinABI TextOutA,[hDC],R13,[cyWindow],Spaces,RDI   ; Display EDI spaces on the same line.
        MOV EAX,[cyChar]
        ADD [cyWindow],EAX
        DEC R14
        JNZ .65:
    .80:TEST R14,R14
        JZ .90:
        DEC R14
        WinABI TextOutA,[hDC],[cxWindow],[cyWindow],Spaces,[Cols]  ; Display spaces on the entire line.
        MOV EAX,[cyChar]
        ADD [cyWindow],EAX
        JMP .80:
    .90:WinABI EndPaint, [hWindowMain], PaintStruct
        RET
       ENDP WndPaintMain:

WndFont
  Release current font [hFont] (if exists) and create a new unproportional ANSI font with [FontSize].
Input
  [FontSize] is required line height in pixels.
Output
  [hFont],[cxChar],[cyChar]
Called by
  WndCreateMain

    WndFont: PROC
        MOV RCX,[hFont]
        JRCXZ .10:
        WinABI DeleteObject,RCX,Lib=gdi32.dll
    .10:WinABI CreateFontW, [FontSize], 0, 0, 0, FW_DONTCARE, 0, 0, 0, ANSI_CHARSET, \
               OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY,              \
               FIXED_PITCH | FF_SWISS, 0
        MOV [hFont],RAX
        MOV RBX,[hWindowMain]
        WinABI GetDC,RBX
        MOV RDI,RAX              ; Device context,
        WinABI SelectObject,RDI,[hFont]
        WinABI GetTextMetrics,RDI,TextMetric
        WinABI ReleaseDC,RBX,RDI
        MOV EAX,[TextMetric.tmHeight]
        MOV ECX,[TextMetric.tmAveCharWidth]
        ADD EAX,[TextMetric.tmExternalLeading]
        MOV [cxChar],ECX
        MOV [cyChar],EAX
        RET
      ENDP WndFont:

WndTitle
  This procedure will update title of the main window in UTF16 to NameUTF16.
  Title is updated when input file, format or level changes.
  The new title is constructed in NameUTF8.
Input
  FormatNamePtr::, Level, FileInput.Name
Output
  NameUTF16

    WndTitle PROC
        LEA RDI,[NameUTF8]
        LEA RSI,[EuroView::]
        MOV ECX,8
        REP MOVSB
        MOV AX,' "'
        STOSW
        LEA RSI,[ArgInputFile::]
        TEST RSI
        JZ .40:
    .30:LODSB
        CMP AL,0
        JE .40:
        STOSB
        JMP .30:
    .40:MOV AL,'"'
        STOSB
        MOV EAX,' as '
        STOSD
        MOV RSI,[FormatNamePtr::]
        TEST RSI
        JZ .60:
    .50:LODSB
        CMP AL,0
        JE .60:
        STOSB
        JMP .50:
    .60:LEA RSI,[=B' level ']
        MOV CL,7
        REP MOVSB
        MOV AX,'0'
        OR AL,[Level]
        STOSW
        MOV RCX,RDI
        LEA RSI,[NameUTF8]
        SUB RCX,RSI
        LEA RDI,[NameUTF16]
        WinABI MultiByteToWideChar,65001,0,RSI,RCX,RDI,SIZE# NameUTF16 /2
        WinABI SetWindowTextW,[hWindowMain],RDI
        RET
      ENDP WndTitle

SaveViewIndex
  Global Window procedure SaveViewIndex is called from analyzing and formating procedures in the OS-independent module viewmain.htm.
  It will store the external variable ViewIndex:: to FileIndex, keep its `.Size`, add `.Size` to .FA, clear `.Level` and `.Rem` in this variable.
Input
  RBX=pointer to VIEW_INDEX variable, usually to ViewIndex::.
  FileIndex is a created file.
Output
  RAX=0.
  RBX= is kept as a pointer to VIEW_INDEX variable.
  [RBX+VIEW_INDEX.FA] is incremented by the previous [RBX+VIEW_INDEX.Size] when .Level=0. Unchanged when .Level>0.
  [RBX+VIEW_INDEX.Size] is kept, but .Level bits are cleared.
  [RBX+VIEW_INDEX.Rem] is cleared.
Clobbers
  RAX

    SaveViewIndex:: PROC
        PUSH RCX
         FileWrite FileIndex, RBX, SIZE# VIEW_INDEX
         MOV EAX,[RBX+VIEW_INDEX.Size]
         MOV ECX,EAX
         AND EAX,0x0FFF_FFFF
         MOV [RBX+VIEW_INDEX.Size],EAX      ; Keep .Size unchanged for the next element.
         SHR ECX,28                         ; Isolate level.
         JNZ .50:
         ADD [RBX+VIEW_INDEX.FA],EAX        ; Add previous .Size to this .FA, but keep .FA unchanged when .Level >0.
    .50: XOR EAX,EAX
         MOV [RBX+VIEW_INDEX.Rem],RAX       ; Always clear .Rem field.
        POP RCX
        RET
       ENDP SaveViewIndex::

ReadFileIni
  Procedure ReadFileIni reads lines from FileIni in UTF-8 and parses its each line into configuration variables Arg*** in UTF-8, too.
  The FileIni.Name is in UTF-16. Procedure writes information about the file name and whether it was found on standard output.
Called by
  Main.
Input
  FileIni is assigned with the name.
Clobbers
  RAX,RCX,RDX,RSI,RDI

    ReadFileIni:: PROC
        SetSt [Status::],ArgFromFile       ; Tell ArgParse that arguments may not begin with / or -.
        StdOutput =U'Configuration "',FileIni.Name,Console=yes,Unicode=yes
    .10:FileStreamOpen FileIni,BufSize=4K
        JNC .20:
        StdOutput =U'" was not found.',Eol=yes,Console=yes,Unicode=yes
        JMP .90:
    .20:FileStreamReadLn FileIni
        JBE .80:
        MOV ECX,EAX
        ; The first line may begin with BOM.
        MOV AX,[RSI]
        CMPW AX,0xBBEF   ; UTF-8 BOM?
        JNE .50:
        ADD RSI,3        ; Skip the BOM.
        SUB ECX,3
        JB .80:
        JMP .50:
    .30:FileStreamReadLn FileIni
        JBE .80:
        MOV ECX,EAX
    .50:CALL ArgParse::
        JNC .30:
        StdOutput Help:,Unicode=no
        TerminateProgram 8
    .80:FileClose FileIni
        StdOutput =U'" was accepted.',Eol=yes,Console=yes,Unicode=yes
    .90:RstSt [Status::],ArgFromFile
        RET
      ENDP ReadFileIni

CreateLstIndex
  This procedure will clear BUFFERs for each level (0..4) and then it will index the listing file (OutputPtr..OutputEnd) into those buffers.
  Buffers contain records in the form of LST_INDEX.
Input
  OutputPtr..OutputEnd is the listing mapped in memory.
Output
  CF=0, LstIndex is an empty variable of LST_INDEX structure which was saved to buffers.
  ListingLines is filled with the total number of lines in the listing.
Error
  CF=1 allocation error.

    CreateLstIndex: PROC
        BufferClear [Level0Buffer::],[Level1Buffer::],[Level2Buffer::],[Level3Buffer::],[Level4Buffer::]
        MOV RBX,[OutputPtr::]              ; Start of the listing in memory.
        XOR ECX,ECX
        MOV AL,10
        DEC RCX
        MOV RDX,RBX
    .10:MOV RDI,RDX
        CMP RDI,[OutputEnd::]
        JNB .80:
        MOV RSI,RDI
        REPNE SCASB                        ; Find the end of line.
        MOV RDX,RDI
        SUB RDI,RSI                        ; Size.
        SUB RSI,RBX                        ; FA.
        SUB EDI,2                          ; Omit CR+LF.
        MOV [LstIndex.FA],ESI
        MOV [LstIndex.Size],EDI
        BufferStore [Level0Buffer::],LstIndex,SIZE# LstIndex
        JC ErrorAlloc::
        CMPB [RBX+RSI+1],'#'               ; Is the line in Level1?
        JNE .10:
        BufferStore [Level1Buffer::],LstIndex,SIZE# LstIndex
        JC ErrorAlloc::
        CMPW [RBX+RSI+1],'##'              ; Is the line in Level2?
        JNE .10:
        BufferStore [Level2Buffer::],LstIndex,SIZE# LstIndex
        CMPB [RBX+RSI+3],'#'               ; Is the line in Level3?
        JNE .10:
        BufferStore [Level3Buffer::],LstIndex,SIZE# LstIndex
        CMPD [RBX+RSI+1],'####'            ; Is the line in Level4?
        JNE .10:
        BufferStore [Level4Buffer::],LstIndex,SIZE# LstIndex
        JMP .10:
    .80:BufferRetrieve [Level0Buffer::]
        SHR ECX,3                          ; SIZE# LstIndex = 8
        MOV [ListingLines::],ECX
        CLC
        RET
       ENDP CreateLstIndex

    %IF %^Debug
     DebugOutput proc
       StdOutput rsi,Size=rcx
       ret
     ENDP DebugOutput
    %ENDIF
      ENDPROGRAM viewwing

▲Back to the top▲