Special Folders are folders which are presented to the user through an interface as an abstract concept, instead of an absolute folder path.
As of Windows Vista, those folders are referenced by a new set of GUID values called Known Folder IDs, replacing the older system of referring to standard folders by a CSIDL value.
See also:
PUBLIC oForm As Explorer
oForm = CREATEOBJECT( "SpecialFoldersForm" )
oForm.Visible=.T.
* end of main
DEFINE CLASS SpecialFoldersForm As Form
Width=520
Height=380
MinButton=.F.
AutoCenter=.T.
Caption="Windows Known Folders"
ShowTips=.T.
Backcolor=RGB(255,255,255)
ShowWindow=2
ADD OBJECT lst As SpecialFolderList WITH;
Left=10, Top=10, Width=500, Height=320,;
Anchor=15
ADD OBJECT cmdBrowse As CommandButton WITH;
Left=210, Top=340, Width=100, Height=27,;
Caption="Browse", Anchor=260
PROCEDURE cmdBrowse.Click
ThisForm.lst.BrowseFolder
ENDDEFINE
DEFINE CLASS SpecialFolderList As OleControl
#DEFINE GWL_STYLE -16
#DEFINE MAX_PATH 260
#DEFINE LVM_FIRST 0x1000
#DEFINE LVM_GETIMAGELIST (LVM_FIRST + 2)
#DEFINE LVM_SETIMAGELIST (LVM_FIRST + 3)
#DEFINE LVM_SETITEM (LVM_FIRST + 6)
#DEFINE LVIF_IMAGE 0x0002
#DEFINE LVS_SHAREIMAGELISTS 0x0040
#DEFINE LVSIL_SMALL 1
#DEFINE LVSIL_NORMAL 0
#DEFINE SHGFI_SMALLICON 0x000000001
#DEFINE SHGFI_LARGEICON 0
#DEFINE SHGFI_SHELLICONSIZE 0x00000004
#DEFINE SHGFI_ICON 0x000000100
#DEFINE SHGFI_TYPENAME 0x000000400
#DEFINE SHGFI_SYSICONINDEX 0x000004000
#DEFINE SHGFI_LINKOVERLAY 0x00008000
#DEFINE SHGFI_USEFILEATTRIBUTES 0x000000010
#DEFINE SHGFI_PIDL 0x00000008
#DEFINE SHGFI_SELECTED 0x00010000
#DEFINE SHGSI_ICONLOCATION 0
#DEFINE SHGSI_ICON SHGFI_ICON
#DEFINE SHGSI_SYSICONINDEX SHGFI_SYSICONINDEX
#DEFINE SHGSI_LINKOVERLAY SHGFI_LINKOVERLAY
#DEFINE SHGSI_SELECTED SHGFI_SELECTED
#DEFINE SHGSI_LARGEICON SHGFI_LARGEICON
#DEFINE SHGSI_SMALLICON SHGFI_SMALLICON
#DEFINE SHGSI_SHELLICONSIZE SHGFI_SHELLICONSIZE
#DEFINE BIF_RETURNONLYFSDIRS 1
#DEFINE BIF_DONTGOBELOWDOMAIN 2
#DEFINE BIF_STATUSTEXT 4
#DEFINE BIF_RETURNFSANCESTORS 8
#DEFINE BIF_EDITBOX 16
#DEFINE BIF_VALIDATE 32
#DEFINE BIF_NEWDIALOGSTYLE 64
#DEFINE BIF_NONEWFOLDERBUTTON 0x200
#DEFINE BIF_BROWSEFORCOMPUTER 0x1000
#DEFINE BIF_BROWSEFORPRINTER 0x2000
#DEFINE BIF_BROWSEINCLUDEFILES 0x4000
#DEFINE BIF_SHAREABLE 0x8000
#DEFINE BIF_UAHINT 0x00000100
#DEFINE BROWSEINFO_SIZE 32
OleClass="MSComctlLib.ListViewCtrl"
PROCEDURE Init
WITH THIS
.View=3
.LabelEdit=1
.HideColumnHeaders=1
.BorderStyle=0
.Appearance=0
.HideSelection=.F.
.AddColumnHeader("Folder", 300)
.AddColumnHeader("Path", 340)
.declare
.PopulateList
ENDWITH
= BINDEVENT(ThisForm, "GotFocus",;
THIS, "SwitchToSystemList")
PROCEDURE AddColumnHeader(cCaption, nWidth)
WITH THIS.ColumnHeaders.Add()
.Text=cCaption
.Width=nWidth
ENDWITH
PROCEDURE SwitchToSystemList
* switches ListItem control to using icons
* from the system image list
LOCAL nWStyle, hSysImgList, nResult,;
cBuffer, nIconFlags, nImgListType
nIconFlags = BITOR(SHGFI_SYSICONINDEX, SHGFI_ICON,;
SHGFI_TYPENAME, SHGFI_USEFILEATTRIBUTES)
WITH THIS
nImgListType = LVSIL_NORMAL
nIconFlags = BITOR(nIconFlags, SHGFI_LARGEICON)
* check if the system list is already assigned
IF SendMessage(.HWND, LVM_GETIMAGELIST,;
nImgListType, 0) = 0
nWStyle = GetWindowLong(.HWND, GWL_STYLE)
SetWindowLong(.HWND, GWL_STYLE,;
BITOR(m.nWStyle, LVS_SHAREIMAGELISTS))
cBuffer = REPLICATE(CHR(0), 1024)
hSysImgList = SHGetFileInfo("", 0,;
@cBuffer, LEN(cBuffer), nIconFlags)
= SendMessage(.HWND, LVM_SETIMAGELIST,;
LVSIL_SMALL, 0)
= INKEY(0.1) && a small delay may be required
= SendMessage(.HWND, LVM_SETIMAGELIST,;
LVSIL_SMALL, hSysImgList)
ENDIF
ENDWITH
PROCEDURE BrowseFolder
LOCAL nFolderId, nRootPIDL, cBuffer,;
oReturnedName, oDlgTitle, nFlags,;
hPidl, cSelectedItem
IF VARTYPE(THIS.SelectedItem) <> "O"
RETURN
ENDIF
nFolderId = VAL( THIS.SelectedItem.Tag )
nRootPIDL = 0
nResult = SHGetSpecialFolderLocation(;
0, nFolderId, @nRootPIDL )
oReturnedName = CREATEOBJECT("PChar",;
REPLICATE(CHR(0),MAX_PATH))
oDlgTitle = CREATEOBJECT("PChar",;
THIS.SelectedItem.Text+CHR(0) )
nFlags = BIF_NEWDIALOGSTYLE + BIF_UAHINT + ;
BIF_NONEWFOLDERBUTTON + BIF_BROWSEINCLUDEFILES
cBuffer = num2dword(ThisForm.HWnd) +;
num2dword(m.nRootPIDL) +;
num2dword(oReturnedName.GetAddr()) +;
num2dword(oDlgTitle.GetAddr()) +;
num2dword(nFlags)
cBuffer = PADR(cBuffer, BROWSEINFO_SIZE, CHR(0))
hPidl = SHBrowseForFolder(@cBuffer)
IF hPidl <> 0
cSelectedItem = oReturnedName.GetValue()
cSelectedItem = SUBSTR(cSelectedItem,;
1, AT(CHR(0),cSelectedItem)-1)
WAIT WINDOW NOWAIT m.cSelectedItem
= CoTaskMemFree( m.hPidl )
ENDIF
= CoTaskMemFree( m.nRootPIDL )
PROCEDURE PopulateList
* CSIDL (constant special item ID list)
WITH THIS
.AddLstItem( "AddNewProgramsFolder", 0x8000 )
.AddLstItem( "Administrative Tools", 0x0030 )
.AddLstItem( "AppData", 0x001a )
.AddLstItem( "Cache", 0x0020 )
.AddLstItem( "CD Burning", 0x003b )
.AddLstItem( "Common Administrative Tools", 0x002f )
.AddLstItem( "Common AppData", 0x0023 )
.AddLstItem( "Common Desktop", 0x0019 )
.AddLstItem( "Common Documents", 0x002e )
.AddLstItem( "Common Programs", 0x0017 )
.AddLstItem( "Common Start Menu", 0x0016 )
.AddLstItem( "Common Startup", 0x0018 )
.AddLstItem( "Common Templates", 0x002d )
* .AddLstItem( "CommonDownloads", 0 )
.AddLstItem( "CommonMusic", 0x0035 )
.AddLstItem( "CommonPictures", 0x0036 )
* .AddLstItem( "CommonRingtones", 0 )
.AddLstItem( "CommonVideo", 0x0037 )
* .AddLstItem( "ConnectionsFolder", 0 )
* .AddLstItem( "Contacts", 0 )
.AddLstItem( "ControlPanelFolder", 0x0003 )
.AddLstItem( "Cookies", 0x0021 )
* .AddLstItem( "CredentialManager", 0 )
* .AddLstItem( "CryptoKeys", 0 )
* .AddLstItem( "CSCFolder", 0 )
* .AddLstItem( "Default Gadgets", 0 )
.AddLstItem( "Desktop", 0 )
* .AddLstItem( "Device Metadata Store", 0 )
.AddLstItem( "DocumentsLibrary", 0x0005 )
* .AddLstItem( "Downloads", 0 )
* .AddLstItem( "DpapiKeys", 0 )
.AddLstItem( "Favorites", 0x0006 )
.AddLstItem( "Fonts", 0x0014 )
* .AddLstItem( "Gadgets", 0 )
* .AddLstItem( "Games", 0 )
* .AddLstItem( "GameTasks", 0 )
.AddLstItem( "History", 0x0022 )
* .AddLstItem( "HomeGroupFolder", 0 )
* .AddLstItem( "ImplicitAppShortcuts", 0 )
.AddLstItem( "InternetFolder", 0x0001 )
* .AddLstItem( "Libraries", 0 )
* .AddLstItem( "Links", 0 )
.AddLstItem( "Local AppData", 0x001c )
* .AddLstItem( "LocalAppDataLow", 0 )
* .AddLstItem( "MAPIFolder", 0 )
* .AddLstItem( "MusicLibrary", 0 )
.AddLstItem( "My Music", 0x000d )
.AddLstItem( "My Pictures", 0x0027 )
.AddLstItem( "My Video", 0x000e )
.AddLstItem( "MyComputerFolder", 0x0011 )
.AddLstItem( "NetHood", 0x0013 )
.AddLstItem( "NetworkPlacesFolder", 0x0012 )
.AddLstItem( "Personal", 0x0005 )
* .AddLstItem( "PicturesLibrary", 0 )
.AddLstItem( "PrintersFolder", 0x0004 )
.AddLstItem( "PrintHood", 0x001b )
.AddLstItem( "Profile", 0x0028 )
.AddLstItem( "ProgramFiles", 0x0026 )
* .AddLstItem( "ProgramFilesCommon", 0x002b )
.AddLstItem( "ProgramFilesCommonX86", 0x002b )
* .AddLstItem( "ProgramFilesX86", 0 )
.AddLstItem( "Programs", 0x0002 )
* .AddLstItem( "Public", 0 )
* .AddLstItem( "PublicGameTasks", 0 )
* .AddLstItem( "PublicLibraries", 0 )
* .AddLstItem( "Quick Launch", 0 )
.AddLstItem( "Recent", 0x0008 )
* .AddLstItem( "RecordedTVLibrary", 0 )
.AddLstItem( "RecycleBinFolder", 0x000a )
* .AddLstItem( "ResourceDir", 0 )
* .AddLstItem( "Ringtones", 0 )
* .AddLstItem( "SampleMusic", 0 )
* .AddLstItem( "SamplePictures", 0 )
* .AddLstItem( "SampleVideos", 0 )
* .AddLstItem( "SavedGames", 0 )
* .AddLstItem( "Searches", 0 )
* .AddLstItem( "SearchHomeFolder", 0 )
.AddLstItem( "SendTo", 0x0009 )
.AddLstItem( "Start Menu", 0x000b )
.AddLstItem( "Startup", 0x0007 )
.AddLstItem( "System", 0x0025 )
* .AddLstItem( "SystemCertificates", 0 )
* .AddLstItem( "SystemX86", 0 )
.AddLstItem( "Templates", 0x0015 )
* .AddLstItem( "User Pinned", 0 )
* .AddLstItem( "UserProfiles", 0x003e )
* .AddLstItem( "UsersFilesFolder", 0 )
* .AddLstItem( "UsersLibrariesFolder", 0 )
* .AddLstItem( "VideosLibrary", 0 )
.AddLstItem( "Windows", 0x0024 )
ENDWITH
PROCEDURE AddLstItem( cFolderName As String,;
nFolderId As Number )
LOCAL hPidl, nTypeIndex, cFileType
hPidl = 0
nResult = SHGetSpecialFolderLocation(;
0, nFolderId, @hPidl )
IF nResult = 0
nTypeIndex = 0
cFileType = ""
THIS.GetFileTypeInfo(hPidl, @nTypeIndex, @cFileType)
oItem = THIS.ListItems.Add(,, cFolderName ) && m.cFileType
WITH oItem
THIS.SetIcon(.Index, m.nTypeIndex)
.Subitems(1) = THIS.PathFromPIDL(m.hPidl)
.Tag = TRANSFORM( m.nFolderId ) && CSIDL
ENDWITH
= CoTaskMemFree( m.hPidl )
ENDIF
PROCEDURE PathFromPIDL( nPIDL As Number ) As String
LOCAL cBuffer
cBuffer = REPLICATE(CHR(0), MAX_PATH)
SHGetPathFromIDList( nPIDL, @cBuffer )
RETURN STRTRAN(m.cBuffer, CHR(0), "")
PROCEDURE GetFileTypeInfo(hPidl, nTypeIndex, cFileType)
* Obtains icon and description for the specified file type
LOCAL nBufsize, cBuffer, nFlags, hIcon
nBufsize=0x200
cBuffer = REPLICATE(CHR(0), nBufsize)
nFlags = BITOR(SHGFI_PIDL, SHGFI_SYSICONINDEX,;
SHGFI_SMALLICON, SHGFI_ICON, SHGFI_TYPENAME )
= SHGetFileInfoN(m.hPidl, 0, @cBuffer, nBufsize, nFlags)
hIcon = buf2dword(SUBSTR(cBuffer, 1, 4))
nTypeIndex = buf2dword(SUBSTR(cBuffer,5, 4))
cFileType = STRTRAN(SUBSTR(m.cBuffer,13+MAX_PATH), CHR(0),"")
IF hIcon <> 0
= DestroyIcon(hIcon)
ENDIF
PROCEDURE SetIcon(nItemIndex, nImgIndex)
* makes ListItem #nItemIndex display an icon
* stored under index #nImgIndex in the system image list
LOCAL cItemBuffer && LVITEM structure
cItemBuffer = num2dword(LVIF_IMAGE) +;
num2dword(nItemIndex-1) + num2dword(0) +;
num2dword(0) + num2dword(0) +;
num2dword(0) + num2dword(0) +;
num2dword(nImgIndex) + num2dword(0)
= SendMessageS(THIS.hWnd, LVM_SETITEM,;
0, @cItemBuffer)
PROCEDURE declare
DECLARE INTEGER DestroyIcon IN user32 INTEGER hIcon
DECLARE CoTaskMemFree IN ole32 INTEGER hPtr
DECLARE INTEGER SHGetFileInfo IN shell32;
STRING pszPath, LONG dwFileAttributes,;
STRING @psfi, LONG cbFileInfo, LONG uFlags
DECLARE INTEGER SHGetFileInfo IN shell32;
AS SHGetFileInfoN;
INTEGER ppidl, LONG dwFileAttributes,;
STRING @psfi, LONG cbFileInfo, LONG uFlags
DECLARE INTEGER SHGetPathFromIDList IN shell32;
INTEGER pidl, STRING @pszPath
DECLARE INTEGER SHGetSpecialFolderLocation IN shell32;
INTEGER hwndOwner, INTEGER nFolder,;
INTEGER @ppidl
DECLARE INTEGER SendMessage IN user32;
INTEGER hWindow, INTEGER Msg,;
INTEGER wParam, INTEGER lParam
DECLARE INTEGER SendMessage IN user32;
AS SendMessageS;
INTEGER hWindow, INTEGER Msg,;
INTEGER wParam, STRING @lParam
DECLARE INTEGER SetWindowLong IN user32;
INTEGER hWindow, INTEGER nIndex,;
INTEGER dwNewLong
DECLARE INTEGER GetWindowLong IN user32;
INTEGER hWindow, INTEGER nIndex
DECLARE INTEGER SHBrowseForFolder IN shell32;
STRING @lpbi
ENDDEFINE
DEFINE CLASS PChar As Session
PROTECTED hMem
PROCEDURE Init(cString As String)
THIS.hMem = 0
THIS.setValue(cString)
PROCEDURE Destroy
THIS.ReleaseString
FUNCTION GetAddr
RETURN THIS.hMem
FUNCTION GetValue
LOCAL nBufsize, cBuffer
nBufsize = THIS.GetAllocSize()
cBuffer = REPLICATE(CHR(0), m.nBufsize)
IF THIS.hMem <> 0
DECLARE RtlMoveMemory IN kernel32 As MemToStr;
STRING @, INTEGER, INTEGER
= MemToStr(@cBuffer, THIS.hMem, nBufsize)
ENDIF
RETURN m.cBuffer
FUNCTION GetAllocSize
DECLARE INTEGER GlobalSize IN kernel32 INTEGER hMem
RETURN Iif(THIS.hMem=0, 0, GlobalSize(THIS.hMem))
PROCEDURE SetValue(cString)
#DEFINE GMEM_FIXED 0
#DEFINE GMEM_MOVEABLE 2
#DEFINE GMEM_ZEROINIT 0x0040
THIS.ReleaseString
DECLARE INTEGER GlobalAlloc IN kernel32;
INTEGER, INTEGER
DECLARE RtlMoveMemory IN kernel32 As StrToMem;
INTEGER, STRING @, INTEGER
LOCAL nBufsize
nBufsize = LEN(cString)
THIS.hMem = GlobalAlloc(0x0040, nBufsize)
IF THIS.hMem <> 0
= StrToMem(THIS.hMem, @cString, nBufsize)
ENDIF
PROCEDURE ReleaseString
IF THIS.hMem <> 0
DECLARE INTEGER GlobalFree IN kernel32 INTEGER
= GlobalFree (THIS.hMem)
THIS.hMem = 0
ENDIF
ENDDEFINE
************** library functions **************
FUNCTION buf2dword(cBuffer)
RETURN Asc(SUBSTR(cBuffer, 1,1)) + ;
BitLShift(Asc(SUBSTR(cBuffer, 2,1)), 8) +;
BitLShift(Asc(SUBSTR(cBuffer, 3,1)), 16) +;
BitLShift(Asc(SUBSTR(cBuffer, 4,1)), 24)
FUNCTION buf2word(lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ;
Asc(SUBSTR(lcBuffer, 2,1)) * 256
FUNCTION num2dword(lnValue)
#DEFINE m0 0x0000100
#DEFINE m1 0x0010000
#DEFINE m2 0x1000000
IF lnValue < 0
lnValue = 0x100000000 + lnValue
ENDIF
LOCAL b0, b1, b2, b3
b3 = Int(lnValue/m2)
b2 = Int((lnValue - b3*m2)/m1)
b1 = Int((lnValue - b3*m2 - b2*m1)/m0)
b0 = Mod(lnValue, m0)
RETURN Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3)
CoTaskMemFree
DestroyIcon
GetWindowLong
GlobalAlloc
GlobalFree
GlobalSize
SHBrowseForFolder
SHGetFileInfo
SHGetPathFromIDList
SHGetSpecialFolderLocation
SendMessage
SetWindowLong
The Known Folders can be enumerated through call to GetFolderIds method of a class that implements IKnownFolderManager interface.