📄 vnchooks.cpp
字号:
// Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.// Copyright (C) 1997 AT&T Laboratories Cambridge. All Rights Reserved.//// This file is part of the VNC system.//// The VNC system is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,// USA.//// If the source code for the VNC system is not available from the place // whence you received this file, check http://www.uk.research.att.com/vnc or contact// the authors on vnc@uk.research.att.com for information on obtaining it.// VNC update hook implementation.//#include "VNCHooks.h"#include <stdlib.h>#include <stdio.h>#include <crtdbg.h>/////////////////////////////////////////////////////////////////////////////// Storage for the global data in the DLL// MSVC is bugged - if a default value is missed off from one of the following// variables then that variable is process-specific for some reason!#pragma data_seg(".SharedData")DWORD vnc_thread_id = 0;UINT UpdateRectMessage = 0;UINT CopyRectMessage = 0;UINT MouseMoveMessage = 0;HHOOK hCallWndHook = NULL; // Handle to the CallWnd hookHHOOK hGetMsgHook = NULL; // Handle to the GetMsg hookHHOOK hDialogMsgHook = NULL; // Handle to the DialogMsg hookHHOOK hLLKeyboardHook = NULL; // Handle to LowLevel kbd hookHHOOK hLLMouseHook = NULL; // Handle to LowLevel mouse hook#pragma data_seg( )/////////////////////////////////////////////////////////////////////////////// Per-instance DLL variablesconst char sPrefSegment[] = "Application_Prefs";char *sModulePrefs = NULL; // Name of the module that created usBOOL prf_use_GetUpdateRect = FALSE; // Use the GetUpdateRect paint modeBOOL prf_use_Timer = TRUE; // Use Timer events to trigger updatesBOOL prf_use_KeyPress = TRUE; // Use keyboard eventsBOOL prf_use_LButtonUp = TRUE; // Use left mouse button up eventsBOOL prf_use_MButtonUp = FALSE; // Use middle mouse button up eventsBOOL prf_use_RButtonUp = FALSE; // Use right mouse button up eventsBOOL prf_use_Deferral = TRUE; // Use deferred updatesHINSTANCE hInstance = NULL; // This instance of the DLLBOOL HookMaster = FALSE; // Is this instance WinVNC itself?BOOL appHookedOK = FALSE; // Did InitInstance succeed?ULONG old_cursor = NULL; // Current Cursor icon handle/////////////////////////////////////////////////////////////////////////////// Registered messages & atoms to be used by VNCHooks.DLL// Messagesconst UINT VNC_DEFERRED_UPDATE = RegisterWindowMessage("VNCHooks.Deferred.UpdateMessage");// Atomsconst char *VNC_POPUPSELN_ATOMNAME = "VNCHooks.PopUpMenu.Selected";ATOM VNC_POPUPSELN_ATOM = NULL;/////////////////////////////////////////////////////////////////////////////// The DLL functions// Forward definition of hook proceduresBOOL HookHandle(UINT msg, HWND hWnd, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK CallWndProc (int nCode, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK DialogMessageProc(int nCode, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK LowLevelKeyboardFilterProc(int nCode, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK LowLevelMouseFilterProc(int nCode, WPARAM wParam, LPARAM lParam);// Forward definition of setup and shutdown proceduresBOOL InitInstance();BOOL ExitInstance();// The DLL's main procedureBOOL WINAPI DllMain (HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved){ // Find out why we're being called switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: _RPT0(_CRT_WARN, "vncHooks : Hook DLL loaded\n"); // Save the instance handle hInstance = (HINSTANCE)hInst; // Call the initialisation function appHookedOK = InitInstance(); // ALWAYS return TRUE to avoid breaking unhookable applications!!! return TRUE; case DLL_PROCESS_DETACH: _RPT0(_CRT_WARN, "vncHooks : Hook DLL unloaded\n"); // Call the exit function // If the app failed to hook OK, ExitInstance will still operate OK (hopefully...) ExitInstance(); return TRUE; default: return TRUE; }}// Function used to find out whether VNCHooks uses "reliable" or "hint" hooks// Currently is always zero to indicate unreliable, hint hooks.DllExport DWORD HooksType(){ // Unreliable "hint" hooks return 0;}// Add the new hookDllExport BOOL SetHooks(DWORD thread_id, UINT UpdateMsg, UINT CopyMsg, UINT MouseMsg){ // Don't add the hook if the thread id is NULL if (!thread_id) return FALSE; // Don't add a hook if there is already one added if (vnc_thread_id) return FALSE; // Add the CallWnd hook hCallWndHook = SetWindowsHookEx( WH_CALLWNDPROC, // Hook in before msg reaches app (HOOKPROC) CallWndProc, // Hook procedure hInstance, // This DLL instance 0L // Hook in to all apps// GetCurrentThreadId() // DEBUG : HOOK ONLY WinVNC ); // Add the GetMessage hook hGetMsgHook = SetWindowsHookEx( WH_GETMESSAGE, // Hook in before msg reaches app (HOOKPROC) GetMessageProc, // Hook procedure hInstance, // This DLL instance 0L // Hook in to all apps// GetCurrentThreadId() // DEBUG : HOOK ONLY WinVNC ); // Add the GetMessage hook hDialogMsgHook = SetWindowsHookEx( WH_SYSMSGFILTER, // Hook in dialogs, menus and scrollbars (HOOKPROC) DialogMessageProc, // Hook procedure hInstance, // This DLL instance 0L // Hook in to all apps ); // Check that it worked if ((hCallWndHook != NULL) && (hGetMsgHook != NULL) && (hDialogMsgHook != NULL)) { vnc_thread_id = thread_id; // Save the WinVNC thread id UpdateRectMessage = UpdateMsg; // Save the message ID to use for rectangle updates CopyRectMessage = CopyMsg; // Save the message ID to use for copyrect MouseMoveMessage = MouseMsg; // Save the message ID to send when mouse moves HookMaster = TRUE; // Set the HookMaster flag for this instance return TRUE; } else { // Stop the keyboard hook SetKeyboardFilterHook(FALSE); SetMouseFilterHook(FALSE); // Kill the main hooks if (hCallWndHook != NULL) UnhookWindowsHookEx(hCallWndHook); if (hGetMsgHook != NULL) UnhookWindowsHookEx(hGetMsgHook); if (hDialogMsgHook != NULL) UnhookWindowsHookEx(hDialogMsgHook); hCallWndHook = NULL; hGetMsgHook = NULL; hDialogMsgHook = NULL; } // The hook failed, so return an error code return FALSE;}// EnumWindows procedure to remove the extra property we addedBOOL CALLBACKKillPropsProc(HWND hwnd, LPARAM lParam){ // Remove our custom property... RemoveProp(hwnd, (LPCTSTR) MAKELONG(VNC_POPUPSELN_ATOM, 0)); return TRUE;}// Remove the hook from the systemDllExport BOOL UnSetHooks(DWORD thread_id){ BOOL unHooked = TRUE; // Remove the extra property value from all local windows EnumWindows((WNDENUMPROC) &KillPropsProc, NULL); // Stop the keyboard & mouse hooks unHooked = unHooked && SetKeyboardFilterHook(FALSE); unHooked = unHooked && SetMouseFilterHook(FALSE); // Is the window handle valid? if (thread_id != vnc_thread_id) return FALSE; // Unhook the procs if (hCallWndHook != NULL) { unHooked = unHooked && UnhookWindowsHookEx(hCallWndHook); hCallWndHook = NULL; } if (hGetMsgHook != NULL) { unHooked = unHooked && UnhookWindowsHookEx(hGetMsgHook); hGetMsgHook = NULL; } if (hDialogMsgHook != NULL) { unHooked = unHooked && UnhookWindowsHookEx(hDialogMsgHook); hDialogMsgHook = NULL; } // If we managed to unhook then reset if (unHooked) { vnc_thread_id = 0; HookMaster = FALSE; } return unHooked;}// Routine to start and stop local keyboard message filteringDllExport BOOL SetKeyboardFilterHook(BOOL activate){ if (activate) {#ifdef WH_KEYBOARD_LL if (hLLKeyboardHook == NULL) { // Start up the hook... hLLKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, // Hook in before msg reaches app (HOOKPROC) LowLevelKeyboardFilterProc, // Hook procedure hInstance, // This DLL instance 0L // Hook in to all apps ); if (hLLKeyboardHook == NULL) return FALSE; } return TRUE;#else#pragma message("warning:Low-Level Keyboard hook code omitted.") return FALSE;#endif } else { if (hLLKeyboardHook != NULL) { // Stop the hook... if (!UnhookWindowsHookEx(hLLKeyboardHook)) return FALSE; hLLKeyboardHook = NULL; } return TRUE; }}// Routine to start and stop local mouse message filteringDllExport BOOL SetMouseFilterHook(BOOL activate){ if (activate) {#ifdef WH_MOUSE_LL if (hLLMouseHook == NULL) { // Start up the hook... hLLMouseHook = SetWindowsHookEx( WH_MOUSE_LL, // Hook in before msg reaches app (HOOKPROC) LowLevelMouseFilterProc, // Hook procedure hInstance, // This DLL instance 0L // Hook in to all apps ); if (hLLMouseHook == NULL) return FALSE; } return TRUE;#else#pragma message("warning:Low-Level Mouse hook code omitted.") return FALSE;#endif } else { if (hLLMouseHook != NULL) { // Stop the hook... if (!UnhookWindowsHookEx(hLLMouseHook)) return FALSE; hLLMouseHook = NULL; } return TRUE; }}// Routine to get the window's client rectangle, in screen coordinatesinline BOOL GetAbsoluteClientRect(HWND hwnd, RECT *rect){ POINT topleft; topleft.x = 0; topleft.y = 0; // Get the client rectangle size if (!GetClientRect(hwnd, rect)) return FALSE; // Get the client rectangle position if (!ClientToScreen(hwnd, &topleft)) return FALSE; // Now adjust the window rectangle rect->left += topleft.x; rect->top += topleft.y; rect->right += topleft.x; rect->bottom += topleft.y; return TRUE;}// Routine to send an UpdateRect message to WinVNCinline void SendUpdateRect(SHORT x, SHORT y, SHORT x2, SHORT y2){ WPARAM vwParam; LPARAM vlParam; vwParam = MAKELONG(x, y); vlParam = MAKELONG(x2, y2); // Send the update to WinVNC if (!PostThreadMessage( vnc_thread_id, UpdateRectMessage, vwParam, vlParam )) vnc_thread_id = 0;}// Send a window's position to WinVNCinline void SendWindowRect(HWND hWnd){ RECT wrect; // Get the rectangle position if (IsWindowVisible(hWnd) && GetWindowRect(hWnd, &wrect)) { // Send the position SendUpdateRect( (SHORT) wrect.left, (SHORT) wrect.top, (SHORT) wrect.right, (SHORT) wrect.bottom ); }}// Send a deferred message into this Window's message queue, so that// we'll intercept it again only after the message that triggered it has been// handledinline void SendDeferredUpdateRect(HWND hWnd, SHORT x, SHORT y, SHORT x2, SHORT y2){ WPARAM vwParam; LPARAM vlParam; vwParam = MAKELONG(x, y); vlParam = MAKELONG(x2, y2); if (prf_use_Deferral) { // Send the update back to the window PostMessage( hWnd, VNC_DEFERRED_UPDATE, vwParam, vlParam ); } else { // Send the update to WinVNC if (!PostThreadMessage( vnc_thread_id, UpdateRectMessage, vwParam, vlParam )) vnc_thread_id = 0; }}inline void SendDeferredWindowRect(HWND hWnd){ RECT wrect; // Get the rectangle position if (IsWindowVisible(hWnd) && GetWindowRect(hWnd, &wrect)) { // Send the position SendDeferredUpdateRect( hWnd, (SHORT) wrect.left, (SHORT) wrect.top, (SHORT) wrect.right, (SHORT) wrect.bottom ); }}inline void SendDeferredBorderRect(HWND hWnd){ RECT wrect; RECT crect; // Get the rectangle position if (IsWindowVisible(hWnd) && GetWindowRect(hWnd, &wrect)) { // Get the client rectangle position if (GetAbsoluteClientRect(hWnd, &crect)) { // Send the four border rectangles SendDeferredUpdateRect(hWnd, (SHORT) wrect.left, (SHORT) wrect.top, (SHORT) wrect.right, (SHORT) crect.top); SendDeferredUpdateRect(hWnd, (SHORT) wrect.left, (SHORT) wrect.top, (SHORT) crect.left, (SHORT) wrect.bottom); SendDeferredUpdateRect(hWnd, (SHORT) wrect.left, (SHORT) crect.bottom, (SHORT) wrect.right, (SHORT) wrect.bottom); SendDeferredUpdateRect(hWnd, (SHORT) crect.right, (SHORT) wrect.top, (SHORT) wrect.right, (SHORT) wrect.bottom); } }}// Generic hook-handlerinline BOOL HookHandle(UINT MessageId, HWND hWnd, WPARAM wParam, LPARAM lParam){ //////////////////////////////////////////////////////////////// // HANDLE DEFERRED UPDATES // Is this a deferred-update message? if (MessageId == VNC_DEFERRED_UPDATE) { // NOTE : NEVER use the SendDeferred- routines to send updates // from here, or you'll get an infinite loop....! // NB : The format of DEFERRED_UPDATE matches that of UpdateRectMessage, // so just send the exact same message data to WinVNC if (!PostThreadMessage( vnc_thread_id, UpdateRectMessage, wParam, lParam )) vnc_thread_id = 0; return FALSE; } // *** Could use WM_COPYDATA to send data to WinVNC/* if (GetClassLong(hWnd, GCW_ATOM) == 32768) { _RPT4(_CRT_WARN, "DBG : popup menu message (hwnd=%d, msg=%d, l=%d, w=%d)\n", hWnd, MessageId, lParam, wParam); }*/ //////////////////////////////////////////////////////////////// // UPDATE-TRIGGERING MESSAGES // Do something dependent upon message type switch (MessageId) { //////////////////////////////////////////////////////////////// // Messages indicating only a border repaint. case WM_NCPAINT: case WM_NCACTIVATE: SendDeferredBorderRect(hWnd); old_cursor = NULL; break; //////////////////////////////////////////////////////////////// // Messages indicating a client area repaint case WM_CHAR: case WM_KEYUP: // Handle key-presses if (prf_use_KeyPress) SendDeferredWindowRect(hWnd); break; case WM_LBUTTONUP: // Handle LMB clicks if (prf_use_LButtonUp) SendDeferredWindowRect(hWnd); break; case WM_MBUTTONUP: // Handle MMB clicks if (prf_use_MButtonUp) SendDeferredWindowRect(hWnd); break; case WM_RBUTTONUP: // Handle RMB clicks if (prf_use_RButtonUp) SendDeferredWindowRect(hWnd); break; case WM_MOUSEWHEEL: // Handle mousewheel events SendDeferredWindowRect(hWnd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -