ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Windows编程之SDK-01.基础篇

2022-01-16 09:32:27  阅读:162  来源: 互联网

标签:01 窗口 Windows 句柄 WM int HINSTANCE NULL SDK


【前言】

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;
}

标签:01,窗口,Windows,句柄,WM,int,HINSTANCE,NULL,SDK
来源: https://blog.csdn.net/shmilyaxy/article/details/122519286

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有