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

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

1. MSG结构体

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

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

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;
怎么使用:

    VS2010 C++ MFC框架学习笔记5 - C++面向对象编程基础1_第2张图片

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

  1.          UINT      style;           //Style这里是窗口类型,用16进制的某一位为1来表示不同的类型设置,如果要同时具备俩属性,就用  |  (或运算符)来分隔,如:wndclass.style=CS_HREDRAW | CS_VREDRAW; 其中,CS_HREDRAW是宏定义的,其本质是0x0001
    VS2010 C++ MFC框架学习笔记5 - C++面向对象编程基础1_第3张图片

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;  //定义消息
   //进入消息循环

    VS2010 C++ MFC框架学习笔记5 - C++面向对象编程基础1_第4张图片

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

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

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

8. 窗口过程函数

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

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

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

     在学习过程中,对于函数,要多用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源文件,编写这个源文件:

/*  File: WinMain.cpp
 *  Date: 2015-6-26 14:11:15
 *  Author: Sonictl
 */

//Includes
#include <Windows.h>
#include <stdio.h>

//Declare the WindowProc function
LRESULT CALLBACK WindowProc(
  _In_ HWND   hwnd,
  _In_ UINT   uMsg,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

//Declare and define WinMain function
int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,
  _In_ HINSTANCE hPrevInstance,
  _In_ LPSTR     lpCmdLine,
  _In_ int       nCmdShow
){
  //Declare a WndClass Obj: wndcls
	WNDCLASS wndcls;
  //Initial WndObj
	wndcls.cbClsExtra=0;
	wndcls.cbWndExtra=0;
	wndcls.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	wndcls.hCursor=LoadCursor(NULL, IDC_CROSS);
	wndcls.hIcon=LoadIcon(NULL,IDI_WINLOGO);
	wndcls.hInstance=hInstance;
	wndcls.lpfnWndProc=WindowProc;
	wndcls.lpszClassName="MyWndCls2016"; //class name
	wndcls.lpszMenuName=NULL; //NULL menu
	wndcls.style=CS_HREDRAW | CS_VREDRAW; //window style
	
  //Register Wnd
	RegisterClass(&wndcls);
	HWND hwnd; //declare handle to this window
	hwnd=CreateWindow("MyWndCls2016", "China Intelligent Robotic Center", \
		WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL,\
		hInstance, NULL);

  //Show Wnd
	ShowWindow(hwnd, SW_SHOWNORMAL); //show window
  //Update Wnd
	UpdateWindow(hwnd);	//update window
  //MsgLoop 
	MSG msg;
	while(GetMessage(&msg, NULL, 0, 0)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}
//Define Window Proc Function
LRESULT CALLBACK WindowProc(
  _In_ HWND   hwnd,
  _In_ UINT   uMsg,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
){
  //hadle messages:
	switch(uMsg){
	case WM_CHAR:
		char szChar[20];
			sprintf(szChar, "Your char is %d", wParam);
			//LPCTSTR lpctstr = (LPCTSTR)szChar;    //type transfer
			//MessageBox(hwnd,"your input is","weixin",0); //lpctstr is LPCTSRT type
			MessageBox(hwnd,szChar,"Report Message",0); //lpctstr is LPCTSRT type
			break;
		case WM_LBUTTONDOWN:
			MessageBox(hwnd,"mouse clicked", "Report Message", 0);
			HDC hdc;
			hdc=GetDC(hwnd);
			TextOut(hdc,0,50,"智能机器人技术研究中心",strlen("智能机器人技术研究中心"));
			ReleaseDC(hwnd,hdc);
			break;
		case WM_PAINT:
			HDC hDC;
			PAINTSTRUCT ps;
			hDC=BeginPaint(hwnd, &ps);
			TextOut(hDC,0,0,"机器人改变世界", strlen("机器人改变世界"));
			EndPaint(hwnd, &ps);
			break;
		case WM_CLOSE:
			if(IDYES==MessageBox(hwnd,"Are u sure to Exit?","Warning",MB_YESNO)){
				DestroyWindow(hwnd);
			}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
	return 0;
}

可能会遇到“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/ UNICODE.  http://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


运行成功.







你可能感兴趣的:(VS2010 C++ MFC框架学习笔记5 - C++面向对象编程基础1)