2015-09-05 23 views
8

Tôi thích các cửa sổ hiện có các máy ảo được tích hợp sẵn, nhưng tôi có một số tính năng mà tôi muốn thêm/sửa đổi. (buộc cửa sổ xuất hiện trên tất cả máy tính để bàn, khởi chạy chế độ xem nhiệm vụ bằng phím nóng, có màn hình trên máy tính để bàn, v.v.)Thay đổi hành vi máy tính để bàn Win10 ảo

Tôi đã tìm kiếm ứng dụng và tài liệu tham khảo của nhà phát triển để giúp tôi tùy chỉnh máy tính để bàn của mình nhưng không có may mắn.

Tôi có biết nên bắt đầu từ đâu không?

+0

Câu hỏi thú vị, nhưng than ôi, yêu cầu tìm thư viện, tài liệu và các tài liệu khác được coi là không có chủ đề. – Steve

+1

StackExchange có một diễn đàn mà điều này sẽ là về chủ đề? – Slicedbread

+0

Bạn sẽ thực sự thích ứng dụng này .... https: //github.com/mzomparelli/zVirtualDesktop –

Trả lời

22

Truy cập có lập trình vào tính năng máy tính để bàn ảo rất hạn chế, Microsoft chỉ tiếp xúc với giao diện COM IVirtualDesktopManager COM. Không đủ gần để hoàn thành bất kỳ điều gì hữu ích. Tôi đã viết một số mã C# dựa trên công việc kỹ thuật đảo ngược được thực hiện bởi NickoTin. Tôi không thể đọc nhiều người Nga trong bài đăng trên blog của anh ấy nhưng mã C++ của anh ấy khá chính xác.

Tôi cần nhấn mạnh rằng mã này không phải là thứ bạn muốn cam kết trong sản phẩm. Microsoft luôn luôn cảm thấy tự do để thay đổi apis không có giấy tờ bất cứ khi nào họ cảm thấy thích nó. Và có một nguy cơ thời gian chạy, mã này không nhất thiết phải tương tác tốt khi người dùng đang tinkering với các máy tính để bàn ảo là tốt. Luôn ghi nhớ rằng một máy tính ảo có thể xuất hiện và biến mất bất cứ lúc nào, hoàn toàn không đồng bộ với mã của bạn.

Tạo dự án thư viện lớp C# mới. Lần đầu tiên tôi sẽ đăng ComInterop.cs, nó chứa các khai báo giao diện COM phù hợp NickoTin của C++ khai báo:

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); 
    } 

} 

Tiếp theo là Desktop.cs, nó chứa thân thiện với C# lớp học mà bạn có thể sử dụng trong mã của bạn:

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; 
    } 
} 

Và cuối cùng là một thử nghiệm nhỏ Dự án Winforms mà tôi đã sử dụng để kiểm tra mã. Chỉ cần thả 4 nút trên một mẫu và đặt tên cho chúng buttonLeft/Phải/Tạo/Phá hủy:

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); 
      } 
     } 
    } 

Các chỉ những đứa thực tôi nhận thấy trong khi thử nghiệm này là di chuyển một cửa sổ từ một máy tính để bàn khác có thể di chuyển nó đến đáy của lệnh Z khi bạn trước tiên chuyển đổi màn hình nền, sau đó di chuyển cửa sổ. Không có vấn đề như vậy nếu bạn làm điều đó theo cách khác.

+0

Cảm ơn một bó cho mã này. Điều này đã giúp tôi rất nhiều! – jtk

+1

Khi gọi đến 'public static int Count' trong' lớp Desktop' Outer: Kiểu khởi tạo cho 'Windows10Interop.DesktopManager' đã ném một ngoại lệ. Bên trong: Truyền được chỉ định không hợp lệ. {System.InvalidCastException} Tôi thành thật bị mất trong mã đó. Giúp đánh giá cao – Benj

+0

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

Các vấn đề liên quan