Tutoriel: comment créer un bureau virtuel
:: Boîte à outils :: Tutoriels
Page 1 sur 1 • Partager •
Tutoriel: comment créer un bureau virtuel
TUTORIEL : COMMENT CRÉER UN BUREAU VIRTUEL
Tutoriel réalisé par Faiseur
Niveau: [ Intermédiaire ]
SUJETS TRAITÉS DANS CE TUTORIEL
- Il introduit au concept de procédures "callback"
- il introduit au concept de handle des fenêtres Windows
- Introduction à quatre APIs: ShowWindow, GetClassName, EnumWindows, lstrcmp
NOTES CONCERNANT CE TUTORIEL
La première fois qu’une API est décrite dans ce tutoriel celle-ci pointe sur son lien direct MSDN Microsoft. N'hésitez pas à vous documenter sur la MSDN pour mieux comprendre le fonctionnement des API utilisées.
Définition de certains termes employés:
Handle : une valeur permettant à Windows d’identifier, dans notre cas, une fenêtre.
Callback : Il s'agit d'une fonction - ou procédure - qui sera automatiquement appelée quand un événement particulier se produit.
DESCRIPTION DU PROGRAMME
Les applications permettant de créer des bureaux virtuels ont eu un certain succès il y a quelques années. D'un premier abord il peut sembler compliqué de mettre en place un tel système mais la création de deux bureaux virtuels uniquement, par exemple, est plutôt simple en se servant de quelques API. De plus ce type de tutoriel est à ma connaissance inconnu en assembleur, ce qui m'a motivé à en proposer un.
Notre démo, dont le code source est fournit en fichier joint plus bas, va permettre à l’utilisateur de changer virtuellement de bureau. Chaque bureau virtuel disposera de ses propres paramètres ; c’est-à-dire qu’il intégrera des fenêtres de navigateurs que l’autre bureau n’affichera pas. Il en sera de même pour les dossiers ouverts par l’utilisateur, qui seront propres à chaque bureau.
Code:
SqueletteGUI.asm
- Code:
comment *
Exemple de bureau virtuel (implémenté dans Horizon Toolbar) par Faiseur
*
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\macros\macros.asm
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\masm32.inc
include \masm32\include\comctl32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\comctl32.lib
include Proc/Bureauvirtuel.asm
.const
IDD_DIALOG1 equ 1000
IDC_BTN1 equ 1001
IDC_BUREAU1 equ 1002
IDC_BUREAU2 equ 1003
.data?
hInstance dd ?
.code
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
Switch uMsg
Case WM_COMMAND
mov edx,wParam
movzx eax,dx
shr edx,16
.if eax==IDC_BTN1
invoke SendMessage,hWin,WM_CLOSE,NULL,NULL
.elseif eax==IDC_BUREAU1
.if virtualdesktop == 2
mov countf,1
invoke EnumWindows,addr EnumExplorerProc2,0
fn SetDlgItemText,hWin,1002,"Bureau virtuel 1 actif"
fn SetDlgItemText,hWin,1003,"Bureau virtuel 2"
mov virtualdesktop,1
.endif
.elseif eax==IDC_BUREAU2
.if virtualdesktop == 1
mov countf,1
invoke EnumWindows,addr EnumExplorerProc,0
fn SetDlgItemText,hWin,1003,"Bureau virtuel 2 actif"
fn SetDlgItemText,hWin,1002,"Bureau virtuel 1"
mov virtualdesktop,2
.endif
.endif
Case WM_CLOSE
invoke EndDialog,hWin,0
default
return FALSE
Endsw
return TRUE
DlgProc endp
start:
mov hInstance,FUNC(GetModuleHandle,0)
invoke InitCommonControls
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
exit
end start
Bureauvirtuel.asm
- Code:
.data
hfolder dd 20 dup(0) ; fenêtres du bureau virtuel 2
gfolder dd 20 dup(0) ; fenêtres du bureau virtuel 1
countf dd 1
virtualdesktop dd 1
.code
EnumExplorerProc proc hwnd:DWORD,lParam:DWORD
LOCAL szWinBuf[261]:BYTE
invoke GetClassName,hwnd,addr szWinBuf,sizeof szWinBuf
fn lstrcmp,addr szWinBuf,"CabinetWClass"
test eax,eax
je @F
fn lstrcmp,addr szWinBuf,"MozillaUIWindowClass"
test eax,eax
je @F
fn lstrcmp,addr szWinBuf,"IEFrame"
test eax,eax
je @F
return TRUE
@@:
mov eax,hwnd
.if eax != gfolder[0] && eax != gfolder[4] && eax != gfolder[8] && eax != gfolder[12] && eax != gfolder[16] && eax != gfolder[20] && eax != gfolder[24] && eax != gfolder[28] && eax != gfolder[32] \
&& eax != gfolder[36] && eax != gfolder[40] && eax != gfolder[44] && eax != gfolder[48] && eax != gfolder[52] && eax != gfolder[56] && eax != gfolder[60] && eax != gfolder[64] && eax != gfolder[68]
.if countf < 19
.if countf ==1
m2m hfolder[0],hwnd
.elseif countf ==2
m2m hfolder[4],hwnd
.elseif countf ==3
m2m hfolder[8],hwnd
.elseif countf ==4
m2m hfolder[12],hwnd
.elseif countf ==5
m2m hfolder[16],hwnd
.elseif countf ==6
m2m hfolder[20],hwnd
.elseif countf ==7
m2m hfolder[24],hwnd
.elseif countf ==8
m2m hfolder[28],hwnd
.elseif countf ==9
m2m hfolder[32],hwnd
.elseif countf ==10
m2m hfolder[36],hwnd
.elseif countf ==11
m2m hfolder[40],hwnd
.elseif countf ==12
m2m hfolder[44],hwnd
.elseif countf ==13
m2m hfolder[48],hwnd
.elseif countf ==14
m2m hfolder[52],hwnd
.elseif countf ==15
m2m hfolder[56],hwnd
.elseif countf ==16
m2m hfolder[60],hwnd
.elseif countf ==17
m2m hfolder[64],hwnd
.elseif countf ==18
m2m hfolder[68],hwnd
.endif
inc countf
invoke ShowWindow,hwnd,SW_HIDE
return TRUE
.endif
.endif
invoke ShowWindow,hwnd,SW_SHOW
return TRUE
EnumExplorerProc endp
EnumExplorerProc2 proc hwnd:DWORD,lParam:DWORD
LOCAL szWinBuf[261]:BYTE
invoke GetClassName,hwnd,addr szWinBuf,sizeof szWinBuf
fn lstrcmp,addr szWinBuf,"CabinetWClass"
test eax,eax
je @F
fn lstrcmp,addr szWinBuf,"MozillaUIWindowClass"
test eax,eax
je @F
fn lstrcmp,addr szWinBuf,"IEFrame"
test eax,eax
je @F
return TRUE
@@:
mov eax,hwnd
.if eax != hfolder[0] && eax != hfolder[4] && eax != hfolder[8] && eax != hfolder[12] && eax != hfolder[16] && eax != hfolder[20] && eax != hfolder[24] && eax != hfolder[28] && eax != hfolder[32] \
&& eax != hfolder[36] && eax != hfolder[40] && eax != hfolder[44] && eax != hfolder[48] && eax != hfolder[52] && eax != hfolder[56] && eax != hfolder[60] && eax != hfolder[64] && eax != hfolder[68]
.if countf < 19
.if countf ==1
m2m gfolder[0],hwnd
.elseif countf ==2
m2m gfolder[4],hwnd
.elseif countf ==3
m2m gfolder[8],hwnd
.elseif countf ==4
m2m gfolder[12],hwnd
.elseif countf ==5
m2m gfolder[16],hwnd
.elseif countf ==6
m2m gfolder[20],hwnd
.elseif countf ==7
m2m gfolder[24],hwnd
.elseif countf ==8
m2m gfolder[28],hwnd
.elseif countf ==9
m2m gfolder[32],hwnd
.elseif countf ==10
m2m gfolder[36],hwnd
.elseif countf ==11
m2m gfolder[40],hwnd
.elseif countf ==12
m2m gfolder[44],hwnd
.elseif countf ==13
m2m gfolder[48],hwnd
.elseif countf ==14
m2m gfolder[52],hwnd
.elseif countf ==15
m2m gfolder[56],hwnd
.elseif countf ==16
m2m gfolder[60],hwnd
.elseif countf ==17
m2m gfolder[64],hwnd
.elseif countf ==18
m2m gfolder[68],hwnd
.endif
inc countf
invoke ShowWindow,hwnd,SW_HIDE
return TRUE
.endif
.endif
invoke ShowWindow,hwnd,SW_SHOW
return TRUE
EnumExplorerProc2 endp
Voici l'intelligence du programme:
1. Lorsque l'utilisateur veut passer au bureau virtuel 2:
- Réinitialiser puis mémoriser les identifiants des fenêtres ouvertes par le bureau virtuel 1 (il s'agit du bureau ouvert par défaut par l'utilisateur)
- Cacher toutes les fenêtres des navigateurs et de l'explorer du bureau 1
- Afficher les fenêtres (les handle) appartenant au bureau 2
2. Lorsque l'utilisateur veut passer au bureau virtuel 1:
- Réinitialiser puis mémoriser les identifiants (handle) des fenêtres ouvertes par le bureau virtuel 2
- Cacher toutes les fenêtres des navigateurs et de l'explorer du bureau 2
- Afficher les fenêtres (les handle) appartenant au bureau 1
ANALYSE DU CODE
Passage du bureau 1 au bureau 2:
Lorsque l’utilisateur veut afficher le bureau virtuel 2 il commence par appuyer sur le bouton correspondant IDC_BUREAU2
- Code:
elseif eax==IDC_BUREAU2
On vérifie si nous sommes bien sur le bureau virtuel 1. Si c'est le cas nous passons à la suite…
- Code:
.if virtualdesktop == 1
Initialisation du compteur des handle.Ce compteur sera utilisé dans les procédures callback EnumExplorerProc et EnumExplorerProc2.
- Code:
mov countf,1
Ceci le cœur de tout le programme. Le passage d’un bureau virtuel à l’autre se fait avec cette fonction Api que nous allons détailler plus bas.
- Code:
invoke EnumWindows,addr EnumExplorerProc,0
On termine en modifiant le texte des deux boutons et en signifiant à l'application que nous sommes passés au bureau virtuel 2
- Code:
invoke SetDlgItemText,hWin,1003,"Bureau virtuel 2 actif"
invoke SetDlgItemText,hWin,1002,"Bureau virtuel 1"
mov virtualdesktop,2
.endif
INTRODUCTION AUX PROCEDURES CALLBACK
On utilise l'API EnumWindows pour récupérer l'handle (identifiant unique) de toutes les fenêtres ouvertes sur le bureau de l'utilisateur.
Cette API nous envoie à une procédure callback qui correspond, dans le programme, à "EnumExplorerProc" "ou EnumExplorerProc2".
"EnumExplorerProc" "ou EnumExplorerProc2" sont appelées chaque fois qu'un événement est trouvé par l'API. "EnumExplorerProc" "et EnumExplorerProc2" vont alors traiter cet événement puis rendre la main à l’API jusqu’au prochain événement.
"EnumExplorerProc" s'occupe de la procédure nécessaire pour afficher le bureau virtuel 2.
"EnumExplorerProc2" s'occupe de la procédure nécessaire pour afficher le bureau virtuel 1.
Dans notre cas l'API EnumWindows appellera nos procédures à chaque fois qu'une fenêtre sera trouvée. Lorsque cette API donne la main à "EnumExplorerProc" "ou EnumExplorerProc2" elle leur envoie, en paramètre, une précieuse information: l'identifiant unique de la fenêtre (handle). C'est avec cette information que nous pourrons tout faire: cacher les fenêtres ou les faire réapparaître.
Voici l'appel de cette fonction dans notre programme:
Pour passer du bureau virtuel 1 au bureau virtuel 2…
- Code:
invoke EnumWindows,addr EnumExplorerProc2,0
Pour passer du bureau virtuel 2 au bureau virtuel 1…
- Code:
invoke EnumWindows,addr EnumExplorerProc,0
ANANYLSE DE LA PROCEDURE CALLBACK « EnumExplorerProc »
Au début de nos procédures callback nous trouvons :
- Code:
invoke GetClassName,hwnd,addr szWinBuf,sizeof szWinBuf
GetClassName permet de retrouver le nom de la classe d'une fenêtre trouvée par l'API EnumWindows. Dans notre cas on vérifie par comparaison de nom (l'API lstrcmp permet de comparer deux chaînes de caractères afin de vérifier si elles sont équivalentes) qu'il s'agit soit:
d'une fenêtre de l'explorer (elles ont pour nom "CabinetWClass")...
- Code:
invoke lstrcmp,addr szWinBuf,"CabinetWClass"
d'une fenêtre de Firefox (elles ont pour nom "MozillaUIWindowClass")...
- Code:
invoke lstrcmp,addr szWinBuf,"MozillaUIWindowClass"
d'une fenêtre d'Internet Explorer (elles ont pour nom "IEFrame")...
- Code:
invoke lstrcmp,addr szWinBuf,"IEFrame"
Si une de ces fenêtres sont trouvées on passe à la suite de la procédure callback, sinon on rend la main à EnumWindows.
On vérifie ici si le handle de la fenêtre trouvée est déjà utilisé dans le bureau 2
- Code:
.if eax != hfolder[0] && eax != hfolder[4] etc
Complément: "&&" est une manière d'écrire la condition "ET" logique
Si c’est le cas on affiche la fenêtre trouvée du bureau 2 avec l’API ShowWindow :
- Code:
invoke ShowWindow,hwnd,SW_SHOW
Si ce n’est pas le cas on mémorise la fenêtre comme appartenant au bureau virtuel 1
- Code:
m2m gfolder[xx],hwnd
Puis on la rend invisible pour l’utilisateur
- Code:
invoke ShowWindow,hwnd,SW_HIDE
Au final on rend la main à l’API EnumWindows
- Code:
return TRUE
EN RÉSUMÉ
- Cette procédure callback aura donc été appelée le nombre de fois correspondant au nombre de fenêtres trouvées par l'API EnumWindows.
- Nous aurons caché les fenêtres de l'explorer et des navigateurs du bureau 1
- Nous aurons mémorisé l'identifiant (handle) des fenêtres de l'explorer et des navigateurs du bureau 1
- Nous aurons ouvert, à partir de leurs identifiants, les fenêtres de l'explorer et des navigateurs du bureau 2
POUR REVENIR AU BUREAU VIRTUEL 1 ?
Il sera nécessaire d’inverser le sens du test des handles lorsque nous voulons retrouver le bureau virtuel 1. C’est pourquoi une deuxième procédure callback est utilisée, « EnumExplorerProc2 », pour revenir à l’état initial. La différence se fait à cet endroit :
- Code:
.if eax != gfolder[0] && eax != gfolder[4] etc
Au lieu de vérifier si une fenêtre trouvée correspond à une fenêtre du bureau virtuel 2, nous vérifions si la fenêtre trouvée correspond à une fenêtre du bureau virtuel 1. Si ce n’est pas le cas nous la mémorisons en tant que fenêtre du bureau virtuel 2 :
- Code:
m2m hfolder[xx],hwnd
Ainsi, gfolder récupère les identifiants (handle) des fenêtres du bureau virtuel 1, hfolder les identifiants (handle) des fenêtres du bureau virtuel 2.
AMELIORATIONS POSSIBLES
On peut évidemment inclure une compatibilité avec les fenêtres d'autres navigateurs bien que les deux cités plus haut sont utilisés dans la grande majorité des cas. Inclure la fermeture des fenêtres d'autres programmes en cours, dont nous ne connaissons pas forcément l'utilisation, n'est évidemment pas conseillé pour diverses raisons. C'est pour cela que le bureau virtuel a ses limites mais offre une bonne versatilité en usage courant. Proposer d'autres bureaux virtuels serait également un plus.
CONCERNANT LA COMPATIBILITE DU CODE SOURCE
Les sources sont en syntaxe Masm/JWasm. Mais si vous utilisez Masm (ml.exe) une erreur va apparaître lors de la compilation du code source.
La ligne ".if eax != gfolder[0] && eax != gfolder[4] ..." est trop longue. Deux possilibités:
1. Utilisez comme moi JWasm, qui n'est pas aussi limité par la longueur du code sur une ligne
2. Séparer cette ligne en plusieurs parties avec la commande ""
Télécharger le code source et l'exécutable de ce tutoriel:
- Fichiers joints
Dernière édition par faiseur le Dim 11 Juil - 15:04, édité 5 fois

faiseur- Admin
- Messages: 371
Date d'inscription: 02/05/2010

Re: Tutoriel: comment créer un bureau virtuel
Tes tutos sont super intéressants et mériteraient qu'on aille jusqu'au bout. Tu devrais les mettre en tant que projets et proposer de monter une équipe pour les développer.

Grincheux- Messages: 247
Date d'inscription: 17/05/2010
Age: 52
Localisation: Mathenay (39), France

Re: Tutoriel: comment créer un bureau virtuel
J'ai revu le tutoriel en le simplifiant un peu. Retrait des macros personnelles et du raccourci pour invoke. L'archive a été modifiée de la même manière, la nouvelle version remplace la précédente dans le tutoriel.

faiseur- Admin
- Messages: 371
Date d'inscription: 02/05/2010

Sujets similaires» Comment créer une frame ?
» tutoriel Joyeux Noël
» Proposer un Tutoriel ou une astuce
» Créér un jeu de domino
» Créer une chronomètre en A.S
» tutoriel Joyeux Noël
» Proposer un Tutoriel ou une astuce
» Créér un jeu de domino
» Créer une chronomètre en A.S
:: Boîte à outils :: Tutoriels
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum





