Using Edit Controls

Edit controls are typically used in dialog boxes, but you can use them in the client area of a standard window as well. Single-line edit controls are useful for retrieving a single string from the user. Multiline edit controls make it easy for your application to implement most of the features of a simple word processor.

The following topics are discussed in this section.

Simple Word Processing with an Edit Control

The following example implements much of the functionality of a simple word processor by filling the client area of a window with a multiline edit control. The system automatically performs Wordwrap operations for this edit control and also handles the processing for the vertical scroll bar (created by specifying ES_AUTOVSCROLL in the call to the CreateWindow function). The WM_COMMAND message processes menu items; they allow the user to undo the previous action, cut or copy selections to the clipboard, paste text from the clipboard, and delete the current selection.

LONG APIENTRY MainWndProc(HWND hwnd,                // window handle 
                          UINT message,             // type of message 
                          WPARAM wParam,            // additional information 
                          LPARAM lParam)            // additional information 
{ 
    static HWND hwndEdit; 
 
    CHAR lpszTrouble[] = "When in the Course of human Events " 
                         "it becomes necessary for one People " 
                         "to dissolve the Political Bands which " 
                         "have connected them with another, and " 
                         "to assume among the Powers of the " 
                         "Earth, the separate and equal Station " 
                         "to which the Laws of Nature and of " 
                         "Nature's God entitle them, a decent " 
                         "Respect to the Opinions of Mankind " 
                         "requires that they should declare the " 
                         "causes which impel them to the " 
                         "Separation. "; 
 
    switch (message) 
    { 
        case WM_CREATE: 
            hwndEdit = CreateWindow("EDIT",      // predefined class 
                                    NULL,        // no window title 
                                    WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
                                    ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 
                                    0, 0, 0, 0,  // set size in WM_SIZE message 
                                    hwnd,        // parent window 
                                    (HMENU) ID_EDITCHILD,   // edit control ID 
                                    (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), 
                                    NULL);       // pointer not needed 
 
            // Add text to the window. 
            SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM) lpszTrouble); 
 
            return 0; 
 
        case WM_COMMAND: 
            switch (wParam) 
            { 
                case IDM_EDUNDO: 
                    // Send WM_UNDO only if there is something to be undone. 
 
                    if (SendMessage(hwndEdit, EM_CANUNDO, 0, 0)) 
                        SendMessage(hwndEdit, WM_UNDO, 0, 0); 
                    else 
                    {
                        MessageBox(hwndEdit, 
                                   "Nothing to undo.", 
                                   "Undo notification", 
                                   MB_OK); 
                    }
                    break; 
 
                case IDM_EDCUT: 
                    SendMessage(hwndEdit, WM_CUT, 0, 0); 
                    break; 
 
                case IDM_EDCOPY: 
                    SendMessage(hwndEdit, WM_COPY, 0, 0); 
                    break; 
 
                case IDM_EDPASTE: 
                    SendMessage(hwndEdit, WM_PASTE, 0, 0); 
                    break; 
 
                case IDM_EDDEL: 
                    SendMessage(hwndEdit, WM_CLEAR, 0, 0); 
                    break; 

                case IDM_PASSWORD: 
                    DialogBox(hinst,                // current instance 
                              "PassBox",            // resource to use 
                              hwnd,                 // parent handle 
                              (DLGPROC) PassProc); 
                    break; 

                case IDM_WRAP: 
                    SendMessage(hwndEdit, 
                                EM_SETWORDBREAKPROC, 
                                (WPARAM) 0, 
                                (LPARAM) (EDITWORDBREAKPROC) WordBreakProc); 

                    SendMessage(hwndEdit, 
                                EM_FMTLINES, 
                                (WPARAM) TRUE, 
                                (LPARAM) 0); 

                    SendMessage(hwndEdit, 
                                EM_SETSEL, 
                                0, -1);             // select all text 

                    SendMessage(hwndEdit, WM_CUT, 0, 0); 

                    SendMessage(hwndEdit, WM_PASTE, 0, 0); 
                    break; 

                case IDM_ABOUT: 
                    DialogBox(hinst,                // current instance 
                              "AboutBox",           // resource to use 
                              hwnd,                 // parent handle 
                              (DLGPROC) About); 
                    break; 

                default: 
                    return DefWindowProc(hwnd, message, wParam, lParam); 
            } 
            break; 

        case WM_SETFOCUS: 
            SetFocus(hwndEdit); 
            return 0; 

        case WM_SIZE: 
            // Make the edit control the size of the window's client area. 

            MoveWindow(hwndEdit, 
                       0, 0,                  // starting x- and y-coordinates 
                       LOWORD(lParam),        // width of client area 
                       HIWORD(lParam),        // height of client area 
                       TRUE);                 // repaint window 
            return 0; 

        case WM_DESTROY: 
            PostQuitMessage(0); 
            return 0; 

        default: 
            return DefWindowProc(hwnd, message, wParam, lParam); 
    } 
    return NULL; 
}

Using Single Line Edit Controls

The example in this section demonstrates how to use a window procedure to produce a dialog box that prompts the user to enter a password.

The single-line edit control in the Password dialog box has the ES_PASSWORD style. By default, edit controls with this style display an asterisk for each character the user types.

Microsoft Windows XP: If an edit control is from user32.dll, an asterisk is the default character for the ES_PASSWORD style. However, if an edit control is from comctl32.dll version 6, a black circle is the default character for the ES_PASSWORD style.

Note  Comctl32.dll version 6 is not redistributable but it is included in Microsoft Windows XP or later. To use Comctl32.dll version 6, specify it in a manifest. For more information on manifests, see Using Windows XP Visual Styles.

This example however, uses the EM_SETPASSWORDCHAR message to change the default character from an asterisk to a plus sign (+).

This window procedure changes the default push button from CANCEL to OK as soon as the user enters text in the edit control. If the user presses the OK button, the window procedure uses the EM_LINELENGTH and EM_GETLINE messages to retrieve the text.

LRESULT CALLBACK PassProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    CHAR lpszPassword[16]; 
    WORD cchPassword; 

    switch (message) 
    { 
        case WM_INITDIALOG: 
            // Set password character to a plus sign (+) 
            SendDlgItemMessage(hDlg, 
                               IDE_PASSWORDEDIT, 
                               EM_SETPASSWORDCHAR, 
                               (WPARAM) '+', 
                               (LPARAM) 0); 

            // Set the default push button to "Cancel." 
            SendMessage(hDlg, 
                        DM_SETDEFID, 
                        (WPARAM) IDCANCEL, 
                        (LPARAM) 0); 

            return TRUE; 

        case WM_COMMAND: 
            // Set the default push button to "OK" when the user enters text. 
            if(HIWORD (wParam) == EN_CHANGE && 
                                LOWORD(wParam) == IDE_PASSWORDEDIT) 
            {
                SendMessage(hDlg, 
                            DM_SETDEFID, 
                            (WPARAM) IDOK, 
                            (LPARAM) 0); 
            }
            switch(wParam) 
            { 
                case IDOK: 
                    // Get number of characters. 
                    cchPassword = (WORD) SendDlgItemMessage(hDlg, 
                                                            IDE_PASSWORDEDIT, 
                                                            EM_LINELENGTH, 
                                                            (WPARAM) 0, 
                                                            (LPARAM) 0); 
                    if (cchPassword >= 16) 
                    { 
                        MessageBox(hDlg, 
                                   "Too many characters.", 
                                   "Error", 
                                   MB_OK); 

                        EndDialog(hDlg, TRUE); 
                        return FALSE; 
                    } 
                    else if (cchPassword == 0) 
                    { 
                        MessageBox(hDlg, 
                                   "No characters entered.", 
                                   "Error", 
                                   MB_OK); 

                        EndDialog(hDlg, TRUE); 
                        return FALSE; 
                    } 

                    // Put the number of characters into first word of buffer. 
                    *((LPWORD)lpszPassword) = cchPassword; 

                    // Get the characters. 
                    SendDlgItemMessage(hDlg, 
                                       IDE_PASSWORDEDIT, 
                                       EM_GETLINE, 
                                       (WPARAM) 0,       // line 0 
                                       (LPARAM) lpszPassword); 

                    // Null-terminate the string. 
                    lpszPassword[cchPassword] = 0; 

                    MessageBox(hDlg, 
                               lpszPassword, 
                               "Did it work?", 
                               MB_OK); 

                    // Call a local password-parsing function. 
                    ParsePassword(lpszPassword); 

                    EndDialog(hDlg, TRUE); 
                    return TRUE; 

                case IDCANCEL: 
                    EndDialog(hDlg, TRUE); 
                    return TRUE; 
            } 
            return 0; 
    } 
    return FALSE; 
    
    UNREFERENCED_PARAMETER(lParam); 
}