相比于 vc++ 默认实例的那个两百行,这个精简很多。
#include <windows.h>
#include <stdio.h>
// 不使用 Win98 风格
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
// 窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
// 关闭窗口
switch (msgID) {
case WM_DESTROY:
PostQuitMessage(0); // 可以使 GetMessage 函数返回 0
break;
}
return DefWindowProc(hWnd, msgID, wParam, lParam);
}
// 入口函数
//int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdShow, int nCmdShow) { // 旧版本入口用这行
int WINAPI wWinMain(HINSTANCE hIns, HINSTANCE hPreIns, PWSTR lpCmdLine, int nCmdShow){ // vs 2022 用的这行
// 注册窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0; // 窗口类的附加数据 buff 的大小
wc.cbWndExtra = 0; // 窗口的附加数据 buff 的大小
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 绘制窗口背景的画刷句柄
wc.hCursor = NULL; // 鼠标的句柄
wc.hIcon = NULL; // 窗口图标的句柄
wc.hInstance = hIns; // 当前模块的实例句柄
wc.lpfnWndProc = WndProc; // 窗口处理函数
wc.lpszClassName = "Main"; // 窗口类的名称
wc.lpszMenuName = NULL; // 窗口菜单的资源 ID 字符串
wc.style = CS_HREDRAW | CS_VREDRAW; // 窗口类的风格(CS_DBLCLICK|CS_NOCLOSE)
// 将以上全部赋值全部写入操作系统
RegisterClass(&wc);
// 在内存中创建窗口
HWND hWnd = CreateWindow("Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);
/* CreateWindowEx 是加强版函数
多了一个dwExStyle: 窗口的扩展风格
窗口创建的过程:
1、根据窗口名称,到每一个窗口类中找到相应的窗口。
2、如果找到,把 HINSTANCE (即 hIns)对比,如果相等,创建窗口。
3、找不到,到应用程序全局窗口类中寻找,还没找到,到系统窗口类寻找
*/
// 显示窗口
ShowWindow(hWnd, SW_SHOW);
// 刷新窗口
UpdateWindow(hWnd);
// 消息循环
MSG nMsg = { 0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg); // 将窗口交给窗口处理函数来处理
}
return 0;
}
这里消息是大写字母常量,真正的消息是数字,这些常量就是代表的数字。
产生时间:窗口被销毁时(不是关闭按钮)
常用于窗口被销毁前做的善后处理,如资源和内存
产生时间:点击最大化、最小化、关闭等产生
返回参数 wParam:具体点击的位置,如 SC_CLOSE 关闭 lParam:鼠标光标位置 LOWORD(lParam); //水平位置 HIWORD(lParam); //垂直位置
常用于窗口关闭时,提示用户处理
产生时间:在窗口创建成功但还未显示时。
返回参数 wParam 为 0 lParam 类型是CREATETRUCT类型的指针 可获取到CreatWindowEx中的全部12个参数
常用于初始化窗口的参数
产生时间:窗口大小发生变化后
返回参数 wParam 窗口大小变化的原因 lParam 窗口变化后的大小 LOWORD(lParam); //变化后的宽度 HIWORD(lParam); //变化后的高度
常用于窗口变化后,调整各个部分的布局
产生时间:程序员发生
返回参数 wParam :PostQuitMessage 函数传递的参数 lParam : 0
用于退出。由 GetMessage 接收
使用实例
#include <windows.h>
#include <stdio.h>
HANDLE g_hOutput = 0; // 接受标准输出句柄
void OnCreate(HWND hWnd, LPARAM lParam){
/* 下面三行代码,把开发者在创建窗口之前弹出那个自定义的字符串pszTest */
CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
char* pszText = (char*)pcs->lpCreateParams;
// MessageBox(NULL,pszText,"Infor",MB_OK);
// 还能创建一个子窗口
CreateWindowEx(0,"EDIT","hello",WS_CHILD|WS_VISIBLE|WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);
}
// 打印长宽高信息
void OnSize( HWND hWnd, LPARAM lParam ){
short nWidth = LOWORD(lParam);
short nHight = HIWORD(lParam);
char szText[256] = { 0 };
sprintf( szText, "WM_SIZE:宽:%d,高:%d\n",nWidth,nHight);
WriteConsole( g_hOutput, szText, strlen(szText), NULL, NULL);
}
// 窗口处理函数(自定义,处理消息)
// 参数:窗口句柄、消息ID,消息参数、消息参数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID, WPARAM wParam,LPARAM lParam){
// 关闭窗口
switch(msgID){
case WM_SIZE:
OnSize(hWnd, lParam);
break;
case WM_CREATE:
OnCreate(hWnd, lParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // 可以使 GetMessage 函数返回 0
/*
PostQuitMessage(0) 可以在 GetMessage 函数经常走的道上埋下
一个叫 WM_QUIT 的雷,当 GetMessage 抓取到这雷,则返回 0
*/
break;
case WM_SYSCOMMAND:
if(wParam == SC_CLOSE){
int nRet = MessageBox( hWnd,"是否退出?","Infor",MB_YESNO);
if(nRet == IDYES){
// 什么都不写
}else{
return 0;
}
}
break;
}
return DefWindowProc( hWnd,msgID,wParam,lParam); // 给各种消息默认处理
}
// 入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdShow, int nCmdShow){
//增加 DOS 窗口
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
// 注册窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0; // 窗口类的附加数据 buff 的大小
wc.cbWndExtra = 0; // 窗口的附加数据 buff 的大小
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // 绘制窗口背景的画刷句柄
wc.hCursor = NULL; // 鼠标的句柄
wc.hIcon = NULL; // 窗口图标的句柄
wc.hInstance = hIns; // 当前模块的实例句柄
wc.lpfnWndProc = WndProc; // 窗口处理函数
wc.lpszClassName = "Main"; // 窗口类的名称
wc.lpszMenuName = NULL; // 窗口菜单的资源 ID 字符串
wc.style = CS_HREDRAW|CS_VREDRAW; // 窗口类的风格(CS_DBLCLICK|CS_NOCLOSE)
/*
如果要创建子窗口
1. 需要设置父窗口的句柄。
2. 创建风格(即 CreateWindow 第三个参数)要增加 WS_CHILD|WS_VISIBLE
*/
// 将以上全部赋值全部写入操作系统
RegisterClass( &wc );
// 在内存中创建窗口
char* pszText = "hello data!";
HWND hWnd = CreateWindow( "Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,pszText);
/* CreateWindowEx 是加强版函数
多了一个dwExStyle: 窗口的扩展风格
窗口创建的过程:
1、根据窗口名称,到每一个窗口类中找到相应的窗口。
2、如果找到,把 HINSTANCE (即 hIns)对比,如果相等,创建窗口。
3、找不到,到应用程序全局窗口类中寻找,还没找到,到系统窗口类寻找
*/
// 创建子窗口类
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = hIns;
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = "Child";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW|CS_VREDRAW;
RegisterClass( &wc );
// 创建子窗口
// HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
// HWND hChild2 = CreateWindowEx(0,"Child","c2",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);
// 显示窗口
ShowWindow( hWnd,SW_SHOW);
// 刷新窗口
UpdateWindow( hWnd );
// 消息循环
MSG nMsg = { 0 };
while( GetMessage(&nMsg,NULL,0,0) ){
TranslateMessage( &nMsg );
DispatchMessage( &nMsg ); // 将窗口交给窗口处理函数来处理
}
/*
消息的组成
1.窗口句柄
2.消息ID
3.消息的两个参数
4.消息产生的时间
5.消息产生时的鼠标位置
GetMessage : 到系统内抓本进程的消息
参数:
LPMSG lpMsg // 存放获取的消息BUFF
HWND hWnd // 窗口句柄(填某个句柄,只抓取那个窗口的消息,如果填 NULL 则都抓取)
UINT wMsgFilterMin // 获取消息的最小ID(这两个参数,限定消息的范围,如果都为0,则不限制)
UINT wMsgFilterMax // 获取消息的最大ID
返回值:
直接决定程序能不能退出
TranslateMessage -翻译消息,将 按键翻译成字符消息
tips: 内部第一件事先检查消息是不是按键消息
*/
return 0;
}
#include <windows.h>
#include <stdio.h>
HANDLE g_hOutput = 0; // 接受标准输出句柄
#define WM_MYMESSAGE WM_USER+1001 //自己定制消息,WM_USER = 0x400
void OnCreate(HWND hWnd, LPARAM lParam){
/* 下面三行代码,把开发者在创建窗口之前弹出那个自定义的字符串pszTest */
CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
char* pszText = (char*)pcs->lpCreateParams;
// MessageBox(NULL,pszText,"Infor",MB_OK);
// 还能创建一个子窗口
CreateWindowEx(0,"EDIT","hello",WS_CHILD|WS_VISIBLE|WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);
// 自定义消息
PostMessage( hWnd,WM_MYMESSAGE, 1, 2);
}
// 打印长宽高信息
void OnSize( HWND hWnd, LPARAM lParam ){
short nWidth = LOWORD(lParam);
short nHight = HIWORD(lParam);
char szText[256] = { 0 };
sprintf( szText, "WM_SIZE:宽:%d,高:%d\n",nWidth,nHight);
WriteConsole( g_hOutput, szText, strlen(szText), NULL, NULL);
}
// 自定义消息的处理函数
void OnMyMessage( HWND hWnd, WPARAM wParam, LPARAM lParam ){
char szText[256] = { 0 };
sprintf( szText,"自定义消息被处理:wParam=%d,lParam=%d\n",wParam,lParam);
MessageBox( hWnd, szText, "Infor", MB_OK);
}
// 窗口处理函数(自定义,处理消息)
// 参数:窗口句柄、消息ID,消息参数、消息参数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID, WPARAM wParam,LPARAM lParam){
// 关闭窗口
switch(msgID){
case WM_MYMESSAGE:
OnMyMessage( hWnd, wParam, lParam);
break;
case WM_SIZE:
OnSize(hWnd, lParam);
break;
case WM_CREATE:
OnCreate(hWnd, lParam);
break;
case WM_DESTROY:
PostQuitMessage(0); // 可以使 GetMessage 函数返回 0
/*
PostQuitMessage(0) 可以在 GetMessage 函数经常走的道上埋下
一个叫 WM_QUIT 的雷,当 GetMessage 抓取到这雷,则返回 0
*/
break;
case WM_SYSCOMMAND:
if(wParam == SC_CLOSE){
int nRet = MessageBox( hWnd,"是否退出?","Infor",MB_YESNO);
if(nRet == IDYES){
// 什么都不写
}else{
return 0;
}
}
break;
}
return DefWindowProc( hWnd,msgID,wParam,lParam); // 给各种消息默认处理
}
// 入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdShow, int nCmdShow){
//增加 DOS 窗口
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
// 注册窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0; // 窗口类的附加数据 buff 的大小
wc.cbWndExtra = 0; // 窗口的附加数据 buff 的大小
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // 绘制窗口背景的画刷句柄
wc.hCursor = NULL; // 鼠标的句柄
wc.hIcon = NULL; // 窗口图标的句柄
wc.hInstance = hIns; // 当前模块的实例句柄
wc.lpfnWndProc = WndProc; // 窗口处理函数
wc.lpszClassName = "Main"; // 窗口类的名称
wc.lpszMenuName = NULL; // 窗口菜单的资源 ID 字符串
wc.style = CS_HREDRAW|CS_VREDRAW; // 窗口类的风格(CS_DBLCLICK|CS_NOCLOSE)
/*
如果要创建子窗口
1. 需要设置父窗口的句柄。
2. 创建风格(即 CreateWindow 第三个参数)要增加 WS_CHILD|WS_VISIBLE
*/
// 将以上全部赋值全部写入操作系统
RegisterClass( &wc );
// 在内存中创建窗口
char* pszText = "hello data!";
HWND hWnd = CreateWindow( "Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,pszText);
/* CreateWindowEx 是加强版函数
多了一个dwExStyle: 窗口的扩展风格
窗口创建的过程:
1、根据窗口名称,到每一个窗口类中找到相应的窗口。
2、如果找到,把 HINSTANCE (即 hIns)对比,如果相等,创建窗口。
3、找不到,到应用程序全局窗口类中寻找,还没找到,到系统窗口类寻找
*/
// 创建子窗口类
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = hIns;
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = "Child";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW|CS_VREDRAW;
RegisterClass( &wc );
// 创建子窗口
// HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
// HWND hChild2 = CreateWindowEx(0,"Child","c2",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);
// 显示窗口
ShowWindow( hWnd,SW_SHOW);
// 刷新窗口
UpdateWindow( hWnd );
/* 消息循环*/
MSG nMsg = { 0 };
/* 这种方式效率太低,注释掉 */
/*while( GetMessage(&nMsg,NULL,0,0) ){
TranslateMessage( &nMsg );
DispatchMessage( &nMsg ); // 将窗口交给窗口处理函数来处理
}*/
/* 使用这个方法,(PeekMessage)可以作为侦察兵 */
while(1){
if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)){
// 侦察兵侦查到有消息
if(GetMessage(&nMsg,NULL,0,0)){
// 消息为真
TranslateMessage( &nMsg );
DispatchMessage( &nMsg );
}else{
return 0;
}
}else{
// 空闲处理(利用空闲的时间,即没有消息的时间,来做点事)
WriteConsole( g_hOutput, "OnIdle", strlen("OnIdles"), NULL, NULL);
}
}
/*
*/
/*
消息的组成
1.窗口句柄
2.消息ID
3.消息的两个参数
4.消息产生的时间
5.消息产生时的鼠标位置
GetMessage : 到系统内抓本进程的消息
参数:
LPMSG lpMsg // 存放获取的消息BUFF
HWND hWnd // 窗口句柄(填某个句柄,只抓取那个窗口的消息,如果填 NULL 则都抓取)
UINT wMsgFilterMin // 获取消息的最小ID(这两个参数,限定消息的范围,如果都为0,则不限制)
UINT wMsgFilterMax // 获取消息的最大ID
返回值:
直接决定程序能不能退出
TranslateMessage -翻译消息,将 按键翻译成字符消息
tips: 内部第一件事先检查消息是不是按键消息
*/
return 0;
}
/*
五个常见消息(都是代表一个数字)。:
1. WM_DESTROY
窗口被销毁时(不是关闭按钮)
常用于窗口被销毁前做的善后处理,如资源和内存
2. WM_SYSCOMMAND
点击最大化、最小化、关闭等产生
附带信息,wParam:具体点击的位置,如 SC_CLOSE 关闭
lParam:鼠标光标位置
LOWORD(lParam); //水平位置
HIWORD(lParam); //垂直位置
常用于窗口关闭时,提示用户处理
3. WM_CREATE
在窗口创建成功但还未显示时。
wParam 为 0
lParam 类型是CREATETRUCT类型的指针
可获取到CreatWindowEx中的全部12个参数
常用于初始化窗口的参数
4. WM_SIZE
窗口大小发生变化后
wParam 窗口大小变化的原因
lParam 窗口变化后的大小
LOWORD(lParam); //变化后的宽度
HIWORD(lParam); //变化后的高度
常用于窗口变化后,调整各个部分的布局
5. WM_QUIT
程序员发生
wParam :PostQuitMessage 函数传递的参数
lParam : 0
用于退出。由 GetMessage 接收
*/
/*
发送消息的两个函数
1. SendMessage() - 发送消息 - 像打电话
2. PostMessage() - 投递消息 - 像投递信件
两者的不同是,第一个会等消息处理的结果,无结果会阻塞
,第二个发送后立即返回,不等结果
上面的
PostQuitMessage(0); 等同于 PostMessage( hWnd, WM_QUT, 0, 0);
系统消息
ID范围 0 - 0x03FF
由系统定义好的消息,可以在系统中直接使用
用户自定义消息
ID范围 0x0400 - 0x7FFF (31743个消息)
由用户自己定义,满足用户自己的需求。
*/