[学习笔记]VC++孙鑫--第一章-Windows程序的运行机制

孙鑫VC++ 同时被 2 个专栏收录
3 篇文章 0 订阅
2 篇文章 0 订阅

windows程序不同于DOS程序在于windows程序是基于事件驱动的方式,基于消息的。也就是说当我们得到一个消息的时候,我们知道消息对应的窗口是什么,消息是什么,消息的附加参数是什么,消息的投递时间是什么,消息投递的时候鼠标的位置是什么。windows程序不同于DOS程序在于windows程序是基于事件驱动的方式,基于消息的。比如,当用户在窗口中画图或者点击一个按钮的时候,按下鼠标左键,此时操作系统会感知这个事件,于是将这个事件包装成一个消息投放到应用程序的消息队列中,然后应用程序从消息队列中取出这个消息并进行相应,实际上是操作系统调用应用程序中一个专门负责处理消息的函数,这个函数叫做窗口过程。操作系统可以控制声卡发出声音也可以感知鼠标和键盘的按下。windows系统提供了各种各样的函数,以方便我们开发windows应用程序,简称API(Application Programming Interface)行数,比如ShowWindow(显示窗口),LoadIcon(用于加载图标),SendMessage(用于发送消息).API-实现各种功能函数的集合。SDK(Software Development kit)软件开发包。HWND-一个窗口的一个句柄,就是窗口的标示,此外还有图标句柄HICON,光标句柄HCURSOR,画刷句柄HBRUSH,资源的标示,资源要占据内存,句柄也就是门牌号或者地址,我们通过句柄找到相应的资源。

typedef struct tagMSG {     // msg 
    HWND   hwnd;   窗口句柄标示,hwnd标示消息所属的窗口  
    UINT   message; UINT unsigned integer
    WPARAM wParam; unsigned interger
    LPARAM lParam; unsigned interger
    DWORD  time; 消息投递到消息队列的时间
    POINT  pt;消息投递到消息队列时鼠标的位置 
} MSG; 

也就是说当我们得到一个消息的时候,我们知道消息对应的窗口是什么,消息是什么,消息的附加参数是什么,消息的投递时间是什么,消息投递的时候鼠标的位置是什么。 

相关C语言知识点:

(1)typedef的用法

typedef int InTEGER;// 指定标示符INTEGER代表int类型  
int i,j;INTEGER i,j;// 这个两句话意思一样
typedef struct tagMSG; //的意思指定tagMSG为struct类型

(2)struct 结构体名

            {

                成员列表

            }变量名列表;

定义一个tagMSG结构体变量MSG

(3)

typedef struct tagPOINT { 
    LONG x; 
    LONG y; 
} POINT; //POINT是一个结构体

UNIT message 用无符号整形来表示一个消息,整数又不好记忆,就用宏来代替这个整数数字,所以windows用WM_XXX宏(WM是window message的缩写)来代表数字方便记忆,比如keydown消息,LButtondown鼠标左键按下的消息。wParam,mParam 当按下字母A键的实收,系统收到了WM_Char消息,所以并不知道具体按下哪一个字母,所以可以通过wParam和mParam来知道具体按下的是什么字母。Dword消息传递出去的时间,Point pt 当消息被投递的时候,消息在屏幕上的位置。

这里面提到了微软在windows编程的时候为什么添加了那么多新的数据类型(比如WPARAM,LPARAM)一旦我们看到这两个数据类型定义的变量,就知道这个消息的附加参数。

每一个应用程序,windows都会给它一个消息队列,消息队列是一个先进先出的缓冲区,windows按顺序放入消息,应用程序按顺序去走消息。应用程序收到消息后,会针对消息进行相应,就有消息相应的代码。

 

创建一个Win32应用程序的步骤

1.编写WinMain函数

2.设计窗口类

3.注册窗口类

4.创建窗口

5.显示并更新窗口

6.编写消息循环

7.编写窗口过程函数

 

main{}函数是DOS程序下的入口函数,WINMAIN{}函数是windows程序的入口函数,这个函数是由操作系统调用的。HINSTANCE当前运行的实例(窗口).LP-长指针。DOS下main函数中的argc用于存放命令行的个数,argv是一个指针数组,它主要用于存放命令行参数.Go F5调试运行(有断点调试的时候使用,当程序遇到断点的时候就停下来了。),WINMAIN 中int nCmdShow 窗口显示的状态。

int WINAPI WinMain( 
 
HINSTANCE hInstance, // handle to current instance  

HINSTANCE hPrevInstance, // handle to previous instance  

LPSTR lpCmdLine, // pointer to command line   LPSTR 指向字符串的指针

int nCmdShow // show state of window  //程序的窗口如何显示,是最大化显示还是隐藏显示。

);

窗口的创建包括设计窗口类(光标的形状,图标是什么,背景是什么),注册窗口类(RegisterClass(&wndcls)),创建窗口( HWND hwnd;hwnd = CreateWindow("Weixin2003","北京维新科学技术培训中心",WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL))

typedef struct _WNDCLASS { 
    UINT    style; 
    WNDPROC lpfnWndProc; // 这个参数用来接收一个函数指针,指向窗口过程函数, 
    int     cbClsExtra;  //可以增加一些额外的内存空间 
    int     cbWndExtra;  //窗口附加内存 
    HANDLE  hInstance; //代表当前应用程序实例号 
    HICON   hIcon;     //
    HCURSOR hCursor; 
    HBRUSH  hbrBackground; 
    LPCTSTR lpszMenuName; 
    LPCTSTR lpszClassName; 
} WNDCLASS; 

 

窗口类结构体WNDCLASS

例子如下:

 WNDCLASS wndcls; //定义了一个结构体变量
 wndcls.cbClsExtra=0;
 wndcls.cbWndExtra=0;
 wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
 wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);  //图标句柄的赋值
 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
 wndcls.hInstance=hInstance;
 wndcls.lpfnWndProc=WinSunProc; //函数名可以代表函数代码的首地址,也就是说函数名就是函数的指针。
 wndcls.lpszClassName="Weixin2003";
 wndcls.lpszMenuName=NULL;
 wndcls.style=CS_HREDRAW | CS_VREDRAW;

 

从goto defition可以看到 CS_HREDRAW CS_VREDRAW的定义如下:

#define CS_VREDRAW 0x0001 // 把他们转换成二进制数之后,那么发现其中只有一位为1,那么如果需要
#define CS_HREDRAW 0x0002
#define CS_DBLCLKS 0x0008
#define CS_OWNDC 0x0020
#define CS_CLASSDC 0x0040
#define CS_PARENTDC 0x0080
#define CS_NOCLOSE 0x0200
#define CS_SAVEBITS 0x0800
#define CS_BYTEALIGNCLIENT 0x1000
#define CS_BYTEALIGNWINDOW 0x2000
#define CS_GLOBALCLASS 0x4000
ATOM RegisterClass(
  CONST WNDCLASS *lpWndClass // address of structure with class 
                               // data ); 

RegisterClass(&wndcls);

 

关于回调函数的解释,回调函数里面的内容是需要我们自己去写好的,但是回调函数不需要我们自己调用的,回调函数是操作系统来负责调用的,我们只是需要负责把回调函数里面的特定的事件写好。

HWND CreateWindow(
  LPCTSTR lpClassName,  // pointer to registered class name    
  LPCTSTR lpWindowName, // pointer to window name
  DWORD dwStyle,        // window style
  int x,                // horizontal position of window,如果设置成为 CW_USEDEFAULT,那么y就不用设置了。
  int y,                // vertical position of window
  int nWidth,           // window width      窗口的宽度
  int nHeight,          // window height    窗口的高度
  HWND hWndParent,      // handle to parent or owner window 父窗口的句柄,没有父窗口的时候 值为NULL
  HMENU hMenu,          // handle to menu or child-window identifier    窗口的菜单的句柄
  HANDLE hInstance,     // handle to application instance  当前应用程序实例的句柄
  LPVOID lpParam        // pointer to window-creation data                     
);

 

HWND hwnd;
hwnd=CreateWindow("sunxin2006","http://www.sunxin.org",WS_OVERLAPPEDWINDOW,
0,0,600,400,NULL,NULL,hInstance,NULL);

 

 

 

,显示和更新窗口 

BOOL ShowWindow(
  HWND hWnd,     // handle to window         显示的是哪一个窗口
  int nCmdShow   // show state of window    显示的状态 最大化显示,还是最小化显示
);

BOOL UpdateWindow(
  HWND hWnd   // handle of window       更新哪一个窗口
);

ShowWindow(hwnd,SW_SHOWNORMAL);

UpdateWindow(hwnd);

 , WINCLASS 结构体,已经定义好了每个元素(光标,背景等)的值得类型,我们只要填写即可。lpfnWndProc-回调函数,指出比如按下窗口中调节增益时,操作系统会调用调节增益的函数,但是具体的回调函数的代码需要我们自己编写比如调整曝光时间呀,比如软触发还是硬触发呀。函数名可以代表函数代码的首地址,wndcls.lpfnWndProc=WinSunProc 在设计窗口类的时候就将回调函数的首地址赋给窗口类的IpfnWndProc指针。HICON 图标-就是应用程序窗口左上角的那个小图标。HCURSOE 光标。HBRUSH-画刷句柄,应用程序背景(HBRUSH)GetStockObject(BLACK_BRUSH) 强制类型转换。lpszMenuName 窗口菜单,lpszClassName 窗口类的名字。屏幕坐标通常以左上角为原点。

 

 

GetMessage() 应用程序从消息队列中取出消息,返回的BOOL的,如果一直有消息的话,就为真,
 

BOOL GetMessage(
  LPMSG lpMsg,         // address of structure with message  消息结构体指针 [out] ,这里面out的含义是我们只需要传递一个地址指针,操作系统为为我们自动赋值。
  HWND hWnd,           // handle of window
  UINT wMsgFilterMin,  // first message  可以指定消息的范围   消息的最小值  如果两个都为0,则不过滤任何消息
  UINT wMsgFilterMax   // last message           消息的最大值
);
TtanslateMessage 能把WM_KEYDOWN和WM_KEYUP消息转换为WM_CHAR消息 这样我们就能够捕获WM_CHAR消息了
 BOOL TranslateMessage(
  CONST MSG *lpMsg   // address of structure with message
);
DispatchMessage() 把消息传递给窗口的回调函数,也就是窗口过程函数,然后与这个回调函数(窗口过程函数)来处理这个消息
LONG DispatchMessage(
  CONST MSG *lpmsg   // pointer to structure with message
);


  
     Windows程序整个消息循环的机制为:当一个应用程序建立的时候(每个窗口的产生),操作系统都会为这个应用程序(窗口,对话框)分配一个消息队列,凡是和这个窗口相关的消息,操作系统都会把这些消息放到消息队列中,我们应用程序利用GetMessage从消息队列中取出一条消息,用我们的TanslateMessage 能把WM_KEYDOWN和WM_KEYUP消息转换为WM_CHAR消息,放到消息队列中,DispatchMessage() 把消息投递出去,分发给操作系统,操作系统根据我们设计窗口类时候提供的回调函数进行处理,传递给窗口的回调函数,也就是窗口过程函数,然后与这个回调函数(窗口过程函数)来处理这个消息,我们要做的就是根据不同的消息,在函数中做出不同的响应,这样就完成了整个程序的循环。

 


LRESULT CALLBACK WindowProc(  //CALLBACK _stdcall 参数调用的约定,标准的调用约定,_cdecl C语言的调用约定,参数传递的顺序,堆栈的清除
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);
 
switch(uMsg)
 {
  case WM_CHAR:
  char szChar[20];
  sprintf(szChar,"char is %d",wParam);   //格式化一个文本到内存当中,将wParam中存放的WM_CHAR中的ASCII码 按照char is %d的格式放到szChar字符数组当中
  MessageBox(hwnd,szChar,"weixin",0);  //用于弹出一个消息框,hwnd 哪一个框口的消息框,
  break;
 int MessageBox(
  HWND hWnd,          // handle of owner window
  LPCTSTR lpText,     // address of text in message box   消息框的内容
  LPCTSTR lpCaption,  // address of title of message box   消息框的标题
  UINT uType          // style of message box    消息框的内容
);

 case WM_LBUTTONDOWN:
  MessageBox(hwnd,"mouse clicked","weixin",0);
  HDC hdc;  //HDC DC句柄,device context,设备上下文 dc和设备驱动程序打交道, 所以我们只需要下命令就行了。用DC(设备描述表)和不同的显卡和不同的图形设备打交道。程序设计者->DC->显示设备。
  hdc=GetDC(hwnd);//获取dc的句柄,DC都是和窗口有关的,窗口可以类比成画布。 dc和显示设备的驱动程序打交道,
  TextOut(hdc,0,50,"计算机编程语言培训",strlen("计算机编程语言培训")); //文本输出的函数,在我们的窗口上输出一个文本。第四个参数-输出的内容,第五个参数-输出内容的长度
  ReleaseDC(hwnd,hdc);  //dc是占用系统内存的,如果不释放这个资源的话,会出现系统内存泄露。
  break; 

 case WM_PAINT: //窗口从无到有,每次都要给一个WM_PAINT的消息。 当窗口的水平坐标和垂直坐标发生变化时,系统会给出一个WM_PAINT消息。
  HDC hDC;
  PAINTSTRUCT ps;
  hDC=BeginPaint(hwnd,&ps);  beginpaint和endpaint只能在WM_PAINT消息中使用。
  TextOut(hDC,0,0,"维新培训",strlen("维新培训"));
  EndPaint(hwnd,&ps);
  break;
 case WM_CLOSE: 当点击退出按钮的时候触发WM_CLOSE消息
  if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO))  
  {
   DestroyWindow(hwnd);// 销毁一个指定的窗口,并发送一个WM_DESTROY消息 
  }
  break; 
 case WM_DESTROY:
  PostQuitMessage(0);  //通知系统终止一个线程,并发送一个WM_QUIT消息到消息队列中,GetMessage取到WM_QUIT消息,会返回一个0.
  break; 
 while(GetMessage(&msg,NULL,0,0))  //这样while语句就会终止循环,同时winmain函数的 return 0 结束winmain函数,整个程序结束。
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 return 0;
 default:  //对缺省的一些消息,我们做一些相应的处理
  return DefWindowProc(hwnd,uMsg,wParam,lParam);
 } 


关于LRESULT CALLBACK WinSunProc这个函数,先在main函数前面声明了这个函数,然后在main函数后面定义了这个函数,查看关于函数的声明和定义,有下面的解释,声明的目的是告诉编译器即将要定义的函数名字是什么,返回值类型是什么以及参数是什么。而定义是告诉编译器这个函数的功能是什么。


程序的编写过程,首先新建一个win32 application 找路径 取名 新建c++ source file 首先包含windows头文件和c语言头文件,首先写一个winmain{}入口函数,然后设计一个窗口类,然后一一设定窗口类的初值,注册窗口,创建窗口,显示更新窗口,消息循环,这样winmain函数就写完了,然后需要写窗口回调函数, OK,这样就全部搞定了。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值