ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

WIN32基础

WIN32基础 1、VS2026生成的默认Win32程序// HelloWindows.cpp : 定义应用程序的入口点。 // #include framework.h #include HelloWindows.h #define MAX_LOADSTRING 100 // 全局变量: HINSTANCE hInst; // 当前实例 WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此处放置代码。 // 初始化全局字符串 LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_HELLOWINDOWS, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HELLOWINDOWS)); MSG msg; // 主消息循环: while (GetMessage(msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg)) { TranslateMessage(msg); DispatchMessage(msg); } } return (int) msg.wParam; } // 函数: MyRegisterClass() // 目标: 注册窗口类。 ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize sizeof(WNDCLASSEX); wcex.style CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc WndProc; wcex.cbClsExtra 0; wcex.cbWndExtra 0; wcex.hInstance hInstance; wcex.hIcon LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HELLOWINDOWS)); wcex.hCursor LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground (HBRUSH)(COLOR_WINDOW1); wcex.lpszMenuName MAKEINTRESOURCEW(IDC_HELLOWINDOWS); wcex.lpszClassName szWindowClass; wcex.hIconSm LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(wcex); } // 函数: InitInstance(HINSTANCE, int) // 目标: 保存实例句柄并创建主窗口 // 注释: // 在此函数中我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst hInstance; // 将实例句柄存储在全局变量中 HWND hWnd CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // 目标: 处理主窗口的消息。 // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: { int wmId LOWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(hWnd, ps); // TODO: 在此处添加任何绘图代码... EndPaint(hWnd, ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) IDOK || LOWORD(wParam) IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }1.1、消息队列和消息循环Windows程序运行是由消息驱动的系统为每一个GUI线程创建消息队列。程序通过一个循环等待消息获取消息后DispatchMessage函数将消息发送到对应的窗口函数进行处理。1消息消息是一种数据结构包括接收消息窗口的句柄消息标识符和相关的附加信息typedef struct tagMSG { HWND hwnd; //收消息的窗口的句柄 UINT message; //消息的标识符。 WPARAM wParam; //消息的附加信息WORD类型参数 LPARAM lParam; //消息的附加信息LONG类型参数 DWORD time; //消息的发布时间。 POINT pt; //发布消息时的光标位置 #ifdef _MAC DWORD lPrivate; #endif } MSG2消息队列Win32的消息队列从系统架构层面可分为‌两大类‌系统为每个 GUI 线程维护一个系统消息队列和一个特定于线程的消息队列。系统消息队列‌由Windows操作系统全局维护统一存放鼠标、键盘等硬件输入产生的原始消息是所有应用程序输入消息的第一入口。线程应用程序消息队列‌属于每个GUI线程独立维护的私有队列系统会将对应线程的消息从系统队列转发至此供线程的消息循环读取处理。此外也可按消息处理逻辑将消息分为队列消息和非队列消息两类二者的流转路径存在明显差异‌。‌队列消息 (Queued Messages)‌由 Windows 放入‌线程消息队列‌通过消息循环GetMessage/PeekMessage DispatchMessage按‌先进先出‌顺序异步分发给窗口过程多为硬件事件触发支持跨线程投递。‌典型代表‌鼠标/键盘输入WM_MOUSEMOVE, WM_KEYDOWN、WM_PAINT、WM_TIMER、WM_QUIT 。‌非队列消息 (Non-Queued Messages)‌‌绕过消息队列‌由系统直接同步调用目标窗口的窗口过程WndProc处理完毕才返回多由特定 API 调用或窗口状态变更触发。‌典型代表‌WM_CREATE、WM_DESTROY、WM_SIZE、WM_ACTIVATE、WM_SETFOCUS、WM_WINDOWPOSCHANGED 。PostMessage发送的是‌队列消息‌异步立即返回SendMessage发送的是‌非队列消息‌同步阻塞等待结果同线程内不入队跨线程时挂起发送者。Windows不会在创建线程时就为其分配消息队列所有线程初始状态下都没有消息队列以此避免非GUI线程的不必要资源开销。系统会在‌该线程首次调用特定的USER或GDI类Win32用户态图形函数时‌才为其创建专属的线程级消息队列将该线程标记为GUI线程。部分场景下线程首次创建窗口调用CreateWindow系列API时也会触发该创建逻辑这是因为创建窗口的底层实现本身就依赖相关USER函数调用。以下是创建一个标准 GUI 线程的完整步骤和核心代码逻辑核心步骤‌创建普通线程‌使用 CreateThread或 _beginthreadex创建一个新线程。‌触发消息队列创建‌在线程入口函数中调用任意一个 USER 模块的 API最典型的是 PeekMessage 或 CreateWindow。‌建立消息循环‌编写标准的 while(GetMessage/PeekMessage) 循环来分发和处理消息。‌创建窗口可选但常见‌在消息循环之前或之中调用 CreateWindowEx 创建属于该线程的窗口。3消息循环MSG msg; // 主消息循环: while (GetMessage(msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg)) { TranslateMessage(msg); DispatchMessage(msg); //DispatchMessage 会将窗口句柄、消息标识符 //以及两个消息参数传递给窗口过程但不会传递消息的 //投递时间或鼠标光标位置。应用程序可以在处理消息时 //通过调用GetMessageTime 和 GetMessagePos 函数来获取这些信息。 } }1.1.1 获取消息BOOL GetMessage( [out] LPMSG lpMsg, [in, optional] HWND hWnd, //要检索其消息的窗口的句柄。 窗口必须属于当前线程。 [in] UINT wMsgFilterMin, [in] UINT wMsgFilterMax );从调用该函数的线程中消息队列中获取一个消息如果队列为空则一直等待。If hWnd is NULL, GetMessage retrieves messages for any window that belongs to the current thread, and any messages on the current threads message queue whose hwnd value is NULL (see the MSG structure). Therefore if hWnd is NULL, both window messages and thread messages are processed.If hWnd is -1, GetMessage retrieves only messages on the current threads message queue whose hwnd value is NULL, that is, thread messages as posted by PostMessage (when the hWnd parameter is NULL) or PostThreadMessage.当接收到WM_QUIT消息时函数返回0退出消息循环其他消息返回非0值。发生错误时返回-1。BOOL PeekMessageA( [out] LPMSG lpMsg, [in, optional] HWND hWnd, [in] UINT wMsgFilterMin, [in] UINT wMsgFilterMax, [in] UINT wRemoveMsg );PeekMessage与GetMessage类似用于检查消息队列中是否有消息没有消息时直接返回有消息时提取消息根据wRemoveMsg中的PM_NOREMOVEPM_REMOVE指定是否从队列中移除消息。通常可以在空闲期间进行额外的处理队列有消息时返回TRUE无消息时返回FALSE。该函数不会产生阻塞。消息循环变成MSG msg; while(TRUE){ if (PeekMessage(msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message WM_QUIT) break; TranslateMessage(msg); DispatchMessage(msg); } else { OnIdle(); } }1.1.2转换快捷键消息int TranslateAcceleratorA( [in] HWND hWnd, [in] HACCEL hAccTable, [in] LPMSG lpMsg );处理菜单命令的快捷键。 该函数将 WM_KEYDOWN 或 WM_SYSKEYDOWN 消息转换为 WM_COMMAND 或 WM_SYSCOMMAND 消息如果指定快捷键表中有项然后将 WM_COMMAND 或 WM_SYSCOMMAND 消息直接发送到指定的窗口过程。TranslateAccelerator 在窗口过程处理消息之前不会返回。1.1.3 转换消息BOOL TranslateMessage( [in] const MSG *lpMsg );将虚拟按键消息转换为字符消息。字符消息将发布到调用线程的消息队列以便下次线程调用 GetMessage 或 PeekMessage 函数时读取增加一个字符消息。1.1.4 分发消息LRESULT DispatchMessage( [in] const MSG *lpMsg );将消息调度到窗口过程将消息传给操作系统由操作系统调用窗口函数。 它通常用于调度 GetMessage 函数检索到的消息。如果 lpmsg 参数指向WM_TIMER消息并且WM_TIMER消息的 lParam 参数不为 NULL则 lParam 指向调用的函数而不是窗口过程。DispatchMessage 函数在窗口过程处理完消息之前不会返回。1.2、创建窗口1注册窗口类创建窗口前要先注册窗口类。窗口类和窗口的关系类似C中类和对象的关系基于一个窗口类可以创建多个窗口。窗口类的数据结构如下typedef struct tagWNDCLASSEXW { UINT cbSize; UINT style; //窗口类样式 WNDPROC lpfnWndProc; //指向窗口消息处理函数的指针。 int cbClsExtra; //为窗口类分配的额外字节数 int cbWndExtra; //为窗口类实例分配的额外字节数 HINSTANCE hInstance; //包含类的窗口过程的实例的句柄。 HICON hIcon; //窗口图标 HCURSOR hCursor; //窗口光标 HBRUSH hbrBackground; //窗口背景画刷 LPCWSTR lpszMenuName; //窗口菜单字符串 LPCWSTR lpszClassName; //窗口类的名字 HICON hIconSm; //窗口小图标 } WNDCLASSEXW, *PWNDCLASSEXW, *NPWNDCLASSEXW, *LPWNDCLASSEXW;窗口类样式定义所有窗口类对象共有的样式主要有CS_DBLCLKS向窗口发送双击消息CS_HREDRAWCS_VREDRAW如果移动或大小调整更改了工作区的宽度或高度则重新绘制整个窗口CS_OWNDC为 类中的每个窗口分配唯一的设备上下文CS_CLASSDC分配一个设备上下文以便类中的所有窗口共享。注册一个窗口类以便在调用 CreateWindow 或 CreateWindowEx 函数时使用。ATOM RegisterClassExW( [in] const WNDCLASSEXW *unnamedParam1 );2创建窗口HWND CreateWindowW( [in, optional] LPCWSTR lpClassName, //窗口类名称 [in, optional] LPCWSTR lpWindowName, //窗口名称。 如果窗口样式指定标题栏lpWindowName 指向的窗口标题将显示在标题栏中。 [in] DWORD dwStyle, //窗口样式 [in] int x, //窗口的初始水平位置。CW_USEDEFAULT 使用默认值 [in] int y, [in] int nWidth, //窗口的宽度,CW_USEDEFAULT 使用默认值 [in] int nHeight, [in, optional] HWND hWndParent, //父窗口指定则变成子窗口 [in, optional] HMENU hMenu, //窗口菜单 [in, optional] HINSTANCE hInstance, [in, optional] LPVOID lpParam );hMenu标识要与窗口一起使用的菜单如果要使用类菜单它可以 NULL。窗口样式常用的窗口样式有:WS_CHILDWINDOW:与WS_CHILD意义相同表示创建一个子窗口。子窗口不能有菜单条hMenu作为一个整数来标识不同的子窗口。并且不能同时指定WS_POPUP风格。WS_OVERLAPPED:创建一个重叠式窗口拥有标题栏和边框。WS_OVERLAPPEDWINDOW:WS_OVERLAPPED 风格、WS_CAPTION 风格、WS_SYSMENU风格 WS_THICKFRAME 风格、WS_MINIMIZEBOX 风格和WS_MAXIMIZEBOX风格的组合。WS_POPUP:创建一个弹出式窗口。不能同时指WS_CHILD风格。WS_CAPTION:创建的窗口拥有标题栏(其中包含了WS_BORDER风格)。WS_SYSMENU:创建的窗口拥有标题栏菜单。必须同时指定WS_CAPTION风格。WS_BORDER:创建的窗口拥有边框。WS_SIZEBOX:创建的窗口拥有边框可变大小。WS_THICKFRAME:与WS_SIZEBOX风格相同。WS_VSCROLL:创建的窗口拥有垂直滚动条。WS HSCROLL:创建的窗口拥有水平滚动条。WS_MAXIMIZE:创建的窗口初始为最大化。WS_MAXIMIZEBOX:创建的窗口拥有最大化按钮。必须同时指定WS_SYSMENU风格。WS_MINIMIZE:创建的窗口初始为最小化。WS_MINIMIZEBOX:创建的窗口拥有最小化按钮。必须同时指定WS_SYSMENU风格。WS_TABSTOP:当用户单击Tab键时所创建的窗口可以接收键盘输入焦点。WS_VISIBLE:创建的窗口初始化为可见。可以通过ShowWindow函数来改变窗口的可见性。WS_DISABLED:创建的窗口初始化为不可用。可以通过EnableWindow函数来改变窗口的可用性。不可用的窗口不接受任何用户输入。窗口可大致分为:重叠窗口子窗口弹出窗口仅消息处理窗口等几类。一个顶层窗口的非用户区就是由许多子窗口构成的如标题栏、状态栏最大化按钮等。最后一个参数 ‌lpParam‌ 的主要用途是‌传递自定义的创建数据‌。数据透传至WM_CREATElpParam是一个LPVOID类型的指针指向应用程序定义的任意数据。当CreateWindow被调用时系统会向窗口的过程函数Window Procedure发送 ‌WM_CREATE‌ 消息。常见用途在面向对象编程中通常需要将窗口消息路由到特定的 C 类实例方法中。由于 Windows 回调函数必须是静态的或全局的无法直接访问非静态成员变量因此常用lpParam传递this指针。// 创建窗口时传递 this 指针 HWND hWnd CreateWindow( szClassName, LTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, this // lpParam: 传递当前类实例指针 ); // 在窗口过程中接收 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg WM_CREATE) { CREATESTRUCT* cs (CREATESTRUCT*)lParam; MyClass* pApp (MyClass*)cs-lpCreateParams; // 获取传递的 this 指针 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pApp); // 保存以便后续使用 } // ... 其他消息处理 }3显示窗口BOOL ShowWindow( [in] HWND hWnd, [in] int nCmdShow );设置指定窗口的显示状态。SW_RESTORESW_HIDESW_SHOWSW_MAXIMIZESW_MINIMIZE等。不进入消息队列直接调用窗口处理函数BOOL UpdateWindow( [in] HWND hWnd );如果窗口的更新区域不为空UpdateWindow函数通过向窗口发送 WM_PAINT 消息来更新指定窗口的工作区。函数绕过应用程序队列将 WM_PAINT 消息直接发送到指定窗口的窗口过程。 如果更新区域为空则不发送任何消息。窗口处理函数默认的窗口处理函数收到WM_CLOSE消息调用DestroyWindow销毁窗口拥有的资源向窗口发送WM_DESTROY消息通常处理此消息时调用PostQuitMessage发送WM_QUITx消息结束消息循环。Windows程序的生命周期1.主线程调用CreateWindow创建一个窗口作为程序的主窗口。CreateWindow 产生窗口后以WM _CREATE消息直接调用窗口函数后者于是可以在此时做些初始化操作(例如配置内存、打开文件、读初始数据.....)。2.在程序运行的过程中不断以GetMessage从消息队列中获取消息。如果这个消息是WM_QUITGetMessage会返回0从而结束while循环进而结束整个程序。3. DispatchMessage 通过 Windows USER模块的协助与监督把消息分派至窗口函数。消息将在该处被判别并处理。4.程序不断进行2.和3.的操作。5.当使用者按下系统菜单中的Close命令项时系统送出WM_CLOSE。通常程序的窗口函数不处理此消息于是DefWindowProc 处理它。6. DefWindowProc 收到 WM_CLOSE后调用 DestroyWindow把窗口销毁然后发送WM_DESTROY消息。7.程序对 WM_DESTROY 的标准反应是调用 PostQuitMessage。8. PostQuitMessage 没什么其它操作只发送 WM_QUIT 消息步骤2消息循环中的GetMessage获取该消息后结束消息循环。1.3、对话框对话框是一种窗口对话框可以包含许多子窗口例如输入框按钮滚动条等这些都是系统提供的、已经具备某些特定功能的子窗口称为常用控件。系统已经预定义了常用控件的窗口类使用时不再需要注册窗口类。在除对话框以外的窗口中使用常用控件仍然需要使用CreateWindow创建它们。父窗口与常用控件间的通信:当用户与控件进行交互时控件会将有关的交互信息以通知消息的形式发送给父窗口这种消息在Windows 中定义为 WM_COMMAND消息其wParam 和 IParam参数的意义如下: LOWORD(wParam) 控件IDHIWORD(wParam) 通知码IParam 控件句柄Windows提供了多种预定义的通知码每一种常用控件都有不同的通知码。反之父窗口也可以向控件发送消息使其执行指定的操作或返回指定的当前状态。例如语句:hFont SendMessage( hwndEdit, WM_GETFONT, 0, OL );用于获得编辑框控件在显示文本时所使用的字体句柄。而语句:SendMessage( hwndEdit, WM_SETFONT,(WPARAM)hFont, 0L);用于设置控件字体。1模态对话框void DialogBoxW( [in, optional] hInstance, [in] lpTemplate, [in, optional] hWndParent, [in, optional] lpDialogFunc );DialogBox根据对话框模板开启对话框指定父窗口和对话框消息处理函数。BOOL EndDialog( [in] HWND hDlg, [in] INT_PTR nResult );EndDialog不会立即销毁对话框。 相反它设置一个标志并允许对话框过程将控制权返回到系统。 在尝试从应用程序队列检索下一条消息之前系统会检查标志。 如果设置了标志系统将结束消息循环销毁对话框并使用nResult中的值作为创建对话框的函数的返回值。典型应用:关于窗口、确认删除提示、必须用户立即响应的警告框。模态对话框内部维护一个专用的消息循环。自动处理对话框特有的键盘消息(如Tab键切换焦点、Enter键触发默认按钮、Esc键取消等)。函数内部自行检索和分发消息直到对话框关闭才返回。对话框消息处理函数返回true表示已经处理了该消息返回false表示未处理该消息由系统自动调用DefDlgPro函数进行处理。通常只处理WM_INITDIALOG消息和WM_COMMAND消息。对话框的每个控件也是一个窗口有窗口类窗口处理函数消息循环。这些由系统管理控件通过向对话框发送WM_COMMAND消息与对话框进行通信。2非模态对话框通常包含标题栏和系统菜单栏常用的窗口样式为WS_POPUP WS_CAPTION WS_SYSMENU WS_VISIBLE如果不包括WS_VISIBLE则需要调用ShowWindow才能显示对话框。CreateDialog创建DestroyWindow结束对话框。非模式对话框的消息要经过主线程的消息循环使用IsDialogMessage将属于该对话框的消息发送给对话框的窗口处理函数。void CreateDialogA( [in, optional] hInstance, [in] lpName, [in, optional] hWndParent, [in, optional] lpDialogFunc );CreateDialog 函数使用 CreateWindowEx 函数来创建对话框。 CreateDialog 然后向对话框过程发送 WM_INITDIALOG 消息。典型应用:查找/替换窗口、属性面板、工具箱、浮动调色板。2、从启动程序到单击关闭按钮记录消息的调用增加函数TraceWindowsMessage用于打印收到的消息类型。#define TRACE_ID(iD) case iD: return L#iD; std::wstring WINAPI TraceWindowsMessage(UINT uMsg) { switch (uMsg) { TRACE_ID(WM_NULL); TRACE_ID(WM_CREATE); TRACE_ID(WM_DESTROY); TRACE_ID(WM_MOVE); TRACE_ID(WM_SIZE); TRACE_ID(WM_ACTIVATE); TRACE_ID(WM_SETFOCUS); TRACE_ID(WM_KILLFOCUS); TRACE_ID(WM_ENABLE); TRACE_ID(WM_SETREDRAW); TRACE_ID(WM_SETTEXT); TRACE_ID(WM_GETTEXT); TRACE_ID(WM_GETTEXTLENGTH); TRACE_ID(WM_PAINT); TRACE_ID(WM_CLOSE); TRACE_ID(WM_QUERYENDSESSION); TRACE_ID(WM_QUERYOPEN); TRACE_ID(WM_ENDSESSION); TRACE_ID(WM_QUIT); TRACE_ID(WM_ERASEBKGND); TRACE_ID(WM_SYSCOLORCHANGE); TRACE_ID(WM_SHOWWINDOW); TRACE_ID(WM_WININICHANGE); TRACE_ID(WM_DEVMODECHANGE); TRACE_ID(WM_ACTIVATEAPP); TRACE_ID(WM_FONTCHANGE); TRACE_ID(WM_TIMECHANGE); TRACE_ID(WM_CANCELMODE); TRACE_ID(WM_SETCURSOR); TRACE_ID(WM_MOUSEACTIVATE); TRACE_ID(WM_CHILDACTIVATE); TRACE_ID(WM_QUEUESYNC); TRACE_ID(WM_GETMINMAXINFO); TRACE_ID(WM_PAINTICON); TRACE_ID(WM_ICONERASEBKGND); TRACE_ID(WM_NEXTDLGCTL); TRACE_ID(WM_SPOOLERSTATUS); TRACE_ID(WM_DRAWITEM); TRACE_ID(WM_MEASUREITEM); TRACE_ID(WM_DELETEITEM); TRACE_ID(WM_VKEYTOITEM); TRACE_ID(WM_CHARTOITEM); TRACE_ID(WM_SETFONT); TRACE_ID(WM_GETFONT); TRACE_ID(WM_SETHOTKEY); TRACE_ID(WM_GETHOTKEY); TRACE_ID(WM_QUERYDRAGICON); TRACE_ID(WM_COMPAREITEM); TRACE_ID(WM_GETOBJECT); TRACE_ID(WM_COMPACTING); TRACE_ID(WM_COMMNOTIFY); TRACE_ID(WM_WINDOWPOSCHANGING); TRACE_ID(WM_WINDOWPOSCHANGED); TRACE_ID(WM_POWER); TRACE_ID(WM_COPYDATA); TRACE_ID(WM_CANCELJOURNAL); TRACE_ID(WM_NOTIFY); TRACE_ID(WM_INPUTLANGCHANGEREQUEST); TRACE_ID(WM_INPUTLANGCHANGE); TRACE_ID(WM_TCARD); TRACE_ID(WM_HELP); TRACE_ID(WM_USERCHANGED); TRACE_ID(WM_NOTIFYFORMAT); TRACE_ID(WM_CONTEXTMENU); TRACE_ID(WM_STYLECHANGING); TRACE_ID(WM_STYLECHANGED); TRACE_ID(WM_DISPLAYCHANGE); TRACE_ID(WM_GETICON); TRACE_ID(WM_SETICON); TRACE_ID(WM_NCCREATE); TRACE_ID(WM_NCDESTROY); TRACE_ID(WM_NCCALCSIZE); TRACE_ID(WM_NCHITTEST); TRACE_ID(WM_NCPAINT); TRACE_ID(WM_NCACTIVATE); TRACE_ID(WM_GETDLGCODE); TRACE_ID(WM_SYNCPAINT); TRACE_ID(WM_NCMOUSEMOVE); TRACE_ID(WM_NCLBUTTONDOWN); TRACE_ID(WM_NCLBUTTONUP); TRACE_ID(WM_NCLBUTTONDBLCLK); TRACE_ID(WM_NCRBUTTONDOWN); TRACE_ID(WM_NCRBUTTONUP); TRACE_ID(WM_NCRBUTTONDBLCLK); TRACE_ID(WM_NCMBUTTONDOWN); TRACE_ID(WM_NCMBUTTONUP); TRACE_ID(WM_NCMBUTTONDBLCLK); TRACE_ID(WM_NCXBUTTONDOWN); TRACE_ID(WM_NCXBUTTONUP); TRACE_ID(WM_NCXBUTTONDBLCLK); TRACE_ID(WM_INPUT); TRACE_ID(WM_KEYDOWN); TRACE_ID(WM_KEYUP); TRACE_ID(WM_CHAR); TRACE_ID(WM_DEADCHAR); TRACE_ID(WM_SYSKEYDOWN); TRACE_ID(WM_SYSKEYUP); TRACE_ID(WM_SYSCHAR); TRACE_ID(WM_SYSDEADCHAR); TRACE_ID(WM_UNICHAR); TRACE_ID(WM_IME_STARTCOMPOSITION); TRACE_ID(WM_IME_ENDCOMPOSITION); TRACE_ID(WM_IME_COMPOSITION); TRACE_ID(WM_INITDIALOG); TRACE_ID(WM_COMMAND); TRACE_ID(WM_SYSCOMMAND); TRACE_ID(WM_TIMER); TRACE_ID(WM_HSCROLL); TRACE_ID(WM_VSCROLL); TRACE_ID(WM_INITMENU); TRACE_ID(WM_INITMENUPOPUP); TRACE_ID(WM_MENUSELECT); TRACE_ID(WM_MENUCHAR); TRACE_ID(WM_ENTERIDLE); TRACE_ID(WM_MENURBUTTONUP); TRACE_ID(WM_MENUDRAG); TRACE_ID(WM_MENUGETOBJECT); TRACE_ID(WM_UNINITMENUPOPUP); TRACE_ID(WM_MENUCOMMAND); TRACE_ID(WM_CHANGEUISTATE); TRACE_ID(WM_UPDATEUISTATE); TRACE_ID(WM_QUERYUISTATE); TRACE_ID(WM_CTLCOLORMSGBOX); TRACE_ID(WM_CTLCOLOREDIT); TRACE_ID(WM_CTLCOLORLISTBOX); TRACE_ID(WM_CTLCOLORBTN); TRACE_ID(WM_CTLCOLORDLG); TRACE_ID(WM_CTLCOLORSCROLLBAR); TRACE_ID(WM_CTLCOLORSTATIC); TRACE_ID(MN_GETHMENU); TRACE_ID(WM_MOUSEMOVE); TRACE_ID(WM_LBUTTONDOWN); TRACE_ID(WM_LBUTTONUP); TRACE_ID(WM_LBUTTONDBLCLK); TRACE_ID(WM_RBUTTONDOWN); TRACE_ID(WM_RBUTTONUP); TRACE_ID(WM_RBUTTONDBLCLK); TRACE_ID(WM_MBUTTONDOWN); TRACE_ID(WM_MBUTTONUP); TRACE_ID(WM_MBUTTONDBLCLK); TRACE_ID(WM_MOUSEWHEEL); TRACE_ID(WM_XBUTTONDOWN); TRACE_ID(WM_XBUTTONUP); TRACE_ID(WM_XBUTTONDBLCLK); TRACE_ID(WM_PARENTNOTIFY); TRACE_ID(WM_ENTERMENULOOP); TRACE_ID(WM_EXITMENULOOP); TRACE_ID(WM_NEXTMENU); TRACE_ID(WM_SIZING); TRACE_ID(WM_CAPTURECHANGED); TRACE_ID(WM_MOVING); TRACE_ID(WM_POWERBROADCAST); TRACE_ID(WM_DEVICECHANGE); TRACE_ID(WM_MDICREATE); TRACE_ID(WM_MDIDESTROY); TRACE_ID(WM_MDIACTIVATE); TRACE_ID(WM_MDIRESTORE); TRACE_ID(WM_MDINEXT); TRACE_ID(WM_MDIMAXIMIZE); TRACE_ID(WM_MDITILE); TRACE_ID(WM_MDICASCADE); TRACE_ID(WM_MDIICONARRANGE); TRACE_ID(WM_MDIGETACTIVE); TRACE_ID(WM_MDISETMENU); TRACE_ID(WM_ENTERSIZEMOVE); TRACE_ID(WM_EXITSIZEMOVE); TRACE_ID(WM_DROPFILES); TRACE_ID(WM_MDIREFRESHMENU); TRACE_ID(WM_IME_SETCONTEXT); TRACE_ID(WM_IME_NOTIFY); TRACE_ID(WM_IME_CONTROL); TRACE_ID(WM_IME_COMPOSITIONFULL); TRACE_ID(WM_IME_SELECT); TRACE_ID(WM_IME_CHAR); TRACE_ID(WM_IME_REQUEST); TRACE_ID(WM_IME_KEYDOWN); TRACE_ID(WM_IME_KEYUP); TRACE_ID(WM_MOUSEHOVER); TRACE_ID(WM_MOUSELEAVE); TRACE_ID(WM_NCMOUSEHOVER); TRACE_ID(WM_NCMOUSELEAVE); TRACE_ID(WM_WTSSESSION_CHANGE); TRACE_ID(WM_TABLET_FIRST); TRACE_ID(WM_TABLET_LAST); TRACE_ID(WM_CUT); TRACE_ID(WM_COPY); TRACE_ID(WM_PASTE); TRACE_ID(WM_CLEAR); TRACE_ID(WM_UNDO); TRACE_ID(WM_RENDERFORMAT); TRACE_ID(WM_RENDERALLFORMATS); TRACE_ID(WM_DESTROYCLIPBOARD); TRACE_ID(WM_DRAWCLIPBOARD); TRACE_ID(WM_PAINTCLIPBOARD); TRACE_ID(WM_VSCROLLCLIPBOARD); TRACE_ID(WM_SIZECLIPBOARD); TRACE_ID(WM_ASKCBFORMATNAME); TRACE_ID(WM_CHANGECBCHAIN); TRACE_ID(WM_HSCROLLCLIPBOARD); TRACE_ID(WM_QUERYNEWPALETTE); TRACE_ID(WM_PALETTEISCHANGING); TRACE_ID(WM_PALETTECHANGED); TRACE_ID(WM_HOTKEY); TRACE_ID(WM_PRINT); TRACE_ID(WM_PRINTCLIENT); TRACE_ID(WM_APPCOMMAND); TRACE_ID(WM_THEMECHANGED); TRACE_ID(WM_HANDHELDFIRST); TRACE_ID(WM_HANDHELDLAST); TRACE_ID(WM_AFXFIRST); TRACE_ID(WM_AFXLAST); TRACE_ID(WM_PENWINFIRST); TRACE_ID(WM_PENWINLAST); TRACE_ID(WM_APP); default: TCHAR buff[20]; ZeroMemory(buff, 20 * sizeof(TCHAR)); wsprintf(buff, L0x%04x, uMsg); return std::wstring(buff); } } void PrintMsgInfo(HWND hwnd, UINT message) { auto msgStr TraceWindowsMessage(message); TCHAR buff[100]; ZeroMemory(buff, 100 * sizeof(TCHAR)); wsprintf(buff, Lhwnd: 0x%x , message: %s \r\n, hwnd, msgStr.c_str()); std::wstring info(buff); OutputDebugString(info.c_str()); }在执行中增加跟踪消息的函数调用BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst hInstance; // 将实例句柄存储在全局变量中 OutputDebugString(Lbefore CreateWindowW: \r\n); HWND hWnd CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } OutputDebugString(Lafter CreateWindowW: \r\n); ShowWindow(hWnd, nCmdShow); OutputDebugString(Lafter ShowWindow: \r\n); UpdateWindow(hWnd); OutputDebugString(Lafter UpdateWindow: \r\n); return TRUE; }消息循环MSG msg; // 主消息循环: while (GetMessage(msg, nullptr, 0, 0)) { OutputDebugString(LGetMessage : ); PrintMsgInfo(msg.hwnd,msg.message); if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg)) { TranslateMessage(msg); DispatchMessage(msg); } } OutputDebugString(LExit GetMessage : ); PrintMsgInfo(msg.hwnd, msg.message);窗口处理函数LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { OutputDebugString(LWndProc message: ); PrintMsgInfo(hWnd, message); ...... }调试窗口的输出如下before CreateWindowW: WndProc message: hwnd: 0x1b0802 , message: WM_GETMINMAXINFO WndProc message: hwnd: 0x1b0802 , message: WM_NCCREATE WndProc message: hwnd: 0x1b0802 , message: WM_NCCALCSIZE WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: 0x0094 WndProc message: hwnd: 0x1b0802 , message: 0x0094 WndProc message: hwnd: 0x1b0802 , message: WM_CREATE after CreateWindowW: WndProc message: hwnd: 0x1b0802 , message: WM_SHOWWINDOW WndProc message: hwnd: 0x1b0802 , message: WM_WINDOWPOSCHANGING WndProc message: hwnd: 0x1b0802 , message: WM_WINDOWPOSCHANGING WndProc message: hwnd: 0x1b0802 , message: WM_ACTIVATEAPP WndProc message: hwnd: 0x1b0802 , message: WM_NCACTIVATE WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: WM_GETICON WndProc message: hwnd: 0x1b0802 , message: WM_GETICON WndProc message: hwnd: 0x1b0802 , message: WM_GETICON WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: 0x0091 WndProc message: hwnd: 0x1b0802 , message: 0x0092 WndProc message: hwnd: 0x1b0802 , message: 0x0092 WndProc message: hwnd: 0x1b0802 , message: WM_ACTIVATE WndProc message: hwnd: 0x1b0802 , message: WM_SETFOCUS WndProc message: hwnd: 0x1b0802 , message: WM_NCPAINT WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: 0x0091 WndProc message: hwnd: 0x1b0802 , message: 0x0092 WndProc message: hwnd: 0x1b0802 , message: 0x0092 WndProc message: hwnd: 0x1b0802 , message: WM_ERASEBKGND WndProc message: hwnd: 0x1b0802 , message: WM_WINDOWPOSCHANGED WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: WM_SIZE WndProc message: hwnd: 0x1b0802 , message: WM_MOVE after ShowWindow: WndProc message: hwnd: 0x1b0802 , message: WM_PAINT after UpdateWindow: WndProc message: hwnd: 0x1b0802 , message: WM_GETICON WndProc message: hwnd: 0x1b0802 , message: WM_SYNCPAINT WndProc message: hwnd: 0x1b0802 , message: WM_GETICON GetMessage : hwnd: 0x1b0802 , message: 0x031f WndProc message: hwnd: 0x1b0802 , message: 0x031f WndProc message: hwnd: 0x1b0802 , message: WM_GETICON GetMessage : hwnd: 0x1b0802 , message: 0xc120 WndProc message: hwnd: 0x1b0802 , message: 0xc120 GetMessage : hwnd: 0x2300a6 , message: 0x0465 GetMessage : hwnd: 0x20056e , message: 0x83f1 GetMessage : hwnd: 0x20056e , message: 0x83f1 GetMessage : hwnd: 0x20056e , message: 0x83f1 GetMessage : hwnd: 0x20056e , message: 0x83f1 GetMessage : hwnd: 0xc0784 , message: 0x0060 GetMessage : hwnd: 0x20056e , message: 0x83f0 GetMessage : hwnd: 0x0 , message: WM_TIMER GetMessage : hwnd: 0xc0784 , message: 0x0060 WndProc message: hwnd: 0x1b0802 , message: 0xc053 WndProc message: hwnd: 0x1b0802 , message: WM_IME_REQUEST GetMessage : hwnd: 0xc0784 , message: 0x0060 GetMessage : hwnd: 0x0 , message: WM_TIMER GetMessage : hwnd: 0x0 , message: WM_TIMER GetMessage : hwnd: 0x170526 , message: WM_TIMER WndProc message: hwnd: 0x1b0802 , message: WM_NCHITTEST WndProc message: hwnd: 0x1b0802 , message: WM_SETCURSOR GetMessage : hwnd: 0x1b0802 , message: WM_NCMOUSEMOVE WndProc message: hwnd: 0x1b0802 , message: WM_NCMOUSEMOVE WndProc message: hwnd: 0x1b0802 , message: WM_SETCURSOR GetMessage : hwnd: 0x1b0802 , message: WM_NCLBUTTONDOWN WndProc message: hwnd: 0x1b0802 , message: WM_NCLBUTTONDOWN WndProc message: hwnd: 0x1b0802 , message: WM_CAPTURECHANGED WndProc message: hwnd: 0x1b0802 , message: WM_SYSCOMMAND WndProc message: hwnd: 0x1b0802 , message: WM_CLOSE WndProc message: hwnd: 0x1b0802 , message: 0x0090 WndProc message: hwnd: 0x1b0802 , message: WM_WINDOWPOSCHANGING WndProc message: hwnd: 0x1b0802 , message: WM_WINDOWPOSCHANGED WndProc message: hwnd: 0x1b0802 , message: WM_NCACTIVATE WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: 0x0093 WndProc message: hwnd: 0x1b0802 , message: 0x0091 WndProc message: hwnd: 0x1b0802 , message: 0x0092 WndProc message: hwnd: 0x1b0802 , message: 0x0092 WndProc message: hwnd: 0x1b0802 , message: WM_ACTIVATE WndProc message: hwnd: 0x1b0802 , message: WM_ACTIVATEAPP WndProc message: hwnd: 0x1b0802 , message: WM_KILLFOCUS WndProc message: hwnd: 0x1b0802 , message: WM_IME_SETCONTEXT WndProc message: hwnd: 0x1b0802 , message: WM_IME_NOTIFY WndProc message: hwnd: 0x1b0802 , message: WM_DESTROY WndProc message: hwnd: 0x1b0802 , message: WM_NCDESTROY GetMessage : hwnd: 0x0 , message: 0x0466 GetMessage : hwnd: 0x0 , message: 0x0466 Exit GetMessage : hwnd: 0x0 , message: WM_QUIT可见大部分的消息都是直接调用消息处理函数并不经过消息队列。
返回列表