1、windows程序框架,建立一个窗口。纯手打程序,自己加了一些注释,关于对这段程序的理解,欢迎和大家一起探讨
2、#include<windows.h>LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow){ WNDCLASS wndclass; //注册窗口类 wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //黑色背景 wndclass.hInstance=hInstance; wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); //鼠标指针 wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); //小图标 wndclass.lpfnWndProc=WndProc; //回调函数 wndclass.lpszClassName="HelloWin"; //类名 wndclass.lpszMenuName=NULL; // wndclass.style=CS_HREDRAW|CS_VREDRAW; //垂直重绘和水平重绘 if(!RegisterClass(&wndclass)) //注册窗口 { MessageBox(NULL,"注册窗口失败!","error",MB_OK); return 0; } HWND hwnd=CreateWindow("HelloWin","HelloWin",WS_OVERLAPPEDWINDOW, //创建窗口 CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,hInstance,NULL); ShowWindow(hwnd,iCmdShow); //显示窗口 UpdateWindow(hwnd); //更新 MSG msg; while(GetMessage(&msg,NULL,0,0)) //消息循环 { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) //回调函数,各种消息{ PAINTSTRUCT ps; switch(msg) { case WM_CREATE: return 0; case WM_PAINT: { HDC hdc=BeginPaint(hWnd,&ps); EndPaint(hWnd,&ps); return 0; } case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd,msg,wParam,lParam); //预处理消息}
3、上面的程序,运行之后显示的是一个背景色为黑色的窗口
4、接下来我们实现下全屏显示。分为两步,一、修改显示设备的属性,二、对窗口样式做一些处理。首先我们修改显示设备的属性,要用到的是LONG ChangeDisplaySettings( LPDEVMODE lpDevMode, DWORD dwflags );第一个参数,指向一个DEVMODE结构,MSDN上的说明是”describes the graphics mode to switch to“DEVMODE包含很多字段,我们在这里用到的有dmSize(结构大小),dmBitsPerPel(每个像素的字节位)dmPelsWidth(屏幕宽),dmPelsHeight(屏幕高度),dmFields(位标记,说明哪些字段有效,在这里将它设置为”DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT“表示前面设置的,屏幕高、宽和像素字节有效)在这里需要注意的是dmPelsWidth和dmPelsHeight的值,需要设置成和CreateWindow里面的宽,高一样,比如我们这里都设置成为800,600。第二个参数,我们用CDS_FULLSCREEN,在新的显示模式下,将任务栏从屏幕移除,并强制windows留下其它的屏幕部分该函数的如果成功返回DISP_CHANGE_SUCCESSFUL,还有返回DISP_CHANGE_RESTART,表示计算机需重启来让设置的显示模式工作,等等(详情看msdn吧~)所以,修改显示设备属性的代码段如下:
5、 DEVMODE dmScreenSettings; memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); dmScreenSettings.dmSize=sizeof(dmScreenSettings); //结构大小 dmScreenSettings.dmPelsHeight=600; //屏幕的高 dmScreenSettings.dmPelsWidth=800; //屏幕的宽 dmScreenSettings.dmBitsPerPel=16; //像素字节位数 dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; //位标记,标明哪些字节是有效的,对应前面设置的三个参数 if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { if (MessageBox(NULL,"修改显示设备属性失败!是否继续用一般模式显示","提示",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) { fullscreen=FALSE; } else { MessageBox(NULL,"点击关闭窗口","ERROR",MB_OK|MB_ICONSTOP); return FALSE; } }
6、修改了显示设备的属性后,我们要对窗口样式做一些处理,如,去掉窗口的顶层/边框,还要把鼠标指针给隐藏起来(因为全屏的窗口这些东西都没有)代码段如下:
7、 dwExStyle=WS_EX_APPWINDOW; //隐藏顶层的窗口 dwStyle=WS_POPUP; //没有边框的窗口 ShowCursor(FALSE); //不显示鼠标指针
8、这样全屏就实现了,下面来说下设置ESC退出程序,只要在回到函数的消息处理中添加按键处理消息WM_KEYDOWN就可以了==1、当ESC被按下,我们发送WM_CLOSE应用消息2、在消息循环中判断msg.message是否为WM_CLOSE。关于这个,为了理解清楚,查了下文档,GetMessage里面的msg是用来接受来自线程消息队列里的消息信息的(英文不好,所以还是:Pointer to an MSG structure that receives message information from the thread's message queue. )而,msg.message指定消息成员(Specifies the message number.)如果接受到了WM_CLOSE消息,就用break,结束消息循环程序段如下
9、回调函数里添加(按照此方式写,方面添加其他的按键处理) case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: PostMessage(hWnd,WM_CLOSE,0,0); break; } return 0;2、消息处理函数改为: MSG msg; while(GetMessage(&msg,NULL,0,0)) { if(msg.message==WM_CLOSE) { break; } TranslateMessage(&msg); DispatchMessage(&msg); }
10、好了这样就大功告成了,程序运行时没错的
11、尝试了下用截图软件,显示分辨率是800*600,800*600之外的不能截,话说我是不是要研究下截图软件了==最后贴出完整的程序吧,里面添加了一些其他的样式(去掉那些样式也能正常运行显示,所以自己理解就好啦,不理解的尽量去理解,还没理解到自己想要的程序,就不用,哼!),加了注释了,应该比较好懂
12、#include<windows.h>LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow){ DWORD dwExStyle; DWORD dwStyle; WNDCLASS wndclass; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); wndclass.hInstance=hInstance; wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); wndclass.lpfnWndProc=WndProc; wndclass.lpszClassName="HelloWin"; wndclass.lpszMenuName=NULL; wndclass.style=CS_HREDRAW|CS_VREDRAW; if(!RegisterClass(&wndclass)) { MessageBox(NULL,"注册失败!","error",MB_OK); return 0; } BOOL fullscreen=true; if(MessageBox(NULL,"是否全屏显示?","提示",MB_YESNO|MB_ICONQUESTION)==IDNO) { fullscreen=false; } if(fullscreen) { DEVMODE dmScreenSettings; memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); dmScreenSettings.dmSize=sizeof(dmScreenSettings); //结构大小 dmScreenSettings.dmPelsHeight=600; //屏幕的高 dmScreenSettings.dmPelsWidth=800; //屏幕的宽 dmScreenSettings.dmBitsPerPel=16; //像素字节位数 dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; //位标记,标明哪些字节是有效的,对应前面设置的三个参数 if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { if (MessageBox(NULL,"修改显示设备属性失败!是否继续用一般模式显示","提示",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) { fullscreen=FALSE; } else { MessageBox(NULL,"点击关闭窗口","ERROR",MB_OK|MB_ICONSTOP); return FALSE; } } if(fullscreen) { dwExStyle=WS_EX_APPWINDOW; //隐藏顶层的窗口 dwStyle=WS_POPUP; //没有边框的窗口 ShowCursor(FALSE); //不显示鼠标指针 } else { dwExStyle=WS_EX_APPWINDOW|WS_EX_WINDOWEDGE; dwStyle=WS_OVERLAPPEDWINDOW; } RECT winRect; winRect.left=0; winRect.right=800; winRect.top=0; winRect.bottom=600; AdjustWindowRectEx(&winRect, dwStyle,FALSE,dwExStyle);//依据所需客户矩形大小,计算需要的窗口矩形的大小。 // 计算出的窗口矩形随后可以传送给CreateWindowEx函数, //用于创建一个客户区所需大小的窗口。 } HWND hwnd=CreateWindowEx(dwExStyle,"HelloWin","HelloWin", dwStyle|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, //WS_CLIPSIBLINGS|WS_CLIPCHILDREN参考后面的参考资料 0,0,800,600, NULL,NULL,hInstance,NULL); ShowWindow(hwnd,iCmdShow); UpdateWindow(hwnd); MSG msg; while(GetMessage(&msg,NULL,0,0)) { if(msg.message==WM_CLOSE) { break; } TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam){ PAINTSTRUCT ps; switch(msg) { case WM_CREATE: return 0; case WM_PAINT: { HDC hdc=BeginPaint(hWnd,&ps); EndPaint(hWnd,&ps); return 0; } case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: PostMessage(hWnd,WM_CLOSE,0,0); break; } return 0; case WM_CLOSE: DestroyWindow(hWnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd,msg,wParam,lParam);}
13、最后主要的参考资料是《Beginning OpenGL Game Programming》以及Nehe的OpenGL中文教程其他一些解读资料,来源博客,百科(好吧,不能加链接,只能标题,大家感兴趣可以搜一搜,我已深深地沉醉在不快乐痛苦的边缘了~):WM_CLOSE WM_DESTROY WM_QUIT 区别窗体的扩展样式和其值关于DEVMODE的数据结构--显示设备的属性很多框架在消息循环是喜欢用PeekMessage,所以,如何区别WS_CLIPCHILDREN和WS_CLIPSIBLINGS的理解(不知道从哪转载的,图片挂了,但是点击右键-属性,把图片的地址贴到地址栏可以显示)AdjustWindowRectEX函数 百科
14、最后申明下,版权的问题,如果您认为我侵犯了您或者其他人的著作权一定要跟我说呀~