【前言】
1.第一个窗口程序
- 对于空项目创建的窗口程序,第一步是先修改项目属性【链接器->系统->子系统->窗口】
1.1WinMain函数【A版】【W版】【T版】--Windows API 都有的版本
- ASC对应A版;UniCode对应W版;公共对应T版;
- 一般【属性->高级->字符集->UNICODE字符集(默认的)】
- 默认的都是UniCode工程,意思默认使用W版的API
- 但是不管是ASC还是UniCode都有弊端,不能综合,因此推荐使用T版
#include<Windows.h>
#include<tchar.h>
//**********************W版本**********************
//关于APIENTRY宏代表的含义->__stdcall
//#define APIENTRY WINAPI
//#define WINAPI __stdcall
int APIENTRY WinMain(
HINSTANCE hInstance, //实例句柄[重点]
HINSTANCE hPreInstance, //前实例句柄
LPSTR lpCmdLine, //命令行参数
int nCmdShow //显示方式
)
//①因为默认的是UNICODE;所以现在的WinMain其实是W版的->wWinMain
//②因为默认的是UNICODE;所以现在LPSTR其实也是W版的->LPWSTR
//**********************A版本**********************
//关于APIENTRY宏代表的含义->__stdcall
//#define APIENTRY WINAPI
//#define WINAPI __stdcall
int APIENTRY WinMain(
HINSTANCE hInstance, //实例句柄[重点]
HINSTANCE hPreInstance, //前实例句柄
LPSTR lpCmdLine, //命令行参数
int nCmdShow //显示方式
)
//①因为默认的是ASC;所以现在的WinMain其实是W版的->AWinMain
//②因为默认的是ASC;所以现在LPSTR其实也是W版的->PWSTR
//**********************T版本**********************
//关于APIENTRY宏代表的含义->__stdcall
//#define APIENTRY WINAPI
//#define WINAPI __stdcall
int APIENTRY _tWinMain(
HINSTANCE hInstance, //实例句柄[重点]
HINSTANCE hPreInstance, //前实例句柄
LPTSTR lpCmdLine, //命令行参数
int nCmdShow //显示方式
)
{
//MessageBoxW(0, L"Hello", L"First Window", 0);
//MessageBoxA(0, "Hello", "First Window", 0);
//不管默认的是A版还是W版,我们直接用MessageBox使用的是默认的版本
//如果想用其他版本,则需要根据版本再MessageBox后+W/A/T
//但是因为A版和W版的输入内容有差别,无法综合使用,因此Windows推荐使用T版
MessageBox(0,_T("Hello"), _T("First Window"), 0);
//_T需包含头文件#include<tchar.h>
return 0;
}
- 【注意】T版的输入内容_T需包含头文件#include
- 默认的版本,直接用MessageBox就能输出;如果想输出其他版本,则需要再后面+A/W;切记T版不用加
2.数字和字符串的转换
#include<Windows.h>
#include<tchar.h>
#include<stdio.h>
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR lpCmdLine, int nCmdShow)
{
int a = 100;
int b = 200;
int c = a + b;
//将int转换成字符串
CHAR cBuff[20] = {};
//_itoa_s(c, cBuff, 20, 10);//参数:需转换的int变量;接收转换的char变量;接收变量大小;转换进制
sprintf_s(cBuff, 20, "%d", c);//需包含头文件stdio.h
MessageBoxA(0, cBuff, 0, 0);
//wchar_t to int 宽字节转换成整数
WCHAR wBuff[20] = { L"3000" };
DWORD number1 = 0;
//swscanf_s(wBuff, L"%d", &number1);
//to给的是返回值
number1 = _wtoi(wBuff);
//T版函数
//int 转 wchar_t ->T版参数:宽字节类型地址;大小;L+%d;转换的int
//_stprintf_s(wBuff, 20,L"%d",c);
//wchar_t 转 int ->T版参数:宽字节类型地址;L+%d;转换的int的地址
//_stscanf_s(wBuff, L"%d", &c);
//to给的是返回值
c=_tstoi(wBuff);
return 0;
}
3.A版字符和W版字符转换
【注意】:W2A和A2W;返回一个值需要用对应的类型指针接收;
#include<Windows.h>
#include<tchar.h>
#include<atlbase.h>
//宏定义:
//宽字符转换多字符Unicode-->ASCII
#define WCHAR_TO_CHAR(lpW_Char,lpChar)\
WideCharToMultiByte(CP_ACP,NULL,lpW_Char,-1,lpChar,_countof(lpChar),NULL,FALSE)
//lpW_Char->宽字符缓存区;lpChar->多字符缓存区;
//多字符转换为宽字符ASCII-->Unicode
#define CHAR_TO_WCHAR(lpChar,lpW_Char)\
MultiByteToWideChar(CP_ACP,NULL,lpChar,-1,lpW_Char,_countof(lpW_Char))
int APIENTRY _tWinMain(
HINSTANCE hInstace,
HINSTANCE hPreInstace,
LPTSTR lpCmdLine,
int nCmdShow
)
{
CHAR cBuff[20] = { "hello char" };
WCHAR wBuff[20] = { L"hello wchar_t" };
CHAR cBuffTemp[20] = {};
CHAR* pcBuff = NULL;
WCHAR* pwBuff = NULL;
WCHAR_TO_CHAR(wBuff, cBuffTemp);
//包含头文件atlbase.h
//使用之前需要声明 USES_CONVETSION
USES_CONVERSION;
pcBuff = W2A(wBuff);
pwBuff = A2W(cBuff);
return 0;
}
4.调试相关问题
#include<Windows.h>
#include<tchar.h>
//输出信息显示->自己封装的_trace函数
bool _trace(const TCHAR* format, ...)//变参函数-->参数是格式化字符串
{
TCHAR Buffer[1000];
va_list argptr; //va_list是宏->char*
va_start(argptr, format);//char* argptr=(char*) format
//将格式化信息写入指定的缓冲区 Buffer
wvsprintf(Buffer, format, argptr);//参数:1.输出缓冲区,最大为1024字节
// 2.格式字符串
// 3.需输出的参数
va_end(argptr);//argptr=nullptr
//将缓冲区信息输出
OutputDebugString(Buffer);
return true;
}
//弹出信息显示->自己封装的MyMessageBox函数
bool MyMessageBox(const TCHAR* format, ...)//变参函数-->参数是格式化字符串
{
TCHAR Buffer[1000];
va_list argptr; //va_list是宏->char*
va_start(argptr, format);//char* argptr=(char*) format
//将格式化信息写入指定的缓冲区 Buffer
wvsprintf(Buffer, format, argptr);//参数:1.输出缓冲区,最大为1024字节
// 2.格式字符串
// 3.需输出的参数
va_end(argptr);//argptr=nullptr
//将缓冲区信息输出
MessageBox(0, Buffer, _T("提示信息"), 0);
return true;
}
//弹出错误码
void MyGetErrorInfo(LPCTSTR lpErrInfo, UINT unErrCode, UINT unLine)//unLine=__LINE__
{
LPTSTR lpMsgBuf = nullptr;
WCHAR szMessage[128] = { 0 };
WCHAR szCaption[32] = { 0 };
//第三个参数是错误码,第五个参数是输出缓冲区
FormatMessage(0x1300, NULL, unErrCode, 0x400, (LPTSTR)&lpMsgBuf, 64, NULL);
swprintf_s(szMessage, 128, L"Error_0x%08X:%s", unErrCode, lpMsgBuf);
swprintf_s(szCaption, 32, L"%s(Error Line:%05d)", lpErrInfo, unLine);
MessageBox(NULL, szMessage, szCaption, MB_OK);
}
int APIENTRY _tWinMain(
HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPTSTR lpCmdLine,
int nCmdShow
)
{
//Windows 编程种,天使信息查看的几种方式
//1.通过OutputDebugString将信息输出到输出窗口上
//调试模式下:调试->窗口->输出
//双击运行的时候,使用Debug View 查看输出信息
OutputDebugString(L"hello");
//2.使用自己封装的_trace函数
_trace(_T("%d %d %s"), 100, 200, _T("hello"));
MyMessageBox(_T("%d %d %s"), 100, 200, _T("hello"));
//错误查询的三种方法【主用第三种】
CreateWindow(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
//1.通过GetLastError函数获取上次执行后的错误码,然后查询
//工具->错误查找
int nErrCode = GetLastError();//必须打断点,只看现在之前的错误,后面会覆盖
//2.自己封装函数弹出错误信息
//__LINE__ 获取当前行号
//__FILE__ 获取当前文件名
//__FUNCTION__ 获取当前函数名
MyGetErrorInfo(_T("错误提示"), nErrCode, __LINE__);
//3.最长用的方式,监视窗口->【err,hr】查看错误信息
return 0;
}
5.创建窗口的相关内容
/*********************************************************************
窗口创建:
1.设计窗口:窗的结构体
2.注册窗口
3.创建窗口
4.显示窗口
5.消息泵
**********************************************************************/
#include<Windows.h>
#include<tchar.h>
HINSTANCE g_hInstance = 0;
// 自定义消息
#define WM_GETID WM_USER + 1
// Windows 消息分为三大类
// 1. 通用消息,WM_XXX
// 窗口消息:任何一个窗口都有的消息
// 命令消息:WM_COMMAND:简单的控件产生的。按钮,文本框,...
// 通知消息:WM_NOTIFY: 复杂控件产生的消息。比如,列表,树,
//
// 2. 控件消息
// BM_XXX,EM_XXX,特定控件产生的消息
//
// 3. 自定义消息,用户自己定义,在 WM_USER 之后
// #define WM_GETID WM_USER + 1
//回调函数
//*********************************************************************************
LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_CREATE://窗口创建
{
//在主窗口创建的时候,创建一个按钮
CreateWindow(_T("button"), _T("按钮1"), WS_CHILD | WS_VISIBLE, 10, 10, 80, 30, hWnd,
(HMENU)0x1000, //当创建的是一个标准控件的时候,此时是一个控件ID
g_hInstance, NULL);
//在主窗口创建的时候,创建第二个按钮
CreateWindow(_T("button"), _T("按钮2"), WS_CHILD | WS_VISIBLE, 10, 50, 80, 30, hWnd,
(HMENU)0x1001, //当创建的是一个标准控件的时候,此时是一个控件ID
g_hInstance, NULL);
break;
}
// WM_COMMAND 消息是由控件产生的
case WM_COMMAND:
{
//WPARAM的低两字节是控件ID
//高两字节是消息码
//LPARAM保存的是窗口的句柄
BN_CLICKED;//当用户单击按钮时发送。
WORD Id = LOWORD(wParam);
switch (Id)
{
case 0x1000:
{
//给指定窗口发送指定消息
SendMessage(hWnd, WM_GETID, wParam, lParam);
break;
}
case 0x1001:
{
//获取计算机的句柄,给计算器0x83这个按钮发送消息
//FindWindow函数用来查询主窗口(子窗口不能查询),并且返回窗口句柄。
// 函数原型:
// praram[in] lpClassName:以NULL结尾的字符串,如果为NULL,则查找所有与lpWindowName的窗口;
// param[in] lpWindowName:以NULL结尾的字符串,表示需要查找的窗口的名称(窗口标题),如果为NULL,查找所有窗口。
// return 返回窗口的句柄,如果没有查询到返回NULL,可以用GetLastError()获取失败原因。
HWND hCalc = FindWindow(NULL, _T("计算器"));
BN_CLICKED;//当用户单击按钮时发送。
//构造 按钮被点击的事件
//按钮被点击的时候,响应的是WM_COMMAND消息
//WPARAM高两字节保存的是消息码,BN_CLICKED是0
// 低两字节保存的是ID,通过spy++获取
SendMessage(hCalc, WM_COMMAND, WPARAM(0x83), NULL);
break;
}
default:
break;
}
break;
}
case WM_GETID: //自定义的
{
MessageBox(0, _T("获取id"), 0, 0);
break;
}
case WM_KEYDOWN:
{
OutputDebugString(_T("key_down\n"));
break;
}
case WM_KEYUP:
{
OutputDebugString(_T("key_up\n"));
break;
}
case WM_CHAR:
{
OutputDebugString(_T("key_char\n"));
break;
}
case WM_CLOSE:
{
//队列消息
//PostMessage:将消息放进消息队列中,继续往下执行
PostMessage(hWnd,WM_GETID,wParam,lParam);
//非队列消息
//SendMessage:直接将消息发送到回调函数,等回调函数执行完成,
// 才返回,继续执行代码
//SendMessage(hWnd, WM_GETID, wParam, lParam);
PostQuitMessage(0);
break;
}
default:
break;
}
// 不需要自己处理的消息,就返回到默认的消息处理函数
return DefWindowProc(hWnd, Message, wParam, lParam);
}
int APIENTRY _tWinMain(
HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPTSTR lpCmdLine,
int nCmdShow
)
{
g_hInstance = hInstance;
//1.设计窗口
//*********************************************************************************
//WNDCLASS是一个结构体,包含了窗口的一些成员属性
// typedef struct tagWNDCLASSW {
// UINT style;
// WNDPROC lpfnWndProc;
// int cbClsExtra;
// int cbWndExtra;
// HINSTANCE hInstance;
// HICON hIcon;
// HCURSOR hCursor;
// HBRUSH hbrBackground;
// LPCWSTR lpszMenuName;
// LPCWSTR lpszClassName;
// } WNDCLASSW, * PWNDCLASSW, NEAR* NPWNDCLASSW, FAR* LPWNDCLASSW;
//#ifdef UNICODE
// typedef WNDCLASSW WNDCLASS;
WNDCLASS ws = {};
//类的风格
//1.CS_VREDRAW 高度改变重绘 CS_HREDRAW 宽度改变重绘
//2.CS_DBLCLKS 鼠标双击时系统所发的消息
//3.CS_NOCLOSE 禁用系统菜单种的关闭命令
//4.CS_OWNDC 为该窗口类的各窗口分配各自独立的设备环境
//5.CS_CLASSDC 为该窗口类的各窗口分配一个共享的设备环境
//6.CS_PARENtdC指定子窗口继承其父窗口的设备环境
ws.style = CS_VREDRAW | CS_HREDRAW;
//窗口回调函数【非常重要】
ws.lpfnWndProc = WndProc;//要自己写一个回调函数
//实例句柄,窗口类注册到哪个实例程序中
//理解为生成的同一个程序,实例句柄都是一样的
ws.hInstance = hInstance;
//窗口类名【非常重要】
ws.lpszClassName = _T("窗口类名");
//窗口背景色
//宏代表数字
//ws.hbrBackground = (HBRUSH)COLOR_HIGHLIGHT;
ws.hbrBackground = CreateSolidBrush(RGB(255, 0, 0));
//-----------------------------------------------------
//资源部分
// HICON hIcon; // 图标
// HCURSOR hCursor; // 光标
// LPCWSTR lpszMenuName; // 菜单
//2.注册窗口
//*********************************************************************************
//窗的结构体定义了一个变量ws,并且我们设计好了这个窗口的一些基本内容
RegisterClass(&ws);
//3.创建窗口
//*********************************************************************************
//CreateWindowExW(
// _In_ DWORD dwExStyle,
// _In_opt_ LPCWSTR lpClassName, 窗口类名
// _In_opt_ LPCWSTR lpWindowName, 窗口名
// _In_ DWORD dwStyle, 窗口风格
// _In_ int X, 窗口左上角坐标
// _In_ int Y,
// _In_ int nWidth, 窗口宽高
// _In_ int nHeight,
// _In_opt_ HWND hWndParent, 父窗口/桌面/NULL
// _In_opt_ HMENU hMenu, 菜单
// _In_opt_ HINSTANCE hInstance, 实例句柄
// _In_opt_ LPVOID lpParam);
//返回值是一个句柄
HWND hWnd = CreateWindow(
_T("窗口类名"), //和设计窗口时候的窗口类名要一致
_T("窗口名"),
WS_OVERLAPPEDWINDOW,
10, 10, 500, 200,
NULL,
NULL,
hInstance,
NULL,
);
//同一个exe打开,这个句柄是不一样的
//int c = (int)hWnd;
//CHAR cBuff[20] = {};
//_itoa_s(c, cBuff, 20, 10);
//MessageBoxA(0, cBuff, 0, 0);
//4.显示更新窗口
//*********************************************************************************
ShowWindow(hWnd, SW_SHOW);
//UpdateWindow函数通过向窗口发送WM_PAINT消息来更新指定窗口的工作区
//(如果该窗口的更新区域不为空)。
//该函数绕过应用程序队列,将WM_PAINT消息直接发送到指定窗口的窗口过程。
//如果更新区域为空,则不发送任何消息。
UpdateWindow(hWnd);
//5.消息循环
//*********************************************************************************
// typedef struct tagMSG {
// HWND hwnd; //这个消息所在的窗口句柄
// UINT message; //消息标识符,如WM_SIZE、WM_COMMAND、WM_QUIT等等
// WPARAM wParam; //32位消息的特定附加信息
// LPARAM lParam; // 32位消息的特定附加信息
// DWORD time; // /消息创建时的时间
// POINT pt; //消息创建时的鼠标位置
//#ifdef _MAC
// DWORD lPrivate;
//#endif
// } MSG, * PMSG, NEAR* NPMSG, FAR* LPMSG;
MSG msg = {};//定义这个结构体为了接收程序队列拿出来的消息
// GetMessage 第二个参数 指定了接受哪一个窗口的消息,
// 填 0 就是全都接受,通常也是写 0
// GetMessageW(
// _Out_ LPMSG lpMsg, 指向MSG结构的指针
// _In_opt_ HWND hWnd, //传入参数。你要获取你程序中哪个窗口的消息,那就把相应的窗口句柄代入其中
// _In_ UINT wMsgFilterMin,
// _In_ UINT wMsgFilterMax);
//#ifdef UNICODE
//#define GetMessage GetMessageW
while (GetMessage(&msg, 0, 0, 0))
{
// 对于可现实字符,会将 key_down 和 key_up 多出一个 key_char
TranslateMessage(&msg);
// 分发消息
DispatchMessage(&msg);
}
return 0;
}