/* $Id: VBoxHook.cpp 46182 2013-05-21 00:04:48Z vboxsync $ */ /** @file * VBoxHook -- Global windows hook dll */ /* * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include #include #include #include #pragma data_seg("SHARED") static HWINEVENTHOOK hWinEventHook[2] = {0}; static HWINEVENTHOOK hDesktopEventHook = NULL; #pragma data_seg() #pragma comment(linker, "/section:SHARED,RWS") static HANDLE hWinNotifyEvent = 0; static HANDLE hDesktopNotifyEvent = 0; #ifdef DEBUG static void WriteLog(const char *pszFormat, ...); # define dprintf(a) do { WriteLog a; } while (0) #else # define dprintf(a) do {} while (0) #endif /* !DEBUG */ static void CALLBACK VBoxHandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) { DWORD dwStyle; if ( idObject != OBJID_WINDOW || !hwnd) return; dwStyle = GetWindowLong(hwnd, GWL_STYLE); if (dwStyle & WS_CHILD) return; switch(event) { case EVENT_OBJECT_LOCATIONCHANGE: if (!(dwStyle & WS_VISIBLE)) return; case EVENT_OBJECT_CREATE: case EVENT_OBJECT_DESTROY: case EVENT_OBJECT_HIDE: case EVENT_OBJECT_SHOW: #ifdef DEBUG switch(event) { case EVENT_OBJECT_LOCATIONCHANGE: dprintf(("VBoxHandleWinEvent EVENT_OBJECT_LOCATIONCHANGE for window %x\n", hwnd)); break; case EVENT_OBJECT_CREATE: dprintf(("VBoxHandleWinEvent EVENT_OBJECT_CREATE for window %x\n", hwnd)); break; case EVENT_OBJECT_HIDE: dprintf(("VBoxHandleWinEvent EVENT_OBJECT_HIDE for window %x\n", hwnd)); break; case EVENT_OBJECT_SHOW: dprintf(("VBoxHandleWinEvent EVENT_OBJECT_SHOW for window %x\n", hwnd)); break; case EVENT_OBJECT_DESTROY: dprintf(("VBoxHandleWinEvent EVENT_OBJECT_DESTROY for window %x\n", hwnd)); break; } #endif if (!hWinNotifyEvent) { hWinNotifyEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, VBOXHOOK_GLOBAL_WT_EVENT_NAME); dprintf(("OpenEvent returned %x (last err=%x)\n", hWinNotifyEvent, GetLastError())); } BOOL ret = SetEvent(hWinNotifyEvent); dprintf(("SetEvent %x returned %d (last error %x)\n", hWinNotifyEvent, ret, GetLastError())); break; } } static void CALLBACK VBoxHandleDesktopEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) { if (!hDesktopNotifyEvent) { hDesktopNotifyEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, VBOXHOOK_GLOBAL_DT_EVENT_NAME); dprintf(("OpenEvent returned %x (last err=%x)\n", hDesktopNotifyEvent, GetLastError())); } BOOL ret = SetEvent(hDesktopNotifyEvent); dprintf(("SetEvent %x returned %d (last error %x)\n", hDesktopNotifyEvent, ret, GetLastError())); } BOOL VBoxHookInstallActiveDesktopTracker(HMODULE hDll) { if (hDesktopEventHook) return TRUE; CoInitialize(NULL); hDesktopEventHook = SetWinEventHook(EVENT_SYSTEM_DESKTOPSWITCH, EVENT_SYSTEM_DESKTOPSWITCH, hDll, VBoxHandleDesktopEvent, 0, 0, 0); return !!hDesktopEventHook; } BOOL VBoxHookRemoveActiveDesktopTracker() { if (hDesktopEventHook) { UnhookWinEvent(hDesktopEventHook); CoUninitialize(); } hDesktopEventHook = 0; return TRUE; } /** Install the global message hook */ BOOL VBoxHookInstallWindowTracker(HMODULE hDll) { if (hWinEventHook[0] || hWinEventHook[1]) return TRUE; CoInitialize(NULL); hWinEventHook[0] = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, hDll, VBoxHandleWinEvent, 0, 0, WINEVENT_INCONTEXT | WINEVENT_SKIPOWNPROCESS); hWinEventHook[1] = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_HIDE, hDll, VBoxHandleWinEvent, 0, 0, WINEVENT_INCONTEXT | WINEVENT_SKIPOWNPROCESS); return !!hWinEventHook[0]; } /** Remove the global message hook */ BOOL VBoxHookRemoveWindowTracker() { if (hWinEventHook[0] && hWinEventHook[1]) { UnhookWinEvent(hWinEventHook[0]); UnhookWinEvent(hWinEventHook[1]); CoUninitialize(); } hWinEventHook[0] = hWinEventHook[1] = 0; return TRUE; } #ifdef DEBUG # include # include /** * dprintf worker using VBoxGuest.sys and VMMDevReq_LogString. */ static void WriteLog(const char *pszFormat, ...) { /* * Open VBox guest driver once. */ static HANDLE s_hVBoxGuest = INVALID_HANDLE_VALUE; HANDLE hVBoxGuest = s_hVBoxGuest; if (hVBoxGuest == INVALID_HANDLE_VALUE) { hVBoxGuest = CreateFile(VBOXGUEST_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (hVBoxGuest == INVALID_HANDLE_VALUE) return; s_hVBoxGuest = hVBoxGuest; } /* * We're apparently afraid of using stack here, so we use a static buffer * instead and pray we won't be here at the same time on two threads... */ static union { VMMDevReqLogString Req; uint8_t abBuf[1024]; } s_uBuf; vmmdevInitRequest(&s_uBuf.Req.header, VMMDevReq_LogString); va_list va; va_start(va, pszFormat); size_t cch = vsprintf(s_uBuf.Req.szString, pszFormat, va); va_end(va); s_uBuf.Req.header.size += (uint32_t)cch; if (s_uBuf.Req.header.size > sizeof(s_uBuf)) __debugbreak(); DWORD cbReturned; DeviceIoControl(hVBoxGuest, VBOXGUEST_IOCTL_VMMREQUEST(s_uBuf.Req.size), &s_uBuf.Req, s_uBuf.Req.header.size, &s_uBuf.Req, s_uBuf.Req.header.size, &cbReturned, NULL); } #endif /* DEBUG */