1.Windows机制:操作系统可以控制输出设备(声卡,显卡),也可以感知输入设备的状态变化(键盘,鼠标)。应用程序通过调用API函数来通知操作系统执行相应的功能。另外操作系统也可以将输入设备上的事件包装成一个称为消息的结构体MSG来上传给应用程序,由应用程序来对事件作出反应。
操作系统对每个应用程序建立一个消息队列。操作系统把事件封装成MSG按顺序放进消息队列,应用程序按先进先出取出队列中的消息。
2.Windows API(Application Programming Interface):操作系统提供给应用程序编程的接口。
消息响应:应用程序对操作系统上传的事件作出相应的过程。
3.消息MSG的定义:
typedef struct tagMSG{
HWND hwnd;//句柄
UINT message;//无符号整形
WPARAM wParam;
LPARAM lPARAM;
DWORD time;//double word,32位整数,标识消息被传递出去的时间
POINT pt;//结构体:表示当消息被投递时光标在屏幕的位置
}MSG;
(1)句柄:资源的标识。操作系统要管理和操作资源都是通过句柄来找到的。按资源的类型将句柄分为图标句柄HICON,光标句柄HCURSOR,窗口句柄HWND,应用程序实例句柄HINSTANCE。
(2)message:事件用无符号整型来标识。通常定义为不同的宏。比如按键按下对应WM_KEYDOWN, 鼠标左键按下WM_LBUTTONDOWN.
(3)wParam,lParam:message的附加消息。比如收到WM_CHAR只标识了按下了字母按键,而wParam具体标识哪一个字符。这里的WPARAM其实就是整型,之所以要重新定义变量的类型,是因为可以直接从变量类型知道变量的用途。
4.WinMain:
在VC程序中,程序的入口函数是WinMain函数,它是由操作系统调用的,并不是我们调用,当操作系统启动程序时,它会给我们运行中的程序分配一个实例号,通过这个参数就传递进来了。
int WINAPI WinMain(HINSTANCE bInstance, HINSTANCE bPrevInstance, LPSTR lpCmdLine, int nCmdShow);
(1)应用程序实例句柄HINSTANCE:实例就是指正在运行的程序。bInstance是指当前运行的实例,bPrevInstance是指之前运行的实例。
(2)LPSTR:指向字符串的长指针,用来表示一个命令行。比如运行NotePad study.txt,后缀study.txt就是一个命令行参数。Windows程序也可以输入一个命令行参数,在Project setting-Debug-Program arguments中输入即可。
(3)nCmdShow:指定程序窗口如何显示。比如最大化最小化还是隐藏。
5.设计窗口类
typedef struct _WNDCLASS{
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMcnuName;
LPCTSTR lpszClassName;
}WNDCLASS;
(1)style:表示窗口类的类型。比如CS_HREDRAW|CS_VREDRAW 表示窗口水平尺寸或垂直尺寸发生变化时,窗口要重画。CS_HREDRAW是定义的宏,该宏所对应的数值0x0001中仅有与该特征相对应的一位为1。
(2)WNDPROC:指定了这一类型窗口的过程函数,即回调函数。当操作系统上传一个消息,应用程序需要调用某一函数来处理消息。这一调用过程是由操作系统完成的,但是回调函数本身的代码必须是应用程序自己完成的。而操作系统到底调用哪个回调函数来处理消息,是由接受消息的窗口所属的类型中的lpfnWndProc成员指定的函数。
(3)cbClsExtra, cbWndExtra:附加内存。
(4)hInstance:需要知道该窗口类是属于哪一个应用程序实例的。这里就是用WinMain给他赋值的。
(5)HICON,HCUSOR:
用LoadIcon函数进行赋值。Windows有标准图标,若使用标准图标则用NULL+IDI_...
(6)HBRUSH:调用函数GetStockObject设置画刷字体调色板的样式。
(HBRUSH)GetStockObject(BLACK_BRUSH);强制类型转换。
(7)lpszMcnuName:用来设置菜单名字。
lpszClassName:这种类型的窗口的名字。
6.向操作系统注册窗口:
WNDCLASS wndclass;
RegisterClass(&wndclass);
7.创建窗口:
(1)HWND hwnd;
hwnd = CreatWindow();
解释:HWND CreatWindow{
LPCTSTR lpClassName,//必须是已经注册的设计好的窗口类
LPCTSTR lpWindowName,//在窗口标题栏里显示的名字
DWORD dwStyle,//窗口的样式 WS_OVERLAPPEDWINDOW 包括层叠窗口,有标题栏,有系统menu,有最大化最小化
int x,//窗口位置可以使用缺省项 CW_USEDEFAULT
int y,
int nWidth,
int nHeight,
HWND hWndParent, //副窗口
HMENU hMenu,//菜单句柄
HINSTANCE hInstance,//通过winmain传递进来的实例号
LPVOID lpParam//多文档参数使用
};
8.显示窗口:
BOOL ShowWindow{
HWND hWnd, //把窗口句柄传递过来就好
int nCmdShow//如何显示:SW_SHOWMINIMIZED
}
UpdateWindow(hwnd);//刷新窗口,可有可无
9.消息循环:调用GetMessage时,应用程序会从消息队列中取出消息。
BOOL GetMessage{
LPMSG lpMsg,//指向MSG的指针,该MSG来自消息队列
HWND hWnd,//要获取哪个窗口的消息 NULL表示所有窗口的消息
UINT wMsgFilterMin,//可以用WM_KEYFIRST表示最小的键盘消息
UINT wMsgFilterMax
};
MSG msg;
while(GetMessage(&msg, NULL,0,0))
{
TranslateMssage(&msg);//把具体的WM_KEYDOWN 和WM_KEYUP合成一个WM_CHAR消息 放入消息队列中
DispatchMessage(&msg);//把消息传给操作系统,由操作系统到窗口类指定的回调函数lpfnWndProc中去处理消息
}
10.回调函数
LRESULT CALLBACK WinSunProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch(uMsg)
{
case WN_PAINT://重绘
hdc=BeginPaint(hwnd,&ps);
TextOut(hdc,0,0,"Create a window for study",strlen("Create a window for study"));
EndPaint(hwnd,&ps);
break;
case WM_CHAR:
char szChar[20];
sprintf(szChar,"char is %d",wParam);//写入字符数组中
MessageBox(hwnd,szChar,"weixin",MB_OK);//当前窗口弹出一个消息框
break;
case WN_LBUTTONDOWN:
MessageBox(hwnd,"mouse click","weixin",MB_OK);
HDC hDC;//这是跟显示相关的硬件有关的句柄参数,程序员不需要关心底层驱动,可以直接使用HDC
hDC = GetDC(hwnd);//获取DC的句柄,图形画在哪个DC上
TextOut(hDC,0,50,"Hello world",strlen("Hellow world"));//窗口上输出一串文本
ReleaseDC(hwnd,hDC);
break;
case WN_CLOSE:
if(IDYES==MessageBox(hwnd,"Exit to the program","weixin",MB_YESNO))
{
DestroyWindow(hwnd);//销毁一个窗口然后产生一个WM_DESTROY消息
}
break;
case WM_DESTROY:
PostQuitMessage(0);//退出程序.发送一个WM_QUIT消息到线程中,在GetMessage时返回0值,WHILE循环结束,退出WinMain函数。
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lPARAM);//系统定义一些缺省操作的响应
}
return 0;
}
11.CALLBACK _stdcall
WINAPIV _cdecl
函数调用的约定,VS缺省情况下默认为C语言调用约定,所以有的函数需要标准调用约定,需要指定STDCALL.