• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dapplo / Dapplo.Windows / 22231723592

20 Feb 2026 04:16PM UTC coverage: 33.416% (-0.07%) from 33.49%
22231723592

push

github

Lakritzator
Small fixes for tests and namespaces

611 of 1948 branches covered (31.37%)

Branch coverage included in aggregate %.

2 of 8 new or added lines in 2 files covered. (25.0%)

231 existing lines in 16 files now uncovered.

1668 of 4872 relevant lines covered (34.24%)

30.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Dapplo.Windows.Messages/WinProcHandler.cs
1
// Copyright (c) Dapplo and contributors. All rights reserved.
2
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3

4
using Dapplo.Windows.Messages.Enumerations;
5
#if !NETSTANDARD2_0
6
using System;
7
using System.Collections.Generic;
8
using System.Diagnostics.CodeAnalysis;
9
using System.Linq;
10
using System.Reactive.Disposables;
11
using System.Windows.Interop;
12

13
namespace Dapplo.Windows.Messages
14
{
15
    /// <summary>
16
    ///     This can be used to handle WinProc messages, for instance when there is no running WinProc
17
    /// </summary>
18
    public class WinProcHandler
19
    {
20
        private static HwndSource _hWndSource;
21

22
        /// <summary>
23
        ///     Hold the singleton
24
        /// </summary>
UNCOV
25
        private static readonly Lazy<WinProcHandler> Singleton = new Lazy<WinProcHandler>(() => new WinProcHandler());
×
26

27
        /// <summary>
28
        ///     Store hooks, so they can be removed
29
        /// </summary>
UNCOV
30
        private List<WinProcHandlerHook> _hooks = new List<WinProcHandlerHook>();
×
31

32
        /// <summary>
33
        ///     Special HwndSource which is only there for handling messages, is top-level (no parent) to be able to handle ALL windows messages
34
        /// </summary>
35
        [SuppressMessage("Sonar Code Smell", "S2696:Instance members should not write to static fields", Justification = "Instance member needs access to the _hooks, this is checked!")]
36
        public HwndSource MessageHandlerWindow
37
        {
38
            get
39
            {
40
                // Special code to make sure the _hWndSource is (re)created when it's not yet there or disposed
41
                // For example in xUnit tests when WpfFact is used, the _hWndSource is disposed.
UNCOV
42
                if (_hWndSource != null && !_hWndSource.IsDisposed)
×
43
                {
UNCOV
44
                    return _hWndSource;
×
45
                }
46
                // Create a new message window
UNCOV
47
                _hWndSource = CreateMessageWindow();
×
UNCOV
48
                _hWndSource.Disposed += (sender, args) =>
×
UNCOV
49
                {
×
UNCOV
50
                    UnsubscribeAllHooks();
×
UNCOV
51
                };
×
52
                // Hook automatic removing of all the hooks
UNCOV
53
                _hWndSource.AddHook((IntPtr hWnd, int msg, IntPtr param, IntPtr lParam, ref bool handled) =>
×
UNCOV
54
                {
×
UNCOV
55
                    var windowsMessage = (WindowsMessages)msg;
×
UNCOV
56
                    if (windowsMessage != WindowsMessages.WM_NCDESTROY)
×
UNCOV
57
                    {
×
UNCOV
58
                        return IntPtr.Zero;
×
UNCOV
59
                    }
×
UNCOV
60

×
UNCOV
61
                    // The hooks are no longer valid, either there is no _hWndSource or it was disposed.
×
UNCOV
62
                    _hooks = null;
×
UNCOV
63
                    return IntPtr.Zero;
×
UNCOV
64
                });
×
UNCOV
65
                return _hWndSource;
×
66
            }
67
        }
68

69
        /// <summary>
70
        ///     The actual handle for the HwndSource
71
        /// </summary>
UNCOV
72
        public IntPtr Handle => MessageHandlerWindow.Handle;
×
73

74
        /// <summary>
75
        ///     Singleton instance of the WinProcHandler
76
        /// </summary>
UNCOV
77
        public static WinProcHandler Instance => Singleton.Value;
×
78

79
        /// <summary>
80
        ///     Subscribe a hook to handle messages
81
        /// </summary>
82
        /// <param name="winProcHandlerHook">WinProcHandlerHook</param>
83
        /// <returns>IDisposable which unsubscribes the hWndSourceHook when Dispose is called</returns>
84
        public IDisposable Subscribe(WinProcHandlerHook winProcHandlerHook)
85
        {
UNCOV
86
            if (_hooks != null && _hooks.Contains(winProcHandlerHook))
×
87
            {
88
                return Disposable.Empty;
×
89
            }
90

UNCOV
91
            MessageHandlerWindow.AddHook(winProcHandlerHook.Hook);
×
92

93
            // Clone and add
UNCOV
94
            var newHooks = _hooks?.ToList() ?? new List<WinProcHandlerHook>();
×
UNCOV
95
            newHooks.Add(winProcHandlerHook);
×
UNCOV
96
            _hooks = newHooks;
×
UNCOV
97
            return Disposable.Create(() =>
×
UNCOV
98
            {
×
UNCOV
99
                Unsubscribe(winProcHandlerHook);
×
UNCOV
100
            });
×
101
        }
102

103
        /// <summary>
104
        ///     Unsubscribe a hook
105
        /// </summary>
106
        /// <param name="winProcHandlerHook">WinProcHandlerHook</param>
107
        private void Unsubscribe(WinProcHandlerHook winProcHandlerHook)
108
        {
UNCOV
109
            MessageHandlerWindow.RemoveHook(winProcHandlerHook.Hook);
×
110

UNCOV
111
            if (_hooks == null)
×
112
            {
113
                return;
×
114
            }
115

116
            // Clone and remove
UNCOV
117
            var newHooks = _hooks.ToList();
×
UNCOV
118
            newHooks.Remove(winProcHandlerHook);
×
UNCOV
119
            _hooks = newHooks;
×
UNCOV
120
            winProcHandlerHook.Disposable?.Dispose();
×
UNCOV
121
        }
×
122

123
        /// <summary>
124
        ///     Unsubscribe all current hooks
125
        /// </summary>
126
        public void UnsubscribeAllHooks()
127
        {
UNCOV
128
            foreach (var winProcHandlerHook in _hooks ?? Enumerable.Empty<WinProcHandlerHook>())
×
129
            {
UNCOV
130
                MessageHandlerWindow.RemoveHook(winProcHandlerHook.Hook);
×
UNCOV
131
                winProcHandlerHook.Disposable?.Dispose();
×
132
            }
UNCOV
133
            _hooks = null;
×
UNCOV
134
        }
×
135

136
        /// <summary>
137
        /// Creates a HwndSource to catch windows message
138
        /// </summary>
139
        /// <param name="parent">IntPtr for the parent, this should usually not be set</param>
140
        /// <param name="title">Title of the window, a default is already set</param>
141
        /// <returns>HwndSource</returns>
142
        public static HwndSource CreateMessageWindow(IntPtr parent = default, string title = "Dapplo.MessageHandlerWindow")
143
        {
UNCOV
144
            return new HwndSource(new HwndSourceParameters
×
UNCOV
145
            {
×
UNCOV
146
                ParentWindow = parent,
×
UNCOV
147
                Width = 0,
×
UNCOV
148
                Height = 0,
×
UNCOV
149
                PositionX = 0,
×
UNCOV
150
                PositionY = 0,
×
UNCOV
151
                AcquireHwndFocusInMenuMode = false,
×
UNCOV
152
                ExtendedWindowStyle = 0, // ExtendedWindowStyleFlags.WS_NONE
×
UNCOV
153
                WindowStyle = 0, // WindowStyleFlags.WS_OVERLAPPED
×
UNCOV
154
                WindowClassStyle = 0,
×
UNCOV
155
                WindowName = title
×
UNCOV
156
            });
×
157
        }
158
    }
159
}
160
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc