Windows 程序设计 笔记

知识点

  1. 双字节字符集和Unicode字符集有何区别?采用双字节字符集有何问题

    • 双字节字符集(DBCS)编码是0-255,DBCS含有1字节代码与2字节代码,而Unicode是统一的16位系统,这样就允许表示 65536个字符。Unicode中的每个字符都是16位宽而不是8位宽。在Unicode中,8位二进制表示一个数值已没意义,而在双字节字符集中仍然 处理8位数值。
    • 双字节字符集并不是所有字符由两个字节代表,这会引起附加的程序设计问题,例如字符串的长度计算。而且处理双字节字符集非常复杂。
  2. 什么叫宽字符?什么是Unicode字符?它们有何区别?

    • 用多个字节来代表的字符称为宽字符,C中用wchar_t表示宽字符数据类型 。
    • Unicode只是宽字符编码的一种实现,用2个字节存贮一个字符
    • Unicode是宽字符的一种,而宽字符并不一定是Unicode。
  3. 讲述_Unicode识别子,TCHAR.h头文件的作用。

    • _UNICODE是控制程序段中的字符串处理函数是按照宽字符串处理函数对待还是按照常规字符串处理函数对待。
    • TCHAR.h为以字符串作为参数的标准库函数提供一系列的替代名称。这些通用函数名称可以指向函数的Unicode版,也可以指向非Unicode版,实现的关键是在编译命令中增加_UNICODE识别字。
  4. 资源描述文件的作用是什么?资源编译器的功能是什么?

    • 资源描述文件的作用是把应用程序或进程用到的资源记录其中。
    • 资源编辑器的功能是根据 RC 文件中模板提供的信息生成资源再编译成所需要的二进制文件,所以现代的资源编译器本质上把资源生成器、编译器联合在一起,利于编程人员的使用。
    • 资源文件与资源描述文件(.RC)的区别?
      • 把应用程序或进程用到的资源记录在一个文件中,这个文件叫做资源描述文件。
      • 在WIN32中,资源称作对象,可分为正文资源,与二进制资源两大类。
  5. 讲讲匈牙利命名惯例的约定,还要记住哪些习惯用法?

    • 匈牙利命名惯例的约定有两条:
      1. 标识符以一个或者几个小写字母开始,这些小写字母表示标识符的数据类型;
      2. 大小写混杂写,使得标识符具有一定的含义,便于理解,增强可读性。
    • 习惯用法:
    • 在命名结构变量时,可以用结构名的小写字符序列作为变量名的字首,或者用整个结构名用作结构变量名。
  6. 解释事件驱动程序的原理,并和过程式程序进行比较。

    • 事件驱动程序
    • 在初始化和创建应用窗口结束后,其他活动基本停止,执行一个无限循环,坐等用户输入消息。一旦用户提供输入产生事件,windows接到消息并分析,根据重要性指挥应用程序工作。如果消息和应用程序无关或无意义则不响应,如果发生很多事件,则在消息队列中排队等候处理。
    • 开始 -> 设置变量,结构 -> 填写窗口类的条款 -> 注册窗口类 -> 创建应用程序窗口 -> 在屏幕上显示窗口

          进入消息循环并从队列中得到一个消息 <---------------------------
                     v                                                ^
              此消息是否为 WM_QUIT---非---->                           |
                     |                     |             是  窗口函数  |
                     |是         应用程序定义过的消息吗?----> 处理消息->|
                     v                      否 V                      |
                 终止执行             对消息进行默认处理--------------->
      
    • 过程式程序是按照编程人员编出程序的顺序执行,自顶向下,单执行流程式样。Windows程序执行过程是应用程序与操作系统相互通信对话的过程,和消息事件密切相关。

  7. 何谓动态链接?何谓静态链接?动态链接库文件的后缀是什么?

    • 动态链接:建立动态链接库让相同的部分只要一个备份,程序执行到这个函数时,就到动态链接库中去取用。
    • 静态链接:程序调用函数时函数的机器码在链接过程中会合并到程序本身中。
    • DLL
  8. 解释窗口类结构名与窗口类变量,为什么要填写窗口类条款?注册的作用是什么?

    • WNDCLAS是Windows中的窗口类结构名,可定义某类窗口的通用模板,体现了窗口们的共同特征。
    • 窗口类变量是依据窗口类结构条目印刷出来的存储区。

    • 窗口类条款是窗口共同书写的记录,填写各条款,形成初始化的窗口类。

    • 注册窗口类的作用是使得Windows操作系统知道这个窗口类,把Windows操作系统和这个窗口类联系起来,使得窗口类处于Windows操作系统的控制之下。
  9. 用哪个函数创建窗口?它是几个参数?请解释每一个参数?

    • CreateWindow:
      HWND CreateWindow(
          LPCTSTR lpClassName,    //pointer to register class name 
          LPCTSTR lpWindowName,    //pointer to window name 
          DWORD dwstyle,    //window style
          int X,    //horizontal position of window 
          int Y,    //vertical positon of window
          int nWidth,    //window width
          int nHeight,    //window height
          HWND hWndParent,    //handle to parent or owner window
          HMENU hMenu,    //handle to menu or child-window identifier
          HANDLE hInstance,    //handle to application instance
          LPVOID lpParam    //pointer to window-creation data
      }
      
  10. 应用程序中用的窗口类名从哪里取得?

    • 窗口类结构条款中的 szAppName,正常应用程序中窗口类名与应用程序名相同。
  11. 主程序WinMain和WndProc是如何联系的?

    • wndclass.lpfnWndProc = WndProc ; // 窗口消息处理程序地址
    • WinProc窗口处理函数是一个回调函数,它是用来处理消息的,是由Windows调用的。
    • 在注册窗口类的时候指定了窗口处理函数的入口地址,应用程序获得的消息都交给此入口地址对应的窗口处理函数来处理。
  12. 解释消息循环中的几个函数?

    • 消息循环与MSG结构:
      while (GetMessage (&msg, NULL, 0, 0)) { // 是否为 !WM_QUIT
          TranslateMessage (&msg);            // 规范化
          DispatchMessage (&msg);             // 调用
      }
      
  13. 解释系统全局窗口类、应用全局窗口类、应用专用窗口类。

    • 系统全局窗口类又称预先定义窗口类,32位Windows提供了7种预先注册好的窗口类,在开发者编写的代码里无需进行任何注册。(COMBOBOX EDIT USEBOX SCROLLBAR CTATIC MDICLIENT)
    • 应用全局窗口类是属于应用程序的,这个应用程序生成的任何进程都可用这个全局窗口类,而不是注册。在多文档程序中使用。
    • 应用专用窗口类是执行进程时就要填写窗口类结构条款、注册的窗口类,属于这个进程,从生成进程过程中注册窗口类开始到进程中断这段时间才是活动的。
  14. 32位Windows支持哪三种窗口类?讲述每种窗口类的用法。

    • 系统全局窗口类、应用全局窗口类、应用专用窗口类
  15. 请解释窗口类结构名和窗口类名。

    • 见 8
  16. 窗口类结构中常用的有哪几个载入函数?它们的用法如何?

    • LoadIcon函数
      HICON  WINAPI LoadIcon(     // 返回的指向图标的指针,如果失败,返回NULL
          HINSTANCE hInstance,    // 用户定义图标在哪个实例中, NULL为系统图标
          LPCSTR lpIconName   // 图标名,也称图标上的标签
      );
      
    • LoadCursor()函数
      HCURSOR WINAPI LoadCursor (     // 返回新载入的光标的句柄
          HINSTANCE hInstance,        // 载入的光标
          LPCTSTR lpCursorName)       // 预定义的光标资源名
      
    • GetStockObject(WHITE_BRUSH);//窗口背景色
  17. 客户区是窗口中的哪部分?

    • 可以由应用程序任意书写和传递窗口信息的部分。
  18. 用哪个函数使得窗口客户区称为无效区域?用哪个函数取得无效区域的坐标?

    • InvalidateRect函数
    • GetUpdateRect函数
  19. Windows环境下,如何实现与设备无关的输出,为什么输出一定要通过GDI函数?

    • 在Windows系统中为每一个设备建立一个数据结构,这个结构记录了设备输出时的详细要求,如文字的颜色,这个数据结构称为设备描述表,简称 DC。Windows系统中使用设备就是抽象成使用DC。这种把设备抽象称为DC,这是实现设备无关性的关键。每个GDI函数就是按照hdc来调用设备 的,GDI函数通过设备进行输出就变成通过DC进行输出。
    • 之所以输出一定要通过GDI函数是因为执行GDI函数输出时,可得到与设备无关的输出。
  20. 解释代号的意义?解释DC的意义?

    • hDC设备描述表代号hDC是指向设备描述表的一个指针。有了hDC代号,编程人员就能自如地在客户区上绘图。应用程序根据hDC代号就知道输出到哪一个窗口或哪一个设备。
    • DC是实现设备无关性的关键。
  21. 解释GDI函数实现与设备无关输出的过程。

    • Windows系统中使用设备就是抽象成使用DC。这种设备抽象称为DC,这是实现设备无关性的关键。每个GDI函数就是按照hdc来调用设备的,GDI函数通过设备进行输出就变成通过DC进行输出。
  22. 有哪两种方法获得屏幕的hDC?

    1. 利用GetDC(hWnd)取得窗口hDC
    2. 处理WM_PAINT消息期间用BeginPaint获得hDC的方法。
  23. InvalidateRect所决定的重画区和BeginPaint所决定的重画区有什么区别?

    • 程序调用BeginPaint时,在大多数情况下,fErase被标志为FALSE(0),这意味着Windows已经擦除了无效矩形的背景。在调用BeginPaint后PAINTSTRUCT结构的fErase条款将成为TRUE(非零)。
    • 而程序通过调用InvalidateRect函数使客户区中的矩形失效,则该函数的最后一个参数会指示是否擦除背景。如果这个参数为FALSE,则执行InvalidateRect时Windows将不擦除背景,反之,则会擦除背景。
  24. 什么情况下产生WM_CREATE窗口消息?什么情况下产生WM_PAINT窗口消息?

    • 产生WM_CREATE窗口消息:执行CreateWindow函数时
    • 产生WM_PAINT窗口消息:
      • 执行UpdateWindow函数时
      • 在使用者移动窗口或显示窗口时,窗口中先前被隐藏的区域重新可见。
      • 使用者改变窗口的大小(如果窗口类别样式有着CS_HREDRAW和CS_VREDRAW位旗标的设定)。
      • 程序使用ScrollWindow或ScrollDC函数滚动显示区域的一部分。
      • 程序使用InvalidateRect或InvalidateRgn函数刻意产生WM_PAINT消息。
      • Windows擦除覆盖了部分窗口的对话框或消息框。
      • (可能)菜单下拉出来,然后被释放。
      • (可能)显示工具提示消息。
  25. 为什么WM_SIZE消息后必然跟着一个WM_PAINT消息?

    • 因为我们定义窗口类的时候制定了类风格 CS_HREDRAW|CS_VREDRAW
  26. 解释滚动条的范围和地址,设置滚动条的范围用哪个函数,设置滚动条的地址用哪个函数?

    • 所谓“范围”是一对整数,分别代表滚动区的最小值和最大值,也就是滑动区的两端;
    • 所谓“地址”是滚动滑块在此范围内的地址。当滚动滑块在滚动区的顶部(或左部)时,滚动滑块的地址是范围的最小值;在滚动条的底部(或右部)时,滚动滑块的地址是范围的最大值。
    • 设置范围函数:SetScrollRange(hwnd,iBar,iMin,iMax,bRedraw);
    • 设置地址函数:SetScrollPos(hwnd,iBar,iPos,bRedraw);
  27. 单击滚动条时会产生通知码,通知码在哪个参数中?意义如何?

    • WParam消息参数被分为一个低位字段和一个高位字段。wParam的低字组是一个数值,它指出了鼠标对滚动条进行的操作,这个数值称为通知码。
  28. 何谓滚动条块当前地址,它一般是整数吗?何谓滚动滑块的大小?何谓“页面大小”?何谓范围?

    • 滑块在滑动区中的当前位置,是整数值。
    • 滑块的大小即滑块的滑动长度,是从滑块的起始地址到滑块的当前地址。
    • “页面大小” 显示区显示内容的长度。
    • 范围 可能显示的文件长度。
  29. 什么是GDI对象?

    • 某些函数不要求设备描述表代号,这些函数称为GDI对象
    • 5类GDI函数:逻辑画笔,画刷,点阵图,区域,字体和调色板。
    • 图形输出设备分为位映射型设备(点阵),向量型设备(矢量)。
  30. 画线函数和画图函数的区别是什么?

    • 画图函数非但要画边界框,还要再画出的区域填入颜色,而画线程序仅仅是画出边界线。
  31. 画椭圆线的函数是什么?画椭圆的函数是什么?

    • Arc函数
    • Ellipse函数
  32. 建立、选择和删除画笔用哪三个函数?

    • 建立画笔:hPen1 = CreatePen (PS_SOLID, 1, 0); // 宽度为1的黑画笔
    • 选择画笔:SelectObject (hdc, hPen1);
    • 删除画笔:DeleteObject (hPen1);
  33. 取得设备描述表代号的方法是什么?

    • 利用GetDC(hWnd)取得窗口hDC
    • 处理WM_PAINT消息期间用BeginPaint获得hDC的方法。
  34. 取得设备描述表中信息的函数是什么?

    • iValue = GetDeviceCaps(hDC,iIndex);
  35. 何谓解析度?屏幕的解析度和打印机的解析度有何不同?如何计算解析度?

    • 解析度:每度量单位内的像素数目
    • 打印机:每英寸的点数
    • 屏幕:以垂直和水平的总像素数
    • 计算:像素大小除以常用度量大小
  36. 何谓像素的色彩数?它和哪些因素有关?

    • 彩色显示器中图形的色彩数等于表示像素可能取的颜色数。
    • 二进制位数越多,表示的颜色就越多,像素的色彩也就愈多。
  37. COLORREF值是什么意思?何谓“RGB彩色”?

    • COLORREF值是一个32位的无正负号长整数。
    • COLORREF值按照红、绿、蓝的亮度指定了一种颜色,通常叫做“RGB色彩”。
  38. 解释设备描述表的构成。修改、取得设备描述表的某属性都有专门的函数,一般在什么情况下进行?

    • 构成:[MSDN][http://msdn.microsoft.com/zh-cn/library/dd183554%28v=vs.85%29.aspx] or [中文][http://166.111.4.15/s96300/vc_dist_course/Chapter4/4.1.1.htm]
    • 当应用程序使用GetDC或BeginPaint函数获得一个设备描述表句柄时,Windows会自动用默认值设置其所有的属性。应用程序可以通过相应的GDI函数调用获取、修改所有的属性值。
    • 取得设备描述表:
      • 处理WM_PAINT消息期间用BeginPaint获得hDC:HDC BeginPaint(HWND, PAINTSTRUCT *)EndPaint(HWND, PAINTSTURCT *)
      • 在处理非WM_PAINT消息期间获得hDC:HDC GetDC(HWND)int ReleaseDC(HWMD ,HDC)
      • 获取整个窗口的设备内容句柄:HDC GetWindowDC(HWND)int ReleaseDC(HWMD ,HDC)
      • 取得不是与特定窗口先关的设备内容句柄:hdc=CreateDC(pszDriver,pszDevice,pszOutput,pData);DeleteDC(hdc); 仅需要获取一个设备内容的设备内容信息而不需进行绘制时,可以使用CreateC。
    • 要保存对设备描述表所做的修改 :
      • 在登录窗口类时在窗口类式样中加入CS_OWNDC
      • DaveDC,RestoreDC
  39. 什么是设备坐标?什么是逻辑坐标?

    • Windows中,一切设备都用统一的坐标,此坐标称为设备坐标。设备坐标是以像素为度量单位的坐标。
    • Windows中还有一种长度单位叫做逻辑坐标,逻辑单位就是数学意义上的坐标,抽象意义上的坐标,如像素。长度单位英寸、米等度量单位的坐标都称为逻辑坐标。
  40. 简述键盘输入的流程。

    • 首先要从键盘的输入开始,一个键盘输入称为一个键盘事件,键盘事件发送到Windows系统,Windows系统就发出一个相应的键盘消息。
  41. 何谓具有输入焦点的窗口?何谓活动窗口?如何辨认活动窗口?

    • 接收特定键盘消息的窗口称为具有输入焦点的窗口。
    • 输入焦点的概念与活动窗口的概念很相近。有输入焦点的窗口一定是活动窗口或活动窗口的衍生窗口。
    • 活动窗口通常是顶层窗口。P180
  42. 何谓系统消息队列?和应用程序消息队列的关系如何?

    • 系统消息队列是独立的消息队列,它由Windows维护,用于初步保存从键盘和鼠标输入的消息。
    • 当Windows应用程序处理完前一个用户输入消息时,Windows才会从系统消息队列中取出下一个消息,并将其放入应用程序的消息序列中。
  43. 按照产生的按键消息分,按键分成哪两类?按键消息有哪四种形式?系统按键消息有什么特点?它在哪里处理?哪些不是系统按键消息?

    • 分为系统按键消息和非系统按键消息
    • 四种形式:
      • WM_KEYDOWN WM_SYSKEYDOWN
      • WM_KEYUP WM_SYSKEYUP
    • 特点:系统按键可能是一个按键也可能是几个按键的组合键,系统按键对Windows系统起作用。
    • 由默认分支DefWindowProc处理系统键盘消息。
    • WM_KEYDOWN WM_KEYUP
  44. 什么是扫描码?什么是虚拟键码?为什么要用虚拟键码?

    • 对于早期的编程人员来说,真实的键码由键盘硬件产生,在Windows文件中将这些键码称为扫描码。
    • 虚拟键盘是概念上的键盘,虚拟键码是Windows设计者在WINUESR.H文件中用识别字定义的键码。
    • 为了实现设备无关性。
  45. 数字和字母的虚拟键码是怎样定义的?

    • 数字、字母的虚拟键码是用ASCII码定义的。
  46. 窗口函数中WM_KEYDOWN消息处理分支中的wParam和SendMessage函数第三个参数wParam有什么不同?

    • 消息处理分支中的wParam它是判断虚拟键盘的。
    • 而SendMessage中的wParam它是存放鼠标通知码。
  47. 字符消息是怎样产生的?字符消息有哪四个?用处如何?字符消息的结构如何?

    • 如果某个按键消息的虚拟按键码是字符码,它将产生一个字符消息,并把字符消息放入应用程序的消息队列。(TranslateMessage函数中实现)
    • WM_CHAR WM_SYSCHAR WM_DEADCHAR WM_SYSDEADCHAR
    • 字符消息把虚拟键码转换为字符的ASCII码或UNICODE码。
    • lParam参数与产生字符消息的按键消息的lParam参数相同,wParam参数的虚拟键码就是字符的ANSI或Unicode代码。
  48. 鼠标是一种“必须要的选择设备”,如何应用GetSystemMetrics函数确认鼠标是否存在?

    • fMouse = GetSystemMetrics (SM_MOUSEPRESENT);
  49. 什么是鼠标游标?它是哪种图?鼠标的热点是什么?

    • 当用户移动鼠标时,Windows在显示器上移动一个小图形,这个小图形实际上是一个点阵图,它称为“鼠标游标”。鼠标游标上有一个像素点,它称为鼠标游标的“热点”。
  50. 鼠标的三个键如何标识?鼠标消息共有几个?鼠标消息与键盘消息的区别是什么?鼠标消息和鼠标的虚拟键码各自用什么前缀?

    • 三键鼠标分为左键、中键、右键,分别用LBUTTON、MBUTTON、RBUTTON识别字表示。
    • 鼠标消息在Windows中共有21个,其中11个消息和显示区域无关。
    • Windows只能把键盘消息发送给拥有输入焦点的窗口函数;只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口函数就会收到鼠标消息。
    • 鼠标消息:WM
    • 鼠标的虚拟键码:MK
  51. 鼠标消息是怎样产生的?鼠标消息中的wparam,lparam各代表什么?

    • 由鼠标硬件和鼠标驱动程序把鼠标事件(或称鼠标动作)变换成为扫描码,再由Windows操作系统把扫描码变换成为鼠标虚拟键码。
    • Wparam是按下去的鼠标按键的虚拟键码,lparam是鼠标地址:低字组是x坐标,高字组是y坐标。
  52. WM_MOUSEMOVE消息是怎样产生的?它有什么特点?

    • 当把鼠标移过窗口显示区域时,产生WM_MOUSEMOVE消息。
    • 只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口函数就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。
  53. 鼠标和Shift Ctrl键如何组合使用?

    • 鼠标消息还可以同时桉下某键盘上的按键和点击鼠标时产生,检测的方法如下:把wparam中的鼠标虚拟键码和某按键的虚拟键码“相与”。
  54. 显示区域鼠标消息中的wParam和lParam参数代表什么?

    • 显示区域鼠标消息的wParam参数是键的虚拟键码。lParam参数是鼠标在屏幕坐标内的x和y地址。
  55. 什么是子窗口控制项?

    • Windows中通常把用作控制作用的子窗口称为控制项、控件、子窗口控制项。
  56. SendMessage 和 PostMessage 有何区别

    • 返回值类型不同
    • PostMessage 是异步的,SendMessage 是同步的
  57. 预定义的控制项窗口类有那七种?

    • Button:按钮窗口类
    • Edit:编辑窗口类
    • Scrollbar:滚动条窗口类
    • Static:静态窗口类
    • ListBox:列表框窗口类
    • MDI:多文档界面控制项
    • Combobox:下拉式列表框控制项
  58. 通知码的作用是什么?P250 试说明键盘上的游标产生的通知码是以什么为前缀的?请列出按钮类、滚动类、编辑类、列表框类的通知码识别字的前缀。

    • 通知码指明父窗口的窗口函数做什么工作
    • 键盘上的游标产生的通知码是以SB_为前缀的识别字。
    • 按钮类 BN_
    • 滚动类 SBN_
    • 编辑类 EN_
    • 列表框类 LBN_
  59. 比较CreateWindow函数创建子窗口控制项与CreateWindow函数创建主窗口?

    • 创建子窗口时必须提供指向父窗口的代号
    • 窗口式样要有WS_CHILDWS_VISIBLE
    • 子窗口ID被强制转换为HMENU
  60. CreateWindow共有11个参数,它们的作用是什么?对创建的子窗口的外形、性能有什么影响?为什么子窗口的窗口式样中要有WS_VISIBLE,而主窗口不要?

    • CreateWindow:
      HWND CreateWindow(
          LPCTSTR lpClassName,    //pointer to register class name 
          LPCTSTR lpWindowName,    //pointer to window name 
          DWORD dwstyle,    //window style
          int X,    //horizontal position of window 
          int Y,    //vertical positon of window
          int nWidth,    //window width
          int nHeight,    //window height
          HWND hWndParent,    //handle to parent or owner window
          HMENU hMenu,    //handle to menu or child-window identifier
          HANDLE hInstance,    //handle to application instance
          LPVOID lpParam    //pointer to window-creation data
      }
      
    • WS_VISIBLE 表示所建的控制项是可见的,用不到执行showWindow函数
  61. WM_COMMAND是怎样产生的?

    • 鼠标单击按钮时,按钮控制项就向其父窗口发送一个WM_COMMAND消息。
  62. 如何表示子窗口与父窗口之间的消息传送?

    • 子窗口->父窗口:WM_COMMAND
      • LOWORD(wParam) 子窗口 ID
      • HIWORD(wParam) 按钮通知码
      • lParam 子窗口代号
    • 父窗口->子窗口:WM_ 和 BM_
  63. 父窗口向子窗口发送消息有哪些目的?

    • 进行交互
  64. WM_CTLCOLORBTN消息是什么情况下产生的?有什么作用?

    • 它称为控制项着色消息,这是当按钮控制项为其显示区域著色时,由按钮控制项发送给其父窗口函数的一个消息。
    • 改变按钮的颜色。
  65. 滚动条有哪两种?如何区分这两种滚动条?滚动条控制项有什么特点?

    • 窗口滚动条和滚动条控制项。
    • 前者出现在窗口的右边和底部。后者是能在父窗口的显示区域的任意地方出现。可以通过lParam参数来区分是窗口滚动条还是滚动条控制项。对窗口滚动条其值为0;滚动条控制项其值为滚动条控制项的代号。
  66. 什么是窗口子类化?说明子类化的目的和方法。子窗口控制项的窗口函数是什么类型的?

    • 通常情况下按钮控制项(窗口)是没有窗口函数的。如果要为控制项设计窗口函数必须解决窗口函数的地址填到预定义窗口类的问题,解决这个问题的技术称为窗口子类化。
    • 使控制项窗口与它的窗口函数相联系。
    • (以子窗口中用 tab 切换为例)用SetWindowLong函数连接子窗口与子窗口的窗口函数,当滚动条子窗口具有输入焦点并在滚动条子窗口中桉动Tab键时,产生的键盘消 息首先进入ScrollProc窗口函数处理,处理结束时再利用CallWindowProc 转到WinMai函数的窗口函数WndProc进行处理,这种技术叫做“窗口子类化”。
    • LRESULT CALLBACK
  67. 什么是对话框?对话框分别哪几类?各类的特点如何?

    • 对话框是由菜单中的选择项来启动的。对话框是一种向下的弹出式窗口,又称下拉式窗口。
    • 对话框主要分成两类,模式对话框和非模式对话框。
    • 所谓模式对话框是指这种对话框出现时其父窗口将暂时失效,处理完对话框所要求的动作后,才能将控制权交回给父窗口。
    • 非模式对话框又称”共存式对话框”,这种对话框出现时,它的父窗口不会失效,用户可以把输入焦点转移到父窗口,并执行父窗口的工作。
  68. 模式对话框和共存式对话框的消息来源有什么不一样?

    • 共存式对话框从WinMain中的消息循环取得消息,而模式对话框的消息来源是对话框管理器。
  69. 含有共存式对话框的应用程序其消息循环必须要做什么?

    • 必须在消息循环中调用IsDialogMessage函数来判断输入消息是否要送给共存式对话框,是的话,就送给共存式对话框函数进行处理,否则,就桉原来的方式处理。
    • 消息循环必须修改成下面形式:
      while (GetMessage (&msg, NULL, 0, 0)) {
          if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg)) {
              TranslateMessage (&msg) ;
              DispatchMessage  (&msg) ;
          }
      }
      
  70. 共存式对话框的建立与结束与模式对话框的建立与结束所用的API函数有什么区别?

    • 共存式对话框的建立靠主程序启动CreateDialog函数来完成。结束则用DestroyWindow函数。
    • 模态对话框的启动函数在应用程序的窗口函数中,在用户点击按钮时,在COMMAND消息处理分支中调用启动函数,启动函数的形式 是:DialogBox (hInstance, TEXT (“AboutBox”), hwnd, AboutDlgProc) ; 模态对话框的结束时刻取决于用户,当用户桉动OK按钮时,进入对话框函数的COMMAND分支,由EndDialog (hDlg, 0)函数结束对话框。
  71. 非模式对话框的特点是什么?怎样建立?

    • 非模态对话框允许用户在对话框与其他程序之间进行切换,又可以在对话框与建立对话框的窗口之间进行切换,但是,用户不能切换到同一程序的另一个窗口,直到非模态对话框被清除为止。因此,非模态对话框与用户程序常见的普通弹出式窗口可能更为相似。
    • 非模态对话框是使用CreateDialog来建立的
  72. 模式对话框与非模式对话框的消息来源有何不同?

    • 模态对话框的消息是从Windows发出,经对话框管理器,再到对话框函数。而非模态对话框的消息要经过消息队列,所以,必须改变应用程序中的消息回路。其消息循环必须修改成下面形式:
      while (GetMessage (&msg, NULL, 0, 0)) {
          if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg)) {
              TranslateMessage (&msg) ;
              DispatchMessage  (&msg) ;
          }
      }
      
  73. 非模式对话框是怎样处理消息的?

    • GetMessage 判断是否为非模式,是就直接由 IsDialogMessage 处理,否则继续 TranslateMessage DispatchMessage 具体:
      while (GetMessage (&msg, NULL, 0, 0)) {
          if (hDlgModeless == 0 || !IsDialogMessage(hDlgModeless, &msg)) {
              TranslateMessage (&msg) ;
              DispatchMessage  (&msg) ;
          }
      }
      
  74. 程序中的“资源”的确切含义是什么?

    • 资源是指图标、游标、字符串、菜单、对话框、点阵图、字体等。通常,我们把计算机的固体部件、器件、组件等成为计算机的硬件资源,把Windows操作系统中的软部件称为软件资源。
  75. 后缀.ICO、.CUR、.BMP、.FNT、.DLG各代表哪种资源?

    • .ICO 图标文件
    • .CUR 光标文件
    • .BMP 图像文件
    • .FNT 字体文件
    • .DLG 对话框资源
  76. 应用程序是怎样使用资源的?

    • 资源原程序文件通过资源编译器编译成为资源二进制文件,应用程序根据需要 用专门的函数载入资源二进制代码。
  77. 简述菜单、菜单项、弹出菜单项、下拉式菜单的含义。

    • 每个菜单至少由一个菜单项所组成。
    • 菜单项又分成两种,一种是能弹出菜单的菜单项,称为弹出菜单项或下拉式菜单项,另一种是不能弹出菜单的菜单项。
    • 凡是包含有弹出菜单项的菜单成为下拉式菜单的“主菜单”或“父菜单”,下拉式菜单成为“子菜单”或弹出菜单。
  78. 在应用程序中引用菜单有哪几种方法?

    1. 填写窗口类条款时指定系统菜单
    2. 在应用程序中使用函数指定菜单
    3. 窗口建立后用SetMenu函数为窗口设定菜单
  79. 解释菜单代号,菜单项ID,菜单ID。

    • 菜单代号:唯一标识这个菜单
    • 菜单项ID:唯一标识该菜单项的ID,也就是拉出的菜单的ID
    • 菜单ID:拉出这个下拉式菜单的菜单项的ID
  80. 当选择菜单项时Windows通常会向菜单所在的窗口函数发送COMMAND消息。除此之外还要发送那些消息?

    1. WM_INITMENU窗口消息:如果顶层菜单是系统菜单,当用户选择系统菜单时,就要向窗口函数发送WM_INITMENU窗口消息.
    2. WM_MENUSELECT窗口消息:用户在菜单项中移动游标或者鼠标。
    3. WM_INITMENUPOPUP窗口消息:当WINDOWS准备显示一个 下拉式菜单时.
    4. WM_COMMAND窗口消息:表示用户已经从菜单中选择了一个被启用的菜单项。
    5. WM_MENUCHAR窗口消息:如果用户按下Alt键和一个与菜单项不匹配的字符时,或者在显示下拉式菜单时,用户按下一个与下拉式菜单里的项目不匹配的字符键。
  81. 用程序实现菜单主要用哪两个函数,基本实现思路是什么?

    • CreateMenu 和 AppendMenu 函数
    • 基本实现思路:先用CreateMenu函数建立的空菜单,后利用AppendMenu将菜单项附加到空菜单中。
      hMenu = CreateMenu();//所建立菜单的菜单代号返回给hMenu
      AppendMenu(hMenuPopup, MF_STRING, IDM_FILE_NEW, "&New");
      

