예제 #1
0
        /// <summary>
        ///     Create an observable for the specified Control (Form)
        /// </summary>
        public static IObservable <WindowMessageInfo> WinProcFormsMessages(this Control control)
        {
            var winProcListener = new WinProcListener(control);

            return(Observable.Create <WindowMessageInfo>(observer =>
            {
                winProcListener.AddHook(WindowMessageHandler);
                // This handles the message, and generates the observable OnNext
                IntPtr WindowMessageHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
                {
                    var message = WindowMessageInfo.Create(hwnd, msg, wParam, lParam);
                    observer.OnNext(message);
                    // ReSharper disable once AccessToDisposedClosure
                    if (winProcListener.IsDisposed || message.Message == WindowsMessages.WM_DESTROY)
                    {
                        observer.OnCompleted();
                    }
                    return IntPtr.Zero;
                }

                return Disposable.Create(() =>
                {
                    winProcListener.Dispose();
                });
            })
                   // Make sure there is always a value produced when connecting
                   .Publish()
                   .RefCount());
        }
        /// <summary>
        /// Create an observable for the specified window or HwndSource
        /// </summary>
        /// <param name="window">Window</param>
        /// <param name="hWndSource">HwndSource</param>
        /// <param name="before">Func which does something as soon as the observable is created</param>
        /// <param name="disposeAction">Action which disposes something when the observable is disposed</param>
        /// <returns>IObservable</returns>
        internal static IObservable <WindowMessageInfo> WinProcMessages <TState>(Window window, HwndSource hWndSource, Func <IntPtr, TState> before = null, Action <TState> disposeAction = null)
        {
            if (window == null && hWndSource == null)
            {
                throw new NotSupportedException("One of Window or HwndSource must be supplied");
            }

            return(Observable.Create <WindowMessageInfo>(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));
                    // ReSharper disable once AccessToDisposedClosure
                    if (hWndSource.IsDisposed)
                    {
                        observer.OnCompleted();
                    }
                    return IntPtr.Zero;
                }

                TState state = default;

                void HwndSourceDisposedHandle(object sender, EventArgs e)
                {
                    observer.OnCompleted();
                }

                void RegisterHwndSource()
                {
                    if (before != null)
                    {
                        state = before(hWndSource.Handle);
                    }
                    hWndSource.Disposed += HwndSourceDisposedHandle;
                    hWndSource.AddHook(WindowMessageHandler);
                }

                if (window != null)
                {
                    hWndSource = window.ToHwndSource();
                }
                if (hWndSource != null)
                {
                    RegisterHwndSource();
                }
                else if (window != null)
                {
                    // No, try to get it later
                    window.SourceInitialized += (sender, args) =>
                    {
                        hWndSource = window.ToHwndSource();
                        RegisterHwndSource();
                        // Simulate the WM_NCCREATE
                        observer.OnNext(WindowMessageInfo.Create(hWndSource.Handle, (int)WindowsMessages.WM_NCCREATE, IntPtr.Zero, IntPtr.Zero));
                    };
                }

                return Disposable.Create(() =>
                {
                    disposeAction?.Invoke(state);
                    hWndSource.Disposed -= HwndSourceDisposedHandle;
                    hWndSource.RemoveHook(WindowMessageHandler);
                    hWndSource.Dispose();
                });
            })
                   // Make sure there is always a value produced when connecting
                   .Publish()
                   .RefCount());
        }