Feedback

C# - Desktop Klasse (CreateDesktop)

Veröffentlicht von am 02.11.2009
(6 Bewertungen)
ich bin dabei eine Desktop Class zu schreiben.
Und das ist Version 1 davon

Am Ende möchte ich zwischen mehreren Desktops umschalten (wie bei Linux)

Using:
using System.Runtime.InteropServices;
GFU-Schulungen  [Anzeige]

VB.NET Einführung

Die Schulung zeigt Ihnen, wie Sie einfache, benutzerorientierte Programme, die auf Datenbanken zugreifen, in VB.NET eigenständig entwickeln. 

C# 2017/2015/2013 Aufbau

In dieser Schulung lernen Sie fortgeschrittene Techniken im Bereich .Net C#. Dabei stehen neben den eigentlichen Techniken auch architektonische Aspekte im Mittelpunkt.


using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;


namespace WindowsDesktop
{
    public class Desktop : IDisposable
    {
        #region DLLs
        [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 SwitchDesktop(IntPtr hDesktop);

        [DllImport("user32.dll", EntryPoint = "CloseDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseDesktop(IntPtr handle);

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

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

        [DllImport("kernel32.dll")]
        public static extern int GetCurrentThreadId();
        #endregion

        #region Enumeratoren
        [Flags]
        internal enum DESKTOP_ACCESS_MASK : uint
        {
            DESKTOP_NONE = 0,
            DESKTOP_READOBJECTS = 0x0001,
            DESKTOP_CREATEWINDOW = 0x0002,
            DESKTOP_CREATEMENU = 0x0004,
            DESKTOP_HOOKCONTROL = 0x0008,
            DESKTOP_JOURNALRECORD = 0x0010,
            DESKTOP_JOURNALPLAYBACK = 0x0020,
            DESKTOP_ENUMERATE = 0x0040,
            DESKTOP_WRITEOBJECTS = 0x0080,
            DESKTOP_SWITCHDESKTOP = 0x0100,

            GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
                            DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK |
                            DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP),
        }
        #endregion

        #region Dispose 
        public void Dispose()
        {
            SwitchToOrginal();
            ((IDisposable)this).Dispose();
        }

        /// <summary>
        /// Unterklassen können hier die Funktionalität der Objektzerstörung erweitern. 
        /// </summary>
        /// <param name="fDisposing"></param>
        protected virtual void Dispose(bool fDisposing)
        {
            if (fDisposing)
            {
                // Hier die verwalteten Ressourcen freigeben
                //BspVariable1 = null;
                CloseDesktop(DesktopPtr);
            }
            // Hier die unverwalteten Ressourcen freigeben
        }

        void IDisposable.Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this); //Fordert das System auf, den Finalizer für das angegebenen Objekt nicht aufzurufen
        }
        #endregion

        #region Variablen
        IntPtr _hOrigDesktop;
        public IntPtr DesktopPtr;
        private string _sMyDesk;
        public string DesktopName
        {
            get
            {
                return (_sMyDesk);
            }
            set
            {
                _sMyDesk = value;
            }
        }
        #endregion

        #region Konstruktoren
        public Desktop()
        {
            _sMyDesk = "";
        }

        public Desktop(string sDesktopName)
        {
            _hOrigDesktop = GetCurrentDesktopPtr();
            _sMyDesk = sDesktopName;
            DesktopPtr = CreateMyDesktop();
        }
        #endregion

        #region Methoden
        public void show()
        {
            SetThreadDesktop(DesktopPtr);
            SwitchDesktop(DesktopPtr);
        }

        public void SwitchToOrginal()
        {
            SwitchDesktop(_hOrigDesktop);
            SetThreadDesktop(_hOrigDesktop);
        }

        private IntPtr CreateMyDesktop()
        {
            return CreateDesktop(_sMyDesk, IntPtr.Zero, IntPtr.Zero, 0, (long)DESKTOP_ACCESS_MASK.GENERIC_ALL, IntPtr.Zero);
        }

        public IntPtr GetCurrentDesktopPtr()
        {
            return GetThreadDesktop(GetCurrentThreadId());
        }
        #endregion

    }
}


11 Kommentare zum Snippet

Krzysztof schrieb am 02.11.2009:
Aufruf Beispiel:


Desktop myDesk = new Desktop("MeinTestDesktop");
System.Threading.Thread.Sleep(1000);
Application.DoEvents();
myDesk.show();
Application.DoEvents();
System.Threading.Thread.Sleep(3000);
myDesk.SwitchToOrginal();
Application.DoEvents();
myDesk.Dispose();

Leonardo schrieb am 02.11.2009:

da ist ja NIX drauf.
aber von mir gibt es eine 10
Krzysztof schrieb am 03.11.2009:
danke,
die nächste version kann Prozesse starten
Krzysztof schrieb am 03.11.2009:
bitte mein Snippet bewerten.
konstruktive Kritik und Vorschläge sind auch erwünscht :-)
Lassi schrieb am 05.11.2009:
Abend,

schöne Sache was du da gemacht hast
also von mir gibt es 10 Punkte!

Ich weis nicht vielleicht hab ichs übersehen aber des Desktop wird doch auf dem selben Kern wie die Anwendung gestartet oder?
Wenn ja kannste das ja einbauen wenn mehrer Desktops gestartet werden das diese verteilt werden.

gruß Lassi
Krzysztof schrieb am 05.11.2009:
hi,

danke für deine Bewertung Lassi.
ja das ist echt ne gute Idee
das kommt auf meine Liste
Krzysztof schrieb am 05.11.2009:
Momentan versuche ich Windoof dazu überreden, dass meine Anwendung automatisch von Desktop zu Desktop mit kommt. Aber die ist stur und erscheint überall aber leider nicht auf meinem neuen Desktop.
Hat einer eine Idee?
Timo Pijnappel schrieb am 15.11.2009:
An diesem Problem habe ich auch schon mal gearbeitet. Die Desktop API hat da aber einige Fallstricke. Besonders seit Vista...

Ich habe das damals so gemacht, dass ich die Listen der aktiven Fenster manuell verwaltet habe und die Fenster je nach Benutzerauswahl angezeigt oder versteckt habe. Das erleichtert auch das verschieben von Fenstern auf andere Desktops.

Hauptsächlich habe ich dafür EnumWindows und ShowWindow genutzt.
Thomas Roskop schrieb am 23.10.2016:
Hier die Erweiterung zum Starten von Prozessen (sehr grob, funktioniert, aber nicht sauber formatiert):


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

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

private const int NORMAL_PRIORITY_CLASS = 0x00000020;

public void CreateProcessInIt(string path)
{
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = this.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) -- Error!

// Get the process.
// Process.GetProcessById(pi.dwProcessId);
}
Anonyme()Methode schrieb am 04.09.2017:
Hallo Krzysztof ,
es würde mich interessieren, du bei diesem Projekt schon weiter bist, vor allem, wie du den P/Invoke Aufruf machst.
Mfg Max
Martin Dauskardt schrieb am 05.09.2017:
@ Anonyme()Methode: Heute haben wir doch alle Windows 10 und damit auch mehrere Desktops zur Verfügung ;-)
 

Logge dich ein, um hier zu kommentieren!