首页 | 互联网 | IT动态 | IT培训 | Cisco | Windows | Linux | Java | .Net | Oracle | 软件测试 | C/C++ | 嵌入式开发 | 存储世界 | 服务器
网络设备 | IDC | 安全 | 求职招聘 | 数字网校 | 网页设计 | 平面设计 | 技术专题 | 电子书下载 | 教学视频 | 源码下载 | 搜索 | 博客 | 论坛
ASP | ASP.NET | JSP | PHP | AJAX | XML | Java script | HTML/CSS | 服务器类
各大城市软件开发培训、软件人才免费咨询热线:400-700-5807
 您现在的位置: 中国IT实验室 >> WEB开发 >> WEB开发 >> 正文
ATL布幔下的秘密之窗口类的秘密(2)
ChinaItLab  2005-1-6  保存本文    收藏本站


  程序的输出是一个窗口中的一条“Hello world from Drive”消息。在我们使用派生类之前,可以说一切都是顺利的。当我们从ZWindow派生出多于一个类的时候,问题就会发生。这样,所有的消息就都会流向ZWindow最后继承的那个派生类。让我们看看以下的程序。
  
  程序71.
  
  #include <windows.h>
  
  class ZWindow;
  
  ZWindow* g_pWnd = NULL;
  
  class ZWindow
  {
   public:
  HWND m_hWnd;
  
  ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { }
  
  inline void Attach(HWND hWnd)
  { m_hWnd = hWnd; }
  
  inline BOOL ShowWindow(int nCmdShow)
  { return ::ShowWindow(m_hWnd, nCmdShow); }
  
  inline BOOL UpdateWindow()
  { return ::UpdateWindow(m_hWnd); }
  
  inline HDC BeginPaint(LPPAINTSTRUCT ps)
  { return ::BeginPaint(m_hWnd, ps); }
  
  inline BOOL EndPaint(LPPAINTSTRUCT ps)
  { return ::EndPaint(m_hWnd, ps); }
  
  inline BOOL GetClientRect(LPRECT rect)
  { return ::GetClientRect(m_hWnd, rect); }
  
  BOOL Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE hInstance,
  HWND hWndParent = 0, DWORD dwStyle = WS_OVERLAPPEDWINDOW,
  DWORD dwExStyle = 0, HMENU hMenu = 0, int x = CW_USEDEFAULT,
  int y = CW_USEDEFAULT, int nWidth = CW_USEDEFAULT,
  int nHeight = CW_USEDEFAULT)
   {
  m_hWnd = ::CreateWindowEx(dwExStyle, szClassName, szTitle, dwStyle,
  x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, NULL);
  return m_hWnd != NULL;
   }
  
   virtual LRESULT OnPaint(WPARAM wParam, LPARAM lParam)
   {
  HDC hDC;
  PAINTSTRUCT ps;
  RECT rect;
  
  hDC = BeginPaint(&ps);
  GetClientRect(&rect);
  ::DrawText(hDC, "Hello world", -1, &rect,
  DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  EndPaint(&ps);
  return 0;
   }
  
   virtual LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam)
   {
  return 0;
   }
  
   virtual LRESULT OnCreate(WPARAM wParam, LPARAM lParam)
   {
  return 0;
   }
  
   virtual LRESULT OnKeyDown(WPARAM wParam, LPARAM lParam)
   {
  return 0;
   }
  
   static LRESULT CALLBACK StartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   {
  ZWindow* pThis = g_pWnd;
  
  if (uMsg == WM_NCDESTROY)
   ::PostQuitMessage(0);
  
  switch (uMsg)
  {
   case WM_CREATE:
    pThis->OnCreate(wParam, lParam);
    break;
  
   case WM_PAINT:
    pThis->OnPaint(wParam, lParam);
    break;
  
   case WM_LBUTTONDOWN:
    pThis->OnLButtonDown(wParam, lParam);
    break;
  
   case WM_KEYDOWN:
    pThis->OnKeyDown(wParam, lParam);
    break;
  
   case WM_DESTROY:
    ::PostQuitMessage(0);
    break;
  }
  
  return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
   }
  };
  
  class ZDriveWindow1 : public ZWindow
  {
   public:
  LRESULT OnPaint(WPARAM wParam, LPARAM lParam)
  {
   HDC hDC;
   PAINTSTRUCT ps;
   RECT rect;
  
   hDC = BeginPaint(&ps);
   GetClientRect(&rect);
   ::SetBkMode(hDC, TRANSPARENT);
   ::DrawText(hDC, "ZDriveWindow1", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
   EndPaint(&ps);
  
   return 0;
  }
  
  LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam)
  {
   ::MessageBox(NULL, "ZDriveWindow1::OnLButtonDown", "Msg", MB_OK);
   return 0;
  }
   };
  
   class ZDriveWindow2 : public ZWindow
   {
  public:
   LRESULT OnPaint(WPARAM wParam, LPARAM lParam)
   {
    HDC hDC;
    PAINTSTRUCT ps;
    RECT rect;
  
    hDC = BeginPaint(&ps);
    GetClientRect(&rect);
    ::SetBkMode(hDC, TRANSPARENT);
    ::Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
    ::DrawText(hDC, "ZDriveWindow2", -1, &rect,
    DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    EndPaint(&ps);
  
    return 0;
   }
  
   LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam)
   {
    ::MessageBox(NULL, "ZDriveWindow2::OnLButtonDown", "Msg", MB_OK);
    return 0;
   }
  };
  
  int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpCmdLine, int nCmdShow)
  {
   char szAppName[] = "Hello world";
   MSG msg;
   WNDCLASS wnd;
   ZDriveWindow1 zwnd1;
   ZDriveWindow2 zwnd2;
  
   wnd.cbClsExtra = NULL;
   wnd.cbWndExtra = NULL;
   wnd.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
   wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
   wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
   wnd.hInstance = hInstance;
   wnd.lpfnWndProc = ZWindow::StartWndProc;
   wnd.lpszClassName = szAppName;
   wnd.lpszMenuName = NULL;
   wnd.style = CS_HREDRAW | CS_VREDRAW;
  
   if (!RegisterClass(&wnd))
   {
  MessageBox(NULL, "Can not register window class", "Error", MB_OK | MB_ICONINFORMATION);
  return -1;
   }
  
   g_pWnd = &zwnd1;
   zwnd1.Create(szAppName, "Hell world", hInstance);
  
   zwnd1.ShowWindow(nCmdShow);
   zwnd1.UpdateWindow();
  
   g_pWnd = &zwnd2;
  
   zwnd2.Create(szAppName, "Hello world", hInstance, zwnd1.m_hWnd, WS_VISIBLE | WS_CHILD | ES_MULTILINE, NULL, NULL, 0, 0, 150, 150);
  
   while (GetMessage(&msg, NULL, 0, 0))
   {
  DispatchMessage(&msg);
   }
   return msg.wParam;
  }
  
  程序的输出表明,不管你单击了哪个窗口,都会弹出相同的MessageBox。
   
  不管你单击了哪个窗口,你都会获得相同的消息框。这就意味着消息并没有传递给适当的窗口。事实上每个窗口都拥有自己的窗口过程,这些窗口过程处理窗口的所有消息。但是在这里,我们对第一个窗口使用了第二个窗口的回调函数,所以我们就不能对第一个窗口的消息进行处理了。
  
  现在,我们最主要的问题是将窗口的回调函数和相应的窗口关联起来。这就意味着HWND应该和相应的派生类关联起来,所以消息应该发送给正确的窗口。解决这个问题可以有若干种方法,让我们来一个一个看一看。
  
  首先我想出了一个最明显的解决方法,我们可以很容易地实现。方法是创建一个全局的结构,这个结构存储HWND和相应的派生类。但是,这个方法有两个主要的问题。第一,这个结构会在窗口逐渐加入程序的过程中越变越大;第二,在结构变得很大之后,在这个结构中进行搜索肯定也会花费大笔时间。
  
  而ATL的最主要目的就是使程序尽可能地小和快。并且,上述技术对于这两个标准都达不到。这个方法不单单是慢,还会在程序中包含大量窗口的情况下占用大量内存。
  
  另一个可能的解决方案是使用WNDCLASS或WNDCLASSEX结构的cbWndExtra域。还有一个问题是,为什么不用cbClsExtra,而要用cbWndExtra呢?答案很简单,cbClsExtra为每个窗口类存储额外的字节,而cbWndExtra为每个窗口存储额外的字节。并且,你可能会从一个窗口类创建多个窗口,这样,如果你使用了cbClsExtra的话,那么你就不能通过cbClsExtra区别不同的回调函数了,因为对于这些相同窗口类产生的窗口来说这个值是一样的。然后,将相应的派生类地址存储到cbWndExtra中。
  
  这个和方法看起来比第一个要好,但是它仍然有两个问题。第一,如果用户希望使用cbWndExtra,那么他/她就可能会覆盖着一技术所使用的数据,这样客户就需要在使用cbWndExtra的时候十分注意了,以防丢失信息。那么好了,你可以在文
