Lost with a systemwide hook
This is not straight MFC, but I hope there are some people
around here who can put me to the right direction.
First let me tell what I am trying to to. Recently I upgraded
from PowerDVD 6 to PowerDVD 7 (for some good reason, v6 did
ignore "set subtile" VM commands totally, v7 works correctly).
Now, I have a notebook with some special multimedia keys,
which I'm used to, I really wouldn't like to miss them.
However PowerDVD 7 does not work as expected with those keys.
They are controled by an app called QtDTAcer.exe.
I have one physicle an two virtual DVD drives. When pressing
the "Play" button a little popup window pos up and lets me choose
which drive to play. When PowerDVD is already running this
popup window does not appear when pressing the button. Instead
playback is stopped/continued. This is the behaviour how it used
to be and how it makes sence.
Now with PowerDVD 7 when pressing the "Play" button the popup
window even appears when PowerDVD is already running. It is
annoying. After giving it up to find some settings to change
(there are no) I had the idea to write a little piece of
software to change this.
First idea was to use a timer. I wrote an app showing a tray
icon (just to be able to turn it off). I start a timer and every
1000 mSec I do this:
- first I check if both PowerDVD and QtDTAcer are running
- if so I try to find the popup window
(EnumWindows, identify it by checking hWnd to belong to
the QtDTAcer process, windows style WS_POPUP and it's
classname ("#32768"). This seems to be unique. I get
exactly one hWnd and it is the correct one.
- last I hide it by a SetWindowPos call.
This works perfectly as expected. Pressing the "Play" button
when PowerDVD is running the window pops up and as soon as the
timer has elapsed it is hidden.
Now there are two things about this. First I see it for a short time.
Second I think it to be the dumb solution because my app is quite
busy all the time. The better way would be to trap the problem at
So I thought of a systemwide hook. I never deeled with hook before.
I found an older article "TRACEWIN" by Paul Dilascia in the MSDN
that ships with VC++6.0. So I tried to adapt the basic idea of this
I created another app showing just a tray icon. Next I created a
DLL to set the systemwide hook. The tray app loads this DLL and the
is set. So far it works as expected. However now I have no idea what
"events" the hook could trap.
One problem is that I cannot examine the popup window's messages in
SPY++. The popup window is by default hidden whenever another app
(as SPY++) is activated. My first app shows that it's window handle
changes all the time. So I guess it is destroyed and recreated when
My questions are:
- What kind of hook will suit my problem best. I tried WH_CBT,
WH_MSGFILTER, WH_CALLWNDPROC and WH_CALLWNDPROCRET
- What events should I search for?
- Is my approach appropriate at all?
- If so what to do?
Here is a code snippet:
int CInjectDll::Inject(HINSTANCE hInstance, int nHookType)
ASSERT(hInstance != NULL);
ASSERT(WH_MINHOOK <= nHookType && nHookType <= WH_MAXHOOK);
g_hHook = SetWindowsHookEx(nHookType, // type of hook
HookProc, // hook callback fn
hInstance, // HINSTANCE of DLL
0); // 0 = system-wide hook
return g_hHook ? NOERROR : E_INJECT_FAILED;
LRESULT CALLBACK CInjectDll::HookProc(int nCode, WPARAM wParam, LPARAM
ASSERT(g_pThis != NULL); // check valid object and
return g_pThis->OnHookProc(nCode, wParam, lParam);
LRESULT CInjectDll::OnHookProc(int nCode, WPARAM wParam, LPARAM
CWPRETSTRUCT * pMsg = (CWPRETSTRUCT*)lParam;
GetClassName(pMsg->hwnd, classname, 400);
static int counter=0;
if (m_bProcessFound && _stricmp(classname, "#32768") == 0 && +
+counter < 100)
sprintf(msg, "OKOK %.8x %.8x %d %s\n%.8x %.8x %.8x %.8x %.8x\n%s",
nCode, wParam, counter, classname,
pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, pMsg-
SetWindowPos(pMsg->hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_ASYNCWINDOWPOS
| SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
MessageBox(NULL, msg, NULL, MB_OK);
static bInjected = FALSE; // one per process/DLL instance
if (!bInjected) // if this is the first time called:
g_pThis->OnInject(); // do first-time init..
bInjected = TRUE; // ..but not again
return nCode < 0 ? CallNextHookEx(g_hHook, nCode, wParam, lParam) :
//ASSERT(m_szModuleName == 0);
GetModuleFileName(NULL, m_szModuleName, sizeof(m_szModuleName));
if (strstr(_strlwr(m_szModuleName), "qtdtacer") != NULL)
m_bProcessFound = TRUE;