Click here to Skip to main content
15,881,882 members
Please Sign up or sign in to vote.
4.20/5 (3 votes)
See more:
C#
using System;
using System.Threading;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Specialized;


using System.IO;


namespace Desktop_withExplorer
{    
    
    public class Desktop : IDisposable, ICloneable
    {
        #region Imports
        [DllImport("kernel32.dll")]
        private static extern int GetThreadId(IntPtr thread);


        [DllImport("kernel32.dll")]
        private static extern int GetProcessId(IntPtr process);

        //
        // Imported winAPI functions.
        //
        [DllImport("user32.dll")]
        private static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags, long dwDesiredAccess, IntPtr lpsa);

        [DllImport("user32.dll")]
        private static extern bool CloseDesktop(IntPtr hDesktop);

        [DllImport("user32.dll")]
        private static extern IntPtr OpenDesktop(string lpszDesktop, int dwFlags, bool fInherit, long dwDesiredAccess);

        [DllImport("user32.dll")]
        private static extern IntPtr OpenInputDesktop(int dwFlags, bool fInherit, long dwDesiredAccess);

        [DllImport("user32.dll")]
        private static extern bool SwitchDesktop(IntPtr hDesktop);

        [DllImport("user32.dll")]
        private static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopProc lpEnumFunc, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr GetProcessWindowStation();

        [DllImport("user32.dll")]
        private static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDesktopWindowsProc lpfn, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern bool SetThreadDesktop(IntPtr hDesktop);

        [DllImport("user32.dll")]
        private static extern IntPtr GetThreadDesktop(int dwThreadId);

