SetTimer from non-static function

I write code that detects key press when window not in focus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// MainHamsterDlg.cpp : implementation file

#include "stdafx.h"
#include "MainHamsterDlg.h"

// MainHamsterDlg dialog
IMPLEMENT_DYNAMIC(MainHamsterDlg, CDialogEx)

MainHamsterDlg::MainHamsterDlg(CWnd* pParent)
    : CDialogEx(MainHamsterDlg::IDD, pParent)
    {}

void MainHamsterDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(MainHamsterDlg, CDialogEx)
   ON_WM_TIMER()
END_MESSAGE_MAP()

HHOOK _hook;
KBDLLHOOKSTRUCT kbdStruct;

LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
   if (nCode >= 0)
   {
      if (wParam == WM_KEYUP)
      {
          kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
          if (kbdStruct.vkCode == VK_INSERT)
          {
              //I want start timer there
          }
       }
    }
return CallNextHookEx(_hook, nCode, wParam, lParam);
}

void SetHook()
{
   if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0)))
   {
      MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
   }
}

void ReleaseHook()
{
   UnhookWindowsHookEx(_hook);
}

BOOL MainHamsterDlg::OnInitDialog()
{ 
   SetHook();
   //SetTimer(0, 0, NULL); <<<------- this starts timer 
   CDialogEx::OnInitDialog();
   return TRUE;
}

void MainHamsterDlg::OnTimer(UINT nIDEvent)
{
    //do something
CDialog::OnTimer(nIDEvent);
}


I want start timer on key press when window not focused. Do I need use some pointers or what to call SetTimer from that function. If there is a better issue to make timer work on key press when application has no focused I wish to know.
Edit: checking my answer, I've just realised you're trying to set a global hook (WH_KEYBOARD_LL); global hooks require the hook function (HookCallback) to be in a DLL, so it can be loaded into all process.

(Now back to my original response...)

Do I need use some pointers or what to call SetTimer from that function.

You could use a callback interface or post a custom message to the window's message loop.

The callback interface approach goes something like this. First you declare a little interface class, e.g.

1
2
3
4
5
class IHookCallback
{
public:
	virtual void StartTimer() = 0;
};


MainHamsterDlg inherits this little interface class and implements the required StartTimer() method, e.g.

1
2
3
4
5
6
7
8
9
void CMFC_DLG_TestDlg::StartTimer()
{
    UINT eventID = 1000; // some ID
    UINT timerInterval_secs = 1000; // 1 sec, for illustration
                                    // (could be defained elsewhere)
    m_eventID = SetTimer( eventID,
                          timerInterval_secs,
                          NULL ); // no timer callback function
}


(Note you also need to add a UINT m_eventID member to MainHamsterDlg, and zeroed it in the constructor init list.)

Then the hooking code need to be adjusted to:

Edit: and moved into a DLL, which means SetHook and ReleaseHook must be exported.

Edit: _pCallback should very probably be protected with a critical section.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
HHOOK          _hook      = NULL;
IHookCallback* _pCallback = NULL;

LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
   if (nCode >= 0)
   {
      if (wParam == WM_KEYUP)
      {
         KBDLLHOOKSTRUCT* kbdStruct = (KBDLLHOOKSTRUCT*)lParam;
         if (kbdStruct->vkCode == VK_INSERT)
         {
            if (NULL != _pCallback) // prob better to check _pCallback first?
            {
               _pCallback->StartTimer();
            }
         }
      }
   }
   return CallNextHookEx(_hook, nCode, wParam, lParam);
}

void SetHook(IHookCallback* pCallback)
{
   _pCallback = pCallback;

   if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0)))
   {
      MessageBox(NULL, _T("Failed to install hook!"), _T("Error"), MB_ICONERROR);
   }
}

void ReleaseHook()
{
   UnhookWindowsHookEx(_hook);

    _pCallback = NULL;
}


and this passed when you call SetHook, e.g. SetHook(this);

If you use a custom window message, you need to do the same kind of thing with the dialog's hwnd, PostMessage, and a custom message handler (for the dialog.)

Andy
Last edited on
Topic archived. No new replies allowed.