Win32 Programming – Add Message Loop to the Application

In our previous article “Win32 Programming – Register the window class“, we have created our GUI-based Application window and successfully displayed it on the screen. And we observed that the window was closed, immediately; because no user interaction code was added. We had a couple of questions in our previous article; we will try to address those here.

Why Win32 Application window was immediately closed?

Before answering this question; let’s have a look at a simple console-based application.

// hello.cpp
#include <stdio.h>

void main()
    printf("Hello, World!\n");

When we compile and run this simple application; it will display a “Hello, World!” message on the console window and exit the program. Observe that, this application also exits immediately. I hope, now you got the answer; there are no statements to execute or there is no user input added to the code; hence, the application exits, immediately. The same reason applies to our GUI-based Application also; there was no user interaction or statements to execute; that was the reason, our Application window disappears immediately.

So, it is clear that we need to add a user interaction code to our Application.

How to add code to interact with the User inputs?

Usually, for console-based applications, we use printf() method (for display purposes) and scanf () statements to read inputs from the user. Then, process the inputs and display the results to the user. It is so simple, right? But for GUI (Graphical User Interface) based applications it is a bit different. Let’s discuss this.

GUI-based applications are Message or Event-driven. Because they are more interactive. Hence, a user interface is required, to enable the users to interact with the application.

What does it mean, message or event-driven?

Whenever the user clicks the mouse button or presses the key on the keyboard etc., Windows Operating System will generate an appropriate message or event. Like that, there are different events generated by the Operating System. These events have to be handled in respective Applications, to do a particular action.

As mentioned earlier, GUI applications are message-driven; Windows Operating System sends these generated messages to the Applications. So, applications will handle these messages to do the appropriate action.

Windows Operating System sends the generated messages, to a Message Queue of an application (actually it is a Thread’s Message Queue). Application’s responsibility is, to read each message from the Message Queue (actually it is Thread’s responsibility.) and process the message, using its Window Procedure (actually it is Thread’s Window Procedure).

So, what do we have to do in our application to add message processing functionality? We have to provide a Message Loop in our application to retrieve each message from the Message Queue. And provide a Window Procedure to process these messages.

Then what about Message Queue? Do we need to create it in our code? No. This one is already created for each Thread (if Thread creates a window) by the Windows Operating System. So, no need to worry about the creation of a Message Queue.

Adding Message Loop to the Application

Now we have to add Message Loop functionality to our code. This loop fetches each message in the Message Queue and dispatches the message to the Window Procedure. The window Procedure will execute the functionality, based on the generated message.

Let’s discuss how to create a Message Loop.

Step 1. As mentioned above, the Application has to take each message from the Message Queue. We have GetMessage() Win32 API function to do this job for us. The syntax of this function looks like below:

BOOL WINAPI GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

Where lpMsg is an address to hold the MSG structure that receives from the Message Queue. hWnd is a valid window handle, for which the messages are retrieved. wMsgFilterMin and wMsgFilterMax entries are, to filter the messages; that means, GetMessage() function only retrieves the messages whose values are in-between wMsgFilterMin and wMsgFilterMax entries, inclusive. If you want to retrieve all available messages you can just pass the value “0” to these two parameters.

If there is an error while retrieving the message from the Message Queue, this function simply returns the value “-1”.

typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;

Step 2. Now we know how to retrieve messages from Message Queues. Once we have the message, we need to dispatch the message to Window Procedure. To dispatch the message, Win32 provides an API function, DispatchMessage(). The syntax of the function looks like below:

LRESULT WINAPI DispatchMessage(CONST MSG *lpMsg);

Where lpMsg is a pointer to the valid MSG structure. Usually, we pass the MSG structure which is received from GetMessage() method,  through this function.

Step 3. Are we done with our Message Loop? Not really. Another important thing we need to remember is, we need to translate the message, before dispatching them to Window Procedure.

Why do we need to translate the message?

Let’s take a simple example. We press “Alt + F4” key combinations from the keyboard; to close the currently active window. This is the same effect when we click on the “Close” button from the window. Actually, when we press the close button on the window, WM_CLOSE message will be generated.

What does the translated message will do, then? 

Translate messages will translate the virtual-key messages to character messages. These messages will be dispatched to the Application’s Message Queue (actually it is Thread’s message queue). Win32 Provides an API function, TranslateMessage(), to translate virtual messages to character messages.

BOOL WINAPI TranslateMessage(const MSG *lpMsg);

Where lpMsg is a pointer to the valid MSG structure. We have to pass the MSG structure which is received from GetMessage(), through this function.

So, when do we need to call TranslateMessage() function?

We need to call this before dispatching the message to the Message Queue; that means before we call DispatchMessage() function.

Step 4. And, one more important thing we need to consider here is; in our Program, we need to call these functions within the loop; to process the messages, when an event occurred. Events can be triggered by user intervention or by the Operating System. So, all these events are handled through the above functions and by calling them within the loop.

When do we have to terminate the loop, then?

It’s simple, we need to terminate the loop until there are no messages in the message queue.

Complete working code

Step 5. Let’s put it all together in a simple program, and the code looks like below.

// sample.cpp
#include <windows.h>
#include <stdio.h>

int main()

   char szClassName[256] = "SampleWindowClass";

   wc.cbSize = sizeof(WNDCLASSEX); = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc = DefWindowProc;
   wc.cbClsExtra = 0;
   wc.cbWndExtra = 0;
   wc.hInstance = (HINSTANCE) GetModuleHandle(NULL);
   wc.hIcon = NULL;
   wc.hCursor = NULL;
   wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
   wc.lpszMenuName = NULL;
   wc.lpszClassName = szClassName;
   wc.hIconSm = NULL;

   ATOM atom = RegisterClassEx(&wc);
   if ( atom == 0 )
       return 0;

   MSG msg;
   HWND hWnd = CreateWindow(szClassName, "My first GUI window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 400, 400, NULL, NULL, NULL, NULL);
   if ( hWnd != NULL )
       while ( GetMessage(&msg, hWnd, 0, 0) != -1 )

   return 0;

Step 6. Let’s compile & run the above code. And observe that an Application window opened, and that doesn’t disappear unless you click on the Close button on the window. That means, we have successfully added, user interaction code to our Application.

That concludes this series of articles and I hope you enjoyed these Articles. Please post your feedback in the comments section.


Win32 Programming – Add Message Loop to the Application

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top