初试Button封装

最开始实现时是用SetWindowLong中的GWL_USERDATA来传递Button对象的this指针,结果被老板狠批了一顿,在他的点拨下改用自定位代码,还好上次做Hook时就已经弄熟了这个东西,还是比较顺利搞了出来,经过一次修改得到下面的代码

 

void  Button::CreateButtonMsgProcCode()
{
    m_bmps 
= new ButtonMsgProcStruct;
    m_bmps
->NotifyPointer = NotifyObserver;
    m_bmps
->ThisPointer = (int)this;

    
char *start, *end;
    
    _asm
    
{
        mov        start, offset _StartCode;
        mov        end, offset _EndCode;    
    }


    
int code_size = end - start;    
    memcpy(m_bmps, start, code_size);
    
return;

_StartCode:
    _asm
    
{
        call     lable
lable:    pop     eax
        sub        eax,
5    

        mov     ecx,dword ptr [eax
+20//this
        mov        eax,[eax+24];   //NotifyObserver
        jmp        eax;
    }

_EndCode:
    
return;    
}

 

 其中m_bmps变量的定义如下:

 

typedef  void  (Button:: *  NOTIFYPOINTER)(HWND, UINT, WPARAM, LPARAM) ;

struct  ButtonMsgProcStruct
{
    
char Instruct[20];
    
int ThisPointer;
    NOTIFYPOINTER NotifyPointer;
}
;

 

Button在创建时调用CreateWindow函数  然后调用SetWindowLong修改Button默认的窗口处理函数 

这个时候就是把这块自定位代码作为ButtonMsgProc传入其中 供Windows系统回调

 

void  Button::ShowWindow()
{
    m_hwndButton 
=  CreateWindow(m_lpClassName, m_lpWindowName, m_dwStyle,  m_x, m_y, m_nWidth, m_nHeight, m_hWndParent, m_hMenu, m_hInstance, m_lpParam);

                     CreateButtonMsgProcCode();   
// 该方法调用后 将创建出自定位代码 以传给下面的函数
                     m_OldMsgProc  =  (WNDPROC)SetWindowLong(m_hwndButton, GWL_WNDPROC, (LONG)m_bmps);
    
}

 

当Button上产生消息时 系统首先就回调我们的消息处理函数 在这里就是我们这片自定位代码

在代码尾部 存放了对象的This指针和NotifyObserver函数的入口地址 所以我们把This放入ECX

然后再掉用NotifyObserver方法 为什么我们没有Call呢? 因为Windows回调的时候就将我们需要的参数压栈了

为了保持堆栈不发生变化 所以调用了JMP指令 如果我们使用call的话 就会压入返回地址

这样就不能直接使用Windows为我们压栈的参数了 而不得不自己在call之前压一次

所以为了提高效率 直接JMP

下面是NotifyObserver的代码:

 

void  Button::NotifyObserver(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    
if  (ObserverContainer.find(message)  !=  ObserverContainer.end())
    {
        Observer
*  o  =  ObserverContainer[message];
        o
-> Action();
    }
    CallWindowProc(m_OldMsgProc, hwnd, message, wParam, lParam);
}

 

在这里我是将挂接的消息和消息处理函数做了一个mapping

所以我先去ObserverContainer里面查找这个消息是否被挂接了 如果不存在 则表示不需要处理这个消息

如果找到则表示需要处理 我们取出Observer的对象指针 它上面有一个虚方法叫Action 直接调用即可

下面再把Observer的注册代码贴出来:

 

void  Button::RegisterMsgProc(UINT msg, Observer *  o)
{
    ObserverContainer[msg] 
=  o;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值