SOUI官方论坛

 找回密码
 立即注册
查看: 221|回复: 2

SOUI中,如何从HWND转换为SHostWnd*?

[复制链接]
  • TA的每日心情
    奋斗
    2022-7-4 09:45
  • 签到天数: 28 天

    [LV.4]偶尔看看III

    59

    主题

    590

    帖子

    5515

    积分

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    5515

    突出贡献优秀版主

    发表于 2022-9-9 14:35:25 | 显示全部楼层 |阅读模式
    在SOUI中,所有界面最基本的类型就是SHostWnd对象。如果我们获取到一人SHostWnd的hwnd值,如何将它转换成SHostWnd*?
    SOUI使用了thunk技术, 在窗口关联的WindowProc数据中保存有this指针,可以参考下面代码:
    [C++] 纯文本查看 复制代码
    LRESULT CALLBACK SNativeWnd::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        SNativeWnd *pThis = (SNativeWnd *)SNativeWndHelper::getSingletonPtr()->GetSharePtr();
    
        pThis->m_hWnd = hWnd;
        // 初始化Thunk,做了两件事:1、mov指令替换hWnd为对象指针,2、jump指令跳转到WindowProc
        pThis->m_pThunk->Init((DWORD_PTR)WindowProc, pThis);
    
        // 得到Thunk指针
        WNDPROC pProc = (WNDPROC)pThis->m_pThunk->GetCodeAddress();
        // 调用下面的语句后,以后消息来了,都由pProc处理
        ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);
    
        return pProc(hWnd, uMsg, wParam, lParam);
    }
    

    从上面代码可以发现,GWLP_WNDPROC保存了和pThis相关的thunk对象地址。
    查看GetCodeAddress的代码可以发现,它实际上就是pThis->m_pThunk的地址。
    因此可以通过GWLP_WNDPROC获取到与该hwnd对应的m_pThunk值。
    由于pThis在pThis->m_pThunk->Init((DWORD_PTR)WindowProc, pThis)中被保存到了tagThunk的m_this数据中,因此获取到pThis->m_pThunk即可以获取到pThis的值。参考下面x86的tagThunk的代码。
    [C++] 纯文本查看 复制代码
    #pragma pack(push, 1)
    struct tagThunk
    {
        DWORD m_mov; // 4个字节
        DWORD m_this;
        BYTE m_jmp;
        DWORD m_relproc;
        //关键代码   //////////////////////////////////////
        void Init(DWORD_PTR proc, void *pThis)
        {
            m_mov = 0x042444C7;
            m_this = (DWORD)(
                ULONG_PTR)pThis; // mov [esp+4], pThis;而esp+4本来是放hWnd,现在被偷着放对象指针了.
            m_jmp = 0xe9;
            // 跳转到proc指定的入口函数
            m_relproc = (DWORD)((INT_PTR)proc - ((INT_PTR)this + sizeof(tagThunk)));
            // 告诉CPU把以上四条语句不当数据,当指令,接下来用GetCodeAddress获得的指针就会运行此指令
            FlushInstructionCache(GetCurrentProcess(), this, sizeof(tagThunk));
        }
        void *GetCodeAddress()
        {
            return this; // 指向this,那么由GetCodeAddress获得的函数pProc是从DWORD m_mov;开始执行的
        }
    };


    因此通过HWND要获取SHostWnd*,可以使用下面代码:
    [C++] 纯文本查看 复制代码
    #pragma pack(push, 1)
    SHostWnd * Hwnd2HostWnd(HWND hWnd){
            WNDPROC proc = (WNDPROC)::GetWindowLongPtr(m_hWnd,GWL_WNDPROC);
            tagThunk *thunk = (tagThunk*)proc;
    #if defined(_M_IX86)
            SNativeWnd *pThis=(SNativeWnd *)thunk->m_this;
    #elif defined(_M_AMD64)
            SNativeWnd *pThis=(SNativeWnd *)thunk->RcxImm;
    #else
           return NULL;
    #endif
            SHostWnd *pHostWnd =(SHostWnd*)pThis;
            return pHostWnd;
    }
    



  • TA的每日心情
    开心
    前天 22:51
  • 签到天数: 946 天

    [LV.10]以坛为家III

    581

    主题

    1343

    帖子

    2万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    28876
    发表于 2022-9-14 19:20:25 | 显示全部楼层
    谢谢楼主分享
  • TA的每日心情
    奋斗
    2024-3-15 15:43
  • 签到天数: 104 天

    [LV.6]常住居民II

    5

    主题

    47

    帖子

    950

    积分

    04:00化神期

    Rank: 4

    积分
    950
    发表于 2023-2-1 17:08:06 | 显示全部楼层
    谢谢分享,学习了
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|SOUI官方论坛

    GMT+8, 2024-5-18 14:17

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表