Vista Game Data Locations - What a Mess!

Discussion in 'Game Development (Technical)' started by Midnight Synergy, Jan 26, 2008.

  1. HappyCat

    Original Member

    Joined:
    Jun 28, 2005
    Messages:
    54
    Likes Received:
    0
    Eek! See below.
     
    #21 HappyCat, Jan 28, 2008
    Last edited: Jan 28, 2008
  2. HappyCat

    Original Member

    Joined:
    Jun 28, 2005
    Messages:
    54
    Likes Received:
    0
    Okay, here you go ...

    First you need the following two .decls file in your "Blitz3D\Userlibs" folder (if you don't already have them):

    One called Kernel32.decls which contains at least:

    .lib "kernel32.dll"
    api_GetVersionEx%(lpVersionInformation*):"GetVersionExA"


    And one called Shell32.decls which contains at least:

    .lib "Shell32.dll"
    api_GetSpecialFolderLocation%(hwnd%,folder%,pidl*): "SHGetSpecialFolderLocation"
    api_GetPathFromIDList%(pidl%,pszPath*): "SHGetPathFromIDListA


    Then you need the following Blitz3D code:

    Const MAX_PATH = 260 ; Maximum path length

    Const CSIDL_PROGRAMS = 2 ; Program Groups Folder
    Const CSIDL_PERSONAL = 5 ; Personal Documents Folder
    Const CSIDL_FAVORITES = 6 ; Favorites Folder
    Const CSIDL_STARTUP = 7 ; Startup Group Folder
    Const CSIDL_RECENT = 8 ; Recently Used Documents Folder
    Const CSIDL_SENDTO = 9 ; Send To Folder
    Const CSIDL_STARTMENU = 11 ; Start Menu Folder
    Const CSIDL_DESKTOPDIRECTORY = 16 ; Desktop Folder
    Const CSIDL_NETHOOD = 19 ; Network Neighborhood Folder
    Const CSIDL_TEMPLATES = 21 ; Document Templates Folder
    Const CSIDL_COMMON_STARTMENU = 22 ; Common Start Menu Folder
    Const CSIDL_COMMON_PROGRAMS = 23 ; Common Program Groups Folder
    Const CSIDL_COMMON_STARTUP = 24 ; Common Startup Group Folder
    Const CSIDL_COMMON_DESKTOPDIRECTORY = 25 ; Common Desktop Folder
    Const CSIDL_APPDATA = 26 ; Application Data Folder
    Const CSIDL_PRINTHOOD = 27 ; Printers Folder
    Const CSIDL_COMMON_FAVORITES = 1 ; Common Favorites Folder
    Const CSIDL_INTERNET_CACHE = 32 ; Temporary Internet Files Folder
    Const CSIDL_COOKIES = 33 ; Cookies Folder
    Const CSIDL_HISTORY = 34 ; History Folder
    Const CSIDL_COMMON_APPDATA = 35 ; Common Application Data Folder

    Function GetSpecialFolderLocation$(FolderID)

    Local Temp = CreateBank(4)
    api_GetSpecialFolderLocation(0, FolderID, Temp)
    Local PIDL = PeekInt(Temp,0)
    FreeBank Temp

    If Not PIDL Then Return

    Temp = CreateBank(MAX_PATH)
    api_GetPathFromIDList(PIDL, Temp)
    Local Path$ = PeekStringValue(Temp)
    FreeBank Temp

    Return Trim(Path$) + "\"​

    End Function

    Function PeekStringValue$(Bank, Offset = 0)

    Local Result$ = ""

    For Index = Offset To BankSize(Bank) -1
    Result$ = Result$ + Chr (PeekByte(Bank, Index))​
    Next

    Return Result$​
    End Function

    Function IsWin2000OrLater()

    Local Result = False

    Local Temp = CreateBank(148)
    PokeInt(Temp, 0, 148)
    api_GetVersionEx(Temp)

    Local MajorVersion = PeekInt(Temp, 1 * 4)
    Local MinorVersion = PeekInt(Temp, 2 * 4)
    Local Build = PeekInt(Temp, 3 * 4)
    Local PlatformID = PeekInt(Temp, 4 * 4)

    FreeBank Temp

    Result = PlatformID = 2 And MajorVersion >= 5 ; NT platform and Win 2000 or later

    Return Result​
    End Function


    Then call GetSpecialFolderLocation() with the required CSIDL constant.

    The IsWin2000OrLater() function isn't required by GetSpecialFolderLocation() but I used it to determine exactly which path I would write to, something like this:

    If IsWin2000OrLater() Then
    ; Windows 2000, XP and Vista - put data in "C:\Documents and Settings\All Users\Application Data\Gun Wing\etc."
    RootFolder$ = GetSpecialFolderLocation(CSIDL_COMMON_APPDATA) + "Gun Wing\"​
    Else
    ; Windows 95, 98, Me and NT - put data under installation folder - ie "C:\Games\Gun Wing\User Data\etc."
    RootFolder$ = "User Data\"​
    End If


    I did this 'cos earlier versions of Windows don't have nice equivalents of "C:\Documents and Settings\All Users\Application Data\"
     
    #22 HappyCat, Jan 28, 2008
    Last edited: Jan 28, 2008
  3. Midnight Synergy

    Indie Author

    Joined:
    Jul 27, 2004
    Messages:
    275
    Likes Received:
    0
    HappyCat - Many many thanks for that, I'll be going through the code later today.

    Reading the data is not a problem - but many of my games (esp the editors) need to create data during runtime. Some data would be only for a local user (e.g. player profile, saved games, etc), other data should be accessible to all users, such as downloaded user-made content. So if I want to play it along the official rules, I should have two separate locations for my data.


    I know this take the thread somewhat off topic, since I really just want to explore the "proper" way to do things rather than debate its merits, BUT... ;)

    [Off Topic]
    this whole restriction idea does seem like a half-measure, at best. "Program Files" is the only folder protected like this. Why bother giving the user the option to change the install path, (e.g. to something like C:\Games, which is what I've been doing for twenty years) and then make any of those installations "insecure".

    I did check again on my Vista laptop - any user can indeed access and change files in e.g. C:\Wonderland, but access is not allowed in e.g. C:\Program Files\Wonderland. I also noted that some new installations install outside of Program Files - e.g. the BFG Gamedownloader puts the program and all its data into just C:\BFGClient on Vista. Interestingly, the same program gets installed on C:\Program Files\BFGClient on XP, which makes me quite certain that this was done precisely to circumvent these access restrictions. The thread's titular "mess" of every program dumping their stuff somewhere different doesn't seem worth the half-baked security you get out of thease measures.

    [On Topic]
    And now back to your regularly scheduled post.

    Just to consider possible further options, does anyone know where games like The Great Tree or Madame Fate put their user data? I just can't track down any player profile or save game files for them?
     
  4. Grey Alien

    Indie Author

    Joined:
    Nov 29, 2005
    Messages:
    2,797
    Likes Received:
    0
    I used all that BMax code in my latest game, Fairway Solitaire, which stores the data in a subfolder of Program Data on Vista (and makes the sub folder readable by all users so that families can play with their profile no matter who originally logged onto the PC). This is the most flexible solution for players imho. Future games will be using the same system. It works in XP too, but users the Docs and Settings/All Users folder instead.
     
  5. Midnight Synergy

    Indie Author

    Joined:
    Jul 27, 2004
    Messages:
    275
    Likes Received:
    0
    I know what you mean, save game files etc are usually kept with a user profile anyhow. I guess the only reason I can see not keeping everything in an all access folder is that "junior" could log into his account and mess up Mom's savegames by selecting her profile. I'm not sure if that's worth the bother of keeping two directory structures, though.


    I've been doing some more reading and trying out different CSIDL values on XP and Vista. I summarized everything (also from above discussion points that others contributed) to help myself make a final decision. I'm not quite there yet, but I thought I'd post my summary so far, in case it's of use to others.



    “Officially” Recomended Locations for Game Data Locations, with CSIDL values and Environment Variables (if available)


    1. Folders given by CSIDL_APPDATA and Variants

    CSIDL_APPDATA ($1A or 26) or EV: APPDATA
    XP: C:\Documents and Settings\<user>\Application Data
    Vista: C:\Users\<user>\AppData\Roaming
    95/98/Me: Unknown

    CSIDL_LOCAL_APPDATA ($1C or 28)
    XP: C:\Documents and Settings\<user>\Local Settings\Application Data
    Vista: C:\Users\<user>\AppData\Local
    95/98/Me: Unknown

    CSIDL_COMMON_APPDATA ($23 or 35)
    XP: C:\Documents and Settings\All Users\Application Data
    Vista: C:\ProgramData
    95/98/Me: Unknown

    Notes:
    i. COMMON_APPDATA requires that you programmatically change read/write security permissions, otherwise other uses may read the data but not write to it.
    See this post for a solution in BlitzMax (contains C++ code):
    http://www.blitzbasic.co.nz/Community/posts.php?topic=73305

    ii. All of the above three are hidden folders by default. This is fine for most game data (temporary files, user profiles, save games) since game players shouldn’t need access to these files. If you need game users to access files (e.g. levels from a level editor to e-mail to friends) then these locations might not be ideal for casual users, given that they are in hidden directories.

    2. Create a MyApp directory in the users (or allusers) profile directory

    CSIDL_PROFILE ($29 or 40) or EV: USERPROFILE
    XP: C:\Documents and Settings\<user>
    Vista: C:\Users\<user>
    95/98/Me: Unknown

    EV: ALLUSERSPROFILE (There is no CSDIL value for this location.)
    XP: C:\Documents and Settings\All Users in XP,
    Vista: C:\PROGRAMDATA
    95/98/Me: Unknown
    Notes:
    i) In vista, this doesn’t point to C:\Users\All Users, as I thought it would/should (?). I have not found a way to get to C:\Users\All Users yet.

    3. Save Games folder in Vista.

    I can’t find a game that uses this, nor can I find a way to point to this directory reliably. I don’t think I’ll be bothering with this solution. :)


    Some outstanding questions (for me at least):
    1. How do you reliably point to C:\Users\All Users in Vista?
    2. Where do the above point in 95/98/Me? (although I might just keep game data in the game directory for those OS)
    3. Adopt the BlitzMax code by Grey Aliens, Gfx, et al, to Blitz3D
    4. Finally, what is the practical difference between CSIDL_APPDATA and CSIDL_LOCAL_APPDATA. Both seem local to the user, why have one in a further subdirectory?
     
  6. ChrisP

    Indie Author

    Joined:
    Feb 5, 2007
    Messages:
    971
    Likes Received:
    0
    It's perhaps worth noting that any/all of these paths could be localised; so don't be tempted to hardcode anything based on OS detection. :)

    My memory is very fuzzy and I don't have any ancient boxes around to check, but I think it's usually something like C:\WINDOWS\Profiles\[username]\[something here?]. Or it might be Users instead of Profiles, not sure; it's been a while! It's also an All Users or equivalent folder sometimes; Windows 9x didn't necessarily have "users" as such, depending on settings.

    Windows NT is similar, in that the profile folders are somewhere under C:\WINNT.

    I'm not certain, but I think the "roaming" app data is intended to move with the user around a network. For example, if the user is logged into an Active Directory, the roaming data might move around with them between computers. OTOH I work in a place that uses AD and I've never visibly seen this happen, so who knows!
     
  7. vjvj

    Indie Author

    Joined:
    Sep 25, 2004
    Messages:
    1,732
    Likes Received:
    0
    The MS article I linked to above states that you should use the same CSIDL interface in 95/98/ME. If anyone has a 95/98/ME machine handy, it'd be easy to add the code and step through it with the debugger to catch the directory that SHGetFolderPath() returns.

    On another note, one might actually find it more useful to use SHGetFolderPathSubDir() with CSIDL_FLAG_CREATE, which allows you to specify your desired subdirectory (e.g. \<company name>\<app name>\) and create it if it doesn't exist, all in one call.
     
  8. TMK

    TMK
    Indie Author

    Joined:
    Aug 7, 2006
    Messages:
    92
    Likes Received:
    0
    I believe both "C:\Users\All Users\" and "C:\ProgramData\" are the same locations. If you place one folder in either one of them, it appears in the other folder as well. I'm not sure which is virtualized and which is the "real" folder though.

    However "C:\Users\All Users\" shows a "shortcut" icon on it in Windows Explorer, while the "C:\ProgramData\" doesn't have that, and Vista usually shows such shortcut icons on virtualized folders from what I've seen.
     
  9. stanchat

    Indie Author

    Joined:
    Aug 30, 2004
    Messages:
    376
    Likes Received:
    1
    I am using Torque Game Builder 1.6 and here is their design for handling Vista App Data Locations. I tested this in both Vista and XP and it works.


    This is how the commonConfig.xml file looks:
     
  10. Bad Sector

    Original Member

    Joined:
    May 28, 2005
    Messages:
    2,742
    Likes Received:
    5
    Open a command prompt and type dir /p in C:\. If ProgramData says "LINK" (or something else than DIRECTORY or FOLDER) besides it, it is the virtualised one.


    Btw, these things are called "symbolic links", not virtualized folders :). Microsoft use this wording too (check the mklink command).
     
  11. TMK

    TMK
    Indie Author

    Joined:
    Aug 7, 2006
    Messages:
    92
    Likes Received:
    0
    Thanks!

    "All Users" folder is marked as SYMLINKD, while others such as "Default User", "Documents and Settings", "Application Data" folder within a User etc. are all marked as JUNCTION. All of them also shows the path they link to next to it.

    "ProgramData" has DIR next to it, so seems thats the correct one :)
     
  12. Bad Sector

    Original Member

    Joined:
    May 28, 2005
    Messages:
    2,742
    Likes Received:
    5
    I think JUNCTIONs are hard links :)
     
  13. Midnight Synergy

    Indie Author

    Joined:
    Jul 27, 2004
    Messages:
    275
    Likes Received:
    0
    As an addendum to the story:

    I've decided to go the same route as Jake/Grey Alien, i.e. use CSIDL_COMMON_APPDATA for all game data (including user profiles and save games - that way a user can play with their own profile from any login).

    My only problem is finding a way to convert Jake's C++ code to be run from Blitz3D (which is what I use for my current projects) - I'm no use at these system type routines, but I'd be happy to pay for someone to convert this into something that can be run from Blitz3D.

    Specifically, I need the B3d equivalent of this C++ code (or a way to run this from Blitz3D the way Jake runs it from BlitzMax):

    Code:
    #include <windows.h>
    #include <aclapi.h>
    
    extern "C" bool GiveDirectoryUserFullAccess(LPCTSTR lpPath)
    {	
    	HANDLE hDir = CreateFile(lpPath,READ_CONTROL|WRITE_DAC,0,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
    	if(hDir == INVALID_HANDLE_VALUE) return false;
    	
    	ACL* pOldDACL=NULL;
    	SECURITY_DESCRIPTOR* pSD = NULL;
    	GetSecurityInfo(hDir,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,&pOldDACL,NULL,&pSD);
    	
    	EXPLICIT_ACCESS ea={0};
    	ea.grfAccessMode = GRANT_ACCESS;
    	ea.grfAccessPermissions = GENERIC_ALL;
    	ea.grfInheritance = CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE;
    	ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    	ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    	ea.Trustee.ptstrName = TEXT("Users");
    	
    	ACL* pNewDACL = NULL;
    	SetEntriesInAcl(1,&ea,pOldDACL,&pNewDACL);
    	
    	SetSecurityInfo(hDir,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDACL,NULL);
    	
    	LocalFree(pSD);
    	LocalFree(pNewDACL);
    	CloseHandle(hDir);
    	return true;
    }
    
    The code is designed to set a directory to "full access", which is required for other users to write/modify files originally created on a different user profile.

    It's hopefully not a big deal, but if someone can do this (better than me ;)) I'd be happy to paypal you $25 for pizza/beer/game money as a token of appreciation. I would also post the resulting code in this thread for anyone else in the community working in Blitz3D to be able to use it for free.

    (and yes, I did check with Jake if it's ok with him to adapt his code this way)

    I you can do this, let me know (either by PM or e-mail to midnight@midnightsynergy.com). (I'll post here first and wait for responses before posting on the Blitz3D forum, since I started this discussion on Indiegamer).

    Cheers,
    Patrick
     
  14. Midnight Synergy

    Indie Author

    Joined:
    Jul 27, 2004
    Messages:
    275
    Likes Received:
    0
    And a final (? - :)) post in this series. I did find someone to code a Write Access function for me in Blitz3D. As promised, I'm sharing the results with anyone else who needs it - so if you want to tackle this problem in Blitz3d, feel free to use this code:

    http://blitzbasic.co.nz/Community/posts.php?topic=76077

    (code is linked a few posts in)

    Cheers!
     
  15. Desktop Gaming

    Moderator Original Member Indie Author

    Joined:
    Feb 24, 2005
    Messages:
    2,296
    Likes Received:
    12
    Nice - would be more useful/handy/bettererer if it was in the code archives though.

    :)
     
  16. Grey Alien

    Indie Author

    Joined:
    Nov 29, 2005
    Messages:
    2,797
    Likes Received:
    0
    Hey glad you got a result, nice one!

    I found this to be the case. I had to get end users AND testers to find those folders (and make them visible via tools options (in XP, but I don't know how in Vista!)) in order to edit the ini file which is a bit of a pain. My old games used to have the ini file in the game install folder which was "incorrect" but SO much easier. You can also run into problems if more than one portal distributes your games and you have different ini settings for different portals and a user tries demos form two portals. When data was stored in the game folder it was not an issue as the ini got overwrote but with it in this "correct" location, it won't be overwritten by an installer, only by your app, except that my games say "don't overwrite the ini if it's already there" Gah! In the end I've decide to FORCE certain ini settings in different exe builds for different portals. Hmm, I wonder if all that makes sense, it's a bit garbled, sorry.
     
  17. Nikos Beck

    Nikos Beck New Member

    Joined:
    Jun 14, 2007
    Messages:
    321
    Likes Received:
    0
    Could you not have added a shortcut to the data folder from the install directory? Make it a little easier to find the ini file?
     
  18. Grey Alien

    Indie Author

    Joined:
    Nov 29, 2005
    Messages:
    2,797
    Likes Received:
    0
    Good idea but, no because you aren't supposed to write to that folder in Vista (it will get virtualised) and you don't know the destination dynamic data folder until the exe has run on the target machine, so you can't include a link with the installation. :-(
     

Share This Page

  • About Indie Gamer

    When the original Dexterity Forums closed in 2004, Indie Gamer was born and a diverse community has grown out of a passion for creating great games. Here you will find over 10 years of in-depth discussion on game design, the business of game development, and marketing/sales. Indie Gamer also provides a friendly place to meet up with other Developers, Artists, Composers and Writers.
  • Buy us a beer!

    Indie Gamer is delicately held together by a single poor bastard who thankfully gets help from various community volunteers. If you frequent this site or have found value in something you've learned here, help keep the site running by donating a few dollars (for beer of course)!

    Sure, I'll Buy You a Beer