Liste tous les fichiers présents sur la partition sélectionnée, avant et après une installation (ou désinstallation)
Compare le contenu des 2 fichiers et établi la liste exacte des fichiers ajoutés ou supprimés.
Source / Exemple :
; ListeFichiers.asm réalisé avec MASM32
;*******************************************************************************
; Modifié le 22 Juillet 2009 par suppression du quota de 200 lignes à contrôler
; avant de changer de sens. Un programme qui avait ajouté 1800 fichiers lors de
; son installation faisait tout foirer.
;*******************************************************************************
.586
.model flat,stdcall
option casemap:none
include ListeFichiers.inc
.code
start:
invoke DialogBoxParam,0,101,NULL,addr DlgProc1,NULL
LaSuite:
;*********************************************************************************
; Allouer la mémoire nécéssaire pour les 2 tampons : pMem2 = Répertoires
; pMem1 = Fichiers.Adresses et tampon1 sont des ptr mobiles dans ces espaces.
;*********************************************************************************
invoke GlobalAlloc,GHND,19000000
mov hMem2,eax
invoke GlobalLock,eax
mov pMem2,eax
mov Tampon,eax
invoke GlobalAlloc,GHND,90000000
mov hMem1,eax
invoke GlobalLock,eax
mov pMem1,eax
mov Tampon1,eax
;****************************************************************************
; Commencer la recherche
;****************************************************************************
invoke Cherche,addr Buffer
;****************************************************************************
; récuperer le chemin complet du dernier répertoire, ou s/rep trouvé dans le
; buffer des répertoires, le supprimer de ce buffer et commencer une nouvelle
; recherche. Cette boucle cessera lorsque Tampon sera vide.
;****************************************************************************
encore:
invoke TourSuivant
;*****************************************************************************
; Créer le fichier qui recevra le contenu de pMem1, le nom diffère suivant
; que l'on a actionné Avant ou Après.
;*****************************************************************************
Final:
.if Passage == 0
invoke CreateFile,addr NomFic1,GENERIC_WRITE,FILE_SHARE_WRITE,
NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,NULL
.elseif Passage == 1
invoke CreateFile,addr NomFic2,GENERIC_WRITE,FILE_SHARE_WRITE,
NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,NULL
.endif
mov hFile1,eax
;****************************************************************************
; recherche de la longueur exacte à écrire
;****************************************************************************
mov eax,Tampon1
sub eax,pMem1
;****************************************************************************
; Ecrire le fichier et libérer la mémoire utilisée
;****************************************************************************
invoke WriteFile,hFile1,pMem1,eax,Addr NbEcrits,NULL
invoke CloseHandle,hFile1
invoke GlobalUnlock,addr pMem1
invoke GlobalFree,addr hMem1
invoke GlobalUnlock,addr pMem2
invoke GlobalFree,addr hMem2
stop:
invoke ExitProcess,NULL
;**********************************************************
DlgProc1 proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
.IF uMsg == WM_INITDIALOG
;***************************************************************************
; Créer la ComboBox et y placer les lecteurs disponibles.
;***************************************************************************
invoke CreateWindowEx,WS_EX_CLIENTEDGE,addr CbBox,0,WS_VSCROLL or\
WS_VISIBLE or WS_BORDER or WS_CHILD,310,14,50,45,hWnd,100,0,0
mov hCbBox,eax
invoke SendMessage,hCbBox,CB_DIR,DDL_DRIVES,addr Lecteur
;******************************************************************************
; Recherche des handles des boutons pour les cacher par ShowWindow
;******************************************************************************
invoke GetDlgItem,hWnd,1001
mov hBtn2,eax
invoke GetDlgItem,hWnd,1002
mov hBtn3,eax
invoke GetDlgItem,hWnd,1000
mov hBtn1,eax
invoke ShowWindow,hBtn1,SW_HIDE
invoke ShowWindow,hBtn2,SW_HIDE
invoke ShowWindow,hBtn3,SW_HIDE
.ELSEIF uMsg == WM_COMMAND
mov eax,wParam
shr eax,16
.if eax == CBN_SELCHANGE
;******************************************************************************
; Rechercher l'index du lecteur choisi et son nom
;******************************************************************************
invoke SendMessage,hCbBox,CB_GETCURSEL,0,0
invoke SendMessage,hCbBox,CB_GETLBTEXT,eax,addr Lecteur
;******************************************************************************
; mettre ce nom en majuscule dans la variable Nom et montrer les boutons.
;******************************************************************************
mov esi,offset Lecteur
add esi,2
mov edi,offset Nom
lodsb
sub eax,32
stosb
invoke ShowWindow,hBtn1,SW_SHOW
invoke ShowWindow,hBtn2,SW_SHOW
invoke ShowWindow,hBtn3,SW_SHOW
.elseif wParam == 1001 ; Après
mov Passage,1
jmp @F
.elseif wParam == 1000 ; Avant
;*******************************************************************************
; Copier ce nom dans Buffer et y ajouter " \*.* "
;*******************************************************************************
@@:
invoke MemCopy,addr Nom,addr Buffer,2
invoke lstrcat,addr Buffer,addr szSlashB
mov eax,hWnd
mov hDialog,eax
jmp LaSuite
.elseif wParam == 1002 ; Changements
call Onyva
.elseif wParam == 1003 ; Quitter
invoke EndDialog,hWnd,0
.endif
.ELSEIF uMsg == WM_CLOSE
jmp stop
.ENDIF
xor eax, eax
ret
DlgProc1 endp
;==========================================================
Cherche proc NomFich :DWORD
pushad
invoke FindFirstFile,NomFich,addr wfd
cmp eax,-1
jne @F
jmp encore
@@:
mov hFile1,eax
mov ebx,eax
.if wfd.cFileName == "." ; Sauter
jmp @F
.else
invoke Traite ; Répertoire ou Fichier ?
.endif
@@:
.While ebx > 0
@@:
invoke FindNextFile,hFile1,addr wfd
mov ebx,eax
cmp eax,0
je @F
cmp wfd.cFileName,"."
je @B
invoke Traite
.Endw
@@:
popad
ret
Cherche endp
;**********************************************************
Traite proc
pushad
lea edi,wfd
mov eax,[edi]
cmp eax,16 ; < :Fichier
jb fic
cmp eax,800 ; pas traité
ja sava
cmp eax,23 ; > : Fichier
ja fic
invoke FaitPath,Tampon,addr CptRep
popad
ret
;*********************************************************************************
; Prépare le chemin complet du Rep ou S/rep dans buffer. Ajoute le nom du fichier
; et transfère le tout dans Tampon1 (Buffer des fichiers trouvés).
;**********************************************************************************
fic:
invoke FaitBuff,addr Buffer,0
invoke szCatStr,addr Buffer,addr wfd.cFileName
invoke szCatStr,Tampon1,addr Buffer
;*********************************************************************
; Affichage sur le Static de la boite de dialogue pendant la recherche
;*********************************************************************
invoke SendDlgItemMessage,hDialog,700,WM_SETTEXT,NULL,addr Buffer
invoke FaitBuff,addr Buffer,0
mov edi,Tampon1
@@:
cmp byte ptr[edi],0 ; Cherche la fin du Path/fichier dans
je @F ; Buffer
inc edi ;
jmp @B ;
@@:
mov ax,0A0Dh ; Y ajoute à la ligne
stosw ;
mov Tampon1,edi ; Adresse du prochain nom de fichier
inc CptFic ;
sava:
popad
ret
Traite endp
;**********************************************************
TourSuivant proc uses eax ebx ecx
cmp CptRep,0 ; Si CptRep = 0 tout le le lecteur à
je Final ; été scanné (Rep et S/Rep)
dec CptRep ;
mov ebx,offset Adresses ; calcul de l'emplacement de l'adresse
mov ecx,4 ; du prochain Rep et récuperation de
mov eax,CptRep ; cette adresse pour la placer dans le
mul cl ; pointeur variable Tampon.
add ebx,eax ;
mov eax,dword ptr[ebx] ;
mov Tampon,eax ;
push eax
push edi
mov edi,offset Buffer ; Mise à zéro de Buffer
xor eax,eax ;
mov ecx,64 ;
rep Stosd ;
;******************************************************************
; Placer dans Buffer le chemin du nouveau Rep à scanner
;******************************************************************
invoke szCatStr,addr Buffer,[Tampon]
pop edi
pop eax
mov esi,Tampon
@@:
cmp byte ptr[esi],0 ; esi sur le début du dernier Path dans Tampon
je @F ; Mettre cet emplacement à zéro (effacement du
mov byte ptr[esi],0 ; Chemin complet qui va être recherché)
inc esi ; Puis appeler la recherche de ce répertoire
jmp @B ;
@@:
invoke Cherche,addr Buffer
jmp encore ; retour à la boucle : Cherche,TourSuivant,Cherche etc...
ret
TourSuivant endp
;**********************************************************
FaitPath proc Place :DWORD,compt :DWORD
pushad
invoke szCatStr,[Tampon],addr Buffer
invoke FaitBuff,[Tampon],0
invoke szCatStr,[Tampon],addr wfd.cFileName
mov esi,[Tampon]
mov ebx,offset Adresses
mov eax,[CptRep]
mov ecx,4
mul cl
add ebx,eax
mov [ebx],esi
@@:
lodsb
cmp al,0
jne @B
sub esi,1
mov dword ptr[esi],2A2E2A5Ch
add esi,5
mov Tampon,esi
inc CptRep
inc NbRep
popad
ret
FaitPath endp
;**********************************************************
FaitBuff proc Buff :DWORD,Num :DWORD
pushad
mov edi,Buff
@@:
cmp byte ptr[edi],0 ; Cherche la fin du Buffer
je @F ;
inc edi ;
jmp @B ;
@@:
dec edi ; retour en arriere pour trouver
cmp byte ptr[edi],5Ch ; le dernier "\"
jne @B ;
inc edi ;
.if Num == 1 ;
mov dword ptr[edi],002A2E2Ah ; ajouter "*.*"
.else
mov Byte ptr[edi],0 ; ou zéro
.endif
popad
ret
FaitBuff endp
;**********************************************************
; Procédures de Comparaison
;**********************************************************
final:
call Resultat
invoke ExitProcess,NULL
;**********************************************************
Onyva proc
;******************************************************************************
; Ouvrir les deux fichiers, Avant et Après. Avertir si erreur.
;******************************************************************************
invoke CreateFile,addr NomFic1,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
cmp eax,-1
jne @F
invoke MessageBox,0,addr Texte,addr szAvertissement,MB_OK
jmp Stop
@@:
mov hFile1,eax
invoke CreateFile,addr NomFic2,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
cmp eax,-1
jne @F
invoke MessageBox,0,addr Texte1,addr szAvertissement,MB_OK
jmp Stop
;********************************************************************************
; Recherche de la taille exacte des 2 fichiers et réservation de la mémoire
; correspondante.Calcul de l'adresse de la fin des tampons pour controle
; de fin de recherche.Placer les fichiers dans les tampons.
;********************************************************************************
@@:
mov hFile2,eax
invoke GetFileSize,hFile1,SizeH
mov Taille1,eax
invoke GetFileSize,hFile2,SizeH
mov Taille2,eax
invoke GlobalAlloc,GHND,Taille1
mov hMem1,eax
invoke GlobalLock,eax
mov pMem1,eax
add eax,Taille1
mov FinAvant,eax
invoke GlobalAlloc,GHND,Taille2
mov hMem2,eax
invoke GlobalLock,eax
mov pMem2,eax
add eax,Taille2
mov FinApres,eax
invoke ReadFile,hFile1,pMem1,Taille1,addr NbLus,NULL
invoke ReadFile,hFile2,pMem2,Taille2,addr NbLus,NULL
;****************************************************************************
; Controle pour savoir si les 2 fichiers correspondent bien au même lecteur.
; sinon avertissement.
;****************************************************************************
mov esi,pMem1 ; début fichier Avant.txt
mov edi,pMem2 ; début fichier Après.txt
cmpsb ; la lettre de lecteur doit être la même.
je @F
invoke MessageBox,0,addr Texte2,addr szAvertissement,0
jmp stop
;*****************************************************************************
; Allocation de mémoire pour buffers temporaires : Fichiers retirés
; et fichiers ajoutés.
;*****************************************************************************
@@:
invoke GlobalAlloc,GHND,2000000
mov hMem3,eax
invoke GlobalLock,eax
mov pMem3,eax
invoke GlobalAlloc,GHND,3000000
mov hMem4,eax
invoke GlobalLock,eax
mov pMem4,eax
;*******************************************************************************
; comparaison esi, edi jusqu'à différence, avec controle si fin de fichier
; avant ou après atteinte. dans ce cas terminer, sinon continue.
;*******************************************************************************
Continue:
cmpsb
jne @F
cmp esi,FinAvant
jae final
cmp edi,FinApres
jae final
jmp Continue
;*********************************************************************************
; on va rechercher l'équivalence de la 1ère ligne non conforme de Avant
; avec une des lignes suivantes de Après.
;*********************************************************************************
@@:
dec esi ; recherche du 1er octet ligne non idem
cmp esi,pMem1 ; dans Avant avec controle debut fichier
je a0 ;
cmp byte ptr[esi],0Ah ;
jne @B ;
inc esi ;
a0:
mov Pointeur1,esi ; Pointeur1 peut varier en cours de recherche
mov Pointeur4,esi ; Référence au point de départ de la recherche
@@:
dec edi ; recherche du 1er octet ligne non idem
cmp edi,pMem2 ; dans Après avec controle début de fichier
je @1 ;
cmp byte ptr[edi],0Ah ;
jne @B ;
inc edi ;
@1:
mov Pointeur2,edi ; Pointeur2 variera pendant la recherche
LigneSuivante:
;******************************************************************************
; Si edi = ou + grand que FinApres, c'est qu'on a rien trouvé : donc changer
; le sens de comparaison.
;******************************************************************************
@@:
inc edi ; recherche de la ligne suivante dans Après
cmp edi,FinApres ; avec controle de dépassement éventuel de
jae Change ; la fin de fichier (moins de 200 restants)
cmp byte ptr[edi],0Ah ;
jne @B ;
inc edi ;
mov Pointeur3,edi ; adresse de la nouvelle ligne
Verifie: cmpsb ; on compare en boucle tant qu'une différence est
jne @F ; trouvée ou que les 200 lignes ne sont pas vues.
cmp esi,FinAvant ; Cotrole de dépassement éventuel
jae final ;
cmp edi,FinApres ;
jae final ;
cmp byte ptr[esi],0Ah ; si OK jusqu'à 0Ah : lignes identiques
je @2 ; donc on traite
jmp Verifie ; sinon : boucle
@@:
mov esi,Pointeur4 ; remettre esi au départ dans Avant
jmp LigneSuivante ; et voir plus loin dans Après
@2:
mov eax,Pointeur4 ; P4 = adresse ligne pas OK dans Avant
sub eax,Pointeur1 ; P1 = adresse ligne OK dans Avant
cmp eax,0 ; si P4 n'a pas bougé : pas de retirés
je @F ;
mov edx,pMem3 ; Début du buffer des retirés
add edx,FinBuf1 ; Nb octets déja écrits
;****************************************************************************
; Copie Nb octets (eax) dans pMem3 (edx) depuis Pointeur1
; et met à jour le Nb octets déjà copiés
;*****************************************************************************
invoke MemCopy,Pointeur1,edx,eax
add FinBuf1,eax ;
@@:
mov eax,Pointeur3 ; P3 = adresse ligne pas OK dans Après
sub eax,Pointeur2 ; P2 = adress ligne OK dans Après
cmp eax,0 ;
je @F ;
mov edx, pMem4 ; idem ci-dessus mais avec Ajoutés et Pointeur2
add edx,FinBuf2 ;
invoke MemCopy,Pointeur2,edx,eax
add FinBuf2,eax ;
@@:
mov esi,Pointeur4 ; replacer les 2 registres pour continuer
mov edi,Pointeur3 ;
jmp Continue ;
Change:
; mov ebx,200 ; comparer 200 fichiers max dans Avant
mov edi,Pointeur2 ; remettre les 2 registres au départ de la
mov Pointeur3,edi ; comparaison dans Avant et Après en inversant
mov esi,Pointeur4 ; les pointeurs puisque on change de fichier
@@:
inc esi ; recherche de la ligne suivante dans Avant
cmp esi,FinAvant ;
jae @2 ;
cmp byte ptr[esi],0Ah ; Fin de ligne?
jne @B ; oui : C'est OK
inc esi ;
mov Pointeur4,esi ; P4 = adresse nouvelle ligne à scanner
jmp Verifie ; et on repart
Stop:
ret
Onyva endp
;==========================================================
Resultat proc
;************************************************************************
; fermer les 2 fichiers ouverts,libérer la mémoire qui n'est plus utile
; et mettre esi sur le début du 1er Buffer provisoire.
;************************************************************************
invoke CloseHandle,hFile1
invoke CloseHandle,hFile2
invoke GlobalUnlock,addr hMem1
invoke GlobalUnlock,addr hMem2
mov esi,pMem3
;*************************************************************************
; recherche du Nb d'octets dans les 2 buffers, les additionner et ajouter
; le Nb d'octets nécéssaires pour les en-têtes (154).
; Allouer la mémoire correspondante et y formater le fichier des différences
;*************************************************************************
@@:
inc esi
cmp byte ptr[esi],0
jne @B
mov eax,esi
sub eax,pMem3
mov esi,pMem4
@@:
inc esi
cmp byte ptr[esi],0
jne @B
mov ebx,esi
sub ebx,pMem4
add eax,ebx
add eax,154
mov NbOctets,eax
invoke GlobalAlloc,GHND,NbOctets
mov hMem1,eax
invoke GlobalLock,hMem1
mov pMem1,eax
invoke szMultiCat,6,pMem1,addr Ajoutes,addr Separe,pMem4,
addr Separe,addr Supprimes,pMem3
;*******************************************************************
; remplir la structure OPENFILENAME et appeler dialogBox demandant
; le nom du fichier pour la sauvegarde.
;*****************************************************************ù**
mov ofn.lStructSize,sizeof OPENFILENAME
mov ofn.hWndOwner,NULL
mov ofn.hInstance,NULL
mov ofn.lpstrFilter,offset szFilter
mov ofn.lpstrFile,offset szFileName
mov ofn.nMaxFile,sizeof szFileName
mov ofn.lpstrTitle,offset szTitle
mov ofn.Flags,OFN_EXPLORER or OFN_LONGNAMES or \
OFN_HIDEREADONLY
@@:
invoke GetSaveFileName,addr ofn
cmp szFileName[0],0
jne @F
invoke MessageBox,0,addr szMess,addr szAvertissement,MB_OK
jmp @B
;*************************************************************************
; Création et écriture du fichier des différences. Fermeture de ce fichier
; et libération du reste de mémoire.
;*************************************************************************
@@:
invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,
NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,NULL
mov hFile1,eax
invoke WriteFile,hFile1,pMem1,NbOctets,addr SizeH,NULL
invoke CloseHandle,hFile1
invoke GlobalUnlock,hMem1
invoke GlobalUnlock,hMem3
invoke GlobalUnlock,hMem4
ret
Resultat endp
;**********************************************************
End start
;**********************************************************
; ListeFichiers.rc
500 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "\masm32\en_cours\icones\ICONE24.ico"
#include "\masm32\include\resource.h"
101 DIALOGEX MOVEABLE PURE LOADONCALL DISCARDABLE 0, 0, 315, 144, 0
STYLE DS_MODALFRAME | 0x0004 | DS_CENTER | WS_CAPTION | WS_SYSMENU | WS_POPUP
CAPTION " Suivi des modifications de fichiers sur le Disque Dur"
FONT 12, "Monotype Corsiva",0,1 /*TRUE(Italique)*/
BEGIN
CONTROL "",700,STATIC,SS_SIMPLE | WS_CHILD | WS_VISIBLE,85,90,210,28
PUSHBUTTON "Disque Avant", 1000, 10,30,60,14, 0, , 0
PUSHBUTTON "Disque Après", 1001, 10,54,60,14, 0, , 0
PUSHBUTTON "Voir Changements",1002, 10,78,60,14, 0, , 0
PUSHBUTTON "Quitter",1003, 10,102,60,14, 0, , 0
LTEXT " Sélectionnez le lecteur à vérifier : ",3,10,5,290,22,WS_BORDER
LTEXT " Sélection obligatoire!",4,12,15,290,10
CTEXT "",1,80,78,220,38,WS_BORDER | 0x00001000,0,0
CTEXT "Ce programme liste les fichiers présents sur le\nDisque dur avant et après l'installation d'un\nlogiciel puis compare les 2 fichiers et indique\n les changements survenus : Fichiers supprimés et ajoutés.", -1,80,30,220,38, WS_BORDER | 0x00001000,0,0
END
;*******************************************************
; ListeFichiers.inc
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\masm32.lib
;=================
; Local prototypes
;=================
DlgProc1 PROTO :DWORD,:DWORD,:DWORD,:DWORD
Cherche PROTO :DWORD
TourSuivant PROTO
Traite PROTO
FaitBuff PROTO :DWORD,:DWORD
FaitPath PROTO :DWORD,:DWORD
.data
szSlashB db "\*.*",0
szSlash db "\",0
Nom db "C:",0
CbBox db "COMBOBOX",0
NomFic1 db "Avant.txt",0
NomFic2 db "Après.txt",0
Ajoutes db "Fichiers ajoutés : ",0Dh,0Ah,0
Supprimes db "Fichiers retirés : ",0Dh,0Ah,0
Separe db "*****************************************************",0Dh,0Ah,0Ah,0
szMess db "Un nom de fichier est obligatoire!",0
szAvertissement db " ATTENTION!",0
szFilter db "Tous Fichiers",0,"*.*",0,
"Fichiers Texte",0,".TXT",0,0
szTitle db "Sauve différences dans....",0
Texte db "Pas de Fichier Avant pour comparaison!!!",0
Texte1 db "Pas de Fichier Après pour comparaison!!!",0
Texte2 db "Les 2 fichiers doivent concerner le même Lecteur!!!!",0
ofn OPENFILENAME <>
bri BROWSEINFO <>
wfd WIN32_FIND_DATA <>
Pt POINT <>
.data?
szFileName db 300 dup (?)
szPath db 40 dup (?)
Buffer db 256 dup (?)
Adresses db 8192 dup (?)
UserName db 12 dup (?)
hMem1 dd ?
pMem1 dd ?
hMem2 dd ?
pMem2 dd ?
hMem3 dd ?
pMem3 dd ?
hMem4 dd ?
pMem4 dd ?
hFile1 dd ?
hFile2 dd ?
Actu dd ?
Actu1 dd ?
Pointeur1 dd ?
Pointeur2 dd ?
Pointeur3 dd ?
Pointeur4 dd ?
Taille1 dd ?
Taille2 dd ?
Tampon dd ?
Tampon1 dd ?
FinBuf1 dd ?
FinBuf2 dd ?
FinAvant dd ?
FinApres dd ?
NbOctets dd ?
NbLus dd ?
NbEcrits dd ?
NbRep dd ?
hDialog dd ?
Passage dd ?
CptRep dd ?
CptFic dd ?
SizeH dd ?
hCbBox dd ?
Lecteur db 6 dup (?)
hBtn1 dd ?
hBtn2 dd ?
hBtn3 dd ?
Conclusion :
Permet de contrôler si une désinstallation a été complètement effectuée ou de savoir ce qui a été réelleme,t ajouté lors d'une installation.
Efficace et très utile lorsque l'on utilise des versions d'essai qui laissent bien souvent des scories après la désinstallation.
les fichiers avant.txt et apres.txt créés lors de l'exécution se trouvent dans le même répertoire que l'exécutable.
Le nom et l'emplacement du fichier contenant les différences est demandé à l'utilisateur à la fin du processus.
Fonctonne sur Windows XP et Windows7.
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.