青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-90  評論-947  文章-0  trackbacks-0

Timer這玩意兒很常用,卻又很煩人。煩人之處有四:

1.         如果將其設(shè)到HWND上,則

a)         必須手工維護TimerID,小心翼翼地保證這些ID不重復(fù),可能有人(比如我)就不怎么喜歡手工維護硬編碼的ID

b)         必須跟一個HWND關(guān)聯(lián),在沒有HWND的時候,或者HWND不方便用的時候,就麻煩了。比如前公司有個GUI系統(tǒng),是個類似HWND控件和DirectUI控件混合支持的系統(tǒng)(看上去很強大是不?),在HWND控件上使用SetTimer很方便,直接用原生的就行了,但如果在DirectUI控件上想要搞個Timer,就傻了。

2.         如果不將其設(shè)到HWND上,則

a)         ID倒是可以讓它生成,雖然我很喜歡,但不一定所有人喜歡,這與1.a兩者必居其一,無法兩全。

b)         回調(diào)函數(shù)又涉及成員化的問題,不然在一個對象化的系統(tǒng)里就很難寫。

就我個人而言,我喜歡2.a特性,因此著眼于解決2.b問題。

 

回調(diào)函數(shù)成員化,看著好像很眼熟。不錯,我們曾經(jīng)在《學(xué)習(xí)下WTLthunk》里面干過這事情。因此幾個月前我就覺得對于Timer也是可以做到的,但由于各種原因沒時間去弄,同時也很遺憾前公司“架構(gòu)師”沒有采用這種方案。

 

今天剛剛打眼到公司有人也做了這件事(1.a + 2.b 模式),趁目前還沒去很仔細地去研究,趕緊自己先寫一個差異化版本,以避免不必要的版權(quán)糾紛^_^

 

Thunk需要占用一個正常參數(shù)。我們觀察一下Timer的回調(diào)函數(shù)格式:

VOID CALLBACK TimerProc(

    _In_  HWND hWnd,

    _In_  UINT uMsg,

    _In_  UINT_PTR idEvent,

    _In_  DWORD dwTime

);

 

很不錯,前面三個參數(shù)幾乎都是沒用的(至少第一個是沒用的,這就夠了)。

 

先把原先為了WNDPROCThunk改得通用些,WNDPROC改成LPVOID或者模版化,所有出現(xiàn)“Wnd”的地方都去掉“Wnd”字樣,改完后變成:

http://xllib.codeplex.com/SourceControl/latest#SourceCode/xl/Win32/GUI/xlThunk.h

 

然后寫Timer的實現(xiàn)。代碼比較短,我先全貼了:

typedef Function<void (DWORD dwTime)> TimerCallback;

 

class Timer

{

public:

    Timer() : m_uTimerId(0)

    {

       

    }

 

    ~Timer()

    {

        Kill();

    }

 

public:

    bool Set(UINT uElapse, TimerCallback fnCallback)

    {

        if (m_uTimerId != 0)

        {

            return false;

        }

 

        m_fnCallback = fnCallback;

        m_thunk.SetObject(this);

        m_thunk.SetRealProc(StaticTimerProc);

 

        m_uTimerId = SetTimer(nullptr, 0, uElapse, m_thunk.GetThunkProc());

 

        if (m_uTimerId == 0)

        {

            return false;

        }

 

        return true;

    }

 

    void Kill()

    {

        if (m_uTimerId != 0)

        {

            KillTimer(nullptr, m_uTimerId);

            m_uTimerId = 0;

        }

    }

 

protected:

    static VOID CALLBACK StaticTimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)

    {

        return ((Timer *)hWnd)->m_fnCallback(dwTime);

    }

 

protected:

    UINT_PTR m_uTimerId;

    Thunk<TIMERPROC> m_thunk;

    TimerCallback m_fnCallback;

};

 

注意Timer::Set里面,設(shè)好Thunk的數(shù)據(jù)以后,直接把Timer創(chuàng)建在Thunk上就可以了,比起窗口那個處理干凈利落多了。咦?窗口里為什么要搞個StartProc,然后再在StartProc里把回調(diào)函數(shù)設(shè)到Thunk上呢?

 

是這樣的,注冊窗口類的時候就需要一個回調(diào)函數(shù),此時窗口未創(chuàng)建。CreateWindow的過程中,會調(diào)用到回調(diào)函數(shù)(WM_CREATE),如果沒有特殊處理,需要調(diào)用回DefWindowProc,其第一個參數(shù)是HWND,而我們此時如果使用Thunk的話,就會篡改掉系統(tǒng)調(diào)用回調(diào)函數(shù)時給出的HWND,從而沒法正確調(diào)用DefWindowProc。也就是說,如果第一次被調(diào)用需要使用第一個參數(shù)的,就需要像窗口的處理一樣,搞個StartProc第一次用。

 

這里我們使用SetTimer(NULL, ...),這第一個參數(shù)任何時候都不需要使用,所以可直接將Timer創(chuàng)建在Thunk上。

 

用例:

int main()

{

    xl::Timer t;

    t.Set(1000, [](DWORD dwTime)

        {

            printf("%u\n", dwTime);

        });

 

    MSG msg = {};

 

    while (GetMessage(&msg, nullptr, 0, 0))

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

 

    return 0;

}

 

運行結(jié)果:

clip_image001

 

源代碼見:

http://xllib.codeplex.com/SourceControl/latest#SourceCode/xl/Win32/Timer/xlTimer.h

 

流浪了近一個月,我又開始上班啦!

posted on 2013-06-25 00:18 溪流 閱讀(4921) 評論(6)  編輯 收藏 引用 所屬分類: C++Windows

評論:
# re: 將 Timer 對象化[未登錄] 2013-06-25 12:35 | cexer
其實可以徹底擺脫那個static,辦法就是在直接(或者使用JITAssembler)手動生成static的代碼,跟thunk替換棧上數(shù)據(jù)一樣的道理。只是這樣生成的代碼同時與編譯器和CPU綁定了,與編譯器綁定是因為各個編譯器生成的調(diào)用成員函數(shù)的方式可能不一樣。
  回復(fù)  更多評論
  
# re: 將 Timer 對象化[未登錄] 2013-06-25 12:37 | cexer
#include <iostream>
#include <string>
#include <windows.h>
#include <cstdio>
using namespace std;


template<class T, class S>
inline T union_cast( S s )
{
union
{
T t;
S s;
} u;
u.s = s;
return u.t;
}

#define __CODE1( a ) \
*(proc++) = a

#define __CODE2( a1, a2 ) \
*(proc++) = a1; \
*(proc++) = a2

#define __CODE3( a1, a2, a3 ) \
*(proc++) = a1; \
*(proc++) = a2; \
*(proc++) = a3

#define __CODE4( a1, a2, a3, a4 ) \
*(proc++) = a1; \
*(proc++) = a2; \
*(proc++) = a3; \
*(proc++) = a4

#define __CODE5( a1, a2, a3, a4, a5 ) \
*(proc++) = a1; \
*(proc++) = a2; \
*(proc++) = a3; \
*(proc++) = a4; \
*(proc++) = a5

#define __CODE6( a1, a2, a3, a4, a5, a6 ) \
*(proc++) = a1; \
*(proc++) = a2; \
*(proc++) = a3; \
*(proc++) = a4; \
*(proc++) = a5; \
*(proc++) = a6

#define __CODE( n, a ) __CODE##n a

#define __PTR( p ) \
{ \
*( (void**)proc ) = union_cast<void*>(p);\
proc += sizeof(void*); \
}

#define __CALL( p ) \
{ \
*(proc++) = 0xE8; \
unsigned char* pfunc = union_cast<unsigned char*>(p);\
*( (ptrdiff_t*)proc ) = pfunc - proc - 4; \
proc += 4; \
}  回復(fù)  更多評論
  
