hi,
ich habe eine Unit geschrieben, die es ermöglicht eigene Windows Desktops zu verwalten.
Die Units sind von mir (bis auf compilers.inc) und in ANSI und Unicode aufgeteilt.
So ziemlich alles ist in Englisch kommentiert und auch mit Beispielen versehen.
Die verwendete Lizenz ist
Creative Commons
# Namensnennung. Sie müssen den Namen des Autors/Rechtsinhabers nennen.
# Keine kommerzielle Nutzung. Dieser Inhalt darf nicht für kommerzielle Zwecke verwendet werden.
# Weitergabe unter gleichen Bedingungen. Wenn Sie diesen Inhalt bearbeiten oder in anderer Weise umgestalten, verändern oder als Grundlage für einen anderen Inhalt verwenden, dann dürfen Sie den neu entstandenen Inhalt nur unter Verwendung identischer Lizenzbedingungen weitergeben.
1. Achtung!
Die aktuelle Version ist noch im Betastatus, da ich noch nicht lange Testen konnte.
2. Achtung!
Teste deine Desktopverwaltung auf einem zweiten PC oder in einer VM (auch über Remotedebugging). Sollte dein Programm unter Delphi eine Exception werfen, so zeigt Delphi die Quellcodezeile an. Da jedoch der Desktop in diesem Moment nicht zurückgesetzt wird, kommst du nicht zu Delphi und kannst daher auch nicht fortsetzen.
Der Desktop wird automatisch geschlossen, sobald deine Anwendung beendet wird.
Man kann daher auch über Telnet (o.Ä.) die Anwendung abschießen.
Bekannte Bugs :
In einigen Fällen bekomme ich bei der Erstellung eines neuen Desktops die Ausnahmen, dass nicht genügend Speicher zur Verfügung steht.
Ein Auszug aus
CreateDesktop beschreibt vermutlich die Ursache.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| The number of desktops that can be created is limited by the size of the system desktop heap, which is 48 MB. Desktop objects use the heap to store resources. You can increase the number of desktops that can be created by reducing the default heap reserved for each desktop in the interactive window station. This value is specified in the SharedSection substring of the following registry value: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems\Windows. The default data for this registry value is as follows:
%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
The first SharedSection value is the size of the shared heap common to all desktops, in kilobytes. The second SharedSection value is the size of the desktop heap needed for each desktop that is created in the interactive window station, WinSta0, in kilobytes. The third SharedSection value is the size of the desktop heap needed for each desktop that is created in a noninteractive window station, in kilobytes. |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163:
| TDesktop = class(TPersistent) public constructor Create(const aParent : TDesktops; const aFlag : TCreationFlag; const aCloseOnDestroy : Boolean; const aName : WideString; const DesktopFlags : TDesktopFlags; const doInherit : Boolean; const aDesiredAccess : ACCESS_MASK; const aSecurityDescriptor : PSECURITYATTRIBUTES);
constructor CreateUnInitialized(const aParent : TDesktops; const aName : WideString);
destructor Destroy; override;
function OpenDesktopByName(const DesktopFlags : TDesktopFlags; const doInherit : Boolean; const aDesiredAccess : ACCESS_MASK) : HDESK; overload; virtual;
function DesktopFlagsToInt(DesktopFlags : TDesktopFlags) : Cardinal;
function GetDesktopWindowHandles : TList; virtual;
function OpenInputDesktop(const DesktopFlags : TDesktopFlags; const doInherit : Boolean; const aDesiredAccess : ACCESS_MASK) : HDESK; virtual;
procedure Close; procedure SetThreadDesktop; procedure SwitchDesktop; procedure SwitchDesktopBack;
published property Name : WideString read GetName; property DesiredAccess : ACCESS_MASK read fDesiredAccess; property SecurityDescriptor : TSECURITYATTRIBUTES read RetrieveSD; property Handle : HDESK read fHandle; property DesktopFlags : TDesktopFlags read GetDesktopFlags write SetDesktopFlags; property IsInputDesktop : Boolean read fIsInputDesktop;
property Parent : TDesktops read fParent; property CloseOnDestroy : Boolean read fCloseOnDestroy write fCloseOnDestroy;
property Opened : Boolean read GetOpened; property OnDestroyDesktop : TOnDestroyDesktop read fOnDestroyDesktop write fOnDestroyDesktop; end; |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164:
| TDesktops = class(TComponent) public constructor Create(AOwner: TComponent); override; destructor Destroy; override;
procedure Clear; virtual;
function FindDesktopByName(const Name : WideString) : TDesktop; virtual; function FindDesktopByHandle(const Handle : HDESK) : TDesktop; virtual; function FindInputDesktop : TDesktop; virtual;
procedure Update; function CreateDesktop(const Name : WideString; const DesktopFlags : TDesktopFlags; const aDesiredAccess : ACCESS_MASK; const aSecurityDescriptor : PSECURITYATTRIBUTES) : TDesktop; virtual;
function OpenDesktop(const Name : WideString; const DesktopFlags : TDesktopFlags; const aDesiredAccess : ACCESS_MASK; const doInherit : Boolean) : TDesktop; virtual; function OpenInputDesktop(const DesktopFlags : TDesktopFlags; const aDesiredAccess : ACCESS_MASK; const doInherit : Boolean) : TDesktop; virtual;
function GetThreadDesktop(ThreadID : Cardinal = 0) : TDesktop;
class function GetDesktopName(const desk : HDESK) : WideString;
class function GetDesktops(WindowStation : HWINSTA) : TTntStringList; overload; virtual;
class function GetDesktopHeapSize : Cardinal; virtual; published property Desktops : tObjectlist read fDesktops; property OnDestroyDesktop : TOnDestroyDesktop read fOnDestroyDesktop write fOnDestroyDesktop;
end; |
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| var Desktops : TDesktops; MyDesktop : TDesktop; begin Desktops := TDesktops.Create(nil); MyDesktop := Desktops.CreateDesktop() MyDesktop := Desktops.CreateDesktop('MyDesktop1' ,[], GENERIC_ALL,nil);
if Assigned(MyDesktop) then try MyDesktop.SwitchDesktop; MyDesktop.SetThreadDesktop; ...do you stuff here... finally MyDesktop.SwitchDesktopBack; MyDesktop.SetThreadDesktop; end; Desktops.Free; Desktops := nil; end; |
Demo
Angehängt habe ich ein Beispielprogram mit VCL und KOL (
kolmck.net/).
Das Programm zeigt auf dem Hauptdesktop ein VCL Formular an mit dem man einen Desktop erstellen kann.
Auf dem neuen Desktop wird dann mit KOL ein neues Fenster in einem neuen Thread erstellt. Im Hintegrund wird ein eingegrautes Bild des alten Desktops dargestellt, so dass der Benutzer sich nicht wundert, warum alle seine Anwendungen verschwunden sind.
Dieses Verhalten sieht man auch in Vista.