         title   TabEdit

         .586
         .model flat, stdcall
         option casemap:none   ; Case sensitive

            include  TabTree.inc

.const

.data
RichEdit       db  'RichEdit20A',0
RichEdDLL      db  'RICHED20.DLL',0
FontNameCN     db  'Courier New',0
FontNameMS     db  'MS Sans Serif',0  ;'Arial',0

PopupMenu      db  'PopupMenu',0
ToolClass      db  'ToolbarWindow32',0
StatClass      db  'msctls_statusbar32',0
TreeClass      db  'SysTreeView32',0
ListClass      db  'SysListView32',0
ButtClass      db  'button',0
StaticClass    db  'static',0
TabClass       db  'SysTabControl32',0
szPart3        db  'Part 3',0

ClassName      db  'TabTree',0
MenuName       db  'MainMenu',0
szAppName      db  'TabTree - ',0
szUntitled     db  '(Untitled)',0

szNull         db  0

szColName      db  'FileName',0
buttxt1        db  'Projects  ',0
buttxt2        db  '   All',0

szLoadPath     db  'L:\MASM32V1\PROGRAMS\AsmEdit\Projects\TabTree\',0
;szLoadPath     db  'C:\Program Files\',0

szError1       db  'The RICHED20.DLL was not found!',0
szError2       db  'The file has been modified.',0Dh,0Ah
               db  'Do you wish to save it?',0
szOpenTitle    db  'Open File',0
szSaveTitle    db  'Save File As',0
szOpened       db  'File size: = ',0
szSaved        db  'File saved size: = ',0
szFilter       db  'All Files',0,'*.*',0,0
szAll          db  '\*.*',0
szRedit        db  'TabEdit',0

FontHeight     dd  -12
FontW          dd  400

hTab           dd  0
hTabSeL        dd  33  dup(0)
TabSelect      dd  0
PathIDs        dd  0

OA             dd  0
SaveAs         dd  1
ViewChk        dd  1
w5             dd  0
SW             dd  0
Test4          dd  0
fmat3          db "%1d",0

szFR           db  'Find And Replace',0
FindEnd        db  'There Are No More Matches.'
               db  0Dh,0Ah
               db  'Would You Like To Restart From The'
TopBot         db  ' Top? '
               db  0
Top            db  ' Top? '
Bot            db  ' Bot? '

.data?
hInst          dd  ?
CommandLine    dd  ?
MainExit       dd  ?
hWnd           dd  ?
hREdDll        dd  ?
hREdit         dd  ?
hWndTool       dd  ?
hWndTool2      dd  ?
hSplitter      dd  ?
hWndStat       dd  ?
hWndTree       dd  ?
hWndList       dd  ?
hImageList     dd  ?
hMenu          dd  ?
hSMenu         dd  ?
hFont          dd  ?
hFontT         dd  ?
lpRichEdit     dd  ?
lpSplitter     dd  ?
hDefHeap       dd  ?
hPath          dd  ?
FRFlags        dd  ?
Prev           dd  ?
pBot           dd  ?
pRight         dd  ?
hFRDlg         dd  ?
hSplitBar      dd  ?
Splitter       dd  ?

FontName       db  64  dup(?)
MenuCnt        dd  ?
sbParts        dd  4   dup(?)
pShellMalloc   LPMALLOC ?

PathName       db  256 dup(?)
WorkBuff       db  256 dup(?)
FileName       db  64  dup(?)
CustClrs       dd  16  dup(?)
szFind         db  100 dup(?)
szRep          db  100 dup(?)

;---------- [Structures] ----------
charF2         CHARFORMAT2  <>
tci            TC_ITEM      <?>
nmhdr          NMHDR        <?>
ft             FINDTEXTEX   <>

.code

;===================================================
; Program initialization section
;===================================================
start:
      INVOKE     GetModuleHandle, NULL
         mov     hInst, eax
      INVOKE     GetCommandLine
         mov     CommandLine, eax

      INVOKE     GetProcessHeap
         mov     hDefHeap, eax

        call     InitCommonControls

;---------- [Initialize the Component Object Model(COM) library] ----------
      INVOKE     CoInitialize, 0
        test     eax, eax                    ; Any HRESULT with the MSB (the sign bit) = 1, is an error
          js     Exit

;---------- [Get global IMalloc object] ----------
      INVOKE     SHGetMalloc, addr pShellMalloc
         cmp     eax, E_FAIL
          jz     Shutdown

;---------- [Load the Riched20.dll] ----------
      INVOKE     LoadLibrary, addr RichEdDLL
         mov     hREdDll, eax
      .if !eax
         INVOKE     MessageBox, NULL, addr szError1, addr szAppName, MB_OK or MB_ICONERROR
            jmp     Exit
      .endif

      INVOKE     WinMain, hInst ,NULL, CommandLine, SW_SHOWDEFAULT
         mov     MainExit, eax
      INVOKE     FreeLibrary, hREdDll

;---------- [Release IMalloc Object] ----------
         mov     eax, pShellMalloc
         mov     eax, [eax]
      INVOKE     (IMalloc PTR [eax]).Release, pShellMalloc

Shutdown:    
;---------- [Close the COM library] ----------
      INVOKE     CoUninitialize 

Exit:
      INVOKE     ExitProcess, MainExit

;===================================================
; WinMain procedure
;===================================================
WinMain proc  uses ebx  hinst:DWORD, hPrevInst, CmdLine, CmdShow
LOCAL    wc:WNDCLASSEX
LOCAL    msg:MSG

         mov     wc.cbSize, sizeof WNDCLASSEX
         mov     wc.style, CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW ;CS_BYTEALIGNWINDOW ;CS_HREDRAW or CS_VREDRAW
         mov     wc.lpfnWndProc, offset WndProc
         mov     wc.cbClsExtra, NULL
         mov     wc.cbWndExtra, NULL
        push     hInst
         pop     wc.hInstance
         mov     wc.hbrBackground, COLOR_BTNFACE+1
         mov     wc.lpszMenuName, offset MenuName
         mov     wc.lpszClassName, offset ClassName
      INVOKE     LoadIcon, NULL, IDI_APPLICATION
         mov     wc.hIcon, eax
         mov     wc.hIconSm, eax
      INVOKE     LoadCursor, NULL, IDC_ARROW
         mov     wc.hCursor, eax
      INVOKE     RegisterClassEx, addr wc

;---------- [Center the window] ----------
      INVOKE     GetSystemMetrics, SM_CXSCREEN
         sub     eax, 500
         shr     eax, 1
        push     eax
      INVOKE     GetSystemMetrics, SM_CYSCREEN
         sub     eax, 400
         shr     eax, 1
         pop     ebx

;---------- [Create the Main Window] ----------
      INVOKE     CreateWindowEx, WS_EX_CLIENTEDGE, addr ClassName,\
                 addr szAppName, WS_OVERLAPPEDWINDOW or WS_CLIPCHILDREN or WS_CLIPSIBLINGS,\
                 ebx, eax, 500, 400, NULL, NULL, hInst, NULL
         mov     hWnd, eax

      INVOKE     ShowWindow, hWnd, SW_SHOWNORMAL
      INVOKE     UpdateWindow, hWnd
      INVOKE     GetMenu, hWnd              ; Get the handle to the main menu
         mov     hMenu, eax

;---------- [Message loop] ----------
      .while TRUE
         INVOKE     GetMessage, addr msg, NULL, 0, 0
            .break .if (!eax)
            INVOKE     TranslateMessage, addr msg
            INVOKE     DispatchMessage, addr msg
      .endw
         mov     eax, msg.wParam
         ret
WinMain endp

;===================================================
; WinProc procedure
;===================================================
WndProc proc  uses ebx esi edi  hwnd:DWORD, wMsg, wParam, lParam
LOCAL    lvc:LV_COLUMN
LOCAL    rect:RECT
LOCAL    lf:LOGFONT
LOCAL    charF:CHARFORMAT2
LOCAL    tbb:TBBUTTON
LOCAL    tbab:TBADDBITMAP
LOCAL    dis:DRAWITEMSTRUCT
LOCAL    bSize:DWORD, hTbBmp, hBrush, SavHand, ID, Cnt, Chg, hBitmap
LOCAL    xPos:DWORD, yPos, Wth, Hgt
LOCAL    szBuff[64]:BYTE, szSize[12]
LOCAL    tvis:TV_INSERTSTRUCT

;___________________________________________________________________________________
;---------- [Create the Control(s) and one time stuff] ----------
      .if wMsg == WM_CREATE
         INVOKE     HeapAlloc, hDefHeap, 0, 28160
            mov     hPath, eax
            and     hItem, 0

;---------- [Create the status bar window] ----------
         INVOKE     CreateWindowEx, 0, addr StatClass, 0,\
                    WS_CHILD or WS_BORDER or WS_VISIBLE or SBS_SIZEGRIP,\
                    0, 0, 0, 0, hwnd, 0, hInst, 0  
         .if !eax
;Do message
               jmp     Ret0
         .endif
            mov     hWndStat, eax

