如何创建一个最简单的Windows桌面应用程序 (C++)

文章转载于: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。单击“添加”。

     添加引用

     我们的应用程序需要使用许多现有定义才能完成所需功能,针对我们的需求,添加引用如下(其中前两个是必须的):

[cpp]  view plain  copy
  1. #include    
  2. #include    
  3. #include    
  4. #include    

     WinMain函数     

     正如每个 C/C++控制台应用程序在起始点必须具有 main 函数,每个基于 Win32 的应用程序的函数也必须具有 WinMain 函数。WinMain就相当于是入口函数,并且具有固定的语法:

[cpp]  view plain  copy
  1. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);   

     实现WinMain函数时内部逻辑大体相同,主要有以下几部分:

     1.创建描述窗体信息的窗口类结构WNDCLASSEX 

     如何创建一个 WNDCLASSEX 类型的窗口类结构?下面的代码演示了一个典型的窗口类结构WNDCLASSEX 的定义:

[cpp]  view plain  copy
  1. //创建 WNDCLASSEX 类型的窗口类结构。 此结构包含关于窗口的信息  
  2.     //例如应用程序图标、窗口背景色、标题栏中显示的名称、窗口过程函数的名称等。  
  3.     WNDCLASSEX wcex;   
  4.     wcex.cbSize = sizeof(WNDCLASSEX);   
  5.     wcex.style          = CS_HREDRAW | CS_VREDRAW;   
  6.     wcex.lpfnWndProc    = WndProc;   
  7.     wcex.cbClsExtra     = 0;   
  8.     wcex.cbWndExtra     = 0;   
  9.     wcex.hInstance      = hInstance;   
  10.     wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));   
  11.     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);   
  12.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);   
  13.     wcex.lpszMenuName   = NULL;   
  14.     wcex.lpszClassName  = szWindowClass;   
  15.     wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));   

     对于初学者,我们不用过分纠结代码的细节,暂时从宏观上把控。我们需要知道,此结构包含关于窗口的信息,例如应用程序图标、窗口背景色、标题栏中显示的名称、窗口过程函数的名称等。
     2.对窗口类进行注册

     现在已创建了窗口类,必须进行注册。

     使用 RegisterClassEx 函数,并将窗口类结构作为参数传递。

[cpp]  view plain  copy
  1. RegisterClassEx(&wcex);  

     3.创建并显示窗口

     现在需要使用CreateWindow函数创建窗口

     使用ShowWindow函数显示窗口

     这部分也很好理解,详见文末的代码

     4.侦听消息

     添加用于侦听操作系统所发送消息的消息循环。

     当应用程序收到一条消息时,此循环将该消息调度到 WndProc 函数。WndProc 函数用于对接收的消息进行处理,我们下面会介绍到。 

     该消息循环类似于以下代码:

[cpp]  view plain  copy
  1. // Main message loop:   
  2.     // 添加用于侦听操作系统所发送消息的消息循环。   
  3.     // 当应用程序收到一条消息时,此循环将该消息调度到 WndProc 函数以进行处理。   
  4.     MSG msg;   
  5.     while (GetMessage(&msg, NULL, 0, 0)) {   
  6.         TranslateMessage(&msg); //翻译消息  
  7.         DispatchMessage(&msg);  //派遣消息  
  8.     }   

     WndProc 函数

     WndProc 函数用以处理应用程序收到的消息。

     首先需要判断收到的消息类型进而做出不同的处理,这需要使用 switch 语句。
     系统提供了众多的消息命令,例如 WM_PAINT 代表收到了绘图消息,而收到鼠标点击消息的标识是WM_LBUTTONDOWN...

     这里以处理 WM_PAINT 消息为例进行说明。

     要处理 WM_PAINT 消息,首先应调用 BeginPaint,然后处理所有的绘图逻辑,例如在窗口中布局文本、按钮和其他控件,然后调用 EndPaint。 

     对于此应用程序,开始调用和结束调用之间的逻辑是在窗口中显示字符串 “Hello,World!”。 在以下代码中,TextOut 函数用于显示字符串。

