• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Leo

            <2007年5月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            統(tǒng)計(jì)

            • 隨筆 - 2
            • 文章 - 0
            • 評(píng)論 - 2
            • 引用 - 0

            常用鏈接

            留言簿(1)

            隨筆檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            如何讓API回調(diào)你的VC類成員函數(shù)而不是靜態(tài)函數(shù)
             

            只要在函數(shù)聲明前加static就好了,哈哈哈哈哈~~~~~  

            。。。開個(gè)玩笑。以前確實(shí)大家都是這樣做的,在靜態(tài)的成員函數(shù)中再查找this指針,它多半是全局變量,或者是回調(diào)函數(shù)提供的附加參數(shù)。如果是前者,就會(huì)大大破壞程序的結(jié)構(gòu)。而現(xiàn)在,隨著社會(huì)生產(chǎn)力的發(fā)展,偶們已經(jīng)能做到將成員函數(shù)映射成為一個(gè)臨時(shí)的靜態(tài)函數(shù)了。本文就來(lái)演示一下這種實(shí)現(xiàn)方式。

            首先需要包含一個(gè)由yzwykkldczsh同志編寫的模板類-----萬(wàn)能多用自適應(yīng)無(wú)限制回調(diào)模板(為紀(jì)念友人fishskin,此模板又稱為H>W模板) 

            /**************************************************************************
             *   ACCallback.h
             *   Helper class of Member function callback mechanism
             **************************************************************************/
            #include "stdafx.h"
            #include "windows.h"

            #pragma pack(push, 1)
            struct _ACCallbackOpCodes
            {
             unsigned char tag;  // CALL e8
             LONG_PTR offset;  // offset (dest - src - 5, 5=sizeof(tag + offset))
             LONG_PTR _this;   // a this pointer
             LONG_PTR _func;   // pointer to real member function address
            };
            #pragma pack(pop)

            static __declspec( naked ) int STDACJMPProc()
            {
             _asm
             {
              POP ECX 
              MOV EAX, DWORD PTR [ECX + 4] // func
              MOV ECX, [ECX]     // this  
              JMP EAX
             }
            }

            static LONG_PTR CalcJmpOffset(LONG_PTR Src, LONG_PTR Dest)
            {
             return Dest - (Src + 5);
            }

            /*
             * NOTE: _TPStdFunc: a type of function pointer to API or Callbacks, *MUST* be _stdcall
                     _TPMemberFunc: a type of function pointer to class member function,
                     *MUST* be the *DEFAULT* calling conversation, *NO* prefix should be added,
                      that is, using ECX for "this" pointer, pushing parameters from right to left,
                      and the callee cleans the stack.
                      _TClass: the class who owns the callback function. The caller should only own the _stdcall function pointer
               LIFE TIME:  It is important to keep the ACCallback object alive until the CALLBACK is not required!!!
             */
            template<typename _TPStdFunc, class _TClass, typename _TPMemberFunc>
            class ACCallback
            {
            public:
             _TClass *m_pThis;
             _TPMemberFunc m_pFunc;

            private:
             _TPStdFunc m_pStdFunc;

             void MakeCode()
             {
              if (m_pStdFunc) ::VirtualFree(m_pStdFunc, 0, MEM_RELEASE);
              m_pStdFunc = (_TPStdFunc)::VirtualAlloc(NULL, sizeof(_ACCallbackOpCodes), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
              _ACCallbackOpCodes *p = (_ACCallbackOpCodes *)m_pStdFunc;
              p->_func = *(LONG_PTR *)&m_pFunc;
              p->_this = (LONG_PTR)m_pThis;
              p->tag = 0xE8;
              p->offset = CalcJmpOffset((LONG_PTR)p, (LONG_PTR)STDACJMPProc);
             }

            public:
             ACCallback<_TPStdFunc, _TClass, _TPMemberFunc>()
             {
             }
             ACCallback<_TPStdFunc, _TClass, _TPMemberFunc>(_TClass* pThis,
              _TPMemberFunc pFunc
              )
             {
              m_pFunc = pFunc;
              m_pThis = pThis;
              m_pStdFunc = NULL;
              MakeCode();
             }
             void Assign(_TClass* pThis,
              _TPMemberFunc pFunc
              )
             {
              m_pFunc = pFunc;
              m_pThis = pThis;
              m_pStdFunc = NULL;
              MakeCode();
             }
             ~ACCallback<_TPStdFunc, _TClass, _TPMemberFunc>()
             {
              ::VirtualFree(m_pStdFunc, 0, MEM_RELEASE);
             }
             operator _TPStdFunc()
             {
              return m_pStdFunc;
             }
            };

            /********************************** EXAMPLE **********************************
            class CClass1
            {
            public:
             TCHAR m_Buf[255];
             BOOL EnumWindowProc(HWND hwnd, LPARAM lp)
             {
              GetWindowText(hwnd, m_Buf, 255);
              printf("Enum window=%s\n", m_Buf);
              return TRUE;
             }
             typedef BOOL (CClass1::*CLASSWNDENUMPROC)(HWND, LPARAM);
            };

            TO USE:
             CClass1 c1;
             ACCallback<WNDENUMPROC, CClass1, CClass1::CLASSWNDENUMPROC> cb(&c1, &CClass1::EnumWindowProc);
             EnumWindows(cb, 0);

            ************************* END OF EXAMPLE *********************************/

            模板的三個(gè)參數(shù)分別是:API函數(shù)指針的類型,類名字,類成員函數(shù)指針的類型(兩種函數(shù)指針在參數(shù)和返回值上應(yīng)該一樣,只是前者聲明為_stdcall,后者不加任何調(diào)用修飾,即默認(rèn)的__thiscall方式)
            該項(xiàng)頭文件的注釋中給了一個(gè)調(diào)用API函數(shù)EnumWindows的例子。現(xiàn)在偶們來(lái)試試調(diào)用SetTimer。

            class CTestCallback
            {
            private:
             /* A callback of SetTimer, mirrored into member OnTimer */
             typedef void (CTestCallback::*CLASSTIMERPROC)(HWND, UINT, UINT_PTR, DWORD);
             void OnTimer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
             ACCallback<TIMERPROC, CTestCallback, CLASSTIMERPROC> m_DOnTimer;
            }

            調(diào)用時(shí),只要這樣寫:
            /* 初始化回調(diào)結(jié)構(gòu) */
            m_DOnTimer.Assign(this, &CTestCallback::OnTimer);
            m_uid = ::SetTimer( NULL, 0, 1000, m_DOnTimer);

            最后記得在CTestCallback的析構(gòu)函數(shù)中KillTimer。由于m_DOnTimer會(huì)實(shí)現(xiàn)轉(zhuǎn)化到靜態(tài)函數(shù)指針類型的操作符,所以調(diào)用的地方只要直接寫回調(diào)結(jié)構(gòu)的名字就可以了。

            使用該模板需要注意兩點(diǎn):
            1.API函數(shù)應(yīng)當(dāng)是_stdcall類型的(這一點(diǎn)絕大部分API都滿足)。類成員函數(shù)必須是默認(rèn)的調(diào)用方式,不要加_stdcall或_cdecl之類的修飾。此方式的重要條件就在于_stdcall和__thiscall之間只相差了一個(gè)ECX指出的this指針,所以我們才能實(shí)現(xiàn)這種映射(這種方式在VCL和ATL的窗口類中都有使用到);
            2.回調(diào)結(jié)構(gòu)的生存周期應(yīng)當(dāng)是在整個(gè)回調(diào)函數(shù)有效的時(shí)間內(nèi)。因此,對(duì)于EnumWindows這樣的函數(shù),只要聲明在棧上就可以了;但對(duì)于SetTimer,就必須定義為類成員變量,同時(shí),在類的析構(gòu)函數(shù)中必須及時(shí)銷毀這個(gè)timer。

            posted on 2007-05-16 13:32 LeoChen 閱讀(1769) 評(píng)論(2)  編輯 收藏 引用

            評(píng)論

            # re: 如何讓API回調(diào)你的VC類成員函數(shù)而不是靜態(tài)函數(shù) [未登錄] 2007-05-16 15:57 walkspeed

            有些意識(shí)。
            特別是那個(gè)_ACCallbackOpCodes結(jié)構(gòu)。他將m_pStdFunc存儲(chǔ)空間中的頭部分的數(shù)據(jù)修改了。用的就是_ACCallbackOpCodes結(jié)構(gòu)。不知這個(gè)結(jié)構(gòu)的具體含義。然道函數(shù)指針空間中存儲(chǔ)了寫信息。呵呵。

            還有那個(gè)匯編代碼。然道類的函數(shù)調(diào)用的匯編代碼及時(shí)這個(gè)樣的。學(xué)習(xí)。

            # re: 如何讓API回調(diào)你的VC類成員函數(shù)而不是靜態(tài)函數(shù)  2007-05-16 16:35 空明流轉(zhuǎn)

            這個(gè)寫法很早就有人提了.但是編譯器相關(guān)實(shí)在太大,換個(gè)編譯器就不太一樣了.所以不敢用.
            比較好的方法還是使用functor或者干脆使用COMMAND模式才是C++的上選.

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            欧美一区二区久久精品| 国产亚洲成人久久| 久久久国产乱子伦精品作者| 亚洲中文字幕无码一久久区| 成人免费网站久久久| 久久99精品国产麻豆婷婷| 一日本道伊人久久综合影| 欧美黑人激情性久久| 久久av免费天堂小草播放| 亚洲狠狠婷婷综合久久蜜芽| 99久久精品无码一区二区毛片 | 久久婷婷国产剧情内射白浆| 超级碰碰碰碰97久久久久| av无码久久久久不卡免费网站| 国产三级精品久久| 精品久久久久久无码专区| 久久久久亚洲av综合波多野结衣| 四虎国产永久免费久久| 久久成人国产精品| 亚洲国产天堂久久久久久| 99久久中文字幕| 久久久久久久久波多野高潮| 久久久久国产| 久久久久久国产精品无码下载| 亚洲愉拍99热成人精品热久久 | 久久国产视频网| 青青国产成人久久91网| 久久久久女人精品毛片| 亚洲综合精品香蕉久久网| 久久人人添人人爽添人人片牛牛| 成人a毛片久久免费播放| 999久久久免费国产精品播放| 久久99国产综合精品女同| 人妻无码久久一区二区三区免费| 色妞色综合久久夜夜| 三级三级久久三级久久| 久久精品国产久精国产果冻传媒| 亚洲国产成人久久笫一页| 久久亚洲国产成人影院| 精品综合久久久久久98| 亚洲av伊人久久综合密臀性色|