Application MultiBureaux

Programmation d'applications complexes
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Application MultiBureaux

Message par graph100 »

J'ouvre ce topic pour suivre la progression de mon projet d'application destinée à permettre l'usage de plusieurs bureaux séparés.
J'apprécierais vos commentaires constructifs :D étant donné le mal que j'ai avec les API.
je remet ce que j'avais marqué lorsque j'avais décris mon projet, puisque c'est assez construit 8)
graph100 a écrit :Je suis tombé il n'y a pas longtemps sur un code permettant de placer les icônes du desktop là ou on veux.
Et j'ai déjà par le passé cherché des progs permettant d'avoir plusieurs bureaux. Mais les logiciels existants ne proposent qu'un changement des fenêtres.

Ce que je me suis défini comme but :

# Offrir plusieurs bureaux différents comportant les éléments suivants propres à chaque bureau
- un fond d'écran
- des icônes différents, à leurs positions respectives
- les fenêtres des différentes application ne se montrent que dans leurs bureaux respectifs.

# Une interface de configuration propre et agréable pour modifier les quelques paramètres du logiciel

# Une combinaison de touche permettant un changement rapide entre bureau, le mieux serais de faire un genre de cube, comme sur Mac. Un truc joli graphiquement, mais qui reste abordable pour les différents processeurs.

# Une possibilité de faire passer une fenêtre ouverte sur un des bureaux sur un autre (si la séparation des fenêtres est bien faite ^^)


Voila, j'espère que j'ai bien présenté mon projet :mrgreen:
Il y a besoin de bonnes connaissances sur les APIs, window, purebasic.
[edit]Je pense que je vais avoir des problèmes au niveau API :?
L'animation pour changer entre les différents bureaux, doit être vraiment belle, et fluide
Dernière modification par graph100 le dim. 12/juin/2011 0:02, modifié 1 fois.
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

Voila mon premier code, c'est un test pour aborder les API concernant les objets Desktops de window.
Pour plus de détail, je recommande la MSDN de MSoft.

Je pense que ça doit fonctionner sur les windows > Win2000, pourriez-vous tester sur window200, XP, et 7 ?
Je code sur un vista actuellement, et ça marche.

Le code créé un nouveau desktop, puis change l'affichage vers ce desktop, attend 10 sec, et ré-affiche le bureau par défaut.

IL EST TRÈS IMPORTANT de ne PAS enlever la ligne suivante :

Code : Tout sélectionner

SwitchDesktop_(ListeDesktop\Desktop("Default")) 
Cette ligne permet le retour sur le bureau par défaut. Si elle est absente, le pc reste sur l'autre (qui est vide :mrgreen: ) et on est bloqué. Il faut soit ctrlaltsuppr + logg off de la session, soit reboot le pc :mrgreen:

Code : Tout sélectionner

;{ structure

; Structure desktop_attribute
; 	nom.s
; 	handle.l ; si = 0 : pas ouvert
; EndStructure

Structure map_desktop
	Map Desktop.l()
EndStructure


;}



;{ procedures

Procedure.s FormatMessage(erreur.l)
	lpbuffer.s = Space(255)
	
	FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError_(), 0, @lpbuffer, 255, 0)
	
	ProcedureReturn lpbuffer
EndProcedure



