Introduction

Welcome back to Interactive Controls and Layouts. We are now in Lesson 3, and our small app already features a label, a text box, and a button. This marks significant progress at this stage of the course, as the window now resembles a functional interface rather than an empty frame.

In this lesson, we will make that interface respond to user actions. More specifically, we will handle the WM_COMMAND message, extract useful information from it, and detect when our Submit button is actually clicked. This is an important step because, once we can recognize a control event, we can start attaching real program behavior to it.

How A Button Reaches Our Code

A button does not execute our application logic on its own. In WinAPI, the button is a child control; when the user interacts with it, Windows sends a message to the parent window. For standard control actions, that message is typically WM_COMMAND.

The advantage is that WM_COMMAND does not merely indicate that something happened; it also carries details regarding which control sent the message and what type of event occurred. That is exactly what we need here. Our job is to read those details carefully so that we respond only to the correct control and the correct action.

Rebuilding The Interface In WM_CREATE

Before we can react to a click, the controls must first exist. Therefore, just as in the previous lessons, we begin inside WM_CREATE, where the window sets up its child controls.

The function begins with the familiar WindowProc signature and then switches on uMsg to determine what kind of message is being handled. Inside WM_CREATE, we retrieve the application instance with GetWindowLongPtr and then recreate the label and edit control from the earlier units. This keeps our interface complete: the label provides context, and the edit box provides a place to type. Even though this lesson focuses on button clicks, these controls still matter because they define the window with which we are interacting.

Placing The Button We Want To Detect

With the label and edit field in place, we add the button that will send the command we care about.

This call creates a standard BUTTON control with the text Submit. The position places it neatly below the input field, and (HMENU)ID_BUTTON_ACTION assigns the identifier that we will check later. The style BS_DEFPUSHBUTTON gives it the appearance of a default push button, which is common in simple forms. Finally, return 0; informs Windows that we handled WM_CREATE successfully and finished setting up this part of the window.

Reading The Data Inside WM_COMMAND

Now we arrive at the heart of the lesson: processing the command message sent by the control.

In WinAPI, the wParam parameter is often used to "pack" multiple pieces of information into a single value to keep message passing efficient. On a 32-bit level, this value is split into two 16-bit segments called words:

  1. LOWORD(wParam): This macro extracts the lower 16 bits (bits 0–15). In the context of WM_COMMAND, this segment holds the Control Identifier. This is the unique ID we assigned to the control when we created it (e.g., ID_BUTTON_ACTION).
  2. HIWORD(wParam): This macro extracts the upper 16 bits (bits 16–31). This segment holds the Notification Code, which describes the specific action that occurred, such as a button click or an edit box gaining focus.

By using these macros, we can cleanly separate the who (the ID) from the what (the event) without performing manual bitwise shifts or masking. This allows a single message to convey both the source and the action. This is why WM_COMMAND is so useful in WinAPI interfaces.

Checking For The Right Control And Event

Once we have both values, we can be precise. We first check whether the command originated from our button, and then we confirm that the event is a normal click.

This nested structure is simple but very important. wmId == ID_BUTTON_ACTION ensures we are responding only to the Submit button. Then wmEvent == BN_CLICKED ensures the specific button event is a standard click. If both checks pass, we show a message box using MessageBoxW. Currently, that message box is simply a clear signal that our event handling works. In the next unit, this same location in the code will become much more useful as we will retrieve text from the edit control and perform a meaningful action with it.

Conclusion and Next Steps

In this lesson, we transitioned from drawing controls to reacting to them. We maintained the interface from the previous units, added the WM_COMMAND branch, extracted the control identifier using LOWORD(wParam), extracted the notification code using HIWORD(wParam), and used both checks together to detect a real button click with BN_CLICKED.

That pattern is one of the core ideas behind interactive WinAPI programs. Once we can determine which control sent a message and what event it reported, we can attach real behavior with confidence. In the upcoming practice tasks, we will apply this message handling flow ourselves so that button events start feeling natural and easy to trace.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal