Windows API一日一練(21)SetWindowLongPtr和GetWindowLongPtr函數

來源:互聯網
上載者:User
 在軟體開發裡,大家一直對著這個問題是執著的,那是“複用”。總想自己寫出來的代碼,可以適應性很強,到那裡都可以落地生根。因此,物件導向的語言就層出不窮,每個都堅稱可以最大地複用代碼。在物件導向裡,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是設定的新值。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.