http://community.borland.com/article/0,1410,10322,00.html
gz

解决方案 »

  1.   

    這個普通的hook函數的問題都沒人能回答嗎?只要進來的人我都給分,緷不食言! (留下gz都可以)請幫手推一把吧!!!!!!!!
      

  2.   

    一点都不阐述现象,叫别人怎么说呢?
    参考以下代码看看:BOOL bWait=true;
    LRESULT CALLBACK JournalPlaybackProc(
      int code,       // hook code
      WPARAM wParam,  // undefined
      LPARAM lParam   // address of message being processed
    )
    {
    char Buffer[1023];
    long Time=0,TimeStamp=0;
    if(pCurr!=NULL) 
    {
         TimeStamp = pCurr->Msg .time - pPre->Msg.time;
    if(TimeStamp == 0) 
    TimeStamp = 10;
    sprintf(Buffer,"code %d ,Index %d TimeStamp %d",code,pCurr->Index,TimeStamp );
    }
        if(pCurr!=pTail&&pCurr!=NULL)
    {
    switch (code )
    {
    case HC_NOREMOVE:
    break;
    case HC_GETNEXT:
    memcpy((void *)lParam,&pCurr->Msg ,sizeof(EVENTMSG)); 
    if(bWait) 
    {
    bWait=false;
    return TimeStamp;
    }
    else
    {
    pWnd->SetWindowText (Buffer);
    return 0;
    }
    break;
    case HC_SKIP:
    if(pCurr!=NULL)
    {
    bWait=true;
    pPre = pCurr;
    pCurr=pCurr->next;
    }
    break;
            case HC_SYSMODALOFF:
    RecCtrl = HC_GETNEXT;
    break;
            case HC_SYSMODALON:
    RecCtrl = HC_SYSMODALON;
    return 0;
    default:
    break;
    }
    }else
    {
    if(::UnhookWindowsHookEx (hPlay))
    {
    MessageBox(0,"PlayBackEnd","Hook",MB_OK);
    FreeList();
    Count=0;
    }
    }

    return  ::CallNextHookEx (hPlay,code,wParam,lParam);

    }
      

  3.   

    2 vcbear(一只平凡无知的熊):
      以下是我的一段代碼,你幫忙看看問是在哪里:LRESULT CALLBACK JournalPlaybackProc(int code,WPARAM wParam,LPARAM lParam)
    {
    LPEVENTMSG lpEvent;
    LRESULT lResult;
    TRACE("------%d-------\n",code);
    switch(code)
    {
    case HC_SKIP:
    if(++m_Record->lStartNum==m_Record->lNum)
    {
    ::UnhookWindowsHookEx(m_hook);
    m_hook=NULL;
    }
    break;
    case HC_GETNEXT:
    lpEvent=(LPEVENTMSG)&m_Record[1];
    lpEvent=&lpEvent[m_Record->lStartNum];
    lpEvent->time+=m_Record->lStartTime;
    *(LPEVENTMSG)lParam=*lpEvent;
    //為了跟蹤數據是否正確而設
    TRACE("hwnd: %X\n",lpEvent->hwnd);
    TRACE("msg: %X\n",lpEvent->message);
    TRACE("paramH: %X\n",lpEvent->paramH);
    TRACE("paramL: %X\n",lpEvent->paramL);
    TRACE("time: %X\n",lpEvent->time); lResult=lpEvent->time-GetTickCount();
    if(lResult<0) lResult=0;
    return lResult;
    break;
    }
    return ::CallNextHookEx (m_hook,code,wParam,lParam);
    }其中的TRACE是我為了跟蹤而加上去的,而TRACE("------%d-------\n",code);總是會show出 1(HC_GETNEXT),只是偶而出個 2(HC_SKIP) (將近有100個1才會有兩個2),因而導致journalplayback成了死循環,不得已我只好把在HC_SKIP的一段碼copy到HC_GETNEXT段中,這樣我在HC_GETNEXT中的TRACE顯示的數據都是正確的,HOOK也可以正常結束。但,問題就是,我為什麼會收不到 HC_SKIP。
      

  4.   

    你研究一下这个先:
    If code is HC_GETNEXT and the return value is greater than zero, the system sleeps for the number of milliseconds specified by the return value. When the system continues, it calls the hook procedure again with code set to HC_GETNEXT to retrieve the same message. The return value from this new call to JournalPlaybackProc should be zero; otherwise, the system will go back to sleep for the number of milliseconds specified by the return value, call JournalPlaybackProc again, and so on. The system will appear to be hung
      

  5.   

    不好意思,小弟E文水平實在....,MSDN那段話只能看個似懂非懂。
    To retrieve the same message over and over, the hook procedure can be called several times with the code parameter set to HC_GETNEXT without an intervening call with code set to HC_SKIP. If code is HC_GETNEXT and the return value is greater than zero, the system sleeps for the number of milliseconds specified by the return value. When the system continues, it calls the hook procedure again with code set to HC_GETNEXT to retrieve the same message. The return value from this new call to JournalPlaybackProc should be zero; otherwise, the system will go back to sleep for the number of milliseconds specified by the return value, call JournalPlaybackProc again, and so on. The system will appear to be hung. 
     是說在返回值大于0的時候,下一次的HOOK調用還是會傳入HC_GETNEXT以 retrieve the same message,然后才返回0,
     那我怎樣才能控制系統以HC_SKIP來call hook procedure 呢? 不好意思,請熊哥再給我講講。
      

  6.   

    你看上面我贴的代码里有个bWait的变量,控制是否返回TimeStamp或者0
      

  7.   

     那麼,熊哥你的意思是:如果返回大于0,則下一次hook調用還是傳入HC_GETNEXT, 若返回0的話,則下一次hook調用傳入HC_SKIP,可是在<<windows程序設計指南>>一書中jeffrey并沒有提到這一點,難道在95以后hook的機制有了變化嗎,可是jeffrey的程序在我的2000也跑得蠻好的,這又是為什麼呢? 下面是其代碼,我貼出來給你看看。
    LRESULT CALLBACK JrnlPlybkHookFunc (int nCode, WPARAM wParam,LPARAM lParam)
    {
       BOOL fCallNextHookProc = FALSE;
       LRESULT lResult = 0;
       LPRECORDSTAT lpRecordStat=0;
       LPEVENTMSG lpEvent;   lpRecordStat = (LPRECORDSTAT) GlobalLock(_hGlblEvents);
       switch (nCode) {      case HC_SKIP:
             // Prepare to return the next event the next time the 
             // hook code is HC_GETNEXT.  If all events have been 
             // played, stop playing.
             if (++(lpRecordStat->wNumEventsPlayed) ==
                lpRecordStat->wNumEvents)
                Recorder(RM_STOPPLAY, 0, 0);   break;      case HC_GETNEXT:
             // Copy the current event to the EVENTMSG 
             // structure pointed to by lParam.
             lpEvent = (LPEVENTMSG) &lpRecordStat[1];
             *((LPEVENTMSG) lParam) =
                lpEvent[lpRecordStat->wNumEventsPlayed];
             // Adjust 'time' by adding time that playback started,
             ((LPEVENTMSG) lParam)->time += lpRecordStat->dwStartTime;         // Return the number of milliseconds Windows should wait
             // before processing the event.
             lResult = ((LPEVENTMSG) lParam)->time - GetTickCount();         // If the event occurred in the past, have Windows 
             // process it now.
             if (lResult < 0) lResult = 0;
             break;      case HC_SYSMODALOFF:
             // When the system-modal dialog box is removed, stop 
             // playing the events and notify the application.
             _PrematureHalt = REC_SYSMODALON;
             Recorder(RM_STOPPLAY, 0, 0);
             fCallNextHookProc = TRUE;
             break;      case HC_SYSMODALON:
          default:
             fCallNextHookProc = TRUE;
             break;   }
       GlobalUnlock(_hGlblEvents);   if (fCallNextHookProc)
          lResult = CallNextHookEx(_hHookJrnl, nCode, wParam, lParam);   return(lResult);
    }
      

  8.   

    其实我觉得jeffrey的代码有点问题,也许是因为我没有细看。
    他返回的lResult几乎不可能大于0,消息是根本不加延迟就回放的,飞快。
    而如果要模拟记录的消息的实际发生速度,应该用当前消息发生的时间减去上一个消息的时间,
    得到时间间隔,让系统进行延时,系统延时结束后,再用HC_GETNEXT进入回调函数,这时
    返回0并且拷贝当前消息,系统则回放该消息并且接着用HC_SKIP进入回调函数。
    应该是这样的流程。
      

  9.   


    是這樣的,我沒有把全部的代碼貼出來。jeffrey的思路是在開始recorder時記下開始時間,記錄完后,再將每個eventmsg中的time都減去開始時間而得到每個事件發生的相對時間值,然后在播放時先記下播放開始時間,然后再為每個eventmsg.time加上該播放開始時間,這樣就得出每個事件的實際播放時間值,再拿此值減去當前時間來作為返回值
      

  10.   

    in fact ,那是高手的一个很差的思路,这样他把运算的时间也加入到消息的时间里了,虽然不多  :PPPP
      

  11.   

    在EVENTMSG中的time應為該事件播放時的時間tick值,但在記錄時記下的該值在播放時肯定應該做修改,那麼你是怎樣來修改time的呢?在你的代碼中只有計算返回值,那在播放之前你就已把該time算好了囉
      

  12.   

    EVENTMSG中的TIME是被记录的消息发生的时间,我把所有记录下来的消息依次放在链表里,
    然后每次回调函数被调用的时候,
    TimeStamp = pCurr->Msg .time - pPre->Msg.time;
    当前消息的时间减上一个消息的时间得到让系统等待的时间长度,就这么简单。
            
      

  13.   

    那你的意思是:EVENTMSG中的time在播放時根本無關緊要,設不設都沒關系。那我就糊涂了,照jeffrey的說法,EVENTMSG的time在播放時要是該事件的實際tick值,而在記錄時和播放時的GetTickCount肯定是不相同的,所以他才在播放時依次計算每個EVENTMSG中的time值。那有可能95和98/2000的journal hook的機制不盡相同(因那本jeffrey的書是針對95編程的),那為什麼他的程序又在2000中跑得很好呢? 但那是已編譯好的exe文件。他的源代碼無法成功編譯,所以我也無法跟蹤。熊哥,你能不能給一份你寫的sample code給我,讓我參考一下,我現在修改后的代碼總是播放速度不太准確。謝謝了。 [email protected]
      

  14.   

    EVENTMSG中的time当然重要了,记录消息发生的时间,前一个消息和后一个消息发生时间的间隔
    就是控制播放速度的值,也是以Tick为单位。不用GetTickCount.
      

  15.   

    我是說,如果在播放(playback)的時候,我將返回值設為正確的,但是把EVENTMSG.time設為一個不正確值(例如,比當前tick還要早),這樣也不會影響到播放速度的正確性。當然,在記錄(record)的時候這個值肯定是很重要的。
      

  16.   

    应该是没有关系的,我想系统只是抽取里面的Msg,wParam,lParam,hWnd,并把他们放到消息队列里,原来的time变量并没有使用,相当于不同的时间(tick)又发生了一次相同的消息。
    有空你不妨试一下。