Dapplo.Windows gives .NET applications on Windows access to what .NET itself doesn't cover: windows and their events, keyboard and mouse hooks, the clipboard, DPI awareness, power management, the Restart Manager, file dialogs and more. It was built for Greenshot and is split into small packages, so you only install what you use.
Documentation: https://www.dapplo.net/Dapplo.Windows/ (guides with samples and the API reference)
- Windows
- .NET Framework 4.8 or .NET 10 (the packages target
net480andnet10.0-windows)
Upgrading from 2.x? Version 3.0 changes many APIs on purpose: read the migration guide and the changelog.
| Package | NuGet | What it's for | Depends on (Dapplo.Windows.*) |
|---|---|---|---|
| Dapplo.Windows | Window information, enumeration and manipulation, WinEvent hooks, window screenshots and icons | Common, Com, DesktopWindowsManager, Gdi32, Icons, Input, Kernel32, Messages, User32 | |
| Dapplo.Windows.Automation | UI Automation: scroll windows which draw their own scroll bars (browsers, WPF, Office), e.g. for a scrolling capture | Dapplo.Windows, Common, Input, User32 | |
| Dapplo.Windows.Clipboard | Monitor, read and write the clipboard, delayed rendering, clipboard history options | Kernel32, Messages | |
| Dapplo.Windows.Input | Keyboard and mouse hooks, hotkeys and key sequences, generating input, raw input | Common, Messages, User32 | |
| Dapplo.Windows.Dpi | DPI calculations, DPI change handling, bitmap scaling, DPI awareness APIs | Common, Gdi32, Messages, User32 | |
| Dapplo.Windows.Forms | Windows Forms integration: DpiAwareForm, window messages of controls, placement |
Dapplo.Windows, Dpi, Messages | |
| Dapplo.Windows.Wpf | WPF integration: DPI handling, window messages, conversions, BitmapSource |
Dapplo.Windows, Dpi, Gdi32, Messages | |
| Dapplo.Windows.Messages | SharedMessageWindow for window messages without a window, session notifications |
Common | |
| Dapplo.Windows.SystemState | Prevent sleep, sleep / shut down / log off, wake timers, power events | Messages | |
| Dapplo.Windows.AppRestartManager | Register for restart, answer shutdown and Restart Manager requests | Messages | |
| Dapplo.Windows.InstallerManager | For installers: find, close and restart the processes which lock files | - | |
| Dapplo.Windows.Dialogs | File open, file save and folder dialogs without WinForms or WPF | Common | |
| Dapplo.Windows.Icons | Extract icons, write ICO and CUR files, capture the mouse cursor | Common, Dpi, Gdi32, Kernel32, Messages, Shell32, User32 | |
| Dapplo.Windows.Devices | Device and volume arrival / removal notifications | Messages | |
| Dapplo.Windows.DesktopWindowsManager | DWM: frame bounds, cloaking, accent color, corners | Common | |
| Dapplo.Windows.Citrix | Citrix session detection and client information | Common | |
| Dapplo.Windows.EmbeddedBrowser | Let the WinForms WebBrowser use the installed IE version |
Com | |
| Dapplo.Windows.Multimedia | Play system sounds and WAV data | - | |
| Dapplo.Windows.Advapi32 | Registry change notifications, logon SID | - | |
| Dapplo.Windows.User32 | User32 P/Invoke: windows, displays, messages | Common, Messages | |
| Dapplo.Windows.Gdi32 | GDI / GDI+ P/Invoke and safe handles | Common, User32 | |
| Dapplo.Windows.Kernel32 | Kernel32 P/Invoke: processes, DLL loading, package identity | Common | |
| Dapplo.Windows.Shell32 | Shell32 P/Invoke: taskbar, icons | Common | |
| Dapplo.Windows.Com | COM helpers | Common | |
| Dapplo.Windows.Common | Shared structs (NativeRect, ...), HResult, WindowsVersion |
- |
Only Dapplo.Windows.Forms, Dapplo.Windows.Wpf and Dapplo.Windows.EmbeddedBrowser reference Windows Forms or WPF.
dotnet add package Dapplo.Windows
dotnet add package Dapplo.Windows.Clipboard
dotnet add package Dapplo.Windows.InputReact to window title changes:
// using Dapplo.Windows.Desktop; using System.Reactive.Linq;
IDisposable subscription = WinEventHook.WindowTitleChangeObservable()
.Subscribe(info =>
{
var window = InteropWindowFactory.CreateFor(info.Handle);
Console.WriteLine($"Title changed: {window.GetCaption(forceUpdate: true)}");
});Log the text that is copied to the clipboard:
// using Dapplo.Windows.Clipboard; using System.Reactive.Linq;
IDisposable subscription = ClipboardNative.OnUpdate
.Where(info => info.FormatIds.Contains((uint)StandardClipboardFormats.UnicodeText))
.Throttle(TimeSpan.FromMilliseconds(100))
.Subscribe(info =>
{
using var clipboard = ClipboardNative.Access();
Console.WriteLine($"Copied: {clipboard.GetAsUnicodeString()}");
});A global hotkey:
// using Dapplo.Windows.Input.Enums; using Dapplo.Windows.Input.Keyboard; using System.Reactive.Linq;
// Ctrl+Shift+S anywhere in Windows. The handler runs on the hook thread, ObserveOn moves the work to the UI thread.
IDisposable subscription = KeyboardHook.KeyboardEvents
.Where(new KeyCombinationHandler(VirtualKeyCode.Control, VirtualKeyCode.Shift, VirtualKeyCode.KeyS))
.ObserveOn(SynchronizationContext.Current)
.Subscribe(_ => Console.WriteLine("Ctrl+Shift+S pressed"));Events arrive on background threads (the hook thread or the thread of the SharedMessageWindow): keep your handlers
short and use ObserveOn for UI work. Getting started explains why.
- Getting started
- Window management
- Window messages and the SharedMessageWindow
- Keyboard and mouse
- Clipboard
- DPI awareness
- Power and system state
- Restart Manager
- Icons and cursors
- File and folder dialogs
- Windows Forms and WPF
- More packages
- Common scenarios
- API reference
The wiki has short versions of these pages.
- Dapplo.Windows.Example.ConsoleDemo: keyboard hook in a console application
- Dapplo.Windows.Example.FormsExample: DPI-aware forms, context menus and bitmap scaling, embedded browser, restart registration
- Dapplo.Windows.Example.WpfExample: WPF window with DPI handling, keyboard hook and device notifications
- Dapplo.Windows.Example.InstallerExample: an "installer" which closes and restarts the FormsExample with the Restart Manager
- Dapplo.Windows.Example.DocSamples: every code sample of the documentation, compiled with each build
You need the .NET 10 SDK (see global.json) on Windows.
dotnet build src/Dapplo.Windows.sln
dotnet test src/Dapplo.Windows.sln --filter "Category!=Interactive"Tests with Category=Interactive send input, replace the clipboard or write to the registry; run them only on a
machine you're not using. tools/build-runner builds and tests on a Windows machine on
request, for tools which can only write files into the repository.
When you change a code sample, change it in src/Dapplo.Windows.Example.DocSamples and copy it into the markdown, see
About the samples.
Every merge to master is a release. The build computes the version with Nerdbank.GitVersioning
(src/version.json: major.minor plus the number of commits since the version last changed, e.g. 3.2.1, 3.2.4, …), packs
everything and then waits for approval of the NuGet environment. After approval it pushes the packages to nuget.org, creates
the tag and the GitHub release and publishes the documentation and the wiki. For a new minor or major version, change
version in src/version.json.
The release notes come from CHANGELOG.md. Because the patch number is only known when the release is built,
write the changes of a new minor version under ## [3.2.0] (the first release of 3.2 uses it), and later fixes under
## [Unreleased]. A section with the exact version (## [3.2.4]) always wins. Without a matching section GitHub generates
the notes from the merged pull requests.
Issues and pull requests are welcome. Please add an entry to CHANGELOG.md for user-visible changes.
MIT, see LICENSE.