中国IT教育热线咨询
相关文章
Flash+PHP+Mysql简单留言本制作实例教程
基础知识:Java Web三层架构的配置详解
使用AJAX技术构建更优秀的Web应用程序
ASP应用程序设计的Web状态管理分析
Ajax驱动的Web站点
最新文章
·Ajax光环背后的隐患
·Windows操作系统下JSP程序开发环
·如何在Java程序中实现FTP的上传下
·Java应用:编写高级JavaScript应
·初学者学习java第一步——JDK环境
 文章评论

 精彩友情推荐
·Asp源码 PHP源码
·CGI源码 JSP源码
·建站书籍教程
·服务器软件 .net源码
·建站工具软件
·IDC资讯大全
·机房品质万里行
·IDC托管必备知识
·全国IDC报价
·网站推广优化
ASP.NET ASP PHP JSP
·ASP.NET开发中的八个最佳实践09-21
·ASP.NET开发中的验证码技术09-18
·控件开发asp.net处理标签间内容09-18
·程序员成为成为编程高手的二十二条军规09-18
·VS 2005和ASP.NET 2.0中处理CSS样式表09-17
·如何有效监控.NET应用程序09-16
·浅析ASP.NET 2.0 Client Callback09-16
·探讨ASP.NETMVC框架内置AJAX支持编程技术09-15
·ASP.NET2.0的URL映射的实现方法09-13
·Java\.net\PHP比较 程序员眼中的.Net世界09-12
·asp.net中实现观察者设计模式09-12
·谈JSP与XML的交互09-01
·ASP连接11种数据库语法总结09-01
·如何利用ASP实现邮箱访问09-01
·ASP随机数的应用技术09-01
·定时使用DWRUtil.addRow生成表格08-27
·ASP申请单动态添加实现方法及代码08-27
·关于ASP中脚本执行顺序的讲解08-25
·ASP程序实现网页伪静态页源代码08-25
·ASP如何调用webservice08-22
·ASP实例:读取xml文件的程序08-14
·Asp组件检测函数08-11
·Linux系统下让PHP提高性能的工具APC05-06
·一个完整、安全的PHP用户登录系统11-14
·Apache+PHP+MySQL建立数据库驱动的动态网站08-24
·用SSH与PHP相连接 确保数据传输的安全性08-23
·PHP5手动最简安装方法08-03
·PHP程序加速探索之服务器负载测试07-11
·完全讲解PHP+MySQL的分页显示示例分析05-30
·用Suhosin加强PHP脚本语言安全性05-26
·初学入门 PHP 和 MySQL05-17
·传奇的诞生 PHP三位创始人简介05-10
·大型系统上PHP令人不爽的九大原因05-10
·JSTL中fn表达式的使用说明09-18
·JSP Web框架研究:Struts09-16
·JSF在GlassFish管理控制台中的应用09-12
·介绍JSP程序动态网站环境搭建的详细步骤09-12
·Jsp页面中文参数传递get和post方法分析09-12
·Java\.net\PHP比较 程序员眼中的.Net世界09-11
·JavaScript最常用的55个经典技巧09-08
·Windows操作系统下JSP程序开发环境配置09-03
·JSF点滴积累--权限验证09-03
·小小分页帮助程序08-29
·经验分享全过程JSP程序员完全蜕变手册08-27
  培训中心
人才交流中心 技术交流中心
  ITLab技术交流平台: