/* * dapplo - building blocks for desktop applications * Copyright (C) Dapplo 2015-2016 * * For more information see: http://dapplo.net/ * dapplo repositories are hosted on GitHub: https://github.com/dapplo * * This program 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 1 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, see . */ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using GreenshotPlugin.UnmanagedHelpers; namespace GreenshotJiraPlugin.Hooking { /// /// The WinEventHook can register handlers to become important windows events /// This makes it possible to know a.o. when a window is created, moved, updated and closed. /// public class WindowsEventHook : IDisposable { private readonly WinEventDelegate _winEventHandler; private GCHandle _gcHandle; /// /// Used with Register hook /// /// /// /// /// /// /// public delegate void WinEventHandler(WinEvent eventType, IntPtr hwnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); /// /// Create a WindowsEventHook object /// public WindowsEventHook() { _winEventHandler = WinEventDelegateHandler; _gcHandle = GCHandle.Alloc(_winEventHandler); } #region native code [DllImport("user32", SetLastError = true)] private static extern bool UnhookWinEvent(IntPtr hWinEventHook); [DllImport("user32", SetLastError = true)] private static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, WinEventHookFlags dwFlags); /// /// Used with SetWinEventHook /// /// /// /// /// /// /// /// private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hwnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); #endregion private readonly IDictionary _winEventHandlers = new Dictionary(); /// /// Are hooks active? /// public bool IsHooked => _winEventHandlers.Count > 0; /// /// Hook a WinEvent /// /// /// /// true if success public void Hook(WinEvent winEvent, WinEventHandler winEventHandler) { Hook(winEvent, winEvent, winEventHandler); } /// /// Hook a WinEvent /// /// /// /// public void Hook(WinEvent winEventStart, WinEvent winEventEnd, WinEventHandler winEventHandler) { var hookPtr = SetWinEventHook(winEventStart, winEventEnd, IntPtr.Zero, _winEventHandler, 0, 0, WinEventHookFlags.WINEVENT_SKIPOWNPROCESS | WinEventHookFlags.WINEVENT_OUTOFCONTEXT); _winEventHandlers.Add(hookPtr, winEventHandler); } /// /// Remove all hooks /// private void Unhook() { foreach (var hookPtr in _winEventHandlers.Keys) { if (hookPtr != IntPtr.Zero) { UnhookWinEvent(hookPtr); } } _winEventHandlers.Clear(); _gcHandle.Free(); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Unhook(); } /// /// Call the WinEventHandler for this event /// /// /// /// /// /// /// /// private void WinEventDelegateHandler(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { WinEventHandler handler; if (_winEventHandlers.TryGetValue(hWinEventHook, out handler)) { handler(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime); } } } }