文章转载于:https://blog.csdn.net/u011583927/article/details/54896961
如何创建一个最简单的Windows桌面应用程序 (C++)
最近刚开始学习C/C++开发Windows应用程序,这里将会以零基础的视角把学习过程完全记录下来。如果你也刚刚起步,那本文一定非常适合你。
进入正题,本文讨论如何使用Visual Studio生成一个最简单的C窗体应用程序,并向用户显示Hello~
下面我们一步步来介绍,对于涉及代码的地方,我们只介绍大体的框架,完整的代码会在文章最后给出。
创建基于 Win32 的项目
1.在文件菜单上,单击新建,然后单击项目。
2.在“新建项目”对话框的左窗格中,依次单击“已安装模板”和“Visual C++”,然后选择“Win32”。在中间窗格中,选择“Win32 项目”。在“名称”框中,键入项目名称,例如HelloApp。单击“确定”。
3.在“Win32 应用程序向导”的欢迎页面中,单击“下一步”。在“应用程序设置”页的“应用程序类型”下,选择“Windows 应用程序”。 在“附加选项”下,选择“空项目”。 单击“完成”以创建项目。
4.在“解决方案资源管理器”中,右键单击 HelloApp项目,然后依次单击“添加”和“新建项”。 在“添加新项”对话框中选择“C++ 文件(.cpp)”。 在“名称”框中,键入文件名,例如GT_HelloWorldWin32.cpp。单击“添加”。
添加引用
我们的应用程序需要使用许多现有定义才能完成所需功能,针对我们的需求,添加引用如下(其中前两个是必须的):
- #include
- #include
- #include
- #include
WinMain函数
正如每个 C/C++控制台应用程序在起始点必须具有 main 函数,每个基于 Win32 的应用程序的函数也必须具有 WinMain 函数。WinMain就相当于是入口函数,并且具有固定的语法:
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
实现WinMain函数时内部逻辑大体相同,主要有以下几部分:
1.创建描述窗体信息的窗口类结构WNDCLASSEX
如何创建一个 WNDCLASSEX 类型的窗口类结构?下面的代码演示了一个典型的窗口类结构WNDCLASSEX 的定义:
-
-
- 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(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
- wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
- wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wcex.lpszMenuName = NULL;
- wcex.lpszClassName = szWindowClass;
- wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
对于初学者,我们不用过分纠结代码的细节,暂时从宏观上把控。我们需要知道,此结构包含关于窗口的信息,例如应用程序图标、窗口背景色、标题栏中显示的名称、窗口过程函数的名称等。
2.对窗口类进行注册
现在已创建了窗口类,必须进行注册。
使用 RegisterClassEx 函数,并将窗口类结构作为参数传递。
3.创建并显示窗口
现在需要使用CreateWindow函数创建窗口
使用ShowWindow函数显示窗口
这部分也很好理解,详见文末的代码
4.侦听消息
添加用于侦听操作系统所发送消息的消息循环。
当应用程序收到一条消息时,此循环将该消息调度到 WndProc 函数。WndProc 函数用于对接收的消息进行处理,我们下面会介绍到。
该消息循环类似于以下代码:
-
-
-
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
WndProc 函数
WndProc 函数用以处理应用程序收到的消息。
首先需要判断收到的消息类型进而做出不同的处理,这需要使用 switch 语句。
系统提供了众多的消息命令,例如 WM_PAINT 代表收到了绘图消息,而收到鼠标点击消息的标识是WM_LBUTTONDOWN...
这里以处理 WM_PAINT 消息为例进行说明。
要处理 WM_PAINT 消息,首先应调用 BeginPaint,然后处理所有的绘图逻辑,例如在窗口中布局文本、按钮和其他控件,然后调用 EndPaint。
对于此应用程序,开始调用和结束调用之间的逻辑是在窗口中显示字符串 “Hello,World!”。 在以下代码中,TextOut 函数用于显示字符串。
- LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
- PAINTSTRUCT ps;
- HDC hdc;
- TCHAR greeting[] = _T("Hello, World!");
- switch (message) {
- case WM_PAINT:
-
-
-
- hdc = BeginPaint(hWnd, &ps);
-
-
-
-
- TextOut(hdc, 50, 5, greeting, _tcslen(greeting));
-
-
- EndPaint(hWnd, &ps);
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- default:
-
-
- return DefWindowProc(hWnd, message, wParam, lParam);
- break;
- }
- return 0;
- }
程序运行的结果为:
完整代码
到此我已经理清了写一个Windows应用程序的主要逻辑
我是按照Microsoft官方文档进行的学习,详见创建Windows桌面应用程序
对于更多的细节,代码中给出了详细注释。
-
-
-
-
- #include
- #include
- #include
- #include
-
-
-
- static TCHAR szWindowClass[] = _T("win32app");
-
- static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
-
-
-
-
-
-
- HINSTANCE hInst;
-
-
-
-
-
-
-
-
-
- LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
-
-
-
-
-
-
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
-
-
- 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(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
- wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
- wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wcex.lpszMenuName = NULL;
- wcex.lpszClassName = szWindowClass;
- wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
-
-
- if (!RegisterClassEx(&wcex)) {
- MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL);
- return 1;
- }
-
-
-
- hInst = hInstance;
-
-
-
-
-
-
-
-
-
-
-
-
- HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL );
- if (!hWnd) {
- MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);
- return 1;
- }
-
-
-
-
-
- ShowWindow(hWnd, nCmdShow);
-
-
-
-
- UpdateWindow(hWnd);
-
-
-
-
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return (int) msg.wParam;
- }
-
-
-
-
-
- LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
- PAINTSTRUCT ps;
- HDC hdc;
- TCHAR greeting[] = _T("Hello, World!");
- switch (message) {
- case WM_PAINT:
-
-
-
- hdc = BeginPaint(hWnd, &ps);
-
-
-
-
- TextOut(hdc, 50, 5, greeting, _tcslen(greeting));
-
-
- EndPaint(hWnd, &ps);
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- default:
-
-
- return DefWindowProc(hWnd, message, wParam, lParam);
- break;
- }
- return 0;
- }