ICZelion TUT33

zhaozj2021-02-11  203

Tutorial 33: Richedit Control: Basics

. There are lots of request on tutorials about RichEdit controls Finally I have played with it enough to think I can write tutorials about it So here it is:.. The first RichEdit tutorial The tutorials will describe nearly everything there is to know about RichEdit control or at least as much as I know it. The amount of information is rather large so I divide it into several parts, this tutorial being the first part. In this tutorial, you'll learn what a RichEdit control is, how to create it And how to load / save data to / from it.

Download The Example.

THEORY

A richedit control can be thought of as a souped-up edit control. It provides many desirable features that are lacking from the plain simple edit control, for example, the ability to use multiple font face / size, multiple-level undo / redo, search-for-text operation, OLE-embedded objects, drag-and-drop editing support, etc. Since the richedit control has so many features, it's stored in a separate DLL. This also means that, to use it, you can ' T Just Call INTCOMMONCONTROLS LIKE OTHER COMMON Controls. You have to call loadlibrary to load the richedit dll.

The Problem Is That There................................

Dll NamericHedit VersionRicHedit Class Nameriched32.dll1.0richeditriched20.dll2.0richedit20age20.dll3.0richedit20a

You can notice that richedit version 2 and 3 use the same DLL name. They also use the same class name! This can pose a problem if you want to use specific features of richedit 3.0. Up to now, I have not found an official Method Of Differentiating Between Version 2.0 and 3.0. However, There is a workaround Which Works OK, I'll show you latter..data

Richeditdll DB "Riched20.dll", 0 ... Data? HRICHEDITDLL DD? .Code invoke loadinglibrary, addr richeditdll Mov Hricheditdll, Eax ... Invoke Freelibrary, Hricheditdll

When the richedit dll is loaded, it registers the RichEdit window class Thus it's imperative that you load the DLL before you create the control The names of the richedit control classes are also different Now you may have a question:... How do I know which version of richedit control should I use? Using the latest version is not always appropriate if you do not require the extra features. So below is the table that shows the features provided by each version of richedit control.

FeatureVersion 1.0Version 2.0version 3.0Selection Bar

x

x

x

Unicode Editing

x

x

Character / Paragraph Formatting

x

x

x

Search for text

Forward

Forward / Backward

Forward / Backward

Ole Embedding

x

x

x

Drag and Drop Editing

x

x

x

Undo / redo

Single-Level

Multi-Level

Multi-Level

Automatic URL Recognition

x

x

Accelerator Key Support

x

x

Windowless Operation

x

x

Line Break

CRLF

CR ONLY

Cr Only (Can Emulate Version 1.0)

Zoom

x

Paragraph Numbering

x

Simple Table

x

Normal and Heading Styles

x

Underline coloring

x

Hidden text

x

Font binding

x

The Above Table is by No Means Comprehensive: i Only List The Important Features.

Creating the richedit control

After loading the richedit dll, you can call CreateWindowEx to create the control. You can use edit control styles and common window styles in CreateWindowEx except ES_LOWERCASE, ES_UPPERCASE and ES_OEMCONVERT..const

Richeditid EQU 300

.DATA

Richeditdll DB "Riched20.dll", 0 Richeditclass DB "Richedit20a", 0

...

.DATA? HRICHEDITDLL DD?

HWNDRICHEDIT DD?

.code

.....

Invoke Loadlibrary, AddR Richeditdll

mov hRichEditDLL, eax invoke CreateWindowEx, 0, addr RichEditClass, WS_VISIBLE or ES_MULTILINE or WS_CHILD or WS_VSCROLL or WS_HSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, RichEditID, hInstance, 0

Mov hwndrichedit, EAX

Setting Default Text And Background Color

You may have the problem with setting text color and the background color of the edit control. But this problem has been remedy in richedit control. To set the background color of the richedit control, you send EM_SETBKGNDCOLOR to the richedit control. This message has the Following Syntax.

wParam == color option. The value of 0 in this parameter specifies that Windows uses the color value in lParam as the background color. If this value is nonzero, Windows uses the Windows system background color. Since we send this message to change the background Color, WE Must Pass 0 in wparam.lparam == specifies the colorref structure of the color you want to set if wparam is 0.

For Example, Iwant To Set The Background Color To Pure Blue, I Would Issue this Following Line:

Invoke SendMessage, Hwndrichedit, EM_SETBKGNDCOLOR, 0, 0FF0000H

To set the text color, richedit control provides another new message, EM_SETCHARFORMAT, for the job This message controls the text formatting of a range to characters in selection or all text in the control This message has the following syntax:.. WParam == formatting Options:

SCF_ALLThe operation affects all text in the control.SCF_SELECTIONThe operation affects only the text in selectionSCF_WORD or SCF_SELECTIONAffects the word in selection. If the selection is empy, ie, only the caret is in the word, the operation affects that word. SCF_WORD flag must be Used with scf_selection.

lParam == pointer to a CHARFORMAT or CHARFORMAT2 structure that specifies the text formatting to be applied. CHARFORMAT2 is available for richedit 2.0 and above only. This does not mean that you must use CHARFORMAT2 with RichEdit 2.0 or above. You can still use CHARFORMAT If the added features in charformat2 is not nepassary for your need.

CharFormata Struct

CBSIZE DWORD?

DWMASK DWORD?

DWEFFECTS DWORD?

YHEIGHT DWORD?

Yoffset DWORD?

CRTEXTCOLOR colorREF?

Bcharset byte?

BPITCHANDFAMILY BYTE?

SZFACENAME BYTE LF_FACESIZE DUP (?)

_WPAD2 WORD?

CharFormata Ends

Field NameDescriptioncbSizeThe size of the structure. RichEdit control uses this field to determine the version of the structure whether it is CHARFORMAT or CHARFORMAT2dwMask Bit flags that determine which of the following members are valid.

CFM_BOLDThe CFE_BOLD value of the dwEffects member is validCFM_CHARSETThe bCharSet member is valid.CFM_COLORThe crTextColor member and the CFE_AUTOCOLOR value of the dwEffects member are validCFM_FACEThe szFaceName member is valid.CFM_ITALICThe CFE_ITALIC value of the dwEffects member is validCFM_OFFSETThe yOffset member is validCFM_PROTECTEDThe CFE_PROTECTED value of the dwEffects member is validCFM_SIZEThe yHeight member is validCFM_STRIKEOUTThe CFE_STRIKEOUT value of the dwEffects member is valid.CFM_UNDERLINEThe CFE_UNDERLINE value of the dwEffects member is validdwEffects The character effects. Can be the combination of the following valuesCFE_AUTOCOLORUse the system text colorCFE_BOLDCharacters are boldCFE_ITALICCharacters are italicCFE_STRIKEOUTCharacters are struck.CFE_UNDERLINECharacters are Underlinedcfe_protacecharacters are protected; an attempt to modected; heightcharacter Height, In Twips (1/1440 of an inch or 1/20 of .. A printer's point) yOffsetCharacter offset, in twips, from the baseline If the value of this member is positive, the character is a superscript; if it is negative, the character is a subscript crTextColor Text color This member is ignored if.. THE CFE_AUTOCOLOR CHARACTER Effect Is Specified. Bcharstcharacter Set ValuebpitchandFamilyFont Family and Pitch. Szfacename Null-Terminated Character Array Specifying The Font Name_WPAD2PADDING

From examination of the structure, you'll see that we can change the text effects (bold, italic, strikeout, underline), text color (crTextColor) and font face / size / character set. A notable flag is CFE_RPOTECTED. The text with this flag is marked as protected which means that when the user tries to modify it, EN_PROTECTED notification message will be sent to the parent window. And you can allow the change to happen or not.CHARFORMAT2 adds more text styles such as font weight, spacing , Text Background Color, Kerning, etc. if you don't need it extra features, Simply Use Charformat.

To set text formatting, you have to think about the range of text you want to apply to Richedit control introduces the notion of character text range Richedit control gives each character a number starting from 0:.. The first characterin the control has Id of 0 , the second character 1 and so on To specify a text range, you must give the richedit control two numbers:.. the IDs of the first and the last character of the range To apply the text formatting with EM_SETCHARFORMAT, you have at most three Choices:

Apply to all text in the control (scf_all) Apply to TEXT CURRENTLY IN Selection Apply to the whole word currently in selection (scf_word or scf_selection)

The first and the second choices are straightforward. The last choice requires a little explanation. If the current selection only covers one or more of the characters in the word but not the whole word, specifying the flag SCF_WORD SCF_SELECTION applies the text formatting to the Whole Word. Even if The IS No Current Selection, IE, ONLY The Caret Is Positioned in The Text Formatting To The Whole Word.

To Use EM_SETCHARFORMAT, You Need To Fill Several Members of Charformat (or CharFormat2) Structure. For Example, IF We Want To Set The Text Color, WE WILL FILL THE CharFormat Structure As Follows: .data?

Cf CharFormat <>

....

.code

Mov Cf.cbsize, Sizeof CF

Mov cf.dwmask, cfm_color

Mov cf.crtextColor, 0FF0000h

Invoke SendMessage, HWndrichedit, EM_SETCHARFORMAT, SCF_ALL, ADDR CF

The above code snippet sets the text color of the richedit control to pure blue. Note that if there is no text in the richedit control when EM_SETCHARFORMAT is issued, the text entered into the richedit control following the message will use the text formatting specified by the EM_SETCHARFORMAT MESSAGE.

Setting the text / saving the text

For those of you who are used to edit control, you'll surely be familiar with WM_GETTEXT / WM_SETTEXT as the means to set the text / get the text to / from the control. This method still works with richedit control but may not be efficient if the file is large. Edit control limits the text that can be entered into it to 64K but richedit control can accept text much larger than that. It would be very cumbersome to allocate a very large block of memory (such as 10 MB or so ) to receive the text from wm_gettext. Richedit Control Offers a New Approach To this Method, IE. Text streaming.

To put it simply, you provide the address of a callback function to the richedit control. And richedit control will call that callback, passing the address of the buffer to it, when it's ready. The callback will fill the buffer with the data it wants to send to the control or read the data from the buffer and then waits for the next call until the operation is finished. This paradigm is used for both streaming in (setting the text) and streaming out (getting the text out of the control) . You'll see that this method is more efficient: the buffer is provided by the richedit control itself so the data are divided into chunks The operations involve two messages:. EM_STREAMIN and EM_STREAMOUTBoth EM_STREAMIN and EM_STREAMOUT use the same syntax:

WPARAM == Formatting Options.

SF_RTFThe data is in the rich-text format (RTF) SF_TEXTThe data is in the plain text formatSFF_PLAINRTFOnly the keywords common to all languages ​​are streamed in.SFF_SELECTIONIf specified, the target of the operation is the text currently in selection. If you stream the text in, the text replaces the current selection. If you stream the text out, only the text currently in selection is streamed out. If this flag is not specified, the operation affects the whole text in the control.SF_UNICODE (Available on RichEdit 2.0 or Later Specify The Unicode Text.

LPARAM == Point to an EditStream Structure Which Has The Following Definition:

EditStream Struct

DWCOOKIE DWORD?

DWERROR DWORD?

PFNCALLBACK DWORD?

EditStream Ends

dwCookieapplication-defined value that will be passed to the callback function speficied in pfnCallback member below. We normally pass some important value to the callback function such as the file handle to use in the stream-in / out procedure.dwErrorIndicates the results of the stream -in (read) or stream-out (write) operation. A value of zero indicates no error. A nonzero value can be the return value of the EditStreamCallback function or a code indicating that the control encountered an error. pfnCallbackPointer to an EditStreamCallback function ., which is an application-defined function that the control calls to transfer data The control calls the callback function repeatedly, transferring a portion of the data with each callThe editstream callback function has the following definition:

EditStreamCallback Proto DWCOOKIE: DWORD, PBUFFER: DWORD,

Numbytes: DWORD,

PBYTESTRANSFERRED: DWORD

You have to create a function with the Above prototype in your program. And then pass its address to em_streamin or em_streamout Via EditStream Structure.

For stream-in Operation (Settting the text in the richedit control):

DWCOOKIE: The Application-Defined Value You Pass To Em_Streamin Via EditStream Structure. We almost always

Pass the file handle of the file we want to set its content to the control here.

PBUFFER: Points to the buffer provided by The Richedit Control That Will Receive The text from your callback function.

Numbytes: The maximum number of bytes you can write the buffer (PBUFFER) in this call. You Must Always Obey this Limit, IE, You CAN Send

Less Data Than The Value in Numbytes But Must Not send More Data Than THIS VALUE. You Can Think of this value as the size

Of the buffer in pbuffer.

pBytesTransferred: points to a dword that you must set the value indicating the number of bytes you actually transferred to the buffer.This value is usually identical to the value in NumBytes The exception is when the data is to send is less than.

The size of the buffer provided such as reason.

For stream-out Out of the richedit control:

DWCOOKIE: Same as The stream-in operation. We Usually pass the file handle we want to write the data to in this parameter.

PBUFFER: Points to the buffed by the richedit control..

To Obtain ITS Size, You Must Examine The Value of Numbytes.

Numbytes: The size of the data in the buffer pointd to by pbuffer.

.................

The callback function returns 0 to indicate success and richedit control will continue calling the callback function if there is still data left to read / write. If some error occurs during the process and you want to stop the operation, returns a non-zero value and the richedit control will discard the data pointed to by pBuffer. The error / success value will be filled in the dwError field of EDITSTREAM so you can examine the error / success status of the stream operation after SendMessage returns.

EXAMPLE:

THE EXAMPLE BELOW IS A Simple Editor Which You CAN Open An ASM Source Code File, Edit and Save It. It Uses Richedit Control Version 2.0 OR Above.

.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.include /masm32/include/kernel32.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

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

IDC_BACKCOLORBOX EQU 1000

IDC_TextColorBox EQU 1001

Richeditid EQU 300

.DATA

ClassName DB "iczeditclass", 0

Appname DB "iczedit Version 1.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

.DATA?

Hinstance DD?

HRICHEDIT DD?

HWNDRICHEDIT DD?

FILENAME DB 256 DUP (?)

AlternateFileName DB 256 DUP (?)

Customcolors DD 16 DUP (?)

.code

Start:

Invoke getModuleHandle, NULL

Mov Hinstance, EAX

Invoke LoadLibrary, AddR Richeditdll.if Eax! = 0

Mov HrichEdit, EAX

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, NULL

MOV HWND, EAX

Invoke ShowWindow, Hwnd, SW_SHOWNORMAL

Invoke UpdateWindow, HWnd

.While true

Invoke GetMessage, Addr MSG, 0,0,0

.break .if (! EAX)

Invoke TranslateMessage, Addr MSG

Invoke DispatchMessage, Addr MSG

.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_TextColorBoxInvoke InvalidateRect, Eax, 0, True

.endif

.ELSEIF AX == IDOK

; ================================================== ==========================================================================================================================================================

; Save The Modify State of The Richedit Control Because Changing The Text Color Changes The TEXT Color Changes

Modify State of The Richedit Control.

; ================================================== ==========================================================================================================================================================

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

WNDPROC PROC HWND: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD

Local Chrg: Charrangelocal OFN: OpenFileName

Local buffer [256]: Byte

Local EditStream: EditStream

Local Hfile: DWORD

.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

; ================================================== ============

Set the text limited. The Default IS 64K

; ================================================== ============

Invoke SendMessage, HwndrichEdit, EM_LIMITTEXT, -1, 0

; ================================================== ============

; Set the default text / background color

; ================================================== ============ Invoke setColor

Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0

Invoke SendMessage, Hwndrichedit, EM_EMPTYUNDOBUFER, 0, 0

.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

; ================================================== ============================

Check WHETHER THEERE IS Some Text In The Clipboard. If So, We Enable The Paste MenuItem

; ================================================== ============================ Invoke sendMessage, HWndrichedit, EM_CANPASTE, CF_TEXT, 0

.IF EAX == 0; No Text in the clipboard

Invoke EnableMenuItem, WPARAM, IDM_PASTE, MF_GRAYED

.lse

Invoke EnableMenuItem, WPARAM, IDM_PASTE, MF_ENABLED

.endif

; ================================================== =========

Check WHETHER THE undo queue is empty

; ================================================== =========

Invoke SendMessage, Hwndrichedit, EM_CANUNDO, 0, 0

.IF EAX == 0

Invoke EnableMenuItem, WPARAM, IDM_UNDO, MF_GRAYED

.lse

Invoke EnableMenuItem, WPARAM, IDM_UNDO, MF_ENABLED

.endif

; ================================================== =========

Check WHETHER THE Redo Queue Is EMPTY

; ================================================== ======== Invoke SendMessage, Hwndrichedit, EM_CANREDO, 0, 0

.IF EAX == 0

Invoke EnableMenuItem, WPARAM, IDM_REDO, MF_GRAYED

.lse

Invoke EnableMenuItem, WPARAM, IDM_REDO, MF_ENABLED

.endif

; ================================================== =========

Check WHETHER THERE IS A CURRENT Selection In The Richedit Control.

; If there is, we enable the copy / delete menuItem

; ================================================== =========

Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR chrg

Mov Eax, Chrg.cpmin

.IF eax == chrg.cpmax; no current selection

Invoke EnableMenuItem, WPARAM, IDM_COPY, MF_GRAYED

Invoke EnableMenuItem, WPARAM, IDM_CUT, MF_GRAYED

Invoke EnableMenuItem, WPARAM, IDM_DELETE, MF_GRAYED

.lse

Invoke EnableMenuItem, WPARAM, IDM_COPY, MF_ENABLED

Invoke EnableMenuItem, WPARAM, IDM_CUT, MF_ENABLED

Invoke EnableMenuItem, WPARAM, IDM_DELETE, MF_ENABLED

.endif

.endif

.ELSEIF uMSG == WM_COMMAND

.IF lparam == 0; Menu Commands

Mov Eax, WPARAM

.IF AX == idm_open

Invoke RTLZEROMEMORY, AddR OFN, SIZEOF OFNMOWN.LSTRUCTSIZE, SIZEOF OFN

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

; ================================================== ================

Stream The Text Into The Richedit Control

; ================================================== ================

Mov EditStream.dwcookie, EAX

Mov EditStream.pfncallback, Offset StreamInproc

Invoke SendMessage, Hwndrichedit, EM_STREAMIN, SF_TEXT, ADDR EditStream

; ================================================== =========

; Initialize the Modify State To False

; ================================================== ========= 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

; ================================================== ================

Stream the text to the file

; ================================================== ================

Mov EditStream.dwcookie, EAX

Mov EditStream.pfncallback, Offset streamoutproc

Invoke SendMessage, Hwndrichedit, EM_STREAMOUT, SF_TEXT, AddR EditStream

; ================================================== =========; Initialize The Modify State To False

; ================================================== =========

Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0

Invoke Closehandle, HFile

.lse

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], 0Mov off.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_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

; ================================================== ==================

The resource file

; ================================================== ==================

#include "resource.h"

#define idR_mainMenu 101

#define IDd_optiondlg 101

#define idc_backcolorbox 1000 # define IDC_TextColorBox 1001

#define IDM_Open 40001

#define idm_save 40002

#define idm_close 40003

#define idm_saveas 40004

#define idm_exit 40005

#define idm_copy 40006

#define idm_cut 40007

#define idm_paste 40008

#define idm_delete 40009

#define IDM_SELECTALL 40010

#define idm_option 40011

#define IDM_UNDO 40012

#define IDM_REDO 40013

IDR_MainMenu Menu Discardable

Begin

Popup "& file"

Begin

Menuitem "& Open", IDM_Open

Menuitem "& close", IDM_Close

Menuitem "& savior", IDM_SAVE

Menuitem "Save & As", IDM_SAVEAS

Menuitem Separator

Menuitem "E & XIT", IDM_EXIT

End

Popup "& Edit"

Begin

Menuitem "& undo", IDM_UNDO

Menuitem "& redo", IDM_redo

Menuitem "& Copy", IDM_COPY

Menuitem "C & UT", IDM_CUT

Menuitem "& Paste", IDM_PASTE

Menuitem Separator

Menuitem "& delete", IDM_DELETE

Menuitem Separator

Menuitem "SELECT & ALL", IDM_SELECTALL

End

Menuitem "Options", IDM_Option

End

IDD_OPTIONDLG DIALOG DISCARDABLE 0, 0, 183, 54

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTERCAPTION "Options"

Font 8, "MS Sans Serif"

Begin

Defpushbutton "OK", IDOK, 137, 7, 39, 14

Pushbutton "Cancel", IDCANCEL, 137, 25, 39, 14

Groupbox "", IDC_STATIC, 5, 0, 124, 49

LTEXT "Background Color:", IDC_STATIC, 20, 14, 60, 8

LTEXT "" ", IDC_BackColorbox, 85, 11, 28, 14, ss_notify | ws_border

LTEXT "Text Color:", IDC_STATIC, 20, 33, 35, 8

LTEXT "" ", IDC_TextColorbox, 85, 29, 28, 14, ss_notify | ws_border

End

Analysis:

The Program First Loads The Richedit DLL, Which in this case. If the dll cannot be loading, it exits to windows.

Invoke Loadlibrary, AddR Richeditdll

.IF EAX! = 0

Mov HrichEdit, EAX

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

After the dll is loading successful, we proceed to create a normal window which will be the parent of the richedit control: WE CREATE The Richedit Control:

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

Note That We Specify ES_MULTILINE STYLE ELSE The Control Will Be a Single-Lined ONE.

Invoke SendMessage, HwndrichEdit, EM_LIMITTEXT, -1, 0

After the richedit control is created, we must set the new text limit on it. By default, the richedit control has 64K text limit, the same as a simple multi-line edit control. We must extend this limit to allow it to operate with Larger Files. in The Above Line, I Specify -1 Which Amounts to 0FFFFFFFH, A VERY LARGE VALUE.INVOKE SETCOLOR

Next, We set the text / background color. Since this Operation Can Be Performed in Other Part of The Program, I Put The Code In a Function Named SetColor.

SetColor Proc

Local CFM: CharFormat

Invoke SendMessage, Hwndrichedit, EM_SETBKGNDCOLOR, 0, BackgroundColor

Setting the background color of the richedit control is a straightforward operation: just send EM_SETBKGNDCOLOR message to the richedit control (If you use a multi-line edit control, you have to process WM_CTLCOLOREDIT) The default background color is white...

Invoke RTLZERMEMORY, AddR CFM, Sizeof CFM

Mov Cfm.cbsize, Sizeof CFM

Mov cfm.dwmask, cfm_color

Push TextColor

POP cfm.crtextColor

After the background color is set, we fill in the members of CHARFORMAT in order to set the text color. Note that we fill cbSize with the size of the structure so the richedit control knows we are sending it CHARFORMAT, not CHARFORMAT2. DwMask has only One Flag, CFM_COLOR, BECAUSE We Only Want To Set The Text Color and CrtextColor Is Filled with the value of the desired text color.

Invoke SendMessage, Hwndrichedit, EM_SETCHARFORMAT, SCF_ALL, ADDR CFM

RET

SetColor ENDP

After Settting The Color, You Have To Empty Und of Changing Text / Background Color is undo-able. We send em_emptyundobuffer message to achieve this.

Invoke SendMessage, Hwndrichedit, EM_EMPTYUNDOBUFER, 0, 0

After filling the CHARFORMAT structure, we send EM_SETCHARFORMAT to the richedit control, specifying SCF_ALL flag in wParam to indicate that we want the text formatting to be applied to all text in the control.Note that when we first created the richedit control, we didn ' That Time. That's Because We Want It To Cover The Whole Client Area of ​​the Parent Window. We Resize It WHENEVER The size of the parent window change.

.ELSEIF uMSG == WM_SIZE

Mov Eax, LPARAM

Mov Edx, EAX

And Eax, 0FFFFH

SHR EDX, 16

Invoke MoveWindow, Hwndrichedit, 0,0, Eax, EDX, True

In The Above Code Snippet, We Use The New Dimension of The Client Area Passed in LParam to Resize The Richedit Control with movewindow.

When the user clicks on the File / Edit menu bar, we process WM_INITPOPUPMENU so that we can prepare the states of the menuitems in the submenu before displaying it to the user. For example, if a file is already opened in the richedit control, we Want to Disable The OpenUItem and enable all the remaining menuitems.

In The Case of the File Menu Bar, WE Use The Variable FileOpened As The Flag To Determine WHETHER A File IS Already Opened. If The Value In This Variable IS TRUE, WE KNOW THAT A File IS Already OPENED.

.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_GRAYEDINVOKE ENABLEMENUITEM, WPARAM, IDM_SAVEAS, MF_GRAYED

.endif

As you can see, IF a file is already Opened, We Gray Out The Open MenuItem and enable the remaining menuitems. The reverse is true of fileopened is false.

In The Case of the Edit Menu Bar, We Need To Check The State of The Richedit Control / Clipboard First.

Invoke SendMessage, Hwndrichedit, EM_CANPASTE, CF_TEXT, 0

.IF EAX == 0; No Text in the clipboard

Invoke EnableMenuItem, WPARAM, IDM_PASTE, MF_GRAYED

.lse

Invoke EnableMenuItem, WPARAM, IDM_PASTE, MF_ENABLED

.endif

We first check whether some text is available in the clipboard by sending EM_CANPASTE message. If some text is available, SendMessage returns TRUE and we enable the paste menuitem. If not, we gray out the menuitem.

Invoke SendMessage, Hwndrichedit, EM_CANUNDO, 0, 0

.IF EAX == 0

Invoke EnableMenuItem, WPARAM, IDM_UNDO, MF_GRAYED

.lse

Invoke EnableMenuItem, WPARAM, IDM_UNDO, MF_ENABLED

.endif

NEXT, WE CHECK WHETHER THE undo buffer is empty by sending em_canundo message. If it's not empty, sendMessage returns true and we enable the undo menuitem.

Invoke SendMessage, Hwndrichedit, EM_CANREDO, 0, 0

.IF EAX == 0

Invoke EnableMenuItem, WPARAM, IDM_REDO, MF_GRAYED

.lse

Invoke EnableMenuItem, WPARAM, IDM_REDO, MF_ENABLED

.endif

WE CHECK The Redo Buffer To The Richedit Control. If IT'S NOT EMPTY, SendMessage Returns True and We enable the redo menuItem.

Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR chrg

Mov Eax, Chrg.cpmin

.IF eax == chrg.cpmax; no current selection

Invoke EnableMenuItem, WPARAM, IDM_COPY, MF_GRAYED

Invoke EnableMenuItem, WPARAM, IDM_CUT, MF_GRAYED

Invoke EnableMenuItem, WPARAM, IDM_DELETE, MF_GRAYED.ELSE

Invoke EnableMenuItem, WPARAM, IDM_COPY, MF_ENABLED

Invoke EnableMenuItem, WPARAM, IDM_CUT, MF_ENABLED

Invoke EnableMenuItem, WPARAM, IDM_DELETE, MF_ENABLED

.endif

Lastly, We Check WHETHER A CURRENT Selection EXSTS by Sending EM_EXGETSEL Message. This Message Uses a Charrange Structure Which IS Defined As Follows:

Charrange struct

CPMIN DWORD?

CPMAX DWORD?

Charrange Ends

.

After EM_EXGETSEL returns, the CHARRANGE structure is filled with the starting-ending character position indices of the selection range. If there is no current selection, cpMin and cpMax are identical and we gray out the cut / copy / delete menuitems.

WE DISPLAY An Open File Dialog Box and if the user selects a file, we open the file and stres. We open the file and stres.

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

After the file is successfully opened with CreateFile, we fill the EDITSTREAM structure in preparation for EM_STREAMIN message. We choose to send the handle to the via opened file dwCookie member and pass the address of the stream callback function in pfnCallback.

The Stream Callback Procedure Itself Is The Essence of Simplicity.

StreamInProc Proc Hfile: DWORD, PBUFFER: DWORD, Numbytes: DWord, PbytesRead: DWordInvoke Readfile, Hfile, Pbuffer, Numbytes, PbytesRead, 0

XOR Eax, 1

RET

StreaminProc ENDP

You can see that all parameters of the stream callback procedure fit perfectly with ReadFile. And the return value of ReadFile is xor-ed with 1 so that if it returns 1 (success), the actual value returned in eax is 0 and vice versa.

Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0

Invoke Closehandle, HFile

Mov FileOpened, True

After EM_STREAMIN RETURns, IT Means The Stream Operation IS Completed. In Reality, We Must Check The Value of Dwerror Member of The EditStream Structure.

Richedit (and edit) control supports a flag to indicate whether its content is modified. We can obtain the value of this flag by sending EM_GETMODIFY message to the control. SendMessage returns TRUE if the content of the control was modified. Since we stream the text into the control, it's a kind of a modification. We must set the modify flag to FALSE by sending EM_SETMODIFY with wParam == FALSE to the control to start anew after the stream-in opertion is finished. We immediately close the file and set FileOpened To True to Indicate That A File Was Opened.

When the user clicks on save / saveas menuitem, we use EM_STREAMOUT message to output the content of the richedit control to a file. As with the streamin callback function, the stream-out callback function is simplicity in itself. It fits perfectly with WriteFile.

The Text Operations Such As Cut / Copy / Paste / Redo / undo Are Easily Implement by Sending Single Message To The Richedit Control, WM_CUT / WM_COPY / WM_PASTE / WM_REDO / WM_UNDO Respectively.

The Delete / Select All Operations Are Done As Follows:

.ELSEIF AX == IDM_DELETEINVOKE SendMessage, Hwndrichedit, EM_REPLAASEL, TRUE, 0

.ELSEIF AX == IDM_SELECTALL

Mov chrg.cpmin, 0

Mov chrg.cpmax, -1

Invoke SendMessage, Hwndrichedit, EM_EXSETSEL, 0, AddR chrg

.................. ..

The select-all operation is done by sending em_exsetsel message, specify cpmin == 0 and cpmax == - 1 Which Amounts to selecting all the text.

WHEN THE USER SELECTS OPTION MENU BAR, WE Display A Dialog Box Presenting The Current Background / Text Colors.

When the user clicks on one of the color boxes, it displays the choose-color dialog box. The "color box" is in fact a static control with SS_NOTIFY and WS_BORDER flag. A static control with SS_NOTIFY flag will notify its parent window with mouse ActionS on it, such as bn_clicked (STN_Clicked). That's the trick.

.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

When the user clicks on one of the color box, we fill the members of the CHOOSECOLOR structure and call ChooseColor to display the choose-color dialog box. If the user selects a color, the colorref value is returned in rgbResult member and we store that value in BackgroundColor variable. After that, we force a repaint on the color box by calling InvalidateRect on the handle to the color box. The color box sends WM_CTLCOLORSTATIC message to its parent window.invoke GetDlgItem, hWnd, IDC_BACKCOLORBOX

.IF EAX == LPARAM

Invoke Createsolidbrush, BackgroundColor

RET

Within the WM_CTLCOLORSTATIC handler, we compare the handle of the static control passed in lParam to that of both the color boxes. If the values ​​match, we create a new brush using the color in the variable and immediately return. The static control will use the Newly created brush to pieint its background.

转载请注明原文地址:https://www.9cbs.com/read-4687.html

New Post(0)