[cpp]  view plain  copy
  1. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {   
  2.     PAINTSTRUCT ps;  
  3.     HDC hdc;   
  4.     TCHAR greeting[] = _T("Hello, World!");   
  5.     switch (message) {   
  6.         case WM_PAINT:   
  7.             //要处理 WM_PAINT 消息,首先应调用 BeginPaint  
  8.             //然后处理所有的逻辑以及在窗口中布局文本、按钮和其他控件等  
  9.             //然后调用 EndPaint。   
  10.             hdc = BeginPaint(hWnd, &ps);   
  11.   
  12.             // -----------------在这段代码对应用程序进行布局------------------------   
  13.             // 对于此应用程序,开始调用和结束调用之间的逻辑是在窗口中显示字符串 “Hello,World!”。  
  14.             // 请注意 TextOut 函数用于显示字符串。  
  15.             TextOut(hdc, 50, 5, greeting, _tcslen(greeting));   
  16.             // -----------------------布局模块结束----------------------------------  
  17.   
  18.             EndPaint(hWnd, &ps);  
  19.             break;   
  20.         case WM_DESTROY:   
  21.             PostQuitMessage(0);   
  22.             break;  
  23.         default:   
  24.             //DefWindowProc缺省窗口处理函数  
  25.             //这个函数是默认的窗口处理函数,我们可以把不关心的消息都丢给它来处理  
  26.             return DefWindowProc(hWnd, message, wParam, lParam);   
  27.             break;   
  28.     }   
  29.     return 0;   
  30. }   

     程序运行的结果为:


     完整代码

     到此我已经理清了写一个Windows应用程序的主要逻辑

     我是按照Microsoft官方文档进行的学习,详见创建Windows桌面应用程序

     对于更多的细节,代码中给出了详细注释。

[cpp]  view plain  copy
  1. // GT_HelloWorldWin32.cpp   
  2. // compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c   
  3. // 这是一个最简单的Win32程序,亦可作为开发桌面应用程序的模板  
  4.   
  5. #include    
  6. #include    
  7. #include    
  8. #include    
  9.   
  10. // ------------------------Global variables---------------------------------  
  11. // 主窗体类名  
  12. static TCHAR szWindowClass[] = _T("win32app");   
  13. // 应用程序标题栏处出现的字符串  
  14. static TCHAR szTitle[] = _T("Win32 Guided Tour Application");   
  15.   
  16. //HINSTANCE 是Windows里的一中数据类型,是用于标示(记录)一个程序的实例。  
  17. //它与HMODULE是一样的(通用的,这两种类型最终就是32位无符号长整形)。  
  18. //HINSTANCE,分开看就是 HANDLE(句柄) + INSTANCE(实例)  
  19. //实例就是一个程序。用qq来举例:你可以开同时开2个qq号,但是你电脑里的qq软件只有一份。  
  20. //这2个qq号就是qq的2个实例  
  21. HINSTANCE hInst;   
  22.   
  23. // -------------------------需要预定义的函数放置在此代码块种:----------------------------   
  24.   
  25.   
  26. //每个 Windows 桌面应用程序必须具有一个窗口过程函数  
  27. //此函数处理应用程序从操作系统中接收的大量消息。   
  28. //例如,如果应用程序的对话框中有“确定”按钮,那么用户单击该按钮时,  
  29. //操作系统会向应用程序发送一条消息,通知按钮已被单击。WndProc 负责对该事件作出响应。  
  30. //在本例中,相应的响应可能是关闭对话框。  
  31. LRESULT CALLBACK WndProc(HWNDUINTWPARAMLPARAM);   
  32.   
  33. //-------------------------------------正式内容-----------------------------------------  
  34.   
  35. //主窗体函数(入口过程)  
  36. //每个基于 Win32 的应用程序的函数必须具有 WinMain 函数  
  37. //正如每个 C 应用程序和 C++ 控制台应用程序在起始点必须具有 main 函数  
  38. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {   
  39.     //创建 WNDCLASSEX 类型的窗口类结构。 此结构包含关于窗口的信息  
  40.     //例如应用程序图标、窗口背景色、标题栏中显示的名称、窗口过程函数的名称等。  
  41.     WNDCLASSEX wcex;   
  42.     wcex.cbSize = sizeof(WNDCLASSEX);   
  43.     wcex.style          = CS_HREDRAW | CS_VREDRAW;   
  44.     wcex.lpfnWndProc    = WndProc;   
  45.     wcex.cbClsExtra     = 0;   
  46.     wcex.cbWndExtra     = 0;   
  47.     wcex.hInstance      = hInstance;   
  48.     wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));   
  49.     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);   
  50.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);   
  51.     wcex.lpszMenuName   = NULL;   
  52.     wcex.lpszClassName  = szWindowClass;   
  53.     wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));   
  54.       
  55.     //对已创建的窗口类进行注册。 使用 RegisterClassEx 函数,并将窗口类结构作为参数传递。  
  56.     if (!RegisterClassEx(&wcex)) {   
  57.         MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL);   
  58.         return 1;   
  59.     }   
  60.   
  61.     // Store instance handle in our global variable   
  62.     // 将句柄实例存储于全局变量中  
  63.     hInst = hInstance;   
  64.       
  65.     // CreateWindow 函数的参数解释:   
  66.     // szWindowClass: the name of the application   
  67.     // szTitle: the text that appears in the title bar   
  68.     // WS_OVERLAPPEDWINDOW: the type of window to create   
  69.     // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)   
  70.     // 500, 100: initial size (width, length)   
  71.     // NULL: the parent of this window   
  72.     // NULL: this application does not have a menu bar   
  73.     // hInstance: the first parameter from WinMain   
  74.     // NULL: not used in this application   
  75.     // 返回的HWND是一个窗口的句柄  
  76.     HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL );   
  77.     if (!hWnd) {   
  78.         MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);   
  79.         return 1;   
  80.     }   
  81.   
  82.   
  83.     // ShowWindow 函数的参数解释:   
  84.     // hWnd: CreateWindow函数返回的窗口句柄   
  85.     // nCmdShow: the fourth parameter from WinMain   
  86.     ShowWindow(hWnd, nCmdShow);  
  87.     // UpdateWindow函数用于更新窗口指定的区域  
  88.     // 如果窗口更新的区域不为空,UpdateWindow函数就发送一个WM_PAINT消息来更新指定窗口的客户区。  
  89.     // 函数绕过应用程序的消息队列,直接发送WM_PAINT消息给指定窗口的窗口过程  
  90.     // 如果更新区域为空,则不发送消息。  
  91.     UpdateWindow(hWnd);   
  92.   
  93.     // Main message loop:   
  94.     // 添加用于侦听操作系统所发送消息的消息循环。   
  95.     // 当应用程序收到一条消息时,此循环将该消息调度到 WndProc 函数以进行处理。   
  96.     MSG msg;   
  97.     while (GetMessage(&msg, NULL, 0, 0)) {   
  98.         TranslateMessage(&msg); //翻译消息  
  99.         DispatchMessage(&msg);  //派遣消息  
  100.     }   
  101.     return (int) msg.wParam;   
  102. }   
  103.   
  104. // //  函数: WndProc(HWND, UINT, WPARAM, LPARAM)   
  105. // //  目标:  处理主窗体产生的信息  
  106. // //  WM_PAINT消息代表绘制主窗体   
  107. // //  WM_DESTROY消息代表投递一个退出消息并返回   
  108. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {   
  109.     PAINTSTRUCT ps;  
  110.     HDC hdc;   
  111.     TCHAR greeting[] = _T("Hello, World!");   
  112.     switch (message) {   
  113.         case WM_PAINT:   
  114.             //要处理 WM_PAINT 消息,首先应调用 BeginPaint  
  115.             //然后处理所有的逻辑以及在窗口中布局文本、按钮和其他控件等  
  116.             //然后调用 EndPaint。   
  117.             hdc = BeginPaint(hWnd, &ps);   
  118.   
  119.             // -----------------在这段代码对应用程序进行布局------------------------   
  120.             // 对于此应用程序,开始调用和结束调用之间的逻辑是在窗口中显示字符串 “Hello,World!”。  
  121.             // 请注意 TextOut 函数用于显示字符串。  
  122.             TextOut(hdc, 50, 5, greeting, _tcslen(greeting));   
  123.             // -----------------------布局模块结束----------------------------------  
  124.   
  125.             EndPaint(hWnd, &ps);  
  126.             break;   
  127.         case WM_DESTROY:   
  128.             PostQuitMessage(0);   
  129.             break;  
  130.         default:   
  131.             //DefWindowProc缺省窗口处理函数  
  132.             //这个函数是默认的窗口处理函数,我们可以把不关心的消息都丢给它来处理  
  133.             return DefWindowProc(hWnd, message, wParam, lParam);   
  134.             break;   
  135.     }   
  136.     return 0;   
  137. }   

你可能感兴趣的:(面试准备)