; procedure appelée en callback par enumDesktop(), pour chaque objet Desktop rencontré
Procedure CallBackDesktop(nom.s, *adresse_map.map_desktop)
	res = OpenDesktop_(nom, 0, #True, #GENERIC_ALL)
	
	AddMapElement(*adresse_map\Desktop(), nom)
	
	*adresse_map\desktop() = res
	
	
; 	Debug "#####"
; 	Debug nom
; 	Debug res
; 	Debug bla
	
	ProcedureReturn #True
EndProcedure

Procedure CloseAllCallBackDesktop(*adresse_map.map_desktop)
	ForEach *adresse_map\Desktop()
		CloseDesktop_(*adresse_map\Desktop())
	Next
	
	ClearMap(*adresse_map\Desktop())
EndProcedure

Procedure EnumDesktops(*CallBackEnum, *adresse_map.map_desktop)
	; recupère la station window courante (normalement la fontion EnumDesktop_() le fait de base, mais ça bug
	current_window_station = GetProcessWindowStation_()
	Debug "Get Current WindowStation : " + FormatMessage(GetLastError_())
	
	If current_window_station = 0
		ProcedureReturn 0
	EndIf
	
	res = EnumDesktops_(current_window_station, *CallBackEnum, *adresse_map)
	
	ProcedureReturn res
EndProcedure



Procedure.l CreateDesktop(nom.s)
	Define.SECURITY_ATTRIBUTES lpsa
	
	lpsa\nLength = SizeOf(SECURITY_ATTRIBUTES)
	lpsa\lpSecurityDescriptor = 0
	lpsa\bInheritHandle = #True
	
	
	desktop_hd.l = CreateDesktop_(nom, #NULL$, #Null, 0, #GENERIC_ALL, @lpsa)
	
	ProcedureReturn desktop_hd
EndProcedure





;}



;{ cops du programme


; créé un nouveau bureau
desktop_hd = CreateDesktop("bureau_de_test")
Debug "Création du bureau : " + FormatMessage(GetLastError_())

If desktop_hd = 0
	End
EndIf

; Debug "On libère le handle de desktop ouvert : " + Str(CloseDesktop_(desktop_hd))


; on liste tout les bureaux ouverts, ATTENTION, la commande de listage est codée pour tous les ouvrir, il faut donc utiliser CloseAllCallBackDesktop() pour fermer les handles ouverts.
Define.map_desktop ListeDesktop

res = EnumDesktops(@CallBackDesktop(), @ListeDesktop)
Debug "Enumération des bureau : " + FormatMessage(GetLastError_())

If res = 0
	End
EndIf


; debug de tout les bureaux
Debug ""
ForEach ListeDesktop\Desktop()
	Debug MapKey(ListeDesktop\Desktop())
	Debug ListeDesktop\Desktop()
	Debug ""
Next





Debug "##############"

MessageRequester("", "Maintenant on va tester la fonction SwitchDesktop xD")

; Debug "Now switch to the desktop 'Bureau_de_test' : " + Str(ListeDesktop\Desktop("bureau_de_test"))
Debug "Now switch to the desktop 'Bureau_de_test' : " + Str(desktop_hd)

; SwitchDesktop_(ListeDesktop\Desktop("Bureau_de_test"))
SwitchDesktop_(desktop_hd)


; on attend 10 sec
For a = 1 To 10
	Delay(1000)
	Debug "plop " + Str(10 - a)
Next

Debug ""
Debug "Now switch back to the desktop 'Default' : " + Str(ListeDesktop\Desktop("Default"))

SwitchDesktop_(ListeDesktop\Desktop("Default")) 

Debug ""
Debug "On libère les desktops"
CloseAllCallBackDesktop(@ListeDesktop)


; on reliste tout pour voir les bureaux ouverts maintenant :

; on liste tout les bureaux ouverts, ATTENTION, la commande de listage est codée pour tous les ouvrir, il faut donc utiliser CloseAllCallBackDesktop() pour fermer les handles ouverts.
ClearMap(ListeDesktop\Desktop())

res = EnumDesktops(@CallBackDesktop(), @ListeDesktop)
Debug "Enumération des bureau : " + FormatMessage(GetLastError_())

If res = 0
	End
EndIf


; debug de tout les bureaux
Debug ""
ForEach ListeDesktop\Desktop()
	Debug MapKey(ListeDesktop\Desktop())
	Debug ListeDesktop\Desktop()
	Debug ""
Next

; on voit bien que l'objet créé n'est pas détruit !!!

Debug ""
Debug "On libère les desktops"
CloseAllCallBackDesktop(@ListeDesktop)


;}

End
Il y a juste un truc qui me chagrine : lorsque je créé un nouveau Desktop, je peux switch vers celui-ci.
Mais lorsque je libère l'objet, puis que je le re-ouvre à nouveau, je ne peux plus. Il doit y avoir une histoire de droits d'accès cachée la dedans.
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
bombseb
Messages : 445
Inscription : jeu. 25/août/2005 22:59
Localisation : 974
Contact :

Re: Application MultiBureaux

Message par bombseb »

Salut,

Je viens de le tester sur Win7, ca à l'air de marcher
C'est interressant en tout cas, je vois que tu a utilisé des apis comme CreateDesktop_
Je croyais que ca n'était pas géré par windows moi....
alors dans ce cas si les apis existent pourquoi n'ont t-ils pas inclus un truc par défaut comme sur Mac ou Linux pour gérer les bureaux ?
étrange quand même

en tout cas c'est un bon début, bon courage pour la suite
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Application MultiBureaux

Message par Backup »

c'est impressionant :)

bon boulot :)
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

bombseb a écrit :C'est interressant en tout cas, je vois que tu a utilisé des apis comme CreateDesktop_
Je croyais que ca n'était pas géré par windows moi....
alors dans ce cas si les apis existent pourquoi n'ont t-ils pas inclus un truc par défaut comme sur Mac ou Linux pour gérer les bureaux ?
Les desktops leurs servent à faire des situations sécurisées, comme l'écran de Logon. Effectivement on peux se poser la question de savoir pourquoi ils n'ont pas utilisé leur système plus loin ;) (pour des performances je pense)

J'ai avancé dans mon code, et j'ai besoin de savoir si le code suivant fonctionne sur toute les plateformes window de 2000 aux dernière version de 7. en effet la fonction que j'utilise ne se charge pas de la même manière partout -_-
moi j'ai testé sur vista.

Ce code énumère tous les process de l'ordinateur sur le debug. en cas d’échec il le signale.

Code : Tout sélectionner

Prototype.l EnumProcess(*pProcessIds.l, cb.l, *pBytesReturned.l)

Procedure EnumProcess(List Process.l())
	
	*pointeur = 0
	
	If OpenLibrary(0, "Kernel32.dll")
		*pointeur = GetFunction(0, "K32EnumProcesses")
	EndIf
		
	If *pointeur = 0
		If IsLibrary(0) : CloseLibrary(0) : EndIf
		
		If OpenLibrary(0, "Psapi.dll")
			*pointeur = GetFunction(0, "EnumProcesses")
			
			If *pointeur = 0
				ProcedureReturn 0
			EndIf
		Else
			ProcedureReturn 0
		EndIf
	EndIf
	
	; ici on devrais se retrouver avec un pointeur valide, vers la fonction EnumProcess
	; on utilise le pointeur pour créer la fonction prototypée
	EnumProcesses.EnumProcess = *pointeur
	
	size_of_memory = SizeOf(Long) * 50
	*mem = 0
	
	Repeat
		size_of_memory = size_of_memory + SizeOf(Long) * 50
		
		*mem = ReAllocateMemory(*mem, size_of_memory)
		res = EnumProcesses(*mem, size_of_memory, @taille_de_retour)
		
	Until res = 0 Or taille_de_retour < size_of_memory
	; si le nombre de byte de retour est egal à la taille du buffer, on considère que la liste est plus grande que ce que peut prendre le buffer
	
	If res = 0
		ProcedureReturn 0
	EndIf
	
	ClearList(Process())
	For a = 0 To taille_de_retour - SizeOf(Long) Step SizeOf(Long)
		AddElement(Process())
		
		Process() = PeekL(*mem + a)
	Next
	
	FreeMemory(*mem)
	
	CloseLibrary(0)
	
	ProcedureReturn 1