;---------- [Create the Toolbar Window] ----------
         INVOKE     CreateWindowEx, 0, addr ToolClass, 0,
                    WS_CHILD or WS_VISIBLE or TBSTYLE_TOOLTIPS or CCS_NOPARENTALIGN or\
                    CCS_NORESIZE or CCS_ADJUSTABLE or TBSTYLE_FLAT or WS_BORDER,\
                    0, -2, 1200, 26, hwnd, 0, hInst, 0
         .if !eax
;Do message
               jmp     Ret0
         .endif
            mov     hWndTool, eax

         INVOKE     LoadBitmap, hInst, 799
            mov     hTbBmp, eax
         INVOKE     SendMessage, hWndTool, TB_BUTTONSTRUCTSIZE, sizeof TBBUTTON, 0
            mov     tbab.hInst, 0
          MOVmd     tbab.nID, hTbBmp
         INVOKE     SendMessage, hWndTool, TB_ADDBITMAP, 16, addr tbab

;---------- [Create the Toolbar structures] ----------
         TBButt     hWndTool, 0, 1001, 0
         TBButt     hWndTool, 1, 1002, 0
         TBButt     hWndTool, 2, 1003, 0
         TBButt     hWndTool, 3, 1005, 0
          TBSep     hWndTool
         TBButt     hWndTool, 4, 1007, 0
         TBButt     hWndTool, 5, 1008, 0
         TBButt     hWndTool, 6, 1009, 0
         TBButt     hWndTool, 7, 1010, 0
         TBButt     hWndTool, 8, 1011, 0
         TBButt     hWndTool, 9, 1012, 0
          TBSep     hWndTool
         TBButt     hWndTool, 10,1018, 0
         TBButt     hWndTool, 11,1019, 0
         TBButt     hWndTool, 12,1020, 0
         TBButt     hWndTool, 13,1021, 0
          TBSep     hWndTool
         TBButt     hWndTool, 15,2001, 0

         INVOKE     InitTreeView, hInst, hwnd
         INVOKE     InitListView, hInst, hwnd

         INVOKE     TreeBranch, addr szLoadPath

;WS_EX_STATICEDGE
; or WS_BORDER  CCS_NODIVIDER or
         INVOKE     CreateWindowEx, WS_EX_STATICEDGE, addr ToolClass, 0,
                    WS_CHILD or WS_VISIBLE or TBSTYLE_TOOLTIPS or CCS_NOPARENTALIGN or CCS_NODIVIDER or\
                    CCS_NORESIZE or CCS_ADJUSTABLE or TBSTYLE_FLAT or TBSTYLE_LIST or WS_BORDER,\
                    0, 311, 121, 18, hwnd, 0, hInst, 0
           test     eax, eax     
             jz     Ret0
            mov     hWndTool2, eax

         INVOKE     SendMessage, hWndTool2, TB_BUTTONSTRUCTSIZE, sizeof TBBUTTON, 0
   
            mov     bSize, 00080000h         ;If Bitmap height is 16
         INVOKE     SendMessage, hWndTool2, TB_SETBITMAPSIZE, 0, bSize

         INVOKE     SendMessage, hWndTool2, TB_ADDSTRING, 0, addr buttxt1
         TBButt     hWndTool2, 0, 1041, eax
          TBSep     hWndTool2
         INVOKE     SendMessage, hWndTool2, TB_ADDSTRING, 0, addr buttxt2
         TBButt     hWndTool2, 0, 1042, eax

;---------- [Get the character format] ----------
            mov     charF2.cbSize, sizeof charF2
         INVOKE     SendMessage, hREdit, EM_GETCHARFORMAT, TRUE, addr charF2
            xor     eax, eax
            mov     eax, FontW
            mov     charF2.wWeight, ax
         INVOKE     lstrcpy, addr FontName, addr FontNameCN

         INVOKE     RtlZeroMemory, addr lf, sizeof lf
         INVOKE     lstrcpy, addr lf.lfFaceName, addr FontName
           push     FontHeight
            pop     lf.lfHeight
            xor     eax, eax
            mov     ax, charF2.wWeight
            mov     lf.lfWeight, eax
            mov     al, charF2.bCharSet
            mov     lf.lfCharSet, al
            mov     al, charF2.bPitchAndFamily
            mov     lf.lfPitchAndFamily, al
         INVOKE     CreateFontIndirect, ADDR lf
            mov     hFont, eax

         INVOKE     lstrcpy, addr lf.lfFaceName, addr FontNameMS
            mov     lf.lfHeight, -8
            mov     lf.lfWeight, 400
         INVOKE     CreateFontIndirect, ADDR lf
            mov     hFontT, eax

         INVOKE     CreateTab, hwnd

         INVOKE     LoadMenu, hInst, addr PopupMenu   
         INVOKE     GetSubMenu, eax, 0
            mov     hSMenu, eax

         INVOKE     GetMenu, hwnd              ; Get the handle to the main menu
         INVOKE     GetSubMenu, eax, 0         ; Get handle to 1st sub menu
         INVOKE     GetMenuItemCount, eax      ; Get count of items in the sub menu
            mov     MenuCnt, eax               ; Menu count for ProcessMRUFiles
            mov     ViewChk, 1
           call     CmdEnableDisable

;___________________________________________________________________________________
;---------- [Move and Size the Control(s)] ----------
      .elseif wMsg == WM_SIZE

;---------- [Size the Statusbar Control] ----------
            mov     eax, lParam       ; Get width
            and     eax, 0ffffh       ; Lowword
            shr     eax, 2            ; /4
            mov     ecx, eax          ; Save factor
            mov     sbParts, eax      ; Make part 1 1/4 the width
            add     eax, ecx
            mov     [sbParts+4], eax  ; and also part2, .. etc
            add     eax, ecx
            mov     [sbParts+8], eax
            mov     [sbParts+12], -1  ; The last part extends to the end
         INVOKE     SendMessage, hWndStat, SB_SETPARTS, 4, addr sbParts
         INVOKE     MoveWindow, hWndStat, 0, 0, 0, 0, TRUE
         INVOKE     SendMessage,  hREdit, WM_GETTEXTLENGTH, 0, 0
         INVOKE     wsprintf, addr szSize, addr fmat3, eax
         INVOKE     lstrcpy, addr szBuff, addr szOpened
         INVOKE     lstrcat, addr szBuff, addr szSize
         INVOKE     SendMessage, hWndStat, SB_SETTEXT, 0, addr szBuff
         INVOKE     SendMessage, hWndStat, SB_SETTEXT, 2, addr szPart3

;---------- [Size the Toolbar Control] ----------
         INVOKE     SendMessage, hWndTool, TB_AUTOSIZE, 0, 0

;---------- [Size the Edit Control] ----------
         INVOKE     GetWindowRect, hWndTool, addr rect ; Rectangle of toolbar
            mov     eax, rect.bottom
            sub     eax, rect.top
           push     eax                  ; Save height of toolbar

         INVOKE     GetWindowRect, hWndStat, addr rect ; Rectangle of statusbar
            mov     eax, rect.bottom
            sub     eax, rect.top        ; eax = height of statusbar

            pop     edx                  ; edx = height of toolbar
            mov     ebx, lParam          ; Width of new client area
            and     ebx, 0ffffh          ; ebx = width
            mov     ecx, lParam
            shr     ecx, 16              ; Height of new client area
            sub     ecx, eax             ; Edit window - height of statusbar
            sub     ecx, edx             ; Edit window - height of toolbar
            sub     edx, 6               ; For border
            add     ecx, 8               ; For border
            mov     xPos, 0
            mov     yPos, edx
            mov     Wth, ebx
            mov     Hgt, ecx

         .if ViewChk
            INVOKE     GetWindowRect, hWndTree, addr rect ; Rectangle of TreeView
               mov     eax, rect.right
               sub     eax, rect.left
            .if Splitter
                  mov     eax, Splitter
            .endif
               mov     xPos, eax
               mov     Splitter, eax
               mov     eax, rect.top
               sub     rect.bottom, eax
               mov     edx, yPos
               mov     ebx, Wth
               mov     ecx, Hgt
              push     xPos
               add     xPos, 1
               sub     ebx, xPos
            INVOKE     MoveWindow, hTab, xPos, yPos, ebx, Hgt, TRUE
            INVOKE     ShowWindow, hWndTree, SW_SHOWDEFAULT
            INVOKE     ShowWindow, hWndList, SW_SHOWDEFAULT
            INVOKE     ShowWindow, hWndTool2, SW_SHOWDEFAULT
               pop     xPos
            INVOKE     MoveWindow, hWndTree, 0, 25, xPos, rect.bottom, TRUE
               mov     ecx, Hgt
               sub     ecx, 125
              push     ecx
            INVOKE     MoveWindow, hWndList, 0, 126, xPos, ecx, TRUE
               pop     ecx
               add     ecx, 126
               mov     edx, xPos
               sub     edx, 2
              push     edx
            INVOKE     MoveWindow, hWndTool2, 0, ecx, edx, 18, TRUE
               pop     edx
               mov     eax, 8
               shl     eax, 16
               shr     edx, 1
               mov     ax, dx
            INVOKE     SendMessage, hWndTool2, TB_SETBUTTONSIZE, 0, eax
               mov     eax, xPos
               sub     eax, 4
            INVOKE     SendMessage, hWndList, LVM_SETCOLUMNWIDTH, 0, eax
            INVOKE     SendMessage, hWndTree, TVM_ENSUREVISIBLE, 0, hItem
         .else
            INVOKE     MoveWindow, hTab, 0, yPos, Wth, Hgt, TRUE
            INVOKE     ShowWindow, hWndTree, SW_HIDE
            INVOKE     ShowWindow, hWndList, SW_HIDE
            INVOKE     ShowWindow, hWndTool2, SW_HIDE
         .endif
         INVOKE     SendMessage, hTab, TCM_GETCURSEL, 0, 0  ; New selected Tab
            mov     TabSelect, eax       ; Save the Tab ID
            mov     ebx, hTabSeL+[eax*4] ; Extract new Tabs handle
            mov     hREdit, ebx
         INVOKE     SendMessage, hTab, TCM_GETITEMRECT, TabSelect, addr rect
            mov     eax, rect.bottom
            sub     eax, rect.top
            add     eax, 7
           push     eax
         INVOKE     GetClientRect, hTab, addr rect
            add     rect.top, 4          ; For border
            pop     eax
            sub     rect.bottom, eax     ; Tab height
          MOVmd     pBot, rect.bottom
          MOVmd     pRight, rect.right
            add     pBot, 20
            mov     eax, Splitter
            add     pRight, eax
            sub     pRight, 6
         INVOKE     MoveWindow, hREdit, 0, rect.top, rect.right, rect.bottom, TRUE
         INVOKE     SetFocus, hREdit

;---------- [For the splitter bar] ----------
      .elseif wMsg == WM_MOUSEMOVE
            mov     eax, lParam
            mov     edx, eax
            and     eax, 0ffffh
            mov     xPos, eax
            shr     edx, 16
            mov     yPos, edx
            mov     edi, pBot
            mov     ecx, Splitter
            mov     edx, Splitter
            sub     ecx, 2
            add     edx, 2
         .if eax < ecx || eax > edx || yPos < 26 || yPos > edi
            .if wParam != MK_LBUTTON
               INVOKE     LoadCursor, 0, IDC_ARROW
               INVOKE     SetCursor, eax
               INVOKE     ReleaseCapture
            .endif
         .else
            INVOKE     LoadCursor, hInst, 899
            INVOKE     SetCursor, eax
            INVOKE     SetCapture, hwnd
         .endif
            mov     edi, pBot
         .if wParam == MK_LBUTTON &&  yPos < edi
            INVOKE     LoadCursor, hInst, 899
            INVOKE     SetCursor, eax
            .if !hSplitBar
               INVOKE     CreateDialogParam, hInst, 4801, hWnd, offset SplitBarProc, 0
            .endif
            INVOKE     GetWindowRect, hWnd, addr rect
               mov     eax, xPos
               mov     Splitter, eax
               add     rect.left, 6
               sub     rect.right, 10
               add     eax, rect.left
               add     rect.left, 4
               mov     xPos, eax
            .if eax > rect. left && eax < rect.right
            INVOKE     GetWindowRect, hREdit, addr rect
               add     rect.top, 3
               mov     eax, rect.top
               add     eax, 3
               sub     rect.bottom, eax
            INVOKE     MoveWindow, hSplitBar, xPos, rect.top, 3, rect.bottom, 1
            .endif
         .endif
;.endif

      .elseif wMsg == WM_LBUTTONUP
         INVOKE     ReleaseCapture
         .if Splitter < 2 || Splitter > 7fffh
               mov     Splitter, 2
         .endif
            mov     eax, pRight
         .if Splitter > eax
               mov     Splitter, eax
         .endif
         INVOKE     LockWindowUpdate, hWnd           ; Lock parent to avoid flicker
         INVOKE     GetClientRect, hWnd, addr rect
            mov     edx, rect.bottom
            shl     edx, 16
            mov     ecx, rect.right
            mov     dx, cx
         INVOKE     SendMessage, hWnd, WM_SIZE, 0, edx
         INVOKE     LockWindowUpdate, 0              ; Unock parent
         INVOKE     SplitBarProc, hSplitBar, WM_COMMAND, IDCANCEL, 0
            and     hSplitBar, 0

;___________________________________________________________________________________
;---------- [Draw the Tabs] ----------
      .elseif wMsg == WM_DRAWITEM
         .if wParam == 702
               mov     esi, lParam
               lea     edi, dis
               mov     ecx, sizeof dis
               rep     movsb
            .if dis.itemID != -1
                  lea     eax, szBuff
                  mov     tci.pszText, eax
                  mov     tci.cchTextMax, sizeof szBuff
               INVOKE     SendMessage, hTab, TCM_GETITEM, dis.itemID, addr tci
               .if dis.itemState == ODS_SELECTED
                  INVOKE     CreateSolidBrush, 00ffffffh
                     mov     hBrush, eax
                  INVOKE     FillRect, dis.hdc, addr dis.rcItem, eax
                  INVOKE     SetTextColor, dis.hdc, 000000ffh
                  INVOKE     SetBkColor, dis.hdc, 00ffffffh
               .else
                  INVOKE     CreateSolidBrush, 00ffff00h
                     mov     hBrush, eax
                  INVOKE     FillRect, dis.hdc, addr dis.rcItem, eax
                  INVOKE     SetTextColor, dis.hdc, 00000000h
                  INVOKE     SetBkColor, dis.hdc, 00ffff00h
               .endif        
               INVOKE     DrawText, dis.hdc, tci.pszText, -1, addr dis.rcItem, DT_CENTER or DT_VCENTER or DT_SINGLELINE
               INVOKE     DeleteObject, hBrush
            .endif
               mov     dis.itemState, ODS_DEFAULT
               mov     dis.hdc, 0
         .endif

;___________________________________________________________________________________
;---------- [Menu select] ----------
      .elseif wMsg == WM_MENUSELECT
           call     CmdEnableDisable

;___________________________________________________________________________________
      .elseif wMsg == WM_NOTIFY
         .if wParam == ID_TREEVIEW
            INVOKE     TreeViewNotify, hWnd, lParam
               jmp     Ret0
         .endif

            mov     ebx, lParam          ; Get pointer to NMHDR
            mov     eax, (NMHDR ptr [ebx]).code
         .if wParam == ID_LISTVIEW
            .if [ebx.NMHDR].code == NM_DBLCLK
               INVOKE     DisplayFileName
                  mov     OA, 1
                  call    OpenFileA
                  jmp     Ret0
            .endif
         .endif

         .if eax == TTN_NEEDTEXT
               mov     eax, (NMHDR ptr [ebx]).idFrom ; Resource id
               mov     ebx, eax
            INVOKE     LoadString, hInst, ebx, addr szBuff, lengthof szBuff
               mov     ebx, lParam                   ; Get the buffer addr
               lea     eax, szBuff
               mov     (TOOLTIPTEXT ptr [ebx]).lpszText, eax
               jmp     Ret0
         .endif

         .if eax == TCN_SELCHANGE
            INVOKE     LockWindowUpdate, hWnd           ; Lock parent to avoid flicker
               mov     eax, TabSelect                   ; Previous selected Tab
               mov     ecx, hTabSeL+[eax*4]             ; Extract previous Tabs handle
            INVOKE     ShowWindow, ecx, SW_HIDE         ; Hide its window
            INVOKE     SendMessage, hTab, TCM_GETCURSEL, 0, 0  ; New selected Tab
               mov     TabSelect, eax                   ; Save the Tab ID
               mov     ecx, hTabSeL+[eax*4]             ; Extract new Tabs handle
               mov     hREdit, ecx

FromClose:
            INVOKE     SendMessage,  hTab, TCM_GETITEM, TabSelect, addr tci
            INVOKE     SetWindowText, hWnd, tci.lParam
            INVOKE     ShowWindow, hREdit, SW_SHOWDEFAULT  ; Show its window
            INVOKE     GetClientRect, hWnd, addr rect
               mov     edx, rect.bottom
               shl     edx, 16
               mov     ecx, rect.right
               mov     dx, cx
            INVOKE     SendMessage, hWnd, WM_SIZE, 0, edx
            INVOKE     LockWindowUpdate, 0              ; Unock parent
            INVOKE     SetFocus, hREdit
              call     CmdEnableDisable
               jmp     Ret0
         .endif
            jmp     DefWin

;___________________________________________________________________________________
;---------- [System and user commands] ----------
      .elseif wMsg == WM_COMMAND
            mov     eax, wParam
           cwde                          ; Only low word contains command
         .if eax == IDM_NEW
               lea     eax, FileName
               mov     tci.pszText, eax                   ; Pointer to string containing tab text
               mov     tci.cchTextMax, sizeof FileName

;---------- [Check to see if blank Window already created] ----------
            INVOKE     SendMessage,  hTab, TCM_GETITEMCOUNT, 0, 0
               mov     Cnt, eax
               mov     ID, 0
            .while (Cnt)
               INVOKE     SendMessage,  hTab, TCM_GETITEM, ID, addr tci
               INVOKE     lstrcpy, addr FileName, tci.pszText
               .if byte ptr FileName == '('
                     mov     eax, ID                      ; Current selected Tab
                   MOVmd     hREdit, hTabSeL+[eax*4]      ; Extract current Tabs handle
                  INVOKE     SendMessage, hREdit, WM_SETTEXT, 0, offset szNull
                  INVOKE     SendMessage, hREdit, EM_SETMODIFY, FALSE, 0
                  INVOKE     SendMessage, hTab, TCM_SETCURSEL, ID, 0
                     mov     nmhdr.code, TCN_SELCHANGE
                     lea     eax, nmhdr
                  INVOKE     SendMessage, hWnd, WM_NOTIFY, 0, eax
                  INVOKE     SetFocus, hREdit
                  .break
               .endif
                  dec     Cnt
                  inc     ID
            .endw
            .if !Cnt
                  mov     SW, 3
                 call     NewTab
                  and     SW, 0
               INVOKE     SendMessage, hTab, TCM_SETCURSEL, TabSelect, 0
               INVOKE     SetWindowText, hWnd, addr szAppName
               INVOKE     GetClientRect, hWnd, addr rect
                  mov     edx, rect.bottom
                  shl     edx, 16
                  mov     ecx, rect.right
                  mov     dx, cx
               INVOKE     SendMessage, hWnd, WM_SIZE, 0, edx
               INVOKE     SendMessage, hREdit, EM_SETSEL, 0, 0
            .endif

         .elseif eax == IDM_OPEN
              call     OpenFileA

         .elseif eax == IDM_SAVE
               mov     SaveAs, 0
              call     SaveFile
               mov     SaveAs, 1

         .elseif eax == IDM_SAVEAS
               mov     SaveAs, 1
              call     SaveFile

         .elseif eax == IDM_SAVEALL
               lea     eax, FileName
               mov     tci.pszText, eax                   ; Pointer to string containing tab text
               mov     tci.cchTextMax, sizeof FileName
            INVOKE     SendMessage,  hTab, TCM_GETITEMCOUNT, 0, 0
               mov     Cnt, eax
               mov     ID, 0
            .while (Cnt)
               INVOKE     SendMessage,  hTab, TCM_GETITEM, ID, addr tci
               INVOKE     lstrcpy, addr FileName, tci.pszText
;               .if byte ptr FileName != '('
                  INVOKE     lstrcpy, addr PathName, tci.lParam
                  INVOKE     SendMessage, hTab, TCM_SETCURSEL, ID, 0
                     mov     nmhdr.code, TCN_SELCHANGE
                     lea     eax, nmhdr
                  INVOKE     SendMessage, hWnd, WM_NOTIFY, 0, eax
                     mov     SaveAs, 0
                    call     SaveFile
                     mov     SaveAs, 1
;               .endif
                  inc     ID
                  dec     Cnt
            .endw

         .elseif eax == IDM_PRINT

         .elseif eax == IDM_EXIT
            INVOKE     SendMessage, hwnd, WM_CLOSE, 0 ,0

         .elseif eax == IDM_CUT
            INVOKE     SendMessage, hREdit, WM_CUT, 0 ,0

         .elseif eax == IDM_COPY
            INVOKE     SendMessage, hREdit, WM_COPY, 0 ,0

         .elseif eax == IDM_PASTE
            INVOKE     SendMessage, hREdit, WM_PASTE, 0 ,0

         .elseif eax == IDM_DEL
            INVOKE     SendMessage, hREdit, WM_CLEAR, 0 ,0

         .elseif eax == IDM_UNDO
            INVOKE     SendMessage, hREdit, EM_GETMODIFY, 0, 0
               mov     Chg, eax
            INVOKE     SendMessage, hREdit, WM_UNDO, 0, 0
            INVOKE     SendMessage, hREdit, EM_SETMODIFY, Chg, 0

         .elseif eax == IDM_REDO
            INVOKE     SendMessage, hREdit, EM_GETMODIFY, 0, 0
               mov     Chg, eax
            INVOKE     SendMessage, hREdit, EM_REDO, 0, 0
            INVOKE     SendMessage, hREdit, EM_SETMODIFY, Chg, 0

         .elseif eax == IDM_SELALL
            INVOKE     SendMessage, hREdit, EM_SETSEL, 0, -1

         .elseif eax == IDM_VIEW
            INVOKE     CheckMenuItem, hMenu, IDM_VIEW, MF_BYCOMMAND
            .if eax == MF_CHECKED
                  and     ViewChk, 0
            .else
                  mov     ViewChk, 1
            .endif
              call     CmdEnableDisable
            INVOKE     LockWindowUpdate, hWnd        ; Lock parent to avoid flicker
            INVOKE     GetClientRect, hWnd, addr rect
               mov     edx, rect.bottom
               shl     edx, 16
               mov     ecx, rect.right
               mov     dx, cx
            INVOKE     SendMessage, hWnd, WM_SIZE, 0, edx
            INVOKE     LockWindowUpdate, 0           ; Unock parent

         .elseif eax == IDM_CHOOSEF
              call     Font

         .elseif eax == IDM_CHOOSEC
              call     Color

         .elseif eax == IDM_BACKGRN
               mov     SW, 4
              call     Color
               and     SW, 0

         .elseif eax == IDM_FIND
            INVOKE     SendMessage, hREdit, EM_GETSELTEXT, 0, addr szFind
            INVOKE     CreateDialogParam, hInst, 4901, hwnd, addr FindReplace, 0
               cmp     eax, 0            ; Canceled?
                je     Ret0              ; yes, then return
            INVOKE     SetDlgItemText, hFRDlg, 101, addr szFind

         .elseif eax == IDM_FINDN || eax == IDM_FINDP
               and     Prev, 0
               mov     FRFlags, 1
               mov     ft.chrg.cpMax, -1
            .if eax == IDM_FINDP
                  mov     Prev, 1
                  and     FRFlags, 0
                  mov     ft.chrg.cpMax, 0
            .endif
            INVOKE     SendMessage, hREdit, EM_GETSELTEXT, 0, addr szFind
              test     eax, eax
                jz     Ret0 
            INVOKE     SendMessage, hREdit, EM_EXGETSEL, 0, addr ft.chrgText
            .if !Prev
                  inc     ft.chrgText.cpMin
            .endif
             MOVmd     ft.chrg.cpMin, ft.chrgText.cpMin
               lea     eax, offset szFind
               mov     ft.lpstrText, eax
            INVOKE     Find, hwnd, 1, FRFlags, ft.lpstrText, Prev

         .elseif eax == IDM_REPLACE
            INVOKE     SendMessage, hREdit, EM_GETSELTEXT, 0, addr szFind
            INVOKE     CreateDialogParam, hInst, 4902, hwnd, addr FindReplace, 0
               cmp     eax, 0            ; Canceled?
                je     Ret0              ; yes, then return
            INVOKE     SetDlgItemText, hFRDlg, 101, addr szFind

;---------- [Delete Tab] ----------
         .elseif eax == IDM_CLOSETAB
               mov     eax, TabSelect                      ; Current selected Tab
             MOVmd     hREdit, hTabSeL+[eax*4]             ; Extract current Tabs handle

            INVOKE     SendMessage, hREdit, EM_GETMODIFY, 0, 0
            .if eax != 0
               INVOKE     MessageBox, NULL, addr szError2, addr szAppName,
                          MB_YESNOCANCEL or MB_ICONEXCLAMATION or MB_SYSTEMMODAL
               .if eax == IDYES
                  INVOKE     SendMessage, hWnd, WM_COMMAND, IDM_SAVE, 0
               .endif
            .endif

            INVOKE     SendMessage,  hTab, TCM_GETITEMCOUNT, 0, 0
               mov     Cnt, eax
            .if eax == 1
                  mov     tci.pszText, offset szUntitled   ; Pointer to string containing tab text
                  mov     tci.cchTextMax, 0
               INVOKE     lstrcpy, tci.lParam, addr szNull
               INVOKE     SendMessage, hTab, TCM_SETITEM, TabSelect, addr tci
               INVOKE     SendMessage, hREdit, WM_SETTEXT, 0, offset szNull
               INVOKE     SendMessage, hREdit, EM_SETMODIFY, FALSE, 0
               INVOKE     SetFocus, hREdit
               INVOKE     SetWindowText, hWnd, addr szAppName

            .else
               INVOKE     LockWindowUpdate, hWnd           ; Lock parent to avoid flicker
                MOVmd     SavHand, hREdit
               INVOKE     DestroyWindow, hREdit
               INVOKE     SendMessage, hTab, TCM_DELETEITEM, TabSelect, 0
                  and     SW, 0
               .if TabSelect
                     dec     TabSelect
               .else
                     mov     SW, 2
               .endif
               INVOKE     SendMessage, hTab, TCM_SETCURSEL, TabSelect, 0
                  mov     eax, TabSelect                   ; Save the Tab ID
               .if SW == 2 ; && Cnt > 2 ;< 3
                     inc     eax
               .endif
                  mov     ecx, hTabSeL+[eax*4]             ; Extract new Tabs handle
                  mov     hREdit, ecx

;---------- [Shift handle left if close] ----------
                  xor     eax, eax
                  mov     ecx, 32
               .while     ecx                              ; Find handle of active window in the array
                     mov     edx, SavHand
                  .if hTabSeL[eax] == edx
                      MOVmd     hTabSeL[eax], hTabSeL[eax+4]
                        add     eax, 4
                        dec     ecx
                     .while     ecx                        ; Shift the array to the left
                         MOVmd     hTabSeL[eax], hTabSeL[eax+4]
                           add     eax, 4
                           dec     ecx
                     .endw
                        .break  
                  .endif
                     add     eax, 4
                     dec     ecx
               .endw
                  jmp     FromClose
            .endif
         .endif
;---------- [End of commands] ----------
EnaDis:
           call     CmdEnableDisable

;___________________________________________________________________________________
;---------- [Shut dowm] ----------
      .elseif wMsg == WM_CLOSE
            lea     eax, FileName
            mov     tci.pszText, eax                ; Pointer to string containing tab text
            mov     tci.cchTextMax, sizeof FileName
         INVOKE     SendMessage,  hTab, TCM_GETITEMCOUNT, 0, 0
            mov     Cnt, eax
            mov     ID, 0
         .while (Cnt)
               mov     eax, ID                      ; Current selected Tab
             MOVmd     hREdit, hTabSeL+[eax*4]      ; Extract current Tabs handle
            INVOKE     SendMessage, hTab, TCM_SETCURSEL, ID, 0
            INVOKE     SendMessage, hREdit, EM_GETMODIFY, 0, 0
            .if eax != 0
               INVOKE     SendMessage,  hTab, TCM_GETITEM, ID, addr tci
               INVOKE     lstrcpy, addr PathName, tci.lParam
                  mov     nmhdr.code, TCN_SELCHANGE
                  lea     eax, nmhdr
               INVOKE     SendMessage, hWnd, WM_NOTIFY, 0, eax
               INVOKE     MessageBox, NULL, addr szError2, addr szAppName,
                          MB_YESNOCANCEL or MB_ICONEXCLAMATION or MB_SYSTEMMODAL
               .if eax == IDYES
                     mov     SaveAs, 0
                    call     SaveFile
                     mov     SaveAs, 1
                  .if eax == IDCANCEL
                        jmp     Ret0
                  .endif
               .elseif eax == IDCANCEL
                     jmp     Ret0
               .endif
            .endif
               inc     ID
               dec     Cnt
         .endw
         INVOKE     DestroyWindow, hwnd

;___________________________________________________________________________________
      .elseif wMsg == WM_DESTROY
         INVOKE     DeleteObject, hTbBmp
         INVOKE     DeleteObject, hImageList
         INVOKE     PostQuitMessage, NULL

      .else

DefWin:
         INVOKE     DefWindowProc, hwnd, wMsg, wParam, lParam
            ret
      .endif

Ret0:
         xor    eax, eax
         ret
WndProc endp

;===============================================
;* SplitBarProc Virtical Sizing Bar PROCEDURE
;===============================================
SplitBarProc PROC    hdlg:DWORD, wmsg, wparam, lparam
         cmp     wmsg, WM_INITDIALOG   ; If message is INITDIALOG then
         jne     NotInit               ; check wmsg
       MOVmd     hSplitBar, hdlg
         jmp     DlgDone

NotInit:
         cmp     wmsg, WM_CTLCOLORDLG
         je      ColorDlg
         cmp     wmsg, WM_COMMAND      ; Is message a WM_COMMAND?
         mov     eax, wparam           ; Otherwise, see if it's OK or CANCEL
         cmp     eax, IDCANCEL         ; that was pressed
         je      CancleIt              ; and if not either of these
         jmp     DlgDone

ColorDlg:
      INVOKE     GetSysColor, COLOR_INFOBK
      INVOKE     CreateSolidBrush, 0
         ret

CancleIt:
      INVOKE     EndDialog, hdlg, wparam
         mov     eax, TRUE             ; Return
         jmp     DlgRet                ; with TRUE
DlgDone:
         mov     eax, FALSE            ; Return with FALSE
DlgRet:
         ret                           ; Return
SplitBarProc ENDP

;===================================================
; SubClass the Edit control procedure
;===================================================
RichEditProc PROC hwnd:DWORD, wmsg, wparam, lparam
LOCAL    rect:RECT

      .if wmsg == WM_RBUTTONDOWN
            jmp     PopUp

      .elseif wmsg == WM_LBUTTONUP || wmsg == WM_KEYUP
           call     CmdEnableDisable
      .endif
         jmp     ThatsAll

PopUp:
        call     CmdEnableDisable
      INVOKE     GetWindowRect, hWnd, addr rect
         mov     ecx, lparam        ; x/y pos of window
         mov     ebx, ecx
         and     ebx, 0000ffffh     ; ebx = LOWORD(lparam) = x pos
         shr     ecx, 16            ; ecx = HIWORD(lparam) = y pos
         add     ebx, rect.left
         add     ecx, rect.top
         add     ebx, 10 
         add     ecx, 70
      INVOKE     TrackPopupMenu, hSMenu, TPM_LEFTALIGN or TPM_LEFTBUTTON,\
                 ebx, ecx, 0, hWnd, addr rect
        jmp      ThatsAll

ThatsAll:
      INVOKE     CallWindowProc, lpRichEdit, hwnd, wmsg, wparam, lparam

         ret
RichEditProc ENDP

;===============================================================
; Open file PROCEDURE
;===============================================================
OpenFileA  PROC
LOCAL    ofn:OPENFILENAME
LOCAL    EditS:EDITSTREAM
LOCAL    rect:RECT
LOCAL    hFile:DWORD, Cnt, ID
LOCAL    szFileName[64]:BYTE


      INVOKE     SendMessage, hREdit, EM_GETMODIFY, 0, 0
      .if eax != 0
         INVOKE     MessageBox, NULL, addr szError2, addr szAppName,
                    MB_YESNOCANCEL or MB_ICONEXCLAMATION or MB_SYSTEMMODAL
         .if eax == IDYES
            INVOKE     SendMessage, hWnd, WM_COMMAND, IDM_SAVE, 0
         .endif
      .endif

      INVOKE     LockWindowUpdate, hWnd           ; Lock parent to avoid flicker

;---------- [Zero out the structures] ----------
      INVOKE     RtlZeroMemory, addr ofn, sizeof ofn
      INVOKE     RtlZeroMemory, addr EditS, sizeof EditS
         cmp     OA, 1
          je     OpenAssoc
         mov     byte ptr PathName, 0

;---------- [Set the OPENFILENAME attributes] ----------
         mov     ofn.lStructSize, sizeof ofn
         mov     eax, hWnd
         mov     ofn.hwndOwner, eax
         mov     eax, hInst
         mov     ofn.hInstance, eax
         mov     ofn.lpstrFilter, offset szFilter
         mov     ofn.lpstrFile, offset PathName
         mov     ofn.nMaxFile, lengthof PathName
         mov     ofn.lpstrFileTitle, offset FileName
         mov     ofn.nMaxFileTitle, lengthof FileName
         mov     ofn.lpstrTitle, offset szOpenTitle
         mov     ofn.Flags, OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST
      INVOKE     GetOpenFileName, addr ofn
      .if !eax                       ; Cancel'ed or error occurred
            jmp     EndOpen
      .endif

OpenAssoc:
      INVOKE     CreateFile, addr PathName,\
                 GENERIC_READ or GENERIC_WRITE ,\
                 FILE_SHARE_READ or FILE_SHARE_WRITE,\
                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL
         cmp     eax, -1             ; Error?
         jne     opcrok

operr:
         jmp     EndOpen

opcrok:
         mov     hFile, eax
         mov     EditS.dwCookie, eax
         mov     EditS.dwError, 0
         mov     EditS.pfnCallback, offset EditStreamRead

         lea     eax, szFileName
         mov     tci.pszText, eax                   ; Pointer to string containing tab text
   mov     tci.cchTextMax, sizeof szFileName
      INVOKE     SendMessage,  hTab, TCM_GETITEMCOUNT, 0, 0
         mov     Cnt, eax
      INVOKE     SendMessage,  hTab, TCM_GETITEM, TabSelect, addr tci
      .if byte ptr szFileName != '(' || byte ptr szFileName == '(' && Cnt > 1

;---------- [Check to see if file already opened] ----------
            mov     ID, 0
         .while (Cnt)
            INVOKE     SendMessage,  hTab, TCM_GETITEM, ID, addr tci
            INVOKE     lstrcmpi, tci.lParam, addr PathName
            .if !eax                                ; Files already opened
               INVOKE     SendMessage, hTab, TCM_SETCURSEL, ID, 0
                  mov     nmhdr.code, TCN_SELCHANGE
                  lea     eax, nmhdr
               INVOKE     SendMessage, hWnd, WM_NOTIFY, 0, eax
                  jmp     EndOpen
            .endif
               inc     ID
               dec     Cnt
         .endw

;---------- [Create a new Tab] ----------
           call     NewTab
         INVOKE     SendMessage, hTab, TCM_SETCURSEL, TabSelect, 0
            jmp     NewWin
      .endif

;---------- [First file] ----------
         mov     tci.pszText, offset FileName       ; Pointer to string containing tab text
         mov     tci.cchTextMax, 0
      INVOKE     lstrcpy, tci.lParam, addr PathName
      INVOKE     SendMessage, hTab, TCM_SETITEM, TabSelect, addr tci

NewWin:
      INVOKE     SendMessage, hREdit, EM_STREAMIN, SF_TEXT, addr EditS
      INVOKE     CloseHandle, hFile
      INVOKE     SetWindowText, hWnd, addr PathName
      INVOKE     SendMessage,  hREdit, EM_SETMODIFY, FALSE, 0

      INVOKE     GetClientRect, hWnd, addr rect
         mov     edx, rect.bottom
         shl     edx, 16
         mov     ecx, rect.right
         mov     dx, cx
      INVOKE     SendMessage, hWnd, WM_SIZE, 0, edx
      INVOKE     SendMessage, hREdit, EM_SETSEL, 0, 0

EndOpen:
         and     OA, 0
      INVOKE     LockWindowUpdate, 0             ; Unlock parent
         ret
OpenFileA  ENDP

;===============================================================
; Edit Stream Read Callback PROCEDURE
;===============================================================
EditStreamRead PROC dwCookie:DWORD, pbBuff, cb, pcb
      INVOKE     ReadFile, dwCookie, pbBuff, cb, pcb, 0
         mov     eax, 0              ; Return 0
         ret
EditStreamRead ENDP

;===============================================================
; Save file PROCEDURE
;===============================================================
SaveFile PROC
LOCAL    ofn:OPENFILENAME
LOCAL    EditS:EDITSTREAM
LOCAL    hFile:DWORD

;---------- [Zero out the structures] ----------
      INVOKE     RtlZeroMemory, addr ofn, sizeof ofn
      INVOKE     RtlZeroMemory, addr EditS, sizeof EditS

      INVOKE     SendMessage,  hREdit, WM_GETTEXTLENGTH, 0, 0
      .if !eax
            jmp     EndSave
      .endif

;---------- [Get the Path and File name from the Tab] ----------
      INVOKE     SendMessage, hTab, TCM_GETCURSEL, 0, 0
      .if eax != -1
            mov     edx, eax
            lea     eax, FileName
            mov     tci.pszText, eax                   ; Pointer to string containing tab text
            mov     tci.cchTextMax, sizeof FileName
         INVOKE     SendMessage,  hTab, TCM_GETITEM, edx, addr tci
      INVOKE     lstrcpy, addr FileName, tci.pszText
         INVOKE     lstrcpy, addr PathName, tci.lParam
      .endif
      .if byte ptr FileName == '('
         INVOKE     GetCurrentDirectory, lengthof PathName, addr PathName
         INVOKE     lstrcat, addr PathName, addr szAll
            mov     SaveAs, 1
      .endif
;      INVOKE     GetWindowText, hWnd, addr PathName, sizeof PathName
      .if !SaveAs
            jmp     SaveIt
      .endif

;---------- [Set the OPENFILENAME attributes] ----------
         mov     ofn.lStructSize, sizeof ofn
         mov     eax, hWnd
         mov     ofn.hwndOwner, eax
         mov     eax, hInst
         mov     ofn.hInstance, eax
         mov     ofn.lpstrFilter, offset szFilter
         mov     ofn.lpstrFile, offset PathName
         mov     ofn.nMaxFile, lengthof PathName
         mov     ofn.lpstrFileTitle, offset FileName
         mov     ofn.nMaxFileTitle, lengthof FileName
         mov     ofn.lpstrTitle, offset szSaveTitle
         mov     ofn.Flags, OFN_OVERWRITEPROMPT or OFN_CREATEPROMPT or\
                 OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST
      INVOKE     GetSaveFileName, addr ofn
      .if !eax                       ; Cancel'ed or error occurred
            mov     eax, IDCANCEL
            jmp     EndSave
      .endif

SaveIt:
      INVOKE     CreateFile, addr PathName,\
                 GENERIC_READ or GENERIC_WRITE ,\
                 FILE_SHARE_READ or FILE_SHARE_WRITE,\
                 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
         cmp     eax, -1             ; Error?
         jne     savcrok

saverr:
         jmp     EndSave

savcrok:
         mov     hFile, eax
         mov     EditS.dwCookie, eax
         mov     EditS.dwError, 0
         mov     EditS.pfnCallback, offset EditStreamWrite

      INVOKE     SendMessage, hREdit, EM_STREAMOUT, SF_TEXT, addr EditS
      INVOKE     CloseHandle, hFile
      INVOKE     SendMessage,  hREdit, EM_SETMODIFY, FALSE, 0

      .if SaveAs
            mov     tci.pszText, offset FileName       ; Pointer to string containing tab text
            mov     tci.cchTextMax, 0
         INVOKE     lstrcpy, tci.lParam, addr PathName
         INVOKE     SendMessage, hTab, TCM_SETITEM, TabSelect, addr tci
         INVOKE     SetWindowText, hWnd, addr PathName
      .endif

EndSave:
         ret
SaveFile ENDP

;===============================================================
; Edit Stream Save Callback PROCEDURE
;===============================================================
EditStreamWrite PROC  dwCookie:DWORD, pbBuff, cb, pcb
      INVOKE     WriteFile, dwCookie, pbBuff, cb, pcb, 0
         mov     eax, 0              ; File completely read
         ret
EditStreamWrite ENDP

;=========================================================================
; Create Tab Control PROCEDURE
;=========================================================================
CreateTab PROC hwnd:DWORD
LOCAL    rect:RECT

      INVOKE     CreateWindowEx, NULL, addr TabClass, NULL,\
                 WS_CHILD or WS_VISIBLE or TCS_BOTTOM or TCS_HOTTRACK or\
                 TCS_FOCUSNEVER or WS_CLIPSIBLINGS or WS_CLIPCHILDREN or TCS_OWNERDRAWFIXED,\
                 0, 0, 0, 0, hwnd, 702, hInst, 0
         mov     hTab, eax

      INVOKE     SendMessage, hTab, WM_SETFONT, hFontT, TRUE
;         mov     ecx, 8
;         mov     cx, 100
;      INVOKE     SendMessage, hTab, TCM_SETITEMSIZE, 0, ecx

;---------- [Set the Tab Control Item structure] ----------
         mov     tci.imask, TCIF_TEXT or TCIF_PARAM   ; Text & Param
         mov     tci.lpReserved1, 0                ; Reserved
         mov     tci.lpReserved2, 0                ; Reserved
         mov     tci.iImage, -1                    ; Index to tab control's image 

         mov     TabSelect, 0
        call     CreateWin
      INVOKE     ShowWindow, hREdit, SW_SHOWDEFAULT

         ret
CreateTab ENDP

;=========================================================================
; Setup for a new Tab PROCEDURE
;=========================================================================
NewTab PROC
LOCAL    rect:RECT

      INVOKE     SendMessage,  hTab, TCM_GETITEMCOUNT, 0, 0
      .if PathIDs > 109 || eax >= 32
; Do Message Max number reached
            ret
      .endif
         mov     eax, TabSelect                   ; Current selected Tab
         mov     ecx, hTabSeL+[eax*4]             ; Extract current Tabs handle
      INVOKE     ShowWindow, ecx, SW_HIDE         ; Hide its window
      INVOKE     SendMessage,  hTab, TCM_GETITEMCOUNT, 0, 0
         mov     TabSelect, eax
        call     CreateWin

         ret
NewTab ENDP

;=========================================================================
; Create the Tab and Edit Control PROCEDURE
;=========================================================================
CreateWin PROC
LOCAL    rect:RECT

         mov     eax, PathIDs                         ; Path ID
        imul     eax, 256
         mov     ecx, hPath
         add     ecx, eax
         mov     tci.lParam, ecx                      ; Path buffer address
         inc     PathIDs

      .if PathIDs == 1 || SW == 3                     ; First time Tab or new blank Window
            mov     tci.pszText, offset szUntitled    ; Pointer to string containing tab text 
            mov     tci.cchTextMax, sizeof szUntitled ; Size of szUntitled
         INVOKE     lstrcpy, tci.lParam, addr szAppName
         INVOKE     SendMessage, hTab, TCM_INSERTITEM, TabSelect, addr tci
      .else
            mov     tci.pszText, offset FileName
            mov     tci.cchTextMax, sizeof FileName
         INVOKE     lstrcpy, tci.lParam, addr PathName
         INVOKE     SendMessage, hTab, TCM_INSERTITEM, TabSelect, addr tci
      .endif

      INVOKE     CreateWindowEx, NULL, addr RichEdit, NULL,\
                 WS_CHILD or WS_VISIBLE or WS_BORDER or ES_MULTILINE or\
                 ES_NOHIDESEL or ES_SAVESEL or ES_SELECTIONBAR or\
                 WS_HSCROLL or ES_AUTOHSCROLL or\
                 WS_VSCROLL or ES_AUTOVSCROLL or WS_CLIPSIBLINGS or WS_CLIPCHILDREN,\
                 0, 0, 0, 0, hTab, 4444, hInst, NULL
         mov     hREdit, eax
         mov     eax, TabSelect
         mov     ecx, hREdit
         mov     hTabSeL+[eax*4], ecx                 ; Save Tabs handle

      INVOKE     SendMessage, hREdit, WM_SETFONT, hFont, TRUE
      INVOKE     SendMessage, hREdit, EM_EXLIMITTEXT, 0, 4000000
      INVOKE     SetFocus, hREdit

;---------- [Control window subclassed] ----------
      INVOKE     SetWindowLong, hREdit, GWL_WNDPROC, RichEditProc
         mov     lpRichEdit, eax
      INVOKE     SendMessage, hTab, TCM_SETCURSEL, TabSelect, 0

         ret
CreateWin ENDP

;==============================================================
; Change Font PROCEDURE
;==============================================================
Font  PROC
LOCAL    lf:LOGFONT
LOCAL    cf:CHOOSEFONT
LOCAL    charF:CHARFORMAT2
LOCAL    Temp:DWORD, Chg

      INVOKE     SendMessage, hREdit, EM_GETMODIFY, 0, 0
         mov     Chg, eax

;---------- [Zero out the structures] ----------
      INVOKE     RtlZeroMemory, addr lf, sizeof lf
      INVOKE     RtlZeroMemory, addr cf, sizeof cf

;---------- [Get the current character format] ----------
         mov     charF.cbSize, sizeof charF
      INVOKE     SendMessage, hREdit, EM_GETCHARFORMAT, TRUE, addr charF
      INVOKE     GetDC, hWnd
        push     eax
      INVOKE     GetDeviceCaps, eax, LOGPIXELSY  ; = 96    eg.
         mov     Temp, eax
         pop     eax
      INVOKE     ReleaseDC, hWnd, eax
         mov     eax, charF.yHeight              ; = 180   eg.
         mul     Temp
         mov     ecx, 1440
         div     ecx
         neg     eax

;---------- [Set the LOGFONT attributes] ----------
         mov     lf.lfHeight, eax                ; = -12   eg.
         mov     lf.lfWeight, FW_NORMAL          ; = 500   eg.
      .if (charF.dwEffects & CFE_BOLD)
            mov     lf.lfWeight, FW_BOLD
      .endif
         mov     lf.lfItalic, FALSE
      .if (charF.dwEffects & CFE_ITALIC)
            mov     lf.lfItalic, TRUE
      .endif
         mov     lf.lfUnderline, FALSE
      .if (charF.dwEffects & CFE_UNDERLINE)
            mov     lf.lfUnderline, TRUE
      .endif
         mov     lf.lfStrikeOut, FALSE
      .if (charF.dwEffects & CFE_STRIKEOUT)
            mov     lf.lfStrikeOut, TRUE
      .endif
         mov     al, charF.bCharSet
         mov     lf.lfCharSet, al
         mov     al, charF.bPitchAndFamily
         mov     lf.lfPitchAndFamily, al
      INVOKE     lstrcpy, addr lf.lfFaceName, addr charF.szFaceName

;---------- [Set the CHOOSEFONT attributes] ----------
         mov     cf.lStructSize, sizeof cf
         mov     eax, hWnd
         mov     cf.hwndOwner, eax
         mov     eax, hInst
         mov     cf.hInstance, eax
         lea     eax, lf
         mov     cf.lpLogFont, eax
         mov     cf.Flags, CF_SCREENFONTS or CF_INITTOLOGFONTSTRUCT or\
                 CF_FORCEFONTEXIST or CF_EFFECTS
         mov     eax, charF.crTextColor
         mov     cf.rgbColors, eax
      INVOKE     ChooseFont, addr cf   ; Invoke common ChooseFont dialog
         cmp     eax, FALSE
          je     FontRet

;---------- [Create a Font] ----------
      INVOKE     CreateFontIndirect, addr lf
         mov     hFont, eax
;      INVOKE     SendMessage, hREdit, WM_SETFONT, hFont, 1

;---------- [Set the CHARFORMAT2 attributes] ----------
         mov     charF.dwMask, 0
         mov     charF.dwEffects, 0
          or     charF.dwMask, CFM_STRIKEOUT or CFM_ITALIC or CFM_UNDERLINE or \
                 CFM_BOLD or CFM_FACE or CFM_SIZE or CFM_COLOR or CFM_WEIGHT
      .if lf.lfStrikeOut
            or     charF.dwEffects, CFE_STRIKEOUT
      .endif
      .if lf.lfItalic
            or     charF.dwEffects, CFE_ITALIC
      .endif
      .if lf.lfUnderline
            or     charF.dwEffects, CFE_UNDERLINE
      .endif
      .if lf.lfWeight == FW_BOLD
            or     charF.dwEffects, CFE_BOLD
      .endif
         mov     eax, cf.iPointSize
         shl     eax, 1                ; Convert from 1/10 pt to twips (which is points*20)
         mov     charF.yHeight, eax
         mov     charF.yOffset, 0
         mov     eax, cf.rgbColors
         mov     charF.crTextColor, eax
         mov     al, lf.lfCharSet
         mov     charF.bCharSet, al
         mov     al, lf.lfPitchAndFamily
         mov     charF.bPitchAndFamily, al
      INVOKE     lstrcpy, addr charF.szFaceName, addr lf.lfFaceName
         mov     charF._wPad2, 0
         mov     eax, lf.lfWeight
         mov     charF.wWeight, ax
         mov     charF.crBackColor, 0

;---------- [Set the character format] ----------
      INVOKE     SendMessage, hREdit, EM_SETCHARFORMAT, SCF_ALL, addr charF

FontRet:
      INVOKE     SendMessage, hREdit, EM_SETMODIFY, Chg, 0
         ret
Font    ENDP

;==============================================================
; Color PROCEDURE
;==============================================================
Color    PROC
LOCAL    cc:CHOOSECOLOR
LOCAL    charF:CHARFORMAT2
LOCAL    Chg:DWORD

      INVOKE     SendMessage, hREdit, EM_GETMODIFY, 0, 0
         mov     Chg, eax

;---------- [Zero out the structure] ----------
      INVOKE     RtlZeroMemory, addr cc, sizeof cc

;---------- [Get the current character format] ----------
         mov     charF.cbSize, sizeof charF
      INVOKE     SendMessage, hREdit, EM_GETCHARFORMAT, TRUE, addr charF
         and     charF.dwEffects, 0fffffffh  ; Turn off AutoColor

;---------- [Set the CHOOSECOLOR attributes] ----------
         mov     cc.lStructSize, sizeof cc
         mov     eax, hWnd
         mov     cc.hwndOwner, eax
         mov     eax, hInst
         mov     cc.hInstance, eax
      .if SW != 4
            mov     eax, charF.crTextColor
      .else
            mov     eax, charF.crBackColor
      .endif
         mov     cc.rgbResult, eax
         mov     cc.lpCustColors, offset CustClrs
         mov     cc.Flags, CC_FULLOPEN or CC_RGBINIT
      INVOKE     ChooseColor, addr cc
         cmp     eax, FALSE                  ; Cancel'ed or error occurred
          je     ColorRet
         mov     eax, cc.rgbResult
      .if SW != 4
            mov     charF.crTextColor, eax
      .else
            mov     charF.crBackColor, eax
         INVOKE     SendMessage, hREdit, EM_SETBKGNDCOLOR, 0, eax
         INVOKE     SendMessage, hREdit, EM_SETCHARFORMAT, SCF_ALL, addr charF
      .endif

;---------- [Set the character format] ----------
      INVOKE     SendMessage, hREdit, EM_SETCHARFORMAT, SCF_ALL, addr charF

ColorRet:
      INVOKE     SendMessage, hREdit, EM_SETMODIFY, Chg, 0
         ret
Color    ENDP

;==============================================================
; Find / Replace PROCEDURE
;==============================================================
FindReplace PROC hdlg:DWORD, wmsg, wparam, lparam

      .if wmsg == WM_INITDIALOG              ; If message is INITDIALOG then
            mov     eax, hdlg
            mov     hFRDlg, eax
         INVOKE     GetDlgItem, hdlg, 101    ; Get handle of edit box
           push     eax                      ; Save handle of edit1
         INVOKE     SetFocus, eax            ; Set focus to this field
            pop     eax
         INVOKE     SendMessage, eax, EM_LIMITTEXT, 100, 0 ; Limit text size
         INVOKE     GetDlgItem, hdlg, 102
         INVOKE     SendMessage, eax, EM_LIMITTEXT, 100, 0 ; Limit text size
         INVOKE     lstrlen, addr szFind
         .if eax == 1 && szFind == ' '
               mov     szFind, 0
         .endif
         INVOKE     SetDlgItemText, hdlg, 101, addr szFind
         INVOKE     SetDlgItemText, hdlg, 102, addr szRep
         INVOKE     GetDlgItem, hdlg, 302    ; Get search down check
         INVOKE     SendMessage, eax, BM_SETCHECK, BST_CHECKED, 0 ; Sets find down to checked
         INVOKE     SendMessage, hREdit, EM_EXGETSEL, 0, addr ft.chrgText
            jmp     FRDone

      .elseif wmsg == WM_COMMAND
         .if wparam == 401 || wparam == 402 || wparam == 403 ; Find - Replace - ReplaceAll
               jmp     FRText
         .elseif wparam == IDCANCEL
               jmp     CloseIt
         .endif
      .endif
         jmp     FRDone

FRText:
         and     FRFlags, 0
      INVOKE     SendMessage, hREdit, EM_EXGETSEL, 0, addr ft.chrgText
      INVOKE     GetDlgItemText, hdlg, 101, addr szFind, 100
        push     ft.chrgText.cpMin
         pop     ft.chrg.cpMin
         mov     ft.chrg.cpMax, -1
         lea     eax, offset szFind
         mov     ft.lpstrText, eax

      .if wparam != 401                   ; Find button
         INVOKE      GetDlgItemText, hdlg, 102, addr szRep, 100
      .endif
      INVOKE     IsDlgButtonChecked, hdlg, 201  ; Whole word
      .if eax
             or     FRFlags, FR_WHOLEWORD
      .endif
      INVOKE     IsDlgButtonChecked, hdlg, 202  ; Match case
      .if eax
             or     FRFlags, FR_MATCHCASE
      .endif
      INVOKE     IsDlgButtonChecked, hdlg, 301  ; Up
      .if eax
            mov     Prev, 1
            mov     ft.chrg.cpMax, 0
      .endif
      INVOKE     IsDlgButtonChecked, hdlg, 302  ; Down
      .if eax
            mov     Prev, 0
             or     FRFlags, FR_DOWN
      .endif
      .if wparam == 401                  ; Find button
         INVOKE     Find, hWnd, 0, FRFlags, ft.lpstrText, Prev
      .endif

Again:
      .if wparam != 401                  ; Find button
         INVOKE     SendMessage, hREdit, EM_REPLACESEL, TRUE, addr szRep
            mov     eax, ft.chrgText.cpMin
            mov     ft.chrgText.cpMax, eax
         INVOKE     lstrlen, addr szRep
            add     ft.chrgText.cpMax, eax
         INVOKE     SendMessage, hREdit, EM_EXSETSEL, 0, addr ft.chrgText
         .if Prev
               sub     ft.chrg.cpMin, 1
         .else
               add     ft.chrg.cpMin, 1
         .endif
         INVOKE     Find, hWnd, 0, FRFlags, ft.lpstrText, Prev
         .if eax != 1
               jmp     FRDone
         .endif 
         .if wparam == 403
               jmp     Again
         .endif
      .endif
         jmp     FRDone

CloseIt:
      INVOKE     EndDialog, hdlg, wparam ; End the dialog with wparam as return
         mov     eax, TRUE               ; Return
         and     hFRDlg, 0
         jmp     FRRet                   ; with TRUE
FRDone:
         mov     eax, FALSE              ; Return with FALSE
FRRet:
         ret                             ; Return
FindReplace  ENDP

;==============================================================
; FindProc returns TRUE or FALSE based on finding FText
;==============================================================
Find    PROC     hwnd:DWORD, Next, Flags, FText, Up

Loop1:
      INVOKE     SendMessage, hREdit, EM_FINDTEXTEX, FRFlags, offset ft
         cmp     eax, -1                 ; Nothing found?
         jne     FoundIt
      .if Up == 0
         INVOKE     lstrcpyn, offset TopBot, offset Top, 6
      .else
         INVOKE     lstrcpyn, offset TopBot, offset Bot, 6
      .endif
      INVOKE     MessageBox, NULL, offset FindEnd, offset szFR, MB_YESNO or\
                 MB_ICONQUESTION or MB_TASKMODAL
         cmp     eax, IDNO
          je     Find0
      .if Up == 0
         INVOKE     SendMessage, hREdit, EM_SETSEL, 0, 0
            mov     ft.chrg.cpMin, 0
            mov     ft.chrg.cpMax, -1
      .else
         INVOKE     SendMessage, hREdit, WM_GETTEXTLENGTH, 0, 0
            mov     ft.chrg.cpMin, eax
            mov     ft.chrg.cpMax, 0
      .endif
         jmp     Loop1

FoundIt:
      .if eax == ft.chrg.cpMin && eax != ft.chrg.cpMax && Up == 0
            inc     ft.chrg.cpMin
            jmp     Loop1
      .endif

      INVOKE     SendMessage, hREdit, EM_EXSETSEL, 0, addr ft.chrgText
         mov     eax, TRUE
         ret

Find0:
        mov     eax, FALSE
        ret
Find    ENDP

;==============================================================
; Enable or disable the items in the edit Menu and Toolbar
;==============================================================
CmdEnableDisable PROC
LOCAL     TempWord:DWORD, SPos, EPos

      INVOKE     SendMessage, hREdit, EM_CANUNDO, 0, 0
         cmp     eax, TRUE
         jne     EdMu1
         mov     TempWord, MF_ENABLED
         jmp     EdMu2
EdMu1:
         mov     TempWord, MF_GRAYED
EdMu2:
      INVOKE     EnableMenuItem, hMenu, IDM_UNDO, TempWord
      INVOKE     EnableMenuItem, hSMenu, IDM_UNDO, TempWord
         xor     TempWord, 1
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_UNDO, TempWord
      INVOKE     SendMessage, hREdit, EM_CANREDO, 0, 0
         cmp     eax, TRUE
         jne     EdMu3
         mov     TempWord, MF_ENABLED
         jmp     EdMu4
EdMu3:
         mov     TempWord, MF_GRAYED
EdMu4:
      INVOKE     EnableMenuItem, hMenu, IDM_REDO, TempWord
      INVOKE     EnableMenuItem, hSMenu, IDM_REDO, TempWord
         xor     TempWord, 1
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_REDO, TempWord
      INVOKE     IsClipboardFormatAvailable, CF_TEXT
         cmp     eax, TRUE
         jne     EdMu5
         mov     TempWord, MF_ENABLED
         jmp     EdMu6
EdMu5:
         mov     TempWord, MF_GRAYED
EdMu6:
      INVOKE     EnableMenuItem, hMenu, IDM_PASTE, TempWord
      INVOKE     EnableMenuItem, hSMenu, IDM_PASTE, TempWord
         xor     TempWord, 1
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_PASTE, TempWord
      INVOKE     SendMessage, hREdit, EM_GETSEL, addr SPos, addr EPos
         mov     eax, SPos
         cmp     eax, EPos         ; If no selection then gray otherwise enable
          je     EdMu7
         mov     TempWord, MF_ENABLED
         jmp     EdMu8
EdMu7:
         mov     TempWord, MF_GRAYED
EdMu8:
      INVOKE     EnableMenuItem, hMenu, IDM_CUT, TempWord
      INVOKE     EnableMenuItem, hSMenu, IDM_CUT, TempWord
      INVOKE     EnableMenuItem, hMenu, IDM_COPY, TempWord
      INVOKE     EnableMenuItem, hSMenu, IDM_COPY, TempWord
      INVOKE     EnableMenuItem, hMenu, IDM_DEL, TempWord
      INVOKE     EnableMenuItem, hSMenu, IDM_DEL, TempWord
      INVOKE     EnableMenuItem, hMenu, IDM_FINDN, TempWord
      INVOKE     EnableMenuItem, hMenu, IDM_FINDP, TempWord

         xor     TempWord, 1
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_CUT, TempWord
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_COPY, TempWord
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_DEL, TempWord
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_FINDN, TempWord
      INVOKE     SendMessage, hWndTool, TB_ENABLEBUTTON, IDM_FINDP, TempWord

      .if ViewChk
         INVOKE     CheckMenuItem, hMenu, IDM_VIEW, MF_CHECKED
      .else
         INVOKE     CheckMenuItem, hMenu, IDM_VIEW, MF_UNCHECKED
      .endif
         ret
CmdEnableDisable ENDP

end start

;INVOKE     MessageBox, NULL, tci.lParam, addr szAppName, MB_OK
