Windows应用程序初始框架详细注解

本文介绍了使用Win32 API进行Windows编程的基础知识,包括WinMain函数、窗口类注册、消息循环处理等内容,并提供了完整的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该程序包含了WinMain函数、WNDCLASS结构、CreateWindow函数、tagMSG结构、MessageBox函数等的解析,参考:Introduction to 3D Game Programming with DirectX 11附录1,MSDN

程序流程:

1. 初始化窗口类并注册;

2. 创建窗口;

3. 执行消息循环,如果有消息,调用WndProc函数,否则转4;

4. 图形渲染,游戏逻辑等。

#include <windows.h>

/*
* 创建主窗口句柄:在windows编程中,经常用句柄(handle)来引用由windows内部维护的对象。
* 很多API的调用需要传递该参数。
*/
HWND mainWnd = 0;

bool initWndApp(HINSTANCE hInstance, int show);
int run();
LRESULT CALLBACK
	WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

/*
* hInstance:	当前应用程序实例的句柄,可能有多个应用程序同时运行
* hPreInstance:	该参数不在Win32编程中使用
* pCmdLine:		命令行参数字符串
* nShowCmd:		指定应用程序的显示方式,
*	SW_SHOW:	按当前大小和位置,
*	SW_SHOWMAXIMIZED:最大化,
*	SW_SHOWMINIMIZED:最小化
*/
int WINAPI 
	WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR pCmdLine, int nShowCmd)
{
	if ( !initWndApp(hInstance, nShowCmd) ){
		return 0;
	}

	return run();
}

WINAPI声明符强制参数从左边向右边传递,而默认的CDECL声明符使参数从右到左转移。

lpcmdline相当于C语言main函数的参数char **argv。比如在命令行带参数的运行test.exe:

test.exe hellow

lpcmdline = "hellow"

typedef struct _WNDCLASSEX {
	UINT cbSize;
	UINT style;
	WNDPROC lpfnWndProc;
	int cbClsExtra;
	int cbWndExtra;
	HANDLE hInstance;
	HICON hIcon;
	HCURSOR hCursor;
	HBRUSH hbrBackground;
	LPSTR lpszMenuName;
	LPSTR lpszClassName;
	HICON hIconSm;
}WNDCLASS;

  • style: 指定类的风格,CS_HREDRAW和CS_VREDRAW的组合表示,窗口水平和垂直方向上大小改变时要重绘
  • cbSize:  结构体的大小
  • lpfnWndProc: 指向windows过程函数的指针,该函数与指定的WNDCLASS对象相关联
  • cbClsExtra, cbWndExtra:  可以额外使用的内存空间,
  • hIcon: 图标句柄
  • hCursor: 光标句柄
  • hbrBackground: 背景刷句柄
  • lpszMenuName: 指定窗口菜单
  • lpszClassName: 指定窗口类结构的名称,方便后面引用

bool initWndApp(HINSTANCE hInstance, int show)
{
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.hInstance = hInstance;
	wc.lpfnWndProc = WndProc;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	//使用默认的应用程序图标和光标
	wc.hIcon = LoadIcon(0,IDI_APPLICATION); 
	wc.hCursor = LoadCursor(0, IDC_CROSS);
	//调用win32函数GetStockObject()返回白色画刷句柄
	wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
	wc.lpszMenuName = 0;
	wc.lpszClassName = L"BasicWndClass";
	//注册填好的WNDCLASS实例,以此创建窗口
	if ( !RegisterClass(&wc)) {
		MessageBox(0, L"RegisterClass Failed", 0, 0);
		return false;
	}
	mainWnd = CreateWindow(L"BasicWndClass", L"Win32Basic",WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		0, 0, hInstance, 0);
	if (mainWnd == 0) {
		MessageBox(0, L"CreateWindow FAILED", 0, 0);
		return false;
	}
	ShowWindow(mainWnd, show);
	UpdateWindow(mainWnd);
	return true;
}
//HWND CreateWindow(
//	LPCTSTR lpClassName,
//	LPCTSTR lpWindowName,
//	DWORD dwStyle,
//	int x,
//	int y,
//	int nWidth,
//	int nHeight,
//	HWND hWndParent,
//	HMENU hMenu,
//	HANDLE hInstance,
//	LPVOID lpParam
//	);
/*
* lpClassName:	注册的WNDCLASS类的名称
* lpWindowName:	窗口名称,将显示在标题栏
* dwStyle:		定义窗口风格
* x, y:			窗口左上角坐标
* nWidth, nHeight:窗口的宽和高,可指定为默认的CW_USEDEFAULT
* hWndParent:	父窗口句柄,没有为0
* hMenu:		菜单句柄,没有为0
* hInstance:	应用程序句柄
* lpParam:		指向用户定义类型的指针,如果需要用到WM_CREATE消息句柄。该消息在窗口创建时发出,
*				一般用于在创建窗口时进行一些初始化。
*/

