Window游戏编程 (二) 创建两个窗口

#define WIN32_LEAN_AND_MEAN //预编译指令 指示编译器不要包含MFC的内容

#include 
#include 

//我们创建的窗口和其他应用程序窗口都会产生事件和消息,所有消息都进入一个队列,并且我们的窗口消息发送到我们的窗口专用队列中,
//然后,主事件循环检索这些消息,并且把他们我们的窗口WindowProc中处理
/*
hwnd:窗口句柄,当我们使用同一个类建立多个窗口时才会用到,hwnd是表明消息来自哪个窗口的唯一途径
*/
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	PAINTSTRUCT ps;
	HDC hdc;
	static int cnt = 2;
	switch (msg) {
		case WM_ACTIVATE: {//当窗口第一次创建
			return 0;
		}break;
		case WM_PAINT: {//当窗口需要重画
			hdc = BeginPaint(hwnd, &ps); //BeginPaint()EndPaint()这一对调用将激活窗口,并使用存储在Windows类中变量hbrBackground填充背景
			EndPaint(hwnd, &ps);
			return 0;
		}break;
		case WM_DESTROY: {//用户关闭窗口时调用,而不是应用程序,应用程序继续运行
			cnt--;
			if (cnt == 0) {
				PostQuitMessage(0);//通知windows终止应用程序
			}			
			return 0;
		}break;
		default:
			break;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}

/*
#define WINAPI __stdcall
#define CALLBACK __stdcall
__stdcall: 函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。
__cdecl: C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。
WINAPI声明符: 一般用于修饰动态链接库中导出函数 3. CALLBACK仅用于修饰回调函数
*/
int WINAPI WinMain(HINSTANCE hinstance, /*windows为应用程序生成的实例句柄。实例是一个指针或一个数。 本例中hinstance用来跟踪应用程序*/
	HINSTANCE hprevinstance,/*用来跟踪应用程序以前的实例,目前不再使用,微软要去除它*/
	LPSTR lpcmdline,//空值终止字符串
	int ncmdshow) {//启动过程中被传递给应用程序,带有如何打开主应用程序窗口的信息。这样用户可以有些控制程序如何启动的能力,可以在函数ShowWindow()中使用
	MessageBox(NULL,
		"Hello",//多字节编码 https://blog.csdn.net/luoweifu/article/details/49382969
		"My First Windows Program",
		MB_OK | MB_ICONEXCLAMATION);
		MessageBeep(MB_OK);//点击按钮后有声音
	/*
	函数返回一个值通知我们发生了什么事,比如IDABORT, IDCANCEL
	int MessageBox(
    _In_opt_ HWND hWnd, 窗口句柄,设置为null,Windows桌面被用作父窗口
    _In_opt_ LPCSTR lpText, 包含显示文本的空值终止字符串
    _In_opt_ LPCSTR lpCaption, 包含显示文本框标题的空值终止字符串
    _In_ UINT uType); 决定显示的是哪种信息框
	*/

	WNDCLASSEX wc = { 0 };
	wc.cbSize = sizeof(wc);
	wc.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hinstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "WINCLASS1";//每个window类代表我们的应用程序所创建的不同的窗口类型,windows需要一些途径跟踪识别它们,lpszClassName就是用于此目的,
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassEx(&wc)) {//注册一个拓展的窗口类,将新类通知给windows
		return 0;
	};

	HWND hwnd;
	//返回新建窗口句柄,失败了返回null
	if (!(hwnd = CreateWindowEx(NULL,"WINCLASS1","My First Window",
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,//WS_VISIBLE 自动显示的类型标识符
		0, 0,//窗口左上角位置
		400, 400,
		NULL,//假如存在父窗口,指向父窗口句柄
		NULL,//指向附属该窗口菜单的句柄
		hinstance,//应用程序实例
		NULL))
		) {
		return 0;
	}

	//----------------创建第二个窗口
	wc.lpszClassName = "WINCLASS2";
	if (!RegisterClassEx(&wc)) {//注册一个拓展的窗口类,将新类通知给windows
		return 0;
	};

	HWND hwnd2;
	//返回新建窗口句柄,失败了返回null
	if (!(hwnd2 = CreateWindowEx(NULL, "WINCLASS2", "My First Window",
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,//WS_VISIBLE 自动显示的类型标识符
		200, 200,//窗口左上角位置
		400, 400,
		NULL,//假如存在父窗口,指向父窗口句柄
		NULL,//指向附属该窗口菜单的句柄
		hinstance,//应用程序实例
		NULL))
		) {
		return 0;
	}
	//---------------第二个窗口创建完成
	ShowWindow(hwnd, ncmdshow);//如果没有添加WS_VISIBLE标识符,手动显示
	UpdateWindow(hwnd);//更新窗口内容,并且产生一个WM_PAINT信息

	ShowWindow(hwnd2, ncmdshow);
	UpdateWindow(hwnd2);

	MSG msg;
	//while (GetMessage(&msg, NULL, 0, 0)) {
	//	TranslateMessage(&msg);
	//	DispatchMessage(&msg);//指出所有操作发生的位置,调用WinProc进一步处理
	//}

	while (TRUE) {
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
			if (msg.message == WM_QUIT) {
				break;
			}

			TranslateMessage(&msg);
			DispatchMessage(&msg);//消息发送给Window Procedure
		}
	}

	return 0;
}

为了实现,两个窗口都关闭才推出程序,因此我们添加了一个计数器 static int cnt = 2;

当两个窗口都关闭时,cnt=0,这时再发送WM_QUIT消息。

参考:

https://bbs.csdn.net/topics/270046351

你可能感兴趣的:(DXD12)