Interfaces IShellFolder & IEnumIDList

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Interfaces IShellFolder & IEnumIDList

Message par Anonyme2 »

Je ne crois pas que c'est un truc ou astuce mais je ne sais pas ou poster cet exemple.
J'ai passé un certain nombre d'heure sur ce code et aussi sur la saine lecture de la dos MS ( :mrgreen: )

Avec les interfaces, rien n'est vraiment simple de prime abord...

Code : Tout sélectionner

; Auteur : Denis 
; Version de PB : 3.91
; Date : 02 juin 2004 
; Testé sous WIN98 SE 
;
; Explication du programme : 
; Utilisation des interfaces IShellFolder et IEnumIDList pour afficher le contenu
; du dossier 'SEND TO' (envoyer vers) pour cet exemple


;- Constantes utilisateur
#Fenetre = 0

; constantes possibles utilisables par la méthode EnumObjects de l'interface IShellFolder
#SHCONTF_FOLDERS = $0020
#SHCONTF_NONFOLDERS = $0040
#SHCONTF_INCLUDEHIDDEN = $0080
#SHCONTF_INIT_ON_FIRST_NEXT = $0100
#SHCONTF_NETPRINTERSRCH = $0200
#SHCONTF_SHAREABLE = $0400
#SHCONTF_STORAGE = $0800

; constantes possibles utilisables par la méthode GetDisplayNameOf de l'interface IShellFolder
#SHGDN_NORMAL = $0000
#SHGDN_INFOLDER = $0001
#SHGDN_FOREDITING = $1000
#SHGDN_FORADDRESSBAR = $4000
#SHGDN_FORPARSING = $8000

; constantes possibles pour le paramètre uType de la structure STRRET
#STRRET_WSTR = 0
#STRRET_OFFSET = 1
#STRRET_CSTR = 2

; quelques constantes possibles pour l'API SHGetSpecialFolderLocation
#CSIDL_DESKTOP = 0
#CSIDL_PRINTERS = 4
#CSIDL_RECENT = 8
#CSIDL_SENDTO = 9
#CSIDL_STARTMENU = 11
#CSIDL_FONTS = 14

; constantes possibles pour l'API CoInitializeEx
#COINIT_MULTITHREADED = 0
#COINIT_APARTMENTTHREADED = 2
#COINIT_DISABLE_OLE1DDE = 4
#COINIT_SPEED_OVER_MEMORY = 8



;- Structure
Structure STRRET
   uType.l
   StructureUnion
   pOleStr.l
   uOffset.l
   cStr.b[#MAX_PATH]
   EndStructureUnion
EndStructure

;- Variables globales
Global ppMalloc.l ; pointeur sur l'interface Shell IMalloc

; ; /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
; ; \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

;- Debut prog
If OpenWindow(0, 0, 0, 600, 400, #PB_Window_ScreenCentered | #PB_Window_SystemMenu, "Explorer les dossiers avec IShellFolder")
   If CreateGadgetList(WindowID())
      IdListIcon = ListIconGadget(0, 10, 10, 580, 380, "Contenu du Dossier SEND TO", 575, #LVS_SHAREIMAGELISTS)
      ; AddGadgetColumn(0, 1, "Taille", 575 / 5)
      ; AddGadgetColumn(0, 2, "Type", 575 / 5 * 2)
      
      CoInitializeEx_(0, #COINIT_SPEED_OVER_MEMORY) ; Initialise la librairie COM pour le thread courant
      
      shlwapiDll = OpenLibrary(100, "shlwapi.dll")
      
      SHGetMalloc_(@pMalloc)
      pszDisplayName = AllocateMemory((#MAX_PATH * 2) + 2)
      
      ; l'API SHGetSpecialFolderLocation retourne  #S_OK en cas de succès sinon une  erreur
      ; Cette API est remplacée par l'API SHGetFolderLocation depuis Windows 2000, mais
      ; fonctionne avec les nouveaux OS
      ; L'API retourne dans ppidl un pointeur sur un élément identifiant une liste specifiant
      ; la localisation du dossier relatif à la racine du 'name space' (le bureau)
      If SHGetSpecialFolderLocation_(0, #CSIDL_SENDTO, @ppidl.l) = #NOERROR And shlwapiDll
         
         ; SHGetDesktopFolder retourne dans ppshf le pointeur sur l'interface IShellFolder
         ; pour le dossier 'Bureau'
         If SHGetDesktopFolder_(@ppshf.IShellFolder) = #NOERROR
            
            ; la méthode BindToObject de l'interface IShellFolder retrouve un object IShellFolder
            ; pour un sous-dossier
            If ppshf\BindToObject(ppidl, 0, ?IID_IShellFolder, @ppvOut.IShellFolder) = #NOERROR
               
               ppshf\Release() ; on libère l'interface IShellFolder retournée par
               ; SHGetDesktopFolder, on n'en a plus besoin
               
               ; La méthode BindToObject de l'interface IShellFolder a retourné dans ppvOut
               ; un pointeur sur une interface IShellFolder  pour un sous-dossier
               ; on peut donc commencer l'énumération avec la méthode EnumObjects (interface IShellFolder)
               ; EnumObjects permet de déterminer le contenu d'un dossier en créant un élément
               ; identifiant un object 'énumeration' et retournant son interface IEnumIDList.
               ; Les méthodes supportée par cette interface peuvent être utilisées pour énumérer
               ; le contenu d'un dossier.
               If ppvOut\EnumObjects(0, #SHCONTF_FOLDERS | #SHCONTF_NONFOLDERS, @ppenum.IEnumIDList) = #S_OK
                  
                  ; La méthode Next de l'interface IEnumIDList permet de commencer l'énumération
                  ; La méthode Next énumère dans notre cas les éléments un par un (1er paramètre quui indique
                  ; aussi que pidlItems est un tableau à un élément. Pour retrouver plus d'éléments à la fois,
                  ; il faut dimensionner le tableau avec SHGetMalloc
                  ; celtFetched retourne une valeur qui indique combien d'éléments sont retournés par
                  ; la fonction et dans notre cas au max 1 sinon 0 si plus d'éléments
                  hr = ppenum\Next(1, @pidlItems, @celtFetched)
                  
                  ; on teste dans la boucle qu'il n'y a pas d'erreur et qu'il y a bien un élément
                  While ((hr = #NOERROR) And (celtFetched = 1))
                     
                     ; la méthopde GetDisplayNameOf de l'interface IShellFolder retrouve
                     ; le nom d'affichage pour le dossier)fichier object spécifié.
                     ; le 3ème paramètre est une variable basée sur la structure STRRET
                     strDispName.STRRET\uType = #STRRET_OFFSET
                     If ppvOut\GetDisplayNameOf(pidlItems, #SHGDN_INFOLDER, @strDispName.STRRET) = #NOERROR
                        
                        ; La chaine retournée par GetDisplayNameOf doit être formatée avant d'être
                        ; affichée correctement avec l'API StrRetToBufA de la dll shlwapi.dll
                        ; pszDisplayName est le buffer qui recevra la chaine à afficher
                        CallFunction(100, "StrRetToBufA", @strDispName, pidlItems, pszDisplayName, #MAX_PATH)
                        
                        ; on affiche dans la Listicon
                        AddGadgetItem(0, 0, PeekS(pszDisplayName)) 
;                         
                        hr = ppenum\Next(1, @pidlItems, @celtFetched)
                     EndIf
                  Wend
                  FreeLibrary_(shlwapiDll) ; ferme shlwapi.dll
               EndIf
            EndIf
         EndIf
      EndIf
   EndIf
   
   CoTaskMemFree_(ppidl) ; libère la mémoire pointée par ppidl
   
   ;- boucle evenements
   While WaitWindowEvent() <> #PB_EventCloseWindow And EventWindowID() <> WindowID()
   Wend
   
EndIf
CoUninitialize_() ; ferme la librairie COM pour le thread courant

End


DataSection
   ; Interface IShellFolder;
   ; helpstring("IShellFolder"),
   ; uuid(000214E6-0000-0000-C000-000000000046)
   
   IID_IShellFolder : ; cléf du registre mise sous la forme de DATA
      Data.l $000214E6
      Data.w $0000, $0000
      Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection

Dernière modification par Anonyme2 le ven. 04/juin/2004 6:37, modifié 1 fois.
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

ça revient à faire un ExamineDirectory, non ?
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Fred
Site Admin
Messages : 2808
Inscription : mer. 21/janv./2004 11:03

Message par Fred »

Du bon boulot !
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Le Soldat Inconnu a écrit :ça revient à faire un ExamineDirectory, non ?
oui, sauf que essaye d'aficher le contenu par exemple du dossier des fichiers temporaire internet, et bien tu n'y arrivera pas (ce sont des objets), par contre avec les interfaces c'est la méthode. De plus, l'extraction des icônes avec les méthodes est plus rapide qu'avec la méthode classique, les interfaces permettent aussi d'afficher rapidement avec les object d'affichage, de trier etc etc etc. C'est vrai que c'est un peu lourd et pas forcément intuitif, j'ai souvent lu et relu la doc en me grattant la tête; en plus pour mettre en forme la chaine, la doc MS parle de StrRetToBuf, et là ça marchait pas et j'ai utilisé le super utilitaire de Cederavic (merci Ced.) pour retourner les fonctions des dll et j'ai vu qu'il fallait mettre StrRetToBufA ou W selon le type de chaine.

Bon, examinedirectory marche bien :D

J'ai essayé de commenter comme je le comprend pour rendre ça un peu plus compréhensible.

Fred a écrit :Du bon boulot !
:D
Avatar de l’utilisateur
cederavic
Messages : 1338
Inscription : lun. 09/févr./2004 23:38
Localisation : Bordeaux

Message par cederavic »

Denis a écrit :j'ai utilisé le super utilitaire de Cederavic (merci Ced.)
:D
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

:wink:
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

C'est toujours un peu problématique de récupérer les valeurs identifiant les interfaces. Elles sont définies dans des fichiers .idl et j'avais pas envie d'écrire un analyseur de fichier.

Le code qui suit récupère la clef dans la base de registre, la met en forme sous forme de DATA utilisables par PureBasic.

Le code est court mais le résultats prend de la place et se trouve dans le presse papier.

Avec mon OS WIN98, j'ai une fois inséré dans Purebasic plus de 13550 lignes.

L'accès à la base de registre ne se fait qu'en lecture donc sans risque :wink:

J'espère que ça sera utile.

voici quelques lignes du résultat

Code : Tout sélectionner

; Clef {0000010D-0000-0000-C000-000000000046}
; Valeur : IViewObject
IID_IViewObject :
Data.l $0000010D
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46

; Clef {0000011D-0000-0000-C000-000000000046}
; Valeur : IOleLink
IID_IOleLink :
Data.l $0000011D
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46

; Clef {00000127-0000-0000-C000-000000000046}
; Valeur : IViewObject2
IID_IViewObject2 :
Data.l $00000127
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46

; Clef {00000128-0000-0000-C000-000000000046}
; Valeur : IOleCache2
IID_IOleCache2 :
Data.l $00000128
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46

; Clef {0000012A-0000-0000-C000-000000000046}
; Valeur : IContinue
IID_IContinue :
Data.l $0000012A
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46

et le code

Code : Tout sélectionner

; Auteur : Denis 
; Version de PB : 3.91
; Date : 03 juin 2004 
; 
; Explication du programme : 
; récupère les cléfs des interfaces et les met sous la forme de Datas
; dans le presse papier


Procedure.s GetDATA(Name.s, Value.s)
   ; retourne une chaine de type
   
   ; IID_IShellFolder : ; cléf du registre mise sous la forme de DATA
   ; ; Value.s = "{000214E6-0000-0000-C000-000000000046}"
   ; Data.l $000214E6
   ; Data.w $0000, $0000
   ; Data.b $C0, $00, $00, $00, $00, $00, $00, $46
   
   Nom.s = "IID_" + Name + " :"
   Data1.s = "Data.l $" + Mid(Value, 2, 8)
   Data2.s = "Data.w $" + Mid(Value, 11, 4) + ", $" + Mid(Value, 16, 4)
   Data3.s = "Data.b $" + Mid(Value, 21, 2) + ", $" + Mid(Value, 23, 2)
   
   For i = 26 To 36 Step 2
      Data3 + ", $" + Mid(Value, i, 2)
   Next i
   
   ProcedureReturn Nom + Chr(10) + Data1 + Chr(10) + Data2 + Chr(10) + Data3
EndProcedure

; énumération des clefs du registre
If RegOpenKeyEx_(#HKEY_CLASSES_ROOT, "Interface", 0, #KEY_ENUMERATE_SUB_KEYS, @hKey) = #ERROR_SUCCESS
   iSubkey = 0 ; compteur utilisé par RegEnumKeyEx pour énumérer les SubKey
   ; incémenté de 1 à chaque tour de boucle
   lpszName$ = Space(100) ; récupère la chaine de la SubKey
   lpcchName = 100 ; variable indiquant la taille de la chaine
   B$ = "" ; récupère toutes les données pour les mettre dans le presse papier
   Enum = RegEnumKeyEx_(hKey, iSubkey, @lpszName$, @lpcchName, 0, 0, 0, @lpftLastWrite)
   lpszValue.s = Space(100)
   pcbValue = 100

   While Enum <> #ERROR_NO_MORE_ITEMS
      ; on récupère le nom de l'interface asscociée
      If RegQueryValue_(hKey, lpszName$, @lpszValue, @pcbValue) = #ERROR_SUCCESS
         B$ + "; Clef " + lpszName$ + Chr(10) + "; Valeur : " + PeekS(lpszValue) + Chr(10) + GetDATA(lpszValue, lpszName$) + Chr(10) + Chr(10)
      EndIf
      iSubkey + 1 ; on incrémente le compteur
      Enum = RegEnumKeyEx_(hKey, iSubkey, lpszName$, @lpcchName, 0, 0, 0, @lpftLastWrite)
   Wend
   
   RegCloseKey_(hKey)
Else
   MessageRequester("RegOpenKeyEx Interface", " a échoué", 16)
EndIf

SetClipboardText(B$) ; résultat dans le presse papier


Debug " Opération terminée"
Répondre