"Use of GoBug" demonstrations
Messages

These tests demonstrate how GoBug deals with the various messages sent to Testbug's window procedure.

The discussion of these tests takes us into the world of arguments on the stack, stack frames, recursion in the window procedure, and the system's records of window titles. There is also a demonstration of user messages, the use of SendMessage, PostMessage, PostThreadMessage, RegisterWindowMessage, WaitForInputIdle and passing messages between threads.

For each demonstration make sure single-step message break is "on", and you will find it useful to have GoBug's sequential log pane visible (menu item "view, sequential log").

The breakpoints are VARIOUS_MESSAGES and INTERTHREAD_MESSAGES, which can be set using GoBug's menu item "action, run to .. procedure".
   Closely watching SETTEXT and GETTEXT messages in the WndProc
   User messages
   Using PostMessage
   Inter-thread messages

Closely watching SETTEXT and GETTEXT messages in the WndProc
Run to the breakpoint VARIOUS_MESSAGES and be ready to single-step over the code from the breakpoint using F6.
The first message WM_SETTEXT is sent to Testbug's main window to set the text in the window's title bar. The very first parameter sent with this message (lParam) contains the address of the new string. Make a note of this. Next you will see the message in WndProc as a result of the single-step message break. Note from the ESP stackpane that the address of the string is now at [ESP+10h]. Press F5 to enter and execute the code. Note that after EBP is set the address of the string is at [EBP+14h]. Follow the message into the 4 pushes just before the call to DefWindowProc. Make a note of ESP just before the call to DefWindowProc. This denotes the beginning of the stack frame used by the API. Note also that the first push is [EBP+14h], which is the orginal lParam sent to SendMessage. So, in effect, the information given in SendMessage will be sent to DefWindowProc. Now here comes the interesting bit. When you reach DefWindowProc press F6 to execute but jump over it. Now - surprise, you are back in WndProc. What has happened is that DefWindowProc (before returning) has sent the message WM_GETTEXT to the window procedure. You can see the message in the status bar, and note also that "recursion=1". Look at the value of ESP. See that is is now much lower (higher in the stack) than when DefWindowProc was called. In other words, DefWindowProc made a large stack frame for local data before sending WM_GETTEXT. Now look at [ESP+10h], which is where lParam is. Note that this an address within the stack frame which was made by DefWindowProc before sending WM_GETTEXT. Now according to the SDK the GETTEXT message puts the existing title text into a buffer pointed to by lParam. In other words the existing title text will go into the stack. Presumably DefWindowProc needs to find this text and its length before processing the SETTEXT message. Open a data inspector ("inspect, data by address") and look at the area of stack into the value pointed to by lParam. Then single-step down to the DefWindowProc and press F6. Now see that the stack contains the new title text. I suspect what has happened here is that the existing title text was put on the stack by DefWindowProc and its size counted when processing WM_GETTEXT, then it was replaced by the new text which was then counted when processing WM_SETTEXT. Finally the text was sent to memory somewhere to be kept as a record of the window title and the title was then drawn directly. To examine this further lets search the memory. Use the GoBug's menu item "inspect, search promenade", write the new title text "Various messages test" in the search control (must have capital "V"), ensure that the combo box shows a search as an ansi string, make sure that "show search result window" is checked and click the "search now" button. Sure enough you will find the new title string in various places in Testbug's memory and one of them is an area reserved for the User32 heap, that is the area of memory created by User32.Dll, which will be where the window titles are kept. Scroll up and down in the search result inspectors to look at the titles of other windows currently open.

User messages
The second and third messages in the VARIOUS_MESSAGES code are what are called "user messages". These are a very useful way to pass information around your program (to and from functions in the window procedure) particularly if you are using more than one thread. This is because SendMessage does not return until the message has been dealt with. This means that you can make sure that all user-interface is carried out by the main thread of your program (which is good Windows practice). When any secondary thread wants to cause changes to the user-interface, it can send a message to the main thread. The message cannot be dealt with by the main thread if it is busy until it has finished what it is doing. And the secondary thread cannot continue until the main thread has dealt with the message.
User messages are also very useful to send information and data from one window to another, particularly where the data needs to be dealt with by the receiving window immediately (because it may change).
User messages must be 400h. WM_USER has a value of 400h, so user messages are expressed as WM_USER+value. Note that some system messages are also above 400h. See GoBug's message list (menu item "action, run to .. message") for a list of messages and values. These messages would be sent by your application to common controls, so hopefully there will be no conflict with your user messages. However, sometimes you may come across such conflict. An example would be the DM_GETDEFID (value 400h) and DM_SETDEFID (value 401h) sent by the IsDialogMessage api. To avoid such conflict you can add a "signature" to the user message. In Testbug's examples, the message WM_USER+0 has the signature "JG" in lParam, and the message WM_USER+20 has the same signature in wParam. You can of course pass data to the window procedure using these two arguments.

