Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Large File Viewer

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin Large File Viewer

    Version 2.3 of large file viewer


    Code:
    '***********************************************************************************************
    ' To Do:
    
    '***********************************************************************************************
    '***********************************************************************************************
    ' check if last line is to long and split, if no delimiter is at the end -> ok
    ' improve navigation speed while indexing -> ok
    ' caret hickup with small files (1 or two lines) -> ok
    ' if last line doesn´t end with a delimiter, it is skipped !!! -> ok
    
    
    ' better formatting of hexview output -> ok
    ' caption records (16 byte), tlc, scrollbar sfy_t/h, -> ok
    ' updatecaret -> ok evtl. in dec (hex ist schon da) -> ok
    
    ' selection byte based instead of line based -> ok (keys
    ', gosub for selection -> ok
    ' make it all zerobased, sel must not be higer than filelenght + 1 -> ok ?
    ' check transition between chunks -> ok
    ' mouse selection -> ok
    ' test hex -> ok ?
    ' goto, find, selection -> ok
    ' copy with fileoffset and line # -> ok
    ' copy to file                    -> ok
    ' keep position when switching text/hex, store byte position and convert to topline -> ok
    ' coffset with find/goto -> ok
    ' eingabe check, not valid -> select -> ok
    ' tlc problem 111 zu viel !!! wieso ??? catch with befor/after compare + msgbox -> ok
    ' hex selection -> ok
    ' topline, size change !!! -> ok
    
    '***********************************************************************************************
    ' scrollbar
    '***********************************************************************************************
    ' scrollbar body click scrolls the more the more total lines there are
    ' thumb may have about 1000 different positions (y screen width = 1024)
    ' y scroll range -> 10000 would be sufficient
    ' for 100M lines this means 100,000 lines per minimum thumb move (1 pixel)
    ' 1000 lines with page up/down key is ok
    ' so 1000 lines per body click, would give enough resolution for 100M lines
    ' adjust this value for smaller line counts (minimum 1, 2 for 100 lines, etc)
    '***********************************************************************************************
    '***********************************************************************************************
    ' limitations:
    ' filesize    = quad (2^64 - 1)
    ' find count  = long (2^32/2)
    '***********************************************************************************************
    '***********************************************************************************************
    
    
    #UTILITY version
    #COMPILER PBWIN 10
    #DIM ALL
    
    #COMPILE EXE "fileviewer.exe"
    #RESOURCE "fileviewer.pbr"
    #INCLUDE ONCE "Win32API.inc"
    
    
    '* FILE
    %IDM_OPEN           = 6000
    
    %IDM_CRLF           = 6001
    %IDM_CR             = 6002
    %IDM_LF             = 6003
    %IDM_ASCII          = 6004
    %IDM_HEX            = 6005
    %IDM_EXIT           = 6009
    '
    '* EDIT
    %IDM_COPY           = 6010
    %IDM_COPYFILE       = 6015
    %IDM_GOTO           = 6011
    %IDM_FIND           = 6012
    %IDM_FINDNEXT       = 6013
    %IDM_FINDPREV       = 6014
    '
    '* HEXVIEW
    %IDM_HEXVIEW        = 6020
    
    '* HELP
    %IDM_HELP           = 6090
    %IDM_ABOUT          = 6091
    %IDM_MEM            = 6092
    
    
    %mg       = 5                                         'margin (pixel offset for drawing)
    %partsize = 1000000                                   'must not be larger than long range (and be smaller than 1000)
    %max_line = 1000                                      'restrict line and wrap on this position
    
    '***********************************************************************************************
    ' could avoid these globals of course, but as this is small project who cares ...
    '***********************************************************************************************
    
    GLOBAL hinst    AS DWORD                              'instance handle
    GLOBAL hstatus  AS DWORD                              'window handles ...
    GLOBAL hwndmain AS DWORD
    GLOBAL hwnde    AS DWORD
    GLOBAL hwndc    AS DWORD
    
    GLOBAL oldeditproc   AS DWORD                         'subclassing
    GLOBAL oldstatusproc AS DWORD
    
    
    GLOBAL f$                                             'file to display
    GLOBAL delimiter AS STRING
    
    GLOBAL smemh   AS DWORD                               'memory handle
    GLOBAL smemb   AS DWORD                               'begin
    GLOBAL smeml   AS DWORD                               'length
    
    GLOBAL smemh1  AS DWORD                               'handle
    GLOBAL smemb1  AS DWORD                               'begin
    GLOBAL smeml1  AS DWORD                               'length
    
    
    GLOBAL p()     AS QUAD                                'array of chunk pointers
    GLOBAL p1()    AS DWORD                               'array of line #
    
    GLOBAL l()     AS DWORD                               'array of line pointers
    GLOBAL lmax    AS DWORD                               'char count of longest line
    GLOBAL lc      AS DWORD                               'line count
    GLOBAL tlc     AS QUAD                                'total line count
    GLOBAL tlc_t   AS QUAD                                'total line count (text)
    GLOBAL tlc_h   AS QUAD                                'total line count (hex)
    GLOBAL pc      AS DWORD                               'parts count
    GLOBAL loffset AS QUAD                                'line offset
    GLOBAL foffset AS QUAD                                'fileoffset
    GLOBAL cp      AS DWORD                               'current part
    
    GLOBAL sfy     AS SINGLE                              'scroll factor y
    GLOBAL sfy_t   AS SINGLE                              'scroll factor y (text)
    GLOBAL sfy_h   AS SINGLE                              'scroll factor y (hex)
    
    GLOBAL fnd$                                           'find string
    GLOBAL fc      AS LONG                                'find count
    GLOBAL ff()    AS QUAD                                'found array (fileoffset)
    
    GLOBAL hexflag AS DWORD                               '0=standart, 1=Hexview
    
    
    TYPE PROCESS_MEMORY_COUNTERS DWORD
       cb                         AS DWORD   ' DWORD
       PageFaultCount             AS DWORD   ' DWORD
       PeakWorkingSetSize         AS DWORD   ' SIZE_T
       WorkingSetSize             AS DWORD   ' SIZE_T
       QuotaPeakPagedPoolUsage    AS DWORD   ' SIZE_T
       QuotaPagedPoolUsage        AS DWORD   ' SIZE_T
       QuotaPeakNonPagedPoolUsage AS DWORD   ' SIZE_T
       QuotaNonPagedPoolUsage     AS DWORD   ' SIZE_T
       PagefileUsage              AS DWORD   ' SIZE_T
       PeakPagefileUsage          AS DWORD   ' SIZE_T
    END TYPE
    
    
    DECLARE FUNCTION GetProcessMemoryInfo LIB "PSAPI.DLL" ALIAS "GetProcessMemoryInfo" ( _
       BYVAL hProcess AS DWORD _                            ' __in HANDLE hProcess
     , BYREF ppsmemCounters AS PROCESS_MEMORY_COUNTERS _    ' __out PPROCESS_MEMORY_COUNTERS ppsmemCounters
     , BYVAL cb AS DWORD _                                  ' __in DWORD cb
     ) AS LONG                                              ' BOOL
    
    
    '***********************************************************************************************
    '***********************************************************************************************
    
    
    SUB CenterWindow(BYVAL hWnd AS LONG)
    '***********************************************************************************************
    ' center this window in apps client space
    '***********************************************************************************************
    LOCAL WndRect AS RECT
    LOCAL r       AS rect
    LOCAL x       AS LONG
    LOCAL y       AS LONG
    
    
      GetWindowRect hWnd, WndRect
      GetWindowRect hWndmain, r
    
      x = r.nleft+((r.nright-r.nleft)\2)-((WndRect.nRight-WndRect.nLeft)\2)
      y = r.ntop+((r.nbottom-r.ntop)\2)-((WndRect.nBottom-WndRect.nTop)\2)
    
      SetWindowPos hWnd, %NULL, x, y, 0, 0, %SWP_NOSIZE OR %SWP_NOZORDER
    
    
    END SUB
    
    
    '***********************************************************************************************
    
    
    FUNCTION AboutProc(BYVAL hDlg AS LONG, BYVAL wMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    '***********************************************************************************************
    ' about callback
    '***********************************************************************************************
    LOCAL hDC      AS LONG
    LOCAL r        AS RECT
    LOCAL LpPaint  AS PaintStruct
    
    
      SELECT CASE wMsg
        CASE %WM_INITDIALOG
          SetTimer(hDlg, 113, 5000, BYVAL %NULL)          'show for 5 seconds, then close again
          centerwindow hdlg                               'center in main window
          EnableWindow hWndMain, %FALSE
          FUNCTION = 1
          EXIT FUNCTION
    
    
        CASE %WM_TIMER
          SendMessage hDlg, %WM_COMMAND, %IDOK, %NULL
    
    
        CASE %WM_COMMAND
          SELECT CASE LOWRD(wParam)
            CASE %IDCANCEL
              KillTimer %NULL, 113
              EndDialog hDlg, 0                           'exit
              EnableWindow hWndMain, %TRUE
              FUNCTION = 1
    
            CASE %IDOK, 101
              KillTimer %NULL, 113
              EndDialog hDlg, 1                           'exit
              EnableWindow hWndMain, %TRUE
              FUNCTION = 1
    
          END SELECT
    
    
        CASE %WM_PAINT                                    'draw some colored text
          hDC = BeginPaint(getdlgitem(hdlg,100), LpPaint)
            GetclientRect getdlgitem(hdlg,100), r
            SetBkMode hDC, %TRANSPARENT
            SetTextColor hDC, %CYAN
            r.nleft=r.nleft+1
            r.ntop=r.ntop+2
            DrawText hDC, "Large File Viewer", -1, r, %DT_SINGLELINE
            SetTextColor hDC, %MAGENTA
            r.nleft=r.nleft-1
            r.ntop=r.ntop-2
            DrawText hDC, "Large File Viewer", -1, r, %DT_SINGLELINE
          EndPaint getdlgitem(hdlg,100), LpPaint
    
    
          FUNCTION = 0
          EXIT FUNCTION
    
      END SELECT
    
    
    END FUNCTION
    
    
    '*************************************************************************************************
    
    
    FUNCTION MainProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG
    '*************************************************************************************************
    ' Main window procedure, handle everything except for text window´s internals (see childproc)
    '*************************************************************************************************
    LOCAL pDis    AS DRAWITEMSTRUCT PTR
    LOCAL hbr     AS DWORD
    LOCAL mm      AS minmaxinfo PTR
    LOCAL pmc     AS PROCESS_MEMORY_COUNTERS
    LOCAL hthread AS DWORD
    LOCAL hicon   AS LONG
    LOCAL t       AS ASCIIZ * 50
    LOCAL s       AS systemtime
    LOCAL r       AS rect
    LOCAL r1      AS rect
    LOCAL si      AS sizel
    LOCAL hdc     AS DWORD
    LOCAL d$
    
    STATIC zText  AS ASCIIZ * 255
    STATIC sp     AS LONG                                 'scan percent
    STATIC st()   AS LONG                                 'array for statusbar parts
    STATIC st1    AS DWORD
    STATIC st2    AS DWORD
    STATIC st3    AS DWORD
    STATIC cf     AS LONG                                 'current find
    STATIC cwp    AS DWORD PTR
    
    
      SELECT CASE AS LONG wMsg
        CASE %WM_CREATE                                   'creation of the main window
          InitCommonControls
    
          DIM   st(3)                                     'st(3) => 4 elements, zerobased !
    
          hstatus = CreateStatusWindow(%WS_CHILD OR %WS_BORDER OR _
                                         %WS_VISIBLE OR %SBS_SIZEGRIP, _
                                         "", hWnd, 200)
    
          sendmessage hstatus, %SB_SETPARTS, 4, VARPTR(st(0))                 'set 4 parts (all array values are zero)
                                                          'statusbar is sized correctly with WM_Size
    
          t=MID$(DATE$,4,2)+"."+MID$(DATE$,1,2)+"."+MID$(DATE$,7,4)
          CALL getlocaltime(s)
    
          SELECT CASE s.wdayofweek
            CASE 0
              t="  Su. "+t
            CASE 1
              t="  Mo. "+t
            CASE 2
              t="  Tu. "+t
            CASE 3
              t="  We. "+t
            CASE 4
              t="  Th. "+t
            CASE 5
              t="  Fr. "+t
            CASE 6
              t="  Sa. "+t
          END SELECT
    
          sendmessage hstatus, %SB_SETTEXT, 2, VARPTR(t)  'set date part
    
          settimer hwnd, 111, 100, BYVAL 0
    
          hicon=loadimage(hinst, "zclock", %Image_Icon, 14, 14, %LR_LOADMAP3DCOLORS)
          sendmessage hstatus, %SB_SETICON, 3, hicon
          hicon=loadimage(hinst, "zcal", %Image_Icon, 14, 14, %LR_LOADMAP3DCOLORS)
          sendmessage hstatus, %SB_SETICON, 2, hicon
    
          hdc=getdc(hstatus)
          selectobject hdc, sendmessage(hstatus, %WM_Getfont, 0, 0)
          t = " 00:00:00   "                              'sample text
          CALL gettextextentpoint32(hdc, t, LEN(t), si)   'get appropriate width for text
          st1 = si.cx + 16 + 16                           'text + icon + sizegrip
          t = " We. 01.01.2000    "                        'sample text
          CALL gettextextentpoint32(hdc, t, LEN(t), si)   'get appropriate width for text
          st2 = si.cx + 16                                'text + icon
          t = " 0x00_00000000  :  00,000,000,000  "       'sample text
          CALL gettextextentpoint32(hdc, t, LEN(t), si)   'get appropriate width for text
          st3 = si.cx                                     'text
          releasedc hstatus, hdc
    
    
          delimiter=$CRLF
          checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_CHECKED)
    
          IF LEN(COMMAND$) THEN
            f$=TRIM$(COMMAND$(1), ANY CHR$(34)+" ")
    
            IF ISFILE(f$) THEN
              postmessage hwnd, %WM_COMMAND, 5000, 0
            END IF
          END IF
    
    
        CASE %WM_getminmaxinfo
           mm = lparam
           IF hexflag=1 THEN
             @mm.ptMinTrackSize.x = @cwp*88+getsystemmetrics(%SM_cxVscroll)
             @mm.ptMaxTrackSize.x = @cwp*88+getsystemmetrics(%SM_cxVscroll)
           ELSE
             @mm.ptMinTrackSize.x = getsystemmetrics(%SM_cxScreen)/2
           END IF
           @mm.ptMinTrackSize.y = getsystemmetrics(%SM_cyScreen)/3
    
           FUNCTION=0
           EXIT FUNCTION
    
    
        CASE %WM_DRAWITEM                                 'ownerdraw
          pDis = lparam
          IF @pdis.ctlid=200 THEN                         'for statusbar
            sendmessage hstatus, %SB_Getrect, 1, VARPTR(r)                    'get to draw in
    
    DIM vert(1) AS TRIVERTEX
    DIM gRect AS GRADIENT_RECT
    
            vert(0).x      = 0
            vert(0).y      = 0
            IF @pdis.itemdata = 0 THEN
              vert(0).Red    = 100*256
              vert(0).Green  = 255*256
              vert(0).Blue   = 100*256
            ELSE
              vert(0).Red    = 255*256
              vert(0).Green  = 150*256
              vert(0).Blue   = 150*256
            END IF
            vert(0).Alpha  = &h0000
            vert(1).x      = r.nleft + (r.nRight - r.nLeft)*sp/10000
            vert(1).y      = r.nBottom - r.nTop + 1
    
            IF @pdis.itemdata = 0 THEN
              vert(1).Red    = 200*256
              vert(1).Green  = 255*256
              vert(1).Blue   = 200*256
            ELSE
              vert(1).Red    = 255*256
              vert(1).Green  = 220*256
              vert(1).Blue   = 220*256
            END IF
            vert(1).Alpha  = &h0000
            gRect.UpperLeft  = 0
            gRect.LowerRight = 1
            GradientFill @pdis.hDc, vert(0), 2, gRect, 1, %GRADIENT_FILL_RECT_H
    
    
            setbkmode @pdis.hdc, %transparent
            IF @pdis.itemdata = 0 THEN
              t = " Indexing:  "+FORMAT$(sp/100, "###.##")+" %"
            ELSE
              t = " Searching:  "+FORMAT$(sp/100, "###.##")+" %"
            END IF
            textout @pdis.hdc, r.nleft, 4, t, LEN(t)
          END IF
    
    
        CASE %WM_USER + 1001
          cwp = wparam                                    'get cw from childproc
    
    
        CASE %WM_USER + 1000
          IF lparam < 10 THEN                              'update indexing
            sp = wparam
            sendmessage hstatus, %SB_SETTEXT, 1 OR %SBT_OWNERDRAW, lparam
    
          ELSEIF lparam => 10 THEN                        'indexing finished
            IF lparam=10 THEN
              t = " Indexing:  100.00 %"
            ELSE
              t = " Searching:  "+FORMAT$(fc)+ " Results"
            END IF
            sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(t)
    
            SLEEP 100                                     'make it flicker
            sendmessage hstatus, %SB_Getrect, 1, VARPTR(r)                    'get to draw in
            r.ntop = r.ntop+1
            r.nbottom = r.nbottom-1
            r.nleft=r.nleft+1
            r.nright=r.nright-1
            hdc=getdc(hstatus)
            IF lparam=10 THEN
              hbr = createsolidbrush(RGB(100, 255, 100))
            ELSE
              hbr = createsolidbrush(RGB(255, 150, 150))
            END IF
            fillrect hdc, r, hbr
            deleteobject hbr
            selectobject hdc, sendmessage(hstatus, %WM_Getfont, 0, 0)
            setbkmode hdc, %transparent
            textout hdc, r.nleft, 4, t, LEN(t)
            releasedc hstatus, hdc
    
            IF lparam=10 THEN
              settimer hwnd, 112, 1500, BYVAL 0
            ELSE
              settimer hwnd, 112, 3500, BYVAL 0
              cf=0
              postmessage hwndc, %WM_COMMAND, %IDM_FIND, cf
              IF fc>0 THEN
                modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find ("+FORMAT$(cf+1)+" of "+FORMAT$(fc)+")"+$TAB+"Ctrl+F"
                modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next ("+FORMAT$(fc-1-cf)+")"+$TAB+"App"
                modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev ("+FORMAT$(cf)+")"+$TAB+"Shift+App"
              ELSE
                modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find"+$TAB+"Ctrl+F"
                modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next"+$TAB+"App"
                modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev"+$TAB+"Shift+App"
              END IF
            END IF
          END IF
    
    
        CASE %WM_TIMER                                    'update date/time
          IF wparam = 111 THEN
            t=" "+TIME$
            sendmessage hstatus, %SB_SETTEXT, 3, VARPTR(t)
            IF t=" 00:00:01" THEN
              t=MID$(DATE$,4,2)+"."+MID$(DATE$,1,2)+"."+MID$(DATE$,7,4)
              CALL getlocaltime(s)
    
              SELECT CASE s.wdayofweek
                CASE 0
                  t=" Su. "+t
                CASE 1
                  t=" Mo. "+t
                CASE 2
                  t=" Tu. "+t
                CASE 3
                  t=" We. "+t
                CASE 4
                  t=" Th. "+t
                CASE 5
                  t=" Fr. "+t
                CASE 6
                  t=" Sa. "+t
              END SELECT
    
              sendmessage hstatus, %SB_SETTEXT, 2, VARPTR(t)                  ' set part 1 (current date)
            END IF
    
          ELSEIF wparam = 112 THEN                        'signal indexing finished
            enablemenuitem (getmenu(hwndmain), %IDM_FIND, %MF_ENABLED)
            enablemenuitem (getmenu(hwndmain), %IDM_FINDNEXT, %MF_ENABLED)
            enablemenuitem (getmenu(hwndmain), %IDM_FINDPREV, %MF_ENABLED)
            enablemenuitem (getmenu(hwndmain), %IDM_GOTO, %MF_ENABLED)
            killtimer hwnd, 112
            t= "  Ready"
            sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(t)
          END IF
    
    
        CASE %WM_SETFOCUS
          setfocus hwndc
    
    
        CASE %WM_NOTIFY                                   'events/notifications
    
    
        CASE %WM_MENUSELECT                               'selection change in a menu
            LoadString hinst, wParam, zText, SIZEOF(zText)
            SendMessage hstatus, %WM_SETTEXT, 0, VARPTR(zText)
            EXIT FUNCTION
    
    
        CASE %WM_MOUSEMOVE                                'mouse move
    
    
        CASE %WM_SIZE                                     'main window has been resized
          SendMessage hstatus, wMsg, wParam, lParam       'statusbar does on it´s own
    
          IF wparam <> %SIZE_MINIMIZED THEN               'only if window is not in minmized state
            GetClientRect hWnd, r1                        'get clientarea
            getwindowrect hstatus, r                      'get statusbar
    
            st(3)= -1
            st(2)= LO(WORD, lparam) - st1
            st(1)= st(2) - st2
            st(0)= st3
    
            sendmessage hstatus, %SB_SETPARTS, 4, VARPTR(st(0)) ' set size of parts in statusbar
            IF hexflag=1 THEN
              MoveWindow hwndc, 69*@cwp, 0, LO(WORD, lparam)-69*@cwp, HI(WORD, lparam)-(r.nbottom-r.ntop), %TRUE 'resize child
            ELSE
              MoveWindow hwndc, 0, 0, LO(WORD, lparam), HI(WORD, lparam)-(r.nbottom-r.ntop), %TRUE 'resize child
            END IF
          END IF
    
          setfocus hwndc
          FUNCTION=%false
          EXIT FUNCTION                                   'nothing to do for defwindowproc
    
    
        CASE %WM_COMMAND                                  'events/notifications from controls
            SELECT CASE AS LONG LOWRD(wParam)
    
            CASE 5000
    newfile:
              IF hexflag=1 THEN                           'start always in text view
                hexflag=0
                tlc=tlc_t
                sfy = sfy_t
                checkmenuItem(getmenu(hwnd), %IDM_HEXVIEW, %MF_UNCHECKED)
                getclientrect hwndmain, r
                sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
              END IF
    
              enablemenuitem (getmenu(hwndmain), %IDM_FIND, %MF_GRAYED)
              enablemenuitem (getmenu(hwndmain), %IDM_FINDNEXT, %MF_GRAYED)
              enablemenuitem (getmenu(hwndmain), %IDM_FINDPREV, %MF_GRAYED)
              enablemenuitem (getmenu(hwndmain), %IDM_GOTO, %MF_GRAYED)
              THREAD CREATE do_scan(BYVAL 0) TO hthread
              THREAD CLOSE hthread TO hthread
              EXIT FUNCTION
    
    
            CASE %IDM_OPEN
              DISPLAY OPENFILE hwnd,,, " Select a file for viewing", "C:\", CHR$("All Files", 0, "*.*", 0), _
                               "", "", %OFN_FILEMUSTEXIST OR %OFN_PATHMUSTEXIST TO d$
    
              IF ISFILE(d$) THEN
                f$=d$
                GOTO newfile
              END IF
    
    
            CASE %IDM_CRLF
              delimiter = $CRLF
              checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_CHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_CR, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_LF, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_ASCII, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_HEX, %MF_UNCHECKED)
    
              modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
              modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
              MSGBOX " "+CHR$(34)+"Carriage Return + Line Feed"+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                     "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                     " Large File Viewer"
    
    
            CASE %IDM_CR
              delimiter = $CR
              checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_CR, %MF_CHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_LF, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_ASCII, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_HEX, %MF_UNCHECKED)
    
              modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
              modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
              MSGBOX " "+CHR$(34)+"Carriage Return"+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                     "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                     " Large File Viewer"
    
    
            CASE %IDM_LF
              delimiter = $LF
              checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_CR, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_LF, %MF_CHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_ASCII, %MF_UNCHECKED)
              checkmenuItem(getmenu(hwnd), %IDM_HEX, %MF_UNCHECKED)
    
              modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
              modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
              MSGBOX " "+CHR$(34)+"Line Feed"+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                     "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                     " Large File Viewer"
    
    
            CASE %IDM_ASCII
              CALL editbox(2)
              EXIT FUNCTION
    
    
            CASE %IDM_HEX
              CALL editbox(3)
              EXIT FUNCTION
    
    
            CASE %IDM_EXIT
              SendMessage hWnd, %WM_DESTROY, wParam, lParam
              EXIT FUNCTION
    
    
            CASE %IDM_COPY
              sendmessage hwndc, %WM_COMMAND, %IDM_COPY, 0
    
    
            CASE %IDM_COPYFILE
              sendmessage hwndc, %WM_COMMAND, %IDM_COPYFILE, 0
    
    
            CASE %IDM_GOTO
              CALL editbox(0)
              EXIT FUNCTION
    
    
            CASE %IDM_FIND
              CALL editbox(1)
              EXIT FUNCTION
    
    
            CASE %IDM_FINDNEXT
              INCR cf
              IF cf > fc-1 THEN cf = fc-1
              postmessage hwndc, %WM_COMMAND, %IDM_FIND, cf
              IF fc>0 THEN
                modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find ("+FORMAT$(cf+1)+" of "+FORMAT$(fc)+")"+$TAB+"Ctrl+F"
                modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next ("+FORMAT$(fc-1-cf)+")"+$TAB+"App"
                modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev ("+FORMAT$(cf)+")"+$TAB+"Shift+App"
              ELSE
                modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next"+$TAB+"App"
              END IF
    
    
            CASE %IDM_FINDPREV
              DECR cf
              IF cf < 0 THEN cf = 0
              postmessage hwndc, %WM_COMMAND, %IDM_FIND, cf
              IF fc>0 THEN
                modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find ("+FORMAT$(cf+1)+" of "+FORMAT$(fc)+")"+$TAB+"Ctrl+F"
                modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev ("+FORMAT$(cf)+")"+$TAB+"Shift+App"
                modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next ("+FORMAT$(fc-1-cf)+")"+$TAB+"App"
              ELSE
                modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev"+$TAB+"Shift+App"
              END IF
    
    
            CASE %IDM_HEXVIEW
              postmessage hwndc, %WM_COMMAND, 5002, 0
    
    
            CASE %IDM_HELP
              d$="  View large Files (filelength may be up to 2^64)"+$CRLF+$CRLF
              d$=d$+$CRLF+"  F1"+$TAB+$TAB+"-"+$TAB+"Help"
              d$=d$+$CRLF+"  Ctrl+F1"+$TAB+$TAB+"-"+$TAB+"About"
              d$=d$+$CRLF+"  Ctrl+M"+$TAB+$TAB+"-"+$TAB+"Memory Usage"+$CRLF
              d$=d$+$CRLF+"  Ctrl+O"+$TAB+$TAB+"-"+$TAB+"Open a file for viewing"
              d$=d$+$CRLF+"  Alt+X"+$TAB+$TAB+"-"+$TAB+"Exit"+$CRLF
              d$=d$+$CRLF+"  Ctrl+C"+$TAB+$TAB+"-"+$TAB+"Copy selection to clipboard"
              d$=d$+$CRLF+"  Ctrl+G"+$TAB+$TAB+"-"+$TAB+"Goto Line (enter line #)"
              d$=d$+$CRLF+"  Ctrl+F"+$TAB+$TAB+"-"+$TAB+"Find (enter a string to search for)"
              d$=d$+$CRLF+"  App"+$TAB+$TAB+"-"+$TAB+"Find next"
              d$=d$+$CRLF+"  Shift+App"+$TAB+"-"+$TAB+"Find previous"+$CRLF
              d$=d$+$CRLF+"  Ctrl+H"+$TAB+$TAB+"-"+$TAB+"Toggle Hex/Text View"+$CRLF
              d$=d$+$CRLF+"  ESC"+$TAB+$TAB+"-"+$TAB+"Cancel current action"
              d$=d$+$CRLF+"  Enter"+$TAB+$TAB+"-"+$TAB+"Finish entry"+$CRLF+$CRLF
              d$=d$+$CRLF+"  You may navigate usings cursor keys or scrollbars, select text "
              d$=d$+$CRLF+"  by using SHIFT+Cursor keys or by dragging the mouse as usual."+$CRLF
    
              d$=d$+$CRLF+"  Charcter combination separating lines (delimiter) may be changed."+$CRLF
    
    
              d$=d$+$CRLF+"  ""Goto"" and ""Find"" accept hex input as well (""0x"" prefix)."+$CRLF
              d$=d$+$CRLF+"  Commandline: "+CHR$(34)+"FILE TO VIEW"+CHR$(34)
    
              messagebox(hwnd, BYVAL STRPTR(d$), "  Large File Viewer Help", %MB_OK OR %MB_APPLMODAL OR %MB_TOPMOST)
              FUNCTION = 0
              EXIT FUNCTION
    
    
    
            CASE %IDM_ABOUT                               'Load and show Dialog Box from resource
              DialogBox(hinst, "ABOUT", hWnd, CODEPTR(AboutProc))
              FUNCTION = 0
              EXIT FUNCTION
    
    
            CASE %IDM_MEM                                 'Show memory usage
              GetProcessMemoryInfo getcurrentprocess, pmc, SIZEOF(pmc)
              MSGBOX " Current Working Set Size : "+FORMAT$(pmc.WorkingSetSize/1000000, "* #.00")+" MB", _
                     %MB_ICONINFORMATION," Memory Usage"
    
    
          END SELECT
    
    
        CASE %WM_exitmenuloop
          postmessage hwndc, %WM_COMMAND, 5010, 0         'restore statusbar
    
    
        CASE %WM_erasebkgnd
          FUNCTION = 1                                    'just do nothing
          EXIT FUNCTION
    
    
        CASE %WM_PAINT
          invalidaterect hwndc, BYVAL 0, BYVAL 0          'do all client painting in hwndc
          updatewindow hwndc
    
    
        CASE %WM_DESTROY                                  'exit - a good point for cleaning up
          PostQuitMessage 0                               'exit message loop in WINMAIN
          EXIT FUNCTION
    
      END SELECT
    
    
      FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam) 'pass messages on to Windows for default processing
    
    
    END FUNCTION
    
    
    '***********************************************************************************************
    
    
    SUB updatecaret(cx AS DWORD, cy AS DWORD, cw AS DWORD, ch AS DWORD, coffset AS LONG, topline AS LONG)
    '***********************************************************************************************
    ' update caret position and show in statusbar
    '***********************************************************************************************
    LOCAL t AS ASCIIZ * 128
    
    
      IF hexflag=1 THEN
        t=" 0x"+HEX$(foffset+(topline+cy)*16+cx)+" - "+FORMAT$(foffset+(topline+cy)*16+cx+1, "#,")
      ELSE
        t=" "+FORMAT$(coffset + cx + 1, "#,")+" :  "+FORMAT$(loffset + topline + cy + 1, "#,")
      END IF
    
      sendmessage hstatus, %SB_Settext, 0, VARPTR(t)
      showcaret hwndc
      setcaretpos((cx)*cw+%mg, (cy)*ch)
    
    
    END SUB
    
    
    '***********************************************************************************************
    
    
    FUNCTION ChildProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG
    '*************************************************************************************************
    ' Textwindow procedure, displays text
    '*************************************************************************************************
    LOCAL ps       AS PAINTSTRUCT
    LOCAL lf       AS logfont
    LOCAL tm       AS textmetric
    LOCAL sbi      AS SCROLLINFO
    LOCAL pt       AS POINTAPI
    LOCAL hdc      AS DWORD
    LOCAL hold     AS DWORD
    LOCAL hmemdc   AS DWORD
    LOCAL hbmp     AS DWORD
    LOCAL dflag    AS DWORD                               'drawflag
    LOCAL sty      AS DWORD
    LOCAL gt       AS QUAD PTR
    LOCAL r        AS rect
    LOCAL n        AS LONG
    LOCAL i        AS LONG
    LOCAL j        AS LONG
    LOCAL lp       AS DWORD                               'line ptr
    LOCAL k        AS LONG
    LOCAL a()      AS WORD                                'bitmap array
    
    LOCAL lx      AS DWORD                                'low start x
    LOCAL ly      AS QUAD                                 'low start y
    LOCAL hx      AS DWORD                                'high end x
    LOCAL hy      AS QUAD                                 'high end y
    LOCAL d$
    LOCAL e$
    LOCAL t$
    
    LOCAL sel1 AS QUAD
    LOCAL sel2 AS QUAD
    
    STATIC hfont   AS DWORD                               'font
    STATIC hcaret  AS DWORD                               'userdefined caret
    STATIC topline AS LONG                                '# of line on top
    STATIC coffset AS LONG                                'char offset for first char shown
    STATIC cpl     AS DWORD                               'chars per line
    STATIC lps     AS DWORD                               'lines per screen
    STATIC pgs     AS DWORD                               'pagescroll
    STATIC cw      AS DWORD                               'char width
    STATIC ch      AS DWORD                               'char height
    STATIC cx      AS LONG                                'caret x (zerobased)
    STATIC cy      AS LONG                                'caret y (zerobased)
    STATIC ms      AS INTEGER                             'mousewheel
    
    STATIC sels    AS QUAD
    STATIC sele    AS QUAD
    STATIC ls      AS DWORD                               'line # (start)
    STATIC le      AS DWORD                               'line # (end)
    
    STATIC selflag AS LONG                                '1=selection, 0=no
    
    
      SELECT CASE AS LONG wMsg
        CASE %WM_CREATE                                   'creation of text window
          lf.lfHeight         =-16
          lf.lfWidth          = 0
          lf.lfEscapement     = 0
          lf.lfOrientation    = 0
          lf.lfWeight         = 400
          lf.lfItalic         = 0
          lf.lfUnderline      = 0
          lf.lfStrikeOut      = 0
          lf.lfCharSet        = 0
          lf.lfOutPrecision   = 3
          lf.lfClipPrecision  = 2
          lf.lfQuality        = 1
          lf.lfPitchAndFamily = 49
          lf.lfFaceName       = "Courier New"
    
          hfont = createfontindirect(lf)                  'create font
    
          hdc = getdc(hwnd)                               'get Device Context
          hold = SelectObject(hdc, hfont)                 'select new font into dc
          GetTextMetrics hdc, tm                          'get font parameters
          SelectObject hdc, hold                          'select old font back into dc
          ReleaseDC hwnd, hdc                             'release dc
    
          cw = tm.tmAveCharWidth                          'character width (fixed font)
          ch = tm.tmHeight + tm.tmExternalLeading         'Line spacing (line height)
    
    '***********************************************************************************************
    ' create caret using a bitmap
    '***********************************************************************************************
    
          i = cw/16                                       'i = number of words necessary per scanline
                                                          '(monochrome, 1 bit per color)
          IF i*16 < cw THEN  i = i + 1                    'make sure array is big enough (i>0)
          n = i*ch                                        'array size
    
          REDIM a(0 TO n)
    
          FOR j=ch-2 TO ch                                'set array according to character dimensions
            FOR k=0 TO i-1
              a(j*i+k)=&HFFFF
            NEXT k
          NEXT j
    
          hcaret = createbitmap(cw, ch, 1, 1, BYVAL VARPTR(a(0)))
          createcaret(hWnd, hCaret, 0, 0)
          topline = 0
          coffset = 0
          lc=0
          cx=0 : cy=0                                     'initial caret pos
    
          updatecaret(cx, cy, cw, ch, coffset, topline)
          postmessage hwndmain, %WM_USER + 1001, VARPTR(cw), 0                'make cw available in mainproc
    
    
        CASE %WM_KILLFOCUS
          destroycaret
    
    
        CASE %WM_SETFOCUS
          createcaret(hWnd, hCaret, 0, 0)
          IF lc>0 THEN
            showcaret hwnd
          END IF
    
    
        CASE %WM_DRAWITEM                                 'ownerdraw
    
    
        CASE %WM_KEYDOWN
          IF (getkeystate(16) AND &H80) THEN          'Shift
          ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
          ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
          ELSE
            IF selflag>0 THEN
              selflag=0
              dflag=1
            END IF
          END IF
    
          IF lc=0 THEN EXIT FUNCTION
    
          SELECT CASE wparam
            CASE %VK_Home
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_home
                ELSE
                  GOTO c_home
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
                selflag=0
    c_home:
                cx=0
                coffset=0
                dflag=1
    
                GOSUB setsele
              END IF
    
    
            CASE %VK_End
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_end
                ELSE
                  GOTO c_end
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
                selflag=0
    c_end:
    '***********************************************************************************************
    ' show delimiter ?? -> yes, necessary for split lines
    ' otherwise some chars would be omittet
    '***********************************************************************************************
    '            n = l(topline + cy)-l(topline +cy -1) - LEN(delimiter) 'linelenght without delimiter
    
                n = l(topline + cy + 1)-l(topline + cy)'+1     'linelenght
                cx = MIN(cpl, n)
                IF cx < 0 THEN cx = 0
                IF n > cpl THEN                             'if longert han screen
                  coffset =  n - cpl                        'set char offest
                  dflag=1                                   'must redraw
                END IF
    
                GOSUB setsele
              END IF
    
    
            CASE %VK_PgUp
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_pgup
                ELSE
                  GOTO c_pgup
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                cp=1
                getfile(cp)
                topline = 0
                cy = 0
                dflag=1
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
    c_pgup:
                IF loffset + topline = 0 THEN
                  cy = 0
                ELSE
                  topline = topline - lps
                  IF topline < 0 THEN
                    IF cp = 1 THEN                        'if in first chunk
                      topline = 0
                    ELSE                                  'there are more chunks
                      DECR cp
                      getfile(cp)
                      topline=p1(cp)-p1(cp-1)-topline     'adjust topline
                    END IF
                  END IF
                  dflag=1
                END IF
    
                GOSUB setsele
              END IF
    
    
            CASE %VK_PgDn
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_pgdn
                ELSE
                  GOTO c_pgdn
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                cp=pc-1
                IF cp < 1 THEN cp = 1
                getfile(cp)
                topline = lc-lps
                IF topline < 0 THEN topline = 0
                cy = lps-1
                dflag=1
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
    c_pgdn:
                IF loffset + topline = tlc-lps THEN
                  cy = lps-1
                ELSE
                  topline = topline + lps
                  IF topline > lc-lps THEN
                    IF cp = pc-1 THEN                     'if in last two chunks
                      topline = lc-lps
                    ELSEIF pc = 1 THEN
                      topline = lc-lps
                      IF topline < 0 THEN topline = 0
                    ELSE                                  'there are more chunks
                      topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                      INCR cp
                      getfile(cp)
                    END IF
                  END IF
                  dflag=1
                END IF
    
                GOSUB setsele
              END IF
    
    
            CASE %VK_Up
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_up
                ELSE
                  GOTO c_up
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
                selflag=0
    c_up:
                DECR cy
                IF cy < 0 THEN
                  DECR topline
                  IF topline < 0 THEN
                    IF cp = 1 THEN                        'if in first chunk
                      topline = 0
                    ELSE                                  'there are more chunks
                      DECR cp
                      getfile(cp)
                      topline=p1(cp)-p1(cp-1)-1           'adjust topline
                    END IF
                  END IF
                  cy = 0
                  dflag=1
                END IF
    
                GOSUB setsele
              END IF
    
    
            CASE %VK_Down
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_down
                ELSE
                  GOTO c_down
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
                selflag=0
    c_down:
                INCR cy
                IF cy > lps-1 THEN
                  INCR topline
                  IF topline > lc-lps THEN
                    IF cp = pc-1 THEN                     'if in last two chunks
                      topline = lc-lps
                    ELSEIF pc = 1 THEN
                      topline = lc-lps
                      IF topline < 0 THEN topline = 0
                    ELSE                                  'there are more chunks
                      topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                      INCR cp
                      getfile(cp)
                    END IF
                  END IF
                  cy = lps-1
                  dflag=1
                END IF
    
                GOSUB setsele
              END IF
    
    
            CASE %VK_Left
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_left
                ELSE
                  GOTO c_left
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
                selflag=0
    c_left:
                DECR cx
                IF cx <= 0 THEN
                  DECR coffset
                  IF coffset < 0 THEN coffset = 0
                  cx = 0
                  dflag=1
                END IF
    
                GOSUB setsele
              END IF
    
    
            CASE %VK_Right
              IF (getkeystate(16) AND &H80) THEN          'Shift
                dflag=1
                IF selflag=0 THEN
                  selflag=1
                  GOSUB setsels
                  GOTO c_right
                ELSE
                  GOTO c_right
                END IF
              ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
              ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
              ELSE
                selflag=0
    c_right:
                INCR cx
                IF hexflag=1 THEN
                  IF cx > cpl THEN
                    cx = cpl
    '                dflag=1
                  END IF
                ELSE
                  IF cx > cpl-1 THEN
                    INCR coffset
                    IF coffset > lmax - cpl THEN coffset = lmax - cpl
                    cx = cpl-1
                    dflag=1
                  END IF
                END IF
    
                GOSUB setsele
              END IF
    
          END SELECT
    
    
          updatecaret(cx, cy, cw, ch, coffset, topline)
    
          IF dflag=1 THEN
            invalidaterect hwnd, BYVAL 0, BYVAL 0
            updatewindow hwnd
          END IF
    
    
        CASE %WM_NOTIFY                                   'events/notifications
    
    
        CASE %WM_MOUSEWHEEL                               'mousewheel scroll up/down
          ms = ms + HIWRD(WPARAM)
    
          WHILE  ms >= 120
            CALL sendmessage(hwnd, %WM_VSCROLL, %SB_LINEUP, 0)
            ms = ms - 120
          WEND
    
          WHILE ms <= -120
            CALL sendmessage(hwnd, %WM_VSCROLL, %SB_LINEDOWN, 0)
            ms = ms + 120
          WEND
    
          FUNCTION = 0
          EXIT FUNCTION
    
    
        CASE %WM_HSCROLL                                  'horizontal scrollbar
          IF lc=0 THEN EXIT FUNCTION
    
          SELECT CASE LO(WORD, wparam)
            CASE %SB_LINELEFT, %SB_PAGELEFT
              IF coffset > 0 THEN
                INCR cx
                IF cx > cpl-1 THEN cx = cpl-1
              END IF
              DECR coffset
              IF coffset < 0 THEN coffset = 0
    
            CASE %SB_LINERIGHT, %SB_PAGERIGHT
              IF coffset < lmax - cpl THEN
                DECR cx
                IF cx < 0 THEN cx = 0
              END IF
              INCR coffset
              IF coffset > lmax - cpl THEN coffset = lmax - cpl
    
            CASE %SB_THUMBTRACK
              coffset = HI(WORD, wparam)
              IF coffset > lmax - cpl THEN coffset = lmax - cpl
          END SELECT
    
          updatecaret(cx, cy, cw, ch, coffset, topline)
    
          invalidaterect hwnd, BYVAL 0, BYVAL 0
          updatewindow hwnd
    
    
        CASE %WM_VSCROLL                                  'vertical scrollbar
          IF lc=0 THEN EXIT FUNCTION
    
          SELECT CASE LO(WORD, wparam)
            CASE %SB_LINEUP
              IF topline > 0 THEN
                INCR cy
                IF cy > lps-1 THEN cy = lps-1
              END IF
    
              DECR topline
              IF topline < 0 THEN
                IF cp = 1 THEN                        'if in first chunk
                  topline = 0
                ELSE                                  'there are more chunks
                  DECR cp
                  getfile(cp)
                  topline=p1(cp)-p1(cp-1)             'adjust topline
                END IF
              END IF
    
    
            CASE %SB_LINEDOWN
              IF topline < lc -lps THEN
                DECR cy
                IF cy < 0 THEN cy = 0
              END IF
    
              INCR topline
              IF topline > lc-lps THEN
                IF cp = pc-1 THEN                     'if in last two chunks
                  topline = lc-lps
                ELSEIF pc = 1 THEN
                  topline = lc-lps
                  IF topline < 0 THEN topline = 0
                ELSE                                  'there are more chunks
                  topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                  INCR cp
                  getfile(cp)
                END IF
              END IF
    
    
            CASE %SB_PAGEUP                               'scrollbar body click
              IF loffset + topline = 0 THEN
                cy = 0
              ELSE
                topline = topline - pgs
                IF topline < 0 THEN
                  IF cp = 1 THEN                        'if in first chunk
                    topline = 0
                  ELSE                                  'there are more chunks
                    DECR cp
                    getfile(cp)
                    topline=p1(cp)-p1(cp-1)-topline     'adjust topline
                  END IF
                END IF
              END IF
    
    
            CASE %SB_PAGEDOWN                             'scrollbar body click
              IF loffset + topline = tlc-lps THEN
                cy = lps-1
              ELSE
                topline = topline + pgs
                IF topline > lc-lps THEN
                  IF cp = pc-1 THEN                     'if in last two chunks
                    topline = lc-lps
                  ELSEIF pc = 1 THEN
                    topline = lc-lps
                    IF topline < 0 THEN topline = 0
                  ELSE                                  'there are more chunks
                    topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                    INCR cp
                    getfile(cp)
                  END IF
                END IF
              END IF
    
    
            CASE %SB_THUMBTRACK
    '***********************************************************************************************
    ' get chunk, load, set topline -> show
    '***********************************************************************************************
    LOCAL q AS QUAD
              q = HI(WORD, wparam)*sfy                    'get line #
              IF q=0 THEN                                 'if first line
                cp=1
                getfile(cp)
                topline=0
    
              ELSEIF q=>tlc-lps+1 THEN                    'if last line
                cp=pc-1
                IF cp<1 THEN cp=1
                getfile(cp)
                topline=lc-lps
    
              ELSEIF pc=1 THEN                            'if only one chunk
                topline=HI(WORD, wparam)*sfy
    
              ELSE                                        'any other case
                IF hexflag=1 THEN
                  q=q*16
                  FOR i=1 TO pc-1
                    IF q < p(i) THEN
                      cp=i
                      getfile(cp)
                      topline=HI(WORD, wparam)*sfy-foffset/16
                      EXIT FOR
                    END IF
                  NEXT i
    
                ELSE
                  FOR i=1 TO pc-1
                    IF q < p1(i) THEN
                      cp=i
                      getfile(cp)
                      topline=HI(WORD, wparam)*sfy-loffset
                      EXIT FOR
                    END IF
                  NEXT i
                END IF
    
              END IF
    
          END SELECT
    
          updatecaret(cx, cy, cw, ch, coffset, topline)
    
          invalidaterect hwnd, BYVAL 0, BYVAL 0
          updatewindow hwnd
    
    
    
        CASE %WM_LBUTTONDOWN
          IF lc=0 THEN EXIT FUNCTION
    
          selflag=0                                       'reset selection
          invalidaterect hwnd, BYVAL 0, BYVAL 0           'redraw
          updatewindow hwnd
    
          pt.x = LO(INTEGER, lparam)
          pt.y = HI(INTEGER, lparam)
          IF dragdetect(hwnd, pt) THEN                    'drag ?
            selflag=3                                     'mouse selection
            cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
            IF cx<0 THEN cx=0
            cy = INT(HI(WORD, lparam)/ch)' + 1
            IF cy>lps-1 THEN cy=lps-1
            updatecaret(cx, cy, cw, ch, coffset, topline)
    
            GOSUB setsels
            GOSUB setsele
    
            invalidaterect hwnd, BYVAL 0, BYVAL 0         'redraw
            updatewindow hwnd
            setcapture hwnd                               'capture mouse
    
          ELSE                                            'lbuttonup !!!
            cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
            IF cx<0 THEN cx=0
            cy = INT(HI(WORD, lparam)/ch)' + 1
            IF cy>lps-1 THEN cy=lps-1
            updatecaret(cx, cy, cw, ch, coffset, topline)
            setfocus hwnd
          END IF
    
    
        CASE %WM_LBUTTONUP
          IF lc=0 THEN EXIT FUNCTION
    
          IF selflag=3 THEN                               'if selection in progress
            selflag=4
            pt.x = LO(INTEGER, lparam)
            pt.y = HI(INTEGER, lparam)
            getclientrect hwnd, r
            IF ptinrect(r, pt) THEN
              cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
              IF cx<0 THEN cx=0
              cy = INT(HI(WORD, lparam)/ch)' + 1
              IF cy>lps-1 THEN cy=lps-1
              updatecaret(cx, cy, cw, ch, coffset, topline)
    
              GOSUB setsele
            END IF
            releasecapture                                'release mouse
          END IF
    
    
        CASE %WM_MOUSEMOVE                                'mouse move
          IF lc=0 THEN EXIT FUNCTION
    
          pt.x = LO(INTEGER, lparam)
          pt.y = HI(INTEGER, lparam)
          getclientrect hwnd, r
    
          IF selflag=3 THEN                               'if selection in progress
            IF ptinrect(r, pt) THEN
              cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
              IF cx<0 THEN cx=0
              cy = INT(HI(WORD, lparam)/ch)' + 1
              IF cy>lps-1 THEN cy=lps-1
              updatecaret(cx, cy, cw, ch, coffset, topline)
    
              GOSUB setsele
    
              invalidaterect hwnd, BYVAL 0, BYVAL 0
              updatewindow hwnd
            ELSE
              IF pt.y < r.ntop THEN postmessage hwnd, %WM_VSCROLL, %SB_LINEUP, 0
              IF pt.y > r.nbottom THEN postmessage hwnd, %WM_VSCROLL, %SB_LINEDOWN, 0
              IF pt.x < r.nleft THEN postmessage hwnd, %WM_HSCROLL, %SB_LINELEFT, 0
              IF pt.x > r.nright THEN postmessage hwnd, %WM_HSCROLL, %SB_LINERIGHT, 0
            END IF
          END IF
    
    
        CASE %WM_SIZE                                     'textwindow has been resized
          cpl = (LO(WORD, lparam) - getsystemmetrics(%SM_CXHSCROLL)) /cw
          lps = (HI(WORD, lparam)  - getsystemmetrics(%SM_CXHSCROLL))/ch
    
          IF topline > lc-lps THEN
            cy=cy+topline-(lc-lps)
            topline = lc-lps
            IF topline < 0 THEN                       'adapt min/max value for topline
              cy=cy+topline'-1
              topline=0
            END IF
          END IF
    
          invalidaterect hwnd, BYVAL 0, BYVAL 0
          updatewindow hwnd
          updatecaret(cx, cy, cw, ch, coffset, topline)
    
          FUNCTION = 0                                    'nothing to do for defwindowproc
          EXIT FUNCTION
    
    
        CASE %WM_COMMAND                                  'events/notifications from controls
          SELECT CASE AS LONG LOWRD(wParam)
            CASE 5000                                     'a new file
              IF hexflag=1 THEN
                sty=getwindowlong(hwnd, %GWL_Style)
                sty = sty XOR %WS_HSCROLL
                setwindowlong(hwnd, %GWL_Style, sty)
    
                getwindowrect hwndmain, r
                IF r.nright-r.nleft <> 88*cw+getsystemmetrics(%SM_cxVscroll) THEN         'ensure correct width for hex view
                  setwindowpos hwndmain, BYVAL 0, 0,0, 88*cw+getsystemmetrics(%SM_cxVscroll), r.nbottom-r.ntop, %SWP_NoZorder OR %SWP_NoMove
                ELSE
                  getclientrect hwndmain, r
                  sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
                END IF
              ELSE                                        'resize, when switching to text view
                sty=getwindowlong(hwnd, %GWL_Style)
                sty = sty OR %WS_HSCROLL
                setwindowlong(hwnd, %GWL_Style, sty)
                getclientrect hwndmain, r
    
                sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
              END IF
    
              showcaret hwnd
              selflag = 0
              topline = 0
              coffset = 0
              cx=0 : cy=0                                 'initial caret pos
    
              updatecaret(cx, cy, cw, ch, coffset, topline)
    
              IF getfile(cp) THEN
                sbi.cbSize = SIZEOF(sbi)
                sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                sbi.nMin   = 1
                sbi.nMax   = lmax-cpl
                sbi.nPage  = 1                            'size of thumb !!!
                sbi.nPos   = 1
                SetScrollInfo hwndc, %SB_HORZ, sbi, 0
    
    
                sbi.cbSize = SIZEOF(sbi)
                sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                sbi.nMin   = 0
                sbi.nMax   = lc-lps'+1
                sbi.nPage  = 1                            'size of thumb !!!
                sbi.nPos   = 1
                SetScrollInfo hwndc, %SB_VERT, sbi, 0
    
                invalidaterect hwnd, BYVAL 0, BYVAL 0
                updatewindow hwnd
                updatecaret(cx, cy, cw, ch, coffset, topline)
              END IF
    
    
            CASE 5001                                     'update y scrollbar
              sbi.cbSize = SIZEOF(sbi)
              sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
              sbi.nMin   = 0
              sbi.nMax   = (tlc-lps)/sfy
              sbi.nPage  = 1                              'size of thumb !!!
              sbi.nPos   = 1
              SetScrollInfo hwndc, %SB_VERT, sbi, 0
    
              IF tlc<11 THEN
                pgs=1
              ELSEIF tlc <100 THEN
                pgs=2
              ELSEIF tlc > 1000000 THEN
                pgs = 1000
              ELSE
                pgs = tlc/(7.56*LOG10(tlc)^2.727)
              END IF
    
              invalidaterect hwndc, BYVAL 0, BYVAL 0
              updatewindow hwndc
    
    
            CASE 5002                                     'toggle hexview
              IF hexflag=0 THEN
                hexflag=1
                tlc=tlc_h
                sfy = sfy_h
                checkmenuItem(getmenu(hwnd), %IDM_HEXVIEW, %MF_CHECKED)
                setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Records"
    
                sty=getwindowlong(hwnd, %GWL_Style)
                sty = sty XOR %WS_HSCROLL
                setwindowlong(hwnd, %GWL_Style, sty)
    
                getwindowrect hwndmain, r
                IF r.nright-r.nleft <> 88*cw+getsystemmetrics(%SM_cxVscroll) THEN         'ensure correct width for hex view
                  setwindowpos hwndmain, BYVAL 0, 0,0, 88*cw+getsystemmetrics(%SM_cxVscroll), r.nbottom-r.ntop, %SWP_NoZorder OR %SWP_NoMove
                ELSE
                  getclientrect hwndmain, r
                  sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
                END IF
    
              ELSE                                        'resize, when switching to text view
                hexflag=0
                tlc=tlc_t
                sfy = sfy_t
                checkmenuItem(getmenu(hwnd), %IDM_HEXVIEW, %MF_UNCHECKED)
                setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Lines"
    
                sty=getwindowlong(hwnd, %GWL_Style)
                sty = sty OR %WS_HSCROLL
                setwindowlong(hwnd, %GWL_Style, sty)
                getclientrect hwndmain, r
    
                sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
              END IF
    
              IF tlc<11 THEN
                pgs=1
              ELSEIF tlc <101 THEN
                pgs=2
              ELSEIF tlc > 1000000 THEN
                pgs = 1000
              ELSE
                pgs = tlc/(7.56*LOG10(tlc)^2.727)
              END IF
    
              q = foffset + l(topline + cy) - smemb + MIN(coffset+cx, l(topline + cy + 1)-l(topline + cy))
    
              showcaret hwnd
              selflag = 0
              coffset = 0
              cx=0 : cy=0                                 'reset caret pos
    
    
              IF getfile(cp) THEN
                q=q-foffset
    
                FOR i=1 TO lc                             'find line
                  IF q < l(i) - smemb THEN
                    topline=i-cy-1                        'set topline (place as first line)
                    q=q-(l(i-1) - smemb)
                    EXIT FOR
                  END IF
                NEXT i
    
                IF topline < 0 THEN                       'adapt min/max value for topline
                  cy=cy+topline'-1
                  topline=0
                ELSEIF topline > lc-lps THEN
                  cy=cy+topline-(lc-lps)
                  topline = lc-lps
                  IF topline < 0 THEN
                    cy=cy+topline'-1
                    topline=0
                  END IF
                END IF
    
                cx=q                                      'set cx
                IF hexflag=0 THEN
                  IF q>cpl THEN                           'bring into view (centered), if necessary
                    coffset=q-cpl/2
                    cx=q-coffset
                  END IF
                END IF
    
    
                sbi.cbSize = SIZEOF(sbi)
                sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                sbi.nMin   = 1
                sbi.nMax   = lmax-cpl
                sbi.nPage  = 1                            'size of thumb !!!
                sbi.nPos   = 1
                SetScrollInfo hwndc, %SB_HORZ, sbi, 0
    
    
                sbi.cbSize = SIZEOF(sbi)
                sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                sbi.nMin   = 0
                sbi.nMax   = (tlc-lps)/sfy
                sbi.nPage  = 1                            'size of thumb !!!
                sbi.nPos   = 1
                SetScrollInfo hwndc, %SB_VERT, sbi, 0
    
                invalidaterect hwnd, BYVAL 0, BYVAL 0
                updatewindow hwnd
                updatecaret(cx, cy, cw, ch, coffset, topline)
              END IF
    
    
            CASE 5010
              updatecaret(cx, cy, cw, ch, coffset, topline)                   'show again after menu closed
    
    
            CASE %IDM_GOTO                                'goto line ^(lparam = quad ptr to line)
              gt = lparam
              coffset = 0
    
              IF pc=1 THEN
                cx=0
                cy=lps/2
                [email protected]                          'set topline (place line in the middle)
    
              ELSE
                FOR i=1 TO pc-1                           'find chunk
                  IF @gt < p1(i) THEN
                    cp=i
                    getfile(cp)                           'read
                    cx=0
                    cy=lps/2
                    [email protected]              'set topline (place line in the middle)
    
                    GOTO exit_goto
                  END IF
                NEXT i
              END IF
    
              IF pc>1 THEN                                'if in last part and if more than one part
                cp=pc-1
                getfile(cp)
                cx=0
                cy=lps/2
                [email protected]                  'set topline (place line in the middle)
              END IF
    
    exit_goto:
              IF topline < 0 THEN                         'adapt min/max value for topline
                cy=cy+topline'-1
                topline=0
              ELSEIF topline > lc-lps THEN
                cy=cy+topline-(lc-lps)
                topline = lc-lps
              END IF
    
              selflag=8                                   'set selection
              sels = foffset + l(topline + cy) - smemb
              IF sels < 0 THEN
                sels = foffset + l(lc) - smemb
              ELSEIF sels > foffset + l(lc) - smemb THEN
                sels = foffset + l(lc) - smemb
              END IF
    
              sele = foffset + l(topline + cy) - smemb + l(topline + cy + 1)-l(topline + cy)
              IF sele < 0 THEN
                sele = foffset + l(lc) - smemb
              ELSEIF sele > foffset + l(lc) - smemb THEN
                sele = foffset + l(lc) - smemb
              END IF
    
    
              updatecaret(cx, cy, cw, ch, coffset, topline)
    
              invalidaterect hwndc, BYVAL 0, BYVAL 0
              updatewindow hwndc
    
    
            CASE %IDM_COPY, %IDM_COPYFILE
              IF sels < sele THEN
                sel1 = sels : sel2 = sele
              ELSE
                sel1 = sele : sel2 = sels
                SWAP ls, le
              END IF
    
    
              OPEN f$ FOR BINARY AS #5 BASE=0
                SEEK #5, sel1
                GET$ #5, sel2 - sel1, d$
              CLOSE #5
    
              IF LEN(d$) THEN
                e$="File : "+CHR$(34)+f$+CHR$(34)+$CRLF+_
                   "Line # "+FORMAT$(ls, "#,")+" - Line # "+FORMAT$(le, "#,")+$CRLF
    
                IF hexflag=1 THEN
                  e$=e$+"Fileoffset "+LEFT$(HEX$(sel1, 2), 2)+"_"+RIGHT$(HEX$(sel1, 8), 8)+_
                        " - Fileoffset : "+LEFT$(HEX$(sel2, 2),2 )+"_"+RIGHT$(HEX$(sel2, 8), 8)
                ELSE
                  e$=e$+"Fileoffset "+FORMAT$(sel1, "#,")+" - Fileoffset : "+FORMAT$(sel2, "#,")
                END IF
                e$=e$+$CRLF+$CRLF
    
                IF LOWRD(wParam) = %IDM_COPY THEN
                  CLIPBOARD SET TEXT e$+d$
    '              MSGBOX e$+d$
                ELSE
                  DISPLAY OPENFILE hwnd,,, " Save Selection as ...", "C:\", CHR$("All Files", 0, "*.*", 0), _
                               "", "", %OFN_EXPLORER TO t$
    
                  IF LEN(t$) THEN
                    OPEN t$ FOR BINARY AS #5 BASE=0
                      PUT$ #5, e$+d$
                    CLOSE #5
                  END IF
                END IF
              ELSE
                MSGBOX "  Copy failed", %MB_ICONEXCLAMATION, " ERROR"
              END IF
    
              EXIT FUNCTION
    
    
            CASE %IDM_FIND
              IF fc>0 THEN                                'if there are results
                q=ff(lparam)
    
                FOR i=1 TO pc-1                           'find chunk
                  IF q < p(i) THEN
                    cp=i
                    getfile(cp)                           'read
                    q=q-foffset
                    GOTO exit_find
                  END IF
                NEXT i
    
                IF pc>1 THEN                              'if in last part and if more than  one part
                  cp=pc-1
                  getfile(cp)
                  q=q-foffset
                END IF
    
    exit_find:
                FOR i=1 TO lc                             'find line
                  IF q < l(i) - smemb THEN
                    cx=0
                    cy=lps/2
                    topline=i-cy-1                        'set topline (place line in the middle)
                    q=q-(l(i-1) - smemb)
                    EXIT FOR
                  END IF
                NEXT i
    
                IF topline < 0 THEN                       'adapt min/max value for topline
                  cy=cy+topline'-1
                  topline=0
                ELSEIF topline > lc-lps THEN
                  cy=cy+topline-(lc-lps)
                  topline = lc-lps
                  IF topline < 0 THEN                       'adapt min/max value for topline
                    cy=cy+topline'-1
                    topline=0
                  END IF
                END IF
    
    
                selflag=11                                'set selection
                sels = foffset + l(topline + cy) - smemb + MIN(q, l(topline + cy + 1)-l(topline + cy))
                IF sels < 0 THEN
                  sels = foffset + l(lc) - smemb
                ELSEIF sels > foffset + l(lc) - smemb THEN
                  sels = foffset + l(lc) - smemb
                END IF
    
    
                sele = foffset + l(topline + cy) - smemb + MIN(q+LEN(fnd$), l(topline + cy + 1)-l(topline + cy))
                IF sele < 0 THEN
                  sele = foffset + l(lc) - smemb
                ELSEIF sele > foffset + l(lc) - smemb THEN
                  sele = foffset + l(lc) - smemb
                END IF
    
    
                IF q>cpl THEN                             'bring into view (centered), if necessary
                  coffset=q-cpl/2
                ELSE
                  coffset=0
                END IF
    
                updatecaret(cx, cy, cw, ch, coffset, topline)
    
                invalidaterect hwndc, BYVAL 0, BYVAL 0
                updatewindow hwndc
              END IF
    
          END SELECT
    
    
        CASE %WM_erasebkgnd
          FUNCTION = 1                                    'just do nothing
          EXIT FUNCTION
    
    
        CASE %WM_PAINT
          IF hexflag=0 THEN
    '***********************************************************************************************
    ' draw text
    '***********************************************************************************************
            hdc = BeginPaint(hWnd, ps)                    'initiates window painting
              getclientrect hwnd, r
              hmemdc = createcompatibledc (hdc)
              hbmp = createcompatiblebitmap (hdc, r.nright, r.nbottom)
    
              CALL SelectObject (hmemdc, hbmp)
              CALL SelectObject (hmemdc, hfont)
              fillrect hmemdc, r, getstockobject(%White_Brush)                'draw background
    
    
              IF lc>0 THEN
                FOR i=topline TO topline+lps
                  IF i>lc-1 THEN EXIT FOR
                  CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL l(i)+coffset, MIN(cpl, l(i+1)-l(i)-coffset)) 'line by line
                NEXT i
    
                IF selflag>0 THEN                         'draw selection
                  enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_ENABLED)
    
                  IF selflag < 10 THEN
                    setbkcolor hmemdc, RGB(200, 200, 255)
                  ELSE
                    setbkcolor hmemdc, RGB(255, 200, 200)
                  END IF
    
    
                  IF sels < sele THEN
                    sel1 = sels : sel2 = sele
                  ELSE
                    sel1 = sele : sel2 = sels
                  END IF
    
    
                  ly = sel1 - foffset
                  FOR i=1 TO lc
                    IF ly <= l(i) - smemb THEN
                      ly = i-1
                      lx = sel1 - foffset - l(i-1) + smemb
                      EXIT FOR
                    END IF
                  NEXT i
    
                  hy = sel2 - foffset
                  FOR i=1 TO lc
                    IF hy <= l(i) - smemb THEN
                      hy = i-1
                      hx = sel2 - foffset - l(i-1) + smemb
                      EXIT FOR
                    END IF
                  NEXT i
    
    
                  FOR i=topline TO topline+lps
                    IF i>lc-1 THEN EXIT FOR
    
                    IF ly=i THEN
                      IF ly=hy THEN                       'selection only in one line
                        d$=PEEK$(l(i), l(i+1)-l(i))
                        n=LEN(d$)
                        IF lx<n THEN                      'if inside line (not beyond end)
                        IF hx=n THEN                      'if selected until end of line
                          d$=MID$(d$, lx+1, hx-lx)+SPACE$(cpl+10)
                          CALL TextOut (hmemdc, %mg+(lx-coffset)*cw, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                        ELSE                              'if selection ends before line ends
                          d$=MID$(d$, lx+1, hx-lx)
                          CALL TextOut (hmemdc, %mg+(lx-coffset)*cw, (i-topline)*ch, BYVAL STRPTR(d$), LEN(d$))
                        END IF
                        END IF
                      ELSE                                'first line of selectiom
                        d$=PEEK$(l(i), l(i+1)-l(i))
                        n=LEN(d$)
                        IF lx<n THEN                      'if inside line (not beyond end)
                          IF coffset < lx THEN
                            d$=MID$(d$, lx+1)+SPACE$(cpl+10)
                            CALL TextOut (hmemdc, %mg+(lx-coffset)*cw, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                          ELSE
                            d$=MID$(d$, coffset+1)+SPACE$(cpl+10)
                            CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                          END IF
                        END IF
                      END IF
                    ELSEIF ly<i THEN
                      IF hy=i THEN                        'last line of selection
                        d$=PEEK$(l(i), l(i+1)-l(i))
                         n=LEN(d$)
                        IF hx=n THEN                      'if selected until end of line
                          d$=MID$(d$, coffset+1, hx)+SPACE$(cpl+10)
                          CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                        ELSE                              'if selection ends before line ends
                          d$=MID$(d$, coffset+1, hx)
                          CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), hx-coffset)
                        END IF
                      ELSEIF hy>i THEN                    'totally selected line
                        d$=PEEK$(l(i), l(i+1)-l(i))
                        d$=MID$(d$, coffset+1)+SPACE$(cpl+10)
                        CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                      END IF
                    END IF
                  NEXT i
    
                ELSE
                  enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_GRAYED)
                END IF
              END IF
    
              BitBlt(hDC, 0, 0, r.nright-r.nleft, r.nbottom-r.ntop, hmemdc, 0, 0, %SRCCOPY) 'draw entire clientarea
              deletedc hmemdc
              deleteobject hbmp
            CALL EndPaint(hWnd, ps)                       'ends window painting
    
          ELSE
    '***********************************************************************************************
    ' draw hex
    '***********************************************************************************************
    LOCAL hdc1      AS DWORD
    LOCAL hmemdc1   AS DWORD
    LOCAL hbmp1     AS DWORD
    LOCAL r1        AS rect
    
            hdc = BeginPaint(hWnd, ps)                    'initiates window painting (text)
              getclientrect hwnd, r
              hmemdc = createcompatibledc (hdc)
              hbmp = createcompatiblebitmap (hdc, r.nright, r.nbottom)
              CALL SelectObject (hmemdc, hbmp)
              CALL SelectObject (hmemdc, hfont)
              fillrect hmemdc, r, getstockobject(%White_Brush)                'draw background
    
              hdc1 = getdc(hwndmain)                      'get dc for hex
              r1 = r
              r1.nright = r1.nleft+69*cw+1
              r1.nbottom = r1.nbottom + 2
              hmemdc1 = createcompatibledc (hdc1)
              hbmp1 = createcompatiblebitmap (hdc1, r1.nright, r1.nbottom)
    
              CALL SelectObject (hmemdc1, hbmp1)
              CALL SelectObject (hmemdc1, hfont)
              setbkmode hmemdc1, %Transparent
              fillrect hmemdc1, r1, getsyscolorbrush(%COLOR_Infobk)           'draw background
              framerect hmemdc1, r1, getsyscolorbrush(%COLOR_WINDOWFRAME)     'draw border
    
              r1.nright = r1.nleft+13*cw+1
              fillrect hmemdc1, r1, getsyscolorbrush(%COLOR_3DFace)           'draw background
              framerect hmemdc1, r1, getsyscolorbrush(%COLOR_WINDOWFRAME)     'draw border
    
              r1 = r
              r1.nright = r1.nleft+69*cw+1
              r1.nbottom = r1.nbottom + 2                 'restore hex dc´s dimensions
    
    
              IF lc>0 THEN
                FOR i=topline TO topline+lps
                  IF i>lc-1 THEN EXIT FOR
                  lp=hexview(BYVAL l(i), l(i+1)-l(i), foffset + i*16)
                  CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL lp+70, 16) 'line by line (text)
                  CALL TextOut (hmemdc1, %mg, (i-topline)*ch, BYVAL lp, 69)   'line by line (hex)
                NEXT i
    
    
                IF selflag>0 THEN                         'draw selection
                  enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_ENABLED)
    
                  IF selflag < 10 THEN
                    setbkcolor hmemdc, RGB(200, 200, 255)
                  ELSE
                    setbkcolor hmemdc, RGB(255, 200, 200)
                  END IF
    
    
                  IF sels < sele THEN
                    sel1 = sels : sel2 = sele
                  ELSE
                    sel1 = sele : sel2 = sels
                  END IF
    
    
                  ly = sel1 - foffset
                  FOR i=1 TO lc
                    IF ly <= l(i) - smemb THEN
                      ly = i-1
                      lx = sel1 - foffset - l(i-1) + smemb
                      EXIT FOR
                    END IF
                  NEXT i
    
                  hy = sel2 - foffset
                  FOR i=1 TO lc
                    IF hy <= l(i) - smemb THEN
                      hy = i-1
                      hx = sel2 - foffset - l(i-1) + smemb
                      EXIT FOR
                    END IF
                  NEXT i
    
                  FOR i=topline TO topline+lps            'line by line
                    IF i>lc-1 THEN EXIT FOR
                    lp=hexview(BYVAL l(i), l(i+1)-l(i), foffset + i*16)
    
    '                setbkcolor hmemdc1, getsyscolor(%COLOR_Infobk)
                    settextcolor hmemdc1, RGB(255,0,0)
    
                    IF ly=i THEN
                      IF ly=hy THEN                       'selection only in one line
                        CALL TextOut (hmemdc, %mg + lx*cw, (i-topline)*ch, BYVAL lp+70+lx, hx-lx)
    
    LOCAL x AS DWORD
    LOCAL y AS DWORD
    '***********************************************************************************************
    ' "00:00000000 : xx xx xx xx - xx xx xx xx = xx xx xx xx - xx xx xx xx  : .... .... .... ...." + $CRLF
    ' offset = 14
    ' 0-1 ok, ab 4 +2, ab 8 +4, ab 12 +6
    '***********************************************************************************************
    
                        x=(lx*3 + INT(lx/4)*2)
                        y=(hx*3 + INT((hx-1)/4)*2)
                        CALL TextOut (hmemdc1, %mg + 14*cw + x*cw, (i-topline)*ch, BYVAL lp+14+x, y-x)
    
                      ELSE                                'first line of selectiom
                        CALL TextOut (hmemdc, %mg + lx*cw, (i-topline)*ch, BYVAL lp+70+lx, 16-lx)
    
                        x=(lx*3 + INT(lx/4)*2)
    '                    y=(16*3 + INT((16-1)/4)*2)      '=54
                        CALL TextOut (hmemdc1, %mg + 14*cw + x*cw, (i-topline)*ch, BYVAL lp+14+x, 54-x)
                      END IF
    
                    ELSEIF ly<i THEN
                      IF hy=i THEN                        'last line of selection
                        CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL lp+70, hx)
    
                        y=(hx*3 + INT((hx-1)/4)*2)
                        CALL TextOut (hmemdc1, %mg + 14*cw, (i-topline)*ch, BYVAL lp+14, y)
    
                      ELSEIF hy>i THEN                    'totally selected line
                        CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL lp+70, 16)
                        CALL TextOut (hmemdc1, %mg + 14*cw, (i-topline)*ch, BYVAL lp+14, 54)
                      END IF
                    END IF
                  NEXT i
    
                ELSE
                  enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_GRAYED)
                END IF
    
              END IF
    
              BitBlt(hDC, 0, 0, r.nright-r.nleft, r.nbottom-r.ntop, hmemdc, 0, 0, %SRCCOPY) 'draw entire clientarea (text)
              deletedc hmemdc
              deleteobject hbmp
    
              BitBlt(hDC1, 0, 0, r1.nright-r1.nleft, r1.nbottom-r1.ntop, hmemdc1, 0, 0, %SRCCOPY) 'draw entire clientarea (hex)
              deletedc hmemdc1
              deleteobject hbmp1
              releasedc hwndmain, hdc1
            CALL EndPaint(hWnd, ps)                       'ends window painting
    
          END IF
    
          IF lc>0 THEN
            setscrollpos hwndc, %SB_VERT, (loffset+topline)/sfy, %true
            setscrollpos hwndc, %SB_HORZ, coffset, %true
            showcaret hwnd
          END IF
    
    
        CASE %WM_DESTROY                                  'exit - clean up
          DeleteObject hfont
          DeleteObject hcaret
          EXIT FUNCTION
    
      END SELECT
    
    
      FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
      EXIT FUNCTION
    
    
    setsels:
      sels = foffset + l(topline + cy) - smemb + MIN(coffset+cx, l(topline + cy + 1)-l(topline + cy))
      IF sels < 0 THEN
        sels = foffset + l(lc) - smemb
      ELSEIF sels > foffset + l(lc) - smemb THEN
        sels = foffset + l(lc) - smemb
      END IF
      ls = loffset + topline + cy + 1
    RETURN
    
    
    setsele:
      sele = foffset + l(topline + cy) - smemb + MIN(coffset+cx, l(topline + cy + 1)-l(topline + cy))
      IF sele < 0 THEN
        sele = foffset + l(lc) - smemb
      ELSEIF sele > foffset + l(lc) - smemb THEN
        sele = foffset + l(lc) - smemb
      END IF
      le = loffset + topline + cy + 1
    RETURN
    
    
    END FUNCTION
    
    
    '***********************************************************************************************
    
    
    FUNCTION Hexview(BYVAL p AS DWORD, BYVAL n AS DWORD, BYVAL q AS QUAD) AS DWORD
    '***********************************************************************************************
    ' "00:00000000 : xx xx xx xx - xx xx xx xx = xx xx xx xx - xx xx xx xx  : .... .... .... ...." + $CRLF
    ' deliver 16 bit output or shorter, regardless if input is longer
    ' no need for longer strings, bcause you can copy it to a file and then use a hexeditor
    '***********************************************************************************************
    #REGISTER NONE
    
    LOCAL pDataIn AS DWORD
    LOCAL pDataout AS DWORD
    STATIC buffer$
    
    
      buffer$ = SPACE$(100)
    
    
      pDataout = STRPTR(buffer$)
      pDataIn = p
      n = pdatain+n
    
    
    !  lea esi, q
    !  mov edi, pdataout                   ;get pointer to output buffer
    !  lea edx, hextable_1
    
    
    '***********************************************************************************************
    ' 10 hex digit offset
    '***********************************************************************************************
    
    !  mov ecx, [esi+4]                    ;get high dword of offset (quad)
    !  movzx ebx, cl                       ;get the low byte of high dword of offset
    !  mov eax, &h205F2020                 ;" _  "
    !  mov ax, [edx+ebx*2]                 ;look up the HEX equivalent characters
    
    !  mov [edi], eax                      ;store the 4 HEX characters in the output buffer
    
    !  mov ecx, [esi]                      ;get low dword of offset (quad)
    !  movzx ebx, cl                       ;get the low byte of low dword of offset
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  shl eax, 16                         ;move them into place in the top half of register
    !  movzx ebx, ch                       ;get the high byte
    !  mov ax, [edx+ebx*2]                 ;look up the hex equvalent charcters and put them in the lower half of eax
    
    !  mov [edi+7], eax                    ;store it in the output buffer
    
    !  shr ecx, 16                         ;get the 2 upper bytes into the lower half of the register so I can get at them
    !  movzx ebx, cl                       ;get the middle byte
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  shl eax, 16                         ;move them into place in the top half of register
    !  movzx ebx, ch                       ;get the high byte
    !  mov ax, [edx+ebx*2]                 ;look up the hex equvalent charcters and put them in the lower half of eax
    
    !  mov [edi+3], eax                    ;store the 4 HEX characters in the output buffer
    !  mov dword ptr [edi+11], &h20202020  ;"  : "
    '!  mov dword ptr [edi+11], &h20203A20  ;"  : "
    
    !  mov dword ptr [edi+72], &h20202020  ;"  : "
    '!  mov dword ptr [edi+72], &h20203A20  ;"  : "
    !  sub edi, 1
    
    
    '***********************************************************************************************
    'now 16 bytes of HEX data
    '***********************************************************************************************
    
    !  mov ecx, n                          ;end pos
    !  mov esi, pDataIn                    ;get pointer to input buffer
    
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+15], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+71], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+18], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+72], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+21], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+73], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+24], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+74], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  mov dword ptr [edi+26], &h20202D20  ;" -  "
    !  add edi, 14
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+15], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+61], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+18], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+62], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+21], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+63], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+24], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+64], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  mov dword ptr [edi+26], &h20203D20  ;" =  "
    !  add edi, 14
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+15], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+51], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+18], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+52], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+21], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+53], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+24], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+54], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  mov dword ptr [edi+26], &h20202D20  ;" -  "
    !  add edi, 14
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+15], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+41], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+18], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+42], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+21], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+43], al                    ;write byte
    !  add esi, 1
    !  cmp esi, ecx
    !  jz ende
    
    !  movzx ebx, byte ptr [esi]           ;1. nibble
    !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
    !  mov [edi+24], ax                    ;write bytes
    !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
    !  mov [edi+44], al                    ;write byte
    
    
    ende:
    
    
      FUNCTION = STRPTR(buffer$)
    
    
    EXIT FUNCTION
    
    
    hextable_1:
      ! dw "00","10","20","30","40","50","60","70","80","90","A0","B0","C0","D0","E0","F0"
      ! dw "01","11","21","31","41","51","61","71","81","91","A1","B1","C1","D1","E1","F1"
      ! dw "02","12","22","32","42","52","62","72","82","92","A2","B2","C2","D2","E2","F2"
      ! dw "03","13","23","33","43","53","63","73","83","93","A3","B3","C3","D3","E3","F3"
      ! dw "04","14","24","34","44","54","64","74","84","94","A4","B4","C4","D4","E4","F4"
      ! dw "05","15","25","35","45","55","65","75","85","95","A5","B5","C5","D5","E5","F5"
      ! dw "06","16","26","36","46","56","66","76","86","96","A6","B6","C6","D6","E6","F6"
      ! dw "07","17","27","37","47","57","67","77","87","97","A7","B7","C7","D7","E7","F7"
      ! dw "08","18","28","38","48","58","68","78","88","98","A8","B8","C8","D8","E8","F8"
      ! dw "09","19","29","39","49","59","69","79","89","99","A9","B9","C9","D9","E9","F9"
      ! dw "0A","1A","2A","3A","4A","5A","6A","7A","8A","9A","AA","BA","CA","DA","EA","FA"
      ! dw "0B","1B","2B","3B","4B","5B","6B","7B","8B","9B","AB","BB","CB","DB","EB","FB"
      ! dw "0C","1C","2C","3C","4C","5C","6C","7C","8C","9C","AC","BC","CC","DC","EC","FC"
      ! dw "0D","1D","2D","3D","4D","5D","6D","7D","8D","9D","AD","BD","CD","DD","ED","FD"
      ! dw "0E","1E","2E","3E","4E","5E","6E","7E","8E","9E","AE","BE","CE","DE","EE","FE"
      ! dw "0F","1F","2F","3F","4F","5F","6F","7F","8F","9F","AF","BF","CF","DF","EF","FF"
    hextable_2:                                           '= hextable_1 + 512
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
      ! db  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
      ! db  64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79
      ! db  80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
      ! db  96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111
      ! db 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
      ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
    
    
    END FUNCTION
    
    
    '***********************************************************************************************
    '*************************************************************************************************
    '*************************************************************************************************
    
    
    FUNCTION WINMAIN(BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpCmdLine AS ASCIIZ PTR, BYVAL iCmdShow AS LONG) AS LONG
    '*************************************************************************************************
    ' Main Program entry point
    '*************************************************************************************************
    LOCAL Msg         AS TAGMSG
    LOCAL wce         AS WNDCLASSEX
    LOCAL szClassName AS ASCIIZ * 80
    LOCAL hMenu       AS DWORD
    LOCAL hAccel      AS DWORD
    
    
      hinst = hInstance
    
    '*************************************************************************************************
    'Setup, Register and create the main window
    '*************************************************************************************************
    
      szClassName = "Fileviewer32"
      wce.cbSize = SIZEOF(wce)
      wce.STYLE = %CS_HREDRAW OR %CS_VREDRAW
      wce.lpfnWndProc = CODEPTR(MainProc)
      wce.hInstance = hInstance
      wce.hIcon = LoadIcon(hInstance, "PROGRAM")
      wce.hCursor = LoadCursor(%NULL, BYVAL %IDC_ARROW)
      wce.hbrBackground = GetStockObject(%WHITE_BRUSH)
      wce.lpszClassName = VARPTR(szClassName)
      wce.hIconSm = LoadIcon(hInstance, BYVAL %IDI_APPLICATION)
      RegisterClassEx wce
    
      hMenu = LoadMenu(hInstance, "MAINMENU")
    
      hwndmain = CreateWindow(szClassName, _            'window class name
      "  Large File Viewer", _                            'window caption
      %WS_OVERLAPPEDWINDOW OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN, _         'window style
      %CW_USEDEFAULT, _                                   'initial x position
      %CW_USEDEFAULT, _                                   'initial y position
      %CW_USEDEFAULT, _                                   'initial x size
      %CW_USEDEFAULT, _                                   'initial y size
      %HWND_DESKTOP, _                                    'parent window handle
      hMenu, _                                            'window menu handle
      hInstance, _                                        'program instance handle
      BYVAL %NULL)                                        'creation parameters
    
    
      hAccel = LoadAccelerators(hInstance, "ACC")         'load accelerators
    
    
    '*************************************************************************************************
    'Setup, Register and create the text window
    '*************************************************************************************************
    
      szClassName = "Textviewer32"
      wce.cbSize = SIZEOF(wce)
      wce.STYLE = %CS_HREDRAW OR %CS_VREDRAW
      wce.lpfnWndProc = CODEPTR(ChildProc)
      wce.hInstance = hInstance
      wce.hIcon = 0
      wce.hCursor = LoadCursor(%NULL, BYVAL %IDC_ARROW)
      wce.hbrBackground = GetStockObject(%WHITE_BRUSH)
      wce.lpszClassName = VARPTR(szClassName)
      wce.hIconSm = 0
      RegisterClassEx wce
    
      hwndc = CreateWindow(szClassName, _                 'window class name
      "", _                                               'window caption
      %WS_CHILD OR %WS_BORDER OR %WS_VSCROLL OR %WS_HSCROLL OR %WS_CLIPSIBLINGS, _ 'window style
      %CW_USEDEFAULT, _                                   'initial x position
      %CW_USEDEFAULT, _                                   'initial y position
      %CW_USEDEFAULT, _                                   'initial x size
      %CW_USEDEFAULT, _                                   'initial y size
      HWNDMAIN, _                                         'parent window handle
      300, _                                              'window id
      hInstance, _                                        'program instance handle
      BYVAL %NULL)                                        'creation parameters
    
    
    
      ShowWindow hwndc, %SW_SHOW                          'show child
    
      ShowWindow hwndmain, iCmdShow                       'show main window
      UpdateWindow hwndmain                               'draw
    
      setfocus hwndc                                      'set focus to textwindow
    
    
      DO WHILE GetMessage(Msg, BYVAL %NULL, 0, 0)         'message loop
        IF ISFALSE TranslateAccelerator(hwndmain, hAccel, Msg) THEN
          TranslateMessage Msg
          DispatchMessage Msg
        END IF
      LOOP
    
    
      GLOBALMEM FREE  smemh TO smemh                      'clean up
      FUNCTION = msg.wParam
    
    
    END FUNCTION
    
    
    '***********************************************************************************************
    
    
    FUNCTION getfile(chunk AS DWORD) AS LONG
    '***********************************************************************************************
    ' read part of file into buffer for viewing, l() holds pointers to corresponding lines
    ' (l(1)=line #1 and so on, lc = line count (0=there are no lines, 5=lines # 1,2,3,4,5 exist)
    ' cut long lines after %max_lines and make it a new line, even if there is no delimiter
    '***********************************************************************************************
    'LOCAL qFreq AS QUAD
    'LOCAL qStart AS QUAD
    'LOCAL qStop AS QUAD
    '   QueryPerformanceFrequency qFreq
    '   QueryPerformanceCounter   qStart
    '***********************************************************************************************
    LOCAL n     AS LONG
    LOCAL y     AS QUAD
    LOCAL z     AS LONG
    LOCAL dp    AS LONG                                   'delimiter pos
    LOCAL pdp    AS LONG                                  'previous delimiter pos
    
    LOCAL hfile AS DWORD
    
    REGISTER c AS LONG
    REGISTER x AS LONG
    
    
      hFile = CreateFile(BYVAL STRPTR(f$), %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0, _
                         %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, BYVAL 0)
    
      IF hFile = %INVALID_HANDLE_VALUE THEN
      END IF
    
    
      IF hexflag=0 THEN                                   'standart view
        foffset = p(chunk-1)                              'total fileoffest
        loffset = p1(chunk-1)                             'total lineoffest
    
        IF pc > 1 THEN                                    'if more than one chunks
          x=p(chunk+1)-p(chunk-1)                         'get these two
          n=p1(chunk+1)-p1(chunk-1)                       '# of lines needed
    
        ELSE                                              'if only one chunk
          x=p(chunk)-p(chunk-1)                           'get this one
          n=p1(chunk)-p1(chunk-1)                         '# of lines needed
        END IF
    
    
        REDIM l(n+10)
        c = ASC(delimiter)
    
    
        setfilepointer hfile, foffset, BYVAL 0, %File_Begin
        readfile(hfile, BYVAL smemb, BYVAL x, z, BYVAL 0) 'read
    
        IF z > 0 THEN
          l(0)=smemb                                      'ptr to first line
          lc=0
          n=1
    
          REDIM char(z-1) AS BYTE AT smemb
          pdp = smemb
    
          FOR x = 0 TO z-1
            IF char(x) = c THEN
              IF PEEK$(smemb+x, LEN(delimiter))=delimiter THEN                'check for (multibyte) delimiter
                dp = x+LEN(delimiter) + smemb             'ptr to next line
                IF dp-pdp > %max_line THEN                'exceeds max line lentght (%max_line)
                  FOR y=1 TO CEIL((dp-pdp)/%max_line)-1
                    pdp = pdp + %max_line
                    l(n) = pdp                            'insert line breaks (might be inside a word !!!)
                    INCR n
                    lmax=MAX(lmax, l(n)-l(n-1))
                  NEXT y
                END IF
    
                l(n) = dp
                lmax=MAX(lmax, l(n)-l(n-1))
                pdp = dp
    
                INCR n
              END IF
            END IF
          NEXT
    
          lc=n-1                                          '# of valid lines (1 to n-2)
    
    
          IF l(n-1)<smemb+z THEN                          'if it doesn´t end with a delimiter
            dp = smemb+z
            IF dp-pdp > %max_line THEN                    'exceeds max line lentght (%max_line)
              FOR y=1 TO CEIL((dp-pdp)/%max_line)-1
                pdp = pdp + %max_line
                l(n) = pdp                                'insert line breaks (might be inside a word !!!)
                INCR n
                lmax=MAX(lmax, l(n)-l(n-1))
              NEXT y
              lc=n-1                                      '# of valid lines (1 to n-2)
            END IF
    
            l(n)=smemb+z
            lmax=MAX(lmax, l(n)-l(n-1))
            lc=lc+1
          END IF
        END IF
    
    
      ELSE                                                'hex view
        foffset = p(chunk-1)
        IF foffset MOD 16 <> 0 THEN foffset = foffset + 16 - foffset MOD 16   'set it on 16 byte border
        loffset = foffset/16                              'total lineoffest
    
    
        IF pc > 1 THEN                                    'if more than one chunks
          y=p(chunk+1)
          IF y MOD 16 <> 0 THEN y = y + 16 - y MOD 16     'set it on 16 byte border
          x=y-foffset
    
        ELSE                                              'if only one chunk
          y=p(chunk)
          IF y MOD 16 <> 0 THEN y = y + 16 - y MOD 16     'set it on 16 byte border
          x=y-foffset
        END IF
    
    
        REDIM l(x/16+10)
        c=smemb
    
        setfilepointer hfile, foffset, BYVAL 0, %File_Begin
        readfile(hfile, BYVAL smemb, BYVAL x, z, BYVAL 0) 'read
    
        IF z > 0 THEN
          l(0)=smemb                                      'ptr to first line
          lc=0
          n=1
    
          FOR x = 1 TO INT(z/16)
            c=c+16
            l(n)=c
            INCR n
          NEXT x
    
          lc=n-1                                          '# of valid lines (1 to n-2)
          lmax=16
    
    
          IF l(2)=0 THEN                                  'only one line
            l(n)=smemb+z
            lc=1
    
          ELSEIF l(n-1)<smemb+z THEN                      'if it doesn´t end with a delimiter
            l(n)=smemb+z
            lc=lc+1
          END IF
        END IF
    
      END IF
    
    
      CloseHandle hfile
      FUNCTION=1
    
    
    '***********************************************************************************************
    '   QueryPerformanceCounter   qStop
    '   ? FORMAT$(1000*(qStop-qStart)/qFreq,"###.00") & " milliseconds   "
    '***********************************************************************************************
    END FUNCTION
    
    
    '***********************************************************************************************
    
    
    THREAD FUNCTION do_scan(BYVAL dummy AS LONG) AS LONG
    '***********************************************************************************************
    ' scan file (Filename) for delimiter in portions of %partsize, save delimiter positions for
    ' each part (=chunk) as fileoffset in p(), save cooreponding line # in p1(), p() and p1() are
    ' zerobased
    '***********************************************************************************************
    LOCAL i      AS LONG
    LOCAL n      AS LONG                                  '# of estimated parts
    LOCAL y      AS LONG
    LOCAL z      AS LONG
    LOCAL hfile  AS DWORD                                 'handle of file
    LOCAL lf     AS QUAD                                  'lenght of file
    LOCAL ld     AS QUAD                                  'last delimiter
    LOCAL pld    AS QUAD                                  'previous last delimiter
    
    REGISTER c AS LONG
    REGISTER x AS LONG
    
    
      hFile = CreateFile(BYVAL STRPTR(f$), %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0, _
                         %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, BYVAL 0)
    
      IF hFile = %INVALID_HANDLE_VALUE THEN
      END IF
    
    
      getfilesizeex(hfile, lf)                             'total lenght of file
      n = lf/%partsize + 1                                 '# of read operations needed
    
      REDIM p(n)
      REDIM p1(n)
    
      smeml=%partsize*2+%max_line*2+1000                  'two chunks + 2*%maxline overhead + 1000 (just to be sure)
      GLOBALMEM ALLOC smeml TO smemh                      'allocate memory for viewing
      GLOBALMEM LOCK  smemh TO smemb
    
      smeml1=%partsize+LEN(delimiter)+100
      GLOBALMEM ALLOC smeml1 TO smemh1                    'allocate memory for scanning
      GLOBALMEM LOCK  smemh1 TO smemb1
    
    
      c     = ASC(delimiter)                              'first delimitting char
      cp    = 1                                           'first part
      pc    = 0                                           'initial part count
      pld   = 0                                           'previous last delimiter
      tlc   = 0
      p(0)  = 0                                           'start of file
      p1(0) = 0                                           'line # (first line = 0)
    
      FOR i=1 TO n
        readfile(hfile, BYVAL smemb1, BYVAL %partsize+LEN(delimiter), y, BYVAL 0) 'read
    
        POKE$ smemb1+y, CHR$(0,0,0,0)                     'put &H00000000 at the end of each part read
        IF %partsize+LEN(delimiter) <> y THEN             'if read less than requested, we just read last part
          z=y                                             'because in last loop we want to process all chars read
        ELSE
          z=y-LEN(delimiter)                              'for every other loop, pprocess %partsize bytes (chars)
        END IF
        IF z <= 0 THEN EXIT FOR
    
        REDIM char(z-1) AS BYTE AT smemb1                 'define byte array
        FOR x = 0 TO z-1                                  'scan char for char
          IF char(x) = c THEN                             'if found
            IF PEEK$(smemb1+x, LEN(delimiter))=delimiter THEN                 'check for (multibyte) delimiter
              ld = (i-1)*%partsize+x+LEN(delimiter)       'save last delimiter pos
              INCR tlc
    
              tlc = tlc + CEIL((ld-pld)/%max_line) - 1    'increase if max line lenght is exceeded
              pld = ld
            END IF
          END IF
        NEXT
    
        INCR pc                                           'increase parts count
        p(pc)  = ld                                       '(file)position of chunk (zerobased)
        p1(pc) = tlc                                      'corresponding line # (zero based)
    
        IF i=2 THEN
          postmessage hwndc, %WM_COMMAND, 5000, 0         'first two chunks are read, start viewing
        END IF
    
    
        postmessage hwndmain, %WM_USER + 1000, i*10000/n, 0                   'indexing progress message (lparam=0)
    
        sfy = tlc/32000
        postmessage hwndc, %WM_COMMAND, 5001, 0           'update y scrollbar
    
        setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Lines"
    
    
        IF %partsize+LEN(delimiter) <> y THEN EXIT FOR
        setfilepointerex hfile, LEN(delimiter)*-1, BYVAL 0, %File_Current
      NEXT i
    
    
      IF p(pc)<lf THEN                                    'if it doesn´t end with a delimiter
        ld = lf
        tlc = tlc + CEIL((ld-pld)/%max_line) - 1          'increase if max line lenght is exceeded
    
        p(pc) = lf
        INCR tlc
        p1(pc) = tlc
        setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Lines"
        IF pc<3 THEN
          postmessage hwndc, %WM_COMMAND, 5000, 0         'reread first chunk, restart viewing
        END IF
      END IF
    
      IF pc=1 THEN
        postmessage hwndc, %WM_COMMAND, 5000, 0           'if only one chunk, start viewing
      END IF
    
    
      CloseHandle hfile
    
    
      sfy = tlc/32000
      postmessage hwndc, %WM_COMMAND, 5001, 0           'update y scrollbar
      tlc_h = CEIL(lf/16)
      tlc_t = tlc
      sfy_h = tlc_h/32000
      sfy_t = sfy
      GLOBALMEM FREE  smemh1 TO smemh1
      postmessage hwndmain, %WM_USER + 1000, 0, 10        'show we are done (lparam=10)
    
    
    END FUNCTION
    
    
    '***********************************************************************************************
    
    
    THREAD FUNCTION do_find(BYVAL dummy AS LONG) AS LONG
    '***********************************************************************************************
    ' scan file (f$) for fnd$ in portions of %partsize (case insensitive), save positions found
    ' ff() holds fileoffsets of found locations (zerobased, ff(0)=first location, 0=first byte
    ' in file, fc = found count (0=no results, 2=two results found)
    '***********************************************************************************************
    LOCAL i      AS LONG
    LOCAL n      AS LONG                                  '# of estimated parts
    LOCAL z      AS LONG
    LOCAL hfile  AS DWORD                                 'handle of file
    LOCAL lf     AS QUAD                                  'lenght of file
    LOCAL fmax   AS DWORD
    LOCAL c1     AS LONG
    LOCAL ufnd$
    
    REGISTER c AS LONG
    REGISTER x AS LONG
    
    
      hFile = CreateFile(BYVAL STRPTR(f$), %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0, _
                         %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, BYVAL 0)
    
      IF hFile = %INVALID_HANDLE_VALUE THEN
      END IF
    
    
      getfilesizeex(hfile, lf)                            'total lenght of file
      n = lf/%partsize + 1                                '# of read operations needed
                                                          'found max
      fmax=10000
      REDIM ff(fmax)
    
    
      smeml1=%partsize+LEN(fnd$)+100
      GLOBALMEM ALLOC smeml1 TO smemh1                    'allocate memory for scanning
      GLOBALMEM LOCK  smemh1 TO smemb1
    
    
      ufnd$ = UCASE$(fnd$)
      fc    = 0                                           'found count
      c     = ASC(fnd$)                                   'first find char
      c1    = ASC(ufnd$)                                  'first find char (uppercase)
    
      FOR i=1 TO n
        readfile(hfile, BYVAL smemb1, BYVAL %partsize+LEN(fnd$), z, BYVAL 0) 'read
    
        POKE$ smemb1+z, CHR$(0,0,0,0)                     'put &H00000000 at the end of each part read
        IF i<n THEN                                       'skip last iteration
          z=z-LEN(fnd$)                                   'because in last loop we want to process all chars read
        END IF
        IF z <= 0 THEN EXIT FOR
    
        REDIM char(z-1) AS BYTE AT smemb1                 'define byte array
        FOR x = 0 TO z-1                                  'scan char for char
          IF char(x) = c THEN                             'if found
            GOTO found
          ELSEIF char(x) = c1 THEN                        'if found
    found:
            IF UCASE$(PEEK$(smemb1+x, LEN(fnd$)))=ufnd$ THEN       'check for (multibyte) fnd$
              ff(fc) = (i-1)*%partsize+x                  'save found pos
              INCR fc
              IF fc MOD 10000 = 0 THEN
                IF MSGBOX(" There are already "+FORMAT$(fc)+" hits "+$CRLF+"Continue ?", _
                          %MB_YESNO OR %MB_ICONQUESTION, " Search") = %IDYES THEN
                  fmax=fmax+10000
                  REDIM PRESERVE ff(fmax)
                ELSE
                  GOTO done
                END IF
              END IF
            END IF
          END IF
        NEXT
    
        postmessage hwndmain, %WM_USER + 1000, i*10000/n, 1                   'find progress message (lparam=1)
        setfilepointerex hfile, LEN(fnd$)*-1, BYVAL 0, %File_Current
    
      NEXT i
    
    
    done:
      CloseHandle hfile
    
    
      GLOBALMEM FREE  smemh1 TO smemh1
      postmessage hwndmain, %WM_USER + 1000, 0, 11        'show we are done (lparam=11)
    
    
    END FUNCTION
    
    
    '***********************************************************************************************
    
    
    SUB editbox (flag AS LONG)
    '***********************************************************************************************
    ' enter line # for goto, fill in text for find, show inside statusbar, use different colors
    ' for goto and find, animate searching
    '***********************************************************************************************
    LOCAL n1       AS DOUBLE
    LOCAL r        AS rect
    LOCAL s        AS sizel
    LOCAL s1       AS sizel
    LOCAL hdc      AS LONG
    LOCAL nstyle   AS LONG
    LOCAL ztext    AS ASCIIZ * 256
    
    
      IF iswindow(hwnde) THEN destroywindow hwnde
    
      hwnde = CreateWindowEx(0, "Edit", BYVAL %NULL, %WS_CHILD OR %WS_BORDER OR %WS_VISIBLE OR %ES_LEFT OR %ES_AUTOHSCROLL, _
                 0, 0, 0, 0, hstatus, 210+flag, hInst, BYVAL 0 )
    
      sendmessage hwnde, %WM_Setfont, sendmessage(hstatus, %WM_Getfont, 0, 0), -1
    
      sendmessage hwnde, %EM_Setmargins, %EC_Leftmargin, 3
    
      oldeditproc=getwindowlong(hwnde, %GWL_Wndproc)      'get address of old window procedure
      CALL setwindowlong(hwnde, %GWL_Wndproc, CODEPTR(neweditproc))           'subclass
    
      oldstatusproc=getwindowlong(hstatus, %GWL_Wndproc)  'get address of old window procedure
      CALL setwindowlong(hstatus, %GWL_Wndproc, CODEPTR(newstatusproc))       'subclass
    
    
      IF flag=0 THEN                                      'goto
        n1 = INT(LOG10(tlc))+ 5
        sendmessage hwnde, %EM_Setlimittext, n1, 0
        IF hexflag=1 THEN
          ztext = "  Goto Position (0x0 - 0x"+HEX$(p(pc))+") :  "
        ELSE
          ztext = "  Goto Line (1 -"+STR$(tlc)+") :  "
        END IF
    
      ELSEIF flag = 1 THEN                                'find
        ztext = "  Find :  "
        IF LEN(fnd$) THEN
          setwindowtext hwnde, BYVAL STRPTR(fnd$)
          sendmessage hwnde, %EM_Setsel, 0, -1
        END IF
      ELSEIF flag = 2 THEN                                'ascii
        ztext = "  Ascii Delimiter :  "
      ELSEIF flag = 3 THEN                                'hex
        ztext = "  Hex Delimter :  "
      END IF
    
      sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(ztext)
      sendmessage hstatus, %SB_Getrect, 1, VARPTR(r)      'get to draw in
      sendmessage hstatus, %WM_USER+1000, 0, 0            'make backcolor
    
      hdc=getdc(hstatus)                                  'get hdc
      selectobject hdc, sendmessage(hstatus, %WM_Getfont, 0, 0)
                                                          'select font into dc
      CALL gettextextentpoint32(hdc,ztext,LEN(ztext),s)   'get appropriate width for text
    
      IF flag=0 THEN                                      'goto
        ztext=REPEAT$(n1+1, "0")
        CALL gettextextentpoint32(hdc,ztext,LEN(ztext),s1)                    'get appropriate width edit box
        SetWindowPos hwnde, %NULL, r.nLeft + s.cx, r.nTop + 2, MIN(s1.cx + 8, r.nright-r.nleft - s.cx -4), r.nbottom - r.ntop - 4, _
                   %SWP_NOZORDER OR %SWP_SHOWWINDOW
    
      ELSE                                                'find, Ascii, Hex
        SetWindowPos hwnde, %NULL, r.nLeft + s.cx, r.nTop + 2, r.nright-r.nleft - s.cx -4, r.nbottom - r.ntop - 4, _
                   %SWP_NOZORDER OR %SWP_SHOWWINDOW
      END IF
    
      CALL releasedc(hstatus, hdc)                        'free resources
      setfocus hwnde
    
    
    END SUB
    
    
    '***********************************************************************************************
    
    
    FUNCTION newstatusproc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                       BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    '***********************************************************************************************
    'subclass of statusbar, give editbox a different color for goto and find
    '***********************************************************************************************
    STATIC backbrush AS DWORD
    STATIC backcolor AS DWORD
    
    
      SELECT CASE wMsg
        CASE %WM_USER+1000
          IF getdlgctrlid(hwnde) = 210 THEN               'goto
            backcolor = RGB(200,200,255)
            backbrush=createsolidbrush(backcolor)
    
          ELSEIF getdlgctrlid(hwnde) = 211 THEN           'find
            backcolor = RGB(255,200,200)
            backbrush=createsolidbrush(backcolor)
    
          ELSEIF getdlgctrlid(hwnde) > 211 THEN           'ascii, Hex
            backcolor = RGB(210,210,210)
            backbrush=createsolidbrush(backcolor)
          END IF
    
    
        CASE %WM_CTLCOLOREDIT                             'make non standart backcolor
          setbkcolor wparam, backcolor
          FUNCTION = backbrush
          EXIT FUNCTION
    
    
        CASE %WM_DESTROY
          deleteobject backbrush
    
      END SELECT
    
    
      FUNCTION=callwindowproc(oldstatusproc, hwnd, wmsg, wparam, lparam)
    
    
    END FUNCTION
    
    
    '***********************************************************************************************
    
    
    FUNCTION neweditproc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                       BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    '***********************************************************************************************
    ' subclass of edit in statusbar, catch ESC and ENTER key, close if editbox loses focus
    '***********************************************************************************************
    LOCAL n       AS LONG
    LOCAL ztext   AS STRING
    LOCAL hthread AS DWORD
    LOCAL d$
    
    STATIC q      AS QUAD
    STATIC etext  AS STRING
    
    
      SELECT CASE wmsg
        CASE %WM_KILLFOCUS                                'lost foucus -> destroy
    nep:
          CALL setwindowlong(hstatus, %GWL_Wndproc, oldstatusproc) 'reset subclass
          destroywindow hwnd
          ztext = "  Ready"
          sendmessage hstatus, %SB_SETTEXT, 1, STRPTR(ztext)
          setfocus hwndc
    
    
        CASE %WM_CHAR
          IF wparam = 27 THEN                             'ESC key -> exit
            GOTO nep
          ELSEIF wparam = 13 THEN                         'ENTER key -> finish entry
            n=sendmessage(hwnde, %WM_GETTEXTLENGTH, 0, 0)+1                   '+1, adjust for terminating null char
            etext=SPACE$(n)                               'prepare string buffer
            getwindowtext hwnd, BYVAL STRPTR(etext), n
    
    
            IF getdlgctrlid(hwnd) = 210 THEN              'goto line
              d$=EXTRACT$(etext, CHR$(0))
              IF LEN(d$) THEN                             'if valid
                IF LEFT$(TRIM$(d$), 2) = "0x" THEN        'hex input
                  d$=MID$(TRIM$(d$), 3)                   'cut "0x"
    
                  d$="0"+d$                               'fill in leading zero (to make "val" results unsigned)
                  d$=UCASE$(d$)
                  IF TALLY(d$, ANY "1234567890ABCDEF") = LEN(d$) THEN         'if only valid hex characters
                    q = VAL("&H"+d$)+1
                  ELSE
                    GOTO newedit_find
                  END IF
                ELSE
                  q = VAL(d$)
                END IF
              END IF
    
              IF hexflag=1 THEN
                q = INT(q/16)+1
              END IF
    
              IF q>0 AND q<=tlc THEN                      'if a valid entry
                postmessage hwndc, %WM_COMMAND, %IDM_GOTO, VARPTR(q)          'goto this line
                GOTO nep
              ELSE                                        'invalid
                MessageBeep &HFFFFFFFF
                sendmessage hwnde, %EM_Setsel, 0, -1
              END IF
    
    
            ELSEIF getdlgctrlid(hwnd) = 211 THEN          'find
              d$=EXTRACT$(etext, CHR$(0))
              IF LEN(d$) THEN                             'if valid
                IF LEFT$(TRIM$(d$), 2) = "0x" THEN        'hex input
                  d$=MID$(TRIM$(d$), 3)                   'cut "0x"
    
                  IF LEN(d$) MOD 2 <> 0 THEN d$="0"+d$    'fill in leading zero
                  d$=UCASE$(d$)
                  IF TALLY(d$, ANY "1234567890ABCDEF") = LEN(d$) THEN         'if only valid hex characters
                    fnd$ = ""
                    FOR n=1 TO LEN(d$) STEP 2
                      fnd$ = fnd$ + CHR$(VAL("&H"+MID$(d$, n, 2)))
                    NEXT n
                  ELSE
                    GOTO newedit_find
                  END IF
                ELSE
                  fnd$=d$
                END IF
    
                enablemenuitem (getmenu(hwndmain), %IDM_FIND, %MF_GRAYED)
                enablemenuitem (getmenu(hwndmain), %IDM_FINDNEXT, %MF_GRAYED)
                enablemenuitem (getmenu(hwndmain), %IDM_FINDPREV, %MF_GRAYED)
                THREAD CREATE do_find(BYVAL 0) TO hthread 'start searching
                THREAD CLOSE hthread TO hthread
                GOTO nep
              ELSE                                        'invalid
    newedit_find:
                MessageBeep &HFFFFFFFF
                sendmessage hwnde, %EM_Setsel, 0, -1
              END IF
    
            ELSEIF getdlgctrlid(hwnd) = 212 THEN          'Ascii
              d$=EXTRACT$(etext, CHR$(0))
              IF LEN(d$) THEN                             'if valid
                checkmenuItem(getmenu(hwndmain), %IDM_CRLF, %MF_UNCHECKED)
                checkmenuItem(getmenu(hwndmain), %IDM_CR, %MF_UNCHECKED)
                checkmenuItem(getmenu(hwndmain), %IDM_LF, %MF_UNCHECKED)
                checkmenuItem(getmenu(hwndmain), %IDM_HEX, %MF_UNCHECKED)
                modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii) "+$TAB+CHR$(34)+d$+CHR$(34)
                modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
                checkmenuItem(getmenu(hwndmain), %IDM_ASCII, %MF_CHECKED)
    
                delimiter = d$
    
                MSGBOX " "+CHR$(34)+d$+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                       "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                       " Large File Viewer"
                GOTO nep
              ELSE                                        'invalid
                MessageBeep &HFFFFFFFF
                sendmessage hwnde, %EM_Setsel, 0, -1
              END IF
    
    
            ELSEIF getdlgctrlid(hwnd) = 213 THEN          'Hex
              d$=EXTRACT$(etext, CHR$(0))
              IF LEN(d$) THEN                             'if valid
                IF LEN(d$) MOD 2 <> 0 THEN d$="0"+d$      'fill in leading zero
                d$=UCASE$(d$)
                IF TALLY(d$, ANY "1234567890ABCDEF") = LEN(d$) THEN           'if only valid hex characters
                  checkmenuItem(getmenu(hwndmain), %IDM_CRLF, %MF_UNCHECKED)
                  checkmenuItem(getmenu(hwndmain), %IDM_CR, %MF_UNCHECKED)
                  checkmenuItem(getmenu(hwndmain), %IDM_LF, %MF_UNCHECKED)
                  checkmenuItem(getmenu(hwndmain), %IDM_ASCII, %MF_UNCHECKED)
                  modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
                  modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex) "+$TAB+CHR$(34)+d$+CHR$(34)
                  checkmenuItem(getmenu(hwndmain), %IDM_HEX, %MF_CHECKED)
    
                  delimiter = ""
                  FOR n=1 TO LEN(d$) STEP 2
                    delimiter = delimiter + CHR$(VAL("&H"+MID$(d$, n, 2)))
                  NEXT n
    
                  MSGBOX " "+CHR$(34)+d$+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                         "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                         " Large File Viewer"
                  GOTO nep
                ELSE                                      'invalid
                  MessageBeep &HFFFFFFFF
                  sendmessage hwnde, %EM_Setsel, 0, -1
                END IF
              END IF
            END IF
          END IF
    
    
      END SELECT
    
    
      FUNCTION=callwindowproc(oldeditproc, hwnd, wmsg, wparam, lparam)
    
    
    END FUNCTION
    
    
    '*************************************************************************************************
    '***********************************************************************************************
    '***********************************************************************************************

    .rc + icons -> see attachment


    JK
    Attached Files
    Last edited by Juergen Kuehlwein; 2 Jan 2014, 06:27 AM.

  • #2
    Updated code above, attachment remains the same. Still looking for an elegant solution providing userdefined delimiters (commandline ?, editbox - but what about control characters ?, hex entry ? hmm...)

    Comment


    • #3
      The code above has been updated (including the attachment). Delimiters now can be changed via menu. Everything needs some more and extensive testing. For the moment it seems to work for me. Bugreports and suggestions for improvement are wellcome!


      JK

      Comment


      • #4
        A minor change, it must be

        Code:
        selex=q+LEN(fnd$)+1

        in line 1460.


        Code above including attachment has been updated.


        JK

        Comment


        • #5
          Had to update again, because it could crash under certain circumstances, if no commandline argument was passed.


          JK

          Comment


          • #6
            Next update fixes issues with copy action sometimes not working properly. Comment out the Messagebox in line 1453 showing what is actually copied to clipboard, if you don´t need it.

            Comment


            • #7
              Next Update, Gary found a bug - should be fixed now.

              Comment


              • #8
                Version 2.3 offers a hex view now, made selection code more straight, fine tuned vertical scrollbar resolution and removed (hopefully) some issues.


                JK

                Comment


                • #9
                  As i cannot edit my first post, a new release here: (now version 2.5)

                  Code:
                  '***********************************************************************************************
                  ' To Do:
                  
                  
                  '***********************************************************************************************
                  ' extra thread for scanning calcs ?, forget it, overhead for thread is too much, takes longer
                  ' set to high priority ?, makes almost no difference (< 100 ms)
                  '***********************************************************************************************
                  ' ini file, programm path or appdata, recent files, restore pos + size -> ok
                  
                  ' reload file if delimiter changed , ask (msgbox) -> ok
                  ' thread sync (stop when in progress, before starting  new: scan, find) -> ok
                  ' line count/v scrollbar problem with .pdf (not $crlf delimited thus split -> ok
                  ' goto   hex/text !!! -> ok
                  
                  ' check if last line is to long and split, if no delimiter is at the end -> ok
                  ' improve navigation speed while indexing -> ok
                  ' caret hickup with small files (1 or two lines) -> ok
                  ' if last line doesn´t end with a delimiter, it is skipped !!! -> ok
                  
                  
                  ' better formatting of hexview output -> ok
                  ' caption records (16 byte), tlc, scrollbar sfy_t/h, -> ok
                  ' updatecaret -> ok evtl. in dec (hex ist schon da) -> ok
                  
                  ' selection byte based instead of line based -> ok
                  ' gosub for selection -> ok
                  ' make it all zerobased, sel must not be higer than filelenght + 1 -> ok ?
                  ' check transition between chunks -> ok
                  ' mouse selection -> ok
                  ' test hex -> ok ?
                  ' goto, find, selection -> ok
                  ' copy with fileoffset and line # -> ok
                  ' copy to file                    -> ok
                  ' keep position when switching text/hex, store byte position and convert to topline -> ok
                  ' coffset with find/goto -> ok
                  ' eingabe check, not valid -> select -> ok
                  ' tlc problem 111 zu viel !!! wieso ??? catch with befor/after compare + msgbox -> ok
                  ' hex selection -> ok
                  ' topline, size change !!! -> ok
                  
                  '***********************************************************************************************
                  ' scrollbar
                  '***********************************************************************************************
                  ' scrollbar body click scrolls the more the more total lines there are
                  ' thumb may have about 1000 different positions (y screen width = 1024)
                  ' y scroll range -> 10000 would be sufficient
                  ' for 100M lines this means 100,000 lines per minimum thumb move (1 pixel)
                  ' 1000 lines with page up/down key is ok
                  ' so 1000 lines per body click, would give enough resolution for 100M lines
                  ' adjust this value for smaller line counts (minimum 1, 2 for 100 lines, etc)
                  '***********************************************************************************************
                  '***********************************************************************************************
                  ' limitations:
                  ' filesize    = quad (2^64 - 1)
                  ' find count  = long (2^32/2)
                  '***********************************************************************************************
                  '***********************************************************************************************
                  
                  
                  #UTILITY version
                  '#UTILITY gpf
                  #COMPILER PBWIN 10
                  #DIM ALL
                  
                  #COMPILE EXE "fileviewer.exe"
                  #RESOURCE "fileviewer.pbr"
                  #INCLUDE ONCE "Win32API.inc"
                  
                  
                  '* FILE
                  %IDM_OPEN           = 6000
                  
                  %IDM_CRLF           = 6001
                  %IDM_CR             = 6002
                  %IDM_LF             = 6003
                  %IDM_ASCII          = 6004
                  %IDM_HEX            = 6005
                  %IDM_EXIT           = 6009
                  '
                  '* EDIT
                  %IDM_COPY           = 6010
                  %IDM_COPYFILE       = 6015
                  %IDM_GOTO           = 6011
                  %IDM_FIND           = 6012
                  %IDM_FINDNEXT       = 6013
                  %IDM_FINDPREV       = 6014
                  '
                  '* HEXVIEW
                  %IDM_HEXVIEW        = 6020
                  
                  '* HELP
                  %IDM_HELP           = 6090
                  %IDM_ABOUT          = 6091
                  %IDM_MEM            = 6092
                  
                  
                  %IDM_MRU            = 7000                            'must be HIGHEST command id in mainproc !
                  
                  
                  %mg       = 5                                         'margin (pixel offset for drawing)
                  %partsize = 1000000                                   'must not be larger than long range (and be smaller than 1000)
                  %max_line = 1000                                      'restrict line and wrap on this position
                  %max_find = 10000                                     'ask to continue if there are %max_find results
                  %max_mru  = 10                                        'max # of mru files to keep
                  
                  '***********************************************************************************************
                  ' could avoid these globals of course, but as this is small project who cares ...
                  '***********************************************************************************************
                  
                  GLOBAL hinst    AS DWORD                              'instance handle
                  GLOBAL hstatus  AS DWORD                              'window handles ...
                  GLOBAL hwndmain AS DWORD
                  GLOBAL hwnde    AS DWORD
                  GLOBAL hwndc    AS DWORD
                  GLOBAL hMenu    AS DWORD
                  
                  GLOBAL oldeditproc   AS DWORD                         'subclassing
                  GLOBAL oldstatusproc AS DWORD
                  
                  
                  GLOBAL f$                                             'file to display
                  GLOBAL delimiter AS STRING
                  
                  GLOBAL smemh   AS DWORD                               'memory handle
                  GLOBAL smemb   AS DWORD                               'begin
                  GLOBAL smeml   AS DWORD                               'length
                  
                  GLOBAL smemh1  AS DWORD                               'handle
                  GLOBAL smemb1  AS DWORD                               'begin
                  GLOBAL smeml1  AS DWORD                               'length
                  
                  
                  GLOBAL p()     AS QUAD                                'array of chunk pointers
                  GLOBAL p1()    AS DWORD                               'array of line #
                  
                  GLOBAL l()     AS DWORD                               'array of line pointers
                  GLOBAL lmax    AS DWORD                               'char count of longest line
                  GLOBAL lc      AS DWORD                               'line count
                  GLOBAL tlc     AS QUAD                                'total line count
                  GLOBAL tlc_t   AS QUAD                                'total line count (text)
                  GLOBAL tlc_h   AS QUAD                                'total line count (hex)
                  GLOBAL pc      AS DWORD                               'parts count
                  GLOBAL loffset AS QUAD                                'line offset
                  GLOBAL foffset AS QUAD                                'fileoffset
                  GLOBAL cp      AS DWORD                               'current part
                  
                  GLOBAL sfy     AS SINGLE                              'scroll factor y
                  GLOBAL sfy_t   AS SINGLE                              'scroll factor y (text)
                  GLOBAL sfy_h   AS SINGLE                              'scroll factor y (hex)
                  
                  GLOBAL fnd$                                           'find string
                  GLOBAL fc      AS LONG                                'find count
                  GLOBAL ff()    AS QUAD                                'found array (fileoffset)
                  
                  GLOBAL hexflag AS DWORD                               '0=standart, 1=Hexview
                  
                  
                  TYPE PROCESS_MEMORY_COUNTERS DWORD
                     cb                         AS DWORD   ' DWORD
                     PageFaultCount             AS DWORD   ' DWORD
                     PeakWorkingSetSize         AS DWORD   ' SIZE_T
                     WorkingSetSize             AS DWORD   ' SIZE_T
                     QuotaPeakPagedPoolUsage    AS DWORD   ' SIZE_T
                     QuotaPagedPoolUsage        AS DWORD   ' SIZE_T
                     QuotaPeakNonPagedPoolUsage AS DWORD   ' SIZE_T
                     QuotaNonPagedPoolUsage     AS DWORD   ' SIZE_T
                     PagefileUsage              AS DWORD   ' SIZE_T
                     PeakPagefileUsage          AS DWORD   ' SIZE_T
                  END TYPE
                  
                  
                  DECLARE FUNCTION GetProcessMemoryInfo LIB "PSAPI.DLL" ALIAS "GetProcessMemoryInfo" ( _
                     BYVAL hProcess AS DWORD _                            ' __in HANDLE hProcess
                   , BYREF ppsmemCounters AS PROCESS_MEMORY_COUNTERS _    ' __out PPROCESS_MEMORY_COUNTERS ppsmemCounters
                   , BYVAL cb AS DWORD _                                  ' __in DWORD cb
                   ) AS LONG                                              ' BOOL
                  
                  
                  '***********************************************************************************************
                  '***********************************************************************************************
                  
                  
                  FUNCTION getappdata AS STRING
                  '***********************************************************************************************
                  ' get/create appdata folder
                  '***********************************************************************************************
                  LOCAL n AS DWORD
                  LOCAL hShell AS DWORD
                  LOCAL zBuffer AS ASCIIZ * %MAX_PATH + 1
                  LOCAL pzStr AS DWORD
                  LOCAL hlib AS DWORD
                  LOCAL apath  AS ASCIIZ * %MAX_PATH + 1
                  
                  
                      hLib = LoadLibrary("SHELL32.DLL")
                      IF hLib THEN
                         hShell = GetProcAddress(hLib, "SHGetSpecialFolderPathA")
                         IF hShell THEN
                            pzStr = VARPTR(zBuffer)
                            ! push 1                       ;true
                            ! push %CSIDL_APPDATA          ;dwType
                            ! push pzStr
                            ! push 0                       ;hParent
                            ! call hShell
                            ! mov n, eax
                            IF n THEN apath = RTRIM$(zBuffer, ANY "/\")
                         END IF
                         FreeLibrary hLib
                  
                         IF LEN(apath) THEN
                           apath = apath + "\" + EXE.NAME$
                           IF DIR$(apath, %SUBDIR) = "" THEN MKDIR apath
                           apath=apath+"\"
                  
                           FUNCTION=apath
                         ELSE
                           FUNCTION=""
                         END IF
                      END IF
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  SUB inifile(action AS LONG)
                  '***********************************************************************************************
                  ' read/write (action=0/1) app´s .ini file
                  '***********************************************************************************************
                  LOCAL i AS LONG
                  LOCAL n AS LONG
                  LOCAL r AS rect
                  LOCAL ztext AS ASCIIZ * %MAX_PATH + 1
                  LOCAL ini AS ASCIIZ * %MAX_PATH + 1                   'ini file name
                  
                  
                    ini = EXE.PATH$ + EXE.NAME$ + ".ini"                'in app´s directory
                  '  ini = getappdata + EXE.NAME$ + ".ini"               'in special folder appdata
                  
                  
                    IF action = 0 THEN
                      Getprivateprofilestring "Rect", "Left", "100", ztext, %MAX_PATH + 1, ini : r.nleft = VAL(ztext)
                      Getprivateprofilestring "Rect", "Right", "400", ztext, %MAX_PATH + 1, ini : r.nright = VAL(ztext)
                      Getprivateprofilestring "Rect", "Top", "100", ztext, %MAX_PATH + 1, ini : r.ntop = VAL(ztext)
                      Getprivateprofilestring "Rect", "Bottom", "300", ztext, %MAX_PATH + 1, ini : r.nbottom = VAL(ztext)
                      movewindow hwndmain, r.nleft, r.ntop, r.nright - r.nleft, r.nbottom - r.ntop, -1
                  
                      insertmenu hmenu, %IDM_MRU-1, %MF_Separator, %IDM_MRU, BYVAL 0
                  
                      n=0
                      FOR i=1 TO %max_mru
                        Getprivateprofilestring "Mru", FORMAT$(i), "-", ztext, %MAX_PATH + 1, ini
                        IF ISFILE(ztext) THEN
                          INCR n
                          insertmenu hmenu, %IDM_MRU, %MF_Bycommand OR %MF_String, %IDM_MRU + i, ztext
                        END IF
                      NEXT i
                  
                      IF n>0 THEN mrulist(n)
                      IF n=0 THEN enablemenuitem getsubmenu(hmenu, 0), 2, %MF_Byposition OR %MF_GRAYED
                  
                  
                    ELSEIF action =1 THEN
                      IF ISFALSE(isiconic(hwndmain) OR iszoomed(hwndmain)) THEN
                        getwindowrect hwndmain, r
                        writeprivateprofilestring "Rect", "Left", FORMAT$(r.nleft), ini
                        writeprivateprofilestring "Rect", "Right", FORMAT$(r.nright), ini
                        writeprivateprofilestring "Rect", "Top", FORMAT$(r.ntop), ini
                        writeprivateprofilestring "Rect", "Bottom", FORMAT$(r.nbottom), ini
                      END IF
                  
                      FOR i=1 TO %max_mru
                        ztext = "-"
                        getmenustring hmenu, %IDM_MRU + i, ztext, %MAX_PATH + 1, %MF_Bycommand
                        writeprivateprofilestring "Mru", FORMAT$(i), ztext, ini
                      NEXT i
                  
                    END IF
                  
                  
                  END SUB
                  
                  
                  '***********************************************************************************************
                  
                  
                  SUB mrulist(BYVAL action AS LONG)
                  '***********************************************************************************************
                  ' manage mru list (menu), action=-1 -> delete, action=0 -> add/update item, action > 0 -> count
                  '***********************************************************************************************
                  LOCAL i AS LONG
                  LOCAL mii AS menuiteminfo
                  LOCAL ztext AS ASCIIZ * %MAX_PATH + 1
                  
                  STATIC mc AS LONG                                     'current mru count
                  
                  
                    IF action > 0 THEN
                      mc = action
                      enablemenuitem getsubmenu(hmenu, 0), 2, %MF_Byposition OR %MF_ENABLED
                  
                  
                    ELSEIF action = 0 THEN                              'add/update
                      FOR i=1 TO mc                                     'look, if it is already there
                        ztext = ""
                        getmenustring hmenu, %IDM_MRU + i, ztext, %MAX_PATH + 1, %MF_Bycommand
                        IF ztext = f$ THEN EXIT FOR
                      NEXT i
                  
                      IF i > mc THEN                                    'no -> a new file
                        INCR mc                                         'increase count
                        IF mc > %max_mru THEN                           'if max is reached
                          mc = %max_mru                                 'set to max
                          deletemenu hmenu, %IDM_MRU + mc, %MF_Bycommand                    'delete last item
                        END IF
                        i = mc
                      ELSE                                              'yes -> already there
                        deletemenu hmenu, %IDM_MRU + i, %MF_Bycommand   'delete this item
                      END IF
                  
                  
                      FOR i=i-1 TO 1 STEP -1                            'i=found, new or %max_mru
                        mii.cbsize = SIZEOF(menuiteminfo)
                        mii.fmask  = %miim_id
                        mii.wid    = %IDM_MRU + i + 1
                        SetMenuItemInfo hmenu, %IDM_MRU + i, 0, mii     'increase id by 1 = shift items
                      NEXT i
                  
                      ztext = f$
                      IF mc=1 THEN                                      'if it is the first item
                        insertmenu hmenu, %IDM_MRU, %MF_Bycommand OR %MF_String, %IDM_MRU + 1, ztext
                      ELSE                                              'there are already items
                        insertmenu hmenu, %IDM_MRU + 2, %MF_Bycommand OR %MF_String, %IDM_MRU + 1, ztext
                      END IF
                  
                      CheckMenuRadioItem hmenu, %IDM_MRU + 1, %IDM_MRU + %max_mru, %IDM_MRU + 1, %MF_Bycommand '= bullet (%MFT_RADIOCHECK)
                      enablemenuitem getsubmenu(hmenu, 0), 2, %MF_Byposition OR %MF_ENABLED
                      inifile(1)
                  
                  
                    ELSEIF action = -1 THEN                             'delete all
                      enablemenuitem getsubmenu(hmenu, 0), 2, %MF_Byposition OR %MF_GRAYED
                      FOR i=1 TO mc
                        deletemenu hmenu, %IDM_MRU + i, %MF_Bycommand
                      NEXT i
                      mc=0                                              'reset count
                      inifile(1)
                    END IF
                  
                  
                  END SUB
                  
                  
                  '***********************************************************************************************
                  
                  
                  SUB CenterWindow(BYVAL hWnd AS LONG)
                  '***********************************************************************************************
                  ' center this window in apps client space
                  '***********************************************************************************************
                  LOCAL WndRect AS RECT
                  LOCAL r       AS rect
                  LOCAL x       AS LONG
                  LOCAL y       AS LONG
                  
                  
                    GetWindowRect hWnd, WndRect
                    GetWindowRect hWndmain, r
                  
                    x = r.nleft+((r.nright-r.nleft)\2)-((WndRect.nRight-WndRect.nLeft)\2)
                    y = r.ntop+((r.nbottom-r.ntop)\2)-((WndRect.nBottom-WndRect.nTop)\2)
                  
                    SetWindowPos hWnd, %NULL, x, y, 0, 0, %SWP_NOSIZE OR %SWP_NOZORDER
                  
                  
                  END SUB
                  
                  
                  '***********************************************************************************************
                  
                  
                  FUNCTION AboutProc(BYVAL hDlg AS LONG, BYVAL wMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                  '***********************************************************************************************
                  ' about callback
                  '***********************************************************************************************
                  LOCAL hDC      AS LONG
                  LOCAL r        AS RECT
                  LOCAL LpPaint  AS PaintStruct
                  
                  
                    SELECT CASE wMsg
                      CASE %WM_INITDIALOG
                        SetTimer(hDlg, 113, 5000, BYVAL %NULL)          'show for 5 seconds, then close again
                        centerwindow hdlg                               'center in main window
                        EnableWindow hWndMain, %FALSE
                        FUNCTION = 1
                        EXIT FUNCTION
                  
                  
                      CASE %WM_TIMER
                        SendMessage hDlg, %WM_COMMAND, %IDOK, %NULL
                  
                  
                      CASE %WM_COMMAND
                        SELECT CASE LOWRD(wParam)
                          CASE %IDCANCEL
                            KillTimer %NULL, 113
                            EndDialog hDlg, 0                           'exit
                            EnableWindow hWndMain, %TRUE
                            FUNCTION = 1
                  
                          CASE %IDOK, 101
                            KillTimer %NULL, 113
                            EndDialog hDlg, 1                           'exit
                            EnableWindow hWndMain, %TRUE
                            FUNCTION = 1
                  
                        END SELECT
                  
                  
                      CASE %WM_PAINT                                    'draw some colored text
                        hDC = BeginPaint(getdlgitem(hdlg,100), LpPaint)
                          GetclientRect getdlgitem(hdlg,100), r
                          SetBkMode hDC, %TRANSPARENT
                          SetTextColor hDC, %CYAN
                          r.nleft=r.nleft+1
                          r.ntop=r.ntop+2
                          DrawText hDC, "Large File Viewer", -1, r, %DT_SINGLELINE
                          SetTextColor hDC, %MAGENTA
                          r.nleft=r.nleft-1
                          r.ntop=r.ntop-2
                          DrawText hDC, "Large File Viewer", -1, r, %DT_SINGLELINE
                        EndPaint getdlgitem(hdlg,100), LpPaint
                  
                  
                        FUNCTION = 0
                        EXIT FUNCTION
                  
                    END SELECT
                  
                  
                  END FUNCTION
                  
                  
                  '*************************************************************************************************
                  
                  
                  FUNCTION MainProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG
                  '*************************************************************************************************
                  ' Main window procedure, handle everything except for text window´s internals (see childproc)
                  '*************************************************************************************************
                  LOCAL pDis    AS DRAWITEMSTRUCT PTR
                  LOCAL hbr     AS DWORD
                  LOCAL mm      AS minmaxinfo PTR
                  LOCAL pmc     AS PROCESS_MEMORY_COUNTERS
                  LOCAL hicon   AS LONG
                  LOCAL t       AS ASCIIZ * 50
                  LOCAL s       AS systemtime
                  LOCAL r       AS rect
                  LOCAL r1      AS rect
                  LOCAL si      AS sizel
                  LOCAL hdc     AS DWORD
                  LOCAL d$
                  
                  STATIC zText  AS ASCIIZ * 255
                  STATIC sp     AS LONG                                 'scan percent
                  STATIC st()   AS LONG                                 'array for statusbar parts
                  STATIC st1    AS DWORD
                  STATIC st2    AS DWORD
                  STATIC st3    AS DWORD
                  STATIC cf     AS LONG                                 'current find
                  STATIC cwp    AS DWORD PTR
                  STATIC hscan  AS DWORD
                  STATIC hfind  AS DWORD
                  STATIC abort  AS DWORD
                  
                  
                    SELECT CASE AS LONG wMsg
                      CASE %WM_CREATE                                   'creation of the main window
                        InitCommonControls
                  
                        DIM   st(3)                                     'st(3) => 4 elements, zerobased !
                  
                        hstatus = CreateStatusWindow(%WS_CHILD OR %WS_BORDER OR _
                                                       %WS_VISIBLE OR %SBS_SIZEGRIP, _
                                                       "", hWnd, 200)
                  
                        sendmessage hstatus, %SB_SETPARTS, 4, VARPTR(st(0))                 'set 4 parts (all array values are zero)
                                                                        'statusbar is sized correctly with WM_Size
                  
                        t=MID$(DATE$,4,2)+"."+MID$(DATE$,1,2)+"."+MID$(DATE$,7,4)
                        CALL getlocaltime(s)
                  
                        SELECT CASE s.wdayofweek
                          CASE 0
                            t="  Su. "+t
                          CASE 1
                            t="  Mo. "+t
                          CASE 2
                            t="  Tu. "+t
                          CASE 3
                            t="  We. "+t
                          CASE 4
                            t="  Th. "+t
                          CASE 5
                            t="  Fr. "+t
                          CASE 6
                            t="  Sa. "+t
                        END SELECT
                  
                        sendmessage hstatus, %SB_SETTEXT, 2, VARPTR(t)  'set date part
                  
                        settimer hwnd, 111, 100, BYVAL 0
                  
                        hicon=loadimage(hinst, "zclock", %Image_Icon, 14, 14, %LR_LOADMAP3DCOLORS)
                        sendmessage hstatus, %SB_SETICON, 3, hicon
                        hicon=loadimage(hinst, "zcal", %Image_Icon, 14, 14, %LR_LOADMAP3DCOLORS)
                        sendmessage hstatus, %SB_SETICON, 2, hicon
                  
                        hdc=getdc(hstatus)
                        selectobject hdc, sendmessage(hstatus, %WM_Getfont, 0, 0)
                        t = " 00:00:00   "                              'sample text
                        CALL gettextextentpoint32(hdc, t, LEN(t), si)   'get appropriate width for text
                        st1 = si.cx + 16 + 16                           'text + icon + sizegrip
                        t = " We. 01.01.2000    "                        'sample text
                        CALL gettextextentpoint32(hdc, t, LEN(t), si)   'get appropriate width for text
                        st2 = si.cx + 16                                'text + icon
                        t = " 0x00_00000000  :  00,000,000,000  "       'sample text
                        CALL gettextextentpoint32(hdc, t, LEN(t), si)   'get appropriate width for text
                        st3 = si.cx                                     'text
                        releasedc hstatus, hdc
                  
                  
                        delimiter=$CRLF
                        checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_CHECKED)
                  
                        postmessage hwnd, %WM_COMMAND, 5020, 0          'read ini
                  
                        IF LEN(COMMAND$) THEN                           'process commandline arguments
                          f$=TRIM$(COMMAND$(1), ANY CHR$(34)+" ")
                  
                          IF ISFILE(f$) THEN
                            postmessage hwnd, %WM_COMMAND, 5000, 0
                          END IF
                        END IF
                  
                  
                      CASE %WM_getminmaxinfo
                         mm = lparam
                         IF hexflag=1 THEN
                           @mm.ptMinTrackSize.x = @cwp*88+getsystemmetrics(%SM_cxVscroll)
                           @mm.ptMaxTrackSize.x = @cwp*88+getsystemmetrics(%SM_cxVscroll)
                         ELSE
                           @mm.ptMinTrackSize.x = getsystemmetrics(%SM_cxScreen)/2
                         END IF
                         @mm.ptMinTrackSize.y = getsystemmetrics(%SM_cyScreen)/3
                  
                         FUNCTION=0
                         EXIT FUNCTION
                  
                  
                      CASE %WM_DRAWITEM                                 'ownerdraw
                        pDis = lparam
                        IF @pdis.ctlid=200 THEN                         'for statusbar
                          sendmessage hstatus, %SB_Getrect, 1, VARPTR(r)                    'get to draw in
                  
                  DIM vert(1) AS TRIVERTEX
                  DIM gRect AS GRADIENT_RECT
                  
                          vert(0).x      = 0
                          vert(0).y      = 0
                          IF @pdis.itemdata = 0 THEN
                            vert(0).Red    = 100*256
                            vert(0).Green  = 255*256
                            vert(0).Blue   = 100*256
                          ELSE
                            vert(0).Red    = 255*256
                            vert(0).Green  = 150*256
                            vert(0).Blue   = 150*256
                          END IF
                          vert(0).Alpha  = &h0000
                          vert(1).x      = r.nleft + (r.nRight - r.nLeft)*sp/10000
                          vert(1).y      = r.nBottom - r.nTop + 1
                  
                          IF @pdis.itemdata = 0 THEN
                            vert(1).Red    = 200*256
                            vert(1).Green  = 255*256
                            vert(1).Blue   = 200*256
                          ELSE
                            vert(1).Red    = 255*256
                            vert(1).Green  = 220*256
                            vert(1).Blue   = 220*256
                          END IF
                          vert(1).Alpha  = &h0000
                          gRect.UpperLeft  = 0
                          gRect.LowerRight = 1
                          GradientFill @pdis.hDc, vert(0), 2, gRect, 1, %GRADIENT_FILL_RECT_H
                  
                  
                          setbkmode @pdis.hdc, %transparent
                          IF @pdis.itemdata = 0 THEN
                            t = " Indexing:  "+FORMAT$(sp/100, "###.##")+" %"
                          ELSE
                            t = " Searching:  "+FORMAT$(sp/100, "###.##")+" %"
                          END IF
                          textout @pdis.hdc, r.nleft, 4, t, LEN(t)
                        END IF
                  
                  
                      CASE %WM_USER + 1001
                        cwp = wparam                                    'get cw from childproc
                  
                  
                      CASE %WM_USER + 1000
                        IF lparam < 10 THEN                              'update indexing
                          sp = wparam
                          sendmessage hstatus, %SB_SETTEXT, 1 OR %SBT_OWNERDRAW, lparam
                  
                        ELSEIF lparam => 10 THEN                        'indexing finished
                          IF lparam=10 THEN
                            t = " Indexing:  100.00 %"
                          ELSE
                            t = " Searching:  "+FORMAT$(fc)+ " Results"
                          END IF
                          sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(t)
                  
                          SLEEP 100                                     'make it flicker
                          sendmessage hstatus, %SB_Getrect, 1, VARPTR(r)                    'get to draw in
                          r.ntop = r.ntop+1
                          r.nbottom = r.nbottom-1
                          r.nleft=r.nleft+1
                          r.nright=r.nright-1
                          hdc=getdc(hstatus)
                          IF lparam=10 THEN
                            hbr = createsolidbrush(RGB(100, 255, 100))
                          ELSE
                            hbr = createsolidbrush(RGB(255, 150, 150))
                          END IF
                          fillrect hdc, r, hbr
                          deleteobject hbr
                          selectobject hdc, sendmessage(hstatus, %WM_Getfont, 0, 0)
                          setbkmode hdc, %transparent
                          textout hdc, r.nleft, 4, t, LEN(t)
                          releasedc hstatus, hdc
                  
                          IF lparam=10 THEN
                            settimer hwnd, 112, 1500, BYVAL 0
                          ELSE
                            settimer hwnd, 112, 3500, BYVAL 0
                            cf=0
                            postmessage hwndc, %WM_COMMAND, %IDM_FIND, cf
                            IF fc>0 THEN
                              modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find ("+FORMAT$(cf+1)+" of "+FORMAT$(fc)+")"+$TAB+"Ctrl+F"
                              modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next ("+FORMAT$(fc-1-cf)+")"+$TAB+"App"
                              modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev ("+FORMAT$(cf)+")"+$TAB+"Shift+App"
                            ELSE
                              modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find"+$TAB+"Ctrl+F"
                              modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next"+$TAB+"App"
                              modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev"+$TAB+"Shift+App"
                            END IF
                          END IF
                        END IF
                  
                  
                      CASE %WM_TIMER                                    'update date/time
                        IF wparam = 111 THEN
                          t=" "+TIME$
                          sendmessage hstatus, %SB_SETTEXT, 3, VARPTR(t)
                          IF t=" 00:00:01" THEN
                            t=MID$(DATE$,4,2)+"."+MID$(DATE$,1,2)+"."+MID$(DATE$,7,4)
                            CALL getlocaltime(s)
                  
                            SELECT CASE s.wdayofweek
                              CASE 0
                                t=" Su. "+t
                              CASE 1
                                t=" Mo. "+t
                              CASE 2
                                t=" Tu. "+t
                              CASE 3
                                t=" We. "+t
                              CASE 4
                                t=" Th. "+t
                              CASE 5
                                t=" Fr. "+t
                              CASE 6
                                t=" Sa. "+t
                            END SELECT
                  
                            sendmessage hstatus, %SB_SETTEXT, 2, VARPTR(t)                  ' set part 1 (current date)
                          END IF
                  
                        ELSEIF wparam = 112 THEN                        'signal indexing finished
                          enablemenuitem (getmenu(hwndmain), %IDM_FIND, %MF_ENABLED)
                          enablemenuitem (getmenu(hwndmain), %IDM_FINDNEXT, %MF_ENABLED)
                          enablemenuitem (getmenu(hwndmain), %IDM_FINDPREV, %MF_ENABLED)
                          enablemenuitem (getmenu(hwndmain), %IDM_GOTO, %MF_ENABLED)
                          killtimer hwnd, 112
                          t= "  Ready"
                          sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(t)
                        END IF
                  
                  
                      CASE %WM_SETFOCUS
                        setfocus hwndc
                  
                  
                      CASE %WM_NOTIFY                                   'events/notifications
                  
                  
                      CASE %WM_MENUSELECT                               'selection change in a menu
                          LoadString hinst, wParam, zText, SIZEOF(zText)
                          SendMessage hstatus, %WM_SETTEXT, 0, VARPTR(zText)
                          EXIT FUNCTION
                  
                  
                      CASE %WM_MOUSEMOVE                                'mouse move
                  
                  
                      CASE %WM_SIZE                                     'main window has been resized
                        SendMessage hstatus, wMsg, wParam, lParam       'statusbar does on it´s own
                  
                        IF wparam <> %SIZE_MINIMIZED THEN               'only if window is not in minmized state
                          GetClientRect hWnd, r1                        'get clientarea
                          getwindowrect hstatus, r                      'get statusbar
                  
                          st(3)= -1
                          st(2)= LO(WORD, lparam) - st1
                          st(1)= st(2) - st2
                          st(0)= st3
                  
                          sendmessage hstatus, %SB_SETPARTS, 4, VARPTR(st(0)) ' set size of parts in statusbar
                          IF hexflag=1 THEN
                            MoveWindow hwndc, 69*@cwp, 0, LO(WORD, lparam)-69*@cwp, HI(WORD, lparam)-(r.nbottom-r.ntop), %TRUE 'resize child
                          ELSE
                            MoveWindow hwndc, 0, 0, LO(WORD, lparam), HI(WORD, lparam)-(r.nbottom-r.ntop), %TRUE 'resize child
                          END IF
                        END IF
                  
                        setfocus hwndc
                        FUNCTION=%false
                        EXIT FUNCTION                                   'nothing to do for defwindowproc
                  
                  
                      CASE %WM_COMMAND                                  'events/notifications from controls
                          SELECT CASE AS LONG LOWRD(wParam)
                  
                          CASE 5000
                  newfile:
                            enablemenuitem (getmenu(hwndmain), %IDM_FIND, %MF_GRAYED)
                            enablemenuitem (getmenu(hwndmain), %IDM_FINDNEXT, %MF_GRAYED)
                            enablemenuitem (getmenu(hwndmain), %IDM_FINDPREV, %MF_GRAYED)
                            enablemenuitem (getmenu(hwndmain), %IDM_GOTO, %MF_GRAYED)
                  
                            IF hscan<>0 THEN
                              abort=1
                              waitforsingleobject hscan, %infinite
                              abort=0
                              THREAD CLOSE hscan TO hscan
                              hscan=0
                            END IF
                  
                            IF hfind<>0 THEN
                              abort=1
                              waitforsingleobject hfind, %infinite
                              abort=0
                              THREAD CLOSE hfind TO hfind
                              hfind=0
                            END IF
                  
                            abort=0
                            THREAD CREATE do_scan(BYVAL VARPTR(abort)) TO hscan
                  '          thread set priority hthread, %THREAD_PRIORITY_HIGHEST
                  
                            mrulist(0)
                            EXIT FUNCTION
                  
                  
                  
                          CASE 5020
                            inifile(0)                                  'read ini, must be here, because in %wm_create sizing fails
                  
                  
                          CASE 5100
                            IF hfind<>0 THEN
                              abort=1
                              waitforsingleobject hfind, %infinite
                              abort=0
                              THREAD CLOSE hfind TO hfind
                              hfind=0
                            END IF
                  
                            abort=0
                            THREAD CREATE do_find(BYVAL VARPTR(abort)) TO hscan
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_OPEN
                            DISPLAY OPENFILE hwnd,,, " Select a file for viewing", "C:\", CHR$("All Files", 0, "*.*", 0), _
                                             "", "", %OFN_FILEMUSTEXIST OR %OFN_PATHMUSTEXIST TO d$
                  
                            IF ISFILE(d$) THEN
                              f$=d$
                              invalidaterect hwndc, BYVAL 0, BYVAL 0
                              updatewindow hwndc
                              GOTO newfile
                            END IF
                  
                  
                          CASE %IDM_MRU - 1                             'delete mru list
                            mrulist(-1)
                  
                  
                          CASE > %IDM_MRU                               'mru files
                            getmenustring hmenu, LOWRD(wParam), ztext, %MAX_PATH + 1, %MF_Bycommand
                            IF ISFILE(ztext) THEN
                              f$=ztext
                              invalidaterect hwndc, BYVAL 0, BYVAL 0
                              updatewindow hwndc
                              GOTO newfile
                            END IF
                  
                  
                          CASE %IDM_CRLF
                            delimiter = $CRLF
                            checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_CHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_CR, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_LF, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_ASCII, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_HEX, %MF_UNCHECKED)
                  
                            modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
                            modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
                            MSGBOX " "+CHR$(34)+"Carriage Return + Line Feed"+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                                   "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                                   " Large File Viewer"
                  
                  
                          CASE %IDM_CR
                            delimiter = $CR
                            checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_CR, %MF_CHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_LF, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_ASCII, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_HEX, %MF_UNCHECKED)
                  
                            modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
                            modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
                            MSGBOX " "+CHR$(34)+"Carriage Return"+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                                   "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                                   " Large File Viewer"
                  
                  
                          CASE %IDM_LF
                            delimiter = $LF
                            checkmenuItem(getmenu(hwnd), %IDM_CRLF, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_CR, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_LF, %MF_CHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_ASCII, %MF_UNCHECKED)
                            checkmenuItem(getmenu(hwnd), %IDM_HEX, %MF_UNCHECKED)
                  
                            modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
                            modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
                            MSGBOX " "+CHR$(34)+"Line Feed"+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                                   "  You must (re)open a file for this to take effect!", %MB_ICONEXCLAMATION, _
                                   " Large File Viewer"
                  
                  
                          CASE %IDM_ASCII
                            CALL editbox(2)
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_HEX
                            CALL editbox(3)
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_EXIT
                            SendMessage hWnd, %WM_CLOSE, wParam, lParam
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_COPY
                            sendmessage hwndc, %WM_COMMAND, %IDM_COPY, 0
                  
                  
                          CASE %IDM_COPYFILE
                            sendmessage hwndc, %WM_COMMAND, %IDM_COPYFILE, 0
                  
                  
                          CASE %IDM_GOTO
                            CALL editbox(0)
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_FIND
                            CALL editbox(1)
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_FINDNEXT
                            INCR cf
                            IF cf > fc-1 THEN cf = fc-1
                            postmessage hwndc, %WM_COMMAND, %IDM_FIND, cf
                            IF fc>0 THEN
                              modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find ("+FORMAT$(cf+1)+" of "+FORMAT$(fc)+")"+$TAB+"Ctrl+F"
                              modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next ("+FORMAT$(fc-1-cf)+")"+$TAB+"App"
                              modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev ("+FORMAT$(cf)+")"+$TAB+"Shift+App"
                            ELSE
                              modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next"+$TAB+"App"
                            END IF
                  
                  
                          CASE %IDM_FINDPREV
                            DECR cf
                            IF cf < 0 THEN cf = 0
                            postmessage hwndc, %WM_COMMAND, %IDM_FIND, cf
                            IF fc>0 THEN
                              modifymenu getmenu(hwndmain), %IDM_FIND, %MF_Bycommand, %IDM_FIND, "Find ("+FORMAT$(cf+1)+" of "+FORMAT$(fc)+")"+$TAB+"Ctrl+F"
                              modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev ("+FORMAT$(cf)+")"+$TAB+"Shift+App"
                              modifymenu getmenu(hwndmain), %IDM_FINDNEXT, %MF_Bycommand, %IDM_FINDNEXT, "Find Next ("+FORMAT$(fc-1-cf)+")"+$TAB+"App"
                            ELSE
                              modifymenu getmenu(hwndmain), %IDM_FINDPREV, %MF_Bycommand, %IDM_FINDPREV, "Find Prev"+$TAB+"Shift+App"
                            END IF
                  
                  
                          CASE %IDM_HEXVIEW
                            postmessage hwndc, %WM_COMMAND, 5002, 0
                  
                  
                          CASE %IDM_HELP
                            d$="  View large Files (filelength may be up to 2^64)"+$CRLF+$CRLF
                            d$=d$+$CRLF+"  F1"+$TAB+$TAB+"-"+$TAB+"Help"
                            d$=d$+$CRLF+"  Ctrl+F1"+$TAB+$TAB+"-"+$TAB+"About"
                            d$=d$+$CRLF+"  Ctrl+M"+$TAB+$TAB+"-"+$TAB+"Memory Usage"+$CRLF
                            d$=d$+$CRLF+"  Ctrl+O"+$TAB+$TAB+"-"+$TAB+"Open a file for viewing"
                            d$=d$+$CRLF+"  Alt+X"+$TAB+$TAB+"-"+$TAB+"Exit"+$CRLF
                            d$=d$+$CRLF+"  Ctrl+C"+$TAB+$TAB+"-"+$TAB+"Copy selection to clipboard"
                            d$=d$+$CRLF+"  Ctrl+G"+$TAB+$TAB+"-"+$TAB+"Goto Line (enter line #)"
                            d$=d$+$CRLF+"  Ctrl+F"+$TAB+$TAB+"-"+$TAB+"Find (enter a string to search for)"
                            d$=d$+$CRLF+"  App"+$TAB+$TAB+"-"+$TAB+"Find next"
                            d$=d$+$CRLF+"  Shift+App"+$TAB+"-"+$TAB+"Find previous"+$CRLF
                            d$=d$+$CRLF+"  Ctrl+H"+$TAB+$TAB+"-"+$TAB+"Toggle Hex/Text View"+$CRLF
                            d$=d$+$CRLF+"  ESC"+$TAB+$TAB+"-"+$TAB+"Cancel current action"
                            d$=d$+$CRLF+"  Enter"+$TAB+$TAB+"-"+$TAB+"Finish entry"+$CRLF+$CRLF
                            d$=d$+$CRLF+"  You may navigate usings cursor keys or scrollbars, select text "
                            d$=d$+$CRLF+"  by using SHIFT+Cursor keys or by dragging the mouse as usual."+$CRLF
                  
                            d$=d$+$CRLF+"  Charcter combination separating lines (delimiter) may be changed."+$CRLF
                  
                  
                            d$=d$+$CRLF+"  ""Goto"" and ""Find"" accept hex input as well (""0x"" prefix)."+$CRLF
                            d$=d$+$CRLF+"  Commandline: "+CHR$(34)+"FILE TO VIEW"+CHR$(34)
                  
                            messagebox(hwnd, BYVAL STRPTR(d$), "  Large File Viewer Help", %MB_OK OR %MB_APPLMODAL OR %MB_TOPMOST)
                            FUNCTION = 0
                            EXIT FUNCTION
                  
                  
                  
                          CASE %IDM_ABOUT                               'Load and show Dialog Box from resource
                            DialogBox(hinst, "ABOUT", hWnd, CODEPTR(AboutProc))
                            FUNCTION = 0
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_MEM                                 'Show memory usage
                            GetProcessMemoryInfo getcurrentprocess, pmc, SIZEOF(pmc)
                            MSGBOX " Current Working Set Size : "+FORMAT$(pmc.WorkingSetSize/1000000, "* #.00")+" MB", _
                                   %MB_ICONINFORMATION," Memory Usage"
                  
                  
                        END SELECT
                  
                  
                      CASE %WM_exitmenuloop
                        postmessage hwndc, %WM_COMMAND, 5010, 0         'restore statusbar
                  
                  
                      CASE %WM_erasebkgnd
                        FUNCTION = 1                                    'just do nothing
                        EXIT FUNCTION
                  
                  
                      CASE %WM_PAINT
                        invalidaterect hwndc, BYVAL 0, BYVAL 0          'do all client painting in hwndc
                        updatewindow hwndc
                  
                  
                      CASE %WM_CLOSE
                        inifile(1)
                  
                  
                      CASE %WM_DESTROY                                  'exit - a good point for cleaning up
                        IF hscan<>0 THEN THREAD CLOSE hscan TO hscan
                        IF hfind<>0 THEN THREAD CLOSE hfind TO hfind
                  
                        PostQuitMessage 0                               'exit message loop in WINMAIN
                        EXIT FUNCTION
                  
                    END SELECT
                  
                  
                    FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam) 'pass messages on to Windows for default processing
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  SUB updatecaret(cx AS DWORD, cy AS DWORD, cw AS DWORD, ch AS DWORD, coffset AS LONG, topline AS LONG)
                  '***********************************************************************************************
                  ' update caret position and show in statusbar
                  '***********************************************************************************************
                  LOCAL t AS ASCIIZ * 128
                  
                  
                    IF hexflag=1 THEN
                      t=" 0x"+HEX$(foffset+(topline+cy)*16+cx)+" - "+FORMAT$(foffset+(topline+cy)*16+cx+1, "#,")
                    ELSE
                      t=" "+FORMAT$(coffset + cx + 1, "#,")+" :  "+FORMAT$(loffset + topline + cy + 1, "#,")
                    END IF
                  
                    sendmessage hstatus, %SB_Settext, 0, VARPTR(t)
                    showcaret hwndc
                    setcaretpos((cx)*cw+%mg, (cy)*ch)
                  
                  
                  END SUB
                  
                  
                  '***********************************************************************************************
                  
                  
                  FUNCTION ChildProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG
                  '*************************************************************************************************
                  ' Textwindow procedure, displays text
                  '*************************************************************************************************
                  LOCAL ps       AS PAINTSTRUCT
                  LOCAL lf       AS logfont
                  LOCAL tm       AS textmetric
                  LOCAL sbi      AS SCROLLINFO
                  LOCAL pt       AS POINTAPI
                  LOCAL hdc      AS DWORD
                  LOCAL hold     AS DWORD
                  LOCAL hmemdc   AS DWORD
                  LOCAL hbmp     AS DWORD
                  LOCAL dflag    AS DWORD                               'drawflag
                  LOCAL sty      AS DWORD
                  LOCAL gt       AS QUAD PTR
                  LOCAL r        AS rect
                  LOCAL n        AS LONG
                  LOCAL i        AS LONG
                  LOCAL j        AS LONG
                  LOCAL lp       AS DWORD                               'line ptr
                  LOCAL k        AS LONG
                  LOCAL a()      AS WORD                                'bitmap array
                  
                  LOCAL lx      AS DWORD                                'low start x
                  LOCAL ly      AS QUAD                                 'low start y
                  LOCAL hx      AS DWORD                                'high end x
                  LOCAL hy      AS QUAD                                 'high end y
                  LOCAL d$
                  LOCAL e$
                  LOCAL t$
                  
                  LOCAL sel1 AS QUAD
                  LOCAL sel2 AS QUAD
                  
                  STATIC hfont   AS DWORD                               'font
                  STATIC hcaret  AS DWORD                               'userdefined caret
                  STATIC topline AS LONG                                '# of line on top
                  STATIC coffset AS LONG                                'char offset for first char shown
                  STATIC cpl     AS DWORD                               'chars per line
                  STATIC lps     AS DWORD                               'lines per screen
                  STATIC pgs     AS DWORD                               'pagescroll
                  STATIC cw      AS DWORD                               'char width
                  STATIC ch      AS DWORD                               'char height
                  STATIC cx      AS LONG                                'caret x (zerobased)
                  STATIC cy      AS LONG                                'caret y (zerobased)
                  STATIC ms      AS INTEGER                             'mousewheel
                  
                  STATIC sels    AS QUAD
                  STATIC sele    AS QUAD
                  STATIC ls      AS DWORD                               'line # (start)
                  STATIC le      AS DWORD                               'line # (end)
                  
                  STATIC selflag AS LONG                                '1=selection, 0=no
                  
                  
                    SELECT CASE AS LONG wMsg
                      CASE %WM_CREATE                                   'creation of text window
                        lf.lfHeight         =-16
                        lf.lfWidth          = 0
                        lf.lfEscapement     = 0
                        lf.lfOrientation    = 0
                        lf.lfWeight         = 400
                        lf.lfItalic         = 0
                        lf.lfUnderline      = 0
                        lf.lfStrikeOut      = 0
                        lf.lfCharSet        = 0
                        lf.lfOutPrecision   = 3
                        lf.lfClipPrecision  = 2
                        lf.lfQuality        = 1
                        lf.lfPitchAndFamily = 49
                        lf.lfFaceName       = "Courier New"
                  
                        hfont = createfontindirect(lf)                  'create font
                  
                        hdc = getdc(hwnd)                               'get Device Context
                        hold = SelectObject(hdc, hfont)                 'select new font into dc
                        GetTextMetrics hdc, tm                          'get font parameters
                        SelectObject hdc, hold                          'select old font back into dc
                        ReleaseDC hwnd, hdc                             'release dc
                  
                        cw = tm.tmAveCharWidth                          'character width (fixed font)
                        ch = tm.tmHeight + tm.tmExternalLeading         'Line spacing (line height)
                  
                  '***********************************************************************************************
                  ' create caret using a bitmap
                  '***********************************************************************************************
                  
                        i = cw/16                                       'i = number of words necessary per scanline
                                                                        '(monochrome, 1 bit per color)
                        IF i*16 < cw THEN  i = i + 1                    'make sure array is big enough (i>0)
                        n = i*ch                                        'array size
                  
                        REDIM a(0 TO n)
                  
                        FOR j=ch-2 TO ch                                'set array according to character dimensions
                          FOR k=0 TO i-1
                            a(j*i+k)=&HFFFF
                          NEXT k
                        NEXT j
                  
                        hcaret = createbitmap(cw, ch, 1, 1, BYVAL VARPTR(a(0)))
                        createcaret(hWnd, hCaret, 0, 0)
                        topline = 0
                        coffset = 0
                        lc=0
                        cx=0 : cy=0                                     'initial caret pos
                  
                        updatecaret(cx, cy, cw, ch, coffset, topline)
                        postmessage hwndmain, %WM_USER + 1001, VARPTR(cw), 0                'make cw available in mainproc
                  
                  
                      CASE %WM_KILLFOCUS
                        destroycaret
                  
                  
                      CASE %WM_SETFOCUS
                        createcaret(hWnd, hCaret, 0, 0)
                        IF lc>0 THEN
                          showcaret hwnd
                        END IF
                  
                  
                      CASE %WM_DRAWITEM                                 'ownerdraw
                  
                  
                      CASE %WM_KEYDOWN
                        IF (getkeystate(16) AND &H80) THEN          'Shift
                        ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                        ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                        ELSE
                          IF selflag>0 THEN
                            selflag=0
                            dflag=1
                          END IF
                        END IF
                  
                        IF lc=0 THEN EXIT FUNCTION
                  
                        SELECT CASE wparam
                          CASE %VK_Home
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_home
                              ELSE
                                GOTO c_home
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                              selflag=0
                  c_home:
                              cx=0
                              coffset=0
                              dflag=1
                  
                              GOSUB setsele
                            END IF
                  
                  
                          CASE %VK_End
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_end
                              ELSE
                                GOTO c_end
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                              selflag=0
                  c_end:
                  '***********************************************************************************************
                  ' show delimiter ?? -> yes, necessary for split lines
                  ' otherwise some chars would be omittet
                  '***********************************************************************************************
                  '            n = l(topline + cy)-l(topline +cy -1) - LEN(delimiter) 'linelenght without delimiter
                  
                              n = l(topline + cy + 1)-l(topline + cy)'+1     'linelenght
                              cx = MIN(cpl, n)
                              IF cx < 0 THEN cx = 0
                              IF n > cpl THEN                             'if longert han screen
                                coffset =  n - cpl                        'set char offest
                                dflag=1                                   'must redraw
                              END IF
                  
                              GOSUB setsele
                            END IF
                  
                  
                          CASE %VK_PgUp
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_pgup
                              ELSE
                                GOTO c_pgup
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                              cp=1
                              getfile(cp)
                              topline = 0
                              cy = 0
                              dflag=1
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                  c_pgup:
                              IF loffset + topline = 0 THEN
                                cy = 0
                              ELSE
                                topline = topline - lps
                                IF topline < 0 THEN
                                  IF cp = 1 THEN                        'if in first chunk
                                    topline = 0
                                  ELSE                                  'there are more chunks
                                    DECR cp
                                    getfile(cp)
                                    topline=p1(cp)-p1(cp-1)-topline     'adjust topline
                                  END IF
                                END IF
                                dflag=1
                              END IF
                  
                              GOSUB setsele
                            END IF
                  
                  
                          CASE %VK_PgDn
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_pgdn
                              ELSE
                                GOTO c_pgdn
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                              cp=pc-1
                              IF cp < 1 THEN cp = 1
                              getfile(cp)
                              topline = lc-lps
                              IF topline < 0 THEN topline = 0
                              cy = lps-1
                              dflag=1
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                  c_pgdn:
                              IF loffset + topline = tlc-lps THEN
                                cy = lps-1
                              ELSE
                                topline = topline + lps
                                IF topline > lc-lps THEN
                                  IF cp = pc-1 THEN                     'if in last two chunks
                                    topline = lc-lps
                                  ELSEIF pc = 1 THEN
                                    topline = lc-lps
                                    IF topline < 0 THEN topline = 0
                                  ELSE                                  'there are more chunks
                                    topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                                    INCR cp
                                    getfile(cp)
                                  END IF
                                END IF
                                dflag=1
                              END IF
                  
                              GOSUB setsele
                            END IF
                  
                  
                          CASE %VK_Up
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_up
                              ELSE
                                GOTO c_up
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                              selflag=0
                  c_up:
                              DECR cy
                              IF cy < 0 THEN
                                DECR topline
                                IF topline < 0 THEN
                                  IF cp = 1 THEN                        'if in first chunk
                                    topline = 0
                                  ELSE                                  'there are more chunks
                                    DECR cp
                                    getfile(cp)
                                    topline=p1(cp)-p1(cp-1)-1           'adjust topline
                                  END IF
                                END IF
                                cy = 0
                                dflag=1
                              END IF
                  
                              GOSUB setsele
                            END IF
                  
                  
                          CASE %VK_Down
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_down
                              ELSE
                                GOTO c_down
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                              selflag=0
                  c_down:
                              INCR cy
                              IF cy > lps-1 THEN
                                INCR topline
                                IF topline > lc-lps THEN
                                  IF cp = pc-1 THEN                     'if in last two chunks
                                    topline = lc-lps
                                  ELSEIF pc = 1 THEN
                                    topline = lc-lps
                                    IF topline < 0 THEN topline = 0
                                  ELSE                                  'there are more chunks
                                    topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                                    INCR cp
                                    getfile(cp)
                                  END IF
                                END IF
                                cy = lps-1
                                dflag=1
                              END IF
                  
                              GOSUB setsele
                            END IF
                  
                  
                          CASE %VK_Left
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_left
                              ELSE
                                GOTO c_left
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                              selflag=0
                  c_left:
                              DECR cx
                              IF cx <= 0 THEN
                                DECR coffset
                                IF coffset < 0 THEN coffset = 0
                                cx = 0
                                dflag=1
                              END IF
                  
                              GOSUB setsele
                            END IF
                  
                  
                          CASE %VK_Right
                            IF (getkeystate(16) AND &H80) THEN          'Shift
                              dflag=1
                              IF selflag=0 THEN
                                selflag=1
                                GOSUB setsels
                                GOTO c_right
                              ELSE
                                GOTO c_right
                              END IF
                            ELSEIF (getkeystate(17) AND &H80) THEN      'Ctrl
                            ELSEIF (getkeystate(18) AND &H80) THEN      'Alt
                            ELSE
                              selflag=0
                  c_right:
                              INCR cx
                              IF hexflag=1 THEN
                                IF cx > cpl THEN
                                  cx = cpl
                  '                dflag=1
                                END IF
                              ELSE
                                IF cx > cpl-1 THEN
                                  INCR coffset
                                  IF coffset > lmax - cpl THEN coffset = lmax - cpl
                                  cx = cpl-1
                                  dflag=1
                                END IF
                              END IF
                  
                              GOSUB setsele
                            END IF
                  
                        END SELECT
                  
                  
                        updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                        IF dflag=1 THEN
                          invalidaterect hwnd, BYVAL 0, BYVAL 0
                          updatewindow hwnd
                        END IF
                  
                  
                      CASE %WM_NOTIFY                                   'events/notifications
                  
                  
                      CASE %WM_MOUSEWHEEL                               'mousewheel scroll up/down
                        ms = ms + HIWRD(WPARAM)
                  
                        WHILE  ms >= 120
                          CALL sendmessage(hwnd, %WM_VSCROLL, %SB_LINEUP, 0)
                          ms = ms - 120
                        WEND
                  
                        WHILE ms <= -120
                          CALL sendmessage(hwnd, %WM_VSCROLL, %SB_LINEDOWN, 0)
                          ms = ms + 120
                        WEND
                  
                        FUNCTION = 0
                        EXIT FUNCTION
                  
                  
                      CASE %WM_HSCROLL                                  'horizontal scrollbar
                        IF lc=0 THEN EXIT FUNCTION
                  
                        SELECT CASE LO(WORD, wparam)
                          CASE %SB_LINELEFT, %SB_PAGELEFT
                            IF coffset > 0 THEN
                              INCR cx
                              IF cx > cpl-1 THEN cx = cpl-1
                            END IF
                            DECR coffset
                            IF coffset < 0 THEN coffset = 0
                  
                          CASE %SB_LINERIGHT, %SB_PAGERIGHT
                            IF coffset < lmax - cpl THEN
                              DECR cx
                              IF cx < 0 THEN cx = 0
                            END IF
                            INCR coffset
                            IF coffset > lmax - cpl THEN coffset = lmax - cpl
                  
                          CASE %SB_THUMBTRACK
                            coffset = HI(WORD, wparam)
                            IF coffset > lmax - cpl THEN coffset = lmax - cpl
                        END SELECT
                  
                        updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                        invalidaterect hwnd, BYVAL 0, BYVAL 0
                        updatewindow hwnd
                  
                  
                      CASE %WM_VSCROLL                                  'vertical scrollbar
                        IF lc=0 THEN EXIT FUNCTION
                  
                        SELECT CASE LO(WORD, wparam)
                          CASE %SB_LINEUP
                            IF topline > 0 THEN
                              INCR cy
                              IF cy > lps-1 THEN cy = lps-1
                            END IF
                  
                            DECR topline
                            IF topline < 0 THEN
                              IF cp = 1 THEN                        'if in first chunk
                                topline = 0
                              ELSE                                  'there are more chunks
                                DECR cp
                                getfile(cp)
                                topline=p1(cp)-p1(cp-1)             'adjust topline
                              END IF
                            END IF
                  
                  
                          CASE %SB_LINEDOWN
                            IF topline < lc -lps THEN
                              DECR cy
                              IF cy < 0 THEN cy = 0
                            END IF
                  
                            INCR topline
                            IF topline > lc-lps THEN
                              IF cp = pc-1 THEN                     'if in last two chunks
                                topline = lc-lps
                              ELSEIF pc = 1 THEN
                                topline = lc-lps
                                IF topline < 0 THEN topline = 0
                              ELSE                                  'there are more chunks
                                topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                                INCR cp
                                getfile(cp)
                              END IF
                            END IF
                  
                  
                          CASE %SB_PAGEUP                               'scrollbar body click
                            IF loffset + topline = 0 THEN
                              cy = 0
                            ELSE
                              topline = topline - pgs
                              IF topline < 0 THEN
                                IF cp = 1 THEN                        'if in first chunk
                                  topline = 0
                                ELSE                                  'there are more chunks
                                  DECR cp
                                  getfile(cp)
                                  topline=p1(cp)-p1(cp-1)-topline     'adjust topline
                                END IF
                              END IF
                            END IF
                  
                  
                          CASE %SB_PAGEDOWN                             'scrollbar body click
                            IF loffset + topline = tlc-lps THEN
                              cy = lps-1
                            ELSE
                              topline = topline + pgs
                              IF topline > lc-lps THEN
                                IF cp = pc-1 THEN                     'if in last two chunks
                                  topline = lc-lps
                                ELSEIF pc = 1 THEN
                                  topline = lc-lps
                                  IF topline < 0 THEN topline = 0
                                ELSE                                  'there are more chunks
                                  topline=topline-(p1(cp)-p1(cp-1))   'adjust topline
                                  INCR cp
                                  getfile(cp)
                                END IF
                              END IF
                            END IF
                  
                  
                          CASE %SB_THUMBTRACK
                  '***********************************************************************************************
                  ' get chunk, load, set topline -> show
                  '***********************************************************************************************
                  LOCAL q AS QUAD
                            q = HI(WORD, wparam)*sfy                    'get line #
                  
                            IF q=0 THEN                                 'if first line
                              cp=1
                              getfile(cp)
                              topline=0
                  
                            ELSEIF q=>tlc-lps+1 THEN                    'if last line
                              cp=pc-1
                              IF cp<1 THEN cp=1
                              getfile(cp)
                              topline=lc-lps
                  
                            ELSEIF pc=1 THEN                            'if only one chunk
                              topline=HI(WORD, wparam)*sfy
                  
                            ELSE                                        'any other case
                              IF hexflag=1 THEN
                                q=q*16                                  'make it an offset
                                FOR i=1 TO pc
                                  IF q < p(i) THEN
                                    cp=i
                                    IF cp=pc THEN cp=pc-1
                                    getfile(cp)
                                    topline=HI(WORD, wparam)*sfy-loffset
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                  'ods("hex - q:"+str$(q)+"  "+str$(loffset)+str$(topline)+str$(cy)+"  cp:"+STR$(cp)+str$(lc))
                  
                              ELSE
                                FOR i=1 TO pc
                                  IF q < p1(i) THEN
                                    cp=i
                                    IF cp=pc THEN cp=pc-1
                                    getfile(cp)
                                    topline=HI(WORD, wparam)*sfy-loffset
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                  'ods("text - q:"+STR$(q)+"  "+STR$(loffset)+STR$(topline)+STR$(cy)+"  cp:"+str$(cp))
                              END IF
                  
                            END IF
                  
                            IF topline < 0 THEN                         'adapt min/max value for topline
                              cy=cy+topline'-1
                              topline=0
                            ELSEIF topline > lc-lps THEN
                              cy=cy+topline-(lc-lps)
                              topline = lc-lps
                            END IF
                  
                        END SELECT
                  
                        updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                        invalidaterect hwnd, BYVAL 0, BYVAL 0
                        updatewindow hwnd
                  
                  
                      CASE %WM_LBUTTONDOWN
                        IF lc=0 THEN EXIT FUNCTION
                  
                        selflag=0                                       'reset selection
                        invalidaterect hwnd, BYVAL 0, BYVAL 0           'redraw
                        updatewindow hwnd
                  
                        pt.x = LO(INTEGER, lparam)
                        pt.y = HI(INTEGER, lparam)
                        IF dragdetect(hwnd, pt) THEN                    'drag ?
                          selflag=3                                     'mouse selection
                          cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
                          IF cx<0 THEN cx=0
                          cy = INT(HI(WORD, lparam)/ch)' + 1
                          IF cy>lps-1 THEN cy=lps-1
                          updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                          GOSUB setsels
                          GOSUB setsele
                  
                          invalidaterect hwnd, BYVAL 0, BYVAL 0         'redraw
                          updatewindow hwnd
                          setcapture hwnd                               'capture mouse
                  
                        ELSE                                            'lbuttonup !!!
                          cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
                          IF cx<0 THEN cx=0
                          cy = INT(HI(WORD, lparam)/ch)' + 1
                          IF cy>lps-1 THEN cy=lps-1
                          updatecaret(cx, cy, cw, ch, coffset, topline)
                          setfocus hwnd
                        END IF
                  
                  
                      CASE %WM_LBUTTONUP
                        IF lc=0 THEN EXIT FUNCTION
                  
                        IF selflag=3 THEN                               'if selection in progress
                          selflag=4
                          pt.x = LO(INTEGER, lparam)
                          pt.y = HI(INTEGER, lparam)
                          getclientrect hwnd, r
                          IF ptinrect(r, pt) THEN
                            cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
                            IF cx<0 THEN cx=0
                            cy = INT(HI(WORD, lparam)/ch)' + 1
                            IF cy>lps-1 THEN cy=lps-1
                            updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                            GOSUB setsele
                          END IF
                          releasecapture                                'release mouse
                        END IF
                  
                  
                      CASE %WM_MOUSEMOVE                                'mouse move
                        IF lc=0 THEN EXIT FUNCTION
                  
                        pt.x = LO(INTEGER, lparam)
                        pt.y = HI(INTEGER, lparam)
                        getclientrect hwnd, r
                  
                        IF selflag=3 THEN                               'if selection in progress
                          IF ptinrect(r, pt) THEN
                            cx = INT((LO(WORD, lparam)-%mg)/cw)' + 1
                            IF cx<0 THEN cx=0
                            cy = INT(HI(WORD, lparam)/ch)' + 1
                            IF cy>lps-1 THEN cy=lps-1
                            updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                            GOSUB setsele
                  
                            invalidaterect hwnd, BYVAL 0, BYVAL 0
                            updatewindow hwnd
                          ELSE
                            IF pt.y < r.ntop THEN postmessage hwnd, %WM_VSCROLL, %SB_LINEUP, 0
                            IF pt.y > r.nbottom THEN postmessage hwnd, %WM_VSCROLL, %SB_LINEDOWN, 0
                            IF pt.x < r.nleft THEN postmessage hwnd, %WM_HSCROLL, %SB_LINELEFT, 0
                            IF pt.x > r.nright THEN postmessage hwnd, %WM_HSCROLL, %SB_LINERIGHT, 0
                          END IF
                        END IF
                  
                  
                      CASE %WM_SIZE                                     'textwindow has been resized
                        cpl = (LO(WORD, lparam) - getsystemmetrics(%SM_CXHSCROLL)) /cw
                        lps = (HI(WORD, lparam)  - getsystemmetrics(%SM_CXHSCROLL))/ch
                  
                        IF topline > lc-lps THEN
                          cy=cy+topline-(lc-lps)
                          topline = lc-lps
                          IF topline < 0 THEN                       'adapt min/max value for topline
                            cy=cy+topline'-1
                            topline=0
                          END IF
                        END IF
                  
                        invalidaterect hwnd, BYVAL 0, BYVAL 0
                        updatewindow hwnd
                        updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                        FUNCTION = 0                                    'nothing to do for defwindowproc
                        EXIT FUNCTION
                  
                  
                      CASE %WM_COMMAND                                  'events/notifications from controls
                        SELECT CASE AS LONG LOWRD(wParam)
                          CASE 5000                                     'a new file
                            IF hexflag=1 THEN
                              sty=getwindowlong(hwnd, %GWL_Style)
                              sty = sty XOR %WS_HSCROLL
                              setwindowlong(hwnd, %GWL_Style, sty)
                  
                              getwindowrect hwndmain, r
                              IF r.nright-r.nleft <> 88*cw+getsystemmetrics(%SM_cxVscroll) THEN         'ensure correct width for hex view
                                setwindowpos hwndmain, BYVAL 0, 0,0, 88*cw+getsystemmetrics(%SM_cxVscroll), r.nbottom-r.ntop, %SWP_NoZorder OR %SWP_NoMove
                              ELSE
                                getclientrect hwndmain, r
                                sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
                              END IF
                            ELSE                                        'resize, when switching to text view
                              sty=getwindowlong(hwnd, %GWL_Style)
                              sty = sty OR %WS_HSCROLL
                              setwindowlong(hwnd, %GWL_Style, sty)
                              getclientrect hwndmain, r
                  
                              sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
                            END IF
                  
                            showcaret hwnd
                            selflag = 0
                            topline = 0
                            coffset = 0
                            cx=0 : cy=0                                 'initial caret pos
                  
                            updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                            IF getfile(cp) THEN
                              sbi.cbSize = SIZEOF(sbi)
                              sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                              sbi.nMin   = 1
                              sbi.nMax   = lmax-cpl
                              sbi.nPage  = 1                            'size of thumb !!!
                              sbi.nPos   = 1
                              SetScrollInfo hwndc, %SB_HORZ, sbi, 0
                  
                  
                              sbi.cbSize = SIZEOF(sbi)
                              sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                              sbi.nMin   = 0
                              sbi.nMax   = lc-lps'+1
                              sbi.nPage  = 1                            'size of thumb !!!
                              sbi.nPos   = 1
                              SetScrollInfo hwndc, %SB_VERT, sbi, 0
                  
                              invalidaterect hwnd, BYVAL 0, BYVAL 0
                              updatewindow hwnd
                              updatecaret(cx, cy, cw, ch, coffset, topline)
                            END IF
                  
                  
                          CASE 5001                                     'update y scrollbar
                            sbi.cbSize = SIZEOF(sbi)
                            sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                            sbi.nMin   = 0
                            sbi.nMax   = (tlc-lps)/sfy
                            sbi.nPage  = 1                              'size of thumb !!!
                            sbi.nPos   = 1
                            SetScrollInfo hwndc, %SB_VERT, sbi, 0
                  
                            IF tlc<11 THEN
                              pgs=1
                            ELSEIF tlc <100 THEN
                              pgs=2
                            ELSEIF tlc > 1000000 THEN
                              pgs = 1000
                            ELSE
                              pgs = tlc/(7.56*LOG10(tlc)^2.727)
                            END IF
                  
                            IF hexflag=0 THEN
                              setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Lines"
                            ELSE
                              setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Records"
                            END IF
                  
                            invalidaterect hwndc, BYVAL 0, BYVAL 0
                            updatewindow hwndc
                  
                  
                          CASE 5002                                     'toggle hexview
                            IF hexflag=0 THEN
                              hexflag=1
                              tlc=tlc_h
                              sfy = sfy_h
                              checkmenuItem(getmenu(hwndmain), %IDM_HEXVIEW, %MF_CHECKED)
                              setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Records"
                  
                              sty=getwindowlong(hwnd, %GWL_Style)
                              sty = sty XOR %WS_HSCROLL
                              setwindowlong(hwnd, %GWL_Style, sty)
                  
                              getwindowrect hwndmain, r
                              IF r.nright-r.nleft <> 88*cw+getsystemmetrics(%SM_cxVscroll) THEN         'ensure correct width for hex view
                                setwindowpos hwndmain, BYVAL 0, 0,0, 88*cw+getsystemmetrics(%SM_cxVscroll), r.nbottom-r.ntop, %SWP_NoZorder OR %SWP_NoMove
                              ELSE
                                getclientrect hwndmain, r
                                sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
                              END IF
                  
                            ELSE                                        'resize, when switching to text view
                              hexflag=0
                              tlc=tlc_t
                              sfy = sfy_t
                              checkmenuItem(getmenu(hwndmain), %IDM_HEXVIEW, %MF_UNCHECKED)
                              setwindowtext hwndmain, "  Large File Viewer  ["+f$+"]  -  "+FORMAT$(tlc)+" Lines"
                  
                              sty=getwindowlong(hwnd, %GWL_Style)
                              sty = sty OR %WS_HSCROLL
                              setwindowlong(hwnd, %GWL_Style, sty)
                              getclientrect hwndmain, r
                  
                              sendmessage hwndmain, %WM_SIZE, %SIZE_RESTORED, MAK(DWORD, r.nright-r.nleft, r.nbottom-r.ntop)
                            END IF
                  
                            IF lc<=0 THEN EXIT FUNCTION                 'if no file is loaded -> exit
                  
                            IF tlc<11 THEN
                              pgs=1
                            ELSEIF tlc <101 THEN
                              pgs=2
                            ELSEIF tlc > 1000000 THEN
                              pgs = 1000
                            ELSE
                              pgs = tlc/(7.56*LOG10(tlc)^2.727)
                            END IF
                  
                            q = foffset + l(topline + cy) - smemb + MIN(coffset+cx, l(topline + cy + 1)-l(topline + cy))
                  
                            showcaret hwnd
                            selflag = 0
                            coffset = 0
                            cx=0 : cy=0                                 'reset caret pos
                  
                  
                            IF getfile(cp) THEN
                              q=q-foffset
                  
                              FOR i=1 TO lc                             'find line
                                IF q < l(i) - smemb THEN
                                  topline=i-cy-1                        'set topline (place as first line)
                                  q=q-(l(i-1) - smemb)
                                  EXIT FOR
                                END IF
                              NEXT i
                  
                              IF topline < 0 THEN                       'adapt min/max value for topline
                                cy=cy+topline'-1
                                topline=0
                              ELSEIF topline > lc-lps THEN
                                cy=cy+topline-(lc-lps)
                                topline = lc-lps
                                IF topline < 0 THEN
                                  cy=cy+topline'-1
                                  topline=0
                                END IF
                              END IF
                  
                              cx=q                                      'set cx
                              IF hexflag=0 THEN
                                IF q>cpl THEN                           'bring into view (centered), if necessary
                                  coffset=q-cpl/2
                                  cx=q-coffset
                                END IF
                              END IF
                  
                  
                              sbi.cbSize = SIZEOF(sbi)
                              sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                              sbi.nMin   = 1
                              sbi.nMax   = lmax-cpl
                              sbi.nPage  = 1                            'size of thumb !!!
                              sbi.nPos   = 1
                              SetScrollInfo hwndc, %SB_HORZ, sbi, 0
                  
                  
                              sbi.cbSize = SIZEOF(sbi)
                              sbi.fMask  = %SIF_ALL OR %SIF_DISABLENOSCROLL
                              sbi.nMin   = 0
                              sbi.nMax   = (tlc-lps)/sfy
                              sbi.nPage  = 1                            'size of thumb !!!
                              sbi.nPos   = 1
                              SetScrollInfo hwndc, %SB_VERT, sbi, 0
                  
                              invalidaterect hwnd, BYVAL 0, BYVAL 0
                              updatewindow hwnd
                              updatecaret(cx, cy, cw, ch, coffset, topline)
                            END IF
                  
                  
                          CASE 5010
                            updatecaret(cx, cy, cw, ch, coffset, topline)                   'show again after menu closed
                  
                  
                          CASE %IDM_GOTO                                'goto line ^(lparam = quad ptr to line)
                            gt = lparam
                            q  = @gt
                            coffset = 0
                  
                            IF pc=1 THEN
                              cx=0
                              cy=lps/2
                              topline=q-cy-1                            'set topline (place line in the middle)
                  
                            ELSE                                        'any other case
                              IF hexflag=1 THEN
                                q=q*16                                  'make it an offset
                                FOR i=1 TO pc
                                  IF q < p(i) THEN
                                    cp=i
                                    IF cp=pc THEN cp=pc-1
                                    getfile(cp)
                                    cx=0
                                    cy=lps/2
                                    [email protected]            'set topline (place line in the middle)
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                  'ods("hex - q:"+str$(q)+"  "+str$(loffset)+str$(topline)+str$(cy)+"  cp:"+STR$(cp)+str$(lc))
                  
                              ELSE
                                FOR i=1 TO pc
                                  IF q < p1(i) THEN
                                    cp=i
                                    IF cp=pc THEN cp=pc-1
                                    getfile(cp)
                                    cx=0
                                    cy=lps/2
                                    [email protected]            'set topline (place line in the middle)
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                  'ods("text - q:"+STR$(q)+"  "+STR$(loffset)+STR$(topline)+STR$(cy)+"  cp:"+str$(cp))
                              END IF
                            END IF
                  
                  
                            IF topline < 0 THEN                         'adapt min/max value for topline
                              cy=cy+topline'-1
                              topline=0
                            ELSEIF topline > lc-lps THEN
                              cy=cy+topline-(lc-lps)
                              topline = lc-lps
                            END IF
                  
                            selflag=8                                   'set selection
                            sels = foffset + l(topline + cy) - smemb
                            IF sels < 0 THEN
                              sels = foffset + l(lc) - smemb
                            ELSEIF sels > foffset + l(lc) - smemb THEN
                              sels = foffset + l(lc) - smemb
                            END IF
                  
                            sele = foffset + l(topline + cy) - smemb + l(topline + cy + 1)-l(topline + cy)
                            IF sele < 0 THEN
                              sele = foffset + l(lc) - smemb
                            ELSEIF sele > foffset + l(lc) - smemb THEN
                              sele = foffset + l(lc) - smemb
                            END IF
                  
                  
                            updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                            invalidaterect hwndc, BYVAL 0, BYVAL 0
                            updatewindow hwndc
                  
                  
                          CASE %IDM_COPY, %IDM_COPYFILE
                            IF sels < sele THEN
                              sel1 = sels : sel2 = sele
                            ELSE
                              sel1 = sele : sel2 = sels
                              SWAP ls, le
                            END IF
                  
                  
                            OPEN f$ FOR BINARY AS #5 BASE=0
                              SEEK #5, sel1
                              GET$ #5, sel2 - sel1, d$
                            CLOSE #5
                  
                            IF LEN(d$) THEN
                              e$="File : "+CHR$(34)+f$+CHR$(34)+$CRLF+_
                                 "Line # "+FORMAT$(ls, "#,")+" - Line # "+FORMAT$(le, "#,")+$CRLF
                  
                              IF hexflag=1 THEN
                                e$=e$+"Fileoffset "+LEFT$(HEX$(sel1, 2), 2)+"_"+RIGHT$(HEX$(sel1, 8), 8)+_
                                      " - Fileoffset : "+LEFT$(HEX$(sel2, 2),2 )+"_"+RIGHT$(HEX$(sel2, 8), 8)
                              ELSE
                                e$=e$+"Fileoffset "+FORMAT$(sel1, "#,")+" - Fileoffset : "+FORMAT$(sel2, "#,")
                              END IF
                              e$=e$+$CRLF+$CRLF
                  
                              IF LOWRD(wParam) = %IDM_COPY THEN
                                CLIPBOARD SET TEXT e$+d$
                  '              MSGBOX e$+d$
                              ELSE
                                DISPLAY OPENFILE hwnd,,, " Save Selection as ...", "C:\", CHR$("All Files", 0, "*.*", 0), _
                                             "", "", %OFN_EXPLORER TO t$
                  
                                IF LEN(t$) THEN
                                  OPEN t$ FOR BINARY AS #5 BASE=0
                                    PUT$ #5, e$+d$
                                  CLOSE #5
                                END IF
                              END IF
                            ELSE
                              MSGBOX "  Copy failed", %MB_ICONEXCLAMATION, " ERROR"
                            END IF
                  
                            EXIT FUNCTION
                  
                  
                          CASE %IDM_FIND
                            IF fc>0 THEN                                'if there are results
                              q=ff(lparam)
                  
                              FOR i=1 TO pc-1                           'find chunk
                                IF q < p(i) THEN
                                  cp=i
                                  getfile(cp)                           'read
                                  q=q-foffset
                                  GOTO exit_find
                                END IF
                              NEXT i
                  
                              IF pc>1 THEN                              'if in last part and if more than  one part
                                cp=pc-1
                                getfile(cp)
                                q=q-foffset
                              END IF
                  
                  exit_find:
                              FOR i=1 TO lc                             'find line
                                IF q < l(i) - smemb THEN
                                  cx=0
                                  cy=lps/2
                                  topline=i-cy-1                        'set topline (place line in the middle)
                                  q=q-(l(i-1) - smemb)
                                  EXIT FOR
                                END IF
                              NEXT i
                  
                              IF topline < 0 THEN                       'adapt min/max value for topline
                                cy=cy+topline'-1
                                topline=0
                              ELSEIF topline > lc-lps THEN
                                cy=cy+topline-(lc-lps)
                                topline = lc-lps
                                IF topline < 0 THEN                       'adapt min/max value for topline
                                  cy=cy+topline'-1
                                  topline=0
                                END IF
                              END IF
                  
                  
                              selflag=11                                'set selection
                              sels = foffset + l(topline + cy) - smemb + MIN(q, l(topline + cy + 1)-l(topline + cy))
                              IF sels < 0 THEN
                                sels = foffset + l(lc) - smemb
                              ELSEIF sels > foffset + l(lc) - smemb THEN
                                sels = foffset + l(lc) - smemb
                              END IF
                  
                  
                              sele = foffset + l(topline + cy) - smemb + MIN(q+LEN(fnd$), l(topline + cy + 1)-l(topline + cy))
                              IF sele < 0 THEN
                                sele = foffset + l(lc) - smemb
                              ELSEIF sele > foffset + l(lc) - smemb THEN
                                sele = foffset + l(lc) - smemb
                              END IF
                  
                  
                              IF q>cpl THEN                             'bring into view (centered), if necessary
                                coffset=q-cpl/2
                              ELSE
                                coffset=0
                              END IF
                  
                              updatecaret(cx, cy, cw, ch, coffset, topline)
                  
                              invalidaterect hwndc, BYVAL 0, BYVAL 0
                              updatewindow hwndc
                            END IF
                  
                        END SELECT
                  
                  
                      CASE %WM_erasebkgnd
                        FUNCTION = 1                                    'just do nothing
                        EXIT FUNCTION
                  
                  
                      CASE %WM_PAINT
                        IF hexflag=0 THEN
                  '***********************************************************************************************
                  ' draw text
                  '***********************************************************************************************
                          hdc = BeginPaint(hWnd, ps)                    'initiates window painting
                            getclientrect hwnd, r
                            hmemdc = createcompatibledc (hdc)
                            hbmp = createcompatiblebitmap (hdc, r.nright, r.nbottom)
                  
                            CALL SelectObject (hmemdc, hbmp)
                            CALL SelectObject (hmemdc, hfont)
                            fillrect hmemdc, r, getstockobject(%White_Brush)                'draw background
                  
                  
                            IF lc>0 THEN
                              FOR i=topline TO topline+lps
                                IF i>lc-1 THEN EXIT FOR
                                CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL l(i)+coffset, MIN(cpl, l(i+1)-l(i)-coffset)) 'line by line
                              NEXT i
                  
                              IF selflag>0 THEN                         'draw selection
                                enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_ENABLED)
                                enablemenuitem (getmenu(hwndmain), %IDM_COPYFILE, %MF_ENABLED)
                  
                                IF selflag < 10 THEN
                                  setbkcolor hmemdc, RGB(200, 200, 255)
                                ELSE
                                  setbkcolor hmemdc, RGB(255, 200, 200)
                                END IF
                  
                  
                                IF sels < sele THEN
                                  sel1 = sels : sel2 = sele
                                ELSE
                                  sel1 = sele : sel2 = sels
                                END IF
                  
                  
                                ly = sel1 - foffset
                                FOR i=1 TO lc
                                  IF ly <= l(i) - smemb THEN
                                    ly = i-1
                                    lx = sel1 - foffset - l(i-1) + smemb
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                                hy = sel2 - foffset
                                FOR i=1 TO lc
                                  IF hy <= l(i) - smemb THEN
                                    hy = i-1
                                    hx = sel2 - foffset - l(i-1) + smemb
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                  
                                FOR i=topline TO topline+lps
                                  IF i>lc-1 THEN EXIT FOR
                  
                                  IF ly=i THEN
                                    IF ly=hy THEN                       'selection only in one line
                                      d$=PEEK$(l(i), l(i+1)-l(i))
                                      n=LEN(d$)
                                      IF lx<n THEN                      'if inside line (not beyond end)
                                      IF hx=n THEN                      'if selected until end of line
                                        d$=MID$(d$, lx+1, hx-lx)+SPACE$(cpl+10)
                                        CALL TextOut (hmemdc, %mg+(lx-coffset)*cw, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                                      ELSE                              'if selection ends before line ends
                                        d$=MID$(d$, lx+1, hx-lx)
                                        CALL TextOut (hmemdc, %mg+(lx-coffset)*cw, (i-topline)*ch, BYVAL STRPTR(d$), LEN(d$))
                                      END IF
                                      END IF
                                    ELSE                                'first line of selectiom
                                      d$=PEEK$(l(i), l(i+1)-l(i))
                                      n=LEN(d$)
                                      IF lx<n THEN                      'if inside line (not beyond end)
                                        IF coffset < lx THEN
                                          d$=MID$(d$, lx+1)+SPACE$(cpl+10)
                                          CALL TextOut (hmemdc, %mg+(lx-coffset)*cw, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                                        ELSE
                                          d$=MID$(d$, coffset+1)+SPACE$(cpl+10)
                                          CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                                        END IF
                                      END IF
                                    END IF
                                  ELSEIF ly<i THEN
                                    IF hy=i THEN                        'last line of selection
                                      d$=PEEK$(l(i), l(i+1)-l(i))
                                       n=LEN(d$)
                                      IF hx=n THEN                      'if selected until end of line
                                        d$=MID$(d$, coffset+1, hx)+SPACE$(cpl+10)
                                        CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                                      ELSE                              'if selection ends before line ends
                                        d$=MID$(d$, coffset+1, hx)
                                        CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), hx-coffset)
                                      END IF
                                    ELSEIF hy>i THEN                    'totally selected line
                                      d$=PEEK$(l(i), l(i+1)-l(i))
                                      d$=MID$(d$, coffset+1)+SPACE$(cpl+10)
                                      CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL STRPTR(d$), cpl+10)
                                    END IF
                                  END IF
                                NEXT i
                  
                              ELSE
                                enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_GRAYED)
                                enablemenuitem (getmenu(hwndmain), %IDM_COPYFILE, %MF_GRAYED)
                              END IF
                            END IF
                  
                            BitBlt(hDC, 0, 0, r.nright-r.nleft, r.nbottom-r.ntop, hmemdc, 0, 0, %SRCCOPY) 'draw entire clientarea
                            deletedc hmemdc
                            deleteobject hbmp
                          CALL EndPaint(hWnd, ps)                       'ends window painting
                  
                        ELSE
                  '***********************************************************************************************
                  ' draw hex
                  '***********************************************************************************************
                  LOCAL hdc1      AS DWORD
                  LOCAL hmemdc1   AS DWORD
                  LOCAL hbmp1     AS DWORD
                  LOCAL r1        AS rect
                  
                          hdc = BeginPaint(hWnd, ps)                    'initiates window painting (text)
                            getclientrect hwnd, r
                            hmemdc = createcompatibledc (hdc)
                            hbmp = createcompatiblebitmap (hdc, r.nright, r.nbottom)
                            CALL SelectObject (hmemdc, hbmp)
                            CALL SelectObject (hmemdc, hfont)
                            fillrect hmemdc, r, getstockobject(%White_Brush)                'draw background
                  
                            hdc1 = getdc(hwndmain)                      'get dc for hex
                            r1 = r
                            r1.nright = r1.nleft+69*cw+1
                            r1.nbottom = r1.nbottom + 2
                            hmemdc1 = createcompatibledc (hdc1)
                            hbmp1 = createcompatiblebitmap (hdc1, r1.nright, r1.nbottom)
                  
                            CALL SelectObject (hmemdc1, hbmp1)
                            CALL SelectObject (hmemdc1, hfont)
                            setbkmode hmemdc1, %Transparent
                            fillrect hmemdc1, r1, getsyscolorbrush(%COLOR_Infobk)           'draw background
                            framerect hmemdc1, r1, getsyscolorbrush(%COLOR_WINDOWFRAME)     'draw border
                  
                            r1.nright = r1.nleft+13*cw+1
                            fillrect hmemdc1, r1, getsyscolorbrush(%COLOR_3DFace)           'draw background
                            framerect hmemdc1, r1, getsyscolorbrush(%COLOR_WINDOWFRAME)     'draw border
                  
                            r1 = r
                            r1.nright = r1.nleft+69*cw+1
                            r1.nbottom = r1.nbottom + 2                 'restore hex dc´s dimensions
                  
                  
                            IF lc>0 THEN
                  'ods("paint:"+STR$(lc))
                              FOR i=topline TO topline+lps
                                IF i>lc-1 THEN EXIT FOR
                                lp=hexview(BYVAL l(i), l(i+1)-l(i), foffset + i*16)
                                CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL lp+70, 16) 'line by line (text)
                                CALL TextOut (hmemdc1, %mg, (i-topline)*ch, BYVAL lp, 69)   'line by line (hex)
                              NEXT i
                  
                  
                              IF selflag>0 THEN                         'draw selection
                                enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_ENABLED)
                                enablemenuitem (getmenu(hwndmain), %IDM_COPYFILE, %MF_ENABLED)
                  
                                IF selflag < 10 THEN
                                  setbkcolor hmemdc, RGB(200, 200, 255)
                                ELSE
                                  setbkcolor hmemdc, RGB(255, 200, 200)
                                END IF
                  
                  
                                IF sels < sele THEN
                                  sel1 = sels : sel2 = sele
                                ELSE
                                  sel1 = sele : sel2 = sels
                                END IF
                  
                  
                                ly = sel1 - foffset
                                FOR i=1 TO lc
                                  IF ly <= l(i) - smemb THEN
                                    ly = i-1
                                    lx = sel1 - foffset - l(i-1) + smemb
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                                hy = sel2 - foffset
                                FOR i=1 TO lc
                                  IF hy <= l(i) - smemb THEN
                                    hy = i-1
                                    hx = sel2 - foffset - l(i-1) + smemb
                                    EXIT FOR
                                  END IF
                                NEXT i
                  
                                FOR i=topline TO topline+lps            'line by line
                                  IF i>lc-1 THEN EXIT FOR
                                  lp=hexview(BYVAL l(i), l(i+1)-l(i), foffset + i*16)
                  
                  '                setbkcolor hmemdc1, getsyscolor(%COLOR_Infobk)
                                  settextcolor hmemdc1, RGB(255,0,0)
                  
                                  IF ly=i THEN
                                    IF ly=hy THEN                       'selection only in one line
                                      CALL TextOut (hmemdc, %mg + lx*cw, (i-topline)*ch, BYVAL lp+70+lx, hx-lx)
                  
                  LOCAL x AS DWORD
                  LOCAL y AS DWORD
                  '***********************************************************************************************
                  ' "00:00000000 : xx xx xx xx - xx xx xx xx = xx xx xx xx - xx xx xx xx  : .... .... .... ...." + $CRLF
                  ' offset = 14
                  ' 0-1 ok, ab 4 +2, ab 8 +4, ab 12 +6
                  '***********************************************************************************************
                  
                                      x=(lx*3 + INT(lx/4)*2)
                                      y=(hx*3 + INT((hx-1)/4)*2)
                                      CALL TextOut (hmemdc1, %mg + 14*cw + x*cw, (i-topline)*ch, BYVAL lp+14+x, y-x)
                  
                                    ELSE                                'first line of selectiom
                                      CALL TextOut (hmemdc, %mg + lx*cw, (i-topline)*ch, BYVAL lp+70+lx, 16-lx)
                  
                                      x=(lx*3 + INT(lx/4)*2)
                  '                    y=(16*3 + INT((16-1)/4)*2)      '=54
                                      CALL TextOut (hmemdc1, %mg + 14*cw + x*cw, (i-topline)*ch, BYVAL lp+14+x, 54-x)
                                    END IF
                  
                                  ELSEIF ly<i THEN
                                    IF hy=i THEN                        'last line of selection
                                      CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL lp+70, hx)
                  
                                      y=(hx*3 + INT((hx-1)/4)*2)
                                      CALL TextOut (hmemdc1, %mg + 14*cw, (i-topline)*ch, BYVAL lp+14, y)
                  
                                    ELSEIF hy>i THEN                    'totally selected line
                                      CALL TextOut (hmemdc, %mg, (i-topline)*ch, BYVAL lp+70, 16)
                                      CALL TextOut (hmemdc1, %mg + 14*cw, (i-topline)*ch, BYVAL lp+14, 54)
                                    END IF
                                  END IF
                                NEXT i
                  
                              ELSE
                                enablemenuitem (getmenu(hwndmain), %IDM_COPY, %MF_GRAYED)
                                enablemenuitem (getmenu(hwndmain), %IDM_COPYFILE, %MF_GRAYED)
                              END IF
                  
                            END IF
                  
                            BitBlt(hDC, 0, 0, r.nright-r.nleft, r.nbottom-r.ntop, hmemdc, 0, 0, %SRCCOPY) 'draw entire clientarea (text)
                            deletedc hmemdc
                            deleteobject hbmp
                  
                            BitBlt(hDC1, 0, 0, r1.nright-r1.nleft, r1.nbottom-r1.ntop, hmemdc1, 0, 0, %SRCCOPY) 'draw entire clientarea (hex)
                            deletedc hmemdc1
                            deleteobject hbmp1
                            releasedc hwndmain, hdc1
                          CALL EndPaint(hWnd, ps)                       'ends window painting
                  
                        END IF
                  
                        IF lc>0 THEN
                          setscrollpos hwndc, %SB_VERT, (loffset+topline)/sfy, %true
                          setscrollpos hwndc, %SB_HORZ, coffset, %true
                          showcaret hwnd
                        END IF
                  
                  
                      CASE %WM_DESTROY                                  'exit - clean up
                        DeleteObject hfont
                        DeleteObject hcaret
                        EXIT FUNCTION
                  
                    END SELECT
                  
                  
                    FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
                    EXIT FUNCTION
                  
                  
                  setsels:
                    sels = foffset + l(topline + cy) - smemb + MIN(coffset+cx, l(topline + cy + 1)-l(topline + cy))
                    IF sels < 0 THEN
                      sels = foffset + l(lc) - smemb
                    ELSEIF sels > foffset + l(lc) - smemb THEN
                      sels = foffset + l(lc) - smemb
                    END IF
                    ls = loffset + topline + cy + 1
                  RETURN
                  
                  
                  setsele:
                    sele = foffset + l(topline + cy) - smemb + MIN(coffset+cx, l(topline + cy + 1)-l(topline + cy))
                    IF sele < 0 THEN
                      sele = foffset + l(lc) - smemb
                    ELSEIF sele > foffset + l(lc) - smemb THEN
                      sele = foffset + l(lc) - smemb
                    END IF
                    le = loffset + topline + cy + 1
                  RETURN
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  FUNCTION Hexview(BYVAL p AS DWORD, BYVAL n AS DWORD, BYVAL q AS QUAD) AS DWORD
                  '***********************************************************************************************
                  ' "00:00000000 : xx xx xx xx - xx xx xx xx = xx xx xx xx - xx xx xx xx  : .... .... .... ...." + $CRLF
                  ' deliver 16 bit output or shorter, regardless if input is longer
                  ' no need for longer strings, bcause you can copy it to a file and then use a hexeditor
                  '***********************************************************************************************
                  #REGISTER NONE
                  
                  LOCAL pDataIn AS DWORD
                  LOCAL pDataout AS DWORD
                  STATIC buffer$
                  
                  
                    buffer$ = SPACE$(100)
                  
                  
                    pDataout = STRPTR(buffer$)
                    pDataIn = p
                    n = pdatain+n
                  
                  
                  !  lea esi, q
                  !  mov edi, pdataout                   ;get pointer to output buffer
                  !  lea edx, hextable_1
                  
                  
                  '***********************************************************************************************
                  ' 10 hex digit offset
                  '***********************************************************************************************
                  
                  !  mov ecx, [esi+4]                    ;get high dword of offset (quad)
                  !  movzx ebx, cl                       ;get the low byte of high dword of offset
                  !  mov eax, &h205F2020                 ;" _  "
                  !  mov ax, [edx+ebx*2]                 ;look up the HEX equivalent characters
                  
                  !  mov [edi], eax                      ;store the 4 HEX characters in the output buffer
                  
                  !  mov ecx, [esi]                      ;get low dword of offset (quad)
                  !  movzx ebx, cl                       ;get the low byte of low dword of offset
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  shl eax, 16                         ;move them into place in the top half of register
                  !  movzx ebx, ch                       ;get the high byte
                  !  mov ax, [edx+ebx*2]                 ;look up the hex equvalent charcters and put them in the lower half of eax
                  
                  !  mov [edi+7], eax                    ;store it in the output buffer
                  
                  !  shr ecx, 16                         ;get the 2 upper bytes into the lower half of the register so I can get at them
                  !  movzx ebx, cl                       ;get the middle byte
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  shl eax, 16                         ;move them into place in the top half of register
                  !  movzx ebx, ch                       ;get the high byte
                  !  mov ax, [edx+ebx*2]                 ;look up the hex equvalent charcters and put them in the lower half of eax
                  
                  !  mov [edi+3], eax                    ;store the 4 HEX characters in the output buffer
                  !  mov dword ptr [edi+11], &h20202020  ;"  : "
                  '!  mov dword ptr [edi+11], &h20203A20  ;"  : "
                  
                  !  mov dword ptr [edi+72], &h20202020  ;"  : "
                  '!  mov dword ptr [edi+72], &h20203A20  ;"  : "
                  !  sub edi, 1
                  
                  
                  '***********************************************************************************************
                  'now 16 bytes of HEX data
                  '***********************************************************************************************
                  
                  !  mov ecx, n                          ;end pos
                  !  mov esi, pDataIn                    ;get pointer to input buffer
                  
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+15], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+71], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+18], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+72], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+21], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+73], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+24], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+74], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  mov dword ptr [edi+26], &h20202D20  ;" -  "
                  !  add edi, 14
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+15], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+61], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+18], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+62], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+21], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+63], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+24], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+64], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  mov dword ptr [edi+26], &h20203D20  ;" =  "
                  !  add edi, 14
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+15], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+51], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+18], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+52], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+21], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+53], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+24], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+54], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  mov dword ptr [edi+26], &h20202D20  ;" -  "
                  !  add edi, 14
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+15], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+41], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+18], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+42], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+21], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+43], al                    ;write byte
                  !  add esi, 1
                  !  cmp esi, ecx
                  !  jz ende
                  
                  !  movzx ebx, byte ptr [esi]           ;1. nibble
                  !  mov eax, [edx+ebx*2]                ;look up the HEX equivalent characters
                  !  mov [edi+24], ax                    ;write bytes
                  !  mov eax, [edx+ebx+512]              ;look up the ASC equivalent characters
                  !  mov [edi+44], al                    ;write byte
                  
                  
                  ende:
                  
                  
                    FUNCTION = STRPTR(buffer$)
                  
                  
                  EXIT FUNCTION
                  
                  
                  #UTILITY gpf -c
                  
                  hextable_1:
                    ! dw "00","10","20","30","40","50","60","70","80","90","A0","B0","C0","D0","E0","F0"
                    ! dw "01","11","21","31","41","51","61","71","81","91","A1","B1","C1","D1","E1","F1"
                    ! dw "02","12","22","32","42","52","62","72","82","92","A2","B2","C2","D2","E2","F2"
                    ! dw "03","13","23","33","43","53","63","73","83","93","A3","B3","C3","D3","E3","F3"
                    ! dw "04","14","24","34","44","54","64","74","84","94","A4","B4","C4","D4","E4","F4"
                    ! dw "05","15","25","35","45","55","65","75","85","95","A5","B5","C5","D5","E5","F5"
                    ! dw "06","16","26","36","46","56","66","76","86","96","A6","B6","C6","D6","E6","F6"
                    ! dw "07","17","27","37","47","57","67","77","87","97","A7","B7","C7","D7","E7","F7"
                    ! dw "08","18","28","38","48","58","68","78","88","98","A8","B8","C8","D8","E8","F8"
                    ! dw "09","19","29","39","49","59","69","79","89","99","A9","B9","C9","D9","E9","F9"
                    ! dw "0A","1A","2A","3A","4A","5A","6A","7A","8A","9A","AA","BA","CA","DA","EA","FA"
                    ! dw "0B","1B","2B","3B","4B","5B","6B","7B","8B","9B","AB","BB","CB","DB","EB","FB"
                    ! dw "0C","1C","2C","3C","4C","5C","6C","7C","8C","9C","AC","BC","CC","DC","EC","FC"
                    ! dw "0D","1D","2D","3D","4D","5D","6D","7D","8D","9D","AD","BD","CD","DD","ED","FD"
                    ! dw "0E","1E","2E","3E","4E","5E","6E","7E","8E","9E","AE","BE","CE","DE","EE","FE"
                    ! dw "0F","1F","2F","3F","4F","5F","6F","7F","8F","9F","AF","BF","CF","DF","EF","FF"
                  hextable_2:                                           '= hextable_1 + 512
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
                    ! db  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
                    ! db  64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79
                    ! db  80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
                    ! db  96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111
                    ! db 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                    ! db  46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46
                  
                  #UTILITY gpf +c
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  '*************************************************************************************************
                  '*************************************************************************************************
                  
                  
                  FUNCTION WINMAIN(BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpCmdLine AS ASCIIZ PTR, BYVAL iCmdShow AS LONG) AS LONG
                  '*************************************************************************************************
                  ' Main Program entry point
                  '*************************************************************************************************
                  LOCAL Msg         AS TAGMSG
                  LOCAL wce         AS WNDCLASSEX
                  LOCAL szClassName AS ASCIIZ * 80
                  'LOCAL hMenu       AS DWORD
                  LOCAL hAccel      AS DWORD
                  
                  
                    hinst = hInstance
                  
                  '*************************************************************************************************
                  'Setup, Register and create the main window
                  '*************************************************************************************************
                  
                    szClassName = "Fileviewer32"
                    wce.cbSize = SIZEOF(wce)
                    wce.STYLE = %CS_HREDRAW OR %CS_VREDRAW
                    wce.lpfnWndProc = CODEPTR(MainProc)
                    wce.hInstance = hInstance
                    wce.hIcon = LoadIcon(hInstance, "PROGRAM")
                    wce.hCursor = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                    wce.hbrBackground = GetStockObject(%WHITE_BRUSH)
                    wce.lpszClassName = VARPTR(szClassName)
                    wce.hIconSm = LoadIcon(hInstance, BYVAL %IDI_APPLICATION)
                    RegisterClassEx wce
                  
                  
                    hMenu = LoadMenu(hInstance, "MAINMENU")
                  
                    hwndmain = CreateWindow(szClassName, _            'window class name
                    "  Large File Viewer", _                            'window caption
                    %WS_OVERLAPPEDWINDOW OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN, _         'window style
                    %CW_USEDEFAULT, _                                   'initial x position
                    %CW_USEDEFAULT, _                                   'initial y position
                    %CW_USEDEFAULT, _                                   'initial x size
                    %CW_USEDEFAULT, _                                   'initial y size
                    %HWND_DESKTOP, _                                    'parent window handle
                    hMenu, _                                            'window menu handle
                    hInstance, _                                        'program instance handle
                    BYVAL %NULL)                                        'creation parameters
                  
                  
                    hAccel = LoadAccelerators(hInstance, "ACC")         'load accelerators
                  
                  
                  '*************************************************************************************************
                  'Setup, Register and create the text window
                  '*************************************************************************************************
                  
                    szClassName = "Textviewer32"
                    wce.cbSize = SIZEOF(wce)
                    wce.STYLE = %CS_HREDRAW OR %CS_VREDRAW
                    wce.lpfnWndProc = CODEPTR(ChildProc)
                    wce.hInstance = hInstance
                    wce.hIcon = 0
                    wce.hCursor = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                    wce.hbrBackground = GetStockObject(%WHITE_BRUSH)
                    wce.lpszClassName = VARPTR(szClassName)
                    wce.hIconSm = 0
                    RegisterClassEx wce
                  
                    hwndc = CreateWindow(szClassName, _                 'window class name
                    "", _                                               'window caption
                    %WS_CHILD OR %WS_BORDER OR %WS_VSCROLL OR %WS_HSCROLL OR %WS_CLIPSIBLINGS, _ 'window style
                    %CW_USEDEFAULT, _                                   'initial x position
                    %CW_USEDEFAULT, _                                   'initial y position
                    %CW_USEDEFAULT, _                                   'initial x size
                    %CW_USEDEFAULT, _                                   'initial y size
                    HWNDMAIN, _                                         'parent window handle
                    300, _                                              'window id
                    hInstance, _                                        'program instance handle
                    BYVAL %NULL)                                        'creation parameters
                  
                  
                  
                    ShowWindow hwndc, %SW_SHOW                          'show child
                  
                    ShowWindow hwndmain, iCmdShow                       'show main window
                    UpdateWindow hwndmain                               'draw
                  
                    setfocus hwndc                                      'set focus to textwindow
                  
                  
                    DO WHILE GetMessage(Msg, BYVAL %NULL, 0, 0)         'message loop
                      IF ISFALSE TranslateAccelerator(hwndmain, hAccel, Msg) THEN
                        TranslateMessage Msg
                        DispatchMessage Msg
                      END IF
                    LOOP
                  
                  
                    GLOBALMEM FREE  smemh TO smemh                      'clean up
                    FUNCTION = msg.wParam
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  FUNCTION getfile(chunk AS DWORD) AS LONG
                  '***********************************************************************************************
                  ' read part of file into buffer for viewing, l() holds pointers to corresponding lines
                  ' (l(1)=line #1 and so on, lc = line count (0=there are no lines, 5=lines # 1,2,3,4,5 exist)
                  ' cut long lines after %max_lines and make it a new line, even if there is no delimiter
                  '***********************************************************************************************
                  'LOCAL qFreq AS QUAD
                  'LOCAL qStart AS QUAD
                  'LOCAL qStop AS QUAD
                  '   QueryPerformanceFrequency qFreq
                  '   QueryPerformanceCounter   qStart
                  '***********************************************************************************************
                  LOCAL n     AS LONG
                  LOCAL y     AS QUAD
                  LOCAL z     AS LONG
                  LOCAL dp    AS LONG                                   'delimiter pos
                  LOCAL pdp    AS LONG                                  'previous delimiter pos
                  
                  LOCAL hfile AS DWORD
                  
                  REGISTER c AS LONG
                  REGISTER x AS LONG
                  
                  
                    hFile = CreateFile(BYVAL STRPTR(f$), %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0, _
                                       %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, BYVAL 0)
                  
                    IF hFile = %INVALID_HANDLE_VALUE THEN
                    END IF
                  
                  
                    IF hexflag=0 THEN                                   'standart view
                      foffset = p(chunk-1)                              'total fileoffest
                      loffset = p1(chunk-1)                             'total lineoffest
                  
                      IF pc > 1 THEN                                    'if more than one chunks
                        x=p(chunk+1)-p(chunk-1)                         'get these two
                        n=p1(chunk+1)-p1(chunk-1)                       '# of lines needed
                  
                      ELSE                                              'if only one chunk
                        x=p(chunk)-p(chunk-1)                           'get this one
                        n=p1(chunk)-p1(chunk-1)                         '# of lines needed
                      END IF
                  
                  
                      REDIM l(n+10)
                      lc=0
                      c = ASC(delimiter)
                  
                  
                      setfilepointer hfile, foffset, BYVAL 0, %File_Begin
                      readfile(hfile, BYVAL smemb, BYVAL x, z, BYVAL 0) 'read
                  
                      IF z > 0 THEN
                        l(0)=smemb                                      'ptr to first line
                        lc=0
                        n=1
                  
                        REDIM char(z-1) AS BYTE AT smemb
                        pdp = smemb
                  
                        FOR x = 0 TO z-1
                          IF char(x) = c THEN
                            IF PEEK$(smemb+x, LEN(delimiter))=delimiter THEN                'check for (multibyte) delimiter
                              dp = x+LEN(delimiter) + smemb             'ptr to next line
                              IF dp-pdp > %max_line THEN                'exceeds max line lentght (%max_line)
                                FOR y=1 TO CEIL((dp-pdp)/%max_line)-1
                                  pdp = pdp + %max_line
                                  l(n) = pdp                            'insert line breaks (might be inside a word !!!)
                                  INCR n
                                  lmax=MAX(lmax, l(n)-l(n-1))
                                NEXT y
                              END IF
                  
                              l(n) = dp
                              lmax=MAX(lmax, l(n)-l(n-1))
                              pdp = dp
                  
                              INCR n
                            END IF
                          END IF
                        NEXT
                  
                        lc=n-1                                          '# of valid lines (1 to n-2)
                  
                  
                        IF l(n-1)<smemb+z THEN                          'if it doesn´t end with a delimiter
                          dp = smemb+z
                          IF dp-pdp > %max_line THEN                    'exceeds max line lentght (%max_line)
                            FOR y=1 TO CEIL((dp-pdp)/%max_line)-1
                              pdp = pdp + %max_line
                              l(n) = pdp                                'insert line breaks (might be inside a word !!!)
                              INCR n
                              lmax=MAX(lmax, l(n)-l(n-1))
                            NEXT y
                            lc=n-1                                      '# of valid lines (1 to n-2)
                          END IF
                  
                          l(n)=smemb+z
                          lmax=MAX(lmax, l(n)-l(n-1))
                          lc=lc+1
                        END IF
                      END IF
                  
                  
                    ELSE                                                'hex view
                      foffset = p(chunk-1)
                      IF foffset MOD 16 <> 0 THEN foffset = foffset + 16 - foffset MOD 16   'set it on 16 byte border
                      loffset = foffset/16                              'total lineoffest
                  
                  
                      IF pc > 1 THEN                                    'if more than one chunks
                        y=p(chunk+1)
                        IF y MOD 16 <> 0 THEN y = y + 16 - y MOD 16     'set it on 16 byte border
                        x=y-foffset
                  
                      ELSE                                              'if only one chunk
                        y=p(chunk)
                        IF y MOD 16 <> 0 THEN y = y + 16 - y MOD 16     'set it on 16 byte border
                        x=y-foffset
                      END IF
                  
                      REDIM l(x/16+10)
                      lc=0
                      c=smemb
                  
                      setfilepointer hfile, foffset, BYVAL 0, %File_Begin
                      readfile(hfile, BYVAL smemb, BYVAL x, z, BYVAL 0) 'read
                  'ods("get1:"+STR$(chunk)+STR$(x)+" read:"+STR$(z)+str$(int(z/16))+" f:"+str$(foffset))
                  
                      IF z > 0 THEN
                        l(0)=smemb                                      'ptr to first line
                        lc=0
                        n=1
                  
                        FOR x = 1 TO INT(z/16)
                          c=c+16
                          l(n)=c
                          INCR n
                        NEXT x
                  
                        lc=n-1                                          '# of valid lines (1 to n-2)
                        lmax=16
                  
                  
                        IF l(2)=0 THEN                                  'only one line
                          l(n)=smemb+z
                          lc=1
                  
                        ELSEIF l(n-1)<smemb+z THEN                      'if it doesn´t end with a delimiter
                          l(n)=smemb+z
                          lc=lc+1
                        END IF
                      END IF
                  'ods("get2:"+str$(lc))
                  
                    END IF
                  
                  
                    CloseHandle hfile
                    FUNCTION=1
                  
                  
                  '***********************************************************************************************
                  '   QueryPerformanceCounter   qStop
                  '   ? FORMAT$(1000*(qStop-qStart)/qFreq,"###.00") & " milliseconds   "
                  '***********************************************************************************************
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  THREAD FUNCTION do_scan(BYVAL flag AS DWORD PTR) AS LONG
                  '***********************************************************************************************
                  ' scan file (Filename) for delimiter in portions of %partsize, save delimiter positions for
                  ' each part (=chunk) as fileoffset in p(), save cooreponding line # in p1(), p() and p1() are
                  ' zerobased
                  '***********************************************************************************************
                  'LOCAL qFreq AS QUAD
                  'LOCAL qStart AS QUAD
                  'LOCAL qStop AS QUAD
                  '   QueryPerformanceFrequency qFreq
                  '   QueryPerformanceCounter   qStart
                  '***********************************************************************************************
                  LOCAL i      AS LONG
                  LOCAL n      AS LONG                                  '# of estimated parts
                  LOCAL y      AS LONG
                  LOCAL z      AS LONG
                  LOCAL hfile  AS DWORD                                 'handle of file
                  LOCAL lf     AS QUAD                                  'lenght of file
                  LOCAL ld     AS QUAD                                  'last delimiter
                  LOCAL pld    AS QUAD                                  'previous last delimiter
                  LOCAL tlc_l  AS QUAD
                  
                  REGISTER c AS LONG
                  REGISTER x AS LONG
                  
                  
                    hFile = CreateFile(BYVAL STRPTR(f$), %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0, _
                                       %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, BYVAL 0)
                  
                    IF hFile = %INVALID_HANDLE_VALUE THEN
                    END IF
                  
                  
                    getfilesizeex(hfile, lf)                             'total lenght of file
                    n = lf/%partsize + 1                                 '# of read operations needed
                  
                    REDIM p(n)
                    REDIM p1(n)
                  
                    smeml=%partsize*2+%max_line*2+1000                  'two chunks + 2*%maxline overhead + 1000 (just to be sure)
                    GLOBALMEM ALLOC smeml TO smemh                      'allocate memory for viewing
                    GLOBALMEM LOCK  smemh TO smemb
                  
                    smeml1=%partsize+LEN(delimiter)+100
                    GLOBALMEM ALLOC smeml1 TO smemh1                    'allocate memory for scanning
                    GLOBALMEM LOCK  smemh1 TO smemb1
                  
                  
                    c     = ASC(delimiter)                              'first delimitting char
                    cp    = 1                                           'first part
                    pc    = 0                                           'initial part count
                    pld   = 0                                           'previous last delimiter
                    tlc   = 0
                    tlc_l = 0
                    p(0)  = 0                                           'start of file
                    p1(0) = 0                                           'line # (first line = 0)
                  
                    FOR i=1 TO n
                      IF @flag<>0 THEN
                        GLOBALMEM FREE  smemh1 TO smemh1
                        EXIT FUNCTION
                      END IF
                  
                      readfile(hfile, BYVAL smemb1, BYVAL %partsize+LEN(delimiter), y, BYVAL 0) 'read
                  
                      POKE$ smemb1+y, CHR$(0,0,0,0)                     'put &H00000000 at the end of each part read
                      IF %partsize+LEN(delimiter) <> y THEN             'if read less than requested, we just read last part
                        z=y                                             'because in last loop we want to process all chars read
                      ELSE
                        z=y-LEN(delimiter)                              'for every other loop, pprocess %partsize bytes (chars)
                      END IF
                      IF z <= 0 THEN EXIT FOR
                  
                      REDIM char(z-1) AS BYTE AT smemb1                 'define byte array
                      FOR x = 0 TO z-1                                  'scan char for char
                        IF char(x) = c THEN                             'if found
                          IF PEEK$(smemb1+x, LEN(delimiter))=delimiter THEN                 'check for (multibyte) delimiter
                            ld = (i-1)*%partsize+x+LEN(delimiter)       'save last delimiter pos
                            INCR tlc_l
                  
                            tlc_l = tlc_l + CEIL((ld-pld)/%max_line) - 1                    'increase if max line lenght is exceeded
                            pld = ld
                          END IF
                        END IF
                      NEXT
                  
                  
                  LOCAL ep AS QUAD
                      ep = (i-1)*%partsize+z                            'get end pos
                      IF ep-ld=>%max_line THEN                          'if last delimiter is back more than %max_line
                        ld = ep
                        tlc_l = tlc_l + CEIL((ld-pld)/%max_line) - 1    'increase if max line lenght is exceeded
                        pld = ld
                      END IF
                  
                  
                      INCR pc                                           'increase parts count
                      p(pc)  = ld                                       '(file)position of chunk (zerobased)
                      p1(pc) = tlc_l                                    'corresponding line # (zero based)
                  
                  
                      tlc_t = tlc_l
                      tlc_h = CEIL(((i-1)*%partsize+z)/16)
                  
                      IF hexflag=0 THEN
                        tlc=tlc_t
                      ELSE
                        tlc=tlc_h
                      END IF
                  
                      IF i=2 THEN
                        postmessage hwndc, %WM_COMMAND, 5000, 0         'first two chunks are read, start viewing
                      END IF
                  
                  
                      postmessage hwndmain, %WM_USER + 1000, i*10000/n, 0                   'indexing progress message (lparam=0)
                  
                      sfy = tlc/32000
                      postmessage hwndc, %WM_COMMAND, 5001, 0           'update y scrollbar
                  
                  
                      IF %partsize+LEN(delimiter) <> y THEN EXIT FOR
                      setfilepointerex hfile, LEN(delimiter)*-1, BYVAL 0, %File_Current
                    NEXT i
                  
                  
                    IF p(pc)<lf THEN                                    'if it doesn´t end with a delimiter
                      ld = lf
                      tlc_l = tlc_l + CEIL((ld-pld)/%max_line) - 1          'increase if max line lenght is exceeded
                  
                      p(pc) = lf
                      INCR tlc_l
                      p1(pc) = tlc_l
                      tlc_h = CEIL(lf/16)
                  
                      IF hexflag=0 THEN
                        tlc=tlc_t
                      ELSE
                        tlc=tlc_h
                      END IF
                  
                      IF pc<3 THEN
                        postmessage hwndc, %WM_COMMAND, 5000, 0         'reread first chunk, restart viewing
                      END IF
                    END IF
                  
                    IF pc=1 THEN
                      postmessage hwndc, %WM_COMMAND, 5000, 0           'if only one chunk, start viewing
                    END IF
                  
                  
                    CloseHandle hfile
                  
                  
                    sfy = tlc/32000
                    tlc_h = CEIL(lf/16)
                    tlc_t = tlc_l
                    sfy_h = tlc_h/32000
                    sfy_t = tlc_t/32000 'sfy
                    postmessage hwndc, %WM_COMMAND, 5001, 0           'update y scrollbar
                  
                    GLOBALMEM FREE  smemh1 TO smemh1
                    postmessage hwndmain, %WM_USER + 1000, 0, 10        'show we are done (lparam=10)
                  
                  
                  '***********************************************************************************************
                  '   QueryPerformanceCounter   qStop
                  '   ? FORMAT$(1000*(qStop-qStart)/qFreq,"###,###.00") & " milliseconds   "
                  '***********************************************************************************************
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  THREAD FUNCTION do_find(BYVAL flag AS DWORD PTR) AS LONG
                  '***********************************************************************************************
                  ' scan file (f$) for fnd$ in portions of %partsize (case insensitive), save positions found
                  ' ff() holds fileoffsets of found locations (zerobased, ff(0)=first location, 0=first byte
                  ' in file, fc = found count (0=no results, 2=two results found)
                  '***********************************************************************************************
                  LOCAL i      AS LONG
                  LOCAL n      AS LONG                                  '# of estimated parts
                  LOCAL z      AS LONG
                  LOCAL hfile  AS DWORD                                 'handle of file
                  LOCAL lf     AS QUAD                                  'lenght of file
                  LOCAL fmax   AS DWORD
                  LOCAL c1     AS LONG
                  LOCAL ufnd$
                  
                  REGISTER c AS LONG
                  REGISTER x AS LONG
                  
                  
                    hFile = CreateFile(BYVAL STRPTR(f$), %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0, _
                                       %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, BYVAL 0)
                  
                    IF hFile = %INVALID_HANDLE_VALUE THEN
                    END IF
                  
                  
                    getfilesizeex(hfile, lf)                            'total lenght of file
                    n = lf/%partsize + 1                                '# of read operations needed
                                                                        'found max
                    fmax=%max_find
                    REDIM ff(fmax)
                  
                  
                    smeml1=%partsize+LEN(fnd$)+100
                    GLOBALMEM ALLOC smeml1 TO smemh1                    'allocate memory for scanning
                    GLOBALMEM LOCK  smemh1 TO smemb1
                  
                  
                    ufnd$ = UCASE$(fnd$)
                    fc    = 0                                           'found count
                    c     = ASC(fnd$)                                   'first find char
                    c1    = ASC(ufnd$)                                  'first find char (uppercase)
                  
                    FOR i=1 TO n
                      IF @flag<>0 THEN
                        GLOBALMEM FREE  smemh1 TO smemh1
                        EXIT FUNCTION
                      END IF
                  
                      readfile(hfile, BYVAL smemb1, BYVAL %partsize+LEN(fnd$), z, BYVAL 0) 'read
                  
                      POKE$ smemb1+z, CHR$(0,0,0,0)                     'put &H00000000 at the end of each part read
                      IF i<n THEN                                       'skip last iteration
                        z=z-LEN(fnd$)                                   'because in last loop we want to process all chars read
                      END IF
                      IF z <= 0 THEN EXIT FOR
                  
                      REDIM char(z-1) AS BYTE AT smemb1                 'define byte array
                      FOR x = 0 TO z-1                                  'scan char for char
                        IF char(x) = c THEN                             'if found
                          GOTO found
                        ELSEIF char(x) = c1 THEN                        'if found
                  found:
                          IF UCASE$(PEEK$(smemb1+x, LEN(fnd$)))=ufnd$ THEN       'check for (multibyte) fnd$
                            ff(fc) = (i-1)*%partsize+x                  'save found pos
                            INCR fc
                            IF fc MOD %max_find = 0 THEN
                              IF MSGBOX(" There are already "+FORMAT$(fc)+" hits "+$CRLF+"Continue ?", _
                                        %MB_YESNO OR %MB_ICONQUESTION, " Search") = %IDYES THEN
                                fmax=fmax+%max_find
                                REDIM PRESERVE ff(fmax)
                              ELSE
                                GOTO done
                              END IF
                            END IF
                          END IF
                        END IF
                      NEXT
                  
                      postmessage hwndmain, %WM_USER + 1000, i*10000/n, 1                   'find progress message (lparam=1)
                      setfilepointerex hfile, LEN(fnd$)*-1, BYVAL 0, %File_Current
                  
                    NEXT i
                  
                  
                  done:
                    CloseHandle hfile
                  
                  
                    GLOBALMEM FREE  smemh1 TO smemh1
                    postmessage hwndmain, %WM_USER + 1000, 0, 11        'show we are done (lparam=11)
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  SUB editbox (flag AS LONG)
                  '***********************************************************************************************
                  ' enter line # for goto, fill in text for find, show inside statusbar, use different colors
                  ' for goto and find, animate searching
                  '***********************************************************************************************
                  LOCAL n1       AS DOUBLE
                  LOCAL r        AS rect
                  LOCAL s        AS sizel
                  LOCAL s1       AS sizel
                  LOCAL hdc      AS LONG
                  LOCAL nstyle   AS LONG
                  LOCAL ztext    AS ASCIIZ * 256
                  
                  
                    IF iswindow(hwnde) THEN destroywindow hwnde
                  
                    hwnde = CreateWindowEx(0, "Edit", BYVAL %NULL, %WS_CHILD OR %WS_BORDER OR %WS_VISIBLE OR %ES_LEFT OR %ES_AUTOHSCROLL, _
                               0, 0, 0, 0, hstatus, 210+flag, hInst, BYVAL 0 )
                  
                    sendmessage hwnde, %WM_Setfont, sendmessage(hstatus, %WM_Getfont, 0, 0), -1
                  
                    sendmessage hwnde, %EM_Setmargins, %EC_Leftmargin, 3
                  
                    oldeditproc=getwindowlong(hwnde, %GWL_Wndproc)      'get address of old window procedure
                    CALL setwindowlong(hwnde, %GWL_Wndproc, CODEPTR(neweditproc))           'subclass
                  
                    oldstatusproc=getwindowlong(hstatus, %GWL_Wndproc)  'get address of old window procedure
                    CALL setwindowlong(hstatus, %GWL_Wndproc, CODEPTR(newstatusproc))       'subclass
                  
                  
                    IF flag=0 THEN                                      'goto
                      n1 = INT(LOG10(tlc))+ 5
                      sendmessage hwnde, %EM_Setlimittext, n1, 0
                      IF hexflag=1 THEN
                        ztext = "  Goto Position (0x0 - 0x"+HEX$(p(pc))+") :  "
                      ELSE
                        ztext = "  Goto Line (1 -"+STR$(tlc)+") :  "
                      END IF
                  
                    ELSEIF flag = 1 THEN                                'find
                      ztext = "  Find :  "
                      IF LEN(fnd$) THEN
                        setwindowtext hwnde, BYVAL STRPTR(fnd$)
                        sendmessage hwnde, %EM_Setsel, 0, -1
                      END IF
                    ELSEIF flag = 2 THEN                                'ascii
                      ztext = "  Ascii Delimiter :  "
                    ELSEIF flag = 3 THEN                                'hex
                      ztext = "  Hex Delimter :  "
                    END IF
                  
                    sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(ztext)
                    sendmessage hstatus, %SB_Getrect, 1, VARPTR(r)      'get to draw in
                    sendmessage hstatus, %WM_USER+1000, 0, 0            'make backcolor
                  
                    hdc=getdc(hstatus)                                  'get hdc
                    selectobject hdc, sendmessage(hstatus, %WM_Getfont, 0, 0)
                                                                        'select font into dc
                    CALL gettextextentpoint32(hdc,ztext,LEN(ztext),s)   'get appropriate width for text
                  
                    IF flag=0 THEN                                      'goto
                      ztext=REPEAT$(n1+1, "0")
                      CALL gettextextentpoint32(hdc,ztext,LEN(ztext),s1)                    'get appropriate width edit box
                      SetWindowPos hwnde, %NULL, r.nLeft + s.cx, r.nTop + 2, MIN(s1.cx + 8, r.nright-r.nleft - s.cx -4), r.nbottom - r.ntop - 4, _
                                 %SWP_NOZORDER OR %SWP_SHOWWINDOW
                  
                    ELSE                                                'find, Ascii, Hex
                      SetWindowPos hwnde, %NULL, r.nLeft + s.cx, r.nTop + 2, r.nright-r.nleft - s.cx -4, r.nbottom - r.ntop - 4, _
                                 %SWP_NOZORDER OR %SWP_SHOWWINDOW
                    END IF
                  
                    CALL releasedc(hstatus, hdc)                        'free resources
                    setfocus hwnde
                  
                  
                  END SUB
                  
                  
                  '***********************************************************************************************
                  
                  
                  FUNCTION newstatusproc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                                     BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                  '***********************************************************************************************
                  'subclass of statusbar, give editbox a different color for goto and find
                  '***********************************************************************************************
                  STATIC backbrush AS DWORD
                  STATIC backcolor AS DWORD
                  
                  
                    SELECT CASE wMsg
                      CASE %WM_USER+1000
                        IF getdlgctrlid(hwnde) = 210 THEN               'goto
                          backcolor = RGB(200,200,255)
                          backbrush=createsolidbrush(backcolor)
                  
                        ELSEIF getdlgctrlid(hwnde) = 211 THEN           'find
                          backcolor = RGB(255,200,200)
                          backbrush=createsolidbrush(backcolor)
                  
                        ELSEIF getdlgctrlid(hwnde) > 211 THEN           'ascii, Hex
                          backcolor = RGB(210,210,210)
                          backbrush=createsolidbrush(backcolor)
                        END IF
                  
                  
                      CASE %WM_CTLCOLOREDIT                             'make non standart backcolor
                        setbkcolor wparam, backcolor
                        FUNCTION = backbrush
                        EXIT FUNCTION
                  
                  
                      CASE %WM_DESTROY
                        deleteobject backbrush
                  
                    END SELECT
                  
                  
                    FUNCTION=callwindowproc(oldstatusproc, hwnd, wmsg, wparam, lparam)
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  
                  
                  FUNCTION neweditproc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                                     BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                  '***********************************************************************************************
                  ' subclass of edit in statusbar, catch ESC and ENTER key, close if editbox loses focus
                  '***********************************************************************************************
                  LOCAL n       AS LONG
                  LOCAL ztext   AS STRING
                  LOCAL hthread AS DWORD
                  LOCAL d$
                  
                  STATIC q      AS QUAD
                  STATIC etext  AS STRING
                  
                  
                    SELECT CASE wmsg
                      CASE %WM_KILLFOCUS                                'lost foucus -> destroy
                  nep:
                        CALL setwindowlong(hstatus, %GWL_Wndproc, oldstatusproc) 'reset subclass
                        destroywindow hwnd
                        ztext = "  Ready"
                        sendmessage hstatus, %SB_SETTEXT, 1, STRPTR(ztext)
                        setfocus hwndc
                  
                  
                      CASE %WM_CHAR
                        IF wparam = 27 THEN                             'ESC key -> exit
                          GOTO nep
                        ELSEIF wparam = 13 THEN                         'ENTER key -> finish entry
                          n=sendmessage(hwnde, %WM_GETTEXTLENGTH, 0, 0)+1                   '+1, adjust for terminating null char
                          etext=SPACE$(n)                               'prepare string buffer
                          getwindowtext hwnd, BYVAL STRPTR(etext), n
                  
                  
                          IF getdlgctrlid(hwnd) = 210 THEN              'goto line
                            d$=EXTRACT$(etext, CHR$(0))
                            IF LEN(d$) THEN                             'if valid
                              IF LEFT$(TRIM$(d$), 2) = "0x" THEN        'hex input
                                d$=MID$(TRIM$(d$), 3)                   'cut "0x"
                  
                                d$="0"+d$                               'fill in leading zero (to make "val" results unsigned)
                                d$=UCASE$(d$)
                                IF TALLY(d$, ANY "1234567890ABCDEF") = LEN(d$) THEN         'if only valid hex characters
                                  q = VAL("&H"+d$)+1
                                ELSE
                                  GOTO newedit_find
                                END IF
                              ELSE
                                q = VAL(d$)
                              END IF
                            END IF
                  
                            IF hexflag=1 THEN
                              q = INT(q/16)+1                           'make it a line #
                            END IF
                  
                            IF q>0 AND q<=tlc THEN                      'if a valid entry
                              postmessage hwndc, %WM_COMMAND, %IDM_GOTO, VARPTR(q)          'goto this line
                              GOTO nep
                            ELSE                                        'invalid
                              MessageBeep &HFFFFFFFF
                              sendmessage hwnde, %EM_Setsel, 0, -1
                            END IF
                  
                  
                          ELSEIF getdlgctrlid(hwnd) = 211 THEN          'find
                            d$=EXTRACT$(etext, CHR$(0))
                            IF LEN(d$) THEN                             'if valid
                              IF LEFT$(TRIM$(d$), 2) = "0x" THEN        'hex input
                                d$=MID$(TRIM$(d$), 3)                   'cut "0x"
                  
                                IF LEN(d$) MOD 2 <> 0 THEN d$="0"+d$    'fill in leading zero
                                d$=UCASE$(d$)
                                IF TALLY(d$, ANY "1234567890ABCDEF") = LEN(d$) THEN         'if only valid hex characters
                                  fnd$ = ""
                                  FOR n=1 TO LEN(d$) STEP 2
                                    fnd$ = fnd$ + CHR$(VAL("&H"+MID$(d$, n, 2)))
                                  NEXT n
                                ELSE
                                  GOTO newedit_find
                                END IF
                              ELSE
                                fnd$=d$
                              END IF
                  
                              enablemenuitem (getmenu(hwndmain), %IDM_FIND, %MF_GRAYED)
                              enablemenuitem (getmenu(hwndmain), %IDM_FINDNEXT, %MF_GRAYED)
                              enablemenuitem (getmenu(hwndmain), %IDM_FINDPREV, %MF_GRAYED)
                  
                              postmessage hwndmain, %WM_COMMAND, 5100, 0
                              GOTO nep
                            ELSE                                        'invalid
                  newedit_find:
                              MessageBeep &HFFFFFFFF
                              sendmessage hwnde, %EM_Setsel, 0, -1
                            END IF
                  
                          ELSEIF getdlgctrlid(hwnd) = 212 THEN          'Ascii
                            d$=EXTRACT$(etext, CHR$(0))
                            IF LEN(d$) THEN                             'if valid
                              checkmenuItem(getmenu(hwndmain), %IDM_CRLF, %MF_UNCHECKED)
                              checkmenuItem(getmenu(hwndmain), %IDM_CR, %MF_UNCHECKED)
                              checkmenuItem(getmenu(hwndmain), %IDM_LF, %MF_UNCHECKED)
                              checkmenuItem(getmenu(hwndmain), %IDM_HEX, %MF_UNCHECKED)
                              modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii) "+$TAB+CHR$(34)+d$+CHR$(34)
                              modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex)"
                              checkmenuItem(getmenu(hwndmain), %IDM_ASCII, %MF_CHECKED)
                  
                              delimiter = d$
                  
                              IF f$<>"" THEN
                                IF MSGBOX (" "+CHR$(34)+d$+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                                       "  Apply to current file ?", %MB_ICONQUESTION OR %MB_YESNO, _
                                       " Large File Viewer") = %IDYES THEN
                                  postmessage hwndmain, %WM_COMMAND, 5000, 0
                                END IF
                              ELSE
                                MSGBOX " "+CHR$(34)+d$+CHR$(34)+" defined as new delimiter. ", %MB_ICONEXCLAMATION, _
                                       " Large File Viewer"
                              END IF
                  
                              GOTO nep
                            ELSE                                        'invalid
                              MessageBeep &HFFFFFFFF
                              sendmessage hwnde, %EM_Setsel, 0, -1
                            END IF
                  
                  
                          ELSEIF getdlgctrlid(hwnd) = 213 THEN          'Hex
                            d$=EXTRACT$(etext, CHR$(0))
                            IF LEN(d$) THEN                             'if valid
                              IF LEN(d$) MOD 2 <> 0 THEN d$="0"+d$      'fill in leading zero
                              d$=UCASE$(d$)
                              IF TALLY(d$, ANY "1234567890ABCDEF") = LEN(d$) THEN           'if only valid hex characters
                                checkmenuItem(getmenu(hwndmain), %IDM_CRLF, %MF_UNCHECKED)
                                checkmenuItem(getmenu(hwndmain), %IDM_CR, %MF_UNCHECKED)
                                checkmenuItem(getmenu(hwndmain), %IDM_LF, %MF_UNCHECKED)
                                checkmenuItem(getmenu(hwndmain), %IDM_ASCII, %MF_UNCHECKED)
                                modifymenu getmenu(hwndmain), %IDM_ASCII, %MF_Bycommand, %IDM_ASCII, "Userdefined (Ascii)"
                                modifymenu getmenu(hwndmain), %IDM_HEX, %MF_Bycommand, %IDM_HEX, "Userdefined (Hex) "+$TAB+CHR$(34)+d$+CHR$(34)
                                checkmenuItem(getmenu(hwndmain), %IDM_HEX, %MF_CHECKED)
                  
                                delimiter = ""
                                FOR n=1 TO LEN(d$) STEP 2
                                  delimiter = delimiter + CHR$(VAL("&H"+MID$(d$, n, 2)))
                                NEXT n
                  
                                IF f$<>"" THEN
                                  IF MSGBOX (" "+CHR$(34)+d$+CHR$(34)+" defined as new delimiter. "+$CRLF+_
                                         "  Apply to current file ?", %MB_ICONQUESTION OR %MB_YESNO, _
                                         " Large File Viewer") = %IDYES THEN
                                    postmessage hwndmain, %WM_COMMAND, 5000, 0
                                  END IF
                                ELSE
                                  MSGBOX " "+CHR$(34)+d$+CHR$(34)+" defined as new delimiter. ", %MB_ICONEXCLAMATION, _
                                         " Large File Viewer"
                                END IF
                  
                                GOTO nep
                              ELSE                                      'invalid
                                MessageBeep &HFFFFFFFF
                                sendmessage hwnde, %EM_Setsel, 0, -1
                              END IF
                            END IF
                          END IF
                        END IF
                  
                  
                    END SELECT
                  
                  
                    FUNCTION=callwindowproc(oldeditproc, hwnd, wmsg, wparam, lparam)
                  
                  
                  END FUNCTION
                  
                  
                  '***********************************************************************************************
                  '***********************************************************************************************
                  '***********************************************************************************************

                  .rc + icons -> see attachment


                  JK
                  Attached Files
                  Last edited by Juergen Kuehlwein; 9 Jan 2014, 03:01 PM.

                  Comment


                  • #10
                    Version 2.6 with drag and drop support, you may drop multiple files, but only the first in list will be opened


                    JK


                    fileviewer.zip

                    Comment


                    • #11
                      Well done Juergen

                      Comment


                      • #12
                        Juergen,
                        May we modify anything and recompile or do you retain the 2013 copyright?
                        No comments link.
                        Great work!
                        https://duckduckgo.com instead of google

                        Comment


                        • #13
                          Mike,

                          you may do what ever you wish except for making money with these sources or executables compiled from these sources - that is you must not sell it or derivatives. If you need it for private or educational purposes or if you think it could be useful as a tool at work, then do as you please.


                          JK

                          Comment


                          • #14
                            COPYRIGHT PROTECTED. Thanks, I won't use it within my software.
                            https://duckduckgo.com instead of google

                            Comment

                            Working...
                            X