My first Windows application

First Windows application

  • There are four steps to create a window application:

    1. Register window class
    2. create a window
    3. Display window
    4. update windows
  • Window class WNDCLASS

    • Window class is not a class in C + +, but can be understood as "category"

    • A window class is a template used to create a window

    • Each window class has a window procedure (WndProc), which is responsible for processing all messages sent to this kind of window

    • Before creating a certain type of window, you must register the window class

    • There are three kinds of window classes

      • System window class
        • Internal use of the system
      • Application global window class
        • Register the window with CS_ The window class registered with globalclass flag (that is, when CS_GLOBALCLASS is in the style attribute)
        • In this process, all modules of this window class can be used (modules are generally dynamic library modules), and many skin libraries of some programs are implemented in this form
      • Application local window class
        • The window was not registered with CS_ The window class registered with globalclass flag (that is, when CS_GLOBALCLASS is not in the style attribute)
        • This window class can only be used within the scope of modules and is not visible to other modules
    •   // WNDCLASS window class structure
        typedef struct tagWNDCLASSA {
            UINT style;//Style of window class
            WNDPROC lpfnWndProc;//Window procedure function, which is responsible for processing all information sent to the window
            int cbClsExtra;//Specifies the number of extra bytes to allocate after the window class structure. The system initializes bytes to zero
            int cbWndExtra;//Specifies the number of extra bytes to allocate after the window instance. The system initializes bytes to zero
            HINSTANCE hInstance;//Instance handle of the window
            HICON hIcon;//The icon used by the window class
            HCURSOR hCursor;//The cursor used by the window class
            HBRUSH hbrBackground;//The background brush used by this window class
            LPCSTR lpszMenuName;//The name of the menu resource used by the window class
            LPCSTR lpszClassName;//Name of this window class
        } WNDCLASSA;
      
    • The optional value of the style property of the window class. If you want to use multiple at the same time, you can use | connection

      • CS_HREDRAW redraws the entire window when the horizontal length changes or moves the window
      • CS_VREDRAW redraws the entire window when the vertical length changes or moves the window
      • CS_NOCLOSE disables the close option of the system menu
      • CS_DBLCLKS allows you to send the message of double clicking the mouse button to the window
      • CS_DROPSHADOW turns on border shadow
  • Register the window class using the RegisterClass function

    • There is only one parameter, which is a pointer to the WNDCLASS structure
    • If the function succeeds, the return value is an ATOM type (essentially an unsigned short type), which is a unique identifier
    • If the function fails and returns 0, you can call the GetLastError function to get the reason for the failure
    •   ATOM WINAPI RegisterClass(
            const WNDCLASS *lpWndClass  //Long pointer to WNDCLASS structure
        );
      
  • Use the CreateWindow function to create a window

    •   HWND WINAPI CreateWindow (
            LPCTSTR lpClassName,  //RegisterClass is the name of the registered window class
            LPCTSTR lpWindowName,  //Window name
            DWORD dwStyle,  //The style of the window
            int x,  //Initial x coordinate (starting point of upper left corner)
            int y,  //Initial y coordinate (starting point of upper left corner)
            int nWidth,  //Window width, CW_USEDEFAULT indicates the default width and height
            int nHeight,  //Window width, CW_USEDEFAULT indicates the default width and height
            HWND hWndParent,  //Parent window handle
            HMENU hMenu,  //Handle to the window menu (if the window has a menu bar)
            HINSTANCE hInstance,  //Handle to the module instance
            LPVOID lpParam  //Via WM_ The IParam parameter of the create message points to the CREATESTRUCT structure (not learned yet, NULL is passed temporarily)
        )
      
    • The first parameter represents the name of the window class, which is consistent with the last parameter of WNDCLASS
    • The second parameter is the title of the window
    • The third parameter, dwStyle, is the style of the window. The available values are
      • WS_BORDER creates a window with a border
      • WS_CAPTION creates a window with a title bar
      • WS_CHILD creates a child window
      • WS_VISIBLE creates an initially visible window
      • WS_MAXIMIZEBOX creates a window with a maximize button
      • WS_ Minizebox creates a window with a minimize button
      • WS_OVERLAPPEDWINDOW creates a window with title bar, maximize, minimize, close button and resizable. WS_TILEDWINDOW is WS_ Alias of overlappedwindow
    • The last parameter hasn't been learned yet. It's NULL temporarily
    • If the function succeeds, the return value is a HWND type and a window handle. If it fails, NULL is returned. You can get more failure information through the GetLastError function
    • CreateWindow sends WM before the function returns_ Create message to window process
  • Use the ShowWindow function to display the window

    •   BOOL WINAPI ShowWindow (
            HWND hWnd,  //Handle to the window
            int nCmdShow  //Controls how windows are displayed
        )
      
    • The first parameter is the handle to the window
    • The second parameter indicates how to display the window, which is of type int
      • When you first call ShowWindow, you should use the nCmdShow parameter value of the WinMain function as its parameter value
      • Subsequent calls to ShowWindow must use a value in the given list instead of the nCmdShow parameter value of the WinMain function (in fact, nCmdShow of the WinMain function can be used instead of a mandatory requirement)
    • If the window was previously visible, the return value is not 0. If the window was previously hidden, the return value is 0
  • Use the UpdateWindow function to update the window

    •   BOOL WINAPI UpdateWindow (
            HWND hWnd  //Handle to the window
        )
      
    • Only one parameter is the window handle
    • If the function succeeds, the return value is non-0; if it fails, the return value is 0
    • UpdateWindow sends WM by_ Paint to the window procedure of the specified window to update (bypass message queue). If the update area is empty, no message will be sent
  • Window procedure WNDPROC

    • The windows application adopts the message mechanism: any operation of the user will send the corresponding message, and then the corresponding message will be sent to the window procedure function for processing
    • WNDPROC is a function pointer to the window procedure function
    • The first parameter is the window handle
    • The second parameter is the message ID, UINT type (typedef unsigned int UINT;)
    • The third parameter is the additional message type, which depends on the value of uMsg parameter and WPARAM type
    • The fourth parameter is additional message information, which depends on the value of uMsg parameter and LPARAM type
    • The return value is of type lrresult (typedef long lrresult;)
    • Default window procedure function
      • In the Windows operating system, when the window is displayed and the user operates on the window (such as moving the mouse, clicking the window and closing the window), the system will send messages to the window continuously, and then the window needs to process these messages, so a function is needed to process these messages. A default window processing function DefWindowProc is defined in Win32API. We can throw messages we don't care about to him for processing. If we need to customize the processing of relevant messages, we need to implement our own window process function
      • The return value is the result of message processing
  • Message loop (message queue)

    • There is a "system message queue" in Windows, and a separate "thread message queue" (application message queue) is maintained for each GUI thread

      • GUI thread is called user32. in the thread. DLL or gdi32 DLL is called GUI thread
      • Only after calling user32 DLL or gdi32 DLL, the system will automatically create a message queue for the thread. There can be only one message queue per thread
    • There are the following steps for a mouse click message to be processed by the window process from generation to processing

      1. According to user events, the mouse driver converts them into messages and automatically places them in the "system message queue" of Windows
      2. The Windows system will automatically take out the message from the "system message queue" and throw it into the "thread message queue" corresponding to the message
      3. You need to get the message from the "thread message queue", then translate the message and distribute the message to the window process
      4. The window procedure function responds to this message and processes it (the window procedure function can be customized or default)
    • So you need to write a while loop in your program and use the GetMessage function to always get messages from the "thread message queue"

      • If the return value is 0, WM is received_ Quit message (indicates that the end signal has been received, so it should jump out of the while loop)
      • If the return value is not 0, WM is retrieved_ Messages other than quit
      • If there is an error and the return value is - 1, you can call the GetLastError function to get the reason for the failure
    • After receiving the message, use the TranslateMessage function to translate the message and convert the message of the virtual key into a character message

      • If the message has been translated, the return value is a non-zero value
      • If the message is WM_KEYDOWN,WM_KEYUP,WM_SYSKEYDOWN,WM_SYSKEYUP, regardless of the translation, the return value is a non-zero value
      • If the message is not converted, the return value is zero
    • After translation, the DispatchMessage function is also used to send the message to the window procedure function for processing

    •   BOOL WINAPI GetMessage(
            LPMSG lpMsg,  //Pointer to MSG structure
            HWND hWnd, //Window handle to retrieve
            UNIT wMsgFilterMin,  //The integer value of the lowest message value to be retrieved, usually 0
            UINT wMsgFilterMax  //The integer value of the highest message value to be retrieved, usually 0
        )
      
        //Message loop (message queue)
        MSG msg;
        while(GetMessage(&msg, NULL, 0, 0)){
            TranslateMessage(&msg);  //Message translation
            DispatchMessage(&msg);  //Distribution of messages
        }
      
  • The SendMessage function can directly send messages to the window process, bypassing the thread message queue

    •   BOOL WINAPI SendMessage(
            HWND hWnd, //Handle to the window that received the message
            UINT Msg,  //Message ID
            WPARAM wParam,  //Additional message specific information
            LPARAM lParam  //Additional message specific information
        )
      
    • SendMessage sends the specified message to one or more windows. It will block and wait until the window process processes the message
    • The SendMessage function can directly send messages to the window process, bypassing the thread message queue
#include<windows.h>
#include <iostream>

// If you want to customize the window procedure function, the four parameters must be strictly consistent, the return value must also be lrresult, and the calling convention must also be callback (_stdcallalias)
LRESULT CALLBACK MyWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_CREATE:
            //This is sent by CreateWindow
            return 0;
        case WM_PAINT:
            //This is sent by UpdateWindow
            return 0;
        case WM_DESTROY:
            //This is sent by DestroyWindow (click the close button in the upper right corner)
            PostQuitMessage(0);  //Send WM_QUIT message to exit the program
            return 0;
        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    //Step 1: register window class
    WNDCLASS wnd;
    wnd.style = CS_DROPSHADOW;  //style
    wnd.lpfnWndProc = MyWndProc;  //Window procedure function for processing messages
    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;
    wnd.hInstance = hInstance;
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);  //Icon icon
    wnd.hCursor = LoadCursor(NULL, IDC_ARROW);  //The mouse cursor adopts the arrow cursor
    wnd.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//Background color
    wnd.lpszClassName = L"MrHuang";  //Window class name
    wnd.lpszMenuName = NULL;  //Menu name
    RegisterClass(&wnd);

    //Step 2: create window (WM_CREATE)
    HWND hWnd = CreateWindow(L"MrHuang", L"my first windows app", WS_OVERLAPPED, 100, 100, 300, 300, NULL, NULL, hInstance, NULL);

    //Step 3: display window
    ShowWindow(hWnd, nShowCmd);

    //Step 4: update window (WM_PAINT)
    UpdateWindow(hWnd);

    //Repeatedly take messages from the thread message queue and forward them to the window process
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);  //Translate messages and convert virtual key messages into character messages
        DispatchMessage(&msg);  //Distribute messages to window procedure functions
    }

    return 0;
}

Keywords: C C++

Added by joel426 on Tue, 01 Feb 2022 17:22:48 +0200