PureBasic Survival Guide XVI - Application Data 
PureBasic Survival Guide
a tutorial for using purebasic for windows 4.51

Part 0 - TOC
Part I - General
Part II - Converts
Part III - Primer I
Part IV - Primer II
Part V - Advanced
Part VI - 2D Graphics I
Part VII - 2D Graphics II
Part X - Assembly
Part XI - Debugger
Part XII - VirtualBox
Part XIII - Databases
Part XIV - Networking
Part XV - Regular Expressions
Part XVI - Application Data
Part XVII - DPI
Part XXVII - Irregular Expressions
Part XXIX - Projects
 

Part XVI - Application Data
v0.04 11.04.2011

16.1 Not all Windows are created equal...
16.2 Links.
16.3 Soft Paths.
16.4 Windows.
16.5 Program Files.
16.6 Program Files / Common Files.
16.7 Application Data.
16.8 Local Application Data.
16.9 My Documents.
16.10 Registry.
 

This page is under construction.
 

16.1 Not all Windows are created equal...
 

These pages do not discuss Linux, but don't worry! Things are confusing enough when dealing with Windows alone :-) This page deals with installation and configuration of your application, and properly storing user data and program data.

Over time, MicroSoft has suggested different 'preferred practices'. I've been looking in the SDK, but couldn't find an easy reference, so this is what I could figure out.
 

Try!

Where are your special folders located? Try the code below to find out.

; survival guide 4_16_100 special folders
; pb 4.51b1 
;
; show all special folders and paths
;
EnableExplicit
;
Global width.i = 700
Global height.i = 500
Global event.i
Global x_retval_string.s
Global x_retval.i

Procedure.s x_getspecialfolderlocation(type.i) 
  Protected folderid.i
  ;
  ; *** retrieve a special folder name
  ;
  ; in:      type.i
  ; retval:  .s                - string containing the path
  ; out:     x_retval_string.s - as retval
  ;          x_retval.i        - 0 aka #TRUE if successful
  ;
  ; first retrieve a pointer to the itemidlist structure of a 'special folder'
  ; followed by retrieving the path from that imtemidlist structure
  ;
  x_retval = SHGetSpecialFolderLocation_(0,type,@folderid)
  If x_retval = 0
    x_retval_string = Space(#MAX_PATH)
    If SHGetPathFromIDList_(folderid,@x_retval_string) = 0
      x_retval = 1
    ElseIf Right(x_retval_string,1) <> "\"
      x_retval_string = x_retval_string+"\"
    EndIf
    ;
    ; free the itemidlist
    ;
    CoTaskMemFree_(folderid)
  EndIf
  If x_retval <> 0
    x_retval_string = ""
  EndIf
  ProcedureReturn x_retval_string 
EndProcedure

OpenWindow(1,10,10,width,height,"Special Folders",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ListIconGadget(1,2,2,width-2,height-2,"Item",200,#PB_ListIcon_GridLines)
AddGadgetColumn(1,1,"Value",800)
;
; which OS
;
If OSVersion() < #PB_OS_Windows_NT3_51
  AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" unknown older version")
Else
  Select OSVersion()
  Case #PB_OS_Windows_NT3_51
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows NT3")
  Case #PB_OS_Windows_95
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows 95")
  Case #PB_OS_Windows_NT_4
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows NT4")
  Case #PB_OS_Windows_98
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows 98")
  Case #PB_OS_Windows_ME
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows ME")
  Case #PB_OS_Windows_2000
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows 2000")
  Case #PB_OS_Windows_XP
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows XP")
  Case #PB_OS_Windows_Server_2003
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows Server 2003")
  Case #PB_OS_Windows_Vista
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows Vista")
  Case #PB_OS_Windows_Server_2008
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windoes Server 2008")
  Case #PB_OS_Windows_7
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" Windows 7")
  Case #PB_OS_Windows_Future
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" unknown version (too new)")
  Default
    AddGadgetItem(1,-1,"OSVersion()"+#LF$+Str(OSVersion())+" failed (should not happen)")
  EndSelect
EndIf
;
AddGadgetItem(1,-1,"")
AddGadgetItem(1,-1,"ProgramFilename()"+#LF$+ProgramFilename())
AddGadgetItem(1,-1,"GetCurrentDirectory()"+#LF$+GetCurrentDirectory())
AddGadgetItem(1,-1,"GetHomeDirectory()"+#LF$+GetHomeDirectory())
AddGadgetItem(1,-1,"GetTemporaryDirectory()"+#LF$+GetTemporaryDirectory())
;
AddGadgetItem(1,-1,"")
AddGadgetItem(1,-1,"SHGetSpecialFolderLocation_()")
AddGadgetItem(1,-1,"  #CSIDL_PERSONAL"+#LF$+x_getspecialfolderlocation(#CSIDL_PERSONAL))
AddGadgetItem(1,-1,"  #CSIDL_APPDATA"+#LF$+x_getspecialfolderlocation(#CSIDL_APPDATA))
AddGadgetItem(1,-1,"  #CSIDL_LOCAL_APPDATA"+#LF$+x_getspecialfolderlocation(#CSIDL_LOCAL_APPDATA))
AddGadgetItem(1,-1,"  #CSIDL_COMMON_APPDATA"+#LF$+x_getspecialfolderlocation(#CSIDL_COMMON_APPDATA))
AddGadgetItem(1,-1,"  #CSIDL_WINDOWS"+#LF$+x_getspecialfolderlocation(#CSIDL_WINDOWS))
AddGadgetItem(1,-1,"  #CSIDL_SYSTEM"+#LF$+x_getspecialfolderlocation(#CSIDL_SYSTEM))
AddGadgetItem(1,-1,"  #CSIDL_PROGRAM_FILES_COMMON"+#LF$+x_getspecialfolderlocation(#CSIDL_PROGRAM_FILES_COMMON))
AddGadgetItem(1,-1,"  #CSIDL_COMMON_DOCUMENTS"+#LF$+x_getspecialfolderlocation(#CSIDL_COMMON_DOCUMENTS))
AddGadgetItem(1,-1,"  #SHGFP_TYPE_CURRENT"+#LF$+x_getspecialfolderlocation(#SHGFP_TYPE_CURRENT))
AddGadgetItem(1,-1,"  #SHGFP_TYPE_DEFAULT"+#LF$+x_getspecialfolderlocation(#SHGFP_TYPE_DEFAULT))
;
AddGadgetItem(1,-1,"")
AddGadgetItem(1,-1,"GetEnvironmentVariable()")
AddGadgetItem(1,-1,"  USERPROFILE"+#LF$+GetEnvironmentVariable("USERPROFILE"))
AddGadgetItem(1,-1,"  APPDATA"+#LF$+GetEnvironmentVariable("APPDATA"))
AddGadgetItem(1,-1,"  HOMEPATH"+#LF$+GetEnvironmentVariable("HOMEPATH"))
AddGadgetItem(1,-1,"  TEMP"+#LF$+GetEnvironmentVariable("TEMP"))
AddGadgetItem(1,-1,"  TMP"+#LF$+GetEnvironmentVariable("TMP"))
AddGadgetItem(1,-1,"  CLIENTNAME"+#LF$+GetEnvironmentVariable("CLIENTNAME"))
AddGadgetItem(1,-1,"  SYSTEMDRIVE"+#LF$+GetEnvironmentVariable("SYSTEMDRIVE"))
AddGadgetItem(1,-1,"  SYSTEMROOT"+#LF$+GetEnvironmentVariable("SYSTEMROOT"))
AddGadgetItem(1,-1,"  ALLUSERSPROFILE"+#LF$+GetEnvironmentVariable("ALLUSERSPROFILE"))
AddGadgetItem(1,-1,"  PATHEXT"+#LF$+GetEnvironmentVariable("PATHEXT"))
;
Repeat
  event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow


16.2 Links.

Let me start by offering some links that might be of help...


16.3 Soft paths.

First the big one: you can NOT rely on 'hardcoded' paths! Users may have changed any of their settings, the locations of their preferred folders, the names of their preferred folders. Localized versions of Windows may have changed the names of specific folders (for example, the Dutch version of windows did away with 'Startup' and called it 'Opstarten'). And on top not all Windows versions may use the same folders in the future.

If you're looking for a specific path, do not assume it's going to be 'x:\y\z' but query Windows to find the proper path.

Warning: never hard-code a path!


16.4 Windows.

Stay away from C:\WINDOWS. There's nothing there of interest. Don't start copying in your DLL's in there. If there is code that you want to share over multiple applications, each with their own install, use the Program Files \ Common Files folder instead.


16.5 Program Files.

This is where your application should go. This is most oftenhandled by an installer, which allows the uneducated masses to install your great application. I've never seen this one localized (but hey, I wouldn't be suprised if even that would be possible :-))

Typically, you'll end up with something like:

C:\ Program Files \ <company> \ <product> \ ...
This folder will be created by your installer, at the moment of installation. Your application should not create or modify any files inside this folder, it should only read from it.

If you need a place to store changed data and / or user documents, then either your installer, or your application upon first run, must create those additional folders. If your application uses / creates data that is of no interest to, or should be somewhat shielded from the user, that data should go into Application Data. Documents created by the user using your application should go into My Documents.

A user with admin rights on Windows XP can do whatever he likes in the Program Files folder. Not so once you move up to Vista or Windows 7. The idea behind this is to provide additional protection to system integrity, as the Program Files folder, containing the executables, is no longer accessible (by external programs) it should be harder for malware to get through.

Non-standard installs.

What happens if you would install your software somewhere else? That would depend on the rights assigned to the different folders. On my own machine, I've created a folder called C:\software, and anything which does not try to install in the Program Files folder I'll redirect there. I've also put anything that comes as an archive in there. So, for example, my 'software' folder now contains:

C:\software
C:\software\utils
C:\software\batch
C:\software\icons
C:\software\autohotkey
C:\software\corel\...
C:\software\cputest
C:\software\osl2000
C:\software\spacemonger
C:\software\gspot
...
(As an aside, I've also created a C:\games folder, so I can exclude all games from my regular backup, even those games that try to install in the Program Files.)

Portable software.

Portable software typically comes as a complete package, and can be run from a memory stick etcetera. Often. the main folder would contain all executables, data, configuration files and more. Good portable software should not leave any trace on your system.

<< add more details on installers... perhaps :-) >>


16.6 Program Files \ Common Files.

If multiple seperate applications use the same libraries, and you want to make sure each of your applications gets the latest version, or that all your applications use the same version, you can install any files 'shared' between your applications in the Program Files \ Common Files.

There's no such thing as Application Data \ Common Files, so appearently anything installed under Common Files is not supposed to keep its own application data :-) You could always create something yourself, or use the registry.

On my machine, this folder resides here:

C:\ Program Files \ Common Files \ ...


Note to self: need to add more details, references, how to find etc.


16.7 Application Data.

If your application uses / creates data that is of no interest to, or should be somewhat shielded from the user, it should go into Application Data. Application Data can be set up to 'roam', so users on a network get the same settings (application data) whenever they move from one workstation to another. If you don't want that data to reside on the network and / or be shared by multiple workstations, you have to use the Local Application Data folders.

My machine shows something like this:

C:\ Documents and Settings \ <user> \ Application Data \ <company> \ <product> \ <version> \ ...
Note to self: add more details, CSIDL_APPDATA, etc.


16.8 Local Application Data.

Just like Application Data, yet any data in here cannot be redirected to the network.

Note to self: add more details, CSIDL_LOCAL_APPDATA, etc.


16.9 My Documents.

Any material created by the user should go into the My Documents folder. This folder may be stored on a network volume for roaming users. Typically paths will have the following structure:

C:\ Documents and Settings \ <user> \ My Documents \ ...
Note to self: add more details, CSIDL_MYDOCUMENTS etc.


16.10 Registry.

Note to self: add more details, limitations, references etc.