编程题

第七章 例子 LINEDUMO

给矩形填上红色

hBrush = CreateSolidBrush(RGB(255, 0, 0));

给椭圆填上绿色
hBrush = CreateSolidBrush(RGB(0, 255, 0));

给圆角矩形填上网格
hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(0, 255, 0));
SelectObject(hdc, hBrush);

修改至少四种画线模式,体验不同的效果
hPen = CreatePen(PS_DASH, 1, RGB(0,0,0)); 虚线
hPen = CreatePen(PS_DOT, 1, RGB(0,0,0));点线
hPen = CreatePen(PS_DASHDOT, 1, RGB(0,0,0));// PS_DASHDOT虚点线
hPen = CreatePen(PS_DASHDOTDOT, 1, RGB(0,0,0));// PS_DASHDOTDOT虚双点线

选择
SelectObject(hdc, hBrush);
SelectObject(hdc, hPen);

画画

SetPixel (hdc, x, y, crColor);  // 画点
MoveToEx(hdc, 0, 0, NULL);      // 画线
LineTo(hdc, x, y);
Rectaangle(hdc, x, y, x, y);    // 画矩形
Ellipse(hdc, x, y, x, y);       // 椭圆
Triangle                        // 三角形

第十章 例子 按钮 颜色改变

只有当按钮类型为BS_OWNERDRAW也就是拥有者绘制按钮的时候拦截WM_CTLCOLORBTN

//设置按钮的属性为可自绘
HWND hBn = GetDlgItem(hDlg, IDOK);
SetWindowLong(hBn, GWL_STYLE, GetWindowLong(hBn, GWL_STYLE) | BS_OWNERDRAW);
return INT_PTR(TRUE);

// 然后再在WM_CTLCOLORBTN消息里执行:
case WM_CTLCOLORBTN ://设置按钮的颜色
if ((HWND)lParam == GetDlgItem(hDlg, IDOK)) {
   HWND hbn = (HWND)lParam;
   HDC hdc = (HDC)wParam;
   RECT rc;
   TCHAR text[64];

   GetWindowText(hbn, text, 63);
   GetClientRect(hbn, &rc);
   SetTextColor(hdc, RGB(255, 255, 255));//设置按钮上文本的颜色
   SetBkMode(hdc, TRANSPARENT);
   DrawText(hdc, text, _tcslen(text), &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

   return (INT_PTR)CreateSolidBrush(RGB(127,0,255));//返回画刷设置按钮的背景色
}
break;

第十一章 实例(对话框)

模态

// in WndProc
case ID_TEST:
    DialogBox(hInst, MAKEINTRESOURCE(IDD_TEST), hWnd, test);
    break;

// in test func
case WM_COMMAND:
    if (LOWORD(wParam) == IDC_BUTTON1 || LOWORD(wParam) == IDOK)
        SetDlgItemText(hDlg, IDC_TTT, TEXT("Click And Change!"));

非模态

// in WndProc
case ID_TEST:
    g_hToolbar = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_TOOLBAR),
                hwnd, ToolDlgProc);
// in ToolDlgProc
case WM_COMMAND:
    if (LOWORD(wParam) == IDC_BUTTON1 || LOWORD(wParam) == IDOK)
        SetDlgItemText(hDlg, IDC_TTT, TEXT("Click And Change!"));

 

转载于:https://www.cnblogs.com/weekbo/p/9076006.html

WINDOWS环境 Windows几乎不需要介绍。然而人们很容易忘记Windows给办公室和家庭桌上型计算机所带来的重大改变。Windows在其早期曾经走过一段坎坷的道路,征服桌上型计算机市场的前途一度相当渺茫。 Windows简史 在1981年秋天IBM PC推出之后不久,MS-DOS就已经很明显成为PC上的主流操作系统。MS-DOS代表Microsoft Disk Operating System(磁盘操作系统)。MS-DOS是一个小型的操作系统。MS-DOS提供给用户一种命令列接口,提供如DIR和TYPE的命令,也可以将应用程序加载内存执行。对于应用程序写作者,它提供了一组函数呼叫,进行文件的输入输出(I/O )。对于其它的外围处理-尤其是将文字或图形写到显示器上-应用程序可以直接存取PC的硬件。 由于内存和硬件的限制,成熟的图形环境缓慢地才到来。当苹果计算机公司不幸的Lisa计算机在1983年1月发表时,它提供了不同于文字模式环境的另一种选择,并在1984年1月成为Macintosh上图形环境的一种标准。尽管Macintosh的市场占有率在下降,但是它仍然被认为是衡量所有其它图形环境的标准。包括Macintosh和Windows的所有图形环境,其实都要归功于Xerox Palo Alto Research Center(PARC)在70年代中期所作的开拓性研究工作。 Windows是由微软在1983年11月(在Lisa之后,Macintosh之前)宣布,并在两年后(1985年11月)发行。在此后的两年中,紧随着Microsoft Windows早期版本1.0之后,又推出了几种改进版本,以支持国际商业市场,并提供新型视讯显示器和打印机的驱动程序。 Windows版本2.0是在1987年11月正式在市场上推出的。该版本对使用者接口做了一些改进。这些改进中最有效的是使用了可重迭式窗口,而Windows 1.0中使用的是并排式窗口。Windows 2.0还增强了键盘和鼠标接口,特别是加入了菜单和对话框。 至此,Windows还只要求Intel 8086或者8088等级的微处理器,以「实际模式」执行,只能存取地址在1MB以下的内存。Windows/386(在Windows 2.0之后不久发行的)使用Intel 386微处理器的「虚拟8086」模式,实现将直接存取硬件的多个MS-DOS程序窗口化和多任务化。为了统一起见,Windows版本2.1被更名为Windows/286。 Windows 3.0是在1990年5月22日发表的。它将Windows/286和Windows/386结合到同一种产品中。Windows 3.0有了一个很大的改变,这就是对Intel的286、386和486微处理器保护模式的支持。这能使WindowsWindows应用程序能存取高达16MB的内存。Windows用于执行程序和维护文件的「外壳」程序得到了全面的改进。Windows 3.0是第一个在家用和办公室市场上取得立足点的版本。 任何Windows的历史介绍都必须包括一些OS/2的说明,OS/2是对DOS和Windows的另一种选择,最初是由Microsoft和IBM合作开发的。OS/2版本1.0(只有文字模式)在Intel 286(或者后来的)微处理器上运行,在1987年末发布。在1988年10月的OS/2版本1.1中出现了管理图形使用者接口的PM(Presentation Manager)。PM最初的设计构想是成为Windows的一种保护模式版本,但是图形API改变程度太大,致使软件生产厂商很难提供对这两种平台的支持。 到1990年9月,IBM和Microsoft之间的冲突达到了高峰,导致这两个公司最后分道扬镳。IBM接管了OS/2,而Microsoft明确表示Windows将是他们操作系统策略的中心。虽然OS/2仍然拥有一些狂热的崇拜者,但是它远不及Windows这样的普及程度。 Microsoft Windows版本3.1是1992年4月发布的,其中包括的几个重要特性是TrueType字体技术(给Windows带来可缩放的轮廓字体)、多媒体(声音和音乐)、对象连结和嵌入(OLE:Object Linking and Embedding)和通用对话框。跟OS/2一样,Windows 3.1只能在保护模式下运作,并且要求至少配置了1MB内存的286或386处理器。 在1993年7月发表的Windows NT是第一个支持Intel 386、486和Pentium微处理器32位保护模式的Windows版本。Windows NT提供32位平坦寻址,并使用32位的指令集。(本章后面我会谈到一些寻址空间的问题)。Windows NT还可以移植到非Intel处理器上,并在几种使用RISC芯片的工作站上执行。 Windows 95是在1995年8月发布的。和Windows NT一样,Windows 95也支持Intel 386或更高等级处理器的32位保护模式。虽然它缺少Windows NT中的某些功能,诸如高安全性和对RISC机器的可移植性等,但是Windows 95具有需要较少硬件资源的优点。 Windows 98在1998年6月发布,具有许多加强功能,包括执行效能的提高、更好的硬件支持以及与因特网和全球信息网(WWW)更紧密的结合。 Windows方面 Windows 98和Windows NT都是支持32位优先权式多任务(preemptive multitasking)及多线程的图形操作系统Windows拥有图形使用者接口(GUI ),这种使用者界面也称作「可视化接口」或「图形窗口环境」。有关GUI的概念可追溯至70年代中期,在Alto和Star等机器上以及SmallTalk等环境中由Xerox PARC所作的研究工作。该项研究的成果后来被Apple Computer和Microsoft引入主流并流行起来。虽然有一些争议,但现在已非常清楚,GUI是(Microsoft的Charles Simonyi的说法)一个在个人计算机工业史上集各方面技术大成于一体的最重要产物。 所有GUI都在点矩阵对应的视讯显示器上处理图形。图形提供了使用屏幕的最佳方式、传递信息的可视化丰富多彩环境,以及能够WYSIWYG(what you see is what you get:所见即所得)的图形视讯显示和为书面文件准备好格式化文字输出内容。 在早期,视讯显示器仅用于响应使用者通过键盘输入的文字。在图形使用者接口中,视讯显示器自身成为使用者输入的一个来源。视讯显示器以图标和输入设备(例如按钮和滚动条)的形式显示多种图形对象。使用者可以使用键盘(或者更直接地使用鼠标等指向设备)直接在屏幕上操纵这些对象,拖动图形对象、按下鼠标按钮以及滚动滚动条。 因此,使用者与程序的交流变得更为亲密。这不再是一种从键盘到程序,再到视讯显示器的单向信息流动,使用者已经能够与显示器上的对象直接交互作用了。 使用者不再需要花费长时间学习如何使用计算机或掌握新程序了。Windows让这一切成真,因为所有应用程序都有相同的基本外观和感觉。程序占据一个窗口-屏幕上的一块矩形区域。每个窗口由一个标题列标识。大多数程序功能由程序的菜单开始。用户可使用滚动条观察那些无法在一个屏幕中装下的信息。某些菜单项目触发对话框,用户可在其中输入额外的信息。几乎在每个大的Windows程序中都有一个用于开启文件的特殊对话框。该对话框在所有这些Windows程序中看起来都一样(或接近相同),而且几乎总是从同一菜单选项中启动。 一旦您了解使用一个Windows程序的方法,您就非常容易学习其它的Windows程序。菜单和对话框允许用户试验一个新程序并探究它的功能。大多数Windows程序同时具有键盘接口和鼠标接口。虽然Windows程序的大多数功能可通过键盘控制,但使用鼠标要容易得多。 从程序写作者的角度看,一致的使用者接口来自于Windows建构菜单和对话框的内置程序。所有菜单都有同样的键盘和鼠标接口,因为这项工作是由Windows处理,而不是由应用程序处理。 为便于多个程序的使用,以及这些程序间信息的交换,Windows支持多任务。在同一时刻能有多个Windows程序显示并运行。每个程序在屏幕上占据一个窗口。用户可在屏幕上移动窗口,改变它们的大小,在不同程序间切换,并从一个程序向另一个程序传送数据。因为这些窗口看起来有些像桌面上的纸(当然,这是计算机还未占据办公桌之前的年代),Windows有时被称作:一个显示多个程序的「具象化桌面」。 Windows的早期版本使用一种「非优先权式(non-preemptive)」的多任务系统。这意味着Windows不使用系统定时器将处理时间分配给系统中运行的多个应用程序,程序必须自愿放弃控制以便其它程序运行。在Windows NT和Windows 98中,多任务是优先权式的,而且程序自身可分割成近乎同时执行的多个执行绪。 操作系统不对内存进行管理便无法实现多任务。当新程序启动、旧程序终止时,内存会出现碎裂空间。系统必须能够将闲置的内存空间组织在一起,因此系统必须能够移动内存中的程序代码和数据块。 即使是在8088微处理器上跑的Windows 1.0也能进行这类内存管理。在实际模式限制下,这种能力被认为是软件工程一个令人惊讶的成就。在Windows 1.0中,PC硬件结构的640KB内存限制,在不要求任何额外内存的情况下被有效地扩展了。但Microsoft并未就此停步:Windows 2.0允许Windows应用程序存取扩充内存(EMS);Windows 3.0在保护模式下,允许Windows应用程序存取高达16MB的扩展内存。Windows NT和Windows 98通过成熟的32位操作系统及平坦寻址空间,摆脱了这些旧的限制。 Windows上执行的程序可共享在称为「动态链接库」的文件中的例程。Windows包括一个机制,能够在执行时连结使用动态链接库中例程的程序。Windows自身基本上就是一个动态链接库的集合。 Windows一个图形接口,Windows程序能够在视讯显示器和打印机上充分利用图形和格式化文字。图形接口不仅在外观上更有吸引力,而且还能够让使用者传递高层次的信息。 Windows应用程序不能直接存取屏幕和打印机等图形显示设备硬件。相反,Windows提供一种图形程序语言(称作图形设备接口,或者GDI),使显示图形和格式化文字更容易。Windows虚拟化了显示硬件,使为Windows编写的程序可使用任何具有Windows设备驱动程序的视频卡或打印机,而程序无需确定系统相连的设备类型。 对Windows开发者来说,将与设备无关的图形接口输出到IBM PC上不是件轻松的事。PC的设计是基于开放式架构的原则,鼓励第三方硬件制造商为PC开发接口设备,而且开发了大量这样的设备。虽然出现了多种标准,PC上的传统MS-DOS程序仍不得不各自支持许多不同的硬设备。这对MS-DOS字处理软件来说非常普遍,它们连同1到2张有许多小文件的磁盘一同销售,每个文件支持一种特定的打印机。Windows程序不要求每个应用程序都自行开发这些驱动程序,因为这种支持是Windows的一部分。 动态链接 Windows运作机制的核心是一个称作「动态链接」的概念。Windows提供了应用程序丰富的可呼叫函数,大多数用于实作其使用者接口和在视讯显示器上显示文字和图形。这些函数采用动态链接库(Dynamic Linking Library,DLL)的方式撰写。这些动态链接库是些具有.DLL或者有时是.EXE扩展名的文件,在Windows 98中通常位于\WINDOWS\SYSTEM子目录中,在Windows NT中通常位于\WINNT\SYSTEM和\WINNT\SYSTEM32子目录中。 在早期,Windows的主要部分仅通过三个动态链接库实作。这代表了Windows的三个主要子系统,它们被称作Kernel、User和GDI。当子系统的数目在Windows最近版本中增多时,大多数典型的Windows程序产生的函数呼叫仍对应到这三个模块之一。Kernel(日前由16位的KRNL386.EXE和32位的KERNEL32.DLL实现)处理所有在传统上由操作系统核心处理的事务-内存管理、文件I/O和多任务管理。User(由16位的USER.EXE和32位的USER32.DLL实作)指使用者接口,实作所有窗口运作机制。GDI(由16位的GDI.EXE和32位的GDI32.DLL实作)是一个图形设备接口,允许程序在屏幕和打印机上显示文字和图形。 Windows 98支持应用程序可使用的上千种函数呼叫。每个函数都有一个描述名称,例如CreateWindow。该函数(如您所猜想的)为程序建立新窗口。所有应用程序可以使用的Windows函数都在表头文件里预先声明过。 在Windows程序中,使用Windows函数的方式通常与使用如strlen等C语言链接库函数的方式相同。主要的区别在于C语言链接库函数的机械码连结到您的程序代码中,而Windows函数的程序代码在您程序执行文件外的DLL中。 当您执行Windows程序时,它通过一个称作「动态链接」的过程与Windows相接。一个Windows的.EXE文件中有使用到的不同动态链接库的参考数据,所使用的函数即在那些动态链接库中。当Windows程序被加载到内存中时,程序中的呼叫被指向DLL函数的入口。如果该DLL不在内存中,就把它加载到内存中。 当您连结Windows程序以产生一个可执行文件时,您必须连结程序开发环境提供的特定「引用链接库(import library)」。这些引用链接库包含了动态链接库名称和所有Windows函数呼叫的引用信息。连结程序使用该信息在.EXE文件中建立一个表格,在加载程序时,Windows使用它将呼叫转换为Windows函数。 WINDOWS程序设计选项 为说明Windows程序设计的多种技术,本书提供了许多范例程序。这些程序使用C语言撰写并原原本本的使用Windows API来开发程序。我将这种方法称作「古典」Windows程序设计。这是我们在1985年为Windows 1.0写程序的方法,它今天仍是写作Windows程序的有效方法。 API和内存模式 对于程序写作者来说,操作系统是由本身的API定义的。API包含了所有应用程序能够使用的操作系统函数呼叫,同时包含了相关的数据型态和结构。在Windows中,API还意味着一个特殊的程序架构,我们将在每章的开头进行研究。 一般而言,Windows API自Windows 1.0以来一直保持一致,没什么重大改变。具有Windows 98程序写作经验的Windows程序写作者会对Windows 1.0程序的原始码感觉非常熟悉。API改变的一种方式是进行增强。Windows 1.0支持不到450个函数呼叫,现在已有了上千种函数呼叫。 Windows API和它的语法的最大变化来自于从16位架构向32位架构转化的过程中。Windows从版本1.0到版本3.1使用16位Intel 8086、8088、和286微处理器上所谓的分段内存模式,由于兼容性的原因,从386开始的32位Intel微处理器也支持该模式。在这种模式下,微处理器缓存器的大小为16位,因此C的int数据型态也是16位宽。在分段内存模式下,内存地址由两个部分组成-一个16位段(segment)指针和一个16位偏移量(offset)指标。从程序写作者的角度看,这非常凌乱并带来了long或far指针(包括段地址和偏移量地址)和short或near指标(包括带有假定段地址的偏移量地址)的区别。 从Windows NT和Windows 95开始,Windows支持使用Intel 386、486和Pentium处理器32位模式下的32位平坦寻址内存模式。C语言的int数据型态也扩展为32位的值。为32位版本Windows编写的程序使用简单的平坦线性空间寻址的32位指针值。 用于16位版本Windows的API(Windows 1.0到Windows 3.1)现在称作Win16。用于32位版本Windows的API(Windows 95、Windows 98和所有版本的Windows NT)现在称作Win32。许多函数呼叫在从Win16到Win32的转变中保持相同,但有些需要增强。例如,图像坐标点由Win16中的16位值变为Win32中的32位值。此外,某些Win16函数呼叫返回一个包含在32位整数值中的二维坐标点。这在Win32中不可能,因此增加的新函数呼叫以不同方式运作。 所有32位版本的Windows都支持Win16 API(以确保和旧有应用程序兼容)和Win32 API(以运行新应用程序)。非常有趣的是,Windows NT与Windows 95及Windows 98的工作方式不同。在Windows NT中,Win16函数呼叫通过一个转换层被转化为Win32函数呼叫,然后被操作系统处理。在Windows 95和Windows 98中,该操作正相反:Win32函数呼叫通过转换层转换为Win16函数呼叫,再由操作系统处理。 在同一时刻有两个不同的Windows API集(至少名称不同)。Win32s (「s」代表「subset(子集)」)是一个API,允许程序写作者编写在Windows 3.1上执行的32位应用程序。该API仅支持已被Win16支持的32位函数版本。此外,Windows 95 API一度被称作Win32c(「c」代表「compatibility(兼容性)」),但该术语已被抛弃了。 现在,Windows NT和Windows 98都被认为能够支持Win32 API。然而,每个操作系统依然都支持某些不被别的操作系统支持的某些功能特性。因为它们的相同之处是相当可观的,所以有可能编写在两个操作系统下都可执行的程序。而且,人们普遍认为这两个产品最终会合而为一。 语言选项 使用C语言和原始的API不是编写Windows 98程序的唯一方法。然而,这种方法却提供给您最佳的性能、最强大的功能和在发掘Windows特性方面最大的灵活性。可执行文件相对较小且运行时不要求外部链接库(自然,Windows DLL自身除外)。最重要的是,不管您最终以什么方式开发Windows应用程序,熟悉API会使您对Windows内部有更深入的了解。 虽然我认为学习古典的Windows程序设计对任何Windows程序写作者都是重要的,我没有必要建议使用C和API编写每个Windows应用程序。许多程序写作者,特别是那些为公司内部开发程序或在家编写娱乐程序的程序写作者喜欢轻松的开发环境,例如Microsoft Visual Basic或者Borland Delphi(它结合了对象导向的Pascal版本)。这些环境使程序写作者将精力集中于应用程序的使用者接口和相关使用者接口对象的程序代码上。要学习Visual Basic,您也许需要参考Microsoft Press的一些其它图书,例如Michael Halvorson1996年着的《Learn Visual Basic Now》。 在专业程序写作者中-特别是那些开发商业应用程序的程序写作者-Microsoft Visual C++和Microsoft Foundation Class Library(MFC)是近年来流行的选择。MFC在一组C++对象类别中封装了许多Windows程序设计中的琐碎细节。Jeff Prosise的《Programming Windows with MFC,第二版》(Microsoft Press,1999年)提供了MFC程序的写作指南。 最近,Internet和World Wide Web的流行大力推广着Sun Microsystems的Java,这是一个受C++启发却与微处理器无关的程序设计语言,而且结合了可在几个操作系统平台上执行的图形应用程序开发工具组。Microsoft Press有一本关于Microsoft J++(Microsoft的Java)开发工具的好书,《Programming Visual J++ 6.0》(1998年),由Stephen R. Davis着。 显然,很难说哪种方法更有利于开发Windows应用程序。更主要的是,也许是应用程序自身的特性决定了所使用的工具。不管您最后实际上使用什么工具写作程序,学习Windows API将使您更深入地了解Windows工作的方式。Windows一个复杂的系统,在API上增加一个程序写作层并未减少它的复杂性,仅仅是掩盖了它,早晚您会碰到它。了解API会给您更好的补救机会。 在原始的Windows API之上的任何软件层都必定将您限制在全部功能的一个子集内。您也许发现,例如,使用Visual Basic编写应用程序非常理想,然而它不允许您做一个或两个很简单的基本工作。在这种情况下,您将不得不使用原始的API呼叫。API定义了作为Windows程序写作者所需的一切。没有什么方法比直接使用API更万能的了。 MFC尤其问题百出。虽然它大幅简化了某些工作(例如OLE),我却经常发现要让它们按我所想的去工作时,会在其它特性(例如Document/View架构)上碰壁。MFC还不是Windows程序设计者所追求的灵丹妙药,很少有人认为它是一个好的对象导向设计的模型。MFC程序写作者从他们使用的对象类别定义如何工作中受益颇深,并会发现他们经常参考MFC原始码,搞懂这些原始码是学习Windows API的好处之一。 程序开发环境 在本书中,假定您正使用Microsoft Visual C++ 6.0,标准版、专业版和企业版都可以。经济的标准版足以应付本书中的程序设计需求。Visual C++ 还是Visual Studio 6.0中的一部分。 Microsoft Visual C++ 软件包中包括C编译器和其它编译及连结Windows程序所需的文件和工具等。它还包括Visual C++ Developer Studio,一个可编辑原始码、以交谈方式建立资源(如图标和对话框)以及编辑、编译、执行和测试程序的环境。 如果您正使用Visual C++ 5.0,则需要为Windows 98和Windows NT 5.0更新表头文件和引用链接库,这些东西可从Microsoft的网站上得到。在 http://www.microsoft.com/msdn/,选择「Downloads」,然后选择「 Platform SDK」(软件开发套件),您就能在选择的目录中下载和安装更新文件。要让Microsoft Developer Studio浏览这些目录,可以从「Tool」菜单项选择「 Options」然后按下「Directories」标签。 Microsoft网站上的msdn部分代表「Microsoft Developer Network(Microsoft软件开发者网络)」。这是一个向程序写作者提供了经常更新的CD-ROM的计划,这些CD-ROM中包含了程序写作者在Windows开发中所需的最新东西。您也可以订阅MSDN,这样就避免经常得从Microsoft的网站下载文件。 API文件 本书不是Windows API权威的正式文件的替代品。那组文件不再以印刷形式出版,它仅能从CD-ROM或Internet上取得。 当您安装Visual C++ 6.0时,您将得到一个包括API文件的在线求助系统。您可通过订阅MSDN或使用Microsoft网站上的在线求助系统更新该文件。连接到 http://www.microsoft.com/msdn/,并选择「MSDN Library Online」。 在Visual C++ 6.0中,从「Help」菜单项选择「Contents」项目开启MSDN窗口。API文件按树形结构组织,寻找标有「 Platform SDK」的部分,所有在本书中引用的文件都来自于该部分。我将向您介绍如何从「 Platform SDK」开始寻找以斜线分层分门别类的文件的位置。(我知道「Platform SDK」是整个MSDN知识库中较为晦涩的部分,但我敢保证那是Windows程序设计的基本核心。)例如,对于如何在Windows程序中使用鼠标的文件,您可参考/ Platform SDK / User Interface Services / User Input / Mouse Input。 我在前面提到Windows大致分为Kernel、User和GDI子系统。kernel接口在/ Platform SDK / Windows Base Services中,User界面函数在 / Platform SDK / User Interface Services中,GDI位于 / Platform SDK / Graphics and Multimedia Services / GDI中。 编写第一个WINDOWS程序 现在是开始写些程序的时候了。为了便于对比,让我们以一个非常短的Windows程序和一个简短的文字模式程序开始。这会帮助我们找到使用开发环境并感受建立和编译程序机制的正确方向。 文字模式(Character-Mode)模型 程序写作者们喜爱的一本书是《The C Programming Language》(Prentice Hall,1978年和1988年),由Brian W. Kernighan和Dennis M. Ritchie(亲切地称为K&R)编着。该书的第一章以一个显示「hello, world」的C语言程序开始。 这里是在《The C Programming Language》第一版第6页中出现的程序: main () { printf ("hello, world\n") ; } 以前C程序写作者在使用printf等C执行期链接库函数时,无需先声明它们。但这是90年代,我们愿意给编译器一个在我们的程序中标出错误的机会。这里是在K&R第二版中修正的程序: #include <stdio.h> main () { printf ("hello, world\n") ; } 该程序仍然是那么短。但它可通过编译并执行得很好,但当今许多程序写作者更愿意清楚地说明main函数的返回值,在这种情况下ANSI C规定该函数必须返回一个值: #include <stdio.h> int main () { printf ("hello, world\n") ; return 0 ; } 我们还可以包括main的参数,把程序弄得更长一些,但让我们暂且这样就好了-包括一个include声明、程序的进入点、一个对执行期链接库函数的呼叫和一个return语句。 同样效果的Windows程序 Windows关于「hello, world」程序的等价程序有和文字模式版本完全相同的组件。它有一个include声明、一个程序进入点、一个函数呼叫和一个return语句。下面便是该程序: /*------------------------------------------------------------------ HelloMsg.c -- Displays "Hello, Windows 98!" in a message box (c) Charles Petzold, 1998 --------------------------------------------------------------------*/ #include <windows.h> int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MessageBox (NULL, TEXT ("Hello, Windows 98!"), TEXT ("HelloMsg"), 0); return 0 ; } 在剖析该程序之前,让我们看一下在Visual C++ Developer Studio中建立新程序的方式。 首先,从File菜单中选New。在 New对话框中,单击Projects页面标签,选择 Win32 Application。在Location栏中,选择一个子目录,在 Project Name栏中,输入该项目的名称,此时该名称是HelloMsg,这便是在 Location栏中显示的目录的子目录。Create New Workspace复选框应该勾起来,Platforms部分应该显示 Win32,选择OK。 将会出现一个标题为Win32 Application - Step 1 Of 1的对话框,指出要建立一个Empty Project,并按下Finish按钮。 从File菜单中再次选择New。在 New对话框中,选择Files页面标签,选择 C++ Source File。Add To Project复选框应被选中,并应显示HelloMsg。在 File Name栏中输入HelloMsg.c,选中OK。 现在您可输入上面所示的HELLOMSG.C文件,您也可以选择Insert菜单和 File As Text选项从本书附带的CD-ROM上复制HELLOMSG.C的内容。 从结构上说,HELLOMSG.C与K&R的「hello,world」程序是相同的。表头文件STDIO.H已被WINDOWS.H所代替,进入点main被WinMain所代替,而且C语言执行时期链接库函数printf被Windows API函数MessageBox所代替。然而,在程序中有许多新东西,包括几个陌生的大写标识符。 让我们从头开始。 表头文件 HELLOMSG.C以一个前置处理器指示命令开始,实际上在每个用C编写的Windows程序的开头都可看到:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值