I installed a global keyboard hook to intercept my multimedia keyboard's special keys and delegate them to Winamp (because the drivers for this keyboard are written so poorly it makes me sick).
When debugging, it seemed to work fine.
In standalone run, it suddenly didn't work anymore. The hook was set, but it didn't catch anything.
It turned out that, no matter how I run this thing, it only catches messages that are sent to Visual Studio!
Does anyone have an explanation for this weird behavior?
Here's the hook DLL.
Code:
#define WINVER 0x0500
#define _WIN32_WINNT 0x0500
#include <windows.h>
#pragma data_seg("shared_data")
// Superglobals
HHOOK g_hhook = 0;
HWND g_hwnd = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:shared_data,S")
HMODULE g_hmodule = 0;
LRESULT CALLBACK MultimediaKeyboardProc(int code, WPARAM w, LPARAM l)
{
if(code < 0 || code == HC_ACTION) {
return CallNextHookEx(g_hhook, code, w, l);
}
MessageBox(0, TEXT("Hook called."), TEXT("MultiHook"), 0);
int winampcmd = 0;
switch(w) {
case VK_MEDIA_NEXT_TRACK:
winampcmd = 40048;
break;
case VK_MEDIA_PREV_TRACK:
winampcmd = 40044;
break;
case VK_MEDIA_PLAY_PAUSE:
{
LRESULT playstatus = SendMessage(g_hwnd, WM_USER, 0, 104);
winampcmd = (playstatus == 1 || playstatus == 3) ? 40046 : 40045;
} break;
case VK_MEDIA_STOP:
winampcmd = 40047;
break;
}
if(winampcmd == 0) {
return CallNextHookEx(g_hhook, code, w, l);
}
MessageBox(0, TEXT("Hook invoked."), TEXT("MultiHook"), 0);
SendMessage(g_hwnd, WM_COMMAND, winampcmd, 0);
return TRUE;
}
BOOL WINAPI DllMain(HMODULE hmod, DWORD reason, LPVOID)
{
if(reason == DLL_PROCESS_ATTACH) {
g_hmodule = hmod;
}
return TRUE;
}
bool WINAPI InstallHook()
{
if(g_hhook != 0) {
return false;
}
g_hwnd = FindWindow(TEXT("Winamp v1.x"), 0);
if(!g_hwnd) {
MessageBox(0, TEXT("Winamp not found!"), TEXT("MultiHook"), 0);
return false;
}
g_hhook = SetWindowsHookEx(WH_KEYBOARD, MultimediaKeyboardProc, g_hmodule, 0);
if(g_hhook) {
MessageBox(0, TEXT("Hook set."), TEXT("MultiHook"), 0);
} else {
MessageBox(0, TEXT("Hook failed."), TEXT("MultiHook"), 0);
}
return g_hhook != 0;
}
void WINAPI ClearHook()
{
if(g_hhook != 0) {
UnhookWindowsHookEx(g_hhook);
MessageBox(0, TEXT("Hook cleared."), TEXT("MultiHook"), 0);
}
}
And the program that makes use of it.
Code:
#include <windows.h>
#include <shellapi.h>
typedef bool (WINAPI *INST)();
typedef void (WINAPI *CLEAR)();
void WaitForQuit();
int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
HMODULE hmod = LoadLibrary(
#if defined(_DEBUG) || defined(DEBUG)
TEXT("..\\MultimediaHook\\Debug\\")
#endif
TEXT("MultimediaHook.dll"));
if(hmod == 0) {
return 1;
}
INST InstallHook = reinterpret_cast<INST>(GetProcAddress(hmod, "InstallHook"));
CLEAR ClearHook = reinterpret_cast<CLEAR>(GetProcAddress(hmod, "ClearHook"));
if(InstallHook && ClearHook) {
InstallHook();
WaitForQuit();
ClearHook();
}
FreeLibrary(hmod);
return 0;
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void WaitForQuit()
{
WNDCLASS wc;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = WndProc;
wc.lpszClassName = TEXT("MultimediaHookCommWnd");
RegisterClass(&wc);
HWND h = CreateWindow(wc.lpszClassName, TEXT("Multimedia Hook Comm Window"),
WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, 0, 0, wc.hInstance, 0);
NOTIFYICONDATA nid;
ZeroMemory(&nid, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = h;
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
nid.hIcon = LoadIcon(0, IDI_WINLOGO);
lstrcpy(nid.szTip, TEXT("Hook Comm"));
nid.uCallbackMessage = WM_USER + 23;
Shell_NotifyIcon(NIM_ADD, &nid);
MSG msg;
while(GetMessage(&msg, 0, 0, 0) > 0) {
DispatchMessage(&msg);
}
Shell_NotifyIcon(NIM_DELETE, &nid);
UnregisterClass(wc.lpszClassName, wc.hInstance);
}
LRESULT CALLBACK WndProc(HWND h, UINT m, WPARAM w, LPARAM l)
{
if(m == WM_USER+23) {
if(l == WM_LBUTTONDOWN) {
DestroyWindow(h);
PostQuitMessage(0);
}
return 0;
}
return DefWindowProc(h, m, w, l);
}