SendDlgItemMessage proto hwndDlg:DWORD,\This API call is immensely useful for interacting with a child window control. For example, if you want to get the text from an edit control, you can do this:
idControl:DWORD,\
uMsg:DWORD,\
wParam:DWORD,\
lParam:DWORD
call 'USER32.SendDlgItemMessageA' D§hDlg ID_EDITBOX &WM_GETTEXT 256 text_bufferIn order to know which message to send, you should consult your Win32 API reference.
Proc DlgProc:The dialog box procedure is very similar to a window procedure except for the type of return value which is TRUE/FALSE instead of LRESULT. The internal dialog box manager inside Windows IS the true window procedure for the dialog box. It calls our dialog box procedure with some messages that it received. So the general rule of thumb is that: if our dialog box procedure processes a message,it MUST return TRUE in eax and if it does not process the message, it must return FALSE in eax. Note that a dialog box procedure doesn't pass the messages it does not process to the DefWindowProc call since it's not a real window procedure.
Arguments @hDlg, @iMsg, @wParam, @lParam
[WindowClassEx:
wc_Size: len wc_style: &CS_HREDRAW+&CS_VREDRAW
WndProc: MainWindowProc
wc_ClsExtra: 0 wc_WndExtra: DLGWINDOWEXTRA
hInstance: 0
wc_hIcon: 0 wc_hCursor:
0
wc_hbrBackground: 16
wc_MenuName: 2000 wc_ClassName: ClassName
wc_hIconSm: 0]
[ClassName:
'DLGCLASS' 0 AppName: 'Our First Window' 0]
[TestString:
"Wow! I'm in an edit box now" 0]
[DlgName:
'MyDialog' 0 MenuName: 'MyMenu' 0]
[FirstMessage: 0 #7] [Buffer: B§ 0 #512] [hDlg: 0 WindowHandle: 0]
[IDC_EDIT 3000 IDC_BUTTON 3001 IDC_EXIT 3002 IDM_EXIT 2]
[M00_Menu
2100 M00_Test_Controls
2101 M00_Get_Text 2102
M00_Clear_Text
2103 M00_Exit 2104]
[MyDialogID 2000]
____________________________________________________________________________________________
____________________________________________________________________________________________
Main:
call 'Kernel32.GetModuleHandleA' &NULL | mov D§hInstance
eax
call 'User32.LoadIconA' 0 &IDI_WINLOGO | mov D§wc_hIcon
eax D§wc_hIconSm eax
call 'User32.LoadCursorA' 0 &IDC_ARROW | mov D§wc_hCursor
eax
call 'User32.RegisterClassExA' WindowClassEX
call 'User32.CreateDialogParamA' D§hInstance MyDialogID &NULL
&NULL &NULL | mov D§hDlg eax
call 'User32.GetDlgItem' D§hDlg IDC_EDIT
call 'User32.SetFocus' eax
call 'User32.ShowWindow' D§hDlg &SW_SHOWNORMAL
call 'User32.UpdateWindow' D§hDlg
L1:
call 'User32.GetMessageA' FirstMessage 0 0 0 | cmp eax 0 | je L9>
call 'User32.IsDialogMessage' D§hDlg FirstMessage
If eax = 0
call 'User32.TranslateMessage' FirstMessage
call 'User32.DispatchMessageA' FirstMessage
End_If
jmp L1<
L9:
call 'Kernel32.ExitProcess' 0
____________________________________________________________________________________________
Proc
MainWindowProc:
Arguments @Adressee, @Message, @wParam, @lParam
pushad
...If D@Message = &WM_DESTROY
call 'User32.PostQuitMessage' &NULL
...Else_if D@Message = &WM_CREATE
call 'User32.SetDlgItemTextA' D@Adressee IDC_EDIT AppName
...Else_if D@Message = &WM_COMMAND
mov eax D@wParam
..If D@lParam = 0
.If ax = M00_Get_Text
call 'User32.GetDlgItemTextA' D@Adressee IDC_EDIT buffer 512
call 'User32.MessageBoxA' &NULL buffer AppName &MB_OK
.Else_If ax = M00_Clear_Text
call 'User32.SetDlgItemTextA' D@Adressee IDC_EDIT &NULL
.Else
call 'User32.DestroyWindow' D@Adressee
.End_If
..Else
mov edx D@wParam | shr edx 16
.If dx = &BN_CLICKED
If ax = IDC_BUTTON
call 'User32.SetDlgItemTextA' D@Adressee IDC_EDIT TestString
Else_If ax = IDC_EXIT
call 'User32.SendMessageA' D@Adressee &WM_COMMAND IDM_EXIT 0
End_If
.ENDIF
..End_If
...Else
popad
call 'User32.DefWindowProcA' D@Adressee D@Message D@wParam D@lParam
Exit
...End_If
popad | mov eax &FALSE
EndP
The interesting part the assembly source code is in the window class structure:
wc_WndExtra: DLGWINDOWEXTRA
wc_ClassName: ClassName
Normally,
this member is left NULL, but if we want to register a dialog box template
as a window class, we must set this member to the value DLGWINDOWEXTRA.
Note that the name of the class must be identical to the one following
the CLASS keyword in the dialog box template. The remaining members
are initialized as usual. After you fill the window class structure, register
it with RegisterClassEx. Seems familiar? This is the same routine you have
to do in order to register a normal window class.
L1:
call 'User32.GetMessageA' FirstMessage 0 0 0 | cmp eax 0 | je L9>
call 'User32.IsDialogMessage' D§hDlg FirstMessage
If eax = 0
call 'User32.TranslateMessage' FirstMessage
call 'User32.DispatchMessageA' FirstMessage
End_If
jmp L1<
The
program enters the message loop and before we translate and dispatch messages,
we call IsDialogMessage function to let the dialog box manager handles
the keyboard logic of our dialog box for us. If this function returns TRUE
, it means the message is intended for the dialog box and is processed
by the dialog box manager. Note another difference from the previous tutorial.
When the window procedure wants to get the text from the edit control,
it calls GetDlgItemText function instead of GetWindowText. GetDlgItemText
accepts a control ID instead of a window handle. That makes the call easier
in the case you use a dialog box.
;
menu equates (given by the editor):
[M00_Menu
1000
M00_Test_Controls 1001
M00_Get_Text 1002
M00_Clear_Text
1003
M00_Exit 1004]
;
Controls equates (set by me):
[IDC_BUTTON
3001 IDC_EXIT 3002 IDC_EDIT 3000]
_____________________________________________________________________________________
Main:
call 'Kernel32.GetModuleHandleA' 0 | mov D§hInstance eax
call 'USER32.DialogBoxParamA' 0 1000 0 DialogProc 0
call 'Kernel32.ExitProcess' 0
______________________________________________________________________________________
Proc
DialogProc:
Arguments @Adressee, @Message, @wParam, @lParam
pushad
.If D@message = &WM_COMMAND
mov eax D@wParam
..If D@lParam = 0
If ax = M00_Get_Text
call 'USER32.GetDlgItemTextA' D@Adressee IDC_EDIT buffer 512
call 'USER32.MessageBoxA' &NULL buffer AppName &MB_OK
Else_If ax = M00_Clear_Text
call 'USER32.SetDlgItemTextA' D@adressee IDC_EDIT &NULL
Else_If ax = M00_Exit
call 'USER32.EndDialog' D@adressee 0
End_If
..Else
mov edx D@wParam | shr edx 16
...If dx = &BN_CLICKED
If ax = IDC_BUTTON
call 'USER32.SetDlgItemTextA' D@adressee IDC_EDIT TestString
Else_If ax = IDC_EXIT
call 'USER32.SendMessageA' D@adressee &WM_COMMAND M00_Exit 0
End_If
...End_If
..End_If
.Else_If D@message = &WM_INITDIALOG
call 'USER32.GetDlgItem' D@adressee IDC_EDIT
call 'USER32.SetFocus' eax
.Else_If D@message = &WM_CLOSE
call 'USER32.SendMessageA' D@adressee &WM_COMMAND M00_Exit 0
.Else
L8:
popad | mov eax &FALSE | Exit
.End_If
L9:
popad | mov eax &TRUE
EndP
call 'USER32.DialogBoxParamA' 0 1000 0 DialogProc 0
The
above line calls DialogBoxParam function which takes 5 parameters: the
instance handle, the name of the dialog box template, the parent window
handle, the address of the dialog box procedure, and the dialog-specific
data. DialogBoxParam creates a modal dialog box. It will not return until
the dialog box is destroyed.
.Else_If D@message = &WM_INITDIALOG
call 'USER32.GetDlgItem' D@adressee IDC_EDIT
call 'USER32.SetFocus' eax
.Else_If D@message = &WM_CLOSE
call 'USER32.SendMessageA' D@adressee &WM_COMMAND M00_Exit 0
The
dialog box procedure looks like a window procedure except that it doesn't
receive WM_CREATE message. The first message it receives is WM_INITDIALOG.
Normally you can put the initialization code here. Note that you must return
the value TRUE in eax if you process the message.
The
internal dialog box manager doesn't send our dialog box procedure the WM_DESTROY
message by default when WM_CLOSE is sent to our dialog box. So if we want
to react when the user presses the close button on our dialog box, we must
process WM_CLOSE message. In our example, we send WM_COMMAND message with
the value M00_EXIT in wParam. This has the same effect as when the user
selects Exit menu item. EndDialog is called in response to M00_EXIT.
The
processing of WM_COMMAND messages remains the same.
When
you want to destroy the dialog box, the only way is to call EndDialog function.
Do not try DestroyWindow! EndDialog doesn't destroy the dialog box immediately.
It only sets a flag for the internal dialog box manager and continues to
execute the next instructions.