2015-09-05 17 views
8

Uwielbiam, że w systemie Windows wbudowano wirtualne pulpity, ale mam kilka funkcji, które chciałbym dodać/zmodyfikować. (wymuś pojawienie się okna na wszystkich komputerach, uruchomienie widoku zadania za pomocą klawisza skrótu, pulpitów na monitor), itp.Zmiana zachowania Win 10 na komputerze stacjonarnym

Szukałem aplikacji i referencji programistów, aby pomóc mi dostosować moje komputery stacjonarne, ale nie miałem szczęścia.

Czy masz pojęcie, od czego zacząć?

+0

Interesujące pytanie, ale niestety, prośba o znalezienie bibliotek, dokumentacji i innych materiałów jest uważana za nietypową. – Steve

+1

Czy StackExchange ma forum, na którym będzie to temat? – Slicedbread

+0

Naprawdę spodoba ci się ta aplikacja .... https: //github.com/mzomparelli/zVirtualDesktop –

Odpowiedz

22

Programowy dostęp do funkcji wirtualnego pulpitu jest bardzo ograniczony, Microsoft ujawnił tylko interfejs COM z IVirtualDesktopManager. Nie na tyle, by osiągnąć cokolwiek pożytecznego. Napisałem trochę kodu C# na podstawie pracy inżynierii odwrotnej wykonanej przez NickoTin. Nie mogę przeczytać wiele rosyjskich w swoim blogu, ale jego kod C++ był dość dokładny.

Muszę podkreślić, że ten kod nie jest czymś, na co chcesz się zaangażować w produkcie. Microsoft zawsze może swobodnie zmieniać nieudokumentowane apisy, kiedy tylko mają na to ochotę. Istnieje ryzyko związane z uruchomieniami, kod ten niekoniecznie dobrze oddziałuje, gdy użytkownik manipuluje wirtualnymi pulpitami. Zawsze pamiętaj, że wirtualny pulpit może pojawiać się i znikać w dowolnym momencie, całkowicie niezsynchronizowany z Twoim kodem.

Utwórz nowy projekt biblioteki klas C#. Będę pierwszym poście ComInterop.cs, zawiera deklaracje interfejsu COM, które odpowiadają NickoTin w C++ deklaracje:

using System; 
using System.Runtime.InteropServices; 

namespace Windows10Interop { 
    internal static class Guids { 
     public static readonly Guid CLSID_ImmersiveShell = 
      new Guid(0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39); 
     public static readonly Guid CLSID_VirtualDesktopManagerInternal = 
      new Guid(0xC5E0CDCA, 0x7B6E, 0x41B2, 0x9F, 0xC4, 0xD9, 0x39, 0x75, 0xCC, 0x46, 0x7B); 
     public static readonly Guid CLSID_VirtualDesktopManager = 
      new Guid("AA509086-5CA9-4C25-8F95-589D3C07B48A"); 
     public static readonly Guid IID_IVirtualDesktopManagerInternal = 
      new Guid("AF8DA486-95BB-4460-B3B7-6E7A6B2962B5"); 
     public static readonly Guid IID_IVirtualDesktop = 
      new Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4"); 
    } 

    [ComImport] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")] 
    internal interface IVirtualDesktop { 
     void notimpl1(); // void IsViewVisible(IApplicationView view, out int visible); 
     Guid GetId(); 
    } 

    [ComImport] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [Guid("AF8DA486-95BB-4460-B3B7-6E7A6B2962B5")] 
    internal interface IVirtualDesktopManagerInternal { 
     int GetCount(); 
     void notimpl1(); // void MoveViewToDesktop(IApplicationView view, IVirtualDesktop desktop); 
     void notimpl2(); // void CanViewMoveDesktops(IApplicationView view, out int itcan); 
     IVirtualDesktop GetCurrentDesktop(); 
     void GetDesktops(out IObjectArray desktops); 
     [PreserveSig] 
     int GetAdjacentDesktop(IVirtualDesktop from, int direction, out IVirtualDesktop desktop); 
     void SwitchDesktop(IVirtualDesktop desktop); 
     IVirtualDesktop CreateDesktop(); 
     void RemoveDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback); 
     IVirtualDesktop FindDesktop(ref Guid desktopid); 
    } 

    [ComImport] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")] 
    internal interface IVirtualDesktopManager { 
     int IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow); 
     Guid GetWindowDesktopId(IntPtr topLevelWindow); 
     void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId); 
    } 

    [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("6D5140C1-7436-11CE-8034-00AA006009FA")] 
    internal interface IServiceProvider10 { 
     [return: MarshalAs(UnmanagedType.IUnknown)] 
     object QueryService(ref Guid service, ref Guid riid); 
    } 

} 

Dalej jest Desktop.cs, zawiera przyjazne C# klas, które można używać w kodzie:

using System; 
using System.Runtime.InteropServices; 

namespace Windows10Interop 
{ 
    public class Desktop { 
     public static int Count { 
      // Returns the number of desktops 
      get { return DesktopManager.Manager.GetCount(); } 
     } 

     public static Desktop Current { 
      // Returns current desktop 
      get { return new Desktop(DesktopManager.Manager.GetCurrentDesktop()); } 
     } 

     public static Desktop FromIndex(int index) { 
      // Create desktop object from index 0..Count-1 
      return new Desktop(DesktopManager.GetDesktop(index)); 
     } 

     public static Desktop FromWindow(IntPtr hWnd) { 
      // Creates desktop object on which window <hWnd> is displayed 
      Guid id = DesktopManager.WManager.GetWindowDesktopId(hWnd); 
      return new Desktop(DesktopManager.Manager.FindDesktop(ref id)); 
     } 

     public static Desktop Create() { 
      // Create a new desktop 
      return new Desktop(DesktopManager.Manager.CreateDesktop()); 
     } 

     public void Remove(Desktop fallback = null) { 
      // Destroy desktop and switch to <fallback> 
      var back = fallback == null ? DesktopManager.GetDesktop(0) : fallback.itf; 
      DesktopManager.Manager.RemoveDesktop(itf, back); 
     } 

     public bool IsVisible { 
      // Returns <true> if this desktop is the current displayed one 
      get { return object.ReferenceEquals(itf, DesktopManager.Manager.GetCurrentDesktop()); } 
     } 

     public void MakeVisible() { 
      // Make this desktop visible 
      DesktopManager.Manager.SwitchDesktop(itf); 
     } 

     public Desktop Left { 
      // Returns desktop at the left of this one, null if none 
      get { 
       IVirtualDesktop desktop; 
       int hr = DesktopManager.Manager.GetAdjacentDesktop(itf, 3, out desktop); 
       if (hr == 0) return new Desktop(desktop); 
       else return null; 

      } 
     } 

     public Desktop Right { 
      // Returns desktop at the right of this one, null if none 
      get { 
       IVirtualDesktop desktop; 
       int hr = DesktopManager.Manager.GetAdjacentDesktop(itf, 4, out desktop); 
       if (hr == 0) return new Desktop(desktop); 
       else return null; 
      } 
     } 

     public void MoveWindow(IntPtr handle) { 
      // Move window <handle> to this desktop 
      DesktopManager.WManager.MoveWindowToDesktop(handle, itf.GetId()); 
     } 

     public bool HasWindow(IntPtr handle) { 
      // Returns true if window <handle> is on this desktop 
      return itf.GetId() == DesktopManager.WManager.GetWindowDesktopId(handle); 
     } 

     public override int GetHashCode() { 
      return itf.GetHashCode(); 
     } 
     public override bool Equals(object obj) { 
      var desk = obj as Desktop; 
      return desk != null && object.ReferenceEquals(this.itf, desk.itf); 
     } 

     private IVirtualDesktop itf; 
     private Desktop(IVirtualDesktop itf) { this.itf = itf; } 
    } 

    internal static class DesktopManager { 
     static DesktopManager() { 
      var shell = (IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell)); 
      Manager = (IVirtualDesktopManagerInternal)shell.QueryService(Guids.CLSID_VirtualDesktopManagerInternal, Guids.IID_IVirtualDesktopManagerInternal); 
      WManager = (IVirtualDesktopManager)Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager)); 
     } 

     internal static IVirtualDesktop GetDesktop(int index) { 
      int count = Manager.GetCount(); 
      if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index"); 
      IObjectArray desktops; 
      Manager.GetDesktops(out desktops); 
      object objdesk; 
      desktops.GetAt(index, Guids.IID_IVirtualDesktop, out objdesk); 
      Marshal.ReleaseComObject(desktops); 
      return (IVirtualDesktop)objdesk; 
     } 

     internal static IVirtualDesktopManagerInternal Manager; 
     internal static IVirtualDesktopManager WManager; 
    } 
} 

I wreszcie mały testowy projekt WinForm, którego użyłem do przetestowania kodu. Wystarczy włożyć 4 przyciski na formularzu i nazwać je buttonLeft/Prawo/Tworzenie/Destroy:

using Windows10Interop; 
using System.Diagnostics; 
... 
    public partial class Form1 : Form { 
     public Form1() { 
      InitializeComponent(); 
     } 

     private void buttonRight_Click(object sender, EventArgs e) { 
      var curr = Desktop.FromWindow(this.Handle); 
      Debug.Assert(curr.Equals(Desktop.Current)); 
      var right = curr.Right; 
      if (right == null) right = Desktop.FromIndex(0); 
      if (right != null) { 
       right.MoveWindow(this.Handle); 
       right.MakeVisible(); 
       this.BringToFront(); 
       Debug.Assert(right.IsVisible); 
      } 
     } 

     private void buttonLeft_Click(object sender, EventArgs e) { 
      var curr = Desktop.FromWindow(this.Handle); 
      Debug.Assert(curr.Equals(Desktop.Current)); 
      var left = curr.Left; 
      if (left == null) left = Desktop.FromIndex(Desktop.Count - 1); 
      if (left != null) { 
       left.MoveWindow(this.Handle); 
       left.MakeVisible(); 
       this.BringToFront(); 
       Debug.Assert(left.IsVisible); 
      } 
     } 

     private void buttonCreate_Click(object sender, EventArgs e) { 
      var desk = Desktop.Create(); 
      desk.MoveWindow(this.Handle); 
      desk.MakeVisible(); 
      Debug.Assert(desk.IsVisible); 
      Debug.Assert(desk.Equals(Desktop.Current)); 
     } 

     private void buttonDestroy_Click(object sender, EventArgs e) { 
      var curr = Desktop.FromWindow(this.Handle); 
      var next = curr.Left; 
      if (next == null) next = curr.Right; 
      if (next != null && next != curr) { 
       next.MoveWindow(this.Handle); 
       curr.Remove(next); 
       Debug.Assert(next.IsVisible); 
      } 
     } 
    } 

Jedynym dziwactwo zauważyłem podczas testowania jest to, że przejście do okna z jednego pulpitu na inny może przenieść go na dno kolejności Z, kiedy najpierw przełączasz pulpit, a następnie przesuwasz okno. Nie ma takiego problemu, jeśli robisz to na odwrót.

+0

Dziękuję za ten kod. To bardzo mi pomogło! – jtk

+1

Podczas wywoływania 'public static int Count' w' klasie Desktop ' Zewnętrzna: inicjator typu dla" Windows10Interop.DesktopManager "zwrócił wyjątek. Wewnętrzna: określona obsada jest nieprawidłowa. {System.InvalidCastException} Szczerze mówiąc, zagubiłem się w tym kodzie. Pomoc doceniona – Benj

+0

https://github.com/Eun/MoveToDesktop/issues/20 –