windows应用程序:WINDOWS应用程序组织及例子

  Windows应用面向对象认识

  面向对象作为种思路方法学要求将数据和操作(代码)归结到某些对象名下将数据看作对象属性要改变这些属性必须通过操作来进行

  进行面向对象设计最好使用面向对象语言如CSamllTalk等面向对象语言语言所起作用就是给员们提供些进行面向对象设计时必需约束使数据和操作衔接有种显式描述并进行些技术性事务管理但是如果我们能理解面向对象设计原理和思路方法即使不使用面向对象语言也能实现面向对象设计

  Windows本身并不是个面向对象设计环境但Windows某些部分还是明显地受到面向对象软件Software概念影响从某种程度上说在进行Windows设计时员是在进行面向对象设计理解Windows面向对象思想和应用设计面向对象思路方法对设计结构合理应用会有很大帮助

  前面已给出了对象定义:每个对象包含有数据和代码代码描述了对象可执行系列预定义动作而数据是对象私有它们由相关可执行代码存取预定义动作和私有数据结合称为封装在C中我们使用来封装个对象私有数据和动作使用switch语句来定义预定义动作这些动作只存取为该本身所知道数据

  Windows和Windows应用是怎样发送消息呢?在Windows及其应用消息被表示为个数据结构并能在对象的间传递发送消息等价于执行其参数表示消息数据参数的个标识该消息预定义消息标识符个对象接受到条消息时消息标识符决定该对象执行何种动作消息传递是以形式来实现这种可以发生在任何地方

  Windows员必须清楚用消息引发动作技术区别对象能以区别动作响应同样消息这样个特定消息可代表个通用事件例如按键操作、移动鼠标或绘制用户区等;而任何个特定消息可以在区别对象中引发区别动作例如区别窗口对象以区别动作处理同样WM_KEYDOWN、WM_MOUSEMOVE或WM_PAINT消息

  个消息可以有个对象发送到另个对象或由Windows发送到某个对象例如WM_KEY_DOWN的类消息是由Windows产生有些消息在对象窗口对其处理完毕后就消失了而有些消息在处理时有产生新消息:个对象通过向其它对象或自己发送条或多条消息来处理条消息这样Windows应用控制流程不象MS-DOS应用那样易于跟踪调试也比MS-DOS应用困难

  除了个别消息以外对象接受消息顺序是不可预知但对象处理每条消息所采取动作是显式定义在窗口对象并不显式地定义所有可能消息动作对于不显示处理消息都交由DefWindowProc进行缺省处理

  消息传递途径很简单:从个对象传递到另对象但由于DefWindowProc对有些消息提供了缺省处理因此员在设计时必须考虑在个窗口中捕获某条消息时是否还应交给DefWindowProc作进处理DefWindowProc能处理所有消息但对大部消息只是简单地废弃的不作具有实际意义处理在窗口捕获这些废弃消息是安全;若要捕获其它消息则必须了解DefWindowProc是怎样处理这条消息并在窗口处理代码中能提供类似处理(或将该消息交由DefWindowProc作进处理)

  现在我们讨论窗口对对象私有数据处理问题窗口类也介绍说明了对象私有数据CreateWindow创建个窗口对象时Windows为创建窗口对象分配私有数据存储区其中存储有窗口例子句柄、父窗口句柄、窗口地址和其它Windows用于管理窗口对象数据对这些私有数据操作只能使用GetWindowWord/GetWindowLong等对于中介绍说明变量如何在窗口中将它们和相关对象衔接在起就比较复杂窗口为该类所有对象共享该类所有对象在接收到消息时都执行相同代码

  在过去Windows推荐使用设计语言是C由于C语言不具备将个对象私有数据和操作这些私有数据代码衔接在语言成份(面向对象语言事务性工作的就是为完成这个工作)这个工作只能由员来作员心中必须清楚中所介绍说明或分配变量私有于哪个对象并采用合适数据结构来表示它们以便在使用它们时能根据区别对象将它们区别开来

  有几种思路方法可用于区分对象私有数据:

  员编制额外代码来判断个对象应使用哪些数据

  使用窗口附加字节

  使用属性表

  当使用第种思路方法时实际是使用对象句柄作索引来检索和该对象相关私有数据Windows也使用这种思路方法使用句柄来检索张表这个表中存储着该句柄所标识对象私有数据Windows许多需要个对象句柄作为第参数其原因就是为区分对象私有数据以便使用相同处理区别对象(数据)

  后两种思路方法和第种思路方法本质是(我们会将在后面章节对其进行介绍)只是Windows提供了些相关来简化工作

  由于C没有继承这种语言成分也就不能形成对象等级结构继承是面向对象语言个重要成分继承使得对象形成个分层次对象结构低层次对象可以将它不处理消息发送到高层对象上进行缺省处理由于在C中不能(或说很难)建立对象这种等级结构但为了简化应用设计又必须要求支持消息缺省处理(否则应用要定义个窗口对象可能接收到所有消息处理代码)因此只能使用DefWindowProc提供消息缺省处理这就要求对个窗口对象所有消息处理定义在就带来了定义窗口返回值和参数类型时使用了种较难为人理解思路方法区别消息可以带有区别类型和个数参数并且返回数据类型也不相同Windows设计者采用了个折中思路方法:为消息规定个十 6位参数和个32位参数将返回类型指定为LRESULT这种类型长度能容下C中所有预定义类型数据

  由于区别类窗口对象定义有自己窗口但C语言不具备根据接受消息对象自动决定该对象窗口能力(在面向对象语言中这种能力被称为多态性)因此向区别窗口对象发送消息时使用SendMessage对窗口作间接由Windows根据该中所使用对象标识符来该对象窗口

  在设计中由于窗口限制需经常进行各种各样数据类型转换例如:

  SendMessage(hwnd, WM_USER, (WPARAM)5, MAKELPARAM(89, 3267));

  在这个例子中为了组建个LPARAM类型数据使用了宏MAKEPARAM它将两个十 6位数据组装成个32位数据(低位字为MAKEPARAM个参数高位字为第 2个参数)当需要从个LPARAM类型数据中分离出低位字和高位字时使用宏LOWORD和HIWORD例如处理上个例子中所发送WM_USER消息窗口代码可能为:

  WORD wStart = LOWORD(lParam);

  WORD wStart = LOWORD(lParam);

  宏MAKELRESULT和MAKELPARAM类似它被用于装配LRESULT类型数据宏MAKELONG用于装配LONG类型数据当需要从LRESULT或LONG类型数据中分离出高位字和低位字时使用宏HIWORD和LOWORD

  基于上面介绍我们在设计Windows应用要明确中存在哪些对象对象的间是如何通过消息传递控制哪些数据是对所有对象公有 哪些数据是私有于某个对象公有数据和对象私有数据必须是存储在静态生存期变量中(局部生存期变量在窗口返回后就消失了不能在下次时保存上次换句话说存储对象数据变量生存期不应小于对象生存期)

  由于Windows应用各个模块的间主要是通过消息传递控制因此Windows应用逻辑结构就区别于MS-DOS应用逻辑结构如图1-1所示从图1-1可以看出Windows应用各个模块通过消息传递被联系在因此如果正确地组织模块性和结构较MS-DOS应用要好



  图1-1 DOS应用和Windows应用逻辑结构比较示意介绍说明

  Windows组织

  将1.9节介绍按照C/C语言要求组织起来就得到个完整Windows个Windows必须有个名为WinMain

  // 1-1.c 代码片段

  # <windows.h>

  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

   PASCAL WinMain(
    HINSTANCE hInstance,   // 应用例子句柄
    HINSTANCE hPrevInstance, // 该应用个例子句柄
    LPSTR lpszCmdLine,    // 命令行参数串
     nCmdShow)       // 化时如何显示窗口
  {
     char szAppName = "Window";
    HWND hwnd;
    MSG msg;
    WNDCLASS wnd;
     (!hPrevInstance) {
      // 该例子是个例子注册窗口类
      wnd.style = CS_VREDRAW | CS_HREDRAW;
      wnd.lpfnWndProc = WndProc;
      wnd.cbClsExtra = 0;
      wnd.cbWndExtra = 0;
      wnd.hInstance = hInstance;
      wnd.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
      wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
      wnd.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
      wnd.lpszMenuName = NULL;
      wnd.lpszClassName = szAppName;

       (!RegisterClass(&wnd))
        // 如果注册失败
         FALSE;
    }

    // 对每个例子创建个窗口对象
    hwnd = CreateWindow(
      szAppName,
      "Sample Program",
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&msg, NULL, 0, 0)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

     msg.wParam;
  }


  WinMain是Windows应用开始执行时入口点返回类型为WinMain作用十分类似于MS-DOS中C应用

  WinMain带有 4个参数参数hInstance和hPrevInstance是例子句柄在Windows环境下可以运行同多个拷贝个拷贝都是该应用个句柄每个例子使用个例子句柄进行标识hInstance是标识当前例子句柄值不会为NULL如果在此的前Windows中已经运行了该个例子则这个例子句柄由参数hPrevInstace给出如果在运行该Windows环境中不存在该个例子则hPrevInstance为NULL

  我们曾经说过对同个类不能向Windows注册次以上在这个通过判别hPrevInstance值是否为NULL来决定是否应向Windows注册窗口类这样逻辑保证了只在该个例子中注册窗口类

  参数lpszCmdLine中包含有运行时传递给命令行参数例如若以这样命令运行该Sample.exe Programming Windows则lpszCmdLine将指向串“Programming Windows”

  最后个参数nCmdShow是类型整数用以介绍说明在被装如内存时Windows以何种方式显示这个窗口根据运行方式区别该参数被设置为SW_SHOWNORMAL或SW_SHOWMINNOACTIVESW含义是“Show Window”(显示窗口)这两个参数含义在后面介绍

  在Sample.CPP中有几个我们未曾介绍表1-3给出了这些介绍说明

  表1-3-1 ShowWindow 用 途 显示或改变给定窗口
原 型 BOOL ShowWindow(  
  HWND hWnd, 指定个窗口对象
   nCmdShow 指定窗口显示方式
);  



返回值 返回该窗口更新前窗口状态对先前可见窗口其值为非零对先前隐藏窗口其值为零



  显示方式(nCmdShow)可以是下列常量的:

类型 介绍说明
SW_HIDE 隐藏该窗口(并是另个窗口激活)
SW_MINIMIZE 使窗口变成图标(并激活窗口管理表顶层窗口)
SW_SHOW 激活个窗口并根据其当前尺寸和位置显示该窗口
SW_SHOWMAXIMIZED 激活并以全屏方式显示个窗口
SW_SHOWMINIMIZED 激活并以图标方式显示个窗口
SW_SHOWMINNOACTIVE 以图标方式显示个窗口当前活动窗口仍保持活动
SW_SHOWNA 以当前状态显示个窗口当前活动窗口仍保持活动
SW_SHOWNOACTIVE 以最近大小和位置显示个窗口当前活动窗口仍保持活动
SW_SHOWNORMAL 激活并显示个窗口若其为图标或全屏方式显示则恢复为它原始大小和位置
SW_RESTORE 同SH_SHOWNORMAL



  表1-3-2 UpdateWindow 用 途 若应用消息队列中存在WM_PAINT消息(绘制用户区消息)则该使Windows立即窗口向其传递WM_PAINT否则该不作为任何动作
原 型 VOID UpdateWindow(  
  HWND hWnd, 标识被刷新窗口句柄
);  



返回值 无



  表1-3-3 GetMessage 用 途 从应用消息队列中检索条消息
原 型 BOOL GetMessage(  
  LPMSG lpMsg, 指向MSG类型变量远指针它包含有从应用消息队列中检索到条消息数据
  HWND hWnd, 指定为哪个窗口检索消息如果hWnd为NULL则检索应用所有消息(不检索属于其它应用消息)
  UINT wMin,  
  UINT wMax 以下两个基本参数指定检索在wMin和wMax范围内消息如果这两个参数都为零检索所有可用消息
);  



返回值 在检索出WM_QUIT消息时返回零值在其它情况下返回非零值



  表1-3-4 DispatchMessage 用 途 将消息发送到指定窗口对象上(窗口)
原 型 LRESULT DispatchMessage(  
  LPCMSG lpMsg 指向MSG类型变量远指针该变量中存储有来自应用消息队列中消息
);  



返回值 若有个WM_CHAR消息被放到应用消息队列中返回非零否则返回零不改变lpMsg所指向变量中存储消息数据



  Windows都是首先以化(注册类、创建对象等)这步开始而且紧跟着就是消息循环运行这这些步骤对所有Windows应用都大同小异Windows应用主要区别点在窗口定义上由于个应用所解决任务区别窗口对消息处理方式也就不相同因而每个应用需要定义区别窗口

  LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    switch (message)
    {
       WM_DESTROY:
        PostQuitMessage(0):
                0;
    }
     DefWindowProc(hwnd, message, wParam, lParam);
  }


  这个窗口仅处理条WM_DESTROY消息这条消息是在用户关闭了屏幕上窗口时Windows发送给窗口对象对这条消息处理只是简单地WindowsPostQuitMessage表1-4给出了PostQuitMessage介绍说明当主消息循环中GetMessage检索出WM_QUIT消息时GetMessage返回零这样消息循环终止也随的被终止存储消息数据变量msgwParam域值是在PostQuitMessage时所提供实参如果正常结束PostQuitMessage时使用零作为该参数如果需要表示由于出现了异常或而必须终止时使用非零值(般使用-1)作为该参数PostQuitMessage使用参数值被主用语句:

   msg.wParam;

  返回给Windows供Windows或其它应用使用因此我们也称PostQuitMessage使用参数为退出码

  表1-4 PostQuitMessage 用 途 通知Windows应用希望中止般用于响应WM_DESTROY消息将消息WM_QUIT消息放入应用消息队列中
原 型 PostQuitMessage(  
   nExitCode 指定应用退出代码它用作WM_QUIT消息wParam参数
);  



返回值 无



  小结

  首先介绍了图形用户界面优点和面向对象设计思路方法从某种意义上说Windows是面向对象它主要建立在把窗口作为个对象概念上窗口的间通过消息进行消息传递

  Windows支持直接操作技术直接操作是对屏幕对象操作数据和封装允许该对象自己响应它们接收到消息在用户界面上发生任何事件被作为消息发送给窗口对象员在设计只须关心个对象要接受哪些消息和怎样处理这些消息消息传递工作由Windows负责因而使用Windows操作环境可以极大地方便开发用户界面工作并使结构合理、模块化更重要支持直接操作技术Windows支持用户进行有创造性界面设计



Tags:  windows程序设计 windows编程实例 windowsxp应用程序 windows应用程序

延伸阅读

最新评论

发表评论