• <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 閱讀(1774) 評(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   博問(wèn)   Chat2DB   管理


            Xx性欧美肥妇精品久久久久久| 国产成人精品久久亚洲| 99热都是精品久久久久久| 久久综合欧美成人| 久久久久亚洲AV成人网人人网站| 久久99精品国产麻豆宅宅| 国产精品美女久久久免费| 青青久久精品国产免费看 | 亚洲AV无码久久精品色欲| 久久久久99精品成人片欧美| 香蕉久久久久久狠狠色| 国产成人综合久久精品尤物| 伊人久久大香线蕉综合网站| 国产高清美女一级a毛片久久w| 九九精品久久久久久噜噜| 久久99国产精品久久99小说| 情人伊人久久综合亚洲| 久久WWW免费人成一看片| 久久99精品久久久久久秒播| 久久精品国产第一区二区| 亚洲国产精品久久66| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 精品无码人妻久久久久久| 久久午夜羞羞影院免费观看| 久久午夜无码鲁丝片秋霞| 大香网伊人久久综合网2020| 久久精品国产清高在天天线| 久久久久久精品无码人妻| 久久国内免费视频| 欧美激情精品久久久久久| 国产免费久久久久久无码| 情人伊人久久综合亚洲| 91精品国产色综合久久| 秋霞久久国产精品电影院| 国产精品九九九久久九九| 国产精品视频久久| 亚洲国产精品久久久久| 久久精品国产秦先生| 欧美一区二区久久精品| 狠狠色丁香久久婷婷综合_中| 久久久噜噜噜久久中文字幕色伊伊|