一.WINAPI解析
#define WINAPI __stdcall
该语句指定了一个调用约定,包括如何生成机器代码以在堆栈中放置函数调用的参数,许多windows函数调用声明为WINAPI
注意:#define CALLBACK __stdcall
CALLBACK也定义成__stdcall,但CALLBACK常用于回调函数,比如说窗口过程
例如:
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lParam)
{
........................
..........................
}
具体用WINAPI还是CALLBACK更加具体情况,方便记忆原则,比如说callback,看名次就知道是回调函数,使用WINAPI就没那么明显了
二.消息与窗口
1.窗口分类:
桌面上最明显的窗口就是应用程序窗口。这些窗口含有显示程序名称的标题列、菜单甚至可能还有工具列和滚动条。
另一类窗口是对话框,它可以有标题列也可以没有标题列。
装饰对话框表面的还有各式各样的按键、单选按钮、复选框、清单方块、滚动条和文字输入区域。其中每一个小的视觉对象都是一个窗口。更确切地说,这些都称为「子窗口」或「控件窗口」或「子窗口控件」。
2.windows给程序发送消息
当窗口发生改变时,比如调整了窗口的大小,窗口文本改变等,windows感应这一消息,把这个消息发送给到程序的消息队列中(该消息对列用来存放该程序可能创建的各种不同窗口的消息),应用程序从消息队列中取出这条消息,然后经过转换,重新发给windows系统,系统调用相应的一个窗口过程(父窗口调用父窗口窗口过程,子窗口调用子窗口处理过程),对消息进行处理。
窗口通常是在窗口类的基础上建立的。窗口类标识了处理窗口消息的窗口过程。使用窗口类使多个窗口能够属于同一个窗口类,并使用同一个窗口过程。例如,所有Windows程序中的所有按钮均依据同一个窗口类。这个窗口类与一个处理所有按钮消息的窗口过程(位于Windows的动态链接库中)联结。在创建这些按钮的时候,都需要指定他们的父窗口(createwindow函数中有一个父窗口句柄参数,需要设置)
注意:
有些消息是不会进入对列的
例如:
sendmessage()函数直接调用相应的窗口过程(windows不会感应)
updatewindow()函数会产生WM_PAINT消息,windows进行感应这消息后,也不进入队
直接调用相应的窗口过程,对wm_paint消息进行处理,其它产生wm_
paint消息,则需要入队
iddialogmessage()函数仍然会进入队列,但程序取出消息后,进行判断,若是指定的消息,则立即调用窗口过程,对消息进行
处理,不需要经过转换和分发阶段
translateaccelerator()函数仍然会进入队列,但程序取出消息后,进行判断,若是WM_KEYDOWN货WM_SYSDEYDOWN消息,则把这消息转换为WM_COMMAND消息,然后立即调用窗口过程,对消息进行处理,不需要经过转换和分发阶段
3.消息循环
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ; //对消息进行些处理,比如说键盘消息,把按键消息转为字符消息
DispatchMessage (&msg) ; //交个操作系统,由操作系统调用窗口过程,处理完后才返回
}
注意: DispatchMessage (&msg)
这条消息将MSG结够回传给windows,然后windows将消息发送给适当的窗口过程,让窗口过程进行处理,处理完后,wndproc返回到windows,此时windows还停留在dispatchmessage调用中,在结束dispatchmessage
调用的处理之后,windows返回到应用程序,并且接着从下一个GetMessage调用开始消息循环
也可以使用下面的消息循环
while(1)
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break ;
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
else
{
..........................
}
}
//PeekMessage有消息时返回true,无消息时返回false,最后一个参数若为PM_REMOVE,表示消息从队列中取出来处理后删除,如果想处理后不删除,则置为 PM_NOREMOVE,不管队列中有没消息,该函数立即返回
三.绘图
1.客户区:
整个应用程序窗口中未被标题列、窗口边框,以及可选的菜单列、工具列、状态列和滚动条占据的部分
2.设备描述表句柄
当您想在一个图形输出设备(诸如屏幕或者打印机)上绘图时,您首先必须获得一个设备内容(或者DC)的句柄。将句柄传回给程序时,Windows就给了您使用设备的权限。然后您在GDI函数中将这个句柄作为一个参数,向Windows标识您想在其上进行绘图的设备
由于设备描述表句柄和特定的设备有关,要想获取该设备的信息,比如说屏幕的大小,像素等等,可以使用以下函数:
This function retrieves information about the capabilities of a specified device.
int GetDeviceCaps( HDC hdc, int nIndex );
设备描述表中默认的属性如下
3.获取设备描述表句柄方法;
3.1 在wm_paint消息中使用beginpaint获取;
当整个窗口或者部分窗口无效时(窗口上的内容没了),产生WM_PAINT消息,该消息使用beginPaint(hwnd,&ps),产生一条插除背景的消息,然后使得整个窗口有效,可以在上面画图或者输出文本了,使得endpaint结束。使用ValdiateRect也使得窗口无效,使窗口无效后(内容没了)是否要插除背景,则由ValdiateRect函数指定,若
该函数最后一个参数为false,则windows将不会插除背景,并且调用完beginpaint后paintstruct结构的ferase将为true;否则,内容相反
注意;在新建窗口,调用showwindow后,只是把窗口显示出来了,但此时窗口仍然无效,因为窗口上没有内容
当窗口过程不出来WM_PAINT消息时,交给defwindowproc去处理,处理过程为
case WM_PAINT:
BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
return 0;
BeginPaint和EndPaint之间没有任何其他语句,仅仅使先前无效区域变为有效
窗口有效无效是对窗口上的内容而言的,若窗口没内容就是无效窗口,有内容就是有效窗口,跟有无背景无关
3.2 在非wm_paint消息中
使用getdc获取设备描述表句柄(客户区),使用releasedc释放句柄
使用GetWindowDC(hwnd)获取整个窗口句柄(包括标题栏,菜单栏等)
使用CreateDC(hdc) 获取整个屏幕的句柄
4.GDI;
要在窗口的显示区域绘图,可以使用Windows的图形设备接口(GDI)函数。要想在客户区上绘图,写文本,必须得获取设备描述表句柄,该设备描述中保存默认的属性值;例如,对于TextOut,设备内容的属性确定了文字的颜色、文字的背景色、x坐标和y坐标映像到窗口的显示区域的方式,以及显示文字时Windows使用的字体。
获取了设备描述表句柄就可以调用相应的GDI函数了,比如TEXTOUT输出文本,画矩形,画椭圆等
4.1 输出文本函数:
drawtext
textout
messagebox
4.2.画线
movetoex;line;
polyline 画连续的线
4.3.矩形,椭圆,圆角矩形等
Rectangle 画矩形
Ellipse 画椭圆
roundRECT 圆角矩形
4.4.白赛尔样条
polybezier;
4.5 填充矩形
fillrect
setrect
注意:
这些GDI函数使用默认的画笔,画刷,要使用自定义画笔,可以使用createpen函数,然后使用selectobject把
这个新建的画笔装到设备描述表中,不需要使用的时候,使用deleteobject删除
同样也可以创建画刷,然后装入设备描述表中
四.滚动条消息
1.WM_VSCROLL和WM_HSCROLL消息
LOWORD(wParam): 消息通知码
HIWORD(wParam); 通知码为SB_THUMBPOSITION或者SB_THUMBTRACK,此值表示滚动条的位置。其它值无效
lParam: 0
2.滚动条使用的函数
1.setscrollrange(); //设置滚动条的范围
2.setcrollpos(); //设置滚动条位置
3.getscrollpos(); //获取滚动条位置
4.setcrollinfo(); //设置滚动条的所有信息
5.getcrollinfo(); //获取滚动条的所有信息
6.scrollwindow(); //使得内容被滚动
五。按键消息
wm_keydown
wm_keyup
wm_char
wparam ; 虚拟键码
//字符按键和数字的虚拟键码为assic(字符大写)
六。鼠标消息
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_RBUTTONDOWN
WM_RBUTTONUP
WM_MOVESECUCE
LOWORD(lParam); 鼠标x坐标
HIWORD(lParam); 鼠标y坐标
wParam; 只是鼠标键和ctrl和shift的状态
MK_LBUTTON 按下左键
MK_MBUTTON 按下中键
MK_RBUTTON 按下右键
MK_SHIFT 按下shift键
MK_CONTROL 按下ctrl键盘
可以使用if(wParam & MK_SHIFT)判断是否shift键盘按下
if(wParam & MK_LBUTTON) 判断左键按下
等
七。子窗口消息
1.按钮,编辑框,列表框给主窗口发送WM_COMMAND消息
LOWORD(lParam); 子窗口ID
HIWORD(lParam);通知吗
lParam 子窗口句柄
2.滚动条给窗口发送WM_VSCROLL或者WM_HSCROLL消息
LOWORD(wParam): 消息通知码
HIWORD(wParam); 通知码为SB_THUMBPOSITION或者SB_THUMBTRACK,此值表示滚动条的位置。其它值无效
lParam: 滚动条句柄
八。菜单消息
当Windows准备显示一个弹出式菜单时,它给窗口消息处理程序发送一个WM_INITMENUPOPUP消息,参数如下:
wParam: 弹出式菜单句柄
LOWORD (lParam):弹出式菜单索引
HIWORD (lParam): 系统菜单为1,其它为0
程序也会接收到WM_MENUSELECT消息。随着使用者在菜单项中移动光标或者鼠标,程序会收到许多WM_MENUSELECT消息。这对实作那些包含对菜单项的文字描述的状态列是很有帮助的。WM_MENUSELECT的参数如下所示:
LOWORD (wParam):被选中项目:菜单ID或者弹出式菜单句柄
HIWORD (wParam):选择旗标
lParam: 包含被选中项目的菜单句柄
最重要的菜单消息是WM_COMMAND,它表示使用者已经从菜单中选中了一个被启用的菜单项。第八章中的WM_COMMAND消息也可以由子窗口控件产生。如果您碰巧为菜单和子窗口控件使用同一ID码,那么您可以通过lParam的值来区别它们,菜单项的lParam其值为0,请参见表10-1。
表10-1 |
菜单 |
控件 |
|
LOWORD (wParam): |
菜单ID |
控件ID |
HIWORD (wParam): |
0 |
通知码 |
lParam: |
0 |
子窗口句柄 |
WM_SYSCOMMAND消息类似于WM_COMMAND消息,只是WM_SYSCOMMAND表示使用者从系统菜单中选择一个启用的菜单项:
wParam: 菜单ID
lParam: 0
九。对话框消息
模态对话框:dialogbox
调用enddialog后,对话框才返回;
非模态对话框: createdialog
立即返回对话框
注意:
不管是模态还是非模态,创建对话框的时候,同时会创建各种子窗口,会产生wm_create,wm_size,wm_paint等消息,交给各个子窗口过程处理,虽然没有写出子窗口过程,但系统会默认处理
wm_command:
LOWORD(lParam); 子窗口ID
HIWORD(lParam);通知吗
lParam 子窗口句柄
十。句柄
获取应用程序实例句柄;
getwindow(HWND hwnd , GWL_HINSTANCE);
也可以使用setwindowlong(HWND hwnd , GWL_HINSTANCE)设置新的实例句柄
该函数还有一种用法;setwindowlong(HWND hwn,GWL_USERDATA) //使得某一个参数和特定的窗口关联
getwindowlong(HWND hwn,GWL_USERDATA) //可以获取这个参数
获取控件句柄;
getdlgitem(HWND hDlg, int ctrlID);
获取控件ID;
GetDlgCtrlID(HWND cTrl) //参数为控件句柄
设置文本:
1、 通过getdlgitem获取子控件的句柄,然后调用
setwindowtext(参数1,参数2); //参数1为控件句柄,参数2为要设置的文本
2. 直接使用setdlgitemtext(对话框句柄,子控件id, 要设置的字符串)
获取文本
1. 通过getdlgitem获取子控件的句柄,然后调用getwindowtext(控件句柄,字符串,字符串大小);
2. getdlgitemtext(对话框句柄,子控件id, 要获得的字符串,字符串大小)