声明:
本人最近也在看孙老师的视频,为了加强理解,所以想一些读书笔记。但是在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中使用