流程
1 建立并注册windows类
2 使用windows类创建窗口
3 实现事件处理,主循环
PeekMessage与GetMessage的对比
相同点:
PeekMessage函数与GetMessage函数都用于查看应用程序消息队列,有消息时将队列中的消息派发出去。不同点:
无论应用程序消息队列是否有消息,PeekMessage函数都立即返回,程序得以继续执行后面的语句(无消息则执行其它指令,有消息时一般要将消息派发出去,再执行其它指令)。GetMessage函数只有在消息对立中有消息时返回,队列中无消息就会一直等,直至下一个消息出现时才返回。在等的这段时间,应用程序不能执行任何指令。
游戏时一般使用PeekMessage不阻塞,主循环里除了事件外还要处理绘制逻辑等。
TranslateMessage
将虚拟键消息转换为字符消息。字符消息被送到调用线程的消息队列中,在下一次线程调用函数GetMessage或PeekMessage时被读出将虚拟键
消息转换为字符消息。字符消息被送到调用线程的消息队列中,在下一次线程调用函数GetMessage或PeekMessage时被读出
消息转换为字符消息。字符消息被送到调用线程的消息队列中,在下一次线程调用函数GetMessage或PeekMessage时被读出
DispatchMessage
该函数调度一个消息给窗口程序。通常调度从GetMessage取得的消息。消息被调度到的窗口程序即是MainProc()函数
4 实现事件回调处理WinProc
代码
实现上面流程的全部代码,其中全屏相关部分可以去掉(游戏往往才会用到全屏,下面代码主要用来展示win程序创建流程),如果是使用opengl等做游戏,与下面代码不同的地方主要是主循环与绘制方式不同
#include "stdafx.h" #include "Win_Base.h" HINSTANCE hInst; //当前应用的实例句柄 HWND hWnd; //窗口句柄 bool exiting = false; //循环开启标志 bool fullscreen=FALSE; //全屏标志 long windowWidth = 800; //默认窗口宽 long windowHeight = 600;//默认窗口高 long windowBits = 32; //每像素所选的色彩深度 ATOM RegisterWinClass(HINSTANCE hInstance); BOOL CreateWin(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MSG msg; //step1 创建并,注册windows class RegisterWinClass(hInstance); //step2 创建(全屏或者非全屏)窗口 if (!CreateWin(hInstance, nCmdShow)) { return FALSE; } //step3 主循环事件处理 while (!exiting) { while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { if (!GetMessage (&msg, NULL, 0, 0)) { exiting = true; break; } TranslateMessage (&msg); DispatchMessage (&msg); } } if (fullscreen) { ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop ShowCursor(TRUE); // Show Mouse Pointer } return (int) msg.wParam; } //创建并,注册windows class ATOM RegisterWinClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; //时间回调函数指针 wcex.cbClsExtra = 0; // wcex.cbWndExtra = 0; // wcex.hInstance = hInstance; //实例 wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = "BaseClass"; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } //创建(全屏或者非全屏)窗口 BOOL CreateWin(HINSTANCE hInstance, int nCmdShow) { //设置全屏,创建窗口都要用到 DWORD dwExStyle; //扩展窗口风格 DWORD dwStyle; //窗口风格 RECT windowRect; //取得矩形的左上角和右下角的坐标值 windowRect.left=(long)0; windowRect.right=(long)windowWidth; windowRect.top=(long)0; windowRect.bottom=(long)windowHeight; hInst = hInstance; //使用全局变量存储应用实例(win32工程默认在这个位置赋值) //设置全屏状态开始------------------------------------------------------------- if (fullscreen) { DEVMODE dmScreenSettings; //设备模式 memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); //情况内存 dmScreenSettings.dmSize = sizeof(dmScreenSettings); //DEVMODE结构size dmScreenSettings.dmPelsWidth = windowWidth; //屏幕宽 dmScreenSettings.dmPelsHeight = windowHeight; //屏幕高 dmScreenSettings.dmBitsPerPel = windowBits; //每像素所选的色彩深度 dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; //尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态条。 if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { MessageBox(NULL, "Display mode failed", NULL, MB_OK); fullscreen = FALSE; } } //由于全屏模式可能失败,用户可能决定在窗口下运行,我们需要在设置屏幕/窗口之前,再次检查fullscreen的值是TRUE或FALSE。 //如果我们仍处于全屏模式,设置扩展窗体风格为WS_EX_APPWINDOW,这将强制我们的窗体可见时处于最前面。再将窗体的风格设为WS_POPUP。这个类型的窗体没有边框,使我们的全屏模式得以完美显示。 //最后我们禁用鼠标指针。当您的程序不是交互式的时候,在全屏模式下禁用鼠标指针通常是个好主意。 //如果我们使用窗口而不是全屏模式,我们在扩展窗体风格中增加了 WS_EX_WINDOWEDGE,增强窗体的3D感观。 //窗体风格改用 WS_OVERLAPPEDWINDOW,创建一个带标题栏、可变大小的边框、菜单和最大化/最小化按钮的窗体。 if (fullscreen) { dwExStyle=WS_EX_APPWINDOW; dwStyle=WS_POPUP; ShowCursor(FALSE); } else { dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style } AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);//调整窗口达到真正要求的大小 //设置全屏状态结束------------------------------------------------------------- //创建窗口开始--------------------------------------------------------------------- hWnd = CreateWindowEx( NULL, // 扩展窗体风格 "BaseClass", // 类名字 "Title", // 窗口标题 dwStyle | // 选择的窗体属性 WS_CLIPCHILDREN | // 必须的窗体风格属性 WS_CLIPSIBLINGS, // 必须的窗体风格属性 0, 0, // 窗口位置 windowRect.right - windowRect.left, // 计算调整好的窗口宽度 windowRect.bottom - windowRect.top, // 计算调整好的窗口高度 NULL, // 无父窗口 NULL, // 无菜单 hInstance, // 实例 NULL); // 不向WM_CREATE传递任何参数 if (!hWnd) { MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; } //创建窗口结束--------------------------------------------------------------------- ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); //绘制代码 EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }