Windows API一日一练 21 SetWindowLongPtr和GetWindowLongPtr函数

在软件开发里,大家一直对着这个问题是执着的,那是“复用”。总想自己写出来的代码,可以适应性很强,到那里都可以落地生根。因此,面向对象的语言就层出不穷,每个都坚称可以最大地复用代码。在面向对象里, C ++是非常强大的。下面就来用 C ++把上面介绍的程序封装起来,这样可以复用,或者说条理更加清晰。
#001 
#002 int APIENTRY _tWinMain(HINSTANCE hInstance,
#003                       HINSTANCE hPrevInstance,
#004                       LPTSTR    lpCmdLine,
#005                       int       nCmdShow)
#006 {
#007  UNREFERENCED_PARAMETER(hPrevInstance);
#008  UNREFERENCED_PARAMETER(lpCmdLine);
#009 
#010  CCaiWin caiWin;
#011 
#012  caiWin.MyRegisterClass(hInstance);
#013  if (!caiWin.InitInstance(hInstance,nCmdShow))
#014  {
#015         return 0;
#016  }
#017 
#018  return caiWin.RunMessage();   
#019 }
 
这段代码跟前面介绍的调用,就是不一样了。
10 行创建了一个 CCaiWin 的对象 caiWin
12 行调用对象 CCaiWin 里的注册函数 MyRegisterClass 来注册一个窗口。
13 行就是初始化一个窗口的创建。
18 行就是调用对象 caiWin 的消息处理函数 RunMessage
 
这样就制定了一个基本应用的框架,可以任意修改对象里的内容,都不会影响这个函数里的调用,也就是说,只要不改那几个函数就可以永远不用修改 WinMain 函数里的内容了。
 
接着下来,再来看看类 CCaiWin 是怎么样编写的。它的类定义如下:
#001 #include <string>
#002 
#003 //
#004 // 封装一个窗口类。
#005 // 蔡军生  2007/07/27
#006 //
#007 class CCaiWin
#008 {
#009 public:
#010  CCaiWin(void);
#011  virtual ~CCaiWin(void);
#012 
#013  ATOM MyRegisterClass(HINSTANCE hInstance);
#014  bool InitInstance(HINSTANCE hInstance, int nCmdShow);  
#015  int RunMessage(void);
#016  HINSTANCE GetAppInstance(void)
#017   {
#018         return m_hInstance;
#019  }
#020 protected:
#021  static LRESULT CALLBACK WndProc(HWND hWnd,
#022         UINT message, WPARAM wParam, LPARAM lParam);
#023  static INT_PTR CALLBACK About(HWND hDlg,
#024         UINT message, WPARAM wParam, LPARAM lParam);
#025 protected:
#026  HINSTANCE m_hInstance;
#027  HWND m_hWnd;
#028 
#029  std::wstring m_strWindowClass;
#030  std::wstring m_strTitle;
#031 };
7 行定义类 CCaiWin
13 行是声明 MyRegisterClass 注册函数。
14 行是声明 InitInstance 初始化窗口函数。
15 行是声明 RunMessage 消息处理函数。
16 行是定义 GetAppInstance 函数获取应用程序句柄。
21 行是声明窗口的消息处理函数。它是静态成员函数,所以它有全局的地址,因此它是没有 this 指针的,不能直接地访问这个类里的成员变量。需要使用其它方法给它传递。
23 行是关于对话框的消息处理函数。
26 行是保存应用程序句柄。
27 行是保存主窗口的句柄。
29 行是保存注册窗口名称。
30 行是保存窗口显示的标题。
 
下面再来仔细地查看类的实现文件。
#001 //
#002 //   函数 : InitInstance(HINSTANCE, int)
#003 //
#004 //   目的 : 保存程序实例句柄,并创建窗口显示。
#005 //
#006 //   蔡军生  2007/07/27 QQ:9073204
#007 //
#008 bool CCaiWin::InitInstance(HINSTANCE hInstance, int nCmdShow)
#009 {
#010  //
#011   m_hInstance = hInstance;
#012 
#013   m_hWnd = CreateWindow(m_strWindowClass.c_str(), m_strTitle.c_str(),
#014         WS_OVERLAPPEDWINDOW,
#015         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
#016 
#017  if (!m_hWnd)
#018  {
#019         return false;
#020  }
#021 
#022  // 保存类的指针到窗口 GWL_USERDATA 字段,
#023  // 以便消息函数里可以获取类指针。
#024  SetWindowLongPtr(m_hWnd, GWL_USERDATA,(LONG)(LONG_PTR)this);
#025 
#026  ShowWindow(m_hWnd, nCmdShow);
#027  UpdateWindow(m_hWnd);
#028 
#029  return true;
#030 }
这里创建窗口,跟以前创建窗口,只有一个地方不一样,那就是在第 24 行里调用 SetWindowLongPtr 函数保存对象指针到窗口用户自定义数据里,这样做就是让后面的静态成员函数 WndProc 可以访问类成员。如下:
#001 //
#002 //  函数 : WndProc(HWND, UINT, WPARAM, LPARAM)
#003 //
#004 //  目的 处理主窗口的消息 .
#005 //
#006 //  蔡军生  2007/07/27   QQ:9073204
#007 //
#008 LRESULT CALLBACK CCaiWin::WndProc(HWND hWnd, UINT message,
#009                                             
#010 WPARAM wParam, LPARAM lParam)
#011 {
#012  // 获取窗口对应的类指针。
#013  LONG_PTR plptrWin = GetWindowLongPtr(hWnd,GWLP_USERDATA);
#014  if (plptrWin == NULL)
#015  {
#016        return DefWindowProc(hWnd, message, wParam, lParam);
#017  }
#018 
#019  //
#020  CCaiWin* pWin = reinterpret_cast<CCaiWin*>(plptrWin);
#021 
#022  int wmId, wmEvent;
#023  PAINTSTRUCT ps;
#024  HDC hdc;
#025 
#026  switch (message)
#027  {
#028  case WM_COMMAND:
#029         wmId    = LOWORD(wParam);
#030         wmEvent = HIWORD(wParam);
#031         // 菜单选项命令响应 :
#032         switch (wmId)
#033         {
#034         case IDM_ABOUT:
#035               DialogBox(pWin->GetAppInstance(), MAKEINTRESOURCE(IDD_ABOUTBOX),
#036                    hWnd, CCaiWin::About);
#037               break;
#038         case IDM_EXIT:
#039               DestroyWindow(hWnd);
#040               break;
#041         default:
#042               return DefWindowProc(hWnd, message, wParam, lParam);
#043         }
#044         break;
#045  case WM_PAINT:
#046         {
#047               hdc = BeginPaint(hWnd, &ps);
#048               //
#049               std::wstring strShow(_T("C++ 窗口类的实现 ,2007-07-27"));
#050               TextOut(hdc,10,10,strShow.c_str(),(int)strShow.length());
#051 
#052               //
#053               EndPaint(hWnd, &ps);
#054         }
#055         break;
#056  case WM_DESTROY:
#057         // 设置窗口类指针为空。
#058         SetWindowLongPtr(hWnd, GWL_USERDATA,NULL);
#059 
#060         PostQuitMessage(0);
#061         break;
#062  default:
#063         return DefWindowProc(hWnd, message, wParam, lParam);
#064  }
#065  return 0;
#066 }
上面第 13 行就是获取窗口里保存的类对象指针,然后再作类型转换为窗口 CCaiWin 的指针,这样就可以使用类的成员了,比如在第 35 行里的调用 pWin->GetAppInstance()
 
其实在封装静态成员函数这里,就有三种方法传递类指针,上面介绍这种是最简单的。一种是 MFC 里使用的,它是采用一个窗口和类指针映射数组来实现的。一种是 WTL 里使用叫做 THUNK 代码实现窗口与静态函数的关联。像上面这种方法,在游戏 Second Life 的源程序就使用它,如果是一般的应用程序,而不是大框架,使用这种简单的方法,就是最好的。
 
函数 GetWindowLongPtr SetWindowLongPtr 声明如下:
WINUSERAPI
LONG
WINAPI
GetWindowLongA(
    __in HWND hWnd,
    __in int nIndex);
WINUSERAPI
LONG
WINAPI
GetWindowLongW(
    __in HWND hWnd,
    __in int nIndex);
#ifdef UNICODE
#define GetWindowLong GetWindowLongW
#else
#define GetWindowLong GetWindowLongA
#endif // !UNICODE
 
WINUSERAPI
LONG
WINAPI
SetWindowLongA(
    __in HWND hWnd,
    __in int nIndex,
    __in LONG dwNewLong);
WINUSERAPI
LONG
WINAPI
SetWindowLongW(
    __in HWND hWnd,
    __in int nIndex,
    __in LONG dwNewLong);
 
#ifdef UNICODE
#define SetWindowLong SetWindowLongW
#else
#define SetWindowLong SetWindowLongA
#endif // !UNICODE
#define GetWindowLongPtrA   GetWindowLongA
#define GetWindowLongPtrW   GetWindowLongW
#ifdef UNICODE
#define GetWindowLongPtr GetWindowLongPtrW
#else
#define GetWindowLongPtr GetWindowLongPtrA
#endif // !UNICODE
 
#define SetWindowLongPtrA   SetWindowLongA
#define SetWindowLongPtrW   SetWindowLongW
#ifdef UNICODE
#define SetWindowLongPtr SetWindowLongPtrW
#else
#define SetWindowLongPtr SetWindowLongPtrA
#endif // !UNICODE
 
hWnd 是窗口句柄。
nIndex 是访问窗口对象数据的索引值。比如像 GWLP_USERDATA GWLP_WNDPROC
dwNewLong 是设置的新值。 

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自www.cnblogs.com/skiwnchh/p/10346662.html