加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

Windows API一日一练 21 SetWindowLongPtr和GetWindowLongPtr函

发布时间:2020-12-14 02:34:32 所属栏目:Windows 来源:网络整理
导读:在软件开发里,大家一直对着这个问题是执着的,那是“复用”。总想自己写出来的代码,可以适应性很强,到那里都可以落地生根。因此,面向对象的语言就层出不穷,每个都坚称可以最大地复用代码。在面向对象里, C ++是非常强大的。下面就来用 C ++把上面
在软件开发里,大家一直对着这个问题是执着的,那是“复用”。总想自己写出来的代码,可以适应性很强,到那里都可以落地生根。因此,面向对象的语言就层出不穷,每个都坚称可以最大地复用代码。在面向对象里, 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,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,CW_USEDEFAULT,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,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,strShow.c_str(),(int)strShow.length());
#051?
#052?????????????? //
#053?????????????? EndPaint(hWnd,&ps);
#054???????? }
#055???????? break;
#056??case WM_DESTROY:
#057???????? // 设置窗口类指针为空。
#058???????? SetWindowLongPtr(hWnd,NULL);
#059?
#060???????? PostQuitMessage(0);
#061???????? break;
#062??default:
#063???????? return DefWindowProc(hWnd,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 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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读