`
阿尔萨斯
  • 浏览: 4137872 次
社区版块
存档分类
最新评论

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

 
阅读更多
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
在软件开发里,大家一直对着这个问题是执着的,那是“复用”。总想自己写出来的代码,可以适应性很强,到那里都可以落地生根。因此,面向对象的语言就层出不穷,每个都坚称可以最大地复用代码。在面向对象里,C++是非常强大的。下面就来用C++把上面介绍的程序封装起来,这样可以复用,或者说条理更加清晰。
#001
#002int APIENTRY _tWinMain(HINSTANCE hInstance,
#003 HINSTANCE hPrevInstance,
#004 LPTSTR lpCmdLine,
#005 int nCmdShow)
#006{
#007UNREFERENCED_PARAMETER(hPrevInstance);
#008UNREFERENCED_PARAMETER(lpCmdLine);
#009
#010CCaiWin caiWin;
#011
#012caiWin.MyRegisterClass(hInstance);
#013if (!caiWin.InitInstance(hInstance,nCmdShow))
#014{
#015 return 0;
#016}
#017
#018return caiWin.RunMessage();
#019}
这段代码跟前面介绍的调用,就是不一样了。
10行创建了一个CCaiWin的对象caiWin
12行调用对象CCaiWin里的注册函数MyRegisterClass来注册一个窗口。
13行就是初始化一个窗口的创建。
18行就是调用对象caiWin的消息处理函数RunMessage
这样就制定了一个基本应用的框架,可以任意修改对象里的内容,都不会影响这个函数里的调用,也就是说,只要不改那几个函数就可以永远不用修改WinMain函数里的内容了。
接着下来,再来看看类CCaiWin是怎么样编写的。它的类定义如下:
#001#include <string></string>
#002
#003//
#004//封装一个窗口类。
#005//蔡军生2007/07/27
#006//
#007class CCaiWin
#008{
#009public:
#010CCaiWin(void);
#011virtual ~CCaiWin(void);
#012
#013ATOM MyRegisterClass(HINSTANCE hInstance);
#014bool InitInstance(HINSTANCE hInstance, int nCmdShow);
#015int RunMessage(void);
#016HINSTANCE GetAppInstance(void)
#017 {
#018 return m_hInstance;
#019}
#020protected:
#021static LRESULT CALLBACK WndProc(HWND hWnd,
#022 UINT message, WPARAM wParam, LPARAM lParam);
#023static INT_PTR CALLBACK About(HWND hDlg,
#024 UINT message, WPARAM wParam, LPARAM lParam);
#025protected:
#026HINSTANCE m_hInstance;
#027HWND m_hWnd;
#028
#029std::wstring m_strWindowClass;
#030std::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//
#008bool 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
#017if (!m_hWnd)
#018{
#019 return false;
#020}
#021
#022//保存类的指针到窗口GWL_USERDATA字段,
#023//以便消息函数里可以获取类指针。
#024SetWindowLongPtr(m_hWnd, GWL_USERDATA,(LONG)(LONG_PTR)this);
#025
#026ShowWindow(m_hWnd, nCmdShow);
#027UpdateWindow(m_hWnd);
#028
#029return true;
#030}
这里创建窗口,跟以前创建窗口,只有一个地方不一样,那就是在第24行里调用SetWindowLongPtr函数保存对象指针到窗口用户自定义数据里,这样做就是让后面的静态成员函数WndProc可以访问类成员。如下:
#001//
#002//函数: WndProc(HWND, UINT, WPARAM, LPARAM)
#003//
#004//目的:处理主窗口的消息.
#005//
#006//蔡军生2007/07/27 QQ:9073204
#007//
#008LRESULT CALLBACK CCaiWin::WndProc(HWND hWnd, UINT message,
#009
#010WPARAM wParam, LPARAM lParam)
#011{
#012//获取窗口对应的类指针。
#013LONG_PTR plptrWin = GetWindowLongPtr(hWnd,GWLP_USERDATA);
#014if (plptrWin == NULL)
#015{
#016 return DefWindowProc(hWnd, message, wParam, lParam);
#017}
#018
#019//
#020CCaiWin* pWin = reinterpret_cast<ccaiwin>(plptrWin);</ccaiwin>
#021
#022int wmId, wmEvent;
#023PAINTSTRUCT ps;
#024HDC hdc;
#025
#026switch (message)
#027{
#028case 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;
#045case 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;
#056case WM_DESTROY:
#057 //设置窗口类指针为空。
#058 SetWindowLongPtr(hWnd, GWL_USERDATA,NULL);
#059
#060 PostQuitMessage(0);
#061 break;
#062default:
#063 return DefWindowProc(hWnd, message, wParam, lParam);
#064}
#065return 0;
#066}
上面第13行就是获取窗口里保存的类对象指针,然后再作类型转换为窗口CCaiWin的指针,这样就可以使用类的成员了,比如在第35行里的调用pWin->GetAppInstance()
其实在封装静态成员函数这里,就有三种方法传递类指针,上面介绍这种是最简单的。一种是MFC里使用的,它是采用一个窗口和类指针映射数组来实现的。一种是WTL里使用叫做THUNK代码实现窗口与静态函数的关联。像上面这种方法,在游戏Second Life的源程序就使用它,如果是一般的应用程序,而不是大框架,使用这种简单的方法,就是最好的。
函数GetWindowLongPtrSetWindowLongPtr声明如下:
WINUSERAPI
LONG
WINAPI
GetWindowLongA(
__in HWND hWnd,
__in int nIndex);
WINUSERAPI
LONG
WINAPI
GetWindowLongW(
__in HWND hWnd,
__in int nIndex);
#ifdef UNICODE
#define GetWindowLongGetWindowLongW
#else
#define GetWindowLongGetWindowLongA
#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 SetWindowLongSetWindowLongW
#else
#define SetWindowLongSetWindowLongA
#endif // !UNICODE
#define GetWindowLongPtrA GetWindowLongA
#define GetWindowLongPtrW GetWindowLongW
#ifdef UNICODE
#define GetWindowLongPtrGetWindowLongPtrW
#else
#define GetWindowLongPtrGetWindowLongPtrA
#endif // !UNICODE
#define SetWindowLongPtrA SetWindowLongA
#define SetWindowLongPtrW SetWindowLongW
#ifdef UNICODE
#define SetWindowLongPtrSetWindowLongPtrW
#else
#define SetWindowLongPtrSetWindowLongPtrA
#endif // !UNICODE
hWnd是窗口句柄。
nIndex是访问窗口对象数据的索引值。比如像GWLP_USERDATAGWLP_WNDPROC
dwNewLong是设置的新值。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics