何苦做程序?!

业精于勤,荒于嬉;行成于思,毁于随! I believe , I can flying! 勿在浮砂筑高台!

C++博客 首页 新随笔 联系 聚合 管理
  4 Posts :: 1 Stories :: 14 Comments :: 0 Trackbacks
 孙鑫VC讲座笔记--WINDOWS程序内部运行原理

声明:

        本人最近也在看孙老师的视频,为了加强理解,所以想一些读书笔记。但是在CSDN上一搜索,发现已经有朋友做了相关笔记。根据面向对象的“继承”观点,为了解决劳动力,所以我打算在他们的基础上添加、修改。应该不涉及著作权什么的东东吧?!

        我在BLOG.CSDN.NET/LEWISLAU上搜索了下 ,有两位朋写了相关笔记(而且都是一样的)。不知道谁才是原作者,所以列出两位BLOG地址:

http://blog.csdn.net/hhitjsj021                                http://blog.csdn.net/d007879

以后我会在前辈的基础上修改、发文!呵呵!继承嘛!

 

 

 

 

windows程序设计是种事件驱动方式的程序设计,主要基于消息的。当用户需要完成某种功能时,需要调用OS某种支持,然后OS将用户的需要包装成消息,并投入到消息队列中,最后应用程序从消息队列中取走消息并进行响应。

 

MSG Structure

--------------------------------------------------------------------------------

The MSG structure contains message information from a thread's message queue.

Syntax

typedef struct {
    HWND hwnd;   //指示一个窗口的句柄,改消息和那个窗口相关联。
    UINT message;  //具体的消息,用无符号整形表示
    WPARAM wParam; //关于消息的附加参数
    LPARAM lParam; //同上
    DWORD time; //32位整数,表示消息被投递出去的时间
    POINT pt; //表示光标位置
} MSG, *PMSG;

 句柄,资源的标识,操作系统通过句柄指到资源。常见的句柄有图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序句柄(HINSTANCE)
 
例如:当按下按键会发送出WM_CHAR消息   通过消息的附加参数,保存对应的ASCII码,即可知道按下的是那个键。

 

 


消息队列:
每个应用程序OS都为它建立一个消息队列,消息队列是个先进先出的缓冲区,其中每个元素都是一个消息,OS将生成的每个消息按先后顺序放进消息队列中,应用程序总是取走当前消息队列中的第一条消息,应用程序取走消息后便知道用户的操作和程序的状态,然后对其处理即消息响应,消息响应通过编码实现。

使用VC编程除了良好的C基础外还需要掌握两方面:
一,消息本身。不同消息所代表的用户操作和应用程序的状态。
二,对于某个特定的消息来说,要让OS执行某个特定的功能去响应消息。


Window程序入口:
int WINAPI WinMain(
  HINSTANCE hInstance,  // 当前事例句柄。
  HINSTANCE hPrevInstance,  // 先前事例句柄。
  LPSTR lpCmdLine,      // 命令行指针
  int nCmdShow          // (窗口)显示的状态
);
说明:WinMain函数是Windows程序入口点函数,由OS调用,当OS启动应用程序的时候,winmain函数的参数由OS传递的。

 

创建一个完整的窗口需要经过下面四个操作步骤:
一,设计一个窗口类;如:WNDCLASS wndcls;
二,注册窗口类;    如:RegisterClass(&wndcls);
三,创建窗口;      如:CreateWindow(),CreateWindowEX();
四,显示及更新窗口。如:ShowWindow(),UpdateWindow();
说明:创建窗口的时候一定要基于已经注册的窗口类.

 

 

Windows提供的窗口类:
typedef struct  WNDCLASS {
    UINT    style;        //窗口的类型
    WNDPROC lpfnWndProc;  //窗口过程函数指针(回调函数)
    int     cbClsExtra; //窗口类附加字节,为该类窗口所共享。通常0。
    int     cbWndExtra; //窗口附加字节。通常设为0。
    HANDLE  hInstance;  //当前应用程序事例句柄。
    HICON   hIcon;      //图标句柄 LoadIcon();
    HCURSOR hCursor;    //光标句柄 LoadCursor();
    HBRUSH  hbrBackground; //画刷句柄 (HBRUSH)GetStockObject();
    LPCTSTR lpszMenuName;  //菜单名字
    LPCTSTR lpszClassName; //类的名字
} WNDCLASS,*PWNDCLASS;


窗口类型style为一个变量,该变量每一位对应着一种特性。对应为1时,有该种特性;对应为0时,无该种特性。为了方便记忆,用一些宏对应一些特征,通过取反(~)和相与(&)可以取消一些特性。  通常设置为"CS_HREDRAW | CS_VREDRAW"表示垂直重绘和水平重绘。

HICON可以由LoadIcon 赋值(它有两个参数HINSTANCE和LPCTSTR,通常第一个参数为空,只对第二个参数赋值,即图标的ID)
HCURSOR同HICON
HBRUSH 使用GetStockObject函数,它可以用来获取笔、画刷、字符、调试板的画刷。使用时要用HBRUSH做一直强制转化。因为GetStockObject返回值和HBRUSH不同。

窗口类注册:
ATOM RegisterClass(
  CONST WNDCLASS *lpWndClass   // address of structure with class
                              // data
);
//注意,是使用地址符

 


创建窗口:
HWND CreateWindow(
  LPCTSTR lpClassName,  //注册窗口类名,用引号
  LPCTSTR lpWindowName, //窗口标题,用引号
  DWORD dwStyle,        //窗口类型(风格)通常为(WS_OVERLAPPEDWINDOW)
  int x,                // 窗口X坐标
  int y,                // 窗口X坐标
  int nWidth,           // 宽度
  int nHeight,          // 高度
  HWND hWndParent,      // 指向父窗口的句柄
  HMENU hMenu,          // 菜单句柄
  HANDLE hInstance,     // 当前实例的句柄,由WINMAIN传递
  LPVOID lpParam        // WM_CREATE附加参数传入指针
);
创建窗口的时候会发送WM_CREATE消息


显示和更新窗口窗口:
BOOL ShowWindow(
  HWND hWnd,     // handle to window
  int nCmdShow   // show state of window
);
BOOL UpdateWindow(
  HWND hWnd   // handle of window  送出WM_PAINT消息
);


消息循环
MSG msg;
while(GetMessage(&msg,...))    //从消息队列中取出一条消息
{
 TranslateMessage(&msg); //进行消息(如键盘消息)转化。转化过程不会影响原消息,只会创建新的消息。
 DispatchMessage(&msg); //分派消息到窗口的回调函数处理,(OS调用窗口回调函数进行处理)。
}

BOOL GetMessage(
  LPMSG lpMsg,         // 消息结构体变量
  HWND hWnd,           // 句柄,那个一个窗口?为NULL则为所有窗口句柄
  UINT wMsgFilterMin,  // 最小消息值,为0时返回所有消息
  UINT wMsgFilterMax   // 最大消息值
);

 

回调原理:当应用程序受到给某个窗口的消息时,就应调用某一函数来处理这条消息。这一消息有操作系统自动完成。

注:函数名可以用以表示函数代码的首地址(函数指针),额外数据通常为0。


窗口过程函数(回调函数)原型:
LRESULT CALLBACK WindowProc(  //这里WindowProc是个代号名字。
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);
说明:两种函数调用约定(__stdcall 和 __cdecl):
#define CALLBACK    __stdcall
//__stdcall 标准调用预定,是PASCAL 调用约定,象DELPHI使用的就是标准调用约定
#define WINAPIV     __cdecl 
// __cdecl 是C 语言形式的调用约定。
主要区别:函数参数传递顺序 和 对堆栈的清除上。
问题:除了那些可变参数的函数调用外,其余的一般都是__stdcall约定。但 C/C++编译默然的是__cdecl约定。所以如果在VC等环境中调用__stdcall约定的函数,必须要在函数声明的时加上 __stdcall 修饰符,以便对这个函数的调用是使用__stdcall约定(如使用DELPHI编写的DLL时候)。
(VC中可通过这途径修改:project|settings..|c/c++|...)
在窗口过程函数中通过一组switch语句来对消息进行处理:
如:
LRESULT CALLBACK WindowProc( 
  HWND hwnd,
  UINT uMsg,
  WPARAM wParam,
  LPARAM lParam  
)
{
    switch(uMsg)
    {
 case WM_PAINT:
  ...
  break;
 case ...
  break;
 case WM_CLOSE:
  //DestroyWindow(hwnd);
   //销毁窗口,并发送WM_DESTROY消息。
  break;
 case WM_DESTROY:
  //PostQuitMessage(0);
  //发送WM_QUIT消息到消息队列中,请求终止。
         //GetMessage()取到WM_QUIT消息后,返回0,退出消息循                //   环,从而终止应用程序。
  break;
 default:
  return DefWindowProc(hwnd,uMsg,wParam,lParam);
 //用缺省的窗口过程处理我们不感兴趣的消息(其它消息)。
 //这是必须的。
    }//switch
 return 0;
}//WindowProc


 响应WM_DESTROY,调用PostQuitMessage(int)结束进程。它会投递一个WM_QUIT消息对消息队列中。当消息循环的GetMessage取到WM_QUIT消息,则返回0,程序结束。
 另外对于不感兴趣的消息要景象缺省的处理,使用DefWindowProc()内为窗口的参数。

 


关于DC句柄获取:
a)使用BeginPaint(),EndPaint()对。注意只能在响应WM_PAINT消息时使用。
b)使用GetDc(),ReleaseDC()对。注意他们不能在响应WM_PAINT中使用

posted on 2006-03-11 11:19 lewislau 阿木 阅读(2650) 评论(1)  编辑 收藏 引用

评论

# re: 孙鑫VC讲座笔记--WINDOWS程序内部运行原理 2006-03-18 18:34 hbyufan
是转我的,笔记我停了,原因是我在研究ACE,精力都花在这上面了,欢迎在我笔记基础上修改


笔记只做到第6讲,技术内幕好象只做到17章吧,后面都没做,希望你或有心人接我后面继续做完,到时候给我留言留下连接,把你的也转过去

http://blog.csdn.net/hbyufan/  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理