winvda
Hardened, zero-cached-state Virtual Desktop engine for Windows 10 and 11.
winvda is a lightweight Python library for managing virtual desktops and application pinning on Windows 10 and Windows 11. It is designed specifically for voice control frameworks (Caster, Talon Voice), window managers, and automated desktop environments that require high stability.
Key Improvements Over Legacy pyvda
| Dimension | Legacy pyvda |
winvda |
|---|---|---|
| COM Proxy Lifetime | Stateful proxies held across arbitrary time. Corrupts on Explorer restart. | Zero-Cached-State: Interface pointers acquired and released inside call scope (< 0.02 ms). |
| Explorer Crash Immunity | Crashes with RPC_S_SERVER_UNAVAILABLE. Requires manual process restart. |
100% Immune: Automatically binds to newly spawned Explorer instances. |
| Threading & Apartments | Thread-local manager leaks COM pointers across threads (RPC_E_WRONG_THREAD). |
Stateless Value Objects: Domain objects are frozen dataclasses with zero COM pointers. |
| Multi-Window App Pinning | Fails on secondary Windows Terminal and modern editor windows due to ~Wh~ sub-AUMIDs. |
Task View Parity: Strips sub-AUMID tokens and pins views individually, matching twinui.pcshell.dll. |
| Runtime Dependencies | Requires comtypes. |
Zero external dependencies: Pure standard library ctypes. |
Quickstart
import winvda
# 1. Enumerate all virtual desktops
desktops = winvda.get_desktops()
for d in desktops:
print(f"Desktop {d.number}: {d.name} ({d.id})")
# 2. Get current desktop
current = winvda.get_current_desktop()
print(f"Currently on: {current.name}")
# 3. Switch to desktop 2 (by number, UUID, or object)
winvda.switch_desktop(2)
# 4. Pin a window to all desktops
winvda.pin_window(hwnd)
# 5. Pin an entire application (including multi-window / XAML Island instances)
winvda.pin_app(hwnd)
Command Line Interface (CLI)
winvda includes a diagnostic and automation CLI:
# List all desktops and active state
python -m winvda list
# Switch to desktop 3
python -m winvda switch 3
# Pin active foreground window (used by background hotkey daemons / shortcuts)
python -m winvda pin-window
# Pin specific window by HWND (used by scripts / tiling window managers)
python -m winvda pin-window --hwnd 0x1a2b3c
# Wait 2 seconds before capturing foreground window (for interactive terminal use)
python -m winvda pin-window --delay 2
# Pin active application across all desktops
python -m winvda pin-app
Threading Model & COM Apartment Architecture
Windows Virtual Desktop management communicates with explorer.exe via out-of-process COM RPC. Standard COM wrappers hold long-lived interface pointers and force Single-Threaded Apartment (STA) modes, leading to process instability. winvda uses three structural design patterns to guarantee resilience:
1. Zero-Cached-State Invocation
winvda never persists COM interface pointers in Python instances across calls:
- Every operation executes inside a call-scoped transient session (< 0.02 ms).
- Fresh pointers (
IServiceProvider,IVirtualDesktopManagerInternal) are acquired directly from the activeexplorer.exeinstance, invoked atomically, and released immediately. - When
explorer.exeterminates, restarts, or crashes, no dead ALPC proxy stubs remain in memory. The subsequent command automatically binds to the newly spawned Explorer process without restart-polling loops or reactive retry decorators. - If a call occurs during the millisecond window while Explorer is down,
winvdaraises a typedShellUnavailableErrorinstead of crashing.
2. Multi-Threaded Apartment (MTA) & Caller Apartment Compatibility
Voice recognition engines (Caster, Talon), async executors, and window managers run on multi-threaded background workers:
winvdajoins the Multi-Threaded Apartment (COINIT_MULTITHREADED) on invocation, allowing concurrent execution without UI message pumps.- If the calling thread was already initialized into an STA apartment (by a GUI framework or
pywinauto),winvdadetectsRPC_E_CHANGED_MODE(0x80010106), executes safely within the caller's existing apartment, and preserves the caller's threading state upon exit.
3. Stateless Value Objects
Domain entities (VirtualDesktop, WindowView) are immutable frozen dataclasses containing purely primitive data (UUID, int, str, bool):
- Value objects store zero COM pointers or RPC proxies.
- They can cross thread boundaries freely, be stored indefinitely, and serialize directly to JSON without triggering
RPC_E_WRONG_THREAD.
Architecture & Specification
Comprehensive architectural specifications, domain model definitions, error taxonomies, and Windows build matrices are documented in docs/SPECIFICATION.md.
Community & Security
- Contributing: Development setup, testing workflows, and pull request guidelines are documented in
CONTRIBUTING.md. - Security Policy: Vulnerability disclosure instructions and reporting channels are detailed in
SECURITY.md.
License & Prior Art
Distributed under the Apache License, Version 2.0. See LICENSE.txt for details.
See ACKNOWLEDGMENTS.md for full citations of prior art including Michael Roberts (pyvda) and Jari Pennanen (VirtualDesktopAccessor).
Metadata
Release files for winvda 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| winvda-0.1.0.tar.gz | 30.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| winvda-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.2 kB
Release files / winvda-0.1.0.tar.gz
| Download URL | winvda-0.1.0.tar.gz |
|---|---|
| Size | 30.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1f4c03cb9923745893c4d067680a780fb64f32aa861f407e2a8bdcbabb89eca2
|
|
BLAKE2b-256 checksum How to use checksums |
0baca1f36f1ac6361b58956f7c778d93dae14b8f6946079e45a300b24e7c2854
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / winvda-0.1.0-py3-none-any.whl
| Download URL | winvda-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f146fb26fd7b81dd4348a368745eca08853723101cca4432a0088dc376df8ca5
|
|
BLAKE2b-256 checksum How to use checksums |
1a154ee853e08fcc678cfeeb8de7b070002f803e3afff1dcb9689c1dad4c5145
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log