        [DllImport("user32.dll")]
        private static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, IntPtr pvInfo, int nLength, ref int lpnLengthNeeded);


        [DllImport("kernel32.dll")]
        private static extern bool CreateProcess(
            string lpApplicationName,
            string lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            bool bInheritHandles,
            int dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            ref PROCESS_INFORMATION lpProcessInformation
            );

        [DllImport("user32.dll")]
        private static extern int GetWindowText(IntPtr hWnd, IntPtr lpString, int nMaxCount);

        private delegate bool EnumDesktopProc(string lpszDesktop, IntPtr lParam);
        private delegate bool EnumDesktopWindowsProc(IntPtr desktopHandle, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential)]
        private struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct STARTUPINFO
        {
            public int cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public int dwX;
            public int dwY;
            public int dwXSize;
            public int dwYSize;
            public int dwXCountChars;
            public int dwYCountChars;
            public int dwFillAttribute;
            public int dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
        #endregion


        #region Constants
        /// <summary>
        /// Size of buffer used when retrieving window names.
        /// </summary>
        public const int MaxWindowNameLength = 100;

        //
        // winAPI constants.
        //
        private const short SW_HIDE = 0;
        private const short SW_NORMAL = 1;
        private const int STARTF_USESTDHANDLES = 0x00000100;
        private const int STARTF_USESHOWWINDOW = 0x00000001;
        private const int UOI_NAME = 2;
        private const int STARTF_USEPOSITION = 0x00000004;
        private const int NORMAL_PRIORITY_CLASS = 0x00000020;
        private const long DESKTOP_CREATEWINDOW = 0x0002L;
        private const long DESKTOP_ENUMERATE = 0x0040L;
        private const long DESKTOP_WRITEOBJECTS = 0x0080L;
        private const long DESKTOP_SWITCHDESKTOP = 0x0100L;
        private const long DESKTOP_CREATEMENU = 0x0004L;
        private const long DESKTOP_HOOKCONTROL = 0x0008L;
        private const long DESKTOP_READOBJECTS = 0x0001L;
        private const long DESKTOP_JOURNALRECORD = 0x0010L;
        private const long DESKTOP_JOURNALPLAYBACK = 0x0020L;
        private const long AccessRights = DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_READOBJECTS;
        #endregion



        #region Structures
        /// <summary>
        /// Stores window handles and titles.
        /// </summary>
        public struct Window
        {
            #region Private Variables
            private IntPtr m_handle;
            private string m_text;
            #endregion

            #region Public Properties
            /// <summary>
            /// Gets the window handle.
            /// </summary>
            public IntPtr Handle
            {
                get
                {
                    return m_handle;
                }
            }

            /// <summary>
            /// Gets teh window title.
            /// </summary>
            public string Text
            {
                get
                {
                    return m_text;
                }
            }
            #endregion

            #region Construction
            /// <summary>
            /// Creates a new window object.
            /// </summary>
            /// <param name="handle">Window handle.</param>
            /// <param name="text">Window title.</param>
            public Window(IntPtr handle, string text)
            {
                m_handle = handle;
                m_text = text;
            }
            #endregion
        }




        /// <summary>
        /// A collection for Window objects.
        /// </summary>
        public class WindowCollection : CollectionBase
        {
            #region Public Properties
            /// <summary>
            /// Gets a window from teh collection.
            /// </summary>
            public Window this[int index]
            {
                get
                {
                    return (Window)List[index];
                }
            }
            #endregion

            #region Methods
            /// <summary>
            /// Adds a window to the collection.
            /// </summary>
            /// <param name="wnd">Window to add.</param>
            public void Add(Window wnd)
            {
                // adds a widow to the collection.
                List.Add(wnd);
            }
            #endregion
        }
        #endregion

        #region Private Variables
        private IntPtr m_desktop;
        private string m_desktopName;
        private static StringCollection m_sc;
        private ArrayList m_windows;
        private bool m_disposed;
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets if a desktop is open.
        /// </summary>
        public bool IsOpen
        {
            get
            {
                return (m_desktop != IntPtr.Zero);
            }
        }

        /// <summary>
        /// Gets the name of the desktop, returns null if no desktop is open.
        /// </summary>
        public string DesktopName
        {
            get
            {
                return m_desktopName;
            }
        }

        /// <summary>
        /// Gets a handle to the desktop, IntPtr.Zero if no desktop open.
        /// </summary>
        public IntPtr DesktopHandle
        {
            get
            {
                return m_desktop;
            }
        }

        /// <summary>
        /// Opens the default desktop.
        /// </summary>
        public static readonly Desktop Default = Desktop.OpenDefaultDesktop();

        /// <summary>
        /// Opens the desktop the user if viewing.
        /// </summary>
        public static readonly Desktop Input = Desktop.OpenInputDesktop();
        #endregion

        #region Construction/Destruction
        /// <summary>
        /// Creates a new Desktop object.
        /// </summary>
        public Desktop()
        {
            // init variables.
            m_desktop = IntPtr.Zero;
            m_desktopName = String.Empty;
            m_windows = new ArrayList();
            m_disposed = false;
        }

        // constructor is private to prevent invalid handles being passed to it.
        private Desktop(IntPtr desktop)
        {
            // init variables.
            m_desktop = desktop;
            m_desktopName = Desktop.GetDesktopName(desktop);
            m_windows = new ArrayList();
            m_disposed = false;
        }

        ~Desktop()
        {
            // clean up, close the desktop.
            Close();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Creates a new desktop.  If a handle is open, it will be closed.
        /// </summary>
        /// <param name="name">The name of the new desktop.  Must be unique, and is case sensitive.</param>
        /// <returns>True if desktop was successfully created, otherwise false.</returns>
        public bool Create(string name)
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // close the open desktop.
            if (m_desktop != IntPtr.Zero)
            {
                // attempt to close the desktop.
                if (!Close()) return false;
            }

            // make sure desktop doesnt already exist.
            if (Desktop.Exists(name))
            {
                // it exists, so open it.
                return Open(name);
            }

            // attempt to create desktop.
            m_desktop = CreateDesktop(name, IntPtr.Zero, IntPtr.Zero, 0, AccessRights, IntPtr.Zero);

            m_desktopName = name;

            // something went wrong.
            if (m_desktop == IntPtr.Zero) return false;

            return true;
        }

        /// <summary>
        /// Closes the handle to a desktop.
        /// </summary>
        /// <returns>True if an open handle was successfully closed.</returns>
        public bool Close()
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // check there is a desktop open.
            if (m_desktop != IntPtr.Zero)
            {
                // close the desktop.
                bool result = CloseDesktop(m_desktop);

                if (result)
                {
                    m_desktop = IntPtr.Zero;

                    m_desktopName = String.Empty;
                }

                return result;
            }

            // no desktop was open, so desktop is closed.
            return true;
        }

        /// <summary>
        /// Opens a desktop.
        /// </summary>
        /// <param name="name">The name of the desktop to open.</param>
        /// <returns>True if the desktop was successfully opened.</returns>
        public bool Open(string name)
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // close the open desktop.
            if (m_desktop != IntPtr.Zero)
            {
                // attempt to close the desktop.
                if (!Close()) return false;
            }

            // open the desktop.
            m_desktop = OpenDesktop(name, 0, true, AccessRights);

            // something went wrong.
            if (m_desktop == IntPtr.Zero) return false;

            m_desktopName = name;

            return true;
        }

        /// <summary>
        /// Opens the current input desktop.
        /// </summary>
        /// <returns>True if the desktop was succesfully opened.</returns>
        public bool OpenInput()
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // close the open desktop.
            if (m_desktop != IntPtr.Zero)
            {
                // attempt to close the desktop.
                if (!Close()) return false;
            }

            // open the desktop.
            m_desktop = OpenInputDesktop(0, true, AccessRights);

            // something went wrong.
            if (m_desktop == IntPtr.Zero) return false;

            // get the desktop name.
            m_desktopName = Desktop.GetDesktopName(m_desktop);

            return true;
        }

        /// <summary>
        /// Switches input to the currently opened desktop.
        /// </summary>
        /// <returns>True if desktops were successfully switched.</returns>
        public bool Show()
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // make sure there is a desktop to open.
            if (m_desktop == IntPtr.Zero) return false;

            // attempt to switch desktops.
            bool result = SwitchDesktop(m_desktop);

            return result;
        }

        /// <summary>
        /// Enumerates the windows on a desktop.
        /// </summary>
        /// <param name="windows">Array of Desktop.Window objects to recieve windows.</param>
        /// <returns>A window colleciton if successful, otherwise null.</returns>
        public WindowCollection GetWindows()
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // make sure a desktop is open.
            if (!IsOpen) return null;

            // init the arraylist.
            m_windows.Clear();
            WindowCollection windows = new WindowCollection();

            // get windows.
            bool result = EnumDesktopWindows(m_desktop, new EnumDesktopWindowsProc(DesktopWindowsProc), IntPtr.Zero);

            // check for error.
            if (!result) return null;

            // get window names.
            windows = new WindowCollection();

            IntPtr ptr = Marshal.AllocHGlobal(MaxWindowNameLength);

            foreach (IntPtr wnd in m_windows)
            {
                GetWindowText(wnd, ptr, MaxWindowNameLength);
                windows.Add(new Window(wnd, Marshal.PtrToStringAnsi(ptr)));
            }

            Marshal.FreeHGlobal(ptr);

            return windows;
        }

        private bool DesktopWindowsProc(IntPtr wndHandle, IntPtr lParam)
        {
            // add window handle to colleciton.
            m_windows.Add(wndHandle);

            return true;
        }

        /// <summary>
        /// Creates a new process in a desktop.
        /// </summary>
        /// <param name="path">Path to application.</param>
        /// <returns>The process object for the newly created process.</returns>
        public Process CreateProcess(string path)
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // make sure a desktop is open.
            if (!IsOpen) return null;

            // set startup parameters.
            STARTUPINFO si = new STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = m_desktopName;

            PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

            // start the process.
            bool result = CreateProcess(null, path, IntPtr.Zero, IntPtr.Zero, true, NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref si, ref pi);

            // error?
            if (!result) return null;

            // Get the process.
            return Process.GetProcessById(pi.dwProcessId);
        }

        /// <summary>
        /// Prepares a desktop for use.  For use only on newly created desktops, call straight after CreateDesktop.
        /// </summary>
        public void Prepare()
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // make sure a desktop is open.
            if (IsOpen)
            {
                // load explorer.
                CreateProcess("explorer.exe");
            }
        }
        #endregion

        #region Static Methods
        /// <summary>
        /// Enumerates all of the desktops.
        /// </summary>
        /// <param name="desktops">String array to recieve desktop names.</param>
        /// <returns>True if desktop names were successfully enumerated.</returns>
        public static string[] GetDesktops()
        {
            // attempt to enum desktops.
            IntPtr windowStation = GetProcessWindowStation();

            // check we got a valid handle.
            if (windowStation == IntPtr.Zero) return new string[0];

            string[] desktops;

            // lock the object. thread safety and all.
            lock (m_sc = new StringCollection())
            {
                bool result = EnumDesktops(windowStation, new EnumDesktopProc(DesktopProc), IntPtr.Zero);

                // something went wrong.
                if (!result) return new string[0];

                //	// turn the collection into an array.
                desktops = new string[m_sc.Count];
                for (int i = 0; i < desktops.Length; i++) desktops[i] = m_sc[i];
            }

            return desktops;
        }

        private static bool DesktopProc(string lpszDesktop, IntPtr lParam)
        {
            // add the desktop to the collection.
            m_sc.Add(lpszDesktop);

            return true;
        }

        /// <summary>
        /// Switches to the specified desktop.
        /// </summary>
        /// <param name="name">Name of desktop to switch input to.</param>
        /// <returns>True if desktops were successfully switched.</returns>
        public static bool Show(string name)
        {
            // attmempt to open desktop.
            bool result = false;

            using (Desktop d = new Desktop())
            {
                result = d.Open(name);

                // something went wrong.
                if (!result) return false;

                // attempt to switch desktops.
                result = d.Show();
            }

            return result;
        }

        /// <summary>
        /// Gets the desktop of the calling thread.
        /// </summary>
        /// <returns>Returns a Desktop object for the valling thread.</returns>
        public static Desktop GetCurrent()
        {
            // get the desktop.
            return new Desktop(GetThreadDesktop(AppDomain.GetCurrentThreadId()));
        }

        /// <summary>
        /// Sets the desktop of the calling thread.
        /// NOTE: Function will fail if thread has hooks or windows in the current desktop.
        /// </summary>
        /// <param name="desktop">Desktop to put the thread in.</param>
        /// <returns>True if the threads desktop was successfully changed.</returns>
        public static bool SetCurrent(Desktop desktop)
        {
            // set threads desktop.
            if (!desktop.IsOpen) return false;

            return SetThreadDesktop(desktop.DesktopHandle);
        }

        /// <summary>
        /// Opens a desktop.
        /// </summary>
        /// <param name="name">The name of the desktop to open.</param>
        /// <returns>If successful, a Desktop object, otherwise, null.</returns>
        public static Desktop OpenDesktop(string name)
        {
            // open the desktop.
            Desktop desktop = new Desktop();
            bool result = desktop.Open(name);

            // somethng went wrong.
            if (!result) return null;

            return desktop;
        }

        /// <summary>
        /// Opens the current input desktop.
        /// </summary>
        /// <returns>If successful, a Desktop object, otherwise, null.</returns>
        public static Desktop OpenInputDesktop()
        {
            // open the desktop.
            Desktop desktop = new Desktop();
            bool result = desktop.OpenInput();

            // somethng went wrong.
            if (!result) return null;

            return desktop;
        }

        /// <summary>
        /// Opens the default desktop.
        /// </summary>
        /// <returns>If successful, a Desktop object, otherwise, null.</returns>
        public static Desktop OpenDefaultDesktop()
        {
            // opens the default desktop.
            return Desktop.OpenDesktop("Default");
        }

        /// <summary>
        /// Creates a new desktop.
        /// </summary>
        /// <param name="name">The name of the desktop to create.  Names are case sensitive.</param>
        /// <returns>If successful, a Desktop object, otherwise, null.</returns>
        public static Desktop CreateDesktop(string name)
        {
            // open the desktop.
            Desktop desktop = new Desktop();
            bool result = desktop.Create(name);

            // somethng went wrong.
            if (!result) return null;

            return desktop;
        }

        /// <summary>
        /// Gets the name of a given desktop.
        /// </summary>
        /// <param name="desktop">Desktop object whos name is to be found.</param>
        /// <returns>If successful, the desktop name, otherwise, null.</returns>
        public static string GetDesktopName(Desktop desktop)
        {
            // get name.
            if (desktop.IsOpen) return null;

            return GetDesktopName(desktop.DesktopHandle);
        }

        /// <summary>
        /// Gets the name of a desktop from a desktop handle.
        /// </summary>
        /// <param name="desktopHandle"></param>
        /// <returns>If successful, the desktop name, otherwise, null.</returns>
        public static string GetDesktopName(IntPtr desktopHandle)
        {
            // check its not a null pointer.
            // null pointers wont work.
            if (desktopHandle == IntPtr.Zero) return null;

            // get the length of the name.
            int needed = 0;
            string name = String.Empty;
            GetUserObjectInformation(desktopHandle, UOI_NAME, IntPtr.Zero, 0, ref needed);

            // get the name.
            IntPtr ptr = Marshal.AllocHGlobal(needed);
            bool result = GetUserObjectInformation(desktopHandle, UOI_NAME, ptr, needed, ref needed);
            name = Marshal.PtrToStringAnsi(ptr);
            Marshal.FreeHGlobal(ptr);

            // something went wrong.
            if (!result) return null;

            return name;
        }

        /// <summary>
        /// Checks if the specified desktop exists (using a case sensitive search).
        /// </summary>
        /// <param name="name">The name of the desktop.</param>
        /// <returns>True if the desktop exists, otherwise false.</returns>
        public static bool Exists(string name)
        {
            return Desktop.Exists(name, false);
        }

        /// <summary>
        /// Checks if the specified desktop exists.
        /// </summary>
        /// <param name="name">The name of the desktop.</param>
        /// <param name="caseInsensitive">If the search is case INsensitive.</param>
        /// <returns>True if the desktop exists, otherwise false.</returns>
        public static bool Exists(string name, bool caseInsensitive)
        {
            // enumerate desktops.
            string[] desktops = Desktop.GetDesktops();

            // return true if desktop exists.
            foreach (string desktop in desktops)
            {
                if (caseInsensitive)
                {
                    // case insensitive, compare all in lower case.
                    if (desktop.ToLower() == name.ToLower()) return true;
                }
                else
                {
                    if (desktop == name) return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Creates a new process on the specified desktop.
        /// </summary>
        /// <param name="path">Path to application.</param>
        /// <param name="desktop">Desktop name.</param>
        /// <returns>A Process object for the newly created process, otherwise, null.</returns>
        public static Process CreateProcess(string path, string desktop)
        {
            if (!Desktop.Exists(desktop)) return null;

            // create the process.
            Desktop d = Desktop.OpenDesktop(desktop);
            return d.CreateProcess(path);
        }

        /// <summary>
        /// Gets an array of all the processes running on the Input desktop.
        /// </summary>
        /// <returns>An array of the processes.</returns>
        public static Process[] GetInputProcesses()
        {
            // get all processes.
            Process[] processes = Process.GetProcesses();

            ArrayList m_procs = new ArrayList();

            // get the current desktop name.
            string currentDesktop = GetDesktopName(Desktop.Input.DesktopHandle);

            // cycle through the processes.
            foreach (Process process in processes)
            {
                // check the threads of the process - are they in this one?
                foreach (ProcessThread pt in process.Threads)
                {
                    // check for a desktop name match.
                    if (GetDesktopName(GetThreadDesktop(pt.Id)) == currentDesktop)
                    {
                        // found a match, add to list, and bail.
                        m_procs.Add(process);
                        break;
                    }
                }
            }

            // put ArrayList into array.
            Process[] procs = new Process[m_procs.Count];

            for (int i = 0; i < procs.Length; i++) procs[i] = (Process)m_procs[i];

            return procs;
        }
        #endregion

        #region IDisposable
        /// <summary>
        /// Dispose Object.
        /// </summary>
        public void Dispose()
        {
            // dispose
            Dispose(true);

            // suppress finalisation
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Dispose Object.
        /// </summary>
        /// <param name="disposing">True to dispose managed resources.</param>
        public virtual void Dispose(bool disposing)
        {
            if (!m_disposed)
            {
                // dispose of managed resources,
                // close handles
                Close();
            }

            m_disposed = true;
        }

        private void CheckDisposed()
        {
            // check if disposed
            if (m_disposed)
            {
                // object disposed, throw exception
                throw new ObjectDisposedException("");
            }
        }
        #endregion

        #region ICloneable
        /// <summary>
        /// Creates a new Desktop object with the same desktop open.
        /// </summary>
        /// <returns>Cloned desktop object.</returns>
        public object Clone()
        {
            // make sure object isnt disposed.
            CheckDisposed();

            Desktop desktop = new Desktop();

            // if a desktop is open, make the clone open it.
            if (IsOpen) desktop.Open(m_desktopName);

            return desktop;
        }
        #endregion

        #region Overrides
        /// <summary>
        /// Gets the desktop name.
        /// </summary>
        /// <returns>The desktop name, or a blank string if no desktop open.</returns>
        public override string ToString()
        {
            // return the desktop name.
            return m_desktopName;
        }
        #endregion









        public static void Log(string logMessage, TextWriter w)
        {
            //w.Write("\r\nLog Entry : ");
            //w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
            //    DateTime.Now.ToLongDateString());
            //w.WriteLine("  :");
            //w.WriteLine("  :{0}", logMessage);
            w.WriteLine("  {0}", logMessage);
            //w.WriteLine("-------------------------------");
        }





        static void Main(string[] args)
        {

            //create desktop, add to it, then destroy

            Desktop desktop_normal= OpenInputDesktop();
            Desktop desktop_new = CreateDesktop("myDesktop");

            desktop_new.Show();
            Thread.Sleep(3000);

            Process p = desktop_new.CreateProcess("calc.exe");
            Thread.Sleep(3000);

            p.Kill();
            Thread.Sleep(3000);

            desktop_normal.Show();
            Thread.Sleep(3000);

            desktop_new.Dispose();
            Thread.Sleep(3000);





        }
    }
}
Posted
Updated 21-Nov-12 5:18am
v4
Comments
Sergey Alexandrovich Kryukov 20-Nov-12 15:57pm    
Why doing all that?
--SA
cellurl 20-Nov-12 15:59pm    
Do you have a simple Desktop example? It works, but doesn't close down (it hangs in the new desktop forever).

Motivation: I have to put a bunch of AHK's in separate Desktops.
Sergey Alexandrovich Kryukov 20-Nov-12 16:08pm    
AHK? What is it? Sorry; I have, but not simple, and not this kind... I cannot understand why running such trash as "Calc" and other things...
--SA
cellurl 20-Nov-12 16:32pm    
www.autohotkey.com
Sergey Alexandrovich Kryukov 20-Nov-12 16:38pm    
Ah, keyboard-based automation... bad thing. Applications are not designed for any collaboration, but some want to control them... dead-end way. Eventually, they disappear, will be replaced with components, the control is limited. Waste of time, I would say...
--SA

1 solution

this could help you,
Desktop Switching[^]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900