Special folder paths in configuration files

Windows specific forum
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Special folder paths in configuration files

Post by tinman »

Hi,

I've got a configuration file for an application that needs to store a path. I can store a fixed path easily enough, such as "C:\foo\bar". However, I'd like to make it able to handle special paths. Easy enough for some things, as I can include a call to ExpandEnvironmentStrings_() so my paths can be written as "%systemdrive%\foo\bar".

However, the only user relative special folder path that seems to be exposed is %USERPROFILE% or %ALLUSERSPROFILE%. Ideally I'd like to be able to specify anything that changes with the OS or language (e.g. the desktop folder isn't always "%USERPROFILE%\Desktop" - or is it?), but there doesn't seem to be a standard way to do it. I don't want to have to add environment variables to the system, and I don't particularly want to have my own special environment variables that I parse first.

It also needs to look like a standard path if possible, something that you'd type on the command line.

Has anyone come across such a thing or am I going to have to go down the custom path string route?

Thanks.
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
User avatar
idle
Always Here
Always Here
Posts: 6048
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Special folder paths in configuration files

Post by idle »

Is this what your looking for? I'm not really sure what your asking.

Code: Select all

#CSIDL_DESKTOP = $0                 ;{desktop}
#CSIDL_INTERNET = $1                ;Internet Explorer (icon on desktop)
#CSIDL_PROGRAMS = $2                ;Start Menu\Programs
#CSIDL_CONTROLS = $3                ;My Computer\Control Panel
#CSIDL_PRINTERS = $4                ;My Computer\Printers
#CSIDL_PERSONAL = $5                ;My Documents
#CSIDL_FAVORITES = $6               ;{user}\Favourites
#CSIDL_STARTUP = $7                 ;Start Menu\Programs\Startup
#CSIDL_RECENT = $8                  ;{user}\Recent
#CSIDL_SENDTO = $9                  ;{user}\SendTo
#CSIDL_BITBUCKET = $A               ;{desktop}\Recycle Bin
#CSIDL_STARTMENU = $B               ;{user}\Start Menu
#CSIDL_DESKTOPDIRECTORY = $10       ;{user}\Desktop
#CSIDL_DRIVES = $11                 ;My Computer
#CSIDL_NETWORK = $12                ;Network Neighbourhood
#CSIDL_NETHOOD = $13                ;{user}\nethood
#CSIDL_FONTS = $14                  ;windows\fonts
#CSIDL_TEMPLATES = $15
#CSIDL_COMMON_STARTMENU = $16       ;All Users\Start Menu
#CSIDL_COMMON_PROGRAMS = $17        ;All Users\Programs
#CSIDL_COMMON_STARTUP = $18         ;All Users\Startup
#CSIDL_COMMON_DESKTOPDIRECTORY = $19;All Users\Desktop
#CSIDL_APPDATA = $1A                ;{user}\Application Data
#CSIDL_PRINTHOOD = $1B              ;{user}\PrintHood
#CSIDL_LOCAL_APPDATA = $1C          ;{user}\Local Settings\Application Data (non roaming)
#CSIDL_ALTSTARTUP = $1D             ;non localized startup
#CSIDL_COMMON_ALTSTARTUP = $1E      ;non localized common startup
#CSIDL_COMMON_FAVORITES = $1F
#CSIDL_INTERNET_CACHE = $20
#CSIDL_COOKIES = $21
#CSIDL_HISTORY = $22
#CSIDL_COMMON_APPDATA = $23          ;All Users\Application Data
#CSIDL_WINDOWS = $24                 ;GetWindowsDirectory()
#CSIDL_SYSTEM = $25                  ;GetSystemDirectory()
#CSIDL_PROGRAM_FILES = $26           ;C:\Program Files
#CSIDL_MYPICTURES = $27              ;C:\Program Files\My Pictures
#CSIDL_PROFILE = $28                 ;USERPROFILE
#CSIDL_SYSTEMX86 = $29               ;x86 system directory on RISC
#CSIDL_PROGRAM_FILESX86 = $2A        ;x86 C:\Program Files on RISC
#CSIDL_PROGRAM_FILES_COMMON = $2B    ;C:\Program Files\Common
#CSIDL_PROGRAM_FILES_COMMONX86 = $2C ;x86 Program Files\Common on RISC
#CSIDL_COMMON_TEMPLATES = $2D        ;All Users\Templates
#CSIDL_COMMON_DOCUMENTS = $2E        ;All Users\Documents
#CSIDL_COMMON_ADMINTOOLS = $2F       ;All Users\Start Menu\Programs\Administrative Tools
#CSIDL_ADMINTOOLS = $30              ;{user}\Start Menu\Programs\Administrative Tools
#CSIDL_FLAG_CREATE = $8000          ;combine with CSIDL_ value to force 
                                                  ;create on SHGetSpecialFolderLocation()
