Windows API
第一章
1.2
在同一时刻能有多个Windows程序显示并运行。
16位Windows是一种非优先权式的多工系统。
Windows执行的应用程序可共享称为“动态链接库”文件中的常项。常项是指实例化的函数或程序,即函数都是参数实例化的函数,程序都是参数及变量都实例化的程序。
1.3
API是应用程序接口(applicaton programming interface)的缩写。Windows操作系统本身是由API定义的。API包含了所有应用程序能够使用,操作系统能够执行的函数调用,同时,API也包含了相关的描述形态和结构的文件。
32位模式下的32位平坦定址存储器模式。
1.7
MessageBox函数相当于C程序中的printf,用于显示短信息,作用是在窗口中央显示信息M essage(NULL, TEXT(“Helli, Windows 98!”), TEXT(“HelloMsg”), 0);
第一个参数:窗口代号,指示在哪个窗口中进行显示。
第二个参数:在窗口显示的字符串。
第三个参数:在窗口标题上显示的字符串。
第四个参数:MessageBox函数生成按钮。
1.8
提出所有字符编码都用16位二进制,这种编码称为Unicode。Unicode是ASCII字符集的扩展。Unicode打算作为ASCII的补充,但可能Unicode最终将代替ASCII码。
Unicode才是真正解决的方案,和含有1字节代码与2字节代码的双字节字符集(DBCS)不同,Unicode是统一的16位系统,这就允许表示65536个字符。
1.9
用多个字节存储一个字符称为宽字符(wchar),C中用wchar_t表示宽字符数据类型,他在WCHAR.H中定义,如下所示:
typedef unsigned short whar_t;
1.10
在Windows中仍然可以使用sprintf及sprintf系列中的其它函数来显示文字。这些函数除了将内容格式化输出到函数第一个参数所提供的字符串缓冲区外,其功能与printf相同。
第二章
2.2
32位保护模式的工作原理类似于16位保护模式,出发点还是一个“段地址,偏移地址”序列。
2.4
线程是程序中能独立执行的最小程序块。
抢占式多任务:具有最高优先级的线程就是当前正在运行的那个线程。驻留在CPU内正在运行的线程会在什么时候中止呢?一种情况是属于它的时间片已到期,另一种情况是加入了另一个优先级更高的线程。通过不断从一个线程到另一个线程的切换,给人的感觉是线程的执行是同步进行的。线层并非随时都需要运行,经常发生的情况是某个线程需要等待用户的输入,另一个线程的信息或者等待I/O请求,否则无法执行下去。有些线程也许本来就处于挂起状态。不管当前情况如何,在多任务多线程环境里,线程的同步是至关重要的。此外,所有线程都必须对某些物理设备进行共享,例如键盘、鼠标、屏幕等。叠置窗口、多个输入请求、特定的I/O、优先级的提高都是Win32系统实现抢占式多任务应该解决的关键。
线程是系统调度用的能够执行的最小执行代码段。
2.5
在32位Windows里,应用程序的每个线程都有输入消息队列。和16位Windows比较起来运作方式也发生了变化。系统中专门设置了一个线程,它称为“原始输入线程”,由它负责把系统队列中的消息传送给线程的输入消息队列,不管系统正在执行什么处理,也不管整体的消息流如何,“原始输入线程”的传送操作与他们无关而始终处于就绪状态,即“原始输入线程”永远不会挂起。
第三章
3.1
资源文件与资源描述文件(.RC):正文资源石油菜单模板、字符串模板、加速键模板、对话框模板产生的资源。二进制资源包括图标、游标、字体等。
由于一个应用程序或一个进程可能用到很多资源,把应用程序或进程用到的资源资源记录在一个文件中,这个文件称为资源描述文件(.RC),简称RC文件。
3.2
为什么要学Windows API:Windows API是当今世界上最著名的API,由于Windows系统本身也是基于API实现的,所以,只有学习好Windows API,才能真正理解Windows系统,才能真正理解Windows应用程序。由此可见,学习与理解API是掌握现有计算机软件的基础中的基础,是掌握Windows编程的基础中的基础,是任何其他Windows编程的“本”。
三个核心API:16位:USER.EXEGDI.EXE KRNL386.EXE
32位:USER32.DLL GDI32.DLL KERNEL32.DLL
3.5
GDI.EXE和32位的GDI32.DLL是图形界面,它用于程序在屏幕和打印机上显示文字和图形。静态链接库和动态链接库:在编写高级语言程序时,势必会调用许多函数,这些函数的机器码在链接过程中会合并到程序本身中,这就称为静态链接。动态链接的目的就是希望让相同的部分只要一个备份。这一份公用的机器码最好放在一个公用的库中,这个库称为动态链接库。程序执行到这个函数时,就到动态链接库中去取用,这种执行时进行链接的方法称为动态链接。
3.7
句柄与代号:句柄来源于文件的编译,它是编译以后能唯一地用来代表一个文件的整数。进入Windows时期,应用程序建立一个实例,也用一个整数来代表。建立一个窗口有也要用一个整数来代表,建立图标、画刷、游标等编译程序都要给一个整数唯一地表示它们,于是统一地把它们成为代号。代号其实就是内部表格的索引值,Windows通过它到内部表格中去存取有关信息,应用程序,应用程序的实例只能处理到代号,而不能直接存取内部表格中的信息。如果自由存取内部表格中的信息,势必破坏Windows的多任务环境。因此通过代号间接存取数据的结构是极其重要的。随着Windows的发展,特别是面向对象编程的出现,因此,32位Windows中,每个对象都有一个唯一的代号,Windows操作系统就是通过代号来管理系统的。
3.8
消息队列:Windows操作系统负责收集输入消息并把它存入系统消息队列(system queue),然后由操作系统再分送给应用程序消息队列(application queue),以供应用程序的消息循环来读取。
第四章
4.1 HELLOWIN.C应用程序(全看)
WinMain函数体从头至尾可以分为7段:
(1)定义应用程序要用的变量
(2)WNDCLASS是Windows中的窗口类结构名,这一段是定义窗口类变量;
(3)根据窗口类结构填写各条款,形成初始化的窗口类;
(4)进行注册,注册失败则输出信息并返回操作系统,注册成功,则跳过if循环;
(5)根据窗口类建立窗口;
(6)在屏幕上显示窗口;
(7)消息循环。
4.4
#define CS_DBLCLKS 0x0008 //有鼠标双击事件,通知Windows。
4.8 函数调用(所有API)
4.10 建立窗口
Hwnd = CreateWindow(szAppName, //window class name
TEXT(“The Hello Program”), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
4.11 显示窗口
ShowWindow(hwnd, iCmdShow); //在显示器上显示窗口
//hwnd:窗口代号
//iCmdShow:确定最初在屏幕上显示窗口的形状,指示显示窗口是一般大小显示、最小化显示还是最大化显示
UpdateWindow(hwnd);
//使Windows向窗口函数发送一个WM_PAINT消息。
4.12 基本消息循环
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
问:按下A,发出什么消息?WM_KEYDOWN, WM_CHAR
点击A?
第五章
5.1
32位Windows支持三种窗口类:系统全局窗口类、应用专用窗口类、应用全局窗口类
5.2窗口类条款的补充说明
NDPROC lpfnWndProc:指向窗口函数的指针,此窗口函数处理窗口消息
LPCSTR lpszClassName:应用程序使用的窗口类名称
HINSTANCE hInstance:指向应用程序实例的指针
HICON hIcon:指向依此窗口类所建窗口中要引入的小图标
5.3几个窗口类有关的函数
LoadIcon
用法:#include
HICON WINAPI LoadIcon(HINSTANCE hInstance, LPCSTR lpIconName);
//hInstance:指向用户定义图标所在位置,即用户定义图标在哪个实例中,当它为NULL时,那么这是系统定义的图标
//lpIconName:图标名,也称图标上的标签
//HICON:返回值的类型,是指向图标的指针
//返回值:LoadIcon返回的是一个指向图标的指针,如果失败,则返回NULL
IDI_APPLICATION Windows徽标
LoadCursor
用法:
HCURSOR WINAPI LoadCursor(HINSTANCE hInstance, LPCSTR lpCursorName)
//hInstence:包含游标的实例代号。用于载入预定义游标
//lpCursorName:游标的标识标签
//返回值:返回指向光标的代号,调用失败,返回NULL
COLORREF
#define RGB(r, g, b)
((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((WORD)(BYTE)(b))<<16)))
HBRUSH hbrBackground 这是指向窗口类所生成窗口底色的函数背景
5.4 窗口类的式样
框架涉及到的参数
第6章
6.1客户区绘制与更新
Windows是通过发送WM_PAINT消息给窗口函数,使得窗口的被覆盖的部分客户区得以重新绘制。
有效矩形和无效矩形:
InvalidateRect:使客户区内的矩形无效,发送WM_PAINT
ValidateRect:使客户区内的任意矩形区域变为有效。
6.2 GDI简介
设备描述表:
获得hDC代号的方法:
1.利用GetDC(hwnd)取得窗口hDC
hDC = GetDC(hwnd); //整个客户区
Rectangle(hDC, 10, 20, 200, 300);
2.处理WM_PAINT消息期间用BeginPaint获得hDC
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps); //无效区域
TextOut(Hdc, 255, 35, “I LOVE SDK!”, 12);
EndPaint(hwnd, &ps);
return 0;
3.绘图信息结构PAINTSTRUCT
窗口类背景条款的设定方法:
Wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
不过,如果程序通过调用InvalidateRect函数使客户区中的矩形无效,则该函数的最后一个参数会指示是否擦除背景。如果这个参数位FALSE,则执行InvalidateRect时Windows 不擦除背景,反之,则会擦除背景。
6.3 TextOut函数
TextOut(hdc, x, y, psText, iLength);
//hdc:屏幕的设备描述表代号
//x和y:定义客户区内字符串的开始地址,x是水平地址,y是垂直地址
//psText:指向需要在窗口显示的字符串的指针
//iLength:字符串中字符的个数
6.5 系统字体
下面是取得系统字体的字符宽度和高度的WM_CREATE程序码:
case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAverCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hdc);
return 0;
下面的程序码显示了wsprintf与TextOu的典型组合:
int iLength;
TCHAR szBuffer[40];
iLength = wsprintf(szBuffer, TEXT(“The sum of %i and %i is %i”), iA, iB, iA+Ib);
TextOut(hdc, x, y, szBuffer, iLength);
6.8 滚动条的使用(内容不多)
Windows负责处理对滚动条起作用的所有鼠标操作,但是,滚动条没有键盘界面,键盘是不能操作滚动条的。
滚动条消息:用鼠标单击滚动区或者拖动滚动滑块时,Windows给窗口函数发送WM_VSCROLL(供上下移动)和WM_HSCROLL(供左右移动)消息。
wParam的低字组是一个数值,它指出了鼠标对滚动条进行的操作,这个数值称为“通知码”。鼠标在滚动区的不同区域单击所产生的通知码如图。
6.9 建立更好的滚动条
Win32 API滚动条函数:
SetScrollInfo
GetScrollInfo
第七章
7.1.1 GDI函数及其分类
1. 取得和释放设备描述表代号的函数
GetDC
ReleaseDC
2. 取得字体尺寸信息的函数
GetTextMetrics:取得设备描述表中当前所选字体的尺寸
3.绘图函数
TextOut:在窗口的客户区显示一些文字
其他:画线、填入区域等
4.设定和取得设备描述表中有关属性的函数
SetTextAlign
所有Set函数用于设置设备描述表的属性,相应的Get函数用以取得当前设备描述表的属性。
5.使用GDI对象的函数
用户可以指定逻辑画笔的有关特征,并通过CreatePen、CreatePenIndirect或ExtCreatePen 函数建立逻辑画笔,这些函数返回指向逻辑画笔的代号,虽然这些函数被认为是GDI的一部分,但是和大多数GDI函数调用不一样,它们不要求设备描述表代号,它称为GDI 对象。
7.1.3 映射模式和变换
GDI映射模式允许用户以英寸(甚至几分之一英寸)、毫米或者任何想使用的单位来绘图。
7.2 设备描述表(重)
7.2.7 色彩
RGB COLORREF
7.3 画线函数与画笔(理解函数意思)p155
图形函数有:
Rectangle 画矩形
Ellipse 画椭圆
RoundRect 画带圆角的矩形
Pie 画椭圆的一部分,使其看起来想一个扇形
Chord 画椭圆的一部分,以呈弓形
设备描述表的五个属性影响着有关的画图函数所画线的外观。
5个属性:当前画笔地址(仅用于LineTo、PolylineTo、PolyBezierTo和ArcTo)、画笔、背景方式、背景色和绘图模式。
画一条直线,必须调用两个函数。第一个函数制定了线的开始点,第二个函数制定了线的终点:
MoveToEx(hdc, xBeg, yBeg, NULL);
LineTo(hdc, xEnd, yEnd);
7.3.7 画笔
GetStockObject函数的功能是返回现有画笔的代号。
HPENhPen;
hPen = GetStockObject(WHITE_PEN);
必须将画笔选进设备描述表后才能利用画线函数画线,把画笔选进设备描述表的函数是SelectObject:
SelectObject(hdc, hPen);
SelectObject的返回值是GetStockObject函数调用前设备描述表中的画笔代号
画笔的建立和删除:
hPen = CreatePen(iPenStype, iWidth, crColor);
//iPenStyle 画笔样式,实线、点线、虚线
//iWidth 画笔画出直线的宽度
//crColor 是一个COLORREF值,32位无正负号长整数,用来表示色彩
建立画刷的5个函数
建立逻辑画刷:hBrush = CreateSolidBrush(crColor);
建立影线画刷:hBrush = CreateHatchBrush(iHatchStyle, crColor);
建立点阵图画刷:CreatePatternBrush和CreateDIBPatternBrushPt
建立逻辑画刷的第5个函数:hBrush = CreateBrushIndirect(&logbrush);
六个Object:画笔、画刷、位图、字体、区域、调色板
7.5 GDI映射方式
视口和窗口(p1771)
“视口”是依据设备坐标(像素)显示并包含有裁剪区域的客户区。因此,粗略地讲视口和客户区具有相同的意义,不过它是用设备坐标表示的。
“窗口”是程序依据逻辑坐标在屏幕上现实所占据的区域。
结论:
视口是设备坐标表示的客户区
窗口是逻辑坐标表示的程序显示区
补充:程序
SetViewPort
SetWindowsPort
SetMapMode
第八章
8.2 按键
8.2.4 虚拟键码
消息是一种MSG结构。MSG结构中有hWnd、message、wParam、lParam四个参数,其中wParam存放按下或释放按键(或系统按键)所引起虚拟键码。
虚拟键码是指存在于思想中而不是现实世界中的。
VK_LBUTTON 鼠标左键
VK_RBUTTON 鼠标右键
VK_CANCEL Ctrl + Break
VK_MBUTTON 鼠标中键
8.5 字体
8.5.1 Windows支持的三种字体
向量字体、TrueType字体、点阵图字体(位图)
第九章
键盘便于输入与操作文字变量,而鼠标则便于画图和操作图像对象。GetSystemMetrics
9.2 按键及其处理
双击鼠标按键及其处理(会考):(p219)
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
如果在窗口式样中未包含CS_DBLCLKS,而用户双击了鼠标按键,窗口函数接收到的是两次单击消息,而不是双击消息,如下:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDOWN
WM_LBUTTONUP
如果窗口类式样中包含了CS_DBLCLKS,那么双击时窗口函数将收到如下消息:WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
双击的第一次按键操作完成单机的功能,第二次按键产生WM_LBUTTONDBLCLK消息,此消息完成第一次按键以外的事情。
9.3 非显示区域鼠标消息及其处理p220
鼠标消息捕获
焦点:SetFocus
9.4 p230
SendMessage(hwnd, message, wParam, lParam)
SendMessage的四个参数和窗口函数的四个参数是一样的。SendMessage的功能是把message窗口消息及消息参数发送到hwnd所指向的窗口函数。当SendMessage的工作完成后,返回到SendMessage之后的下一条语句。
与PostMessage的区别:
第十章
10.1.1 什么是子窗口控制项?P247
子窗口、父窗口?
10.1.3 控制项的操作
通知码:p250 子窗口的通知码指明父窗口函数干什么工作。通知码用识别字表示。
按钮通知码:BN_
键盘上的游标产生的通知码:SB_
编辑控制项产生的通知码:EN_
列表框控制项产生的通知码:LBN_
10.4 按钮
10.4.1 按钮的分类
常规按钮、核取方块和单选按钮、核取方块的分类
10.7 滚动条控制项
P286
SetWindowLong函数的功能:连接子窗口与子窗口的窗口函数(LONG)ScrollProc。返回指向子窗框的窗口函数的指针。
当滚动条子窗口具有输入焦点并在滚动条子窗口中按动Tab键时,产生的键盘消息首先进入ScrollProc窗口函数处理,处理结束时再利用CallWindowProc转到WinMain函数的窗口函数WndProc进行处理,这种技术叫做”窗口子类化“。
(1)建立新画刷的函数,返回指向新画刷的指针。
(LONG)CreateSolidBrush(RGB(color[0], color[1], color[2]))
(2)把新画刷插入hwnd窗口的窗口类结构中,GCL_HBRBACKGROUND识别字表示插入的是指向背景画刷的指针,GCL_表示是SetClassLong或GetClassLong所用的识别字,SetClassLong 函数返回指向老画刷的指针。
(HBRUSH)SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)(建立新画刷的函数));
第十一章
11.1.2 对话框的分类p304
对话框主要分为两类,它们是模式对话框(mode dialog box)和非模式对话框(modeless dialog box)。
对话框创建?
对话框函数?
11.2 模式对话框p313
在窗口函数中启用对话框
hInstance = ((LPCREATESTRUCT) lParam) -> hInstance;
//利用下面的程序取得的执行实体代号并将它放在静态变量hInstance中:
DialogBox(hInstance, TEXT(“About Box”), hwnd, AboutDlgProc);
//hInstance 执行实例代号
//TEXT 对话框名称
//hwnd 父窗口
//AboutDlgProc 对话框函数
3.取得子窗口控制项代号及ID的方法
从对话框代号和按钮控制项ID来取得控制项的代号:
hwndCtrl = GetDlgItem(hDlg, id);
//hDlg 对话框的代号
//id控制项的ID
//hwndCtrl 控制项的代号
也可以使用如下函数进行相反的求取,从控制项窗口代号中取得控制项的ID值:id = GetWindowLong(hwndCtrl, GWL_ID);
用SendDlgItemMessage循环实现按钮互斥
SendDlgItemMessage(hDlg, id, iMsg, wParam, lParam);
相当于:
SendMessage(GetDlgItem(hDlg, id), id, wParam, lParam);
11.3 非模式对话框
hDlgMo deless = CreateDialog(…);
IsDialogMessage(hDlgModeless, &msg);
对话框初始化:InitDlg();
第十二章资源
资源描述文件p346
12.2 图标
大:48*48
中:32*32
小:16*16
自制图标
12.5 菜单
主菜单、下拉式(浮动式)菜单、弹出式菜单
WM_COMMOND窗口消息
由lParam判断消息来源p365
参数菜单子窗口控制项
HIWORD(wParam) 0 通知码
LOWORD(wParam) 菜单ID子窗口控制项ID
LParam 0 子窗口控制项代号
定时器Timer p372
P377 程序黑体字
BEGIN //顶层菜单(POPMENU)定义条款的开始
POPUP “MYMENU” //这是顶层菜单的菜单项,它是弹出菜单项,能弹出下一级菜单…..
END // POPUP “&File”菜单项弹出菜单定义条款的结束
12.5.8 系统菜单p378
WM_CLOSE -------SendMessage()
12.6 加速键p381
p386
首先,把加速键表的代号定义为类型HANDLE:
HANDLE hAccel;
然后载入加速键表的到实例规定的内存:
hAccel = LoadAccelerators(hInstance, TEXT(“MyAccelerators”));
//hAccel 内存中加速键表的代号
//MyAccelerators 根据模板生成的加速键表
//hInstance实力代号指出了载入的加速键表在哪个实例规定的内存中