Solved

speed up SetWindowsHookEx, or alternative?

Posted on 2004-09-29
16
1,340 Views
Last Modified: 2012-06-27
Hello,

I have a program that runs in the background and uses Windows Hooks to look at the keyboard/mouse usage.

I use SetWindowsHookEx(), listening to WH_KEYBOARD_LL and WH_MOUSE_LL. However hooks tend to slow down systems pretty much, especially when playing games.

My question, is there a way to speed up processing these hooks, or are there better alternatives (besides DirectInput), I appriciate any feedback!
0
Comment
Question by:njitram
16 Comments
 
LVL 22

Expert Comment

by:grg99
ID: 12185827
The hook itself is mighty speedy;  it's waht you do in thehook procedure that can slow  things down.

How about you show us the code?
0
 

Author Comment

by:njitram
ID: 12187232
Alright, below is my code. It does quite alot when it's called, and everything works, it's just slow when playing games such as Half-life. I switched this part over from a DirectInput program, and in there it worked perfectly fast.

I hook it with:

g_hKbHook            = ::SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)kbProc, AfxGetApp()->m_hInstance, 0);


LRESULT CALLBACK
kbProc (int iCode, WPARAM wParam, LPARAM lParam)
{
    static HWND activeWnd = 0;

    if (iCode < 0) {
       return CallNextHookEx(g_hKbHook, iCode, wParam,lParam);
    }
    else {
        if(!pFrame->m_pAppWnd->state.bCountkeys)
        {
             return 0;
        }

        if (iCode == HC_ACTION)
        {
            KBDLLHOOKSTRUCT kbDllHookStruct = *(KBDLLHOOKSTRUCT*)lParam;
            if (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN)
            {
                if ((kbDllHookStruct.flags & LLKHF_INJECTED) != 0)
                {
                    return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
                }

                if ((GetKeyState(kbDllHookStruct.vkCode) & 0x8000) == 0)
                {
                    pFrame->KeyCount.getAccess();
                    pFrame->KeyCount.increment();
                    pFrame->KeyCount.releaseAccess();

                    pFrame->m_tray.SetIcon(IDI_TRAYICON_KEYDOWN);

                    pFrame->bKeyHitSinceSave = TRUE;

                    UINT tempkeys = 0;
                    CQuickCrypt crypt, crypto;
                    CString str;

                    str.Format("%s", gKeysHit);
                    crypt.SetCipher(str);
                    tempkeys = _ttoi(crypt.DeCipher1());
                    tempkeys++;
                              
                    str.Format("%ld", tempkeys);
                    crypto.SetPlain(str);
                    strcpy(gKeysHit, crypto.Cipher1());

                    gTotalKeys++;

                    if(pFrame->m_pAppWnd->state.bKeepFreq) {
                        Keys.IncrementHitCount(kbDllHookStruct.vkCode);
                        pFrame->m_pAppWnd->state.keysSinceLR++;
                    }
                }
            }
            if(wParam == WM_KEYUP)
            {
                pFrame->m_tray.SetIcon(IDI_TRAYICON);
                pFrame->SetTrayToolTip(TRUE);
            }
        }
    }

    return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
}
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 12188412
There is some code that might get improved:

>>>  pFrame->KeyCount.getAccess();
>>>  pFrame->KeyCount.increment();
>>>  pFrame->KeyCount.releaseAccess();

Maybe you can use InterlockedIncrement to have an atomic increment instead.

>>> pFrame->m_tray.SetIcon(IDI_TRAYICON_KEYDOWN);

That is a SendMessage to another window that shouldn't be done in a hook function. If the hook function is the only place where tray icons are going to be changed, you may hold the status of the tray in a static variable and call SetIcon only if there is a change. Or have a PostMessage instead of a SendMessage (get the internal call from afxcmn2.inl).

I don't know how much time the encrypting of the counter takes, but you may prove if you really need string encrypting for that. If you only need to hide a counter take an algorithm like that:

int hideNumber(int i)
{
    unsigned int x = i, y = 0;    
    for (int n = 0; n < 32; n++) if (x & (1<<(31-n))) y |= (1<<n);
    return (int)y;
}
int showNumber(int i)
{
    unsigned int x = 0, y = i;
    for (int n = 0; n < 32; n++) if (y & (1<<n)) x |= (1<<(31-n));
    return (int)x;
}

Regards, Alex
0
 

Author Comment

by:njitram
ID: 12193195
I think I know more about where the slowness comes from. I pasted the code for the keyboard calls above, only I also have mouse calls, registered with WH_MOUSE_LL.