# re: 將 Timer 對象化[未登錄] 2013-06-25 12:38 | cexer
class CTest
{
public:
CTest()
: m_value( 0x12345678 )
{
build_proc();
}

public:
LRESULT CALLBACK member_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
{
printf( "hwnd:%d, msg:%d, wparam:%d, lparam:%d\n", (int)hwnd, (int)msg, (int)wparam, (int)lparam );
printf( "CTest::value: 0x%x\n", m_value );
return 0;
}

void build_proc()
{
unsigned char* proc = m_proc;
///////////////////////// Prolog.
__CODE( 1, ( 0x55 ) ); // 55 push ebp
__CODE( 2, ( 0x8B, 0xEC ) ); // 8B EC mov ebp,esp
__CODE( 6, ( 0x81, 0xEC, 0xC0, 0x00, 0x00, 0x00 ) ); // 81 EC C0 00 00 00 sub esp,0C0h
__CODE( 1, ( 0x53 ) ); // 53 push ebx
__CODE( 1, ( 0x56 ) ); // 56 push esi
__CODE( 1, ( 0x57 ) ); // 57 push edi
__CODE( 6, ( 0x8D, 0xBD, 0x40, 0xFF, 0xFF, 0xFF ) ); // 8D BD 40 FF FF FF lea edi,[ebp+FFFFFF40h]
__CODE( 5, ( 0xB9, 0x30, 0x00, 0x00, 0x00 ) ); // B9 30 00 00 00 mov ecx,30h
__CODE( 5, ( 0xB8, 0xCC, 0xCC, 0xCC, 0xCC ) ); // B8 CC CC CC CC mov eax,0CCCCCCCCh
__CODE( 2, ( 0xF3, 0xAB ) ); // F3 AB rep stos dword ptr es:[edi]

////////////////////// Codes
__CODE( 3, ( 0x8B, 0x45, 0x14 ) ); // 8B 45 14 mov eax,dword ptr [ebp+14h] [lparam]
__CODE( 1, ( 0x50 ) ); // 50 push eax
__CODE( 3, ( 0x8B, 0x45, 0x10 ) ); // 8B 45 10 mov eax,dword ptr [ebp+10h] [wparam]
__CODE( 1, ( 0x50 ) ); // 50 push eax
__CODE( 3, ( 0x8B, 0x55, 0x0C ) ); // 8B 55 0C mov edx,dword ptr [ebp+0Ch] [msg]
__CODE( 1, ( 0x52 ) ); // 52 push edx
__CODE( 3, ( 0x8B, 0x45, 0x08 ) ); // 8B 45 08 mov eax,dword ptr [ebp+8] [hwnd]
__CODE( 1, ( 0x50 ) ); // 50 push eax
__CODE( 1, ( 0xB9 ) ); __PTR( this ); // B9 ?? ?? ?? ?? mov ecx, this
__CODE( 1, ( 0x51 ) ); // 51 push ecx
__CALL( &CTest::member_proc ); // E8 ?? ?? ?? ?? call CTest::member_proc

/////////////////////// Epilog.
__CODE( 1, ( 0x5F ) ); // 5F pop edi
__CODE( 1, ( 0x5E ) ); // 5E pop esi
__CODE( 1, ( 0x5B ) ); // 5B pop ebx
__CODE( 6, ( 0x81, 0xC4, 0xC0, 0x00, 0x00, 0x00 ) ); // 81 C4 C0 00 00 00 add esp,0C0h
__CODE( 2, ( 0x8B, 0xE5 ) ); // 8B E5 mov esp,ebp
__CODE( 1, ( 0x5D ) ); // 5D pop ebp
__CODE( 3, ( 0xC2, 0x10, 0x00 ) ); // C2 10 00 ret 10h

DWORD old = 0;
VirtualProtect( &m_proc, sizeof(m_proc), PAGE_EXECUTE_READWRITE, &old );
}

WNDPROC get_proc()
{
return (WNDPROC)(void*)m_proc;
}

public:
char m_proc[1024];
int m_value;
};


int main( int argc, char** argv )
{
CTest test;
WNDPROC proc = test.get_proc();
proc( (HWND)1, 2, 3, 4 );

return 0;
}  回復(fù)  更多評論
  
# re: 將 Timer 對象化 2013-06-25 13:37 | WXX
如果我說chromium的base庫的延遲任務(wù)更好呢??
  回復(fù)  更多評論
  
# re: 將 Timer 對象化 2013-06-25 21:10 | 溪流
@cexer
學(xué)習(xí)了  回復(fù)  更多評論
  
# re: 將 Timer 對象化 2013-06-25 21:10 | 溪流
@WXX
有更好的很正常。  回復(fù)  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲一区久久久| 制服丝袜激情欧洲亚洲| 欧美好骚综合网| 欧美成年人视频| 亚洲国产一区二区a毛片| 亚洲成色777777女色窝| 亚洲茄子视频| 亚洲视频大全| 欧美一区二区大片| 久久婷婷成人综合色| 蜜臀a∨国产成人精品| 欧美精品久久久久久久| 欧美日韩在线免费观看| 国产老女人精品毛片久久| 国产日韩欧美综合| 亚洲成人在线视频播放| 亚洲精品一区二| 亚洲综合精品自拍| 久久久免费精品| 亚洲盗摄视频| 亚洲最黄网站| 久久成年人视频| 欧美成人免费网| 国产精品乱子久久久久| 狠狠色狠狠色综合| 日韩一二三区视频| 欧美一区二区精品| 欧美肥婆在线| 亚洲网站啪啪| 久久免费视频网| 欧美午夜影院| 在线观看成人网| 亚洲一区二区在线视频| 久久亚洲午夜电影| 99国产精品久久| 久久精品一二三| 欧美日韩系列| 一区二区在线观看av| 99精品国产在热久久| 久久se精品一区二区| 亚洲国产精品日韩| 欧美一区2区三区4区公司二百| 老司机免费视频久久| 国产精品欧美激情| 91久久精品一区二区别| 亚洲欧美在线看| 欧美大色视频| 午夜激情亚洲| 欧美激情精品久久久| 国产亚洲一区二区三区在线观看 | 亚洲精品一区二区三区福利| 亚洲一区二区三区四区五区午夜| 久久天天躁狠狠躁夜夜爽蜜月| 亚洲日韩欧美一区二区在线| 久久精品99无色码中文字幕 | 亚洲黄色成人| 午夜亚洲福利| 亚洲日本中文字幕免费在线不卡| 午夜精品美女久久久久av福利| 欧美久久综合| 尤物精品国产第一福利三区| 亚洲欧美中文日韩v在线观看| 欧美黑人多人双交| 欧美在线视频免费观看| 国产精品久久久久久久久久免费| 亚洲欧洲三级| 欧美99在线视频观看| 欧美一区二区三区男人的天堂| 欧美日韩精品国产| 亚洲国产成人在线| 久久精品在线| 亚洲一区免费网站| 欧美日韩情趣电影| 亚洲精品中文字幕女同| 免费影视亚洲| 欧美主播一区二区三区美女 久久精品人| 欧美日韩国产色站一区二区三区| 亚洲国产欧美一区二区三区久久| 久久天天躁夜夜躁狠狠躁2022| 亚洲欧美激情视频| 国产精品久久久久久久久久免费看| 99在线视频精品| 亚洲人成久久| 欧美成人中文字幕| 91久久香蕉国产日韩欧美9色| 免费欧美高清视频| 久久女同互慰一区二区三区| 国产情人节一区| 久久国产免费看| 香蕉久久夜色精品国产| 国产精品一区二区在线观看网站| 亚洲一区二区在线免费观看| 夜夜嗨一区二区三区| 欧美色视频日本高清在线观看| 亚洲视频在线看| 一本大道av伊人久久综合| 欧美午夜电影一区| 亚洲一本视频| 亚洲一区二区三区四区中文| 国产精品欧美日韩久久| 亚洲欧美影音先锋| 午夜精品偷拍| 国产亚洲一区二区三区在线观看| 久久se精品一区精品二区| 性伦欧美刺激片在线观看| 国产亚洲人成网站在线观看| 久久精品一级爱片| 久久久久久久久久看片| 在线观看欧美精品| 亚洲福利在线视频| 欧美日本高清| 亚洲免费视频一区二区| 亚洲欧洲av一区二区| 国内成人精品视频| 欧美激情国产日韩| 欧美日韩99| 午夜欧美不卡精品aaaaa| 午夜精品一区二区三区四区| 国产在线欧美日韩| 欧美大尺度在线| 欧美精品在线免费观看| 亚洲一区免费| 久久se精品一区精品二区| 在线观看日韩av电影| 亚洲人www| 国产精品一区久久| 久久中文精品| 欧美日韩高清不卡| 欧美中文字幕精品| 麻豆av一区二区三区| 亚洲图片欧洲图片av| 欧美一区网站| 日韩视频专区| 午夜精品久久久久久久久久久久久| 在线观看日韩专区| 99亚洲一区二区| 狠狠色伊人亚洲综合网站色 | 欧美.www| 西西裸体人体做爰大胆久久久| 久久精品男女| 夜夜爽www精品| 欧美在线观看网站| 亚洲精品乱码久久久久久蜜桃麻豆 | 欧美日韩国产在线播放网站| 欧美与黑人午夜性猛交久久久| 久久伊人免费视频| 亚洲欧美日韩一区二区三区在线 | 一区二区视频欧美| 夜夜嗨av色综合久久久综合网| 黑人巨大精品欧美一区二区 | 欧美日韩综合另类| 久久综合九九| 欧美性猛交xxxx免费看久久久 | 亚洲一卡久久| 亚洲精品一区二区三区四区高清| 午夜精品99久久免费| 夜夜精品视频一区二区| 久久久久在线观看| 午夜精品福利在线观看| 欧美国产视频在线观看| 久久九九全国免费精品观看| 欧美三级欧美一级| 欧美国产综合一区二区| 国产一区二区三区日韩欧美| 一本色道久久综合| 亚洲精品免费网站| 久久久精品国产99久久精品芒果| 亚洲欧美日韩成人| 欧美久久久久| 欧美激情亚洲视频| 精品粉嫩aⅴ一区二区三区四区| 中文精品视频一区二区在线观看| 亚洲精选在线| 久久中文久久字幕| 久久人人爽人人爽| 国产乱码精品1区2区3区| aa级大片欧美三级| 亚洲美女福利视频网站| 久久中文字幕一区| 老司机一区二区| 国产一区二区三区不卡在线观看| 亚洲香蕉成视频在线观看| 亚洲视频久久| 欧美日产在线观看| 亚洲精品1区2区| 91久久综合亚洲鲁鲁五月天| 久久偷窥视频| 牛人盗摄一区二区三区视频| 伊人色综合久久天天| 久久精品综合一区| 久久女同精品一区二区| 国产一区久久久| 欧美在线国产| 久久视频一区二区| 影音先锋中文字幕一区| 久久精品人人做人人爽| 理论片一区二区在线| 悠悠资源网久久精品| 麻豆成人在线观看| 亚洲国产电影|