//typedef struct tagMSG{
//	HWND hwnd;
//	UNIT message;
//	WPARAM wParam;
//	LPARAM lParam;
//	DWORD time;
//	POINT pt;	
//}MSG;
/*
* hwnd:		用于接收消息的窗口句柄
* message:	消息标示,如:WM_QUIT
* wParam, lParam:消息的额外信息
* time:		消息发出的时间
* pt:		消息发出时,鼠标光标在屏幕坐标系中的坐标(x,y)
*/
int run()
{
	MSG msg = {0};
	BOOL bRet = 1;
	//while ( (bRet = GetMessage(&msg,0,0,0)) != 0 ) {
	//	//返回-1表示GetMessage出现错误
	//	//返回0 表示收到WM_QUIT消息,需要终止消息循环,
	//	//返回其他值时,先TranslateMessage,Windows会做一些键盘转换,
	//	//特别是将按键转换成字符消息;然后DispatchMessage将消息发送给
	//	//合适的窗口过程
	//	if (bRet == -1) {
	//		MessageBox(0, L"GetMessage FAILED", L"Error", MB_OK);
	//	}else {
	//		TranslateMessage(&msg);
	//		DispatchMessage(&msg);
	//	}
	//}
	// 当消息队列中没有消息时,GetMessage会将进程挂起,直到收到消息。
	// 对于游戏程序,我们并不想这样。在没有消息的时候我们需要做游戏相关的事。
	// PeekMessage在没有消息时会立即返回

	while (msg.message != WM_QUIT) {
		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}else {
			//do animation/game stuff
		}
	}
	return (int)msg.wParam;
}

int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );

  • hWnd: 该消息父窗口的句柄,NULL表示该消息盒子父窗口为桌面
  • lpText: 在盒子中显示的信息
  • lpCaption:盒子的标题,如果是NULL,则默认为Error
  • uType: 指定盒子的内容和行为,
    MB_OK 表示会有一个OK键,类似的还有MB_OKCANCLE,MB_YESNO等
    MB_ICONEXCLAMATION 表示显示一个惊叹号图标,类似的有MB_ICONINFORMATION,MB_ICONQUESTION,MB_ICONSTOP,分别表示I图标,问号图标,终止符图标。MB_DEFBUTTONn 控制默认高亮的按钮,n=1-4
  • 返回值,例如,IDYES表示按下了YES按钮,该返回值可以用来测试用户按下的是哪个键。

//WndProc是一个回调函数,Windows将在程序的代码空间外调用该函数
//用于处理收到的消息,如按键,鼠标点击等。
/*
* hWnd:	接受消息的窗口
* msg:	接受的消息,如:WM_QUIT
* wParam, lParam:消息的额外信息
*/
LRESULT CALLBACK
	WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg){
	case WM_CREATE:
		MessageBox(0, L"窗口创建成功!", L"Create", 0);
		return 0;
	case WM_LBUTTONDOWN:
		MessageBox(0, L"你好!", L"Hello", MB_OK);
		return 0;
	case WM_KEYDOWN:
		//如果按下Escape键,DestroyWindow销毁主窗口
		//wParam参数保存着虚拟键码(Virtual key code)
		if (wParam == VK_ESCAPE){
			DestroyWindow(mainWnd);
		}
		return 0;
	case WM_CLOSE:
		//关闭窗口时提示是否要退出
		if (MessageBox(0, L"确定要退出吗?", L"Exit",
			MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDYES){
				PostQuitMessage(0);
		}
		return 0;
	case WM_DESTROY:
		//当窗口销毁时,发出WM_QUIT消息,退出消息循环
		PostQuitMessage(0);
		return 0;
	}
	//最后调用默认Windows过程函数,处理其他消息
	return DefWindowProc(hWnd, msg, wParam, lParam);
}
  • WM_CREATE,当窗口第一次创建的时候传递该消息,以便进行一些初始化或资源分配。
  • WM_DESTROY,在关闭窗口时被发送。当然,这仅仅是关闭窗口,而不是终止应用程序。必须通过发送WM_QUIT消息,来终止消息循环,从而终止应用程序。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

superbin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值