More on SendMessage
SendMessage is the way by which communication between the various application/windows and the operating system takes place and the events fired by the application are the result of execution of these messages. While SendMessage provides way for communicating with other applications, it also handling the controls within the application in more efficient manner.
My previous post “Adding File Names to a ListBox” contains a procedure AddToList which searches the listbox for a specific string and if not found adds it to the list. While the part-1 of post handled this in a traditional way by looping through all list items, part-2 applied it using SendMessage Call with fewer lines of code.
Now that I sat down to elaborate this function, I thought of doing something that cannot be done without a SendMessage call, i.e. Pressing two buttons by a single click.
Since SendMessage function exists in User32.dll, we will have to declare the function in our project which we do by following lines.
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long
The function takes four parameters :
First, Handle of the control we are sending message to. If the control exists within the same application from where we are generating the message, the handle can be obtained by accessing the “hWnd” property of the control, otherwise we would have to make API calls as we did in the previous post to get the handle.
Second, the message that we are sending to the controls, of data type long. To make it more readable and global it is expected that Contants with standard names be defined before calling SendMessage. List of all supported Messages are available in Winuser.h, Search for it in Visual Studio installation and find “Window Messages”. Since this file is included by Windows.h, C++ developers do not require to seperately define them.
Next two parameters wParam and lParam are additional parameters passed with the message, and their values depends on the message being sent.
Now create a new project. Add the declaration line mentioned above in the code section of the form, as well as the constant for message which we would be using now.
Private Const BM_SETSTATE = &HF3

Add two buttons on the form named Command1 and Command2 and the following code in the Code Section.
Private Sub Command1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
SendMessage Command2.hwnd, BM_SETSTATE, 1, ""
End Sub
Private Sub Command1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
SendMessage Command2.hwnd, BM_SETSTATE, 0, ""
End Sub
Now execute the code and click on the Command1 button. That’s it. BM_SETSTATE message instructs the Button to change its state according to value sent by wParam. “1″ signifies “Down” state and “0″ the “Up” state. Notice the empty string sent for lParam, as BM_SETSTATE requires only one additional parameter, and as these parameters are not optional.
So, when the mouse was clicked the MouseDown event of Command1 was fired, and when mouse was released MouseUp event was fired. Did these events fire for Command2 also? We saw it clicking! Let’s check it by adding below code to the form.
Private Sub Command2_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Command2.Caption = "Down"
End Sub
Private Sub Command2_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Command2.Caption = "Up"
End Sub
If these events really happened the caption on the second button should change. Execute and check. No! the message just changed the state of the button and did not fire the events as would have happened when clicked on that button.
Add other message constants to the code
Private Const WM_LBUTTONDOWN = &H201 Private Const WM_LBUTTONUP = &H202
and the code below to Command1_MouseDown sub
SendMessage Command2.hwnd, WM_LBUTTONDOWN, 1, ""
and this line to Command2_MouseUp sub
SendMessage Command1.hwnd, WM_LBUTTONUP, 0, ""
The wParam sends the virtual keys that are down and can be Left Mouse Button (1), Right Mouse Button (2), Shift Button (4), Control Button (8), Middle Mouse Button (16) or combinations of them.
The lParam requires the location of mouse relative to top-left of the control to be sent, we are sending empty string which doesnot affect it’s working as expected now.
Execute the code. When Mouse is clicked on Command1 the MouseDown event for Command1 fires, which calls SendMessage to fire MouseDown event of Command2. When mouse is released the MouseUp event of Command2 fires (Not of Command1) and which then calls SendMessage to fire MouseUp event of Command1
Now that all events are fired the buttons have stopped functioning as intended, that’s because all events occured while the mouse was on a sigle position over Command1, Windows(OS) generated SendMessages caused this problem. We can get over it by patching up a little. Let me rewrite the complete code here.
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long
Private Const BM_SETSTATE = &HF3
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Sub Command1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
SendMessage Command2.hwnd, WM_LBUTTONDOWN, 1, ""
SendMessage Command2.hwnd, BM_SETSTATE, 1, ""
End Sub
Private Sub Command1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
SendMessage Command2.hwnd, BM_SETSTATE, 0, ""
End Sub
Private Sub Command2_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Command2.Caption = "Down"
SendMessage Command1.hwnd, BM_SETSTATE, 1, ""
End Sub
Private Sub Command2_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Command2.Caption = "Up"
SendMessage Command1.hwnd, WM_LBUTTONUP, 0, ""
SendMessage Command1.hwnd, BM_SETSTATE, 0, ""
End Sub
Private Sub Command2_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Y < 0 Then
SendMessage Command2.hwnd, BM_SETSTATE, 1, ""
End If
End Sub
The Command_MouseMove sub added here patches for the error that occured due to difference between location of mouse and the Control when event was fired. Now our code not only shows the two button clicking at the same time. but fires all relevent events as well.
This is just a minute fraction of what SendMessage can do, and there is lot to explore. May be we will later take up some interesting problem to solve through SendMessage.

[...] form. Getting a window text or setting it requires calling the SendMessage function (described in More on SendMessage) with messages WM_GETTEXT and WM_SETTEXT [...]
Pingback by WinAPI : Getting Window Texts « Jalaj — February 1, 2007 @ 5:26 am
[...] : Starting with Device ContextWinAPI : Working with Windows HandlesWinAPI : GetPixel FunctionMore on SendMessageGetting Window HandlesWinAPI : Prevent Setting foreground windowWinAPI : Making Form [...]
Pingback by Accessing System Tray from Application « Jalaj — March 16, 2007 @ 3:59 am
[...] More on SendMessage [...]
Pingback by Google Toolbar PR Update « Jalaj — July 17, 2007 @ 6:40 am