本片博文属于Window编程的相关知识,对Windows开发很熟悉的读者可直接无视。
一、创建空项目
1、打开Visual Studio开发工具,版本可以随便选择,我个人使用的版本是Microsoft Visual studio 2010。
2、从菜单栏中依次选择【文件】—【新建】—【项目】菜单项,打开新建项目对话框;在项目类型列表中选择Win32,模板类型选择Win32控制台应用程序,然后输入项目名称。如下图所示:
3、点击确定后,会弹出一个向导,继续单击【下一步】,弹出应用程序设置向导,应用程序类型选择Windows应用程序,附加选项选择空项目,如下图所示。
4、单击完成,这样一个空项目便创建成功了。
二、添加入口函数
上面我们创建好了空项目,接下来就需要我们自己添加代码了。按照以下几步就可轻松完成:
1、打开【解决方案资源管理器】,在“源文件”文件夹上右击,从菜单中找到【添加】—【新建项】,打开添加新项对话框,类别选择visual c++,模板选择c++文件,然后输入文件名称,如下图所示:
2、添加完成后,在解决方案的源文件目录下面会出现一个空的TestMain.cpp文件,首先在源文件中包含Windows.h头文件,这个是最基本的。
//包含Windows.h头文件. #include <windows.h>
接下来在原文件中增加应用程序的入口函数WinMain,学过标准C++的朋友,应该都知道每个应用程序运行时都会先进入入口点函数main,而当从main函数跳出时,程序就结束了。在Windows编程里面,也是一样的,只是入口点函数不是main,而是WinMain,它的声明形式是固定死的,不能随便改的。如果忘记了,可以在MSDN中查找一下即可。
//入口函数 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return 0; }
3、编写完成后,我们编译一下工程,如果能编译通过,则说明项目的创建以及代码编写都没有问题。
三、创建窗口
用Windows API创建应用程序窗口,主要包括下面五个步骤:
-
(1) 注册窗口
-
(2) 创建窗口
-
(3) 处理消息
-
(4) 显示窗口
-
(5) 启动消息循环
既然步骤是固定的,那么就可以按照步骤,一步步来创建窗口,首先在源文件中增加下面两个全局变量和两个空函数:
//应用程序实例句柄 HINSTANCE g_windows_instance= 0; //windows窗口句柄 HWND g_windows_hwnd = 0; LRESULT CALLBACK window_proc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { LRESULT ret=0; return ret; } bool init(unsigned width, unsigned height) { return true; }
首先在init函数中实现注册窗口和创建窗口,这个函数代码有点多,不过很简单,大家可以慢慢看,代码里增加了比较详细的注释。完整的函数如下:
// 初始化函数 bool init(unsigned width, unsigned height) { WNDCLASS wc; // 设计窗口 wc.lpszClassName = TEXT("AGGAppClass"); //注册窗口类名 wc.lpfnWndProc = window_proc; //窗口过程 wc.style = CS_VREDRAW |CS_HREDRAW; //窗口风格 wc.hInstance = g_windows_instance; //应用程序实例 wc.hIcon = LoadIcon(0,IDI_APPLICATION); //应用程序图标 wc.hCursor = LoadCursor(0,IDC_ARROW); //应用程序光标 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); //窗口背景 wc.lpszMenuName = NULL; //窗口菜单名 wc.cbClsExtra = 0; //默认 wc.cbWndExtra = 0; //默认 //1. 注册窗口 if(!RegisterClass(&wc)) { return 0; } //2. 创建窗口 HWND hwnd = CreateWindow( TEXT("AGGAppClass"), //类名,要和刚才注册的一致 L"我的应用程序", //窗口标题文字 WS_OVERLAPPEDWINDOW, //窗口外观样式 38, //窗口相对于父级的X坐标 20, //窗口相对于父级的Y坐标 width, //窗口的宽度 height, //窗口的高度 NULL, //没有父窗口,为NULL NULL, //没有菜单,为NULL g_windows_instance, //当前应用程序的实例句柄 NULL); //没有附加数据,为NULL // 检查窗口是否创建成功 if(!hwnd) { return 0; } return true; }
接下来继续实现窗口消息处理的函数,由于目前的窗口什么事情也不需要干,所以暂时只处理窗口退出的消息,其他消息先不管,最终完成的函数代码如下:
// 3. 消息处理 LRESULT CALLBACK window_proc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { LRESULT ret=0; switch(msg) { case WM_CREATE: { g_windows_hwnd=hWnd; // 保存窗口句柄 } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd,&ps);//取得设备内容句柄 //添加Window绘图代码…… EndPaint(hWnd,&ps);//释放句柄 } break; case WM_DESTROY: { ::PostQuitMessage(0); // 窗口退出消息 } break; default: ret = ::DefWindowProc(hWnd,msg,wParam,lParam); } return ret; }
【注意】:在window_pro中处理WM_PAINT时,必须调用BeginPaint和EndPaint函数处理绘图消息,否则系统会不断的投放WM_PAINT绘图消息,造成CPU占用率过高。
创建窗口的五个步骤,我们已经实现了三步,下来我们再增加一个run函数,完成最后两步。run函数的实现如下:
//运行函数 int run() { MSG msg; //4. 显示窗口 ShowWindow(g_windows_hwnd,SW_SHOW|SW_NORMAL); //5. 消息循环 while(GetMessage(&msg,NULL, 0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
最后修改一下WinMain函数,去调用我们封装的init和run两个函数,实现最终的窗口创建,修改之后的WinMain函数如下:
//入口函数 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { g_windows_instance =hInstance; init(400, 400); run(); return 0; }
四、运行结果
最后编译运行下,期待已久的窗口就出来,运行截图如下。
源码下载: CreateWindow