A way to detect if an OS has the C:/user/appdata/

Community Forums/General Help/A way to detect if an OS has the C:/user/appdata/

Blitzplotter(Posted 2013) [#1]
Just wondering recent thoughts on games writing save files before I go and try to re-invent the wheel. Don't think W7 likes you writing to the C:/Program Files/Application/ directory ordinarily. Any thoughts greatly appreciated.


Yasha(Posted 2013) [#2]
This is what the %APPDATA% environment variable is for. You should ideally avoid assuming things like the existence of C: or that the path will even be the same on two installations of the same OS version.


xlsior(Posted 2013) [#3]
You should never use hard-coded paths like that, or you'll be bit big time in many situations (32/64 bit systems, non-English windows installs, etc.)

Bruceh has a blitzmax module, bah.volumes, which will return a lot of the 'correct' paths for windows/linux/mac, such as the users home directory, application folder, desktop, etc.

But never hard code -- even if you try to deduce the most likely location, it's bound to fail spectacularly next time that MS changes their rules again and your program may grind to a halt under windows 9 / 10 / whatever.
Use the MS API's (or a wrapper) to query the OS for the proper paths to write to.


GfK(Posted 2013) [#4]
Bruceh has a blitzmax module, bah.volumes
I almost said the same, but I'm pretty sure he uses Blitz3D still...


Blitzplotter(Posted 2013) [#5]
Thanks for the feedback folks, I've got a job again which has somewhat diminished my coding mojo.

B3D was my 2nd BRL love (BBasic 2.1 was the first!), I developed a little program sanctioned by BECTA (think they're defunct now) in BMAX, so I might shoe horn a little Brucey moddule into my suite (oh alright, theres only 2 executables so far, but they're sweet if I say so myself) executables.

Although, in the leary morning light the %APPDATA variable seems ever so much the easier option.

Have been digging around trying to find how to use APPDATA with systemproperty in B3D, however the closest I could find was : http://www.blitzbasic.com/Community/posts.php?topic=100256#1182262 Might resort to Brucey's bah.volumes

Although, this looks promising:

http://www.blitzbasic.com/Community/posts.php?topic=100344#1184042

Hell, yes - that's some pretty sweet code by Rob - bit of water under the bridge since he penned that though 2001 !


Cheers folks ;)


virtlands(Posted 2013) [#6]
Rob Hutchinson and Joseph Cox created that nice BlitSys package [back in 2001]

You're probably searching for Episode 7 : (Get special directory info).


----------------------------------------------------------------
You can also get related info using the SET command, information similar to THIS! (I use Windows 7):

APPDATA=C:\Users\##########\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=##########-PC
ComSpec=C:\Windows\system32\cmd.exe
HOME=C:\Users\##########
HOMEDRIVE=C:
HOMEPATH=\Users\##########
LOCALAPPDATA=C:\Users\##########\AppData\Local
LOGONSERVER=\\##########-PC
NUMBER_OF_PROCESSORS=16
OS=Windows_NT
Path=C:\programming\PellesC\Bin; ...................
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CH;.py;.pyw
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 15 Stepping 6, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0f06
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
PROMPT=$P$G
PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\##########\AppData\Local\Temp
TMP=C:\Users\##########\AppData\Local\Temp
USERDOMAIN=##########-PC
USERNAME=##########
USERPROFILE=C:\Users\##########
windir=C:\Windows



xlsior(Posted 2013) [#7]
Oh, something else to consider, another reason why it's bad to hard-code the paths: the OS doesn't necessarily have to be installed on the C:\ drive either

(I've come across several machines in the real world where the OS is either on D:\ or M:\ no idea WHY anyone would do that, but they are out there...)


Blitzplotter(Posted 2013) [#8]
Thanks for the feedback, also found this interesting article about 'where to stick it':--

http://vb.mvps.org/articles/vsm20090119.pdf


John G(Posted 2013) [#9]
I used Brucey's BaH.Volumes and it seemed to work fine with Win XP, Vista and Win 7. Couldn't get it to work for Macs and bypassed it. Now I may be having trouble with Mac Preference Files. Has anyone used it successfully with say OSX 10.5 thru 10.8.5?


John G(Posted 2013) [#10]
Apologies: Brucey's BaH.Volumes seems to work just fine with Macs -- at least the ones available here. How could I question our Brucey??? Carry on.


Kryzon(Posted 2013) [#11]
I would create a userlib for this: http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx

.lib "shell32.dll"

SHGetFolderPath% ( hwndOwner%, nFolder%, hToken%, dwFlags%, pszPath* ) : "SHGetFolderPathA"
Const MAX_PATH = 260
Const CSIDL_APPDATA = 26 ;Taken from Shlobj.h
Const SHGFP_TYPE_CURRENT = 0
Const SHGFP_TYPE_DEFAULT = 1

pathBank = CreateBank( MAX_PATH )

SHGetFolderPath( 0, CSIDL_APPDATA, 0, SHGFP_TYPE_DEFAULT, pathBank )

temp$ = ""
For x = 0 To MAX_PATH-1
	temp = temp + Chr( PeekByte( pathBank, x ) )
Next

Print temp
WaitKey()
End
It has been deprecated on versions of Windows above XP, but it is implemented in them anyway for backwards compatibility.


Grey Alien(Posted 2015) [#12]
Small bit of advice, if you are getting something like the MyDocuments folder (CSIDL_PERSONAL), you should use SHGFP_TYPE_CURRENT not SHGFP_TYPE_DEFAULT because it's possible to move the MyDocuments folder and you don't want to get the original location, you want the new (current) one.


Grey Alien(Posted 2015) [#13]
Also, I'm a bit of a noob at making userlibs, do you know how to convert the top bit of code so that it can simply be included in a normal .bmx file? For example I do this for some other api calls:

?win32
Extern "win32"
	Function CloseLibrary(hLib%) = "FreeLibrary@4"
	Function GetEnvironmentVariable(lpName$z, lpBuffer:Byte Ptr, nSize%) = "GetEnvironmentVariableA@12"
	Function GetVersionExA(infoex:Byte Ptr)
	Function RegOpenKey%(hKeyParent%,SubKey$z,phkResult:Byte Ptr)="RegOpenKeyA@12"
	Function RegCloseKey%(hKey%)="RegCloseKey@4"
	Function RegQueryValueEx%(hKey%,ValueName$z,Reserved%,nType:Byte Ptr,ValueBytes:Byte Ptr,ValueSize:Byte Ptr)="RegQueryValueExA@24"
	Function SHGetPathFromIDList(pidList%, lpBuffer:Byte Ptr)
	Function SHGetSpecialFolderLocation(hwndOwner%, nFolder%, pIdl:Byte Ptr)
End Extern
?

Thanks.


Kryzon(Posted 2015) [#14]
Hello. The Win32 module ( pub.mod\win32.mod\ ) has some of the functions wrapped, so they're a nice reference. The module didn't wrap that function though.

With BlitzMax the declaration would be like this:




Kryzon(Posted 2015) [#15]
And this is the sanitised function to support unicode or ANSI (it can avoid unexpected errors):




Grey Alien(Posted 2015) [#16]
Wow awesome thanks! The Widechar (Unicode) version will definitely avoid errors because on some users' systems they have non-ASCII chars in their user names (and thus special folder paths) e.g. Japanese or Russian characters.

On my system _bbusew is true. I'm assuming that's because Mark made BlitzMax support Unicode a number of years ago, so anyone running the latest (unmodified) version will get true for that value right?

I'm then using BMax functions like CreateDir() with the path returned from SHGetFolderPathW() and I'm hoping it's compatible because all the file handling stuff in BlitzMax is Unicode right?


Kryzon(Posted 2015) [#17]
The result is converted to a standard BlitzMax string, so even though it may come from Unicode, once you obtain that string you can use it with any BlitzMax function \ operation.


Grey Alien(Posted 2015) [#18]
Great, thanks for the confirmation. I'm pretty sure I read years ago that BlitzMax Strings are now Unicode anyway. Oh yeah, from the docs "String is a BlitzMax container type containing a sequence of unicode characters." I guess I was more concerned about if all the file handling stuff was Unicode or not.


Grey Alien(Posted 2015) [#19]
OK just tested this with a profile with a unicode char in it (ł) and I was able to read the MyDocuments folder with and then create a subfolder it in correctly.

In a contrast, some of my old code doesn't work with that user name because it's probably using this Windows function in ANSI mode instead of widechar mode (probably because I didn't specify the W version)

Function SHGetPathFromIDList(pidList%, lpBuffer:Byte Ptr)

So just a heads up, to people to be careful, especially if you are making a commercial game.


Grey Alien(Posted 2015) [#20]
I wanted to confirm that Kryzon's SHGetFolderPathW code works great on XP Home (32-bit), Win 7 Pro (64-bit), Windows 8.1 (32-bit). I tested it with CSIDL_APPDATA and CSIDL_PERSONAL (using the SHGFP_TYPE_CURRENT flag).


Brucey(Posted 2015) [#21]
Of course you do know that SHGetFolderPath doesn't always work as expected on the new OS's, and you should really be using SHGetKnownFolderPath instead, if it is available.


Grey Alien(Posted 2015) [#22]
Yeah I know that SHGetFolderPath says it's "depreciated" on MS site but I know some pretty big games that still use it that have sold a huge amount recently. In what way doesn't it always work as expected? I'm keen to know.

Anyway, before I was using SHGetSpecialFolderLocation, which is totally unsupported, so SHGetFolderPath is a bit better.

The reason I didn't use SHGetKnownFolderPath is that it's Vista+ only, so I'd need to test if OS is XP and use SHGetFolderPath instead. Not too hard I know. How would you test if it's available?


BlitzSupport(Posted 2015) [#23]
One way to check would be like this:




grable(Posted 2015) [#24]
I dont understand why noone uses the environment variables meant for this instead of faffing around with all these different apis.
And for those who think they are unreliable, they are infact circular.
Changing the relevant environment variables will also change the results returned from these different apis.

I use this fact to fool applications into running off usb drives with their own copy of PROGRAMDATA, USERPROFILE, APPDATA etc, never touching the system.


Grey Alien(Posted 2015) [#25]
That's a good point grable. I guess it never occurred to me to use those. Is there ever a case when they are not defined on a system? Or perhaps they are not all available on XP for example?

@BlitzSupport Aha thanks for that. So I could use that and if it fails (function not found), use Kryzon's code above.


Blitzplotter(Posted 2015) [#26]
Or perhaps they are not all available on XP for example?


I'd a right headache developing a front end on XP using environment variables and then trying to use that front end on W7 - it was an interesting (there is other words..) learning exercise.

Gog.com just access right on the System Drive for some stuff - I found this kinda stuff works well: (not sanitized...)