I tried to remove the registering of the mouse handle, just for fun, but it turns out, removing this helped a great deal. So I'm kinda thinking something is wrong with the way I handle the mouse.

Below is the code for the mouse handling. This is only supposed to catch mouse buttons.

// Registering the mouse hook
g_hMouseHook      = ::SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)mouseProc, AfxGetApp()->m_hInstance, 0);

// mouse handling
LRESULT CALLBACK
kbProc (int iCode, WPARAM wParam, LPARAM lParam)
{
        if (iCode < 0) {
              return CallNextHookEx(g_hKbHook, iCode, wParam,lParam);
        }
        else {
                if (iCode == HC_ACTION)
                {
                      KBDLLHOOKSTRUCT kbDllHookStruct = *(KBDLLHOOKSTRUCT*)lParam;
                     if (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN)
                     {
                           if ((kbDllHookStruct.flags & LLKHF_INJECTED) != 0)
                           {
                                  return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
                           }

                           if ((GetKeyState(kbDllHookStruct.vkCode) & 0x8000) == 0)
                           {
                                   // handle a clicked mouse button
                            }
                     }
                     if(wParam == WM_KEYUP)
                     {
                            // when the button goes up
                     }
               }
        }

        return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
}

Is there anything wrong with this?
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 12193322
Looks like a mismatch. Please post mouseProc and not kbProc.

Regards, Alex
0
 

Author Comment

by:njitram
ID: 12193392
Woops, sorry, no idea where that came from...below the mouseProc;

LRESULT CALLBACK
mouseProc(int iCode, WPARAM wParam, LPARAM lParam)
{
    if (iCode < 0) {
        return CallNextHookEx(g_hMouseHook, iCode, wParam, lParam);
    }
    else {
        if (iCode == HC_ACTION)
        {
            MSLLHOOKSTRUCT msllHookStruct = *(MSLLHOOKSTRUCT*)lParam;
            if (wParam == WM_LBUTTONDOWN || wParam == WM_RBUTTONDOWN || wParam == WM_XBUTTONDOWN ||
                wParam == WM_MBUTTONDOWN)
            {
                if ((msllHookStruct.flags & LLMHF_INJECTED) != 0)
                {
                    return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
                }

                // handle mouse down
            }
            if (wParam == WM_LBUTTONUP || wParam == WM_RBUTTONUP || wParam == WM_XBUTTONUP ||
                wParam == WM_MBUTTONUP)
            {
                 // handle mouse up
            }
        }
    }
    return CallNextHookEx(g_hMouseHook, iCode, wParam, lParam);
}

The functions inside the handling are about the same as the keyboard, but considering those work perfectly fast in the keyboard proc now..I thought I'd save some room...
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 12193518
No, that code couldn't be slow as it handles only mouse button clicks (and not mouse moves as i guessed before your post).

However, it will be called for any mouse move message as well. So little times may add to something that is measurable, though i don't believe it. But you may use a static counter to find out, how often it is called.

Is there another mouse hook somewhere?

Regards, Alex
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 12193545
You also could comment the handling of the mouse clicks, to see whether the mouse hook itself or your mouse handling slows down.

Regards, Alex
0
 

Author Comment

by:njitram
ID: 12193625
There is not a second mouse hook somewhere, I'm only using 2 hooks, one for the keyboard and one for the mouse.

I tried putting a small counter which counted the times mouseProc was called, well, that was alot. ;) So I figure it gets called everytime the mouse moves/clicks.

I also tried to empty the code that handles the mouse clicks to a single 'clicks++;', but it still continued to go slow.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 12193797
>> that was alot. ;)

How often a second? And do you have to move the mouse for that?

You could try to return not calling CallNextHookEx. Only to see if these calls are the reason for the slowness.

Regards, Alex


0
 

Author Comment

by:njitram
ID: 12193907
I'd say every pixel, inch, or whatever is used to measure mouse distances to see when another message is posted.

And when I remove the return's, the mouse stops responding totally (Including in Windows).
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 12197851
>>> the mouse stops responding totally

You *have* to call CallNextHookEx if nCode < 0. Return 0 all other returns, as a non-zero return means you've processed the message, thus the message will not get processed by the target window.

Regards, Alex

0
 

Author Comment

by:njitram
ID: 12200380
No change when I put the returns to 0, I'm really out of ideas...do you have any left?
0
 

Accepted Solution

by:
modulo earned 0 total points
ID: 12687938
PAQed with points refunded (500)

modulo
Community Support Moderator
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now