VC++孙鑫-第一章-Windows程序的运行机制

来源:互联网 发布:网络歌曲么么哒 编辑:程序博客网 时间:2024/06/10 11:48
2014年3月30日更新--2014年11月26日-更新---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; 
也就是说当我们得到一个消息的时候,我们知道消息对应的窗口是什么,消息是什么,消息的附加参数是什么,消息的投递时间是什么,消息投递的时候鼠标的位置是什么。
相关知识点:
(1)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  //程序的窗口如何显示,是最大化显示还是隐藏显示。
);

2012年12月26日--窗口的创建包括设计窗口类(光标的形状,图标是什么,背景是什么),注册窗口类(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   消息框的标题
 U INT
 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