EndProcedure


NewList Process.l()

res = EnumProcess(Process())

If res = 0
	Debug "Echec de l'énumération"
Else
	ForEach Process()
		Debug Str(Process())
	Next
EndIf


@Dobro : merci ;)
c'est du débroussaillage d'API, et de l'adaptation vers Pb
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Application MultiBureaux

Message par Backup »

Sur XP ça me sort ça :
0
4
864
912
936
980
992
1156
1224
1264
1288
1368
1404
1728
1804
1836
260
888
892
1360
1532
688
700
708
828
1584
1904
2072
2088
2100
2128
2180
2228
2236
2276
2304
2760
3000
3344
3356
3364
3464
2380
2300
544
428
3672
756
3012
636
772
2404
3228
tu voulais obtenir quoi en fait ?
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

Donc ça fonctionne sous XP :D Parfait !
Ce code liste les PID des processus. Comme le fait le gestionnaires des tâches !
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

Bon, j'ai laissé tomber cette fonction pour le moment, je n'arrive pas à récupérer sur quel bureau se trouve un process, alors qu'on peux lancer un process dans un bureau particulier. J'arrête de plancher la-dessus...

Voila un exemple d'application, très basique, le code créé un nouveau Desktop, lance explorer dessus, ce qui permet de pouvoir avoir une interface. Puis une calculatrice, et retourne sous le bureau par défaut au bout de 10sec.

Pour le moment, je ne peux pas fermer un desktop : une fois créé, il reste là, jusqu'à la prochaine fermeture de session. Les processus lancés dedans sont toujours là, et donc prennent de la ram. C'est un des défauts de l'approche que j'ai choisie pour mon programme : explorer.exe doit être lancé autant de fois qu'il y a de bureaux ouverts.
je pense proposer de pouvoir lancer un autre programme à l'ouverture du bureau, pour permettre l'utilisation de GUI plus légère, si il en existe.

J'ai chez moi un problème, je ne peux créer qu'un seul nouveau bureau correctement. Sur tous les autres, les applications n'apparaissent pas. Je pense que c'est du à un problème de pile. Je regarderais ça demain.

Code : Tout sélectionner


;--------------------------------------
Procedure.s FormatMessage(erreur.l)
	lpbuffer.s = Space(255)
	
	FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError_(), 0, @lpbuffer, 255, 0)
	
	ProcedureReturn lpbuffer
EndProcedure
;--------------------------------------


