Introduction
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
WinMain
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
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
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
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
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_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
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
ConfirmOperation
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
To do this, it sends the
WM_SETTEXT
message to the main application window, with the new title as the lParam.
Conclusion
Of course, for a detailed
description of Edit Controls, read the Windows API reference.
For a plaintext copy: edit_tut.txt