VS2010 C++ MFC框架学习笔记5 - C++面向对象编程基础1

VS2010 C++ MFC框架学习笔记5 - C++面向对象编程基础1

时隔一周多,再继续C++之路。

1. MSG结构体

   Windows应用程序响应操作系统的消息,通过MSG结构体传达消息信息:

2. 消息队列

Windows消息队列,被应用程序逐条响应

注意2点:

            1. 消息——用户操作、程序状态

            2. 消息响应

3. WinMain函数——VC++的入口函数

 

int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,//实例的句柄,标识这个当前运行的实例
  _In_ HINSTANCE hPrevInstance,  //实例的句柄,标识previous运行的实例
  _In_ LPSTR     lpCmdLine,  //LongPointer_String 长指针,指向一个String , 运行程序时,传入的命令行参数。ARGC ARGV
  _In_ int       nCmdShow  //指定窗口显示时的状态(最大化、适中、隐藏。。。)
);

4. 窗口应用程序的创建步骤

  • 设计一个窗口类
  • 注册窗口
  • 创建窗口
  • 显示及更新窗口
typedef struct tagWNDCLASS {
  UINT      style;           //Style这里是窗口类型,见上面的解释
  WNDPROC   lpfnWndProc;     //窗口过程函数的指针,用这个函数来处理相应的消息
  int       cbClsExtra;     //分配的额外的内存空间,通常称为类的附加内存
  int       cbWndExtra;     //窗口的附加内存
  HINSTANCE hInstance;     // = hInstance
  HICON     hIcon;     //图标句柄wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
  HCURSOR   hCursor;     //光标句柄wndclass.hCursor=LoadCursor(NULL,IDC_CROSS);
  HBRUSH    hbrBackground;     //窗口背景被这个参数控制
            //画刷的句柄wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
  LPCTSTR   lpszMenuName;     //长指针常量String,用来设定菜单的名字,NULL
  LPCTSTR   lpszClassName;     //常量字符串,设定类的名字。"weixin",创建窗口时,名字要与其一致,否则创建不出窗口
} WNDCLASS, *PWNDCLASS;

怎么使用:

   

      以上的WNDCLASS中UINT      style参数解释:

  1. UINT      style;           //Style这里是窗口类型,用16进制的某一位为1来表示不同的类型设置,如果要同时具备俩属性,就用  |  (或运算符)来分隔,如:wndclass.style=CS_HREDRAW | CS_VREDRAW; 其中,CS_HREDRAW是宏定义的,其本质是0x0001

