// Greenshot - a free and open source screenshot tool // Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot // // 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.Reactive.Disposables; using System.Reactive.Linq; using System.Windows; using System.Windows.Interop; namespace Greenshot.Addon.Win10.Native { /// /// A monitor for window messages /// public static class WindowMessageMonitor { /// /// Create a HwndSource for the specified Window /// /// Window /// HwndSource private static HwndSource ToHwndSource(this Window window) { IntPtr windowHandle = new WindowInteropHelper(window).Handle; if (windowHandle == IntPtr.Zero) { return null; } return HwndSource.FromHwnd(windowHandle); } /// /// Create an observable for the specified window /// public static IObservable WindowMessages(this Window window) { return WindowMessages(window, null); } /// /// Create an observable for the specified HwndSource /// public static IObservable WindowMessages(this HwndSource hwndSource) { return WindowMessages(null, hwndSource); } /// /// Create an observable for the specified window or HwndSource /// /// Window /// HwndSource /// IObservable private static IObservable WindowMessages(Window window, HwndSource hwndSource) { if (window == null && hwndSource == null) { throw new NotSupportedException("One of Window or HwndSource must be supplied"); } if (window != null && hwndSource != null) { throw new NotSupportedException("Either Window or HwndSource must be supplied"); } return Observable.Create(observer => { // This handles the message, and generates the observable OnNext IntPtr WindowMessageHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { observer.OnNext(WindowMessageInfo.Create(hwnd, msg, wParam, lParam, ref handled)); // ReSharper disable once AccessToDisposedClosure if (hwndSource.IsDisposed) { observer.OnCompleted(); } return IntPtr.Zero; } void HwndSourceDisposedHandle(object sender, EventArgs e) { observer.OnCompleted(); } void RegisterHwndSource() { hwndSource.Disposed += HwndSourceDisposedHandle; hwndSource.AddHook(WindowMessageHandler); } if (window != null) { hwndSource = window.ToHwndSource(); } if (hwndSource != null) { RegisterHwndSource(); } else { // No, try to get it later window.SourceInitialized += (sender, args) => { hwndSource = window.ToHwndSource(); RegisterHwndSource(); }; } return Disposable.Create(() => { hwndSource.Disposed -= HwndSourceDisposedHandle; hwndSource.RemoveHook(WindowMessageHandler); hwndSource.Dispose(); }); }) // Make sure there is always a value produced when connecting .Publish() .RefCount(); } } }