PoshCode Logo PowerShell Code Repository

Desktop (modification of post by view diff)
View followups from Joel Bennett | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/2008"></script>download | new post

A C# class (use with Add-Type -Path) that encapsulates the desktop APIs…

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

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