Introduction
A control is a child window an application uses in with another window to perform simple input and output tasks. Controls are most often used within dialog boxes, but they can also be used in other windows. An edit control is a rectangular control window typically used in a dialog box to permit the user to enter and edit text from the keyboard.
This article will show how to easily create a simple text editor by using an edit control. The control itself provides most of the needed functionality, and only a small amount of actual code is needed.
In order make sure the common controls library is loaded, so that you can use them, you should call the InitCommonControls function.
An
edit control can send notification messages to its parent window in the
form of WM_COMMAND messages. A parent window can send messages to an edit
control in a dialog box by calling the SendDlgItemMessage function.
Files and Tools
Here are some things you will need to use this tutorial....
MASM
- (Get the MASM32
package)
Borlands
MAKE - (if you wish to use my makefile)
Borlands
BRCC32 - (i dont know why, but i still use borland resource
compiler)
Borlands
H2ASH - (not really necessary... easy way to convert .h to .inc)
The
complete source code (http://lordlucifer.cjb.net/win32asm/files/edit_tut.zip)
Win32
API reference
WinMain
This function is where the execution effectively begins... It initializes the various window controls, files, and keyboard accelerators.
Keyboard accelerators are basically keyboard shortcuts to menu items. To use accelerators, an accelerator table is created as a resource, in the following basic form:
acceltablename ACCELERATORS
{
event, idvalue, [type] [options]
...
}
event corresponds to the
key to be used. It can be of the form "c", an
integer value representing a char, or a virtual-key value.
idvalue integer which specifies the
ID
type specifies VIRTKEY
or ASCII
options NOINVERT, ALT, SHIFT, CONTROL
WinMain is also the home of the message loop. Here, the GetMessage function grabs the next message from the message queue. The TranslateAccelerator function then checks the message to see if it is an accelerator. If it is, it handles the message. If not, execution is passed to the TranslateMessage and DispatchMessage functions which sends the message to the appropriate window procedure.
The
message loop is broken when GetMessage retrieves the WM_QUIT message.
InitWindow
This function creates and shows the main application window.
To
create a window, first you must register a window class for that window.
This is done by filling in a WNDCLASSEX structure and passing it to the
RegisterClassEx function. Then the CreateWindowEx function is called,
using the newly created window class to create and show the window.
InitEditControl
This procedure initializes the Edit control and sizes it to fit inside the main window.
All edit controls belong to the window class "EDIT". This class name is specified in the call to CreateWindowEx. With common controls, you do not define and register your own class, you use the pre-defined window classes, defined in the commctrl.dll.
The edit window can have a variety of styles. In addition to the standard window styles, the edit control has sever additional styles:
ES_MULTILINE:
control can have more than one line (default is 1 line only)
ES_AUTOVSCROLL,
ES_AUTOHSCROLL: If the text to be displayed exceeds the size
of the window, these flags tell the control to automatically scroll the
text into view
ES_LEFT,
ES_CENTER, ES_RIGHT: These set the text alignment, and apply only
to multiline edit controls.
ES_LOWERCASE,
ES_UPPERCASE: Sets the text to all lowercase or uppercase characters,
respectively.
ES_OEMCONVERT:
Converts the text into a specific character set.
ES_NUMBER:
Limits text input to numbers only.
ES_NOHIDESEL:
Specifies the selected text is not hidden when the control loses focus.
ES_READONLY:
Makes the text read-only.
ES_PASSWORD:
Displays all characters as * (or other user defined character)
ES_WANTRETURN:
Specifies that a return is inserted when the enter key is pressed, for
multiline controls only.
InitFile
In this function, I get the command line arguments, and if a file is specified, it is loaded into the editor. If no file is specified, the editor begins with a new document.
To
get the command line arguments, I have created another function called
GetCommandLineArgs. This uses the GetCommandLine API function to
get the entire command line. I then parse the string to get
the arguments only. If the program is called with no arguments, the
command line is returned from GetCommandLine as a string. If it has
arguments, or is called from a directory with spaces, the command line
is returned as a string with the full exe's path in quotes, and with the
arguments following.
MainWndProc
This function is the window procedure for the main application window. This is specified in the lpfnWndProc member of the WNDCLASSEX struct, which is passed to the RegisterClassEx function. This is a callback function, called by windows and requiring the following form:
MainWndProc
proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
...
MainWndProc
endp
The hWnd parameter specifies the window handle that the message is sent to. uMsg specifies the message sent. wParam and lParam have varying meanings, depending on which message is being sent.
The window procedure is responsible for handling all of the messages sent to the application window. Here, the editing functionality, menu commands, window re-sizing and window termination are handled here.
I only handle the messages which I need for this application. All other messages are passed to the DefWindowProc API function, so they are properly dealt with and not lost.
The WM_DESTROY message should always be handled. This message is sent when the application window is closed. The handler then calls the PostQuitMessage API function, which is used to terminate the application. Failure to call this will result in the window disappearing but the application remaining in memory.
The WM_COMMAND message is sent whenever a menu item is chosen, or an accelerator key is pressed. The values of lParam and wParam for the WM_COMMAND are:
wNotifyCode = HIWORD(wParam)
: notification code
wID
= LOWORD(wParam) : item, control, or accelerator identifier
hwndCtl
= lParam : handle of control
which message is from
The
WM_COMMAND handler is where all of the interface to the edit control occurs.
Edit Control Messages
EM_SETSEL is used to set the selection in the edit control. wParam is the starting character position of the selection, and lParam is the ending position. If wParam = 0 and lParam = -1, all the text is selected. If wParam = -1, no text is selected (or a previous selection is de-selected).
EM_SETMODIFY sets or clears the modified flag of the edit control. This flag indicated whether the text has changed. wParam specified the true/false value to set the modified flag to. This is automatically set when the text is first changed. The EM_GETMODIFY message can be used to retrieve the modified flag.
WM_COPY, WM_CUT, WM_PASTE, WM_CLEAR these messages affect the currently selected text, and perform their respective actions. For each, the wParam and lParam parameters are set to 0.
EM_UNDO is used to undo the last edit operation. A second call to WM_UNDO will undo the undo...
There
are many other edit control messages which you can use (I am just too lazy
to write about them all...) For further reading, consult the API
reference...
EditOpenFile / FileOpen
These functions are used to open a file, and load it into the edit control.
EditOpenFile first calls the GetOpenFileName API function to get the filename to open. For this function, you must first fill the OPENFILENAME structure, which contains the information needed to initialize the Open common dialog box. The GetOpenFilaName function returns TRUE if a file was selected, FALSE otherwise. The selected file is returned in the lpstrFile member of the OPENFILENAME structure.
This
filename is then passed to the FileOpen function, which actually opens
the file, and puts it into the edit controls text buffer. It begins
by opening the file with the CreateFile API, using the OPEN_EXISTING parameter.
Next, the file size is determined, so it is known how many bytes to allocate
to store it. The memory buffer is allocated using the HeapAlloc API
function, and Read File is used to copy the contents of the file into the
newly created buffer. This buffer is then copied to the edit control,
by sending it the WM_SETTEXT message. This function ends by closing the
file, and releasing the memory buffer.
EditSaveFile / FileSave
These
functions are very similar to their open counterparts, the only differences
being, instead of reading from the file and writing to the edit control,
it is saved to the file and read from the control.
ConfirmOperation
This is a simple utility function which i use to confirm that the user really wants to do what he says...
The
function checks to see if the edit control has been modified, and if so,
it shows a yes/no message box. This is done by using the MessageBox
API with the MB_YESNO option. It then returns IDYES if the
user chooses yes (or the control has not been modified), or IDNO, if the
user chooses no.
SetTitle
This is another utility function which sets the application title to show the filename of the file currently being edited, or Untitled for a new file.
To do this, it sends the WM_SETTEXT message to the main application window, with the new title as the lParam.
SourceCode
Conclusion
Hmm.. this turned out to be not much of a tutorial on edit controls... as I have added a lot of non-edit control related code in an attempt to prevent the example program from being a completely useless app... Instead it is only a mostly useless app...
Of
course, for a detailed description of Edit Controls, read the Windows API
reference.
For
a plaintext copy: edit_tut.txt
Copyright
(C) 1999
Lord
Lucifer lord-lucifer@usa.net