;Autor: freak ; Special Shell folders CLSID values: ; ; Note: those are "relative" values, so since the control panel is inside ; "My Computer", the path to it is actually this: ; "::{20d04fe0-3aea-1069-a2d8-08002b30309d}\::{21ec2020-3aea-1069-a2dd-08002b30309d}" ; Some can be used directly (like My Network Places), but most need to ; be put together with their parents CLSIDs to work. ; ; ::{d20ea4e1-3957-11d2-a40b-0c5020524153} Administrative Tools ; ::{85bbd920-42a0-1069-a2e4-08002b30309d} Briefcase ; ::{21ec2020-3aea-1069-a2dd-08002b30309d} Control Panel ; ::{d20ea4e1-3957-11d2-a40b-0c5020524152} Fonts ; ::{ff393560-c2a7-11cf-bff4-444553540000} History ; ::{00020d75-0000-0000-c000-000000000046} Inbox ; ::{00028b00-0000-0000-c000-000000000046} Microsoft Network ; ::{20d04fe0-3aea-1069-a2d8-08002b30309d} My Computer ; ::{450d8fba-ad25-11d0-98a8-0800361b1103} My Documents ; ::{208d2c60-3aea-1069-a2d7-08002b30309d} My Network Places ; ::{1f4de370-d627-11d1-ba4f-00a0c91eedba} Network Computers ; ::{7007acc7-3202-11d1-aad2-00805fc1270e} Network Connections ; ::{2227a280-3aea-1069-a2de-08002b30309d} Printers And Faxes ; ::{7be9d83c-a729-4d97-b5a7-1b7313c39e0a} Programs Folder ; ::{645ff040-5081-101b-9f08-00aa002f954e} Recycle Bin ; ::{e211b736-43fd-11d1-9efb-0000f8757fcd} Scanners And Cameras ; ::{d6277990-4c6a-11cf-8d87-00aa0060f5bf} Scheduled Tasks ; ::{48e7caab-b918-4e58-a94d-505519c795dc} Start Menu Folder ; ::{7bd29e00-76c1-11cf-9dd0-00a0c9034933} Temporary Internet Files ; ::{bdeadf00-c265-11d0-bced-00a0c90ab50f} Web Folders ; Some stuff that is needed: ; #SHCONTF_FOLDERS = $0020; // only want folders enumerated (SFGAO_FOLDER) #SHCONTF_NONFOLDERS = $0040; // include non folders #SHCONTF_INCLUDEHIDDEN = $0080; // show items normally hidden #SHCONTF_INIT_ON_FIRST_NEXT = $0100; // allow EnumObject() To Return before validating enum #SHCONTF_NETPRINTERSRCH = $0200; // hint that client is looking For printers #SHCONTF_SHAREABLE = $0400; // hint that client is looking sharable resources (remote shares) #SHCONTF_STORAGE = $0800; // include all items With accessible storage And their ancestors #_SHGDN_NORMAL = $0000; // Default (display purpose) #_SHGDN_INFOLDER = $0001; // displayed under a folder (relative) #_SHGDN_FOREDITING = $1000; // For in-place editing #_SHGDN_FORADDRESSBAR = $4000; // UI friendly parsing name (remove ugly stuff) #_SHGDN_FORPARSING = $8000; // parsing name For ParseDisplayName() Structure STRRET uType.l StructureUnion *pOleStr uOffset.l cStr.b[#MAX_PATH] EndStructureUnion EndStructure #STRRET_WSTR = 0 #STRRET_OFFSET = $1 #STRRET_CSTR = $2 DataSection IID_IShellFolder: ; {000214E6-0000-0000-C000-000000000046} Data.l $000214E6 Data.w $0000, $0000 Data.b $C0, $00, $00, $00, $00, $00, $00, $46 EndDataSection ; Helper function to read the content of the filled STRRET structure ; correctly, and release any memory it allocated. ; Procedure.s ReadSTRRET(*ret.STRRET) If *ret\uType = #STRRET_WSTR And *ret\pOleStr Result$ = PeekS(*ret\pOleStr, -1, #PB_Unicode) CoTaskMemFree_(*ret\pOleStr) *ret\pOleStr = 0 ElseIf *ret\uType = #STRRET_OFFSET Result$ = "" ; SDK is not fully clear on how to handle this. ElseIf *ret\uType = #STRRET_CSTR Result$ = PeekS(@*ret\cstr[0], #MAX_PATH, #PB_Ascii) EndIf ProcedureReturn Result$ EndProcedure ; Function to recursively scan a Shell folder up to a maximum level ; of recursivity (so not the entire file structure is read.) ; Procedure ScanShellFolder(Folder.IShellFolder, Sublevel, MaxSublevel) ; Try to get an enumerator object for the children of this object. ; Play around a bit with the flags to exclude certain objects from the enumeration ; If Folder\EnumObjects(0, #SHCONTF_FOLDERS|#SHCONTF_NONFOLDERS|#SHCONTF_INCLUDEHIDDEN|#SHCONTF_SHAREABLE, @Enum.IEnumIDList) = #S_OK ; get the child *idl pointers from the enumerator object While Enum\Next(1, @*idl.ITEMIDLIST, 0) = #NOERROR ; get the display name for the object If Folder\GetDisplayNameOf(*idl, #_SHGDN_NORMAL, @result.STRRET) = #S_OK Name$ = ReadSTRRET(@result) EndIf ; get a "parsable" name for the object ; for files or normal folders, this is a path If Folder\GetDisplayNameOf(*idl, #_SHGDN_FORPARSING, @result.STRRET) = #S_OK Path$ = ReadSTRRET(@result) EndIf ; add to tree AddGadgetItem(0, -1, Name$ + " (" + Path$ + ")", 0, Sublevel) index = CountGadgetItems(0)-1 If Sublevel <= MaxSublevel ; To scan the children of this item as well, we need to get a IShellFolder ; pointer from the *idl value If Folder\BindToObject(*idl, 0, ?IID_IShellFolder, @NewFolder.IShellFolder) = #S_OK ; once again a scan ScanShellFolder(NewFolder, Sublevel + 1, MaxSublevel) NewFolder\Release() EndIf EndIf SetGadgetItemState(0, index, #PB_Tree_Expanded) ; free idl memory CoTaskMemFree_(*idl) Wend ; free enumerator object Enum\Release() EndIf EndProcedure ; Code Start ; If OpenWindow(0, 0, 0, 400, 500, "Shell Folders", #PB_Window_SystemMenu|#PB_Window_ScreenCentered) TreeGadget(0, 10, 10, 380, 480) ; To get to a shell folder, we always start with the desktop object, so get it: ; If SHGetDesktopFolder_(@Desktop.IShellFolder) = #NOERROR ; Now parse the CLSID to get to the "My Network Places". ; Try the second line to explore the content of the Control Panel ; If Desktop\ParseDisplayName(0, 0, "::{208d2c60-3aea-1069-a2d7-08002b30309d}", 0, @*idl.ITEMIDLIST, 0) = #S_OK ; What we have now is the *idl pointer. This sort of a path in the Shell ; From that we get a new IShellFolder object representing the "My Network Places" ; If Desktop\BindToObject(*idl, 0, ?IID_IShellFolder, @Network.IShellFolder) = #S_OK ; Lets get the display name of "My Network Places" ; This is done on the parent object, with our *idl ; If Desktop\GetDisplayNameOf(*idl, #_SHGDN_NORMAL, @result.STRRET) = #S_OK AddGadgetItem(0, -1, ReadSTRRET(@result), 0, 0) EndIf ; call our scan procedure for this object. max 4 levels depth ; ScanShellFolder(Network, 1, 3) SetGadgetItemState(0, 0, #PB_Tree_Expanded) ; Release objects Network\Release() EndIf ; the memory used by an IDL must be freed CoTaskMemFree_(*idl) EndIf ; Release desktop object Desktop\Release() EndIf Repeat Until WaitWindowEvent() = #PB_Event_CloseWindow EndIf