Skip to content

Windows 11 25H2 #112

Description

@stinkingshoe

Love your Virtual Desktop! When I upgraded to Windows 11 25H2 the SetDesktopName stopped working for me. While I won't pretend to understand everything happening, with the help of Gemini I've ended up with the following code, which I can confirm creates a virtual desktop, and sets the name appropriately in Windows 11 25H2. Posting here if it helps you with a 25H2 revision.

// Original Author: Markus Scholtes, 2025
// Version 1.21, 2025-08-11
// Modified Version for Windows 11 25H2
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Diagnostics;

namespace VirtualDesktop
{
    #region COM API
    internal static class Guids
    {
        public static readonly Guid CLSID_ImmersiveShell = new Guid("C2F03A33-21F5-47FA-B4BB-156362A2F239");
        public static readonly Guid CLSID_VirtualDesktopManagerInternal = new Guid("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B");
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")]
    internal interface IObjectArray
    {
        void GetCount(out int count);
        void GetAt(int index, ref Guid iid, [MarshalAs(UnmanagedType.Interface)] out object obj);
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("3F07F4BE-B107-441A-AF0F-39D82529072C")]
    internal interface IVirtualDesktop
    {
        void Unused1();
        Guid GetId();
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("53F5CA0B-158F-4124-900C-057158060B27")]
    internal interface IVirtualDesktopManagerInternal
    {
        int GetCount();
        void MoveViewToDesktop(object view, IVirtualDesktop desktop);
        bool CanViewMoveDesktops(object view);
        IVirtualDesktop GetCurrentDesktop();
        void GetDesktops(out IObjectArray desktops);
        [PreserveSig] int GetAdjacentDesktop(IVirtualDesktop from, int direction, out IVirtualDesktop desktop);
        void SwitchDesktop(IVirtualDesktop desktop);
        void SwitchDesktopAndMoveForegroundView(IVirtualDesktop desktop);
        IVirtualDesktop CreateDesktop();
        void MoveDesktop(IVirtualDesktop desktop, int nIndex);
        void RemoveDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback);
        IVirtualDesktop FindDesktop(ref Guid desktopid);
        void GetDesktopSwitchIncludeExcludeViews(IVirtualDesktop desktop, out IObjectArray unknown1, out IObjectArray unknown2);

        // FIX: Use IntPtr instead of string to avoid Marshaling error
        void SetDesktopName(IVirtualDesktop desktop, IntPtr hstringName);
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
    internal interface IServiceProvider10
    {
        [return: MarshalAs(UnmanagedType.IUnknown)] object QueryService(ref Guid service, ref Guid riid);
    }
    #endregion

    internal static class DesktopManager
    {
        static DesktopManager()
        {
            var shell = (IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell));
            VirtualDesktopManagerInternal = (IVirtualDesktopManagerInternal)shell.QueryService(Guids.CLSID_VirtualDesktopManagerInternal, typeof(IVirtualDesktopManagerInternal).GUID);
        }
        internal static IVirtualDesktopManagerInternal VirtualDesktopManagerInternal;
    }

    public class Desktop
    {
        [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int WindowsCreateString([MarshalAs(UnmanagedType.LPWStr)] string sourceString, uint length, out IntPtr hstring);

        [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int WindowsDeleteString(IntPtr hstring);

        private IVirtualDesktop ivd;
        private Desktop(IVirtualDesktop desktop) { this.ivd = desktop; }

        public static Desktop Create() => new Desktop(DesktopManager.VirtualDesktopManagerInternal.CreateDesktop());

        public void SetName(string Name)
        {
            IntPtr hString = IntPtr.Zero;
            try
            {
                // 1. Manually create the WinRT HString
                WindowsCreateString(Name, (uint)Name.Length, out hString);

                // 2. Pass the raw pointer to the COM method
                DesktopManager.VirtualDesktopManagerInternal.SetDesktopName(this.ivd, hString);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("SetName COM failed: " + ex.Message);
            }
            finally
            {
                if (hString != IntPtr.Zero) WindowsDeleteString(hString);
            }
        public void MakeVisible()
        {
            DesktopManager.VirtualDesktopManagerInternal.SwitchDesktop(this.ivd);
        }
    }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions