EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

viewwing.htm
Data
Data
Procedures
Copy2Clipboard
CreateLstIndex
FileIndexReopen
FileWriteOutput
Search
Main
MsgLoopFind
ReadFileIni
SaveViewIndex
ViewEpilogue
ViewPrologue
WndCreateFind
WndCreateMain
WndFont
WndPaintMain
WndProcFind
WndProcMain
WndResizeFind
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,debug.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.

;;IdEncoding       = 0x8031
;;;IdHelp           = 0x8040
IdBtnCancel      = 0x8051
IdBtnFind        = 0x8053
IdBtnClear       = 0x8054
heBtnIO          =  20        ; Position of Arg subwindows.
heFind           = 106
heTitle1         =  18
wiBorder         =  10
wiBtnIO          =  90
wiFind           = 480
;;;;wiHelp           = 580
;;;;;;wiTitleEncoding  = 480
yFindButton      =  40

;                       B G R
ColorDump         = 0x00D0D0D0 ; Dump.
ColorRem          = 0x00D0FFFF ; Remark.
Color1            = 0x00D0FFD0 ; Level 1.
Color2            = 0x0030FFFF ; Level 2.
Color3            = 0x00D0D0FF ; Level 3.
Color4            = 0x00FFD0D0 ; Level 4.
BkColorFound      = 0x00FFFFFF ; Found.
TextColorFound    = 0x00FF00FF ; Found.
TextColorSelected = 0x00FFFFFF ; Selected.
BkColorSelected   = 0x00C06733 ; Selected.
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.
TitleWindowFind  DB "EuroTextFind",0
Help:
 DB 13,10
 DB " EuroView is one of the EuroTool from https://euroassembler.eu/eurotool",13,10
 DB "  which 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,  "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 screen",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,"F | F7",9,9,9,"Find a string",10
 DB 9,"N | F3",9,9,9,"Find the next occurence",10
 DB 9,"P | Shift-F3",9,9,"Find the previous occurence",10
 DB 9,"Left button drag",9,9,"mark a rectangular selection",10
 DB 9,"Ctrl C",9,9,9,"copy the selection to clipboard",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, terminate program.",10
 DB 0
FormatNames:
FF %FOR %FileFormats
     DB "%FF",0
   %ENDFOR FF
EndFormatNames:
[.data]
FoundCnt         DD 0             ; How many time was Find$ found.
FoundOffset      DD 0             ; Offset of found string in line.
FindUTF8Size     DD 0             ; Size of the searched string in bytes.
FindUTF8         DB MAX_PATH_SIZE * BYTE    ; Text string to search for.
[.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
RectWindowMain   DS RECT
FileIni          DS FILE64
FileInput        DS FILE64
FileOutput::     DS FILE64
FileIndex::      DS FILE64
hWindowMain      D QWORD         ; Window handles.
hWindowHelp      D QWORD
hWindowFind      D QWORD
hEditFind        D QWORD
hBtnFind         D QWORD
hBtnClear        D QWORD
hBtnCancel       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.
IndexBegin       D QWORD         ; Pointer to array of LST_INDEX records in current levelN buffer.
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.
WindowFindWidth  D DWORD         ; Number of characters in FindText.
Level            D DWORD         ; What level of headers to display (0..4).
LevelPrevious    D DWORD         ; To detect when level changes.
DocRowStart      D DWORD         ; Start row when left MB down. 1,2,3,,, Used to mark selection for clipboard.
DocColStart      D DWORD         ; Start col when left MB down. 0,1,2,,,Cols. The first selected.
DocRowStop       D DWORD         ; Stop row when left MB up.    1,2,3,,,Lines.
DocColStop       D DWORD         ; Stop col when left MB up.    0,1,2,,,Cols. The last selected.
Spaces           D 800 * B
NameUTF16::      D 800 * UNICHAR ; Temporary working space for file names in UTF-16.
NameUTF8::       D 32K * BYTE    ; Temporary working space for file names in UTF-8 and for clipboard.

[.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. Or return CF=1 when no more arguments.
    JC .40:                  ; When they are no more arguments.
    StripQuotes RSI,RCX,Unicode=yes
    SHR ECX,1                ;  Convert size from bytes to characters.
    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, Unicode=no
    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=64
    JC ErrorAlloc
    MOV [ExportBuffer::],RAX
    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

   ; Create Help window but don't show it yet.
    LEA RCX,[Help:]
    WinABI CreateWindowExA,WS_EX_OVERLAPPEDWINDOW  + WS_EX_TOPMOST + WS_EX_TRANSPARENT,  \
           =B"STATIC",RCX, WS_CHILD, \
           40,50,640,660, \
           [hWindowMain], 0, [WndClassEx.hInstance], 0
    MOV [hWindowHelp],RAX

    ; Register Find window class.
    MOVQ [WndClassEx.lpszClassName],TitleWindowFind
    MOVQ [WndClassEx.lpfnWndProc],WndProcFind
    WinABI RegisterClassExA, WndClassEx
    RET
   ENDP WndCreateMain
WndCreateFind
Register window class, create nonmodal window and all its subwindows.
Called by
MsgLoopFind.
WndCreateFind  PROC
    ; Create the Find window.
    WinABI CreateWindowExA,0,                                     \
           TitleWindowFind,=B"EuroView find",WS_OVERLAPPEDWINDOW, \
           CW_USEDEFAULT,CW_USEDEFAULT,wiFind,heFind,             \
           0, 0, [WndClassEx.hInstance], 0
    MOV [hWindowFind],RAX
    ; Create child windows of the WindowFind.
    ; Find edit.
    MOV ESI,wiFind-2*wiBorder
    WinABI CreateWindowExW,0,=U'EDIT',FindUTF8,WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
           wiBorder,wiBorder,RSI,heTitle1,[hWindowFind],0,[WndClassEx.hInstance],0
    MOV [hEditFind],RAX
    WinABI SetWindowText,RAX,FindUTF8
    WinABI SetFocus,[hEditFind]

    MOV ECX,wiFind-wiBorder-wiBtnIO
    WinABI CreateWindowExA,0,=B'BUTTON',=B"&Find",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP+BS_DEFPUSHBUTTON, \
           RCX,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnFind,[WndClassEx.hInstance],0
    MOV [hBtnFind],RAX       ; Button Find.
    WinABI CreateWindowExA,0,=B'BUTTON',=B"C&lear",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
           wiBorder+wiBtnIO+wiBorder,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnClear,[WndClassEx.hInstance],0
    MOV [hBtnClear],RAX      ; Button Clear.
    WinABI CreateWindowExA,0,=B'BUTTON',=B"&Cancel",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
           wiBorder,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnCancel,[WndClassEx.hInstance],0
    MOV [hBtnCancel],RAX     ; Button Cancel.
    RET
  ENDP WndCreateFind
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=RDX=RAX to its handler using macro Dispatch:
    Dispatch EDX, WM_VSCROLL,WM_LBUTTONDOWN,WM_LBUTTONUP,WM_RBUTTONDOWN,WM_RBUTTONUP, \
                   WM_MOUSEWHEEL,WM_MOUSEMOVE,WM_PAINT,WM_SIZE,WM_KEYDOWN,WM_DESTROY
.Def:WinABI DefWindowProc,[%hWnd],[%uMsg],[%wParam],[%lParam] ; Ignored messages go 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 helper .subprocedures for keyboard and scrollbox event handlers:

.GetCtrl2ECX: ; 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.
.GetCtrl2ECX.2:
     XOR ECX,ECX
     SAL AX,1      ; Shift MSbit to CF.
     RCL ECX,1     ; Virtual key handlers receive RCX=1 when Ctrl or Shift was pressed, otherwise RCX=0.
     RET

.GetShift2ECX: ; 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.
     JMP .GetCtrl2ECX.2:

.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:

.Mouse2Char: PROC ; Convert mouse coordinates from R9=lParam to RAX (document Row) and RDX (document Col). Clobbers RCX.
     MOV EAX,R9D             ; xPos,yPos when clicked.
     AND EAX,0xFFFF          ; xPos of the mouse click.
     XOR EDX,EDX
     MOV ECX,[cxChar]
     DIV RCX
     PUSH RAX                ; Column.
      MOV EAX,R9D            ; xPos,yPos when clicked.
      SHR EAX,16             ; yPos of the mouse click.
      XOR EDX,EDX
      MOV ECX,[cyChar]
      DIV RCX                ; RAX is vertical position in characters.
      ADD EAX,[TopLine]
     POP RDX
     RET
    ENDP .Mouse2Char:

    ; Handle messages for the main window:
.WM_PAINT:
     CALL WndPaintMain
     JMP .Ret0:
.WM_SIZE:
     CALL WndResizeMain
     JMP .Def:
.VK_TAB:                     ; Tab pressed.
     CALL .GetShift2ECX
     TEST ECX
     JZ .WM_LBUTTONUP:
.WM_RBUTTONUP:               ; Shift-Tab: Increase level.
     MOV ECX,[Level]
     CMP ECX,4
     JAE .Ret0:
     INC ECX
.LevelChanged:
     MOV [Level],ECX
     CALL WndTitle:
     WinABI InvalidateRect,[hWindowMain],0,0
.WM_RBUTTONDOWN:
     JMP .Ret0:

.WM_LBUTTONDOWN:             ; Left mouse button captures mouse and marks the text to be selected for clipboard.
     MOV ECX,[Level]
     JRCXZ .SelectionStart:
     JMP .WM_RBUTTONDOWN:  ; Do nothing when Level above 0.   WM_LBUTTONUP will decrease it.
.SelectionStart:
     SetSt [Status::],ArgMouseCaptured
     CALL .Mouse2Char:
     XOR ECX,ECX
     MOV [DocRowStop],ECX
     MOV [DocColStop],ECX
     MOV [DocRowStart],EAX
     MOV [DocColStart],EDX
     JMP .Ret0:

.WM_LBUTTONUP:               ; Decrease level. At Level=0, start or stop selection by mouse.
     MOV ECX,[Level]
     JRCXZ .Selection:
     DEC ECX
     JMP .LevelChanged:
.Selection:
     RstSt [Status::],ArgMouseCaptured
     CALL .Mouse2Char:
     CMP EAX,[DocRowStart]   ; Swap so DocStop is always greater than DocStart.
     JAE .Se2:
     XCHG EAX,[DocRowStart]
.Se2:MOV [DocRowStop],EAX
     CMP EDX,[DocColStart]
     JAE .Se4:
     XCHG EDX,[DocColStart]
.Se4:MOV [DocColStop],EDX
     WinABI InvalidateRect,[hWindowMain],0,0
     JMP .Ret0:

.WM_MOUSEMOVE:
     JNSt [Status::],ArgMouseCaptured, .Def:
     CALL .Mouse2Char:
     CMP EAX,[DocRowStart]
     JA .M2:
     XCHG EAX,[DocRowStart]
.M2: CMP EDX,[DocColStart]
     JA .M4:
     XCHG EDX,[DocColStart]
.M4: MOV [DocRowStop],EAX
     MOV [DocColStop],EDX
     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,'C','F',VK_F7,'N',VK_F3,'P',VK_RETURN
     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]  ; Open file.
     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:

.C:  CALL .GetCtrl2ECX:      ; Returns RCX=1 when Ctrl is pressed.
     TEST ECX
     JZ .Def:
     CALL Copy2Clipboard:
     JMP .Ret0:
.F:                                    ; Key F (Find) pressed.
.VK_F7:
     WinABI IsWindow,[hEditFind]
     JZ .F3:
     WinABI PostMessage,[hEditFind],EM_SETSEL,0,-1  ; Select all.
.F3: WinABI SetFocus,[hEditFind]
     CALL MsgLoopFind
     CALL WndTitle
.Inv:WinABI InvalidateRect,[hWindowMain],0,0
     JMP .Ret0:

.N:
.VK_F3:
     CALL .GetShift2ECX:   ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
     JRCXZ .N1:
     JMP .P:
.N1: MOV EDX,[Level]
     BufferRetrieve [Level0Buffer::+8*RDX]  ; SIZE# LST_INDEX=8
     MOV R10,RSI
     MOV EDX,[TopLine]                      ; 1,2,3,,,Lines.
.N2: CMP EDX,[Lines]
     JNB .Ret0:
     LEA RSI,[R10+8*RDX]                    ; SIZE# LST_INDEX=8
     LODSD
     LODSD
     INC EDX
     SHR EAX,24
     JZ .N2:
     MOV [TopLine],EDX
     WinABI InvalidateRect,[hWindowMain],0,0
     JMP .Ret0:

.P:  MOV EDX,[Level]                        ; Key P pressed.
     BufferRetrieve [Level0Buffer::+8*RDX]  ; SIZE# LST_INDEX=8
     MOV R10,RSI
     MOV EDX,[TopLine]
.P2: DEC EDX
     JS .Ret0:
     MOV [TopLine],EDX
     LEA RSI,[R10+8*RDX]
     LODSD
     LODSD
     SHR EAX,24
     JZ  .P2:
     WinABI InvalidateRect,[hWindowMain],0,0
     JMP .Ret0:

.VK_RETURN:
    WinABI IsWindowVisible,[hEditFind]
    TEST RAX
    JZ .Ret0:
    WinABI GetWindowTextA,[hEditFind],FindUTF8,254
    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 .43:
    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.
    MOV [IndexBegin],RSI
    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.
    MOV [IndexBegin],RSI
    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:

.43:; Level EAX is unchanged.
    BufferRetrieve [Level0Buffer::+8*RAX] ; RSI,RCX are LST_INDEX records.
    MOV [IndexBegin],RSI
    SHR ECX,3                          ; SIZE# LST_INDEX = 8
    MOV [Lines],ECX
    MOV EDI,[TopLine]
    CMP EDI,[Lines]
    JBE .47:
    MOV EDI,[Lines]
.47:MOV [TopLine],EDI
    WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,-1
    SUB RSI,SIZE# LST_INDEX
    XOR EDX,EDX
.50:INC EDX                            ; RDX is line number 1,2,3,,,Lines.
    ADD RSI,SIZE# LST_INDEX
    CMP EDX,EDI                        ; Reached TopLine?
    JB .50:
    MOV R14D,[Rows]                    ; R14 is number of rows on screen.
    CMP EDX,[Lines]                    ; Reached the end of lines?
    JA .80:
    MOV R15D,[AddressDigits::]         ; 4..8.
    ADD R15D,38                        ; R15 is the number of gray characters in dump, including address and |.
.55:; Display lines indexed by RSI=LST_INDEX until EDX>[Lines] (out of lines) or until R14=0 (all rows displayed).
    LODSD                              ; LST_INDEX.FA
    LEA RBX,[R12+RAX]                  ; RBX is now pointer to the line in mapped listing. R12 is OutputPtr.
    LODSD                              ; LST_INDEX.Size + shifted FoundOffset, if found on this line.
    MOV ECX,EAX
    SHR ECX,24                         ; ECX is now offset of found string in the line RBX.
    MOV [FoundOffset],ECX
    AND EAX,NoFlags                    ; Get rid of FAFound bits.
    MOV ECX,EAX                        ; RCX is line size in bytes, without spaces.
    MOV EDX,[cxChar]                   ; Width of one character in pixels.
    MUL RDX                            ; RAX is line width in pixels, without spaces.
    MOV R13,RAX                        ; R13 is cxWindow at the start of spaces.
    MOV EDI,[Cols]                     ; RDI is columns in the window, including padding spaces.
    SUB EDI,ECX                        ; EDI is the number of spaces following the remark in listing line.
    MOV EAX,Color4
    CMPD [RBX+1],'####'
    JE .60:
    MOV EAX,Color3
    CMPB [RBX+3],'#'
    JE .60
    MOV EAX,Color2
    CMPW [RBX+1],'##'
    JE .60:
    MOV EAX,Color1
    CMPB [RBX+1],'#'
    JE .60:

    ; Current line is dump line Level0 , gray 38+AddressDigits chars wide, plus color Remark + same color spaces.
    ; Example of a line:   gray column         | color column                                 remark         Spaces_to_pad_the_line
    ;|0000:7F454C46 020100100 00000000 00000000| DD 0x464C457F,0x00010102,0x000000,0x000000 ; Signature ELF64______________________
    ; Line is mapped in memory at RBX,RCX. Its index is RSI.
    PUSH RCX                           ; Number of characters in this listing line, without padding spaces.
     WinABI SetBkColor,[hDC],ColorDump ; Level0 gray column.  ; R15 is size of gray characters between | |.
     WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,R15 ; Display gray part of the line pointed to with RBX.
     WinABI SetBkColor,[hDC],ColorRem  ; Yellish color.
     ADD RBX,R15                       ; Add the width of the dump column. RBX points to the remark.
     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 .65:
    WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX ; Print the remark.
    JMP .65:

.60:; Current line is Level1, Level2, Level3 or Level4 in color EAX. No gray column.
    WinABI SetBkColor,[hDC],RAX        ; RAX is LevelX color.
    WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,RCX ; Display RCX characters at RBX.
.65:WinABI TextOutA,[hDC],R13,[cyWindow],Spaces,RDI     ; Display EDI spaces on the same line as padding.
    ; Line is now displayed, but without the found string and without the selected string.
    MOV ECX,[FoundOffset]              ; 0 (nothing found) or 1,2,3,,, for offset 0,1,2,,,
    TEST ECX,ECX
    JZ .70:                            ; Skip when the string was not found in this line.
    ; Display the found string again in different color TextColorFound+BkColorFound.
    WinABI GetTextColor,[hDC]
    MOV R10,RAX
    WinABI SetBkColor,[hDC],BkColorFound ; Bright white.
    WinABI SetTextColor,[hDC],TextColorFound
    MOV EBX,[RSI-SIZE# LST_INDEX+LST_INDEX.FA] ; Offset of the start of the line again.
    MOV ECX,[FoundOffset]              ; Offset 1,2,3,,,  again.
    DEC ECX
    ADD EBX,ECX                        ; Offset of the start of the found string.
    ADD RBX,R12                        ; Start of the found string in line RBX. R12 is OutputPtr.
    MOV EDX,[cxChar]                   ; Width of one character in pixels.
    MOV EAX,[FoundOffset]              ; Number of bytes from the start of line.
    DEC EAX
    MUL EDX
    ADD EAX,[cxWindow]
    MOV ECX,[FindUTF8Size]
    WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX ; Display the found string in magenta on white.
    WinABI SetTextColor,[hDC],R10      ; Restore original text color.
.70:; Check if the current line indexed by RSI will match Doc* (specified by left button mouse capture).
    ; In this case display the selected string again with TextColorSelected+BkColorSelected.
    MOV RAX,RSI                        ; Get current line number.
    SUB RAX,[IndexBegin]
    SHR EAX,3                          ; EAX is now this line number (0..Lines).
    CMP EAX,[DocRowStart]
    JB .78:
    CMP EAX,[DocRowStop]
    JA .78:
    ; This line RSI is selected. Display again the selected text between [DocColStart]..[DocColStop].
    WinABI GetTextColor,[hDC]
    MOV R10,RAX
    WinABI SetBkColor,[hDC],BkColorSelected
    WinABI SetTextColor,[hDC],TextColorSelected
    MOV EBX,[DocColStart]              ; 0,1,2,,,Cols.
    MOV ECX,[DocColStop]               ; 0,1,2,,,Cols.
    MOV EAX,[RSI-SIZE# LST_INDEX+LST_INDEX.Size]
    AND EAX,NoFlags
    CMP EAX,ECX
    JA .73:
    MOV ECX,EAX
.73:                                   ; RCX is the smaller of DocColStop and line size.
    MOV EAX,[cxChar]
    MUL RBX
    MOV EBX,[RSI - SIZE# LST_INDEX + LST_INDEX.FA]
    MOV EDX,[DocColStart]
    ADD EBX,EDX
    SUB ECX,EDX
    ADD RBX,R12                        ; R12=OutputPtr.
    INC ECX
    WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX
    WinABI SetTextColor,[hDC],R10      ; Restore original text color.
.78:MOV EAX,[cyChar]                   ; Height of one character in pixels.
    ADD [cyWindow],EAX
    DEC R14                            ; Number of remaining rows on screen.
    JNZ .55:
.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, Level or Find string changes.
The new title is constructed in NameUTF8, e. g.: EuroView "input.bin" as ELFX64 level 0. Found 0× "" and then converted to UTF-16 for SetWindowTextW.
Input
FormatNamePtr::, Level, FileInput.Name, FoundCnt, FindUTF8.
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,8
    REP MOVSB
    MOV AL,'0'
    OR AL,[Level]
    STOSB
    LEA RSI,[=B', found ']
.65:LODSB
    CMP AL,0
    JE .70:
    STOSB
    JMP .65:
.70:MOV EAX,[FoundCnt]
    StoD RDI
    MOV EAX,0x222097C3       ; × "     in UTF-8.
    STOSD
    LEA RSI,[FindUTF8]
.75:LODSB
    CMP AL,0
    JE .78:
    STOSB
    JMP .75:
.78:MOV AX,'"'
    STOSW                      ; Copy FindUTF8 to NameUTF8.
    MOV RCX,RDI
    LEA RSI,[NameUTF8]
    SUB RCX,RSI
    LEA RDI,[NameUTF16]
    WinABI MultiByteToWideChar,65001,0,RSI,RCX,RDI,SIZE# NameUTF16 /2 ; Convert NameUTF8 to NameUTF16.
    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 encoded in UTF-8) 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.
Called by
ViewEpilogue
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
WndProcFind, hWnd, uMsg, wParam, lParam
This is a callback procedure which receives and handles messages for the WindowFind.
Window Find has EDIT field for the searched text and buttons [Cancel], [Clear], [Find].
Handler input
RCX=[%hWnd] is the main window handle (the same as static [hWindowArg].
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.
WndProcFind Procedure hWnd, uMsg, wParam, lParam ; These parameters are provided in RCX,RDX,R8,R9.
    SaveToShadow
    Uses RBX,RSI,RDI,R12,R13,R14,R15 ; It's only necessary if some of callee-save registers was used in this fastcalled procedure.
    CALL .GetShift2ECX:
    ; Fork message uMsg=RDX to its handler using macro Dispatch:
     Dispatch EDX, WM_DESTROY, WM_SIZE, WM_KEYDOWN, WM_SYSKEYDOWN, WM_COMMAND
.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:.
.GetShift2ECX PROC ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
     WinABI GetAsyncKeyState,VK_SHIFT  ; 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
.WM_SIZE:
     CALL WndResizeFind
     JMP .Ret0:
.WM_KEYDOWN:                 ; Non-character hot key R8D=wParam was pressed.
     Dispatch R8D, VK_ESCAPE,VK_RETURN,VK_TAB,'C','L','F'
     JMP .Def:               ; Pass unhandled keys to WinABI DefWindowProc.
.WM_SYSKEYDOWN:              ; A key pressed together with Alt.
     Dispatch R8D,'C','L','F',VK_RETURN,VK_ESCAPE
     JMP .Def:               ; Pass unhandled keys to WinABI DefWindowProc.
.WM_COMMAND:                 ; Window element Id=LOWORD R8 was activated.
     MOVZX EDX,R8W
     Dispatch EDX,IdBtnFind, IdBtnClear, IdBtnCancel
    JMP .Def:                ; Let other commands handle by DefWindowProc().
.VK_TAB:
    TEST ECX
    JZ .Back:
    WinABI SetFocus,[hBtnFind]
    JMP .Def:
.L:                          ; Hotkey 'L' pressed.
.IdBtnClear:                 ; Button Clear clicked.
    MOVB [FindUTF8],0
    WinABI SetWindowTextA,[hEditFind],FindUTF8
    CALL Search
    CALL WndTitle
    WinABI SetFocus,[hEditFind]
    JMP .Ret0:

.Back:WinABI SetFocus,[hEditFind] ; Shift-Tab pressed inside Find dialog.
    JMP .Def:

.VK_RETURN:                  ; Enter pressed.
.F:                          ; Hotkey 'F' pressed.
.IdBtnFind:                  ; Button Find clicked.
     LEA RDI,[FindUTF8]
     WinABI GetWindowTextA,[hEditFind],RDI,MAX_PATH_SIZE
     CALL Search
     CALL WndTitle
     WinABI InvalidateRect,[hWindowMain],0,0
.C:                          ; HotKey 'C' pressed (Cancel).
.IdBtnCancel:                ; Button Cancel clicked.
.VK_ESCAPE:                  ; Terminate thread.
.WM_DESTROY:                 ; Thread terminates.
     WinABI ShowWindow,[hWindowFind],SW_HIDE
.Ret0:XOR EAX,EAX            ; RAX=0 signalizes that the message was processed here.
.Ret:EndProcedure WndProcFind
WndResizeFind
Dimensions of WindowFind changed.
WndResizeFind PROC
    LEA RBX,[RectWindowMain]
    WinABI GetWindowRect,[hWindowFind],RBX
    MOV ESI,[RBX+RECT.left]
    MOV ECX,[RBX+RECT.right]
    SUB ECX,ESI
    MOV [WindowFindWidth],ECX
    MOV EDI,[RBX+RECT.top]
    MOV EDX,[RBX+RECT.bottom]
    SUB EDX,EDI
    CMP EDX,120
    JA .20:
    MOV EDX,120
.20:WinABI MoveWindow,[hWindowFind],RSI,RDI,RCX,RDX,-1
    MOV ESI,[WindowFindWidth]; Button input file select.
    SUB ESI,3*wiBorder
    WinABI MoveWindow,[hEditFind],wiBorder,wiBorder,RSI,heTitle1,1
    SUB ESI,wiBtnIO          ; Button Find.f
    WinABI MoveWindow,[hBtnFind],RSI,yFindButton,wiBtnIO,heBtnIO,1
   RET
ENDP WndResizeFind
Search PROC
    LEA RDI,[FindUTF8]
    MOV [FoundCnt],0
    GetLength$ RDI
    MOV [FindUTF8Size],ECX
    JRCXZ .90:
    XOR R11,R11                        ; FoundCnt.
    MOV AL,[RDI]                       ; 1st byte of the needle.
    LEA R8,[RDI+1]                     ; R8 is pointer to 2nd byte of the needle.
    LEA R9,[RCX-1]                     ; R9 is size of the needle - 1.
    MOV RBX,[Level0Buffer]
    CALL .SearchBuffer
    MOV [FoundCnt],R11D
    MOV RBX,[Level1Buffer]
    CALL .SearchBuffer
    MOV RBX,[Level2Buffer]
    CALL .SearchBuffer
    MOV RBX,[Level3Buffer]
    CALL .SearchBuffer
    MOV RBX,[Level4Buffer]
    CALL .SearchBuffer
.90:RET

.SearchBuffer PROC ; RBX=^Buffer
    BufferRetrieve RBX
    LEA RDX,[RSI+RCX]
    SUB RSI,SIZE#LST_INDEX
.1: ADD RSI,SIZE#LST_INDEX
    CMP RSI,RDX
    JNB .9:
    MOV EDI,[RSI+LST_INDEX.FA]         ; Offset from OutputPtr.
    MOV ECX,[RSI+LST_INDEX.Size]
    ADD RDI,[OutputPtr]
    AND ECX,NoFlags
    MOV [RSI+LST_INDEX.Size],ECX
    LEA R10,[RDI+RCX]                  ; R10 is pointer to the end of line.
.3: REPNE SCASB                        ; Search for 1st byte of the needle.
    JNE .1:
    TEST R9
    JZ .6:
    PUSH RCX,RSI,RDI
      LEA RSI,[RDI+R9]                 ; RSI is temporary pointer to the end of needle.
      CMP RSI,R10
      JA .5:                           ; Needle oversizes end of line. Not found.
      MOV RSI,R8                       ; Pointer to 2nd byte of needle.
      MOV RCX,R9                       ; Size of needle - 1.
      REPE CMPSB
.5: POP RDI,RSI,RCX
    JNE .3:                            ; Go to continue the search of 1st byte.
.6: DEC RDI                            ; Pointer to needle found,
    SUB RDI,[OutputPtr]                ; Offset from start of file.
    SUB RDI,[RSI+LST_INDEX.FA]
    INC EDI                            ; Offset + 1.
    SHL EDI,24                         ; Offset+1 from the start of line.
    OR [RSI+LST_INDEX.Size],EDI
    INC R11                            ; FoundCnt.
    JMP .1:
.9: RET
   ENDP .SearchBuffer
  ENDP Search
MsgLoopFind
Message handling procedure of child window for getting the searched text.
MsgLoopFind PROC
     WinABI IsWindow,[hWindowFind]
     TEST EAX
     JNZ .10:
     CALL WndCreateFind                ; Window for retrieving searched text.
.10: WinABI PostMessage,[hEditFind],EM_SETSEL,0,-1  ; Select all searched string..
     WinABI ShowWindow,[hWindowFind],SW_SHOW
     WinABI UpdateWindow,[hWindowFind]
.MsgLoop:
     WinABI GetMessage, Msg,0,0,0
     TEST RAX
     JZ .MsgQuit:                      ; ZF signalizes message WM_QUIT - request for cancel and termination.
     CMPD [Msg.wParam],VK_ESCAPE
     JNE .30:
     WinABI PostMessage,[hWindowFind],WM_KEYDOWN,VK_ESCAPE,0
     JMP .MsgQuit:
.30: CMPD [Msg.wParam],VK_RETURN
     JNE .40:
     WinABI PostMessage,[hWindowFind],WM_KEYDOWN,VK_RETURN,0
     WinABI PostMessage,[hWindowMain],WM_KEYDOWN,0x4E,0 ; Simulate key "N".
     JMP .MsgQuit:
.40: WinABI IsDialogMessage,[hWindowFind],Msg     ; Let Windows handle TAB keys.
     TEST RAX
     JNZ .MsgLoop:
.50: WinABI TranslateMessage, Msg      ; Remap character keys from national keyboards.
     WinABI DispatchMessage,  Msg      ; Let Windows call our WndProc.
     JMP .MsgLoop:                     ; Wait for another message.
.MsgQuit:
     WinABI ShowWindow,[hWindowFind],SW_HIDE
     XOR EAX,EAX
     RET                               ; Return to CUI module.
   ENDP MsgLoopFind
Copy2Clipboard
Copy the rectangular selected text identified with [DocRowStart],[DocColStart]..[DocRowStop],[DocColStop] from OutpuFile to NameUTF8 and then to Windows clipboard.
Input
R12= OutputPtr of listing mappend in memory.
[DocRowStart],[DocColStart]..[DocRowStop],[DocColStop] identifies selected text.
Copy2Clipboard PROC
     MOV R12,[OutputPtr::]
     BufferRetrieve [Level0Buffer]     ; Get the buffers contents to RSI,RCX.
     MOV R8,RSI                        ; R8=RSI now points to an array of LST_VIEW records.
     LEA RDI,[NameUTF8]                ; RDI points to a temporary buffer which will concatenate selected text.
     MOV R10D,[DocRowStart]            ; R10D will grow from DocRowStart to DocRowStop.
     LEA R9,[RDI+SIZE# NameUTF8]       ; R9 points at the end of temporary buffer.
.10: CMP RDI,R9
     JNB .50:
     MOV EAX,R10D                      ; Line number, starting with DocRowStart (0,1,2,,,DocRowStop).
     CMP EAX,[DocRowStop]
     JA .50:
     DEC EAX
     MOV EBX,[R8+8*RAX+LST_INDEX.FA]   ; EBX is file address of the selected line.
     MOV EAX,[R8+8*RAX+LST_INDEX.Size]
     AND EAX,NoFlags                   ; EAX is size of the selected line.
     LEA RSI,[R12+RBX]                 ; R12 is pointer to memory-mapped lines.
     MOV EDX,[DocColStart]             ; Entire selected line is RSI,RAX.
     MOV ECX,[DocColStop]
     INC ECX
     CMP EAX,ECX
     JA .30:
     XCHG EAX,ECX
.30: SUB ECX,EDX                        ; ECX is the less of EAX,ECX.
     JNA .50:
     ADD RSI,RDX
     REP MOVSB
     MOV AX,0x0A0D
     STOSW
     INC R10D
     JMP .10:
.50: XOR EAX,EAX                       ; End of concatenation.
     STOSB
     MOV R12,RDI
     LEA RSI,[NameUTF8]
     SUB R12,RSI                       ; R12 is size of the string.
     WinABI GlobalAlloc,GMEM_FIXED|GMEM_SHARE,R12
     TEST RAX
     JZ .90:
     MOV R13,RAX
     WinABI GlobalLock,RAX
     MOV RDI,RAX
     MOV RCX,R12
     REP MOVSB
     WinABI GlobalUnlock,R13
     WinABI OpenClipboard,[hWindowMain]
     WinABI EmptyClipboard
     WinABI SetClipboardData,CF_TEXT,R13
     TEST RAX
     JNZ .80:
     WinABI GlobalFree,R13
.80: WinABI CloseClipboard
.90: RET
 ENDP Copy2Clipboard
%IF %^Debug
  INCLUDE1 winabi.htm
 DebugOutput proc
   StdOutput rsi,Size=rcx
   ret
 ENDP DebugOutput
%ENDIF
  ENDPROGRAM viewwing

▲Back to the top▲