#CSIDL_FLAG_DONT_VERIFY = $4000      ;combine with CSIDL_ value to force 
                                                  ;create on SHGetSpecialFolderLocation()
#CSIDL_FLAG_MASK = $FF00             ;mask for all possible flag values
#SHGFP_TYPE_CURRENT = $0             ;current value for user, verify it exists
#SHGFP_TYPE_DEFAULT = $1


Procedure.s GetSpecialFolderLocation(Value.l)
  Protected Folder_ID,SpecialFolderLocation.s
  If SHGetSpecialFolderLocation_(0, Value, @Folder_ID) = 0
    SpecialFolderLocation = Space(#MAX_PATH)
    SHGetPathFromIDList_(Folder_ID, @SpecialFolderLocation)
    If SpecialFolderLocation
      If Right(SpecialFolderLocation, 1) <> "\"
        SpecialFolderLocation + "\"
      EndIf
    EndIf
   CoTaskMemFree_(Folder_ID)   
 EndIf

ProcedureReturn SpecialFolderLocation.s
EndProcedure


Debug GetSpecialFolderLocation(#CSIDL_COMMON_DESKTOPDIRECTORY)
Debug GetSpecialFolderLocation(#CSIDL_APPDATA)


Last edited by idle on Fri Oct 30, 2009 10:59 pm, edited 2 times in total.
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Re: Special folder paths in configuration files

Post by tinman »

Hi,

Thanks, I know about using the API to get the paths. What I was looking for was some way to represent the CSIDL's in a configuration file without having to come up with some unique way. I was hoping there was some standard way to represent those special paths outside of a piece of running code (in this case, as text in a configuration file).

For example, if the path was meant to represent the root of the user profile then I easily could do something like this:

Code: Select all

[MyIniSection]
StorageDir = %USERPROFILE%
And then when I read the string back in I can call ExpandEnvironmentStrings_() to get the full path. However, if I want to represent the user's desktop directory I can either do one of the following:

Code: Select all

[MyIniSection]
StorageDir = %USERPROFILE%\Desktop ; Note 1
StorageDir = [DESKTOPDIRECTORY] ; Note 2.
Note 1: This is not guaranteed to be correct since the text "Desktop" may not be the same on all versions of Windows.

Note 2: In this case I must do my own processing to recognise the token [DESKTOPDIRECTORY], convert it to #CSIDL_DESKTOPDIRECTORY and call SHGetSpecialFolderPath. I would have like to avoid this, but it seems like it is the way I will go.

Edit: PS, in the code you posted there looks like there might be a memory leak. It calls SHGetSpecialFolderLocation_(), but never frees the IDList.
The MSDN docs wrote:ppidl
[out] A pointer to an item identifier list (PIDL) specifying the folder's location relative to the root of the namespace (the desktop). The calling application is responsible for freeing this pointer with the Shell's IMalloc interface (see SHGetMalloc).
I think it would be easier to just call SHGetSpecialFolderPath_() directly, rather than SHGetSpecialFolderLocation_() then SHGetPathFromIDList_()?
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
User avatar
idle
Always Here
Always Here
Posts: 6048
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Special folder paths in configuration files

Post by idle »

Note 2: In this case I must do my own processing to recognise the token [DESKTOPDIRECTORY], convert it to #CSIDL_DESKTOPDIRECTORY and call SHGetSpecialFolderPath. I would have like to avoid this, but it seems like it is the way I will go.

Edit: PS, in the code you posted there looks like there might be a memory leak. It calls SHGetSpecialFolderLocation_(), but never frees the IDList.
Yes I think that would be the way to go, just use the values of the CSIDL as tokens.
I don't think there are many options since the directory names are language dependent

I and added, CoTaskMemFree_(Folder_ID) not sure if that will fix the leak though.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Special folder paths in configuration files

Post by IdeasVacuum »

The GetSpecialFolderLocation() Procedure works fine, but since Vista KNOWNFOLDERID was introduced instead - and Windows 8 only supports KNOWNFOLDERID whereas Vista/Win7 were backwards compatible with CSIDL.

MSDN has a lot to say about it but is lacking in examples
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

So, how can we use KNOWNFOLDERID in PB?

Edit: GJ-68 has solved it: http://www.purebasic.fr/english/viewtop ... =5&t=55173
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Post Reply