• 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.Devices/DeviceNotification.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 System;
5
using System.ComponentModel;
6
using System.Reactive.Linq;
7
using System.Runtime.InteropServices;
8
using Dapplo.Windows.Devices.Enums;
9
using Dapplo.Windows.Devices.Structs;
10
using Dapplo.Windows.Messages;
11
using Dapplo.Windows.Messages.Enumerations;
12
using Dapplo.Windows.Messages.Native;
13

14
#if !NETSTANDARD2_0
15

16
namespace Dapplo.Windows.Devices
17
{
18
    /// <summary>
19
    /// 
20
    /// </summary>
21
    public static class DeviceNotification
22
    {
23
        /// <summary>
24
        /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerdevicenotificationw">RegisterDeviceNotificationW function</a>
25
        /// Registers the device or type of device for which a window will receive notifications.
26
        /// </summary>
27
        /// <param name="hRecipient">IntPtr</param>
28
        /// <param name="notificationFilter">DevBroadcastDeviceInterface</param>
29
        /// <param name="flags">DeviceNotifyFlags</param>
30
        /// <returns>IntPtr with the device notification handle</returns>
31
        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
32
        private static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, in DevBroadcastDeviceInterface notificationFilter, DeviceNotifyFlags flags);
33

34
        /// <summary>
35
        /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-unregisterdevicenotification">UnregisterDeviceNotification function</a>
36
        /// </summary>
37
        /// <param name="handle">IntPtr with device notification handle from RegisterDeviceNotification</param>
38
        /// <returns></returns>
39
        [DllImport("user32.dll")]
40
        private static extern bool UnregisterDeviceNotification(IntPtr handle);
41

42
        /// <summary>
43
        ///     This observable publishes the current clipboard contents after every paste action.
44
        ///     Best to use SubscribeOn with the UI SynchronizationContext.
45
        /// </summary>
UNCOV
46
        public static IObservable<DeviceNotificationEvent> OnNotification { get; }
×
47

48
        /// <summary>
49
        ///     Private constructor to create the default DeviceNotifications observable
50
        /// </summary>
51
        static DeviceNotification()
52
        {
UNCOV
53
            OnNotification = CreateDeviceNotificationObservable();
×
54
        }
×
55

56
        /// <summary>
57
        /// Create a specific DeviceNotification IObservable
58
        /// </summary>
59
        /// <param name="deviceInterfaceClass">DeviceInterfaceClass</param>
60
        /// <returns>IObservable of DeviceNotificationEvent</returns>
61
        public static IObservable<DeviceNotificationEvent> CreateDeviceNotificationObservable(DeviceInterfaceClass deviceInterfaceClass = DeviceInterfaceClass.Unknown)
62
        {
UNCOV
63
            if (deviceInterfaceClass == DeviceInterfaceClass.Unknown && OnNotification != null)
×
64
            {
UNCOV
65
                return OnNotification;
×
66
            }
67

UNCOV
68
            return Observable.Create<DeviceNotificationEvent>(observer =>
×
69
                {
×
70
                    var devBroadcastDeviceInterface = DevBroadcastDeviceInterface.Create();
×
71

×
72
                    var deviceNotifyFlags = DeviceNotifyFlags.WindowHandle;
×
73
                    // Use the specified class
×
74
                    if (deviceInterfaceClass != DeviceInterfaceClass.Unknown)
×
75
                    {
×
76
                        devBroadcastDeviceInterface.DeviceClass = deviceInterfaceClass;
×
77
                    }
×
78
                    else
×
79
                    {
×
80
                        // React to all interface classes
×
81
                        deviceNotifyFlags |= DeviceNotifyFlags.AllInterfaceClasses;
×
82
                    }
×
83

×
84
                    IntPtr deviceNotificationHandle = IntPtr.Zero;
×
85

×
86
                    return SharedMessageWindow.Listen(
×
87
                        onSetup: hwnd =>
×
88
                        {
×
89
                            deviceNotificationHandle = RegisterDeviceNotification((IntPtr)hwnd, devBroadcastDeviceInterface, deviceNotifyFlags);
×
90
                            if (deviceNotificationHandle == IntPtr.Zero)
×
91
                            {
×
92
                                observer.OnError(new Win32Exception());
×
93
                            }
×
94
                        },
×
95
                        onTeardown: hwnd => UnregisterDeviceNotification(deviceNotificationHandle)
×
96
                    )
×
97
                    .Where(m => m.Msg == (uint)WindowsMessages.WM_DEVICECHANGE && m.LParam != 0)
×
98
                    .Subscribe(m =>
×
99
                    {
×
100
                        observer.OnNext(new DeviceNotificationEvent((IntPtr)m.WParam, (IntPtr)m.LParam));
×
101
                    }, observer.OnError, observer.OnCompleted);
×
102
                })
×
103
                // Make sure there is always a value produced when connecting
×
104
                .Publish()
×
105
                .RefCount();
×
106
        }
107

108
        /// <summary>
109
        /// A simplification for on device arrival
110
        /// </summary>
111
        /// <param name="observable">Optional IObservable</param>
112
        /// <returns>IObservable with DeviceInterfaceInfo</returns>
113
        public static IObservable<DeviceInterfaceChangeInfo> OnDeviceArrival(IObservable<DeviceNotificationEvent> observable = null)
114
        {
115
            
116
            return (observable ?? OnNotification)
×
UNCOV
117
                .Where(deviceNotificationEvent => deviceNotificationEvent.EventType == DeviceChangeEvent.DeviceArrival && deviceNotificationEvent.Is(DeviceBroadcastDeviceType.DeviceInterface))
×
UNCOV
118
                .Select(deviceNotificationEvent =>
×
UNCOV
119
                    {
×
UNCOV
120
                        deviceNotificationEvent.TryGetDevBroadcastDeviceInterface(out var devBroadcastDeviceInterface);
×
UNCOV
121
                        return new DeviceInterfaceChangeInfo
×
UNCOV
122
                        {
×
UNCOV
123
                            EventType = deviceNotificationEvent.EventType,
×
UNCOV
124
                            Device = devBroadcastDeviceInterface
×
UNCOV
125
                        };
×
UNCOV
126
                    });
×
127
        }
128

129
        /// <summary>
130
        /// A simplification for on device remove complete
131
        /// </summary>
132
        /// <param name="observable">Optional IObservable</param>
133
        /// <returns>IObservable with DeviceInterfaceInfo</returns>
134
        public static IObservable<DeviceInterfaceChangeInfo> OnDeviceRemoved(IObservable<DeviceNotificationEvent> observable = null)
135
        {
136
            return (observable ?? OnNotification)
×
137
                .Where(deviceNotificationEvent => deviceNotificationEvent.EventType == DeviceChangeEvent.DeviceRemoveComplete && deviceNotificationEvent.Is(DeviceBroadcastDeviceType.DeviceInterface))
×
UNCOV
138
                .Select(deviceNotificationEvent =>
×
UNCOV
139
                {
×
UNCOV
140
                    deviceNotificationEvent.TryGetDevBroadcastDeviceInterface(out var devBroadcastDeviceInterface);
×
UNCOV
141
                    return new DeviceInterfaceChangeInfo
×
UNCOV
142
                    {
×
UNCOV
143
                        EventType = deviceNotificationEvent.EventType,
×
UNCOV
144
                        Device = devBroadcastDeviceInterface
×
UNCOV
145
                    };
×
UNCOV
146
                });
×
147
        }
148

149
        /// <summary>
150
        /// Get all Volume changes
151
        /// </summary>
152
        /// <param name="observable">Optional IObservable</param>
153
        /// <returns>IObservable with VolumeInfo</returns>
154
        public static IObservable<VolumeInfo> OnVolumeChanges(IObservable<DeviceNotificationEvent> observable = null)
155
        {
156
            return (observable ?? OnNotification)
×
157
                .Where(deviceNotificationEvent => deviceNotificationEvent.Is(DeviceBroadcastDeviceType.Volume))
×
UNCOV
158
                .Select(deviceNotificationEvent =>
×
UNCOV
159
                {
×
UNCOV
160
                    deviceNotificationEvent.TryGetDevBroadcastVolume(out var devBroadcastVolume);
×
UNCOV
161
                    return new VolumeInfo
×
UNCOV
162
                    {
×
UNCOV
163
                        EventType = deviceNotificationEvent.EventType,
×
UNCOV
164
                        Volume = devBroadcastVolume
×
UNCOV
165
                    };
×
UNCOV
166
                });
×
167
        }
168

169
        /// <summary>
170
        /// A simplification for volume added
171
        /// </summary>
172
        /// <param name="observable">Optional IObservable</param>
173
        /// <returns>IObservable with VolumeInfo</returns>
174
        public static IObservable<VolumeInfo> OnVolumeAdded(IObservable<DeviceNotificationEvent> observable = null)
175
        {
176
            return OnVolumeChanges(observable)
×
177
                .Where(volumeInfo => volumeInfo.EventType == DeviceChangeEvent.DeviceArrival);
×
178
        }
179

180
        /// <summary>
181
        /// A simplification for volume removed
182
        /// </summary>
183
        /// <param name="observable">Optional IObservable</param>
184
        /// <returns>IObservable with VolumeInfo</returns>
185
        public static IObservable<VolumeInfo> OnVolumeRemoved(IObservable<DeviceNotificationEvent> observable = null)
186
        {
187
            return OnVolumeChanges(observable)
×
188
                .Where(volumeInfo => volumeInfo.EventType == DeviceChangeEvent.DeviceRemoveComplete);
×
189
        }
190
    }
191
}
192

193
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc