PoshCode Logo PowerShell Code Repository

Get-Desktop.ps1 by Joel Bennett 18 months ago (modification of post by Joel Bennett view diff)
diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/2009"></script>download | new post

4 lines of PowerShell to wrap that C# class and show you how to use it… (with Add-Type -Path)

  1. Add-Type @'
  2. #region License
  3. // Desktop 1.1
  4. //                                                                                                                                                                                                                                                                                                              *
  5. // Copyright (C) 2004  http://www.onyeyiri.co.uk
  6. // Coded by: Nnamdi Onyeyiri
  7. //
  8. // This code may be used in any way you desire except for commercial use.
  9. // The code can be freely redistributed unmodified as long as all of the authors
  10. // copyright notices remain intact, as long as it is not being sold for profit.
  11. // Although I have tried to ensure the stability of the code, I will not take
  12. // responsibility for any loss, damages, or death it may cause.
  13. //
  14. // This software is provided "as is" without any expressed or implied warranty.
  15. //
  16. // -------------------------
  17. // Change Log
  18. //
  19. // Version 1.0:  -First Release
  20. //
  21. // Version 1.1:  -Added Window and WindowCollection classes
  22. // 6/6/2004      -Added another GetWindows overload, that used WindowCollection
  23. //               -Added GetInputProcesses method to retrieve processes on Input desktop
  24. //               -Changed GetWindows and GetDesktops to return arrays, instead of them being passed by ref
  25. //
  26. // Version 1.2   -Implemented IDisposable
  27. // 8/7/2004      -Implemented ICloneable
  28. //               -Overrided ToString to return desktop name
  29. //
  30. // Version 2.0   -Switched to Generic Collections
  31. // 7/19/2010     -Added enumeration of process from alternate desktops
  32. // Joel Bennett  -Renamed a lot of methods to remove duplication
  33. #endregion
  34.  
  35. using System;
  36. using System.Threading;
  37. using System.Text;
  38. using System.Diagnostics;
  39. using System.Runtime.InteropServices;
  40. using System.Collections.Generic;
  41. using System.ComponentModel;
  42.  
  43. /// <summary>
  44. /// Encapsulates the Desktop API.
  45. /// </summary>
  46. public class Desktop : IDisposable, ICloneable
  47. {
  48.   #region Imports
  49.   [DllImport("kernel32.dll")]
  50.   private static extern int GetThreadId(IntPtr thread);
  51.  
  52.   [DllImport("kernel32.dll")]
  53.   private static extern int GetProcessId(IntPtr process);
  54.  
  55.   //
  56.   // Imported winAPI functions.
  57.   //
  58.   [DllImport("user32.dll")]
  59.   private static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags, long dwDesiredAccess, IntPtr lpsa);
  60.  
  61.   [DllImport("user32.dll")]
  62.   private static extern bool CloseDesktop(IntPtr hDesktop);
  63.  
  64.   [DllImport("user32.dll")]
  65.   private static extern IntPtr OpenDesktop(string lpszDesktop, int dwFlags, bool fInherit, long dwDesiredAccess);
  66.  
  67.   [DllImport("user32.dll")]
  68.   private static extern IntPtr OpenInputDesktop(int dwFlags, bool fInherit, long dwDesiredAccess);
  69.  
  70.   [DllImport("user32.dll")]
  71.   private static extern bool SwitchDesktop(IntPtr hDesktop);
  72.  
  73.   [DllImport("user32.dll")]
  74.   private static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopProc lpEnumFunc, IntPtr lParam);
  75.  
  76.   [DllImport("user32.dll")]
  77.   private static extern IntPtr GetProcessWindowStation();
  78.  
  79.   [DllImport("user32.dll")]
  80.   private static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDesktopWindowsProc lpfn, IntPtr lParam);
  81.  
  82.   [DllImport("user32.dll")]
  83.   private static extern bool SetThreadDesktop(IntPtr hDesktop);
  84.  
  85.   [DllImport("user32.dll")]
  86.   public static extern IntPtr GetThreadDesktop(int dwThreadId);
  87.  
  88.   [DllImport("user32.dll")]
  89.   [return: MarshalAs(UnmanagedType.Bool)]
  90.   private static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, IntPtr pvInfo, int nLength, ref int lpnLengthNeeded);
  91.  
  92.  
  93.  
  94.   [DllImport("user32.dll")]
  95.   private static extern int GetWindowText(IntPtr hWnd, IntPtr lpString, int nMaxCount);
  96.  
  97.   private delegate bool EnumDesktopProc(string lpszDesktop, IntPtr lParam);
  98.   private delegate bool EnumDesktopWindowsProc(IntPtr desktopHandle, IntPtr lParam);
  99.  
  100.  
  101.   // The Unicode version of this function, CreateProcessW, can modify the contents of the lpCommandLine string.
  102.   // Therefore, you can't just pass a string (because it's a constant, so it becomes a pointer to read-only memory).
  103.   [return: MarshalAs(UnmanagedType.Bool)][DllImport("kernel32.dll")]
  104.   private static extern bool CreateProcess( string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, int dwCreationFlags,  IntPtr lpEnvironment,  string lpCurrentDirectory,  [In] ref STARTUPINFO lpStartupInfo, [Out]out PROCESS_INFORMATION lpProcessInformation);
  105.  
  106.   [StructLayout(LayoutKind.Sequential)]
  107.   private struct PROCESS_INFORMATION
  108.   {
  109.      public IntPtr hProcess;
  110.      public IntPtr hThread;
  111.      public int dwProcessId;
  112.      public int dwThreadId;
  113.   }
  114.  
  115.   [StructLayout(LayoutKind.Sequential)]
  116.   private struct STARTUPINFO
  117.   {
  118.      public int cb;
  119.      public string lpReserved;
  120.      public string lpDesktop;
  121.      public string lpTitle;
  122.      public int dwX;
  123.      public int dwY;
  124.      public int dwXSize;
  125.      public int dwYSize;
  126.      public int dwXCountChars;
  127.      public int dwYCountChars;
  128.      public int dwFillAttribute;
  129.      public int dwFlags;
  130.      public short wShowWindow;
  131.      public short cbReserved2;
  132.      public IntPtr lpReserved2;
  133.      public IntPtr hStdInput;
  134.      public IntPtr hStdOutput;
  135.      public IntPtr hStdError;
  136.   }
  137.   #endregion
  138.  
  139.   #region Constants
  140.   /// <summary>
  141.   /// Size of buffer used when retrieving window names.
  142.   /// </summary>
  143.   public const int MaxWindowNameLength = 100;
  144.  
  145.   //
  146.   // winAPI constants.
  147.   //
  148.   private const short SW_HIDE = 0;
  149.   private const short SW_NORMAL = 1;
  150.   private const int STARTF_USESTDHANDLES = 0x00000100;
  151.   private const int STARTF_USESHOWWINDOW = 0x00000001;
  152.   private const int UOI_NAME = 2;
  153.   private const int STARTF_USEPOSITION = 0x00000004;
  154.   private const int NORMAL_PRIORITY_CLASS = 0x00000020;
  155.   private const long DESKTOP_CREATEWINDOW = 0x0002L;
  156.   private const long DESKTOP_ENUMERATE = 0x0040L;
  157.   private const long DESKTOP_WRITEOBJECTS = 0x0080L;
  158.   private const long DESKTOP_SWITCHDESKTOP = 0x0100L;
  159.   private const long DESKTOP_CREATEMENU = 0x0004L;
  160.   private const long DESKTOP_HOOKCONTROL = 0x0008L;
  161.   private const long DESKTOP_READOBJECTS = 0x0001L;
  162.   private const long DESKTOP_JOURNALRECORD = 0x0010L;
  163.   private const long DESKTOP_JOURNALPLAYBACK = 0x0020L;
  164.   private const long AccessRights = DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_READOBJECTS;
  165.   #endregion
  166.  
  167.   #region Structures
  168.   /// <summary>
  169.   /// Stores window handles and titles.
  170.   /// </summary>
  171.   public struct Window
  172.   {
  173.      #region Private Variables
  174.      private IntPtr m_handle;
  175.      private string m_text;
  176.      #endregion
  177.  
  178.      #region Public Properties
  179.      /// <summary>
  180.      /// Gets the window handle.
  181.      /// </summary>
  182.      public IntPtr Handle
  183.      {
  184.         get
  185.         {
  186.            return m_handle;
  187.         }
  188.      }
  189.  
  190.      /// <summary>
  191.      /// Gets teh window title.
  192.      /// </summary>
  193.      public string Text
  194.      {
  195.         get
  196.         {
  197.            return m_text;
  198.         }
  199.      }
  200.      #endregion
  201.  
  202.      #region Construction
  203.      /// <summary>
  204.      /// Creates a new window object.
  205.      /// </summary>
  206.      /// <param name="handle">Window handle.</param>
  207.      /// <param name="text">Window title.</param>
  208.      public Window(IntPtr handle, string text)
  209.      {
  210.         m_handle = handle;
  211.         m_text = text;
  212.      }
  213.      #endregion
  214.   }
  215.   #endregion
  216.  
  217.   #region Private Variables
  218.   private IntPtr m_desktop;
  219.   private string m_desktopName;
  220.   private static List<String> m_sc;
  221.   private List<IntPtr> m_windows;
  222.   private bool m_disposed;
  223.   #endregion
  224.  
  225.   #region Public Properties
  226.   /// <summary>
  227.   /// Gets if a desktop is open.
  228.   /// </summary>
  229.   public bool IsOpen
  230.   {
  231.      get
  232.      {
  233.         return (m_desktop != IntPtr.Zero);
  234.      }
  235.   }
  236.  
  237.   /// <summary>
  238.   /// Gets the name of the desktop, returns null if no desktop is open.
  239.   /// </summary>
  240.   public string DesktopName
  241.   {
  242.      get
  243.      {
  244.         return m_desktopName;
  245.      }
  246.   }
  247.  
  248.   /// <summary>
  249.   /// Gets a handle to the desktop, IntPtr.Zero if no desktop open.
  250.   /// </summary>
  251.   public IntPtr DesktopHandle
  252.   {
  253.      get
  254.      {
  255.         return m_desktop;
  256.      }
  257.   }
  258.  
  259.   /// <summary>
  260.   /// Opens the default desktop.
  261.   /// </summary>
  262.   public static readonly Desktop Default = Desktop.OpenDefault();
  263.  
  264.   /// <summary>
  265.   /// Opens the desktop the user if viewing.
  266.   /// </summary>
  267.   public static readonly Desktop Input = Desktop.OpenInput();
  268.   #endregion
  269.  
  270.   #region Construction/Destruction
  271.   /// <summary>
  272.   /// Creates a new Desktop object.
  273.   /// </summary>
  274.   public Desktop()
  275.   {
  276.      // init variables.
  277.      m_desktop = IntPtr.Zero;
  278.      m_desktopName = String.Empty;
  279.      m_windows = new List<IntPtr>();
  280.      m_disposed = false;
  281.   }
  282.  
  283.   /// <summary>
  284.   /// Creates a new Desktop object.
  285.   /// </summary>
  286.   public Desktop(string name)
  287.   {
  288.      // init variables.
  289.      m_desktop = IntPtr.Zero;
  290.      m_desktopName = name;
  291.      m_windows = new List<IntPtr>();
  292.      m_disposed = false;
  293.   }
  294.  
  295.   // constructor is private to prevent invalid handles being passed to it.
  296.   private Desktop(IntPtr desktop)
  297.   {
  298.      // init variables.
  299.      m_desktop = desktop;
  300.      m_desktopName = Desktop.GetName(desktop);
  301.      m_windows = new List<IntPtr>();
  302.      m_disposed = false;
  303.   }
  304.  
  305.   ~Desktop()
  306.   {
  307.      // clean up, close the desktop.
  308.      Close();
  309.   }
  310.   #endregion
  311.  
  312.   #region Methods
  313.  
  314.  
  315.   /// <summary>
  316.   /// Closes the handle to a desktop.
  317.   /// </summary>
  318.   /// <returns>True if an open handle was successfully closed.</returns>
  319.   public bool Close()
  320.   {
  321.      // make sure object isnt disposed.
  322.      CheckDisposed();
  323.  
  324.      // check there is a desktop open.
  325.      if (m_desktop != IntPtr.Zero)
  326.      {
  327.         // close the desktop.
  328.         bool result = CloseDesktop(m_desktop);
  329.  
  330.         if (result)
  331.         {
  332.            m_desktop = IntPtr.Zero;
  333.  
  334.            m_desktopName = String.Empty;
  335.         }
  336.  
  337.         return result;
  338.      }
  339.  
  340.      // no desktop was open, so desktop is closed.
  341.      return true;
  342.   }
  343.  
  344.   /// <summary>
  345.   /// Opens a desktop.
  346.   /// </summary>
  347.   /// <param name="name">The name of the desktop to open.</param>
  348.   /// <returns>True if the desktop was successfully opened.</returns>
  349.   public bool Open()
  350.   {
  351.      // make sure object isnt disposed.
  352.      CheckDisposed();
  353.  
  354.      // close the open desktop.
  355.      if (m_desktop != IntPtr.Zero)
  356.      {
  357.         // attempt to close the desktop.
  358.         if (!Close()) return false;
  359.      }
  360.  
  361.      // open the desktop.
  362.      m_desktop = OpenDesktop(m_desktopName, 0, true, AccessRights);
  363.  
  364.      // something went wrong.
  365.      if (m_desktop == IntPtr.Zero) return false;
  366.  
  367.      return true;
  368.   }
  369.  
  370.   /// <summary>
  371.   /// Switches input to the currently opened desktop.
  372.   /// </summary>
  373.   /// <returns>True if desktops were successfully switched.</returns>
  374.   public bool Show()
  375.   {
  376.      // make sure object isnt disposed.
  377.      CheckDisposed();
  378.  
  379.      // make sure there is a desktop to open.
  380.      if (m_desktop == IntPtr.Zero) return false;
  381.  
  382.      // attempt to switch desktops.
  383.      bool result = SwitchDesktop(m_desktop);
  384.  
  385.      return result;
  386.   }
  387.  
  388.   /// <summary>
  389.   /// Enumerates the windows on a desktop.
  390.   /// </summary>
  391.   /// <param name="windows">Array of Desktop.Window objects to recieve windows.</param>
  392.   /// <returns>A window colleciton if successful, otherwise null.</returns>
  393.   public List<Window> GetWindows()
  394.   {
  395.      // make sure object isnt disposed.
  396.      CheckDisposed();
  397.  
  398.      // make sure a desktop is open.
  399.      if (!IsOpen) return null;
  400.  
  401.      // init the List.
  402.      m_windows.Clear();
  403.      List<Window> windows = new List<Window>();
  404.  
  405.      // get windows.
  406.      bool result = EnumDesktopWindows(m_desktop, new EnumDesktopWindowsProc(DesktopWindowsProc), IntPtr.Zero);
  407.  
  408.      // check for error.
  409.      if (!result) return null;
  410.  
  411.      // get window names.
  412.      IntPtr ptr = Marshal.AllocHGlobal(MaxWindowNameLength);
  413.  
  414.      foreach(IntPtr wnd in m_windows)
  415.      {
  416.         GetWindowText(wnd, ptr, MaxWindowNameLength);
  417.         windows.Add(new Window(wnd, Marshal.PtrToStringAnsi(ptr)));
  418.      }
  419.  
  420.      Marshal.FreeHGlobal(ptr);
  421.  
  422.      return windows;
  423.   }
  424.  
  425.   private bool DesktopWindowsProc(IntPtr wndHandle, IntPtr lParam)
  426.   {
  427.      // add window handle to colleciton.
  428.      m_windows.Add(wndHandle);
  429.  
  430.      return true;
  431.   }
  432.  
  433.   /// <summary>
  434.   /// Creates a new process in a desktop.
  435.   /// </summary>
  436.   /// <param name="path">Path to application.</param>
  437.   /// <returns>The process object for the newly created process.</returns>
  438.   public Process CreateProcess(string path)
  439.   {
  440.      return CreateProcess(path, null);
  441.   }
  442.  
  443.   /// <summary>
  444.   /// Creates a new process in a desktop.
  445.   /// </summary>
  446.   /// <param name="path">Path to application.</param>
  447.   /// <param name="commandLineParameters">Arguments for the application.</param>
  448.   /// <returns>The process object for the newly created process.</returns>
  449.   public Process CreateProcess(string path, string commandLineParameters)
  450.   {
  451.      // make sure object isnt disposed.
  452.      CheckDisposed();
  453.      return Desktop.CreateProcess(path,commandLineParameters,m_desktopName);
  454.   }
  455.  
  456.   /// <summary>
  457.   /// Prepares a desktop for use by launching the Explorer Shell.  For use only on newly created desktops, call straight after CreateDesktop.
  458.   /// </summary>
  459.   public void Prepare()
  460.   {
  461.      // make sure object isnt disposed.
  462.      CheckDisposed();
  463.  
  464.      // make sure a desktop is open.
  465.      if (IsOpen)
  466.      {
  467.         // load explorer.
  468.         CreateProcess("explorer.exe");
  469.      }
  470.   }
  471.  
  472.   /// <summary>
  473.   /// Gets an array of all the processes running on this desktop.
  474.   /// </summary>
  475.   /// <returns>An array of the processes.</returns>
  476.   public Process[] GetProcesses()
  477.   {
  478.      return GetProcesses( m_desktopName, StringComparison.InvariantCulture);
  479.   }
  480.   #endregion
  481.  
  482.   #region Static Methods
  483.   /// <summary>
  484.   /// Enumerates all of the desktops.
  485.   /// </summary>
  486.   /// <param name="desktops">String array to recieve desktop names.</param>
  487.   /// <returns>True if desktop names were successfully enumerated.</returns>
  488.   public static string[] GetDesktops()
  489.   {
  490.      // attempt to enum desktops.
  491.      IntPtr windowStation = GetProcessWindowStation();
  492.  
  493.      // check we got a valid handle.
  494.      if (windowStation == IntPtr.Zero) return new string[0];
  495.  
  496.      string[] desktops;
  497.  
  498.      // lock the object. thread safety and all.
  499.      lock(m_sc = new List<String>())
  500.      {
  501.         bool result = EnumDesktops(windowStation, new EnumDesktopProc(DesktopProc), IntPtr.Zero);
  502.  
  503.         // something went wrong.
  504.         if (!result) return new string[0];
  505.  
  506.          //     // turn the collection into an array.
  507.         desktops = new string[m_sc.Count];
  508.         for(int i = 0; i < desktops.Length; i++) desktops[i] = m_sc[i];
  509.      }
  510.  
  511.      return desktops;
  512.   }
  513.  
  514.   private static bool DesktopProc(string lpszDesktop, IntPtr lParam)
  515.   {
  516.      // add the desktop to the collection.
  517.      m_sc.Add(lpszDesktop);
  518.  
  519.      return true;
  520.   }
  521.  
  522.   /// <summary>
  523.   /// Switches to the specified desktop.
  524.   /// </summary>
  525.   /// <param name="name">Name of desktop to switch input to.</param>
  526.   /// <returns>True if desktops were successfully switched.</returns>
  527.   public static bool Show(string name)
  528.   {
  529.      // attmempt to open desktop.
  530.      bool result = false;
  531.  
  532.      using (Desktop d = new Desktop(name))
  533.      {
  534.         result = d.Open();
  535.  
  536.         // something went wrong.
  537.         if (!result) return false;
  538.  
  539.         // attempt to switch desktops.
  540.         result = d.Show();
  541.      }
  542.  
  543.      return result;
  544.   }
  545.  
  546.   /// <summary>
  547.   /// Gets the desktop of the calling thread.
  548.   /// </summary>
  549.   /// <returns>Returns a Desktop object for the valling thread.</returns>
  550.   public static Desktop GetCurrent()
  551.   {
  552.      // get the desktop.
  553.      return new Desktop(GetThreadDesktop(System.Threading.Thread.CurrentThread.ManagedThreadId));
  554.   }
  555.  
  556.   /// <summary>
  557.   /// Sets the desktop of the calling thread.
  558.   /// NOTE: Function will fail if thread has hooks or windows in the current desktop.
  559.   /// </summary>
  560.   /// <param name="desktop">Desktop to put the thread in.</param>
  561.   /// <returns>True if the threads desktop was successfully changed.</returns>
  562.   public static bool SetCurrent(Desktop desktop)
  563.   {
  564.      // set threads desktop.
  565.      if (!desktop.IsOpen) return false;
  566.      return SetThreadDesktop(desktop.DesktopHandle);
  567.   }
  568.  
  569.   /// <summary>
  570.   /// Opens a desktop.
  571.   /// </summary>
  572.   /// <param name="name">The name of the desktop to open.</param>
  573.   /// <returns>If successful, a Desktop object, otherwise, null.</returns>
  574.   public static Desktop Open(string name)
  575.   {
  576.      // open the desktop.
  577.      Desktop desktop = new Desktop(name);
  578.      bool result = desktop.Open();
  579.  
  580.      // something went wrong.
  581.      if (!result) return null;
  582.  
  583.      return desktop;
  584.   }
  585.  
  586.   /// <summary>
  587.   /// Opens the current input desktop.
  588.   /// </summary>
  589.   /// <returns>If successful, a Desktop object, otherwise, null.</returns>
  590.   public static Desktop OpenInput()
  591.   {
  592.      // open the desktop.        
  593.      IntPtr deskptr = OpenInputDesktop(0, true, AccessRights);
  594.      if (deskptr == IntPtr.Zero) return null;
  595.      
  596.      return new Desktop(deskptr);
  597.   }
  598.  
  599.   /// <summary>
  600.   /// Opens the default desktop.
  601.   /// </summary>
  602.   /// <returns>If successful, a Desktop object, otherwise, null.</returns>
  603.   public static Desktop OpenDefault()
  604.   {
  605.      // opens the default desktop.
  606.      return Desktop.Open("Default");
  607.   }
  608.  
  609.   /// <summary>
  610.   /// Creates a new desktop.
  611.   /// </summary>
  612.   /// <param name="name">The name of the desktop to create.  Names are case sensitive.</param>
  613.   /// <returns>If successful, a Desktop object, otherwise, null.</returns>
  614.   public static Desktop Create(string name)
  615.   {
  616.      // make sure desktop doesnt already exist.
  617.      if (Desktop.Exists(name))
  618.      {
  619.         // it exists, so open it.
  620.         return Open(name);
  621.      }
  622.  
  623.      // attempt to create desktop.
  624.      IntPtr deskptr = CreateDesktop(name, IntPtr.Zero, IntPtr.Zero, 0, AccessRights, IntPtr.Zero);
  625.      if (deskptr == IntPtr.Zero) return null;
  626.  
  627.      // open the desktop.
  628.      return Open(name);
  629.   }
  630.  
  631.   /// <summary>
  632.   /// Gets the name of a given desktop.
  633.   /// </summary>
  634.   /// <param name="desktop">Desktop object whos name is to be found.</param>
  635.   /// <returns>If successful, the desktop name, otherwise, null.</returns>
  636.   public static string GetName(Desktop desktop)
  637.   {
  638.      // get name.
  639.      if (desktop.IsOpen) return null;
  640.  
  641.      return GetName(desktop.DesktopHandle);
  642.   }
  643.  
  644.  
  645.   public static Win32Exception LastError;
  646.  
  647.   /// <summary>
  648.   /// Gets the name of a desktop from a desktop handle.
  649.   /// </summary>
  650.   /// <param name="desktopHandle"></param>
  651.   /// <returns>If successful, the desktop name, otherwise, null.</returns>
  652.   public static string GetName(IntPtr desktopHandle)
  653.   {
  654.      // check its not a null pointer.
  655.      // null pointers wont work.
  656.      if (desktopHandle == IntPtr.Zero) return null;
  657.  
  658.      // get the length of the name.
  659.      int needed = 0;
  660.      string name = null;
  661.      // always returns false, because we pass 0 for available size
  662.      GetUserObjectInformation(desktopHandle, UOI_NAME, IntPtr.Zero, 0, ref needed);
  663.  
  664.      // get the name.
  665.      IntPtr ptr = Marshal.AllocHGlobal(needed);
  666.      if(!GetUserObjectInformation(desktopHandle, UOI_NAME, ptr, needed, ref needed)) {
  667.         Marshal.FreeHGlobal(ptr);
  668.         LastError = new Win32Exception();
  669.      } else {
  670.         name = Marshal.PtrToStringAnsi(ptr);
  671.         Marshal.FreeHGlobal(ptr);
  672.      }
  673.      return name;
  674.   }
  675.  
  676.   /// <summary>
  677.   /// Checks if the specified desktop exists (using a case sensitive search).
  678.   /// </summary>
  679.   /// <param name="name">The name of the desktop.</param>
  680.   /// <returns>True if the desktop exists, otherwise false.</returns>
  681.   public static bool Exists(string name)
  682.   {
  683.      return Desktop.Exists(name, StringComparison.InvariantCultureIgnoreCase);
  684.   }
  685.  
  686.   /// <summary>
  687.   /// Checks if the specified desktop exists.
  688.   /// </summary>
  689.   /// <param name="name">The name of the desktop.</param>
  690.   /// <param name="comparisonType">The type of string comparison to do.</param>
  691.   /// <returns>True if the desktop exists, otherwise false.</returns>
  692.   public static bool Exists(string name, StringComparison comparisonType)
  693.   {
  694.      // enumerate desktops.
  695.      string[] desktops = Desktop.GetDesktops();
  696.  
  697.      // return true if desktop exists.
  698.      foreach(string desktop in desktops)
  699.      {
  700.         if(desktop.Equals( name, comparisonType )) return true;
  701.      }
  702.  
  703.      return false;
  704.   }
  705.  
  706.   /// <summary>
  707.   /// Creates a new process on the specified desktop.
  708.   /// </summary>
  709.   /// <param name="path">Path to application.</param>
  710.   /// <param name="commandLineParameters">Arguments for the application.</param>
  711.   /// <param name="desktop">Desktop name.</param>
  712.   /// <returns>A Process object for the newly created process, otherwise, null.</returns>
  713.   public static Process CreateProcess(string path, string commandLineParameters, string desktop)
  714.   {
  715.      if (!Desktop.Exists(desktop)) return null;
  716.  
  717.      // set startup parameters.
  718.      STARTUPINFO si = new STARTUPINFO();
  719.      si.cb = Marshal.SizeOf(si);
  720.      si.lpDesktop = desktop;
  721.  
  722.      PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
  723.  
  724.      //StringBuilder lpPath = new StringBuilder(path);
  725.      StringBuilder lpCommandLine = new StringBuilder();
  726.      lpCommandLine.Append("\"");
  727.      lpCommandLine.Append(path);
  728.      lpCommandLine.Append("\" ");
  729.      lpCommandLine.Append(commandLineParameters);
  730.      // lpPath.EnsureCapacity(256);
  731.      // create the process.
  732.      if(!CreateProcess(null, lpCommandLine.ToString(), IntPtr.Zero, IntPtr.Zero, true, NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref si, out pi) ) {
  733.         throw new Win32Exception();
  734.      }
  735.      
  736.      // Get the process.
  737.      return Process.GetProcessById(pi.dwProcessId);
  738.      
  739.   }
  740.  
  741.  
  742.  
  743.   /// <summary>
  744.   /// Gets an array of all the processes running on the Input desktop.
  745.   /// </summary>
  746.   /// <returns>An array of the processes.</returns>
  747.   public static Process[] GetInputProcesses()
  748.   {
  749.      return GetProcesses( GetName(Desktop.Input.DesktopHandle), StringComparison.InvariantCulture);
  750.   }  
  751.  
  752.   /// <summary>
  753.   /// Gets an array of all the processes running on the specified desktop.
  754.   /// </summary>
  755.   /// <param name="desktop">The name of the desktop for which to return processes</param>
  756.   /// <returns>An array of the processes.</returns>
  757.   public static Process[] GetProcesses(string desktop)
  758.   {
  759.      return GetProcesses( desktop, StringComparison.InvariantCultureIgnoreCase);
  760.   }      
  761.  
  762.   /// <summary>
  763.   /// Gets an array of all the processes running on the specified desktop (using the speficied string comparison)
  764.   /// </summary>
  765.   /// <param name="desktop">The name of the desktop for which to return processes</param>
  766.   /// <param name="comparisonType">The type of string comparison to do</param>
  767.   /// <returns>An array of the processes.</returns>
  768.   public static Process[] GetProcesses(string desktop, StringComparison comparisonType)
  769.   {
  770.      // get all processes.
  771.      Process[] processes = Process.GetProcesses();
  772.  
  773.      List<Process> procs = new List<Process>();
  774.  
  775.      // cycle through the processes.
  776.      foreach(Process process in processes)
  777.      {
  778.         // check the threads of the process - are they in this one?
  779.         foreach(ProcessThread pt in process.Threads)
  780.         {
  781.            string deskname = GetName(GetThreadDesktop(pt.Id));
  782.            if(deskname == null) continue;
  783.            
  784.            // check for a desktop name match.
  785.            if (deskname.Equals(desktop,comparisonType))
  786.            {
  787.               // found a match, add to list, and bail.
  788.               procs.Add(process);
  789.               break;
  790.            } else {
  791.               Console.WriteLine("Wow, Really? The '" + deskname + "' desktop showed up!");
  792.            }
  793.         }
  794.      }
  795.      return procs.ToArray();
  796.   }
  797.   #endregion
  798.  
  799.   #region IDisposable
  800.   /// <summary>
  801.   /// Dispose Object.
  802.   /// </summary>
  803.   public void Dispose()
  804.   {
  805.      // dispose
  806.      Dispose(true);
  807.  
  808.      // suppress finalisation
  809.      GC.SuppressFinalize(this);
  810.   }
  811.  
  812.   /// <summary>
  813.   /// Dispose Object.
  814.   /// </summary>
  815.   /// <param name="disposing">True to dispose managed resources.</param>
  816.   public virtual void Dispose(bool disposing)
  817.   {
  818.      if (!m_disposed)
  819.      {
  820.         // dispose of managed resources,
  821.         // close handles
  822.         Close();
  823.      }
  824.  
  825.      m_disposed = true;
  826.   }
  827.  
  828.   private void CheckDisposed()
  829.   {
  830.      // check if disposed
  831.      if (m_disposed)
  832.      {
  833.         // object disposed, throw exception
  834.         throw new ObjectDisposedException("");
  835.      }
  836.   }
  837.   #endregion
  838.  
  839.   #region ICloneable
  840.   /// <summary>
  841.   /// Creates a new Desktop object with the same desktop open.
  842.   /// </summary>
  843.   /// <returns>Cloned desktop object.</returns>
  844.   public object Clone()
  845.   {
  846.      // make sure object isnt disposed.
  847.      CheckDisposed();
  848.  
  849.      Desktop desktop = new Desktop(m_desktopName);
  850.  
  851.      // if a desktop is open, make the clone open it.
  852.      if (IsOpen) desktop.Open();
  853.  
  854.      return desktop;
  855.   }
  856.   #endregion
  857.  
  858.   #region Overrides
  859.   /// <summary>
  860.   /// Gets the desktop name.
  861.   /// </summary>
  862.   /// <returns>The desktop name, or a blank string if no desktop open.</returns>
  863.   public override string ToString()
  864.   {
  865.      // return the desktop name.
  866.      return m_desktopName;
  867.   }
  868.   #endregion
  869. }
  870. '@
  871.  
  872. if( !([Desktop]::GetDesktops() -eq "Alternate") ) {
  873.    [Desktop]::Create("Alternate") | Out-Null
  874.    ## Don't use PowerShell.exe (Try it, you'll see why)
  875.    [Desktop]::CreateProcess("PowerShell_ISE.exe", $MyInvocation.MyCommand.Definition, "Alternate")
  876. }
  877.  
  878. Write-Host "Now try:
  879. [Desktop]::Show('Alternate')
  880. and when you get there, to come back you can:
  881. [Desktop]::Show('Default')
  882. "

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me