static BOOL CALLBACK DialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
break;
case WM_CLOSE:
EndDialog(hwndDlg,0);
return TRUE;
}
return FALSE;
A dialog box procedure is called by the system. It has then, a fixed argument interface, and should return a predefined value. It receives from the system the handle of the dialog box window, the message, and two extra parameters.
Normally these procedures are a big switch statement that handles the messages the program is interested in. The return value should be TRUE if the dialog box procedure has handled the message passed to it, FALSE otherwise.
The general form of a switch statement is very simple: you have the switch expression that should evaluate to an integer and then you have several "cases" that should evaluate to compile time constants.
All those names in the switch statement above are just integers that have been given a symbolic name in windows.h using the preprocessor #define directive. A "break" keyword separates one "case" from the next one.
Note that in C a case statement can finish without a break keyword.
In that case J execution continues with the code of the next case. In any case, of course, a return statement finishes execution of that case, since control is immediately passed to the calling function.
In this procedure we are interested in only three messages, hence we have only three "cases" in our switch:
WM_INITDIALOG. This message is sent after the window of the dialog box has been created, but before the dialog is visible in the screen. Here is done the initialization of the dialog box data structures, or other things. The wizard inserts here a call to a procedure for handling this message.
WM_COMMAND. This message is sent when one of the controls (or child windows if you want to be exact) has something to notify to the dialog: a button has been pressed, a check box has been pressed, data has been entered in an entry field, etc. Since we can have several controls, we use again a switch statement to differentiate between them. Switch statements can be nested of course.
WM_CLOSE. This message arrives when the user has pressed the "close" button in the system menu, or has typed the Alt+F4 keyboard shortcut to close the dialog.
Now, the whole purpose of this exercise is to input a character string. The text is entered by the user in our entry field. It is important, from a user's perspective, that when the dialog box is displayed, the cursor is at the beginning of the entry field. It could be annoying to click each time in the entry field to start editing the text. We take care of this by forcing the focus to the entry field.
Under windows, there is always a single window that has the focus, i.e. receives all the input from the keyboard and the mouse. We can force a window to have the focus using the SetFocus API.
static int InitializeApp(HWND hDlg,WPARAM wParam, LPARAM lParam)
We add this call in the procedure InitializeApp. We test, and. it doesn't work. We still have to click in the edit field to start using it. Why?
Because, when we read the documentation of the WM_INITDIALOG message it says:
WM_INITDIALOG
hwndFocus = (HWND) wParam; // handle of control to receive focus
lInitParam = lParam; // initialization parameter
Parameters
hwndFocus
Value of wParam. Identifies the control to receive the default keyboard focus. Windows assigns the default keyboard focus only if the dialog box procedure returns TRUE.
Well, that is it! We have to return FALSE, and our SetFocus API will set the focus to the control we want. We change that, and. it works! Another bug is gone.
Note that the SetFocus API wants a window handle. To get to the window handle of a control in the dialog box we use its ID that we took care of defining in the dialog editor. Basically we give to the SetFocus function the result of calling the API GetDlgItem. This is nice, since we actually need only one window handle, the window handle of the dialog box that windows gives to us, to get all other window handles of interest.
Now comes a more difficult problem. When the user presses the OK button, we want to get the text that he/she entered. How do we do that?
We have two problems in one: the first is to decide when we want to get the text, and the other is how to get that text.
For the first one the answer is clear. We want to read the text only when the user presses the OK button. If the Cancel button is pressed, or the window is closed, we surely aren't interested in the text, if any. We will read the text then when we handle the message that the OK button window sends to us when is pressed. We change our dialog procedure like this:
case WM_COMMAND:
switch (LOWORD(wParam))
break;
We add a call to a function that will get the text into a buffer. That function looks like this:
static char buffer[1024];
int ReadText(HWND hwnd)
return 0;
We define a buffer that will not be visible from other modules, hence static. We set a fixed buffer with a reasonable amount of storage.
Our function cleans the buffer before using it, and then calls one of the workhorses of the dialog procedures: the API GetDlgItemText. This versatile procedure will put in the designated buffer, the text in a control window, in this case the text in the entry field. We again indicate to the API which control we are interested in by using its numerical ID. Note that GetDlgItemText returns the number of characters read from the control. If there isn't anything (the user pressed OK without entering any text), GetDlgItemText returns zero.
The first time that we do that; we will surely will want to verify that the text we are getting is the one we entered. To do this, we use the API MessageBox that puts up a message in the screen without forcing us to register a window class, define yet another window procedure, etc.
We add then to our window procedure, the following lines:
case IDOK:
if (ReadText(hwndDlg))
return 1;
MessageBox takes a parent window handle, in this case the handle of the dialog box procedure, a buffer of text, a title of the message box window, and several predefined integer constants, that indicate which buttons it should show. We want just one button called OK, so we pass that constant.
Note too, that if the user entered no text, we do NOT call the EndDialog API, so the dialog box will refuse to close, even if we press the OK button. We force the user to enter some text before closing the dialog. Since we haven't changed anything in the logic for the Cancel button, the dialog box will still close when the user presses those buttons. Only the behavior of the OK button will change.
The EndDialog API takes two parameters: the dialog box window handle that it should destroy, and a second integer parameter. The dialog box will return these values as the result of the DialogBox call from WinMain remember?
Since WinMain returns itself this value as its result, the value returned by the DialogBox will be the return value of the program.
|