5. 窗口的定义和创建

    窗口类定义好了,就应该用这个Class来创建一个窗口了。

   

  

    CreateWindow函数的说明:

      hwnd=CreateWindow(“WeiXin”, “欢迎使用我”,“WS_OVERLAPPEDWINDOW”,"…
  1.ClassName
  2.WindowName, Title
  3.WindowStyle
  4. 窗口水平坐标
  5. 窗口垂直坐标
  6. 窗口宽度
  7. 窗口高度
  8. HWND窗口句柄,指示一个父窗口的句柄,NULL
  9. HMENU子菜单句柄
  10. 实例号,传入hInstance即可
  11. lpRaram, 创建时间,NULL

6. 窗口的显示和更新

    ShowWindow(HWIND, 显示状态);  //最大化,最小化,normal

    UpdateWindow(hwnd);   

7.消息循环

   MSG msg;  //定义消息
   //进入消息循环

   

    关于GetMessage函数:程序通过GetMessage从消息队列中获得消息。

      1. LPMSG  lpMsg,取到消息后,指向应该放入的目标消息结构体的地址,比如此处是msg的地址,拿到它以后就将取到的消息可以存入msg了。
      2. 从哪个窗口中调用消息
      3. 最小消息值,Filter
      4. 消息最大值,Filter

    TranslateMessage(&msg); //将按键的wmkeydown & wmkeyup消息转换成wmchar消息,放到消息队列中
    DispatchMessage(&msg); //将受到的消息,路由给OS,再调用 *窗口过程函数* 进行处理。

8. 窗口过程函数

    MSDN中搜索“WindowProc”,得到它的说明:
   

     窗口过程函数的形式必须这样,函数名可以改,参数名可变。消息结构体的前四个参数直接传给她的四个参数。

    

     在学习过程中,对于函数,要多用MSDN查,对于大写字母的宏定义等搞不清的,用右键Go to definition查。

     中间我们对消息进行了分类,有:
         WM_PAINT – 窗口粉刷消息
         WM_CHAR – 按键消息
         WM_LBUTTONDOWN – 鼠标左键按下消息
         WM_CLOSE – 窗口关闭被按下消息,此时我们调用了DestroyWindow(); 函数,调用时,它会销毁窗口,返回WM_DESTROY消息
         WM_DESTROY – 焚毁完成消息,此时我们调用了PostQuitMessage(); 函数,退出程序。它会投递一个WM_QUIT消息到队列中,这个WM_QUIT被GetMessage函数取到时,GetMessage会返回一个0,此时在WinMain函数的 取消息 循环中会退出while循环,导致整个程序退出。

    至此,我们就分析完了消息处理函数里的内容,最后,消息处理函数里有个default: 语句,内含的指令是当消息没有落在上述case里时,能有个默认的消息处理机制。

 

9. 关于窗口过程函数声明时的CALLBACK

    LRESULT CALLBACK WinSunProc(  //LRESULT - Long Int Result Code
      HWND  hwnd,
      UINT  uMsg,
      WPARAM wParam,
      LPARAM lParam
    );

    右键 go to definition看, #define CALLBACK __stdcall, 其中,stdcall是和cdecl一样的“调用约定”,一种是标准调用约定(PASCAL),主要定义了参数传递顺序、堆栈清除机制。msdn查stdcall,即可。因为VC++中默认使用 cdecl 调用约定,要用 stdcall 的调用习惯,就要标注 CALLBACK 一下。

    在 菜单-工程-设置-C/C++ 中 代码生成选项下,可以修改这个约定。

   

10. WinMain窗口程序的创建过程及源代码

新建一个工程,选择win32 应用程序,命名为WinMain
再新建一个WinMain.cpp源文件,编写这个源文件:

1. /*  File: WinMain.cpp
2. *  Date: 2015-6-26 14:11:15
3. *  Author: Sonictl
4. */
5. 
6. //Includes
7. #include <Windows.h>
8. #include <stdio.h>
9. 
10. //Declare the WindowProc function
11. LRESULT CALLBACK WindowProc(
12. _In_ HWND   hwnd,
13. _In_ UINT   uMsg,
14. _In_ WPARAM wParam,
15. _In_ LPARAM lParam
16. );
17. 
18. //Declare and define WinMain function
19. int CALLBACK WinMain(
20. _In_ HINSTANCE hInstance,
21. _In_ HINSTANCE hPrevInstance,
22. _In_ LPSTR     lpCmdLine,
23. _In_ int       nCmdShow
24. ){
25. //Declare a WndClass Obj: wndcls
26. WNDCLASS wndcls;
27. //Initial WndObj
28. wndcls.cbClsExtra=0;
29. wndcls.cbWndExtra=0;
30. wndcls.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
31. wndcls.hCursor=LoadCursor(NULL, IDC_CROSS);
32. wndcls.hIcon=LoadIcon(NULL,IDI_WINLOGO);
33. wndcls.hInstance=hInstance;
34. wndcls.lpfnWndProc=WindowProc;
35. wndcls.lpszClassName="MyWndCls2016"; //class name
36. wndcls.lpszMenuName=NULL; //NULL menu
37. wndcls.style=CS_HREDRAW | CS_VREDRAW; //window style
38. 
39. //Register Wnd
40. RegisterClass(&wndcls);
41. HWND hwnd; //declare handle to this window
42. hwnd=CreateWindow("MyWndCls2016", "China Intelligent Robotic Center", \
43. WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL,\
44. hInstance, NULL);
45. 
46. //Show Wnd
47. ShowWindow(hwnd, SW_SHOWNORMAL); //show window
48. //Update Wnd
49. UpdateWindow(hwnd);	//update window
50. //MsgLoop
51. MSG msg;
52. while(GetMessage(&msg, NULL, 0, 0)){
53. TranslateMessage(&msg);
54. DispatchMessage(&msg);
55. }
56. return 0;
57. }
58. //Define Window Proc Function
59. LRESULT CALLBACK WindowProc(
60. _In_ HWND   hwnd,
61. _In_ UINT   uMsg,
62. _In_ WPARAM wParam,
63. _In_ LPARAM lParam
64. ){
65. //hadle messages:
66. switch(uMsg){
67. case WM_CHAR:
68. char szChar[20];
69. sprintf(szChar, "Your char is %d", wParam);
70. //LPCTSTR lpctstr = (LPCTSTR)szChar;    //type transfer
71. //MessageBox(hwnd,"your input is","weixin",0); //lpctstr is LPCTSRT type
72. MessageBox(hwnd,szChar,"Report Message",0); //lpctstr is LPCTSRT type
73. break;
74. case WM_LBUTTONDOWN:
75. MessageBox(hwnd,"mouse clicked", "Report Message", 0);
76. HDC hdc;
77. hdc=GetDC(hwnd);
78. TextOut(hdc,0,50,"智能机器人技术研究中心",strlen("智能机器人技术研究中心"));
79. ReleaseDC(hwnd,hdc);
80. break;
81. case WM_PAINT:
82. HDC hDC;
83. PAINTSTRUCT ps;
84. hDC=BeginPaint(hwnd, &ps);
85. TextOut(hDC,0,0,"机器人改变世界", strlen("机器人改变世界"));
86. EndPaint(hwnd, &ps);
87. break;
88. case WM_CLOSE:
89. if(IDYES==MessageBox(hwnd,"Are u sure to Exit?","Warning",MB_YESNO)){
90. DestroyWindow(hwnd);
91. }
92. break;
93. case WM_DESTROY:
94. PostQuitMessage(0);
95. break;
96. default:
97. return DefWindowProc(hwnd, uMsg, wParam, lParam);
98. }
99. return 0;
100. }

可能会遇到“a value of type “const char *” cannot be assigned to an entity of type “LPCWSTR””错误, writingL"MyString" in place of"MyString"即可。原因是Your code is written to compile as ANSI but your solution settings include _UNICODE/ UNICODEhttp://stackoverflow.com/questions/18470791/c-build-errors-on-win32-school-application

所以在VS2011中,我们的程序作了一点点修改,把编译环境设置成“多字符集”(Multi-Byte Character Set),就可以避免这样转换来转换去。就是在“Project->Configuration Properties->General->Character Set,选择”Use Unicode Character Set“就是使用Uncode字符集,选择” Use Multi-Byte Character Set“就是多字节字符集。
http://jingyan.baidu.com/article/6525d4b1090139ac7d2e9413.html

运行成功.

Published At
comments powered by Disqus