;--------------------------------------
Procedure.l CreateDesktop(nom.s)
	Define.SECURITY_ATTRIBUTES lpsa
	
	lpsa\nLength = SizeOf(SECURITY_ATTRIBUTES)
	lpsa\lpSecurityDescriptor = 0
	lpsa\bInheritHandle = #True
	
	
	desktop_hd.l = CreateDesktop_(nom, #NULL$, #Null, 0, #GENERIC_ALL, @lpsa)
	
	ProcedureReturn desktop_hd
EndProcedure

Procedure.l OpenDesktop(nom.s, *desktophd.Long) ; ouvre un bureau existant, ou le créer si il n'existait pas
	*desktophd\l = OpenDesktop_(nom, 0, #True, #GENERIC_ALL)
	
	res = 2 ; le bureau spécifié existe déjà
	
	If *desktophd\l = 0
; 		Debug "Le bureau : " + nom + " n'existe pas. On va le recréer."
		
		*desktophd\l = CreateDesktop(nom)
		
		If *desktophd\l = 0
			; Debug "Création du bureau : " + FormatMessage(GetLastError_())
			ProcedureReturn 0 ; on retourne une erreur
		EndIf
		
		res = 1 ; on crée le bureau, car il n'existait pas
	EndIf
	
	ProcedureReturn res
EndProcedure
;--------------------------------------


;--------------------------------------
Procedure CreateProcess(application.s, desktop_name.s, *lpProcessInformation.PROCESS_INFORMATION)
	
	Define.SECURITY_ATTRIBUTES lpProcessAttributes
	
	With lpProcessAttributes
		\nLength = SizeOf(SECURITY_ATTRIBUTES)
		\lpSecurityDescriptor = 0
		\bInheritHandle = #True
	EndWith
	
	
	Define.STARTUPINFO lpStartupInfo
	
	With lpStartupInfo
		\cb = SizeOf(STARTUPINFO)
		\lpDesktop = @desktop_name
	EndWith
	
	res = CreateProcess_(#Null, #DQUOTE$ + application + #DQUOTE$, lpProcessAttributes, #Null, #True, #NORMAL_PRIORITY_CLASS, #Null, GetPathPart(application), lpStartupInfo, *lpProcessInformation)
	
	If res = 0
		Debug "Failed"
		Debug "CreateProcess : " + FormatMessage(GetLastError_())
	Else
		Debug "Created"
	EndIf
	
	ProcedureReturn res
EndProcedure
;--------------------------------------





nom_du_bureau.s = "bureau_de_test"
res = OpenDesktop(nom_du_bureau, @desktop_hd)

If res = 0 
	Debug "Erreur lors de la création du bureau : " + nom_du_bureau
	End
EndIf


If res = 1
	Debug "Création du bureau : " + nom_du_bureau
	
	; on lance explorer dans le nouveau bureau, mais juste la 1ère fois
	CreateProcess("C:\Windows\explorer.exe", "bureau_de_test", @information_process.PROCESS_INFORMATION)
Else
	Debug "Ouverture du bureau : " + nom_du_bureau
EndIf

CreateProcess("C:\Windows\System32\calc.exe", "bureau_de_test", @information_process.PROCESS_INFORMATION)


; on passe sur le bureau nouvellement créé
SwitchDesktop_(desktop_hd)


Delay(10000)


desktop_default = OpenDesktop_("Default", 0, #True, #GENERIC_ALL)

; on retourne sur le bureau par défaut
SwitchDesktop_(desktop_default)
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

Le problème concernant la création de plusieurs bureau est normalement réglé.
Le bureau se créaient bien, mais explorer doit être lancé avec un répertoire courant différent pour chaque instance. sinon ça ouvre juste une autre fenêtre dans l'autre.

Je vous sort une version qui permet de changer entre les bureaux simplement dans pas trop longtemps.
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Application MultiBureaux

Message par nico »

Pour ton problème de savoir dans quel bureau à été lancé un exe, je pense qu'il devrait suffire de regarder quel est le parent qui a lancé l'exe et ainsi de suite pour vérifier à quel PID de l'explorer il appartient, c'est vrai qu'un process du bureau 1 peut lancer un process dans le bureau 2 mais c'est un cas qui restera assez rare.
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

Tu es sûr que tout les process sont enfants du process explorer ?
Mais le problème, c'est que si ça plante, et que le explorer se ferme, on ne peut plus remonter :(

Il devrait y avoir un tag dans les threads normalement, qui définit à quel desktop le thread appartient. Car c'est encore plus vicieux que cela n'y parait ! Ce ne sont pas les process qui sont associés avec un desktop, ce sont les threads !
Un process peut avoir un thread dans chaque desktop. Et d'après ce que j'ai compris, pour fermer un desktop, il ne faut plus de thread actifs dans ce desktop, ni de handle de ce même desktop ouverts.

Comme les desktops se ferment lors de la fermeture de session, je ne pense pas que ce soit un inconvénient majeur. cependant, la présence de tout les explorer et les autres programmes peut ralentir le pc...
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Application MultiBureaux

Message par nico »

Tout les process qui sont lancés par l'utilisateur sont normalement enfant de l'explorer; tu peux utiliser Process Explorer pour le vérifier.
Mais c'est vrai que si l'explorateur plante, ça complique la chose

Mais bon, il est logique que ce soit l'utilisateur qui met fin aux processus qui les a lancés.
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

nico a écrit :Mais bon, il est logique que ce soit l'utilisateur qui met fin aux processus qui les a lancés.
Effectivement, c'est aussi une des raisons pour laquelle j'ai stoppé dans cette direction. Je me suis dit que je n'aimerais pas qu'on tue mes applications pas très proprement avec un TerminateProcess_() -_-
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Application MultiBureaux

Message par graph100 »

Première version de MultiBureau.
Je n'en suis pas fier du tout. Le code est assez brouillon. ça part dans tout les sens. Et surtout il y trop de thread. Et de la découle des erreurs possibles et parfois non débuggable.

Normalement cette version est à peu près stable. Tout les tests que j'ai réalisé (sous Vista) n'ont pas buggés.
Lorsque le programme se lance, la fenêtre de paramètre apparait, elle ne permet pour l'instant que de rajouter des bureaux. (Ajouter, mettre un nom, puis créer). J'ai tester jusqu'à 6 bureaux, je n'ai pas fait de contrôle sur le nombre de bureau, mais on ne peux en accéder que 10 de toute façon.

Le programme créé les dossiers : Bureau_1, bureau_2, etc.. dans le répertoire racine de l'utilisateur pour lancer les différentes fenêtres des Shell (explorer.exe)

Raccourcis : Ctrl + 1, Ctrl + 2, ...., Ctrl + 9, Ctrl + 0 pour switcher entre les bureaux, Ctrl + F3 pour ouvrir la fenetre de paramètrage
Il y a aussi Ctrl + F12 pour fermer l'application, cependant, comme les bureaux ne se ferment pas, ainsi que les applications lancées, ce raccourci n'est là que pour le développement de l'application.

Pour fermer tout les bureaux : Fermez la session :lol:

Code : Tout sélectionner

;######################################
; programme : MultiBureau
#VERSION = "1.00alpha0"
; description : - Permet de créer plusieurs bureaux réels sur window et de changer entre eux rapidement
;								
; détails :			- Fenetre de parametre pour regler les différents bureaux ( Ctrl + F3 )
;								- raccourcis Ctrl + 1 ~ 9 et 0 pour switcher entre les bureaux
;								- fermer le programme : Ctrl + F12 (ne ferme pas les desktops, ni les applications lancées, il faut fermer la session pour cela)

;	ajouts prévus :	- modification de l'interface
;									- eradication des bugs possibles
;									- changement réels des bureaux pour l'explorateur windows
;									- changement du système de raccourcis
;									
; auteur : graph100 alias Kriek106
;######################################




;{ Structure, variables globales et constantes

Structure Bureau
	nom.s
	hd_bureau.l
	numero.l
	
	hd_miniature.l
	
	nom_utilisateur.s
	dossier_bureau.s
	
	programme.s
	wallpaper.s
	
	thread.l
EndStructure


Global currentdirectory$ = GetCurrentDirectory()
Global USER.s, InitFile$ = "Multibureau.init"

Global Bureau_ACTUEL.s = "Default", IS_PARAMETRE_BEING_SET.b = #False
Global taille_max_snapshot.l = 140, EXIT_PROGRAM.b = #False

Global NewMap Desktop.Bureau()

#WHEEL_DELTA = 120

;}


;{ procedure

Declare ThreadRaccourcisClavier(*adresse.String)


Procedure.s GetUserName()
	_user_.s = Space(255)
	size = 255
	
	While GetUserName_(@_user_, @size) = #False
		_user_ + Space(255)
		size + 255
	Wend
	
	ProcedureReturn Left(_user_, size)
EndProcedure

Procedure.s GetWindowsDirectory()
	_dir_.s = Space(255)
	size = 255
	
	While GetWindowsDirectory_(@_dir_, @size) = #False
		_dir_ + Space(255)
		size + 255
	Wend
	
	ProcedureReturn Left(_dir_, size)
EndProcedure

Procedure.s GetUserProfileDirectory()
	_dir_.s = Space(255)
	size = 255
	
	If OpenProcessToken_(GetCurrentProcess_(), #TOKEN_QUERY, @usertoken) = #False
		ProcedureReturn ""
	EndIf
	
	If GetUserProfileDirectory_(usertoken, @_dir_, @size) = #False
		_dir_ = Space(size)
		
		If GetUserProfileDirectory_(usertoken, @_dir_, @size) = #False
			ProcedureReturn ""
		EndIf
	EndIf
	
	ProcedureReturn Left(_dir_, size) + "\"
EndProcedure


Procedure DesktopSnapShot(w, h, img = #PB_Any)
	Ecran_Largeur = GetSystemMetrics_(#SM_CXSCREEN)
	Ecran_Hauteur = GetSystemMetrics_(#SM_CYSCREEN)
	
	coef.d = Ecran_Largeur / w
	coef2.d = Ecran_Hauteur / h
	
	If coef < coef2
		Swap coef, coef2
	EndIf
	
	DC = GetDC_(0)
	
	If img = #PB_Any
		img = CreateImage(#PB_Any, Ecran_Largeur, Ecran_Hauteur)
	Else
		If IsImage(img)
			FreeImage(img)
		EndIf
		
		CreateImage(img, Ecran_Largeur, Ecran_Hauteur)
	EndIf
	
	Dessin = StartDrawing(ImageOutput(img))
	
	If Dessin
		BitBlt_(Dessin, 0, 0, Ecran_Largeur, Ecran_Hauteur, DC, 0, 0, #SRCPAINT | $40000000)
		
		StopDrawing()
	EndIf
	
	ReleaseDC_(0, DC)
	
	ResizeImage(img, Ecran_Largeur / coef, Ecran_Hauteur / coef, #PB_Image_Smooth)
	
; 		w.l = Ecran_Largeur / coef
; 		h.l = Ecran_Hauteur / coef
; 		
; 		CreateImage(snap, w, h)
; 		
; 		If StartDrawing(ImageOutput(snap))
; 			DrawImage(ImageID(img), 0, 0, w, h)
; 			
; 			StopDrawing()
; 		EndIf
; 		
; 		FreeImage(img)
	
	ProcedureReturn img
EndProcedure


;--------------------------------------
Procedure.l CreateDesktop(nom.s)
	Define.SECURITY_ATTRIBUTES lpsa
	
	lpsa\nLength = SizeOf(SECURITY_ATTRIBUTES)
	lpsa\lpSecurityDescriptor = 0
	lpsa\bInheritHandle = #True
	
	
	desktop_hd.l = CreateDesktop_(nom, #NULL$, #Null, 0, #GENERIC_ALL, @lpsa)
	
	ProcedureReturn desktop_hd
EndProcedure

Procedure.l OpenDesktop(nom.s, *desktophd.Long) ; ouvre un bureau existant, ou le créé si il n'existait pas
	*desktophd\l = OpenDesktop_(nom, 0, #True, #GENERIC_ALL)
	
	res = 2 ; le bureau spécifié existe déjà
	
	If *desktophd\l = 0
; 		Debug "Le bureau : " + nom + " n'existe pas. On va le recréer."
		
		*desktophd\l = CreateDesktop(nom)
		
		If *desktophd\l = 0
			; Debug "Création du bureau : " + FormatMessage(GetLastError_())
			ProcedureReturn 0 ; on retourne une erreur
		EndIf
		
		res = 1 ; on crée le bureau, car il n'existait pas
	EndIf
	
	ProcedureReturn res
EndProcedure
;--------------------------------------

;--------------------------------------
Procedure CreateProcess(application.s, dossier_courant.s, desktop_name.s, *lpProcessInformation.PROCESS_INFORMATION)
	
	Define.SECURITY_ATTRIBUTES lpProcessAttributes
	
	With lpProcessAttributes
		\nLength = SizeOf(SECURITY_ATTRIBUTES)
		\lpSecurityDescriptor = 0
		\bInheritHandle = #True
	EndWith
	
	
	Define.STARTUPINFO lpStartupInfo
	
	With lpStartupInfo
		\cb = SizeOf(STARTUPINFO)
		\lpDesktop = @desktop_name
	EndWith
	
	res = CreateProcess_(#Null, #DQUOTE$ + application + #DQUOTE$, lpProcessAttributes, #Null, #True, #NORMAL_PRIORITY_CLASS, #Null, dossier_courant, lpStartupInfo, *lpProcessInformation)
	
	If res = 0
		Debug "Failed"
; 		Debug "CreateProcess : " + FormatMessage(GetLastError_())
	Else
; 		Debug "Created"
	EndIf
	
	ProcedureReturn res
EndProcedure
;--------------------------------------



;{ Parametre

Global _desktop_affiche_actuellement.l, _exit_thread_affichage_serie.b

Macro FindSpecificMapElement(_map, _element)
	fin.b = #True
	ForEach _map
		If _map\numero = _element
			fin = #False
			Break
		EndIf
	Next
EndMacro


Procedure Affiche_miniature_deroulante(img.l)
	affiche_x = 1
	
			; 	w = ImageWidth(img) ; pour adaptivité
			; 	h = ImageHeight(img)
	w = 410  ; comme on a fixé la taille de la fenêtre
	h = 140
	
	nb_image_affiche = Round(2 + w / h, #PB_Round_Up) - 2 ; 1ere image partielle + images entre + 2eme image partielle
	
	taille_affichage = 130
	
	Repeat
		Delay(25)
		
		If affiche_x <> h * _desktop_affiche_actuellement ; on arrete de bouger
			
			dif = _desktop_affiche_actuellement * h - affiche_x
			
			adif = Abs(dif)
			
			If adif > 100 : vitesse = 40
			ElseIf adif <= 100 And adif > 50 : vitesse = 20
			ElseIf adif <= 50 And adif > 10 : vitesse = 10
			ElseIf adif <= 10 And adif > 5 : vitesse = 5
			ElseIf adif <= 5 : vitesse = 1
			EndIf
			
			affiche_x = affiche_x + vitesse * Sign(dif)
			
			
			; 	Debug nb_image_affiche
			
			premiere_image_affiche = Round(affiche_x / h - nb_image_affiche / 2, #PB_Round_Down)
			; 	Debug premiere_image_affiche
			
			derniere_image_affiche = premiere_image_affiche + nb_image_affiche
			; 	Debug derniere_image_affiche
			
			If premiere_image_affiche < 0 : premiere_image_affiche = 0 : EndIf
			If derniere_image_affiche > MapSize(Desktop()) - 1 : derniere_image_affiche = MapSize(Desktop()) - 1 : EndIf
			
			; 			SelectElement(Serie_Choix(), premiere_image_affiche)
			
			If StartDrawing(ImageOutput(img))
				Box(0, 0, w, h, 0)
				
				For a = premiere_image_affiche To derniere_image_affiche
; 					FindMapElement(mini_vignette(), Serie_Choix())
					FindSpecificMapElement(Desktop(), a)
					
					If fin = #True
						Break
					EndIf
					
					If a = _desktop_affiche_actuellement
						Box(- affiche_x + a * h + (w - taille_affichage) / 2, 0, h, h, #Red)
					EndIf
					
					ratio.d = ImageWidth(Desktop()\hd_miniature) / ImageHeight(Desktop()\hd_miniature)
					
					h1 = taille_affichage / ratio
					w1 = taille_affichage * ratio
					
					If h1 <= taille_affichage
						DrawImage(ImageID(Desktop()\hd_miniature), - affiche_x + a * h + (w + h) / 2 - taille_affichage, (h - h1) / 2, taille_affichage, h1)
						
						; 				If x >= a * wr And x <= a * wr + wr And y >= b * hr + hr / 2 - h1 / 2 And y <= b * hr + hr / 2 + h1 / 2
						; 					index_sous_la_sourie = MapKey(mini_vignette())
						; 				EndIf
						
					Else
; 						DrawImage(ImageID(Desktop()\hd_miniature), - affiche_x + ((a + nb_image_affiche / 2) * 80) + (h - w1) / 2, (h - taille_affichage) / 2, w1, taille_affichage)
						DrawImage(ImageID(Desktop()\hd_miniature), - affiche_x + a * h + (w - taille_affichage + h - w1) / 2, (h - taille_affichage) / 2, w1, taille_affichage)
						
						; 				If x >= a * wr + wr / 2 - w1 / 2 And x <= a * wr + wr / 2 + w1 / 2 And y >= b * hr And y <= b * hr + hr
						; 					index_sous_la_sourie = MapKey(mini_vignette())
						; 				EndIf
						
					EndIf
				Next
				
				StopDrawing()
			EndIf
			
			SetGadgetState(7, ImageID(img))
		EndIf
		
	Until _exit_thread_affichage_serie = #True
EndProcedure

Procedure.i WindowCallBack_molette_souris(hWnd,uMsg,wParam,lParam)
	Define.i ValeurRetour
; 	Static compteur.l = 0
	
	
	ValeurRetour = #PB_ProcessPureBasicEvents
	
	If uMsg = #WM_MOUSEWHEEL
		
; 		If compteur < 2
; 			compteur = compteur + 1
; 			ProcedureReturn ValeurRetour
; 		EndIf
; 		
; 		compteur = 0
		
		Molette.l= -(wParam >> 16) / #WHEEL_DELTA
		
		tmp = _desktop_affiche_actuellement + Molette
		
		If tmp < 0 : tmp = 0 : EndIf
		If tmp > MapSize(Desktop()) - 1 : tmp = MapSize(Desktop()) - 1 : EndIf
		
		_desktop_affiche_actuellement = tmp
		
	EndIf
	
	ProcedureReturn ValeurRetour
EndProcedure



Procedure Fenetre_Parametre(bla.l)
	
	;{ on associe le thread au bureau actuel
	
	If SetThreadDesktop_(Desktop(Bureau_ACTUEL)\hd_bureau) = #False
		ProcedureReturn 0
	EndIf
	
	_desktop_affiche_actuellement = Desktop(Bureau_ACTUEL)\numero
	
	;}
	
	;{ ouverture de la fenetre
	
	If OpenWindow(0, 0, 0, 430, 300, "MultiBureau - Paramètres", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
		ButtonGadget(0, 10, 10, 100, 20, "Ajouter un Bureau")
		ButtonGadget(8, 120, 10, 150, 20, "Créer le nouveau Bureau")
		DisableGadget(8, #True)
		
		TextGadget(1, 10, 40, 100, 20, "Nom du bureau")
		StringGadget(2, 120, 40, 100, 20, Desktop()\nom_utilisateur)
		
		TextGadget(3, 10, 70, 100, 20, "Shell :")
		StringGadget(4, 120, 70, 300, 20, Desktop()\programme)
		
		TextGadget(5, 10, 100, 100, 20, "Wallpaper :")
		StringGadget(6, 120, 100, 300, 20, Desktop()\wallpaper)
		
		ImageGadget(7, 10, 150, 410, 140, 0)
		
		image_defilante = CreateImage(#PB_Any, 410, 140)
		
	Else
		ProcedureReturn 0
	EndIf
	
	SetWindowCallback(@WindowCallBack_molette_souris(), 0)
	
	
	;}
	
	;{ lancement du dessin des miniatures
	
	_exit_thread_affichage_serie = #False
	thread_dessin_miniature = CreateThread(@Affiche_miniature_deroulante(), image_defilante)
	
	;}
	
	StickyWindow(0, #True)
	SetForegroundWindow_(WindowID(0))
	
	;{ boucle principale des evenements
	
	Repeat
		event = WaitWindowEvent(100)
		
		If event = #PB_Event_Gadget
			Select EventGadget()
					
				;{ nouvelle page de bureau
				Case 0
					SetGadgetText(2, "")
					SetGadgetText(4, GetWindowsDirectory() + "\explorer.exe")
					SetGadgetText(6, Desktop(Bureau_ACTUEL)\wallpaper)
					
					DisableGadget(8, #False)
					
					;}
					
				;{ création effective d'un nouveau bureau
				Case 8
					nom$ = GetGadgetText(2)
					
					If nom$ = ""
						MessageRequester("Erreur", "Spécifiez un nom de bureau")
					Else
						
						ok_1.b = #True
						ForEach Desktop()
							If Desktop()\nom_utilisateur = nom$
								ok_1 = #False
								Break
							EndIf
						Next
						
						If ok_1 = #False
							MessageRequester("Erreur", "Spécifiez un nom de bureau différent, celui-ci existe déjà")
						Else
							
							
							If FileSize(GetGadgetText(4)) <= 0
								MessageRequester("Erreur", "Le Shell n'existe pas")
							Else
								
								nombredesktopmax.l = 0
								For a = 1 To MapSize(Desktop())
									ok.b = #True
									
									ForEach Desktop()
										If Desktop()\numero = a
											ok = #False
											Break
										EndIf
									Next
									
									If ok = #True
										nombredesktopmax = a
										Break
									EndIf
								Next
								
								nom_bureau$ = "bureau_" + Str(nombredesktopmax)
								
								;{ on arrete de mettre à jour la defilante pour eviter les bug
								
								; 							_exit_thread_affichage_serie = #True
								; 							WaitThread(thread_dessin_miniature)
								PauseThread(thread_dessin_miniature)
								
								;}
								
								AddMapElement(Desktop(), nom_bureau$)
								
								Debug "---"
								Debug nom_bureau$
								Debug "AddMapElement(Desktop(), nom_bureau$)"
								
								With Desktop(nom_bureau$)
									\nom = nom_bureau$
									\nom_utilisateur = nom$
									\numero = nombredesktopmax
									
									\programme = GetGadgetText(4)
									\dossier_bureau = GetUserProfileDirectory() + nom_bureau$ + "\" ; pour le moment
									
									\wallpaper = GetGadgetText(6)
									
									
									Debug "\wallpaper = GetGadgetText(6)"
									
									\hd_miniature = DesktopSnapShot(taille_max_snapshot, taille_max_snapshot, 100 + \numero)
									If StartDrawing(ImageOutput(\hd_miniature))
										Box(0, 0, ImageWidth(\hd_miniature), ImageHeight(\hd_miniature), #White)
										StopDrawing()
									EndIf
									
									Debug "StopDrawing()"
									
									handle.Long\l = 0
									OpenDesktop(\nom, @handle)
									
									Debug "OpenDesktop(\nom, @handle)"
									
									\hd_bureau = handle\l
									
									If \hd_bureau = 0
										MessageRequester("Erreur Fatale", "Impossible de créer le Bureau " + nom$ + "." + "Essayez de changer les permissions du programme.")
										
										FreeImage(\hd_miniature)
										DeleteMapElement(Desktop())
									EndIf
									
									CreateDirectory(GetUserProfileDirectory() + nom_bureau$)
									Debug "CreateDirectory(GetUserProfileDirectory() + nom_bureau$) : " + GetUserProfileDirectory() + nom_bureau$
									
									res = CreateProcess(\programme, GetUserProfileDirectory() + nom_bureau$, nom_bureau$, @information_process.PROCESS_INFORMATION)
									
									Debug "CreateProcess " + Str(res)
									
									Delay(1000)
									
									
									Debug "fin delay"
									\thread = CreateThread(@ThreadRaccourcisClavier(), @nom_bureau$)
									
									Debug "Thread créer : " + Str(\thread)
									
								EndWith
								
								;{ on reprend l'affichage des miniatures
								
								; 							_exit_thread_affichage_serie = #False
								; 							thread_dessin_miniature = CreateThread(@Affiche_miniature_deroulante(), image_defilante)
								ResumeThread(thread_dessin_miniature)
								
								_desktop_affiche_actuellement = nombredesktopmax
								
								;}
								
							EndIf
						EndIf
						
					EndIf
					
					;}
					
			EndSelect
		EndIf
		
	Until event = #PB_Event_CloseWindow
	
	Debug "on sort de la fenetre de parametre"
	
	;}
	
	;{ clean up
	
	_exit_thread_affichage_serie = #True
	If IsThread(thread_dessin_miniature)
		WaitThread(thread_dessin_miniature)
	EndIf
	
	FreeImage(image_defilante)
	
	CloseWindow(0)
	
	;}
	
	IS_PARAMETRE_BEING_SET = #False
	
	ProcedureReturn 1
EndProcedure

Macro Parametre()
	If IS_PARAMETRE_BEING_SET = #False
		IS_PARAMETRE_BEING_SET = #True
		
		thread_parametre = CreateThread(@Fenetre_Parametre(), 0)
	EndIf
EndMacro

;}


Procedure SwitchDesktop(num.l)
	If IS_PARAMETRE_BEING_SET = #False
		DesktopSnapShot(taille_max_snapshot, taille_max_snapshot, Desktop(Bureau_ACTUEL)\hd_miniature)
		
		ok.b = #False
		ForEach Desktop()
			If Desktop()\numero = num
				ok = #True
				Break
			EndIf
		Next
		
		If ok = #False : ProcedureReturn 0 : EndIf
		
		Bureau_ACTUEL = Desktop()\nom
		
		SwitchDesktop_(Desktop(Bureau_ACTUEL)\hd_bureau)
	EndIf
EndProcedure

Procedure ThreadRaccourcisClavier(*adresse)
	SetThreadDesktop_(Desktop(PeekS(*adresse))\hd_bureau)
	
	Debug PeekS(*adresse)
	
	Define desktop_in_thread.Bureau
	
	CopyStructure(@Desktop(PeekS(*adresse)), @desktop_in_thread, Bureau)
	
; 	key = #VK_1
; 	Select desktop_in_thread\numero
; 		Case 1 : key = #VK_2
; 		Case 2 : key = #VK_3
; 		Case 3 : key = #VK_4
; 		Case 4 : key = #VK_5
; 		Case 5 : key = #VK_6
; 		Case 6 : key = #VK_7
; 		Case 7 : key = #VK_8
; 		Case 8 : key = #VK_9
; 		Case 9 : key = #VK_0
; 	EndSelect
	
	Repeat
		Delay(25)
		
		If Bureau_ACTUEL = desktop_in_thread\nom
			num = -1
			If GetAsyncKeyState_(#VK_1) <> 0 : num = 0
			ElseIf GetAsyncKeyState_(#VK_2) <> 0 : num = 1
			ElseIf GetAsyncKeyState_(#VK_3) <> 0 : num = 2
			ElseIf GetAsyncKeyState_(#VK_4) <> 0 : num = 3
			ElseIf GetAsyncKeyState_(#VK_5) <> 0 : num = 4
			ElseIf GetAsyncKeyState_(#VK_6) <> 0 : num = 5
			ElseIf GetAsyncKeyState_(#VK_7) <> 0 : num = 6
			ElseIf GetAsyncKeyState_(#VK_8) <> 0 : num = 7
			ElseIf GetAsyncKeyState_(#VK_9) <> 0 : num = 8
			ElseIf GetAsyncKeyState_(#VK_0) <> 0 : num = 9
			EndIf
			
			If GetAsyncKeyState_(#VK_CONTROL) <> 0
				
				If num <> -1
					SwitchDesktop(num)
					
					Debug desktop_in_thread\nom + "  switch to : " + Str(num)
				Else
					If GetAsyncKeyState_(#VK_F3) <> 0
						Parametre()
						
						Debug desktop_in_thread\nom + "  Show parameter"
					EndIf
					
					
					If GetAsyncKeyState_(#VK_F12) <> 0 : EXIT_PROGRAM = #True : EndIf ; à virer ensuite
					
				EndIf
				
			EndIf
		EndIf
	Until EXIT_PROGRAM = #True
	
EndProcedure


;}



;{ on récupère le nom de l'utilisateur qui a lancé le programme

USER = GetUserName()

; à chaque changement de bureau, on va tester l'utilisateur.
; Si l'utilisateur courant n'est pas celui qui a lancé l'application,
; alors on ne fait rien.

; il faut fonctionner comme cela, pour éviter que les différentes sessions
; ne crée de problème avec tout les desktops. (hypothèque)

; c'est peut-être inutile, cependant, tant que je n'ai pas fait de test,
; c'est l'inconnu.

;}


;{ initialisation de la liste

thread_parametre.l = 0

If ReadFile(0, currentdirectory$ + InitFile$)
	
	
Else ; le fichier d'init n'existe pas, il faut montrer la fenêtre des paramètres à l'utilisateur
	; on initialise le bureau par defaut
	
	AddMapElement(Desktop(), Bureau_ACTUEL)
	
	With Desktop()
		\nom = Bureau_ACTUEL
		\nom_utilisateur = "Bureau par Défaut"
		\numero = 0
		
		\programme = GetWindowsDirectory() + "\explorer.exe"
		\dossier_bureau = GetUserProfileDirectory() + "Bureau\"
		
		\wallpaper = ""
		
		\hd_miniature = DesktopSnapShot(taille_max_snapshot, taille_max_snapshot, 100 + \numero)
		
		\hd_bureau = OpenDesktop_(\nom, 0, #True, #GENERIC_ALL)
		
		If \hd_bureau = 0
			MessageRequester("Erreur Fatale", "Impossible d'accéder au Bureau par Défaut." + "Essayez de changer les permissions du programme.")
			End
		EndIf
		
		\thread = CreateThread(@ThreadRaccourcisClavier(), @Bureau_ACTUEL)
		
	EndWith
	
	Parametre()
	
EndIf


;}


;{ boucle principale d'attente

is_one_thread_active.b = #True
EXIT.b = #False

Repeat
	
	If is_one_thread_active = #False ; on tourne 2 fois pour être sur que les threads sont tous finis
		EXIT = #True
	Else
		EXIT = #False
	EndIf
	
	is_one_thread_active.b = #False
	
	If IsThread(thread_parametre)
		WaitThread(thread_parametre)
		
		is_one_thread_active = #True
	EndIf
	
	ForEach Desktop()
		If IsThread(Desktop()\thread)
			WaitThread(Desktop()\thread)
			
			is_one_thread_active = #True
		EndIf
	Next
	
Until EXIT = #True And is_one_thread_active = #False


;}

End
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Application MultiBureaux

Message par nico »

ça marche chez moi, mais n'oublie pas de mettre des interger dans tes procedures de thread sinon on ne peut pas compiler en 64 bits

Remarque:je perd aéro dans la création des nouveaux bureaux
Répondre