Tutorial 35: Richedit Control: Syntax Hilighting
Before Reading this Tutorial, Let Me Warn You That's A Complicated Subject: NOT SUITED For a Beginner. This is The last in the richedit control tutorials.
Download The Example.
THEORY
Syntax hilighting is a subject of hot debate for those writing text editors. The best method (in my opinion) is to code a custom edit control and this is the approach taken by lots of commercial softwares. However, for those of us who don ' T Have Time for Coding Such Control, The Next Best Thing Is To Adapt The Existing Control To Make It Suit Our NEED.
Let us take a look at what RichEdit control provides to help us in implementing syntax hilighting I should state at this moment that the following method is not the "correct" path:.. I just want to show you the pitfall that many fall for RichEdit control provides EM_SETCHARFORMAT message that you can use to change the color of the text. At first glance, this message seems to be the perfect solution (I know because I was one of the victim). However, a closer examination will show you several things That Are Undesirable:
EM_SETCHARFORMAT only works for a text currently in selection or all text in the control. If you want to change the text color (hilight) a certain word, you must first select it. EM_SETCHARFORMAT is very slow It has a problem with the caret position in The Richedit Control
WITH The Above Discussion, You Can See That Using EM_SETCHARFORMAT IS A WRONG Choice. I'll show you the "relatively correct" choice.
The method I currently use is "syntax hilighting just-in-time". I'll hilight only the visible portion of text. Thus the speed of the hilighting will not be related to the size of the file at all. No matter how large The File, Only A Small Portion of It Is Visible At One Time.how To Do That? The Answer IS Simple:
subclass the richedit control and handle WM_PAINT message within your own window procedure When it receives WM_PAINT message, it calls the original window procedure of the richedit control to let it update the screen as usual. After that, we overwrite the words to be hilighted with different Color
Of Course, The Road is Not That Easy: There Still A Couple of Minor Things To FIX But The Above Method Works Quite Nice Seatisfactory.
Now let's concentrate on the detail. The subclassing process is simple and does not require much attention. The really complicated part is when we have to find a fast way of searching for the words to be hilighted. This is further complicated by the need not To Hilight Any Word Withnin A Comment Block.
The Method I Use May Not Be The Best But IT Works OK. I'm Sure You CAN Find A Faster Way. Anyway, Here IT IS:
I create a 256 dword array, initialized to 0. Each dword corresponds to a possible ASCII character, named ASMSyntaxArray For example, the 21th dword represents the ascii 20h (space) I use them as a fast lookup table:.. For example, if i have the word "include", i'll extract the first character (i) from the word and look up the dword at the corresponding index. If that dword is 0, i know immediately that there is no words to be hilighted starting with "i". If the dword is non-zero, it contains the pointer to the linked list of the WORDINFO structure which contains the information about the word to be hilighted. I read the words to be hilighted and create a WORDINFO structure for each of Them.WordInfo Struct
Wordlen Dd?; The Length of The Word: Used As a Quick Comparison
PSZWORD DD?; Pointer to the Word
PCOLOR DD?; Point To the Dword That Contains The Color Used to Hilite The Word
NEXTLINK DD?; Point to the next WordInfo Structure
WordInfo Ends
As you can see, I use the length of the word as the second quick comparison. If the first character of the word matches, we next compare its length to the available words. Each dword in ASMSyntaxArray contains a pointer to the head of the associated WORDINFO array. For example, the dword that represents the character "i" will contain the pointer to the linked list of the words that begin with "i". pColor member points to the dword that contains the color value used to hilight the word. Pszword Points to the Word To Be Hilighted, in LowerCase.
.
The word list is stored in a file named "wordfile.txt" and I access it with GetPrivateProfileString APIs. I provide as many as 10 different syntax coloring, starting from C1 to C10. The color array is named ASMColorArray. PColor member of each WORDINFO structure points to one of the dwords in ASMColorArray Thus it is easy to change the syntax coloring on the fly:. you just change the dword in ASMColorArray and all words using that color will use the new color immediately.Example
.386
.Model flat, stdcall
Option CaseMAP: NONE
INCLUDE /MASM32/INCLUDE/Windows.inc
INCLUDE /MASM32/INCLUDE/USER32.INC
INCLUDE /MASM32/INCLUDE/COMDLG32.INC
INCLUDE /MASM32/INCLUDE/gdi32.inc
INCLUDE /MASM32/INCLUDE / WANEL32.INC
INCLUDELIB /MASM32/LIB/GDI32.LIB
INCLUDELIB /MASM32/LIB/COMDLG32.LIB
INCLUDELIB /MASM32/LIB/USER32.LIB
INCLUDELIB /MASM32/LIB/kernel32.lib
Winmain Proto: DWORD,: DWORD,: DWORD,: DWORD
WordInfo Struct
Wordlen Dd?; The Length of The Word: Used As a Quick Comparison
PSZWORD DD?; Pointer to the Word
PCOLOR DD?; Point To the Dword That Contains The Color Used to Hilite The Word
NEXTLINK DD?; Point to the next WordInfo Structure
WordInfo Ends
.const
IDR_MAINMENU EQU 101
IDM_Open EQU 40001
IDM_SAVE EQU 40002
IDM_Close EQU 40003
IDM_SAVEAS EQU 40004
IDM_EXIT EQU 40005
IDM_COPY EQU 40006
IDM_CUT EQU 40007
IDM_PASTE EQU 40008
IDM_DELETE EQU 40009
IDM_SELECTALL EQU 40010
IDM_OPTION EQU 40011
IDM_UNDO EQU 40012
IDM_REDO EQU 40013
IDD_OPTIONDLG EQU 101IDC_BACKCOLORBOX EQU 1000
IDC_TextColorBox EQU 1001
IDR_MAINACCEL EQU 105
IDD_FINDDLG EQU 102
IDD_GOTODLG EQU 103
IDD_REPLACEDLG EQU 104
IDC_FindEdit EQU 1000
IDC_MatchCase EQU 1001
IDC_ReplaceEdit EQU 1001
IDC_WholeWord EQU 1002
IDC_DOWN EQU 1003
IDC_UP EQU 1004
IDC_LINENO EQU 1005
IDM_FIND EQU 40014
IDM_FINDNEXT EQU 40015
IDM_REPLACE EQU 40016
IDM_GOTOLINE EQU 40017
IDM_FINDPREV EQU 40018
Richeditid EQU 300
.DATA
ClassName DB "iczeditclass", 0
Appname DB "iczedit Version 3.0", 0
Richeditdll DB "Riched20.dll", 0
Richeditclass DB "Richedit20a", 0
Norichedit DB "Cannot Find Riched20.dll", 0
Asmfilterstring DB "ASM Source Code (* .asm)", 0, "*. ASM", 0
DB "all files (*. *)", 0, "*. *", 0, 0
OpenFileFail DB "Cannot Open THE FILE", 0
Wannasave DB "The Data IN THE CONTOL IS MODIFIED. WANT TO SAVE IT?", 0
FILEOPENED DD FALSE
BackgroundColor DD 0FFFFFFH; Default to White
TextColor DD 0; Default to Black
WordFileName DB "/wordfile.txt" ,0
Asmsection DB "assembly", 0
C1key DB "C1", 0
C2key DB "C2", 0
C3key DB "C3", 0
C4key DB "C4", 0
C5key DB "C5", 0
C6key DB "C6", 0
C7key DB "C7", 0
C8key DB "C8", 0
C9key DB "C9", 0
C10key DB "C10", 0
Zerostring DB 0
ASMCOLORARRAY DD 0FF0000H, 0805F50H, 0FFH, 666F00H, 44F0H, 5F8754H, 4 DUP (0FF0000H) CommentColor DD 808000H
.DATA?
Hinstance DD?
HRICHEDIT DD?
HWNDRICHEDIT DD?
FILENAME DB 256 DUP (?)
AlternateFileName DB 256 DUP (?)
Customcolors DD 16 DUP (?)
FindBuffer DB 256 DUP (?)
ReplaceBuffer DB 256 DUP (?)
UFLAGS DD?
FindText Findtextex <>
ASMSYNTAXARRAY DD 256 DUP (?)
HSEARCH DD?; Handle to The Search / Replace Dialog Box
Haccel DD?
Hmainheap dd?; Heap Handle
OldWndProc DD?
Richeditversion DD?
.code
Start:
MOV BYTE PTR [Findbuffer], 0
MOV BYTE PTR [ReplaceBuffer], 0
Invoke getModuleHandle, NULL
Mov Hinstance, EAX
Invoke Loadlibrary, AddR Richeditdll
.IF EAX! = 0
Mov HrichEdit, EAX
Invoke getProcessHeap
Mov Hmainheap, EAX
Call FillhiliteInfo
Invoke Winmain, Hinstance, 0, 0, SW_SHOWDEFAULT
Invoke Freelibrary, HrichEdit
.lse
Invoke Messagebox, 0, AddR Norichedit, Addr Appname, MB_OK OR MB_ICONERROR
.endif
Invoke EXITPROCESS, EAX
Winmain Proc Hinst: DWORD, HPREVINST: DWORD, CMDLINE: DWORD, CMDSHOW: DWORD
Local WC: WNDCLASSEX
Local MSG: MSG
Local hwnd: DWORD
Mov wc.cbsize, sizeof wndclassex
Mov wc.style, 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_Window 1
Mov wc.lpszMenuname, IDR_MainMenu
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
INVOKE CreateWindowEx, NULL, ADDR ClassName, ADDR AppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULLmov hwnd, eax
Invoke ShowWindow, Hwnd, SW_SHOWNORMAL
Invoke UpdateWindow, HWnd
Invoke loadingAccelerators, Hinstance, IDR_MAINACCEL
Mov Haccel, EAX
.While true
Invoke GetMessage, Addr MSG, 0,0,0
.break .if (! EAX)
Invoke isDialogmessage, HSearch, Addr MSG
.IF EAX == false
Invoke TranslateAccelerator, HWnd, Haccel, Addr MSG
.IF EAX == 0
Invoke TranslateMessage, Addr MSG
Invoke DispatchMessage, Addr MSG
.endif
.endif
.endw
Mov Eax, Msg.wParam
RET
Winmain ENDP
StreamInproc Proc Hfile: DWORD, PBUFFER: DWORD, Numbytes: DWORD, PBYTESREAD: DWORD
Invoke Readfile, Hfile, Pbuffer, Numbytes, Pbytesread, 0
XOR Eax, 1
RET
StreaminProc ENDP
StreamoutProc Proc Hfile: DWORD, PBUFFER: DWORD, Numbytes: DWORD, PBYTESWRITEN: DWORD
Invoke Writefile, Hfile, Pbuffer, Numbytes, Pbyteswritten, 0
XOR Eax, 1
RET
StreamoutProc ENDP
CheckModifyState Proc HWND: DWORD
Invoke SendMessage, Hwndrichedit, EM_GETMODIFY, 0, 0
.IF EAX! = 0
Invoke Messagebox, Hwnd, Addr Wannasave, Addr Appname, MB_YESNOCANCEL
.IF eax == iDYES
Invoke SendMessage, Hwnd, WM_Command, IDM_SAVE, 0
.ELSEIF EAX == Idcancel
Mov Eax, False
RET
.endif
.endif
Mov Eax, True
RET
CheckModifyState Endp
SetColor Proc
Local CFM: CharFormat
Invoke SendMessage, Hwndrichedit, EM_SETBKGNDCOLOR, 0, BackgroundColor
Invoke RTLZERMEMORY, AddR CFM, Sizeof CFM
Mov Cfm.cbsize, Sizeof CFM
Mov cfm.dwmask, cfm_color
Push TextColor
POP cfm.crtextColor
Invoke SendMessage, Hwndrichedit, EM_SETCHARFORMAT, SCF_ALL, ADDR CFM
RET
SetColor ENDP
Optionproc Proc HWND: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
Local CLR: Choosecolor.if umsg == WM_INITDIALOG
.ELSEIF uMSG == WM_COMMAND
Mov Eax, WPARAM
SHR EAX, 16
.IF AX == BN_Clicked
Mov Eax, WPARAM
.IF AX == idcancel
Invoke SendMessage, HWnd, WM_Close, 0, 0
.ELSEIF AX == IDC_BACKCOLORBOX
Invoke RTLZERMEMORY, ADDR CLR, SIZEOF CLR
Mov CLR.LSTRUCTSIZE, SIZEOF CLR
Push hwnd
POP CLR.HWNDOWNER
Push hinstance
POP CLR.HINSTANCE
Push Backgroundcolor
POP CLR.RGBRESULT
Mov CLR.LPCustColors, Offset Customcolors
Mov CLR.FLAGS, CC_Anycolor or CC_RGBINIT
Invoke Choosecolor, AddR CLR
.IF EAX! = 0
Push CLR.RGBRESULT
Pop BackgroundColor
Invoke getdlgitem, hwnd, idc_backcolorbox
Invoke InvalidateERECT, EAX, 0, TRUE
.endif
.ELSEIF AX == IDC_TextColorBox
Invoke RTLZERMEMORY, ADDR CLR, SIZEOF CLR
Mov CLR.LSTRUCTSIZE, SIZEOF CLR
Push hwnd
POP CLR.HWNDOWNER
Push hinstance
POP CLR.HINSTANCE
Push TextColor
POP CLR.RGBRESULT
Mov CLR.LPCustColors, Offset Customcolors
Mov CLR.FLAGS, CC_Anycolor or CC_RGBINIT
Invoke Choosecolor, AddR CLR
.IF EAX! = 0
Push CLR.RGBRESULT
Pop TextColor
Invoke getdlgitem, hwnd, idc_textcolorbox
Invoke InvalidateERECT, EAX, 0, TRUE
.endif
.ELSEIF AX == IDOK
Invoke SendMessage, Hwndrichedit, EM_GETMODIFY, 0, 0
Push EAX
Invoke setColor
POP EAX
Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, EAX, 0
Invoke EndDialog, HWND, 0
.endif
.endif
.ELSEIF uMSG == WM_CTLCOLORSTATIC
Invoke getdlgitem, hwnd, idc_backcolorbox
.IF EAX == LPARAM
Invoke Createsolidbrush, BackgroundColor
RET
.lse
Invoke getdlgitem, hwnd, idc_textcolorbox
.IF EAX == LPARAM
Invoke Createsolidbrush, TextColor
RET
.endif
.endif
Mov Eax, False
RET
.ELSEIF uMSG == WM_Close
Invoke EndDialog, HWND, 0
.lse
Mov Eax, False
RET
.endif
Mov Eax, True
RET
OptionProc ENDP
SearchProc Proc Hwnd: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
.IF uMSG == WM_INITDIALOG
Push hwnd
POP HSEARCH
Invoke CheckRadiobutton, HWnd, IDC_Down, IDC_UP, IDC_DOWN
Invoke Senddlgitemmessage, HWnd, IDC_Findedit, WM_SETTEXT, 0, AddR Findbuffer
.ELSEIF uMSG == WM_COMMAND
Mov Eax, WPARAM
SHR EAX, 16
.IF AX == BN_Clicked
Mov Eax, WPARAM
.IF AX == iDOK
Mov uflags, 0
Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR FindText.chrg
Invoke getdlgitemtext, hwnd, idc_findedit, AddR Findbuffer, Sizeof Findbuffer
.IF EAX! = 0
Invoke isdlgbuttonchecked, hwnd, idc_down
.IF eax == bst_checked
Or uflags, fr_down
Mov Eax, FindText.chrg.cpmin
.IF EAX! = FindText.chrg.cpmax
Push FindText.chrg.cpmax
POP FindText.chrg.cpmin
.endif
MOV Findtext.chrg.cpmax, -1
.lse
MOV Findtext.chrg.cpmax, 0
.endif
Invoke isdlgbuttonchecked, hwnd, idc_matchcase
.IF eax == bst_checked
Or uflags, fr_matchcase
.endif
Invoke isdlgbuttonchecked, hwnd, idc_wholeword
.IF eax == bst_checked
Or uflags, fr_wholeword
.endif
MOV FindText.lpstrText, Offset Findbuffer
Invoke SendMessage, Hwndrichedit, EM_FINDTEXTEX, UFLAGS, AddR Findtext
.IF EAX! = - 1
Invoke SendMessage, HwndrichEdit, EM_EXSETSEL, 0, AddR FindText.chrgtext
.endif
.endif
.ELSEIF AX == IDCANCEL
Invoke SendMessage, HWnd, WM_Close, 0, 0
.lse
Mov Eax, False
RET
.endif
.endif
.ELSEIF uMSG == WM_Close
Mov HSearch, 0
Invoke EndDialog, HWND, 0
.lse
Mov Eax, False
RET
.endif
Mov Eax, True
RET
SearchProc ENDP
ReplaceProc Proc HWND: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
Local setText: SetTextex
.IF uMSG == WM_INITDIALOG
Push hwnd
POP HSEARCH
Invoke setdlgitemtext, hwnd, idc_findedit, addr findbufferinvoke setdlgitemtext, hwnd, idc_replaceedit, addr replacebuffer
.ELSEIF uMSG == WM_COMMAND
Mov Eax, WPARAM
SHR EAX, 16
.IF AX == BN_Clicked
Mov Eax, WPARAM
.IF AX == idcancel
Invoke SendMessage, HWnd, WM_Close, 0, 0
.ELSEIF AX == IDOK
Invoke getdlgitemtext, hwnd, idc_findedit, AddR Findbuffer, Sizeof Findbuffer
Invoke getdlgitemtext, hwnd, idc_replaceEdit, AddR ReplaceBuffer, Sizeof ReplaceBuffer
Mov Findtext.chrg.cpmin, 0
MOV Findtext.chrg.cpmax, -1
MOV FindText.lpstrText, Offset Findbuffer
Mov setText.Flags, ST_SELECTION
MOV setText.codepage, CP_ACP
.While true
Invoke SendMessage, Hwndrichedit, EM_FINDTEXTEX, fr_down, addr findxt
.IF EAX == - 1
.break
.lse
Invoke SendMessage, HwndrichEdit, EM_EXSETSEL, 0, AddR FindText.chrgtext
Invoke SendMessage, Hwndrichedit, EM_SETTEXTEX, ADDR Settext, Addr ReplaceBuffer
.endif
.endw
.endif
.endif
.ELSEIF uMSG == WM_Close
Mov HSearch, 0
Invoke EndDialog, HWND, 0
.lse
Mov Eax, False
RET
.endif
Mov Eax, True
RET
ReplaceProc ENDP
Gotoproc Proc Hwnd: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
LOCAL LINENO: DWORD
Local Chrg: Charrange
.IF uMSG == WM_INITDIALOG
Push hwnd
POP HSEARCH
.ELSEIF uMSG == WM_COMMAND
Mov Eax, WPARAM
SHR EAX, 16
.IF AX == BN_Clicked
Mov Eax, WPARAM
.IF AX == idcancel
Invoke SendMessage, HWnd, WM_Close, 0, 0
.ELSEIF AX == IDOK
Invoke getdlgitemint, hwnd, IDC_LINENO, NULL, FALSE
Mov Lineno, EAX
Invoke SendMessage, Hwndrichedit, EM_GETLINECUNT, 0, 0
.IF EAX> Lineno
Invoke SendMessage, Hwndrichedit, EM_LINEINDEX, LINENO, 0
Invoke SendMessage, Hwndrichedit, EM_SETSEL, EAX, EAX
Invoke setfocus, HWNDRICHEDIT
.endif
.endif
.endif
.ELSEIF uMSG == WM_Closemov HSearch, 0
Invoke EndDialog, HWND, 0
.lse
Mov Eax, False
RET
.endif
Mov Eax, True
RET
Gotoproc ENDP
PrepareEditmenu Proc Hsubmenu: DWORD
Local Chrg: Charrange
Invoke SendMessage, Hwndrichedit, EM_CANPASTE, CF_TEXT, 0
.IF EAX == 0; No Text in the clipboard
Invoke EnableMenuItem, HSubmenu, IDM_Paste, MF_GRAYED
.lse
Invoke EnableMenuItem, HSubmenu, IDM_Paste, MF_ENABLED
.endif
Invoke SendMessage, Hwndrichedit, EM_CANUNDO, 0, 0
.IF EAX == 0
Invoke EnableMenuItem, HSubmenu, IDM_UNDO, MF_GRAYED
.lse
Invoke EnableMenuItem, HSubmenu, IDM_UNDO, MF_ENABLED
.endif
Invoke SendMessage, Hwndrichedit, EM_CANREDO, 0, 0
.IF EAX == 0
Invoke EnableMenuItem, Hsubmenu, IDM_REDO, MF_GRAYED
.lse
Invoke EnableMenuItem, HSubmenu, IDM_REDO, MF_ENABLED
.endif
Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR chrg
Mov Eax, Chrg.cpmin
.IF eax == chrg.cpmax; no current selection
Invoke EnableMenuItem, HSubmenu, IDM_COPY, MF_GRAYED
Invoke EnableMenuItem, HSubmenu, IDM_CUT, MF_GRAYED
Invoke EnablemenuItem, HSubmenu, IDM_DELETE, MF_GRAYED
.lse
Invoke EnableMenuItem, HSubmenu, IDM_COPY, MF_ENABLED
Invoke EnableMenuItem, HSubmenu, IDM_CUT, MF_ENABLED
Invoke EnableMenuItem, HSubmenu, IDM_DELETE, MF_ENABLED
.endif
RET
PrepareEDitMenu ENDP
Parsebuffer Proc Uses Edi ESI HHEAP: DWORD, PBUFFER: DWORD, NSIZE: DWORD, ARRAYOFFSET: DWORD, PARRAY: DWORD
Local buffer [128]: BYTE
Local Inprss: DWORD
Mov Inprogress, False
Lea ESI, Buffer
Mov EDI, PBuffer
Invoke Charlower, EDI
MOV ECX, NSIZE
Searchloop:
OR ECX, ECX
JZ Finished
CMP Byte PTR [EDI], ""
Je endofword
CMP Byte PTR [EDI], 9; TAB
Je endofword
Mov Inprogress, True
Mov Al, Byte Ptr [EDI]
MOV BYTE PTR [ESI], Al
Inc ESI
Skipit:
Inc EDI
Dec ECX
JMP Searchloopendofword:
CMP Inprogress, True
JE WordFound
JMP Skipit
WordFound:
MOV Byte Ptr [ESI], 0
Push ECX
Invoke Heapalloc, Hheap, Heap_Zero_Memory, Sizeof WordInfo
PUSH ESI
Mov ESI, EAX
Assume ESI: PTR WordInfo
Invoke Lstrlen, AddR Buffer
MOV [ESI]. Wordlen, EAX
Push arrayoffset
POP [ESI] .pcolor
INC EAX
Invoke Heapalloc, Hheap, Heap_Zero_Memory, EAX
MOV [ESI] .pszword, EAX
Mov Edx, EAX
Invoke Lstrcpy, EDX, AddR Buffer
Mov Eax, Parray
Movzx EDX, Byte Ptr [Buffer]
SHL EDX, 2; Multiply by 4
Add Eax, EDX
.IF DWORD PTR [EAX] == 0
Mov DWORD PTR [EAX], ESI
.lse
Push DWORD PTR [EAX]
POP [ESI] .NextLink
Mov DWORD PTR [EAX], ESI
.endif
POP ESI
POP ECX
Lea ESI, Buffer
Mov Inprogress, False
JMP Skipit
Finished:
.IF inprogress == true
Invoke Heapalloc, Hheap, Heap_Zero_Memory, Sizeof WordInfo
PUSH ESI
Mov ESI, EAX
Assume ESI: PTR WordInfo
Invoke Lstrlen, AddR Buffer
MOV [ESI]. Wordlen, EAX
Push arrayoffset
POP [ESI] .pcolor
INC EAX
Invoke Heapalloc, Hheap, Heap_Zero_Memory, EAX
MOV [ESI] .pszword, EAX
Mov Edx, EAX
Invoke Lstrcpy, EDX, AddR Buffer
Mov Eax, Parray
Movzx EDX, Byte Ptr [Buffer]
SHL EDX, 2; Multiply by 4
Add Eax, EDX
.IF DWORD PTR [EAX] == 0
Mov DWORD PTR [EAX], ESI
.lse
Push DWORD PTR [EAX]
POP [ESI] .NextLink
Mov DWORD PTR [EAX], ESI
.endif
POP ESI
.endif
RET
ParseBuffer Endp
FillhiliteInfo Proc Uses Edi
Local Buffer [1024]: Byte
Local PTEMP: DWORD
Local Blocksize: DWORD
Invoke RTLZERMEMORY, AddR AsmsyntaxArray, Sizeof AsmsyntaxArray
Invoke GetModuleFileName, Hinstance, Addr Buffer, Sizeof Buffer
Invoke Lstrlen, AddR Buffer
MOV ECX, EAX
Dec ECX
Lea Edi, Buffer
Add Edi, ECX
STD
MOV Al, "/"
Repne scaSB
CLD
Inc EDI
MOV Byte Ptr [EDI], 0
Invoke Lstrcat, AddR Buffer, Addr WordfileNameInvoke GetFileAttributes, AddR Buffer
.IF EAX! = - 1
Mov Blocksize, 1024 * 10
Invoke Heapalloc, Hmainheap, 0, Blocksize
MOV PTEMP, EAX
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C1key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C2key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 4
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, AddR Asmsection, Addr C3key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 8
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C4key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 12
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C5key, Addr Zerostring, Ptemp, Blocksize, Addr Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 16
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C6key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 20
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C7key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 24
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C8key, Addr Zerostring, Ptemp, Blocksize, Addr Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 28
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C9key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer.if Eax! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add EDX, 32
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C10key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
Mov Edx, Offset Asmcolorarray
Add Edx, 36
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
.endif
Invoke HeapFree, Hmainheap, 0, Ptemp
.endif
RET
FillhiliteInfo Endp
NEWRICHEDITPROC PROC HWND: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
Local HDC: DWORD
Local Holdfont: DWord
Local Firstchar: DWORD
Local Rect: RECT
Local TxtRange: TextRange
Local Buffer [1024 * 10]: Byte
Local HRGN: DWORD
Local HoldRGN: DWORD
Local RealRect: Rect
Local Pstring: DWORD
Local Buffersize: DWORD
LOCAL PT: POINT
.IF uMSG == WM_PAINT
Push EDI
PUSH ESI
Invoke hidecaret, hwnd
Invoke CallWindowProc, OldWndProc, Hwnd, UMSG, WPARAM, LPARAM
Push EAX
Mov Edi, Offset AsmsyntaxArray
Invoke getdc, hwnd
MOV HDC, EAX
Invoke setbkmode, hdc, transparent
Invoke SendMessage, Hwnd, EM_GETRECT, 0, AddR Rect
Invoke SendMessage, Hwnd, EM_CHARFROMPOS, 0, ADDR RECT
Invoke SendMessage, HWnd, EM_LINEFROMCHAR, EAX, 0
Invoke SendMessage, Hwnd, EM_LINEINDEX, EAX, 0
Mov txtrange.chrg.cpmin, EAX
Mov firstchar, EAX
Invoke SendMessage, Hwnd, Em_Charfrompos, 0, Addr Rect.right
Mov txtrange.chrg.cpmax, Eaxpush Rect.Left
Pop RealRect.Left
Push Rect.Top
POP realRect.top
Push Rect.right
Pop RealRect.Right
Push Rect.Bottom
Pop RealRect.Bottom
Invoke CreateRectrgn, RealRect.Left, RealRect.top, RealRect.right, RealRect.Bottom
Mov HRGN, EAX
Invoke SelectObject, HDC, HRGN
Mov HoldRGN, EAX
Invoke SetTextColor, HDC, CommentColor
Lea Eax, Buffer
Mov txtrange.lpstrText, EAX
Invoke SendMessage, Hwnd, Em_GettextRange, 0, Addr TxtRange
.IF EAX> 0
MOV ESI, ESI ESI == Size of the Text
Mov buffersize, EAX
Push EDI
Push EBX
Lea Edi, Buffer
Mov Edx, EDI; Used as The Reference Point
MOV ECX, ESI
MOV Al, ";"
ScanMore:
Repne scaSB
Je nextskip
JMP Nomorehit
Nextskip:
Dec Edi
Inc ECX
MOV PSTRING, EDI
MOV EBX, EDI
SUB EBX, EDX
Add ebx, Firstchar
Mov txtrange.chrg.cpmin, EBX
Push EAX
MOV Al, 0DH
Repne scaSB
POP EAX
HilittheComment:
.IF ECX> 0
MOV BYTE PTR [EDI-1], 0
.endif
MOV EBX, EDI
SUB EBX, EDX
Add ebx, Firstchar
Mov txtrange.chrg.cpmax, EBX
Pushhad
Mov Edi, PString
Mov ESI, TXTRANGE.CHRG.CPMAX
Sub ESI, TXTRANGE.CHRG.CPMIN; ESI Contains The Length of the Buffer
MOV EAX, ESI
Push EDI
.while eax> 0
.IF BYTE PTR [EDI] == 9
MOV Byte Ptr [EDI], 0
.endif
Inc EDI
Dec EAX
.endw
POP EDI
.While ESI> 0
.IF BYTE PTR [EDI]! = 0
Invoke Lstrlen, EDI
Push EAX
MOV ECX, EDI
Lea Edx, Buffer
SUB ECX, EDX
Add Ecx, Firstchar
.IF richeditversion == 3
Invoke SendMessage, Hwnd, EM_POSFROMCHAR, AddR Rect, ECX
.lse
Invoke SendMessage, HWnd, EM_POSFROMCHAR, ECX, 0
MOV ECX, EAX
And ECX, 0FFFFH
Mov Rect.Left, ECX
SHR EAX, 16
Mov Rect.Top, EAX
.endif
Invoke DrawText, HDC, EDI, -1, Addr Rect, 0
POP EAX
Add Edi, EAX
SUB ESI, EAX
.lse
Inc EDI
Dec ESI
.endif
.endw
MOV ECX, TXTRANGE.CHRG.CPMAXSUB ECX, TXTRANGE.CHRG.CPMIN
Invoke RTLZERMEMORY, PSTRING, ECX
Popad
.IF ECX> 0
JMP Scanmore
.endif
Nomorehit:
POP EBX
POP EDI
Mov ECX, Buffersize
Lea ESI, Buffer
.While ECX> 0
MOV Al, Byte Ptr [ESI]
.IF AL == "" | | Al == 0DH || Al == "/" || Al == "| || Al ==" "|| Al == "-" || Al == "*" || Al == "&" || Al == "<" || Al == "> || Al ==" = "| Al ==" ( "|| Al ==") "|| Al ==" {"|| al =="} "|| Al ==" ["|| Al =="] "| | Al ==" ^ "| | AL == ":" || Al == 9
MOV Byte Ptr [ESI], 0
.endif
Dec ECX
Inc ESI
.endw
Lea ESI, Buffer
Mov ECX, Buffersize
.While ECX> 0
MOV Al, Byte Ptr [ESI]
.IF AL! = 0
Push ECX
Invoke lstrlen, ESI
Push EAX
Mov Edx, ED; EDX Contains the Length of The String
Movzx Eax, Byte Ptr [ESI]
.IF Al> = "a" && al <= "z"
SUB Al, "a"
Add Al, "A"
.endif
SHL EAX, 2
Add Eax, EDI; EDI Contains the Pointer to the WordInfo Pointer Array
.IF DWORD PTR [EAX]! = 0
MOV Eax, DWORD PTR [EAX]
Assume EAX: PTR WordInfo
.while eax! = 0
.IF EDX == [EAX]. Wordlen
Pushhad
Invoke lstrcmpi, [EAX] .pszword, ESI
.IF EAX == 0
Popad
MOV ECX, ESI
Lea Edx, Buffer
SUB ECX, EDX
Add Ecx, Firstchar
Pushhad
.IF richeditversion == 3
Invoke SendMessage, Hwnd, EM_POSFROMCHAR, AddR Rect, ECX
.lse
Invoke SendMessage, HWnd, EM_POSFROMCHAR, ECX, 0
MOV ECX, EAX
And ECX, 0FFFFH
Mov Rect.Left, ECX
SHR EAX, 16
Mov Rect.Top, EAX
.endif
Popad
Mov Edx, [EAX] .pcolor
Invoke SetTextColor, HDC, DWORD PTR [EDX]
Invoke DrawText, HDC, ESI, -1, Addr Rect, 0
.break
.endif
Popad
.endif
Push [eax] .nextlink
POP EAX
.endw
.endif
POP EAX
POP ECX
Add ESI, ESI
SUB ECX, EAX
.lse
Inc ESI
Dec ECX
.endif
.endw
.endif
Invoke SelectObject, HDC, Holdrgn
Invoke deleteObject, hrgn
Invoke SelectObject, HDC, HoldFont
Invoke ReleaseDC, HWND, HDC
Invoke showcaret, hwnd
POP EAX
POP ESI
POP EDI
RET
.ELSEIF uMSG == WM_Close
Invoke SetWindowlong, HWnd, GWL_Wndproc, OldWndproc
.lse
Invoke CallWindowProc, OldWndProc, Hwnd, UMSG, WPARAM, LPARAM
RET
.endif
NewricHEDITPROC ENDP
WNDPROC PROC HWND: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
LOCAL OFN: OpenFileName
Local buffer [256]: Byte
Local EditStream: EditStream
Local Hfile: DWORD
Local HPOPUP: DWORD
LOCAL PT: POINT
Local Chrg: Charrange
.IF uMSG == WM_CREATE
invoke CreateWindowEx, WS_EX_CLIENTEDGE, addr RichEditClass, 0, WS_CHILD or WS_VISIBLE or ES_MULTILINE or WS_VSCROLL or WS_HSCROLL or ES_NOHIDESEL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, RichEditID, hInstance, 0
Mov hwndrichedit, EAX
Invoke SendMessage, Hwndrichedit, EM_SETTYPOGRAPHYOPTIONS, TO_SIMPLINEBREAK, TO_SIMPLINEBREAK
Invoke SendMessage, HwndrichEdit, EM_GETTYPOGRAPHYOPTIONS, 1, 1
.IF EAX == 0; Means this message is not processed
Mov Richeditversion, 2
.lse
Mov Richeditversion, 3
Invoke SendMessage, HwndrichEdit, Em_seteditStyle, SES_EMULATESYSEDIT, SES_EMULATESYSEDIT
.endif
Invoke SetWindowlong, Hwndrichedit, GWL_WndProc, AddR NewRichEditproc
Mov OldWndProc, EAX
Invoke SendMessage, HwndrichEdit, EM_LIMITTEXT, -1, 0
Invoke setColor
Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0
Invoke sendMessage, hwndrichedit, em_seteventmask, 0, enm_mouseeventsinvoke sendmessage, hwndrichedit, em_emptyundobuffer, 0,0
.ELSEIF uMSG == WM_NOTIFY
PUSH ESI
Mov ESI, LPARAM
Assume ESI: PTR NMHDR
.IF [ESI] .code == en_msgfilter
Assume ESI: PTR MSGFilter
.IF [ESI] .msg == WM_RBUTTONDOWN
Invoke GetMenu, HWND
Invoke GetSubmenu, Eax, 1
MOV HPOPUP, EAX
Invoke PrepareEditmenu, HPOPUP
Mov Edx, [ESI] .lparam
MOV ECX, EDX
And EDX, 0FFFFH
SHR ECX, 16
MOV PT.X, EDX
Mov pt.y, ECX
Invoke Clienttoscreen, Hwnd, Addr Pt
Invoke TRACKPOPUPMENU, HPOPUP, TPM_LEFTALIGN OR TPM_BOTTOMALIGN, PT.X, PT.Y, NULL, HWND, NULL
.endif
.endif
POP ESI
.ELSEIF uMSG == WM_INITMENUPOPUP
Mov Eax, LPARAM
.IF AX == 0; File Menu
.IF fileopened == true; a file is already OPENED
Invoke EnableMenuItem, WPARAM, IDM_OPEN, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_CLOSE, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_SAVE, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_SAVEAS, MF_ENABLED
.lse
Invoke EnableMenuItem, WPARAM, IDM_OPEN, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_CLOSE, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_SAVE, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_SAVEAS, MF_GRAYED
.endif
.ELSEIF AX == 1; Edit Menu
Invoke PrepareEditmenu, WPARAM
.ELSEIF AX == 2; Search Menu Bar
.IF fileopened == TRUE
Invoke EnableMenuItem, WPARAM, IDM_FIND, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_FINDNEXT, MF_ENABED
Invoke EnableMenuItem, WPARAM, IDM_FINDPREV, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_REPLACE, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_GOTOLINE, MF_ENABLED
.lse
Invoke EnableMenuItem, WPARAM, IDM_FIND, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_FINDNEXT, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_FINDPREV, MF_GRAYEDINVOKE ENABLEMENUITEM, WPARAM, IDM_REPLACE, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_GOTOLINE, MF_GRAYED
.endif
.endif
.ELSEIF uMSG == WM_COMMAND
.IF lparam == 0; Menu Commands
Mov Eax, WPARAM
.IF AX == idm_open
Invoke RTLZERMEMORY, ADDR OFN, SIZEOF OFN
Mov ofn.lstructsize, Sizeof off
Push hwnd
POP OFN.HWNDOWNER
Push hinstance
POP OFN.HINSTANCE
Mov off.lpstrfilter, offset asmfilterstring
Mov ofn.lpstrfile, offset filename
MOV BYTE PTR [filename], 0
Mov ofn.nmaxfile, Sizeof FileName
Mov off.flags, OFN_FILEMUSTEXIST or OFN_HIDEREADOSLY OR OFN_PATHMUSTEXIST
Invoke GetopenFileName, Addr OFN
.IF EAX! = 0
Invoke Createfile, Addr FileName, Generic_Read, File_Share_read, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
.IF EAX! = INVALID_HANDLE_VALUE
Mov Hfile, EAX
Mov EditStream.dwcookie, EAX
Mov EditStream.pfncallback, Offset StreamInproc
Invoke SendMessage, Hwndrichedit, EM_STREAMIN, SF_TEXT, ADDR EditStream
Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0
Invoke Closehandle, HFile
Mov FileOpened, True
.lse
Invoke Messagebox, Hwnd, Addr OpenFilefail, Addr Appname, MB_OK OR MB_ICONERROR
.endif
.endif
.ELSEIF AX == IDM_Close
Invoke CheckmodifyState, Hwnd
.IF EAX == True
Invoke setWindowText, Hwndrichedit, 0
Mov FileOpened, False
.endif
.ELSEIF AX == IDM_SAVE
Invoke CreateFile, Addr FileName, Generic_Write, File_Share_read, null, crete_always, file_attribute_normal, 0
.IF EAX! = INVALID_HANDLE_VALUE
@@:
Mov Hfile, EAX
Mov EditStream.dwcookie, EAX
Mov EditStream.pfncallback, Offset streamoutproc
Invoke SendMessage, Hwndrichedit, EM_STREAMOUT, SF_TEXT, AddR EditStream
Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0
Invoke Closehandle, Hfile.ELSE
Invoke Messagebox, Hwnd, Addr OpenFilefail, Addr Appname, MB_OK OR MB_ICONERROR
.endif
.ELSEIF AX == IDM_COPY
Invoke SendMessage, Hwndrichedit, WM_COPY, 0, 0
.ELSEIF AX == IDM_CUT
Invoke SendMessage, Hwndrichedit, WM_CUT, 0, 0
.ELSEIF AX == IDM_PASTE
Invoke SendMessage, Hwndrichedit, WM_Paste, 0,0
.ELSEIF AX == IDM_DELETE
Invoke SendMessage, HwndrichEdit, EM_REPLACESEL, TRUE, 0
.ELSEIF AX == IDM_SELECTALL
Mov chrg.cpmin, 0
Mov chrg.cpmax, -1
Invoke SendMessage, Hwndrichedit, EM_EXSETSEL, 0, AddR chrg
.ELSEIF AX == IDM_UNDO
Invoke SendMessage, Hwndrichedit, EM_UNDO, 0, 0
.ELSEIF AX == IDM_REDO
Invoke SendMessage, Hwndrichedit, EM_REDO, 0, 0
.ELSEIF AX == IDM_OPTION
Invoke Dialogboxparam, Hinstance, IDD_OptionDLG, HWND, Addr Optionproc, 0
.ELSEIF AX == IDM_SAVEAS
Invoke RTLZERMEMORY, ADDR OFN, SIZEOF OFN
Mov ofn.lstructsize, Sizeof off
Push hwnd
POP OFN.HWNDOWNER
Push hinstance
POP OFN.HINSTANCE
Mov off.lpstrfilter, offset asmfilterstring
Mov ofn.lpstrfile, Offset AlternateFileName
MOV BYTE PTR [AlternateFileName], 0
Mov ofn.nmaxfile, Sizeof AlternateFileName
Mov off.flags, OFN_FILEMUSTEXIST or OFN_HIDEREADOSLY OR OFN_PATHMUSTEXIST
Invoke GetsaveFileName, AddR OFN
.IF EAX! = 0
Invoke createfile, addr alternatefilename, generic_write, file_share_read, null, create_always, file_attribute_normal, 0
.IF EAX! = INVALID_HANDLE_VALUE
JMP @B
.endif
.endif
.ELSEIF AX == IDM_FIND
.IF hSearch == 0
Invoke CreateDialogparam, Hinstance, IDd_Findlg, Hwnd, AddR searchProc, 0
.endif
.ELSEIF AX == IDM_REPLACE
.IF hSearch == 0
Invoke CreateDialogparam, Hinstance, IDD_REPLACEDLG, HWND, AddR ReplaceProc, 0
.endif
.ELSEIF AX == idm_gotoline.if hSearch == 0
Invoke CreateDialogparam, Hinstance, IDD_GOTODLG, HWND, Addr gotoproc, 0
.endif
.ELSEIF AX == IDM_FINDNEXT
Invoke Lstrlen, AddR Findbuffer
.IF EAX! = 0
Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR FindText.chrg
Mov Eax, FindText.chrg.cpmin
.IF EAX! = FindText.chrg.cpmax
Push FindText.chrg.cpmax
POP FindText.chrg.cpmin
.endif
MOV Findtext.chrg.cpmax, -1
MOV FindText.lpstrText, Offset Findbuffer
Invoke SendMessage, Hwndrichedit, EM_FINDTEXTEX, fr_down, addr findxt
.IF EAX! = - 1
Invoke SendMessage, HwndrichEdit, EM_EXSETSEL, 0, AddR FindText.chrgtext
.endif
.endif
.ELSEIF AX == IDM_FINDPREV
Invoke Lstrlen, AddR Findbuffer
.IF EAX! = 0
Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR FindText.chrg
MOV Findtext.chrg.cpmax, 0
MOV FindText.lpstrText, Offset Findbuffer
Invoke SendMessage, Hwndrichedit, EM_FINDTEXTEX, 0, AddR Findtext
.IF EAX! = - 1
Invoke SendMessage, HwndrichEdit, EM_EXSETSEL, 0, AddR FindText.chrgtext
.endif
.endif
.ELSEIF AX == IDM_EXIT
Invoke SendMessage, HWnd, WM_Close, 0, 0
.endif
.endif
.ELSEIF uMSG == WM_Close
Invoke CheckmodifyState, Hwnd
.IF EAX == True
Invoke DestroyWindow, HWnd
.endif
.ELSEIF uMSG == WM_SIZE
Mov Eax, LPARAM
Mov Edx, EAX
And Eax, 0FFFFH
SHR EDX, 16
Invoke MoveWindow, Hwndrichedit, 0,0, Eax, EDX, True
.ELSEIF uMSG == WM_DESTROY
Invoke PostquitMessage, NULL
.lse
Invoke DefWindowProc, Hwnd, UMSG, WPARAM, LPARAM
RET
.endif
XOR EAX, EAX
RET
WNDPROC ENDP
End Start
Analysis:
. This is the content.
FillhiliteInfo Proc Uses Edi
Local Buffer [1024]: Byte
Local PTEMP: DWordLocal Blocksize: DWORD
Invoke RTLZERMEMORY, AddR AsmsyntaxArray, Sizeof AsmsyntaxArray
Initialize asmsyntaxArray to zero.
Invoke GetModuleFileName, Hinstance, Addr Buffer, Sizeof Buffer
Invoke Lstrlen, AddR Buffer
MOV ECX, EAX
Dec ECX
Lea Edi, Buffer
Add Edi, ECX
STD
MOV Al, "/"
Repne scaSB
CLD
Inc EDI
MOV Byte Ptr [EDI], 0
Invoke Lstrcat, AddR Buffer, Addr WordFileName
Construct The Full Path Name of Wordfile.txt: I Assume That's Always in The Same Folder as the program.
Invoke getFileAttributes, AddR buffer
.IF EAX! = - 1
I use this method as a quick way of checking.
Mov Blocksize, 1024 * 10
Invoke Heapalloc, Hmainheap, 0, Blocksize
MOV PTEMP, EAX
Allocate The Memory Block to Store The Words. Default To 10k. The Memory Is Allocated from The Default HEAP.
@@:
Invoke GetPrivateProfileString, Addr Asmsection, Addr C1key, Addr Zerostring, Ptemp, Blocksize, AddR Buffer
.IF EAX! = 0
I Use getprivateprofilestring to retrieve the content of each key in wordfile.txt. The key starts from c1 to c10.
INC EAX
.IF EAX == blocksize; the buffer is to small
Add Blocksize, 1024 * 10
Invoke HeapRealloc, Hmainheap, 0, Ptemp, Blocksize
MOV PTEMP, EAX
JMP @B
.endif
CHECKING WHETHER THE MEMORY BLOCK IS LARGE ENOUGH. IT IS Not, We Increment The size by 10k Until The Block is Large Enough.
Mov Edx, Offset Asmcolorarray
Invoke PaSebuffer, Hmainheap, Ptemp, Eax, Edx, Addr AsmsyntaxArray
Pass The Words, The Memory Block Handle, The Size of The Data Read from Wordfile.txt, The Address of The Color Dword That Will Be Used To Hilight The Words and The Address of AsmsyntaxArray.
Now, let's examine what ParseBuffer does. In essence, this function accepts the buffer containing the words to be hilighted, parses them to individual words and stores each of them in a WORDINFO structure array that can be accessed quickly from ASMSyntaxArray.ParseBuffer proc uses edi ESI HHEAP: DWORD, PBUFFER: DWORD, NSIZE: DWORD, ARRAYOFFSET: DWORD, PARRAY: DWORD
Local buffer [128]: BYTE
Local Inprss: DWORD
Mov Inprogress, False
Inprogress is the flag i use to indeicate WHETER THE SCANNING Process Has Begun. We Haven't Encountered A Non-White Space Character Yet.
Lea ESI, Buffer
Mov EDI, PBuffer
Invoke Charlower, EDI
ESI Points To Our Local Buffer That Will Contain The Word We Have Parsed from The Word List. EDI Points To The Word List String. To Simplify The Search Later, We Convert All Characters To LowerCase.
MOV ECX, NSIZE
Searchloop:
OR ECX, ECX
JZ Finished
CMP Byte PTR [EDI], ""
Je endofword
CMP Byte PTR [EDI], 9; TAB
Je endofword
Scan The Whole Word List in The Buffer, Looking for the White Spaces. If A White SpaceMine WHETER IT MARKS The End or the beginning beginning of a word.
Mov Inprogress, True
Mov Al, Byte Ptr [EDI]
MOV BYTE PTR [ESI], Al
Inc ESI
Skipit:
Inc EDI
Dec ECX
JMP Searchloop
IF the byte under scrutiny is not a white space, we copy it to the buffer to construct a word and then contract.
Endofword:
CMP Inprogress, True
JE WordFound
JMP Skipit
If a white space is found, we check the value in InProgress. If the value is TRUE, we can assume that the white space marks the end of a word and we may proceed to put the word currently in the local buffer (pointed to by ESI) INTO A WordInfo Structure. If The Value IS False, We Continue The Scan Until A Non-White Space Character Is Found.WordFound:
MOV Byte Ptr [ESI], 0
Push ECX
Invoke Heapalloc, Hheap, Heap_Zero_Memory, Sizeof WordInfo
...............................
PUSH ESI
Mov ESI, EAX
Assume ESI: PTR WordInfo
Invoke Lstrlen, AddR Buffer
MOV [ESI]. Wordlen, EAX
We Obtain the Length of The Word in The Local Buffer and Store IT IN The Wordlen Member of The WordInfo Structure, To BE Used As a Quick Comparison.
Push arrayoffset
POP [ESI] .pcolor
Store The Address of The DWord That Contains The Color To Be Used to Hilight The Word in Pcolor Member.
INC EAX
Invoke Heapalloc, Hheap, Heap_Zero_Memory, EAX
MOV [ESI] .pszword, EAX
Mov Edx, EAX
Invoke Lstrcpy, EDX, AddR Buffer
Allocate Memory from The Heap To Store The Word Itself. Right Now, The WordInfo Structure Is Ready To Be Inserted INTO The Appropriate Linked List.
Mov Eax, Parray
Movzx EDX, Byte Ptr [Buffer]
SHL EDX, 2; Multiply by 4
Add Eax, EDX
pArray contains the address of ASMSyntaxArray. We want to move to the dword that has the same index as the value of the first character of the word. So we put the first character of the word in edx then multiply edx by 4 (because each element In AsmsyntaxArray IS 4 BYTES in size) and the address of ask the offset to the address of asmsyntaxarray. we have the address of the corresponding dword in eax..if dword ptr [EAX] == 0
Mov DWORD PTR [EAX], ESI
.lse
Push DWORD PTR [EAX]
POP [ESI] .NextLink
Mov DWORD PTR [EAX], ESI
.endif
Check The Value of The DWord. If it's 0, it..................................
If the value in the dword is not 0, it means there is at least one word that begins with this character in the array. We thus insert this WORDINFO structure to the head of the linked list and update its NextLink member to point to the next Wordinfo structure.
POP ESI
POP ECX
Lea ESI, Buffer
Mov Inprogress, False
JMP Skipit
After the Operation is Complete, We Begin The next scan cycle until the end of buffer is reached.
Invoke SendMessage, Hwndrichedit, EM_SETTYPOGRAPHYOPTIONS, TO_SIMPLINEBREAK, TO_SIMPLINEBREAK
Invoke SendMessage, HwndrichEdit, EM_GETTYPOGRAPHYOPTIONS, 1, 1
.IF EAX == 0; Means this message is not processed
Mov Richeditversion, 2
.lse
Mov Richeditversion, 3
Invoke SendMessage, HwndrichEdit, Em_seteditStyle, SES_EMULATESYSEDIT, SES_EMULATESYSEDIT
.endif
After the richedit control is created, we need to determine the its version. This step is necessary since EM_POSFROMCHAR behaves differently for RichEdit 2.0 and 3.0 and EM_POSFROMCHAR is crucial to our syntax hilighting routine. I have never seen a documented way of checking the version of richedit control thus I have to use a workaround. In this case, I set an option that is specific to version 3.0 and immediately retrieve its value. If I can retrieve the value, I assume that the control version is 3.0.If you use RichEdit control version 3.0, you will notice that updating the font color for a large file takes quite a long time This problem seems to be specific to version 3.0 I found a workaround:.. making the control emulate the behavior of the system edit control by sending Em_seteditstyle Message.
After We can Obtain the Version Information, WE Proceed To Subclass The Richedit Control. We will now Examine The New Window Procedure for the Richedit Control.
NEWRICHEDITPROC PROC HWND: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
........
.......
.IF uMSG == WM_PAINT
Push EDI
PUSH ESI
Invoke hidecaret, hwnd
Invoke CallWindowProc, OldWndProc, Hwnd, UMSG, WPARAM, LPARAM
Push EAX
We handle WM_PAINT message. First, we hide the caret so as to avoid some ugly gfx after the hilighting. After that we pass the message to the original richedit procedure to let it update the window. When CallWindowProc returns, the text is updated with its Usual color / backgroundunity to do syntax hilighting.
Mov Edi, Offset AsmsyntaxArray
Invoke getdc, hwnd
MOV HDC, EAX
Invoke setbkmode, hdc, transparent
Store the address of ASMSyntaxArray in edi. Then we obtain the handle to the device context and set the text background mode to transparent so the text that we will write will use the default background color.invoke SendMessage, hWnd, EM_GETRECT, 0, addr rect
Invoke SendMessage, Hwnd, EM_CHARFROMPOS, 0, ADDR RECT
Invoke SendMessage, HWnd, EM_LINEFROMCHAR, EAX, 0
Invoke SendMessage, Hwnd, EM_LINEINDEX, EAX, 0
We want to obtain the visible text so we first have to obtain the formatting rectangle by sending EM_GETRECT message to the richedit control. Now that we have the bounding rectangle, we obtain the nearest character index to the upper left corner of the rectangle with EM_CHARFROMPOS. Once we have the character index (the first visible character in the control), we can start to do syntax hilighting starting from that position. But the effect might not be as good as when we start from the first character of the line that the character Is in. That's why i need to obtain the line number is in by sending em_linefromchar message. To Obtain the first character of then line, i send em_lineindex message.
Mov txtrange.chrg.cpmin, EAX
Mov firstchar, EAX
Invoke SendMessage, Hwnd, Em_Charfrompos, 0, Addr Rect.right
Mov txtrange.chrg.cpmax, EAX
Once we have the first character index, store it for future reference in FirstChar variable. Next we obtain the last visible character index by sending EM_CHARFROMPOS, passing the lower-right corner of the formatting rectangle in lParam.
Push Rect.Left
Pop RealRect.Left
Push Rect.Top
POP realRect.top
Push Rect.right
Pop RealRect.Right
Push Rect.Bottom
Pop RealRect.Bottom
Invoke CreateRectrgn, RealRect.Left, RealRect.top, RealRect.right, RealRect.Bottom
Mov HRGN, EaxInvoke SelectObject, HDC, HRGN
Mov HoldRGN, EAX
While doing syntax hilighting, I noticed an unsightly side-effect of this method: if the richedit control has a margin (you can specify margin by sending EM_SETMARGINS message to the richedit control), DrawText writes over the margin Thus I need to create a. CLIPPING Region, The size of the formatting reccTangle, by calling createrecn. The Output of GDI Functions Will Be Clipped to the "Writable" Area.
Next, we need to hilight the comments first and get them out of our way My method is to search for ";" and hilight the text with the comment color until the carriage return is found I will not analyze the routine here:.. It's .
Mov ECX, Buffersize
Lea ESI, Buffer
.While ECX> 0
MOV Al, Byte Ptr [ESI]
.IF AL == "" | | Al == 0DH || Al == "/" || Al == "| || Al ==" "|| Al == "-" || Al == "*" || Al == "&" || Al == "<" || Al == "> || Al ==" = "| Al ==" ( "|| Al ==") "|| Al ==" {"|| al =="} "|| Al ==" ["|| Al =="] "| | Al ==" ^ "| | AL == ":" || Al == 9
MOV Byte Ptr [ESI], 0
.endif
Dec ECX
Inc ESI
.endw
. Once the comments are out of our way, we separate the words in the buffer by replacing the "separator" characters with 0s With this method, we need not concern about the separator characters while processing the words in the buffer anymore: there is only One Separetor Character, Null.lea ESI, Buffer
Mov ECX, Buffersize
.While ECX> 0
MOV Al, Byte Ptr [ESI]
.IF AL! = 0
Search The Buffer for the First Character That Is Not Null, IE, The First Character of A Word.
Push ECX
Invoke lstrlen, ESI
Push EAX
Mov Edx, EAX
Obtain the length of the word and put it in edx
Movzx Eax, Byte Ptr [ESI]
.IF Al> = "a" && al <= "z"
SUB Al, "a"
Add Al, "A"
.endif
Convert the Character to LowerCase (if it's an uppercase character)
SHL EAX, 2
Add Eax, EDI; EDI Contains the Pointer to the WordInfo Pointer Array
.IF DWORD PTR [EAX]! = 0
After That, We Skip to The Corresponding DWORD IN ASMSYNTAXARRAY and Check WHETER THE VALUE IN THAT IS 0. If IT WORD.
MOV Eax, DWORD PTR [EAX]
Assume EAX: PTR WordInfo
.while eax! = 0
.IF EDX == [EAX]. Wordlen
If the value in the dword is non-zero, it points to the linked list of WORDINFO structures. We process to walk the linked list, comparing the length of the word in our local buffer with the length of the word in the WORDINFO structure. This Is A Quick Test Before We Compare The Words. Should Save Some Clock Cycles.
Pushhad
Invoke lstrcmpi, [EAX] .pszword, ESI
.IF EAX == 0
IF The Length, WE Proceed To Compare The with lstrcmpi.
Popad
MOV ECX, ESI
Lea Edx, Buffer
SUB ECX, EDX
Add Ecx, Firstchar
We construct the character index from the address of the first character of the matching word in the buffer. We first obtain its relative offset from the starting address of the buffer then add the character index of the first visible character to it.pushad
.IF richeditversion == 3
Invoke SendMessage, Hwnd, EM_POSFROMCHAR, AddR Rect, ECX
.lse
Invoke SendMessage, HWnd, EM_POSFROMCHAR, ECX, 0
MOV ECX, EAX
And ECX, 0FFFFH
Mov Rect.Left, ECX
SHR EAX, 16
Mov Rect.Top, EAX
.endif
Popad
Once we know the character index of the first character of the word to be hilighted, we proceed to obtain the coordinate of it by sending EM_POSFROMCHAR message. However, this message is interpreted differently by richedit 2.0 and 3.0. For richedit 2.0, wParam contains the character index and lParam is not used. It returns the coordinate in eax. For richedit 3.0, wParam is the pointer to a POINT structure that will be filled with the coordinate and lParam contains the character index.
As you can see, Passing The Wrong Arguments to EM_POSFROMCHAR CAN WREAK HAVOC To Your System. That's why i since ly to differentiate Between Richedit Control Versions.
Mov Edx, [EAX] .pcolor
Invoke SetTextColor, HDC, DWORD PTR [EDX]
Invoke DrawText, HDC, ESI, -1, Addr Rect, 0
Once We got The Coordinate to Start, We set The text color with the one specified in The WordInfo Structure. And then the new color.