WINDOWS消息

news2025/1/16 19:50:56

WINDOWS消息

Unit01消息队列

01消息队列概念

  • 消息队列是用于存放消息的队列
  • 消息在队列中先进先出
  • 所有窗口程序都有消息队列
  • 程序(GetMessage)可以从队列中获消息

02消息队列分类

  • 系统消息队列:由系统维护的消息队列(这个队列非常庞大),存放系统产生的所有消息,例如鼠标、键盘等
  • 程序消息队列:属于每一个应用程序(线程)的消息队列,由应用程序(线程)维护

03消息和队列关系

  • 消息和消息队列的关系
    • 当鼠标、键盘产生消息时,会将消息放到系统消息队列
    • 系统会根据存放的消息,找到对应程序的消息队列
    • 将消息投递到程序的消息队列中
  • 根据消息和消息队列之间使用关系,将消息分成两类:
    • 队列消息:消息的发送和获取,都是通过消息队列完成
    • 非队列消息:消息的发送和获取,是直接调用消息的窗口处理完成(就是消息不进队列直接调用消息处理函数对消息进行处理)

在这里插入图片描述

  • 队列消息:消息发送后,首先放入队列,然后通过消息循环,从队列当中完成
    • GetMessage:从消息队列中获取消息
    • PostMessage:将消息投递到消息队列
    • 常见队列消息:WM_PAINT、键盘、鼠标、定时器
  • 非队列消息:消息发送时,首先查找消息接收窗口的窗口处理函数,直接调用处理函数,完成消息
    • SendMessage:直接将消息发送给窗口的处理函数,并等待处理结果
    • 常见非队列消息:WM_CREATE、WM_SIZE等

在这里插入图片描述

04深谈GetMessage原理

  • 在程序(线程)消息队列超找消息,如果队列中有消息,检查消息是否满足指定条件(HWND,ID范围),不满足条件就不会取出消息,否则从队列中取出消息返回
  • 如果程序(线程)消息队列中没有消息,向系统消息队列获取属于本程序的消息。如果系统队列的当前消息属于本程序,系统会将消息转发到程序消息队列中。
  • 如果系统消息队列也没有消息,检查当前进程的所有窗口的需要重新绘制的区域,如果发现有需要绘制的区域,产生WM_PAINT消息,取得消息返回处理
  • 如果没有重新绘制的区域,检查定时器如果有到时得定时器,产生WM_TIMER,返回处理执行
  • 如果没有到时的定时器,整理程序的资源、内存等
  • GetMessage会继续等待下一条消息。PeekMessage会返回FALSE,交出程序的控制权
  • 注意:GetMessage如果获取到时WM_QUIT,函数或返回FALSE

05WM_PAINT消息

  • 产生时间:当窗口需要绘制的时候
  • 附带信息(对于此消息,附带消息没用)
    • wParam:0
    • lParam:0
  • 专职用法:用于绘图
#include <windows.h>
HANDLE g_hOutput = 0;
void OnPaint(HWND hWnd){
	char* pszText = "WM_PAINT\n";
	WriteConsole(g_hOutput,pszText,strlen(pszText),NULL,NULL);
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_PAINT:
		OnPaint(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}
  • 窗口无效区域:需要重新绘制的区域
BOOL InvalidateRect(  
	HWND hWnd,           // handle to window 窗口句柄
  CONST RECT* lpRect,  // rectangle coordinates 区域的矩形坐标(如果为NULL指的是整个窗口)
  BOOL bErase          // erase state 重绘前是否先擦除
);

示例代码:

#include <windows.h>
HANDLE g_hOutput = 0;
void OnPaint(HWND hWnd){
	char* pszText = "WM_PAINT\n";
	WriteConsole(g_hOutput,pszText,strlen(pszText),NULL,NULL);
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_PAINT:
		OnPaint(hWnd);
		break;
	case WM_LBUTTONDOWN://点击鼠标的左键消息
		InvalidateRect(hWnd,NULL,TRUE);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}
  • 消息处理步骤
    • 开始绘图
    HDC BeginPaint(
    	HWND hwnd,            // handle to window 绘制窗口句柄
    	LPPAINTSTRUCT lpPaint // paint information 绘图参数的BUFF
    );//返回绘图设备句柄HDC
    
    • 正式绘图
    • 结束绘图
    BOOL EndPaint(
    	HWND hWnd,                  // handle to window 绘制窗口句柄
    	CONST PAINTSTRUCT *lpPaint  // paint data 绘图参数的指针BeginPaint返回
    );
    

示例代码:

#include <windows.h>
HANDLE g_hOutput = 0;
void OnPaint(HWND hWnd){
	char* pszText = "WM_PAINT\n";
	WriteConsole(g_hOutput,pszText,strlen(pszText),NULL,NULL);
	//这个结构体内部的内容不用管
	PAINTSTRUCT ps = {0};
	//开始绘图
	HDC hdc = BeginPaint(hWnd, &ps);
	//正式绘图
	TextOut(hdc, 100, 100, "hello", 5);
	//结束绘图
	EndPaint(hWnd, &ps);
	//以上绘图的代码,必须放在处理WM_PAINT消息时调用
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_PAINT:
		OnPaint(hWnd);
		break;
	case WM_LBUTTONDOWN://点击鼠标的左键消息
		InvalidateRect(hWnd,NULL,TRUE);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

Unit02键盘消息

01键盘消息分类

  • WM_KEYDOWN按键被按下时产生
  • WM_KEYUP按键被放开时产生
  • WM_SYSKEYDOWN系统按键下时产生,比如:ALT、F10
  • WM_SYSKEYUP系统按键放开时产生
  • 这些消息附带信息:
    • WPARAM:按键的Virtual Key(键码值世界通用)
    • LPARAM:按键的参数,例如按下次数
#include <windows.h>
#include <stdio.h>
HANDLE g_hOutput = 0;

void OnKeyDown(HWND hWnd,WPARAM wParam){
	char szText[256] = {0};
	sprintf(szText,"WM_KEYDOWN:键码值=%d\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnKeyUp(HWND hWnd,WPARAM wParam){
	char szText[256] = {0};
	sprintf(szText,"WM_KEYUP:键码值=%d\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_KEYDOWN:
		OnKeyDown(hWnd,wParam);
		break;
	case WM_KEYUP:
		OnKeyUp(hWnd,wParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

图中笔误TransMessage应该是TranslateMessage
笔误TransMessage应该是TranslateMessage

02字符消息(WM_CHAR)

  • TreanslateMessage在转换WM_KEYDOWN消息时,对于可见字符可以产生WM_CHAR,不可见字符没有此消息
  • 附带信息:
    • WPARAM:输入的字符的ASCII字符编码值
    • LPARAM:按键相关参数(这个参数在此没什么用)
  • TranslateMessage函数执行过程的伪代码:
TranslateMessage(&Msg){
	if(nMsg.message != WM_KEYDOWN){
		return;
	}
	//根据nMsg.wParam(键码值)可以获取哪个按键被按下
	if(不可见字符的按键){
		return;
	}
	//查看CapsLock(大写锁定键)是否处于打开状态
	if(打开)
		//65是A的键码值(示例按下的是A键)
		PostMessage(nMsg.hwnd,WM_CHAR,65,...);
	else
		//97是a的键码值
		PostMessage(nMsg.hwnd,WM_CHAR,97,...);
}

示例代码

#include <windows.h>
#include <stdio.h>
HANDLE g_hOutput = 0;

void OnKeyDown(HWND hWnd,WPARAM wParam){
	char szText[256] = {0};
	sprintf(szText,"WM_KEYDOWN:键码值=%d\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnKeyUp(HWND hWnd,WPARAM wParam){
	char szText[256] = {0};
	sprintf(szText,"WM_KEYUP:键码值=%d\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnChar(HWND hWnd,WPARAM wParam){
	char szText[256] = {0};
	sprintf(szText,"WM_KEYUP:键码值=%d\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_CHAR:
		OnChar(hWnd,wParam);
		break;
	case WM_KEYDOWN:
		OnKeyDown(hWnd,wParam);
		break;
	case WM_KEYUP:
		OnKeyUp(hWnd,wParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述

Unit03鼠标消息

01鼠标消息分类

  • 基本鼠标消息
    • WM_LBUTTONDOWN鼠标左键按下
    • WM_LBUTTONUP鼠标左键抬起
    • WM_RBUTTONDOWN鼠标右键按下
    • WM_RBUTTONUP鼠标右键抬起
    • WM_MOUSEMOVE鼠标移动消息
  • 双击消息
    • WM_LBUTTONDBLCLK鼠标左键双击
    • WM_RBUTTONDBLCLK鼠标右键双击
  • 滚轮消息
    • WM_MOUSEWHEEL鼠标滚轮消息

02鼠标基本消息

  • 附带信息
    • WPARAM:其他按键的状态,例如Ctrl/shift等
    • LPARAM:
      • 鼠标的位置,窗口客户坐标系
        • LOWORDx坐标的位置
        • HIWORDy坐标的位置
  • 一般情况鼠标按下或抬起成对出现,在鼠标移动过程中,会根据移动速度产生一系列的WM_MOUSEMOVE消息
#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;

void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_LBUTTONDOWN:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_LBUTTONUP:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_MOUSEMOVE:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_MOUSEMOVE:
		OnMouseMove(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONDOWN:
		OnLButtonDown(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONUP:
		OnLButtonUp(hWnd,wParam,lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

03鼠标双击消息

  • 附带信息
    • WPARAM:其他按键的状态,例如Ctrl/shift等
    • LPARAM:
      • 鼠标的位置,窗口客户坐标系
        • LOWORDx坐标的位置
        • HIWORDy坐标的位置
  • 消息产生顺序
    • 以左键双击为例
      • WM_LBUTTINDOWN
      • WM_LBUTTONUP
      • WM_LBUTTONBLACK
      • WM_LBUTTONUP
  • 注意:使用时需要在注册窗口类的时候加上CS_DBLCLKS风格
#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;

void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_LBUTTONDOWN:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_LBUTTONUP:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_MOUSEMOVE:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	//WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnButtonDoubleClick(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char* szText = "WM_LBUTTONDBLCLK\n";
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_LBUTTONDBLCLK:
		OnButtonDoubleClick(hWnd,wParam,lParam);
		break;
	case WM_MOUSEMOVE:
		OnMouseMove(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONDOWN:
		OnLButtonDown(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONUP:
		OnLButtonUp(hWnd,wParam,lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述

04鼠标滚动消息

  • 附带信息
    • WPARAM:
      • LOWORD其他按键的状态
      • HIWORD滚轮的偏移量,通过正负值表示滚动的方向(正:向前滚动,负:向后滚动)
    • LPARAM:鼠标当前的位置,屏幕坐标系
      • LOWORDx坐标的位置
      • HIWORDy坐标的位置
  • 使用:通过偏移量获取滚动的方向距离
#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;

void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_LBUTTONDOWN:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_LBUTTONUP:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"WM_MOUSEMOVE:其他按键状态:%d, X=%d,Y=%d\n",
		wParam,LOWORD(lParam),HIWORD(lParam));
	//WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnButtonDoubleClick(HWND hWnd,WPARAM wParam,LPARAM lParam){
	char* szText = "WM_LBUTTONDBLCLK\n";
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnMouseWheel(HWND hWnd, WPARAM wParam){
	short nDelta = HIWORD(wParam);
	char szText[256] = {0};
	sprintf(szText,"WM_MOUSEWHEEL:nDelta=%d\n", nDelta);
	WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL);
}

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_MOUSEWHEEL:
		OnMouseWheel(hWnd, wParam);
		break;
	case WM_LBUTTONDBLCLK:
		OnButtonDoubleClick(hWnd,wParam,lParam);
		break;
	case WM_MOUSEMOVE:
		OnMouseMove(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONDOWN:
		OnLButtonDown(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONUP:
		OnLButtonUp(hWnd,wParam,lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述

Unit04定时器消息

01定时器的消息介绍

  • 产生时间:在程序中创建定时器,当达到时间间隔时,定时器会向程序发送一个WM_TIMER消息(实际上是GetMessage发送的消息)。定时器的精度是毫秒,但是准确度很低。例如设置时间间隔为1000ms,但是会在非1000毫秒到达消息。
  • 附带信息:
    • wParam:定时器ID
    • lParam:定时器处理函数指针

02创建销毁定时器

  • 创还能定时器
UINT_PTR SetTimer(
	HWND hWnd,//定时器窗口句柄
	UINT_PTR nIDEvent,//定时器ID
	UINT uElapse,//时间间隔
	TIMERPROC lpTimerFunc//定时器处理函数指针(一般不使用,为NULL)
);//创建成功返回非0
  • 关闭定时器
BOOL KillTimer(
	HWND hWnd,//定时器窗口句柄
	UINT_PTR uIDEvent//定时器ID
);

示例代码:

#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;

void OnTimer(HWND hWnd,WPARAM wParam){
	char szText[256] = {0};
	sprintf(szText,"WM_TIMER:定时器ID=%d\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_TIMER:
		OnTimer(hWnd, wParam);
		break;
	case WM_CREATE:
		SetTimer(hWnd, 1, 1000, NULL);
		SetTimer(hWnd, 2,2000, NULL);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述

Unit05菜单资源

01菜单分类

  • 窗口的顶层菜单(窗口title下面的一长条菜单)
  • 弹出式菜单(右键菜单)
  • 系统菜单(点击窗口title或者logo弹出的菜单)
  • 注意:HMENU(菜单句柄)类型表示菜单,ID表示菜单项

02资源相关

  • 资源脚本文件:*.rc文件
  • 编译器:RC.EXE
    在这里插入图片描述

03菜单资源使用

  • 添加菜单资源
  • 加载菜单资源
    • 注册窗口类时设置菜单
    • 创建窗口传参设置菜单
    • 在主窗口WM_CREATE消息中利用SetMenu函数设置菜单
//加载资源
HMENU LoadMenu(
	HINSTANCE hInstance,//handle to module
	LPCTSTR lpMenuName//menu name or resource identifier
); 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

示例代码:

#include <windows.h>
#include "resource.h"

//***********************
//保存全局窗口实例,为了第三种方法加载菜单中使用SetMenu()函数中获取实例
HINSTANCE g_hIns = 0;
//第三种方法加载菜单在创建窗口消息中触发加载菜单
void OnCreate(HWND hWnd){
	HMENU hMenu = LoadMenu(g_hIns, (char*)IDR_MENU1);
	SetMenu(hWnd, hMenu);
}
//***********************

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	//*****************
	//第三种加载菜单的的方法:在创建窗口消息中加载菜单
	case WM_CREATE:
		OnCreate(hWnd);
		break;
	//****************
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	//将当前窗口实例保存到全局变量中
	g_hIns = hIns;
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	//第一种加载菜单的方法:(char*)IDR_MENU1
	wc.lpszMenuName = NULL;//(char*)IDR_MENU1;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//***********************
	//第二种加载菜单的方法:在创建窗口时使用LoadMenu()函数加载菜单
	//HMENU  hMenu = LoadMenu(hIns,(char*)IDR_MENU1);
	//在内存创建窗口,添加菜单
	//HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,hMenu,hIns,NULL);
	//***********************
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述

04 命令消息(WM_CIMMADN)处理

  • WM_CIMMADN点击菜单项发出的消息
  • 附带信息
    • WPARAM:
      • HIWORD:对于菜单为0(说明没有用)
      • LOWORD:菜单项的ID
    • LPARAM:对于菜单为0

示例代码:

#include <windows.h>
#include "resource.h"

//***********************
//保存全局窗口实例,为了第三种方法加载菜单中使用SetMenu()函数中获取实例
HINSTANCE g_hIns = 0;
//第三种方法加载菜单在创建窗口消息中触发加载菜单
void OnCreate(HWND hWnd){
	HMENU hMenu = LoadMenu(g_hIns, (char*)IDR_MENU1);
	SetMenu(hWnd, hMenu);
}
//***********************
void OnCommand(HWND hWnd,WPARAM wParam){
	switch(LOWORD(wParam)){
	case ID_NEW:
		MessageBox(hWnd, "新建被点击", "Infor", MB_OK);
		break;
	case ID_EXIT:
		MessageBox(hWnd, "退出被点击", "Infor", MB_OK);
		break;
	case ID_ABOUT:
		MessageBox(hWnd, "关于被点击", "Infor", MB_OK);
		break;
	}
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_COMMAND:
		OnCommand(hWnd,wParam);
		break;
	//*****************
	//第三种加载菜单的的方法:在创建窗口消息中加载菜单
	case WM_CREATE:
		OnCreate(hWnd);
		break;
	//****************
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	//将当前窗口实例保存到全局变量中
	g_hIns = hIns;
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	//第一种加载菜单的方法:(char*)IDR_MENU1
	wc.lpszMenuName = NULL;//(char*)IDR_MENU1;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//***********************
	//第二种加载菜单的方法:在创建窗口时使用LoadMenu()函数加载菜单
	//HMENU  hMenu = LoadMenu(hIns,(char*)IDR_MENU1);
	//在内存创建窗口,添加菜单
	//HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,hMenu,hIns,NULL);
	//***********************
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述

05 菜单项状态

06上下文菜单

  • 显示上下文菜单(弹出式菜单)
BOOL TrackPopupMenu(  
	HMENU hMenu,   	//菜单句柄
	UINT uFlags,   	//显示方式
	int x,   			//鼠标水平位置,屏幕坐标系
	int y, 				//鼠标垂直位置,屏幕坐标系
	int nReserved, 	//保留,必须为0
	HWND hWnd,   	//处理菜单消息的窗口句柄
	const RECT* prcRect //NULL,此参数可忽略
); //TrackPopupMenu是阻塞函数
  • 处理上下文菜单弹出的两种方式
    • WM_RBUTTONUP:鼠标右键抬起消息为窗口坐标系,要使用需将其转成屏幕坐标系坐标,可通过ClientToScreen函数进行转换
    • WM_CONTEXTMENU
      • WPARAM:右键点击的窗口句柄
      • LPARAM:对于菜单为0
        • HIWORD:X坐标,屏幕坐标
        • LOWORD:Y坐标,屏幕坐标
      • WM_CONTEXTMENU消息是在WM_RBUTTONUP消息之后产生
BOOL ClientToScreen(  
	HWND hWnd,       // handle to window
	LPPOINT lpPoint  // screen coordinates
);

示例代码1:通过WM_RBUTTONUP消息进行弹出,这种方式显示的上下文菜单有一点问题,因为我们所需要的鼠标位置是屏幕坐标系下的坐标,而通过lParam获取的是客户窗口坐标系的坐标,所以导致鼠标右键点击出现的上下文菜单和鼠标的位置有一定的距离,偏差较大

#include <windows.h>
#include "resource.h"

//***********************
//保存全局窗口实例,为了第三种方法加载菜单中使用SetMenu()函数中获取实例
HINSTANCE g_hIns = 0;
//第三种方法加载菜单在创建窗口消息中触发加载菜单
void OnCreate(HWND hWnd){
	HMENU hMenu = LoadMenu(g_hIns, (char*)IDR_MENU1);
	SetMenu(hWnd, hMenu);
}
//***********************
void OnCommand(HWND hWnd,WPARAM wParam){
	switch(LOWORD(wParam)){
	case ID_NEW:
		MessageBox(hWnd, "新建被点击", "Infor", MB_OK);
		break;
	case ID_EXIT:
		MessageBox(hWnd, "退出被点击", "Infor", MB_OK);
		break;
	case ID_ABOUT:
		MessageBox(hWnd, "关于被点击", "Infor", MB_OK);
		break;
	}
}

void OnRButtonUp(HWND hWnd,LPARAM lParam){
	HMENU hMain = LoadMenu(g_hIns, (char*)IDR_MENU1);
	//GetSubMenu函数获取hMain大菜单[文件0,帮助1]中的小菜单[文件0]
	HMENU hPopup = GetSubMenu(hMain,0);
	TrackPopupMenu(hPopup,TPM_CENTERALIGN|TPM_VCENTERALIGN,LOWORD(lParam),HIWORD(lParam),0,hWnd,NULL);
}

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	//上下文菜单弹出的时机:在鼠标右键抬起时弹出上下文菜单
	case WM_RBUTTONUP:
		OnRButtonUp(hWnd,lParam);
		break;
	case WM_COMMAND:
		OnCommand(hWnd,wParam);
		break;
	//*****************
	//第三种加载菜单的的方法:在创建窗口消息中加载菜单
	case WM_CREATE:
		OnCreate(hWnd);
		break;
	//****************
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	//将当前窗口实例保存到全局变量中
	g_hIns = hIns;
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	//第一种加载菜单的方法:(char*)IDR_MENU1
	wc.lpszMenuName = NULL;//(char*)IDR_MENU1;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//***********************
	//第二种加载菜单的方法:在创建窗口时使用LoadMenu()函数加载菜单
	//HMENU  hMenu = LoadMenu(hIns,(char*)IDR_MENU1);
	//在内存创建窗口,添加菜单
	//HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,hMenu,hIns,NULL);
	//***********************
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

示例代码2:通过WM_CONTEXTMENU方式弹出

#include <windows.h>
#include "resource.h"

//***********************
//保存全局窗口实例,为了第三种方法加载菜单中使用SetMenu()函数中获取实例
HINSTANCE g_hIns = 0;
//第三种方法加载菜单在创建窗口消息中触发加载菜单
void OnCreate(HWND hWnd){
	HMENU hMenu = LoadMenu(g_hIns, (char*)IDR_MENU1);
	SetMenu(hWnd, hMenu);
}
//***********************
void OnCommand(HWND hWnd,WPARAM wParam){
	switch(LOWORD(wParam)){
	case ID_NEW:
		MessageBox(hWnd, "新建被点击", "Infor", MB_OK);
		break;
	case ID_EXIT:
		MessageBox(hWnd, "退出被点击", "Infor", MB_OK);
		break;
	case ID_ABOUT:
		MessageBox(hWnd, "关于被点击", "Infor", MB_OK);
		break;
	}
}

void OnContextMenu(HWND hWnd,LPARAM lParam){
	HMENU hMain = LoadMenu(g_hIns, (char*)IDR_MENU1);
	//GetSubMenu函数获取hMain大菜单[文件0,帮助1]中的小菜单[文件0]
	HMENU hPopup = GetSubMenu(hMain,0);
	TrackPopupMenu(hPopup,TPM_LEFTALIGN|TPM_TOPALIGN,LOWORD(lParam),HIWORD(lParam),0,hWnd,NULL);
}

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	//上下文菜单弹出的时机
	case WM_CONTEXTMENU:
		OnContextMenu(hWnd,lParam);
		break;
	case WM_COMMAND:
		OnCommand(hWnd,wParam);
		break;
	//*****************
	//第三种加载菜单的的方法:在创建窗口消息中加载菜单
	case WM_CREATE:
		OnCreate(hWnd);
		break;
	//****************
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	//将当前窗口实例保存到全局变量中
	g_hIns = hIns;
	//注册窗口类
	WNDCLASS wc = {0};
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	//第一种加载菜单的方法:(char*)IDR_MENU1
	wc.lpszMenuName = NULL;//(char*)IDR_MENU1;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//***********************
	//第二种加载菜单的方法:在创建窗口时使用LoadMenu()函数加载菜单
	//HMENU  hMenu = LoadMenu(hIns,(char*)IDR_MENU1);
	//在内存创建窗口,添加菜单
	//HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,hMenu,hIns,NULL);
	//***********************
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/415558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt的内存管理机制

QObject的parent设置为null 1.如果构造时直接指定了null&#xff0c;当前实例不会有父对象存在&#xff0c;Qt也不能自动析构该实例&#xff0c;除非实例超出作用域导致析构函数被调用&#xff0c;使用deletelater()函数&#xff0c;不建议使用delete 2.如果指定了parent&#…

关于电商商品数据API接口列表,你想知道的(详情页、Sku信息、商品描述、评论问答列表)

目录 一、商品数据API接口列表 二、商品详情数据API调用代码item_get 三、获取sku详细信息item_sku 四、获得淘宝商品评论item_review 五、数据说明文档 进入 一、商品数据API接口列表 二、商品详情数据API调用代码item_get <?php// 请求示例 url 默认请求参数已经URL…

数据结构-插入排序

一.概要 插入排序是一种基于比较的排序算法&#xff0c;其基本思想是将待排序的元素插入到已排序的序列中&#xff0c;形成新的有序序列。 插入排序算法的过程如下&#xff1a; 将待排序序列分为两部分&#xff1a;已排序部分和未排序部分&#xff1b; 初始时&#xff0c;已…

C++string类的详细使用方法

String类的详细使用 文章目录String类的详细使用初始化扩容空间resize与reserve扩容长度获取插入与删除函数运算符插入append插入assign字符串截取push_back尾插erase删除replase替换swap交换pop_back尾删substr截断字符串功能copy拷贝find查找rfind反向查找find_first_of匹配查…

三路快排(基于三指针单趟排序的快速排序)+快排时间复杂度再分析

目录 一.前言 二. 三路快排 &#x1f60d;算法思想: &#x1f60d;算法实现步骤: &#x1f60d;三指针单趟排序的实现:​ &#x1f60d;非递归快排完全体: &#x1f914;与C标准库里的快排进行对比测试: 三.快排时间复杂度再分析 一.前言 http://t.csdn.cn/mz8dghttp://…

SolidWorks2020安装教程

破解文件及步骤 和 安装包 hf&#xff1a;SolidWorks2020 即可 &#xff08;我的推广 共中号&#xff09; Before installation, block the outgoing Internet access by means of Windows Firewall or cord plug. Check .NET Framework 3.5 and 4.0 are installed. If .NET …

Hive安装与操作

目录 环境 数据 实验步骤与结果 &#xff08;1&#xff09;环境启动 &#xff08;2&#xff09;Hive基本操作 环境 Hadoop集群开发环境、mysql、Hive环境 数据 course.txt、sc.txt、student.txt 实验步骤与结果 &#xff08;1&#xff09;环境启动 ①执行命令&#xf…

JVM的内存结构(超详细附加大厂面试题)

内存结构 1、什么是 JVM &#xff1f; 1&#xff09;定义 Java Virtual Machine &#xff0c;Java 程序的运行环境&#xff08;Java 二进制字节码的运行环境&#xff09;。 2&#xff09;好处 一次编译&#xff0c;处处执行 自动的内存管理&#xff0c;垃圾回收机制 数组下…

结构重参数化宇宙(Re-parameterization Universe)

文章目录0. 前言1. Re-parameterization Universe1.1 RepVGG1.2. RepOptimizer2. 应用参考资料0. 前言 一方面&#xff0c;大量研究表明&#xff0c;多分支网络架构的性能普遍优于单分支架构&#xff1b;另一方面&#xff0c;相比多分支架构&#xff0c;单分支架构更有利于部署…

windows系统管理_windows server 2016 用户管理

用户账户的概述 **计算机用户账户&#xff1a;**由将用户定义到某一系统的所有信息组成的记录,账户为用户或计算机提供安 全凭证&#xff0c;包括用户名和用户登陆所需要的密码&#xff0c;以及用户使用以便用户和计算机能够登录到网络并 访问域资源的权利和权限。不同的身份拥…

自动控制原理模拟卷2

自动控制原理模拟题二 Question1 电炉温度控制系统原理如下图所示,分析系统保持电炉温度恒定的工作过程,指出系统的被控对象、被控量及各部件的作用,并画出系统方块图。 解: 电炉使用电阻丝加热,并要求保持炉温恒定,图中采用热电偶来测量电炉温并将其转换为电压信号,将…

Android 新版 Logcat 操作小技巧

新版的Android Studio中启用了新的 Logcat&#xff0c;有些小技巧这里介绍一下&#xff1a; 文章目录1. Logcat启动2. Logcat 搜索1. 搜索当前包名下的日志&#xff1a;2. 添加日志级别3. 添加标签4. 标签字段5. 排除字段6. 使用正则表达式7. 使用正则表达式排除8. 使用age截取…

初识C语言 ——“C Primer Plus”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是读一本好书&#xff0c;这一本书的名字就叫做《C Primer Plus》&#xff0c;那么&#xff0c;又回到了我们的初识C语言阶段啦&#xff0c;保证零基础都能看懂噢&#xff0c;下面&#xff0c;让我们进入C语言的…

app抓包实战

文章目录一、抓包原理二、常用应用场景三、过滤四、重发五、修改请求六、断点&#xff08;BreakPoint&#xff09;一、抓包原理 二、常用应用场景 解决移动端接口测试 解决接口测试过程中检查传参错误问题 mock测试&#xff08;虚拟的对象代替正常的数据、后端接口没有开发完成…

XXL-JOB分布式任务调度平台搭建以及和SpringBoot整合应用

1 前言 XXL-JOB 是一个轻量级分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。 可以前往 Gitee 地址进行下载使用&#xff1a; https://gitee.com/xuxueli0323/xxl-job.g…

计算机网络考试复习——第三章 3.1 3.2

本章考试范围为3.1 3.2 3.3 3.4 首先明确数据链路层在网络中是在物理层的上面从下网上看是在第二层&#xff0c;在数据链路层传输的单位是帧。 网络中的主机、路由器等都必须实现数据链路层&#xff0c;局域网中的主机、交换机等都必须实现数据链路层。 数据链路层的地位&am…

Win10 下编译 OpenCV 4.7.0详细全过程,包含xfeatures2d

在Win10下编译 OpenCV 4.7.0过程中&#xff0c;踩了几个坑&#xff0c;这里记录下来&#xff0c;供大家参考。 1. 下载源文件 GitHub上下载OpenCV 4.7.0源文件&#xff0c;及opencv_contrib-4.7.0&#xff0c;如果不方便下载&#xff0c;以下是百度网盘链接&#xff0c;有需要…

maven将jar包添加到本地仓库

第一步&#xff1a;下载需要添加的jar包 可以在maven库中查找下载&#xff0c;也可以在对应官网下载 maven库网址&#xff1a;https://mvnrepository.com/ 找到对应版本的jar包下载 第二步&#xff1a;将下载的jar包放到指定位置&#xff08;位置自己指定&#xff09;&#xf…

Spring的核心与设计思想

目录 IoC 传统程序开发思想 传统程序开发的缺陷 控制反转式程序开发 对比总结 理解Spring IoC DI 总结 我们通常所说的Spring指的是Spring Framework(Spring 框架),它是一个开源的框架,有着活跃而庞大的社区,Spring支持广泛的应用场景,可以让Java企业级的应用程序开发…

改进蚁狮优化算法

目录 ​1 主要内容 2 部分程序 3 程序结果 4 程序链接 ​1 主要内容 该程序方法复现《改进蚁狮算法的无线传感器网络覆盖优化》两种改进算法模型&#xff0c;即原始ALO算法的基础上添加了两种改进策略&#xff1a; - 改进1&#xff1a;将原先的间断性边界收缩因子变为连…