Using PostMessage
SendMessage is fine for sending data and instructions when the message can or must be dealt with immediately. This is because SendMessage does not return until the message has been dealt with. But sometimes this is not what you want at all. You may want to give the information or instruction to the window but return to the system before the instruction is carried out. An obvious example is when you want to destroy a window and its class as well (a window class has its own window procedure) and will take up memory unless it is removed when the window is destroyed. Now you can't call UnregisterClass from within the window to be destroyed, but you can post a message to the main window using PostMessage asking it to call UnregisterClass. The good thing about PostMessage is that it puts the message in the message queue and does not send it directly to the window procedure like SendMessage. Therefore the window procedure does not receive the message until it is ready and the thread has returned to the system. So whereas SendMessage calls the window procedure directly PostMessage simply puts the message in the message queue, to be extracted by the GetMessage/DespatchMessage loop.
To watch PostMessage in action continue to F6 down in the VARIOUS_MESSAGES code to PostMessage and note that unlike when using SendMessage, there appears to be no reaction at all to the call. Single-step down through the rest of the code until the VARIOUS_MESSAGES function is completely finished, continue past DefWindowProc in the window procedure until the very last RET which returns control to the system. Note that the system then calls the window procedure again several times. Yet it has still not dealt with the PostMessage call. Only when the system is ready will it do so. You then see the message which you posted being received in the message loop by GetMessage and then appearing in the window procedure having been sent there by DispatchMessage.
PostMessage is further examined belowinter-thread messages.

Inter-thread messages
These demonstrations use a registered message. A registered message is unique to the system and therefore can be used to send a message from one application to another, however here we merely use the message to pass between threads.
Make sure the single-step message break is "on", go to the breakpoint INTERTHREAD_MESSAGES and single-step from there. You will see the registered message being established, then the new thread being made and passed the id of the current thread (this will be used later so that the new thread can send a message back to the main thread). Since you have single-stepped over CreateThread when the new thread is made, the panes "sweep" to show the change of thread.
Continue single-stepping and watch the progress of the messages. As you do so, you will see from the sweep how the system divides the processor's time between the threads. In the code the series of XOR instructions provide some baffle to help to demonstrate this.
As you continue to single-step you can see that the first SendMessage appears to have no effect. Why is this? Well, in fact, the registered message sent by the first SendMessage does get through to the window procedure. It's just that the system does not establish GoBug's hook (which catches the messages) for the new thread until the first API call. Hence the first message is missed by the hook. This is quite normal, but it is something to watch for when making new threads under GoBug control. In fact, if it is not already loaded in Testbug's memory space, you will see GoBugSpy.dll showing as loaded there soon after the first API call in the new thread.
The next thing the new thread does is to wait for the main thread to clear all messages arising from reaching the breakpoint. This is done by WaitForInputIdle, which is a useful API in sequence critical situations, or where the user-interface needs to finish its job before the secondary thread proceeds. Here it is done to show the passing of messages more clearly. For this reason also, Testbug's timer was switched off before reaching the breakpoint. You will probably see that while the new thread is in WaitForInputIdle, the main thread is given time to complete processing of all outstanding messages.
One thing to note is that the message when using SendMessage is received in the window procedure by the main thread. The message was sent by the new thread but received by the main thread (check this by single-stepping within the window procedure when the message is received - the sending and calling threads will appear in the log). Because the main thread is used to receive such messages, a window procedure would not need to process messages from more than one thread at a time, at least not messages passed by the system.
The same thing happens with PostMessage or PostThreadMessage. The difference, however is that the message is queued and goes through the message loop, and therefore is sent to the main thread only when the system is ready and with nothing else to do. Because the message is queued, it appears in the log as having come from the main thread.
Here is the code:-

INTERTHREAD_MESSAGES:
CMP D[TESTMESSAGE],0    ;see if already have registered testmessage
JNZ >L30                ;yes
PUSH 'TestBug'
CALL RegisterWindowMessageA     ;must be named
MOV [TESTMESSAGE],EAX   ;same value until Windows restarts
L30:
CALL GetCurrentThreadId
PUSH ADDR Thread2AId
PUSH 0,EAX              ;send thread id as a parameter
PUSH ADDR IMMAIN        ;address for new thread to start
PUSH 0,0
CALL CreateThread
XOR EAX,EAX
XOR EAX,EAX
XOR EAX,EAX
XOR EAX,EAX
XOR EAX,EAX
XOR EAX,EAX
RET
;
IMMAIN:
PUSH 0,0,[TESTMESSAGE],[hWnd]
CALL SendMessageA
CALL GetCurrentProcess
PUSH -1,EAX             ;timeout, handle to debuggee process
CALL WaitForInputIdle   ;wait till messages generated by test dealt with
XOR EDX,EDX
XOR EDX,EDX
PUSH 0,0,[TESTMESSAGE],[hWnd]
CALL SendMessageA
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
PUSH 0,0,[TESTMESSAGE],[hWnd]
CALL PostMessageA
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
PUSH 0,0,[TESTMESSAGE],[EBP+0Ch]  ;message sent in wParam, ID of the thread
CALL PostThreadMessageA
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
XOR EDX,EDX
RET