科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件ATL布幔下的秘密之窗口类的秘密

ATL布幔下的秘密之窗口类的秘密

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

很多人认为ATL只是用来编写COM组件的,其实你也可以使用ATL中的窗口类来创建基于窗口的应用程序 .

作者:李马编译 来源:VCKBASE 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
下面是一个完整的程序,它示范了在派生类中WM_PAINT消息的使用。

  程序70.

#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)
  {
   m_hWnd = ::CreateWindowEx(dwExStyle, szClassName, szTitle, dwStyle,
CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, 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 OnCreate(WPARAM wParam, LPARAM lParam)
  {
   return 0;
  } 

  static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  {
   ZWindow* pThis = g_pWnd;

   switch (uMsg)
   {
    case WM_CREATE:
     pThis->OnCreate(wParam, lParam);
     break;

    case WM_PAINT:
     pThis->OnPaint(wParam, lParam);
     break;

    case WM_DESTROY:
     ::PostQuitMessage(0);
     break;
   }
  return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
 }
};

class ZDriveWindow : 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, "Hello world From Drive", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
   EndPaint(&ps);

   return 0;
  }
};

  程序的输出是一个窗口中的一条“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应该和相应的派生类关联起来,所以消息应该发送给正确的窗口。解决这个问题可以有若干种方法,让我们来一个一个看一看。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章