Library / SDK
Ciantic/VirtualDesktopAccessor avatar
Ciantic/VirtualDesktopAccessor

VirtualDesktopAccessor: driving Windows 11 virtual desktops from a script

DLL for accessing Windows 11/10 Virtual Desktop features from e.g. AutoHotkey

1,118 stars117 forksRustMIT

At a glance

What is it?
VirtualDesktopAccessor is an MIT licensed Windows DLL and Rust library that exposes Windows 11 virtual desktop operations to AutoHotkey and other callers, with a flat function list that returns -1 for every failure.
Who is it for?
Adopt VirtualDesktopAccessor if your automation needs to place a window on a specific Windows 11 virtual desktop and you can pin your deployment to build 26100.2605 or newer. Skip it if you support older Windows releases, if you need documented error codes, or if you are shipping a product where an undocumented shell interface might change without notice.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap between Task View and a scriptable desktop

Windows lets you build virtual desktops by hand, but a script has no supported way to ask the shell which desktop a window belongs to, or to move a window onto another one. VirtualDesktopAccessor fills that gap. The project description calls it a DLL for accessing Windows 11 virtual desktop features from e.g. AutoHotkey, and the repository ships two AutoHotkey examples, example.ahk for AutoHotkey V1 and example.ah2 for AutoHotkey V2. That pairing tells you the intended audience: people writing window management shortcuts, launcher macros and productivity scripts who need precise control over which desktop a window lands on. The crate description for the Rust side is blunter still: it provides functions for accessing the Windows 11 virtual desktop API, requires at least 24H2 26100.2605. Everything the project offers is built around that single requirement, so the OS version is the first thing to check before anything else.

A flat export list instead of a COM dance

The mechanism is a native DLL with a small, deliberately unadorned export list. Every entry point takes plain handles and integers, and the README states that all functions return -1 in case of error. There is no error object, no HRESULT and no exception surface to interpret. The Rust code behind it leans on the windows crate, and the dependency list in Cargo.toml calls out Win32_System_Com and Win32_UI_Shell_Common with the comment for IObjectArray, which is where the shell's collection interfaces come from. The repository also carries a note file named note-IVirtualDesktopNotification.md and another named note-window-rs.md, so the working knowledge behind the interfaces is written down alongside the code rather than hidden in a wiki.

Installing means taking a binary from the releases page

There is no package manager step and no build recipe in the documentation, so installation is a download. The README points to the releases page on GitHub, and the recent releases are Windows 11 binaries named by build, including 2024-12-16-windows11, which the release note says works with 24H2 26100.2605. Older entries cover earlier builds: 2024-01-25-windows11 works with 23H2 22631.3085, and 2023-11-10-windows11 works with 22621.2215 and 23H2 22631.2506. Pick the binary that matches the build your machine reports, then call it from your script. Here is the export list as the README writes it:

rust
fn GetCurrentDesktopNumber() -> i32
fn GetDesktopCount() -> i32
fn GetWindowDesktopId(hwnd: HWND) -> GUID
fn GetWindowDesktopNumber(hwnd: HWND) -> i32
fn IsWindowOnCurrentVirtualDesktop(hwnd: HWND) -> i32
fn MoveWindowToDesktopNumber(hwnd: HWND, desktop_number: i32) -> i32
fn GoToDesktopNumber(desktop_number: i32) -> i32
fn IsWindowOnDesktopNumber(hwnd: HWND, desktop_number: i32) -> i32

The Windows handles and the desktop numbers are the whole contract. A caller that gets a handle wrong gets -1 back, and the documentation does not say anything more precise than that.

The Windows 11 only half of the surface

Several exports are marked Win11 only, and the distinction matters if you plan to run the same script on more than one machine. SetDesktopName and GetDesktopName rename a desktop, CreateDesktop creates one, RemoveDesktop deletes a desktop while taking a fallback desktop number, and MoveDesktop reorders desktops by moving one to a new index. Pinning a window or an app to a desktop is a separate family of calls: IsPinnedWindow, PinWindow, UnPinWindow, IsPinnedApp, PinApp and UnPinApp, alongside RegisterPostMessageHook and UnregisterPostMessageHook for receiving notifications. A script that only moves windows between desktops can stay on the stable subset. A script that renames desktops locks itself into the newer shell surface and the newer Windows build that exposes it.

The Rust route offers the same operations as a crate

The repository also carries a Rust library called winvd, and the Cargo.toml gives it version 0.0.49, edition 2021 and an MIT license entry. The library lives at src/lib.rs, the DLL is a separate workspace member alongside testbin, and the crate is configured for docs.rs with a default target of x86_64-pc-windows-msvc. Its dependency list is the practical part:

toml
[dependencies]
windows = { version = "0.58", features = [
    "implement",
    "Win32_System_Com",
    "Win32_UI_Shell_Common",        # for IObjectArray
    "Win32_UI_WindowsAndMessaging", # for TranslateMessage etc.
    "Win32_Foundation",             # for FindWindowW
    "Win32_System_Threading",       # For CreateThread
] }
windows-core = { version = "0.58" }

Optional dependencies widen the surface. crossbeam-channel and winit are both marked optional, and a feature named integration-tests is declared. The difference in approach between the two routes is the point: the DLL suits a scripting language that already knows how to call a native function, while the crate suits a program that wants typed calls and can take on a Rust dependency tree.

Where the API is thin, and where it is silent

Two limits are visible in the export list itself. GetDesktopIdByNumber and GetDesktopNumberById are both marked Untested, so code that depends on translating between a GUID and a desktop number is leaning on functions the author has flagged as unverified. The error model is the other limit: a single -1 covers every failure, so a caller cannot tell a bad window handle from a desktop number that does not exist, and the README does not document a retry or rollback path. The documentation does not describe what happens to windows when RemoveDesktop deletes a desktop other than that a fallback number is accepted as an argument. It also says nothing about thread affinity, message pump requirements for the notification hook, or what a caller must do when the shell restarts. For an automation layer, that silence is workable, but it means each behavior has to be established by your own testing.

Status, licensing and the cost of an OS upgrade

The repository is not archived, and the last push was on 2026-10-11, so the code is being worked on. The binaries are older than that: the newest listed release, 2024-12-16-windows11, targets 24H2 26100.2605. The gap between a recent push and an older release binary is the upgrade cost in practice, since a machine on a newer build may need a freshly built DLL rather than a downloaded one, and the repository ships the Rust sources needed to produce it. Licensing is MIT, which is the same license the Cargo.toml declares for the crate, so a script that loads the DLL and a program that links the crate carry the same terms. MIT is permissive, though it is not an answer to the question of whether the underlying shell interface will keep its shape across Windows releases, and nothing in the project offers a compatibility guarantee beyond the build numbers named in the release list.

Editorial conclusion

Adopt VirtualDesktopAccessor if your automation needs to place a window on a specific Windows 11 virtual desktop and you can pin your deployment to build 26100.2605 or newer. Skip it if you support older Windows releases, if you need documented error codes, or if you are shipping a product where an undocumented shell interface might change without notice. Before you build on it, check the release notes for your exact OS build, run the shipped AutoHotkey examples against your own windows, and confirm that the functions you rely on are marked tested rather than untested.

Frequently asked questions

What Windows 11 version does VirtualDesktopAccessor need?

The project requires at least 24H2 26100.2605, and the documentation says it was tested with 25H2 OS Build 26200.8117. The build requirements describe Windows 11 builds, while the repository description still names Windows 10.

How do I install the VirtualDesktopAccessor DLL?

There is no package manager install step documented. The README points to the GitHub releases page, where Windows 11 binaries are published per build, including 2024-12-16-windows11 for 24H2 26100.2605. A Rust user can instead depend on the winvd crate, which the repository ships at version 0.0.49.

Does VirtualDesktopAccessor work with AutoHotkey v2?

Yes. The repository includes both an AutoHotkey V1 example, example.ahk, and an AutoHotkey V2 example, example.ah2, and the project description names AutoHotkey as the intended caller.

How do I tell if a VirtualDesktopAccessor call failed?

The README states that all exported functions return -1 in case of error. There is no separate error code, so the return value tells you that something failed but not what.

Official sources

  1. Ciantic/VirtualDesktopAccessor on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ciantic-virtualdesktopaccessor.svg)](https://hysenlabs.com/projects/ciantic-virtualdesktopaccessor)

Was this useful?