• <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

            <2025年8月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            統(tǒng)計(jì)

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

            常用鏈接

            留言簿(1)

            隨筆檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

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

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

            。。。開(kāi)個(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同志編寫(xiě)的模板類(lèi)-----萬(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ù)指針的類(lèi)型,類(lèi)名字,類(lèi)成員函數(shù)指針的類(lèi)型(兩種函數(shù)指針在參數(shù)和返回值上應(yīng)該一樣,只是前者聲明為_(kāi)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í),只要這樣寫(xiě):
            /* 初始化回調(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ù)指針類(lèi)型的操作符,所以調(diào)用的地方只要直接寫(xiě)回調(diào)結(jié)構(gòu)的名字就可以了。

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

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

            評(píng)論

            # re: 如何讓API回調(diào)你的VC類(lèi)成員函數(shù)而不是靜態(tài)函數(shù) [未登錄](méi) 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ǔ)了寫(xiě)信息。呵呵。

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

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

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

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


            久久精品麻豆日日躁夜夜躁| 国产亚洲欧美精品久久久| 久久亚洲国产成人影院| 久久精品aⅴ无码中文字字幕不卡| 久久精品无码专区免费青青 | 亚洲精品第一综合99久久| 亚洲国产精品无码久久九九| 无码日韩人妻精品久久蜜桃 | 久久久久亚洲av无码专区导航| 久久se精品一区二区| 中文字幕无码精品亚洲资源网久久| 99久久精品免费国产大片| 中文字幕久久久久人妻| 久久精品视屏| 亚洲成色999久久网站| 日本强好片久久久久久AAA| 色99久久久久高潮综合影院| 久久精品国产69国产精品亚洲| 精品人妻伦九区久久AAA片69| 久久综合五月丁香久久激情| 国产L精品国产亚洲区久久| 九九久久自然熟的香蕉图片| 青青草原综合久久大伊人| 久久天天躁狠狠躁夜夜av浪潮| 亚洲国产天堂久久综合网站| 国产亚洲婷婷香蕉久久精品| 色88久久久久高潮综合影院| 狠狠色噜噜色狠狠狠综合久久| 伊人久久大香线蕉AV一区二区 | 久久天天躁狠狠躁夜夜2020一| 久久综合亚洲色HEZYO国产| 青青热久久综合网伊人| 亚洲综合精品香蕉久久网97| 精品久久久久久亚洲| 色综合合久久天天综合绕视看| 91精品国产高清久久久久久国产嫩草 | 国产精品成人无码久久久久久 | 久久99精品久久久久久hb无码| 久久久久久久久无码精品亚洲日韩 | 久久香蕉综合色一综合色88| 国产精品免费看久久久香蕉|