Reading/writing to files, cross-platform

BlitzMax Forums/BlitzMax Beginners Area/Reading/writing to files, cross-platform

I've read several reports that Vista doesn't allow programs to write to anywhere but My Documents (and please correct me if I'm wrong).

Given this, what would be best practices for a program that 1) will be creating/writing to/reading from multiple files (probably text files) during runtime and 2) you want to be cross-platform?

Will it require having the program check the OS and choose between a Vista-specific routine (that would only write to My Documents) and a general routine (for all other OS's)?

Thanks,
JJ

1&2. I guess detecting the os first would be the best practice, but it depends if the only difference in file creating/writing/reading is the location of the file. If it is, then you only need to change the location, since the file functions allready are cross-platform.

To detect OS, you can simply do:

?Win32
Print "This is win32"
?linux
Print "This is linux"
?MacOS
Print "This is mac os"
?


I'm not sure if you can do a;

?Vista
print "This is vista"
?


yet, but if you need to detect vista at this time, i guess a search at http://msdn.microsoft.com will give you an answer how to detect if the os is vista or not.

Update: I'm currently downloading vista, will let you know if

?Vista
print "This is vista"
?


works.

Given this, what would be best practices for a program that 1) will be creating/writing to/reading from multiple files (probably text files) during runtime and 2) you want to be cross-platform?
Actually Vista helps you out there. Now you can just write to every users "home" directory.

Thanks, Sub_Zero and FlameDuck.

So it looks like I can do something like

Global appDataPath$ = getenv_("HOMEDRIVE") + getenv_("HOMEPATH") + "\Application Data\appname"

to set the path for files the game will use in Windows (even if the user has the Documents and Settings directory on a drive other than C:). From what I've read, this should work in both XP and Vista, which would cover the case if BlitzMax doesn't do a ?Vista test.

I assume just writing streams out to the currentdir is fine in both Mac and Linux?

?vista
?

Does not work.

However, in Vista x86 (32-bit), the os detection in blitzmax is equal at win32. So I can confirm your method will work as expected.

Great, much thanks.

For cross-platformness, this thread might be of interest.
It mentions a cross-platform module that gives access to things like the Home and Document folders for the user, using APIs rather than environment variables...

:-)

Thanks, Brucey! I'll definitely check your volumes module out.

The volumes module is great =)

FlameDuck wrote:
Actually Vista helps you out there. Now you can just write to every users "home" directory.


Do you know of a better way than:
getenv_("USERPROFILE")+"\My Documents"
to do this? XP seems not to allow renaming "My Documents", but I recall doing it on one Win 95/98 system.

I found that Brucey's module works great in XP, but there was an issue with 98, so I'm investigating a solution that goes back that far. The above code works as long as "My Documents" hasn't been renamed, since getenv_("USERPROFILE") returns an empty string under 98.

EDIT: I just noticed JazzieB's comment in another thread: "I can't simply add /My Documents/ on the end as [...] it's not actually called that in a lot of countries."

So, any suggestions? Is there no environment variable in 98, XP, and Vista that points to a localized version of My Documents?

I now have Windows Vista and have been doing some testing, although I'm far from complete, but here are my observations so far...

It looks like a program can read and write files to its own folder, i.e. the folder it was installed to. At least I've tested my games from a standard/restricted account and they seem to be able to store high scores and config files in the program's own folder without any issues.

I intend to do some more thorough testing tomorrow (or within the next couple of days), to confirm if there's any differences between admin and standard accounts, both with UAC enabled and disabled. The only difference I have found so far are with the installation itself (i.e. from an installer), as these look as though they need to be run from an admin account, or ran as admin from a standard account. The presence of UAC also makes a difference, i.e. admin account with no UAC means the installer runs as it did under XP. Any other account has other steps.

Besides all this, it would still be useful to retrieve the location of any special folder, so that things can be done the 'proper' way in future.

Good to know, thanks. I look forward to your testing results since I plan to use an installer like InnoSetup for larger games/projects, but I'd also like little ones that don't require an installer to continue to work in Vista as they did in XP. I hope that programs which haven't been installed per se can still write/read the My Documents folder...?

After posting the earlier message above, I kept digging and found:
http://technet2.microsoft.com/WindowsVista/en/library/3f1be40e-70c6-462c-9e8f-591d14d875cd1033.mspx

And this:
http://blitzbasic.com/Community/posts.php?topic=45722
had the other half (getting it working in BlitzMax)

So, this seems to do what Vista seems to need (get at "My Documents" regardless of where it is or what it's called), along with other good stuff:
'WinApi Commands
Extern "Win32"
Function SHGetSpecialFolderLocation(hwndOwner, nFolder, pIdl:Byte  Ptr)
Function SHGetPathFromIDList( pidList ,lpBuffer:Byte  Ptr)
End Extern


Const CSIDL_DESKTOP                 = $0000  ' <desktop>
Const CSIDL_INTERNET                = $0001  ' Internet Explorer (icon on desktop)
Const CSIDL_PROGRAMS                = $0002  ' Start Menu\Programs
Const CSIDL_CONTROLS                = $0003  ' My Computer\Control Panel
Const CSIDL_PRINTERS                = $0004  ' My Computer\Printers
Const CSIDL_PERSONAL                = $0005  ' My Documents
Const CSIDL_FAVORITES               = $0006  ' <user name>\Favorites
Const CSIDL_STARTUP                 = $0007  ' Start Menu\Programs\Startup
Const CSIDL_RECENT                  = $0008  ' <user name>\Recent
Const CSIDL_SENDTO                  = $0009  ' <user name>\SendTo
Const CSIDL_BITBUCKET               = $000a  ' <desktop>\Recycle Bin
Const CSIDL_STARTMENU               = $000b  ' <user name>\Start Menu
Const CSIDL_MYDOCUMENTS             = $000c  ' logical "My Documents" desktop icon
Const CSIDL_MYMUSIC                 = $000d  ' "My Music" folder
Const CSIDL_MYVIDEO                 = $000e  ' "My Videos" folder
Const CSIDL_DESKTOPDIRECTORY        = $0010  ' <user name>\Desktop
Const CSIDL_DRIVES                  = $0011  ' My Computer
Const CSIDL_NETWORK                 = $0012  ' Network Neighborhood
Const CSIDL_NETHOOD                 = $0013  ' <user name>\nethood
Const CSIDL_FONTS                   = $0014  ' windows\fonts
Const CSIDL_TEMPLATES               = $0015
Const CSIDL_COMMON_STARTMENU        = $0016  ' All Users\Start Menu
Const CSIDL_COMMON_PROGRAMS         = $0017  ' All Users\Programs
Const CSIDL_COMMON_STARTUP          = $0018  ' All Users\Startup
Const CSIDL_COMMON_DESKTOPDIRECTORY = $0019  ' All Users\Desktop
Const CSIDL_APPDATA                 = $001a  ' <user name>\Application Data
Const CSIDL_PRINTHOOD               = $001b  ' <user name>\PrintHood
Const CSIDL_LOCAL_APPDATA           = $001c  ' <user name>\Local Settings\Application Data (non roaming)
Const CSIDL_ALTSTARTUP              = $001d  ' non localized startup
Const CSIDL_COMMON_ALTSTARTUP       = $001e  ' non localized common startup
Const CSIDL_COMMON_FAVORITES        = $001f
Const CSIDL_INTERNET_CACHE          = $0020
Const CSIDL_COOKIES                 = $0021
Const CSIDL_HISTORY                 = $0022
Const CSIDL_COMMON_APPDATA          = $0023  ' All Users\Application Data
Const CSIDL_WINDOWS                 = $0024  ' GetWindowsDirectory()
Const CSIDL_SYSTEM                  = $0025  ' GetSystemDirectory()
Const CSIDL_PROGRAM_FILES           = $0026  ' C:\Program Files
Const CSIDL_MYPICTURES              = $0027  ' C:\Program Files\My Pictures
Const CSIDL_PROFILE                 = $0028  ' USERPROFILE
Const CSIDL_SYSTEMX86               = $0029  ' x86 system directory on RISC
Const CSIDL_PROGRAM_FILESX86        = $002a  ' x86 C:\Program Files on RISC
Const CSIDL_PROGRAM_FILES_COMMON    = $002b  ' C:\Program Files\Common
Const CSIDL_PROGRAM_FILES_COMMONX86 = $002c  ' x86 Program Files\Common on RISC
Const CSIDL_COMMON_TEMPLATES        = $002d  ' All Users\Templates
Const CSIDL_COMMON_DOCUMENTS        = $002e  ' All Users\Documents
Const CSIDL_COMMON_ADMINTOOLS       = $002f  ' All Users\Start Menu\Programs\Administrative Tools
Const CSIDL_ADMINTOOLS              = $0030  ' <user name>\Start Menu\Programs\Administrative Tools
Const CSIDL_CONNECTIONS             = $0031  ' Network and Dial-up Connections
Const CSIDL_COMMON_MUSIC            = $0035  ' All Users\My Music
Const CSIDL_COMMON_PICTURES         = $0036  ' All Users\My Pictures
Const CSIDL_COMMON_VIDEO            = $0037  ' All Users\My Video
Const CSIDL_RESOURCES               = $0038  ' Resource Direcotry


Function GetSpecialFolder:String(folder_id) 
		
Local  idl:TBank = CreateBank (8) 
Local  pathbank:TBank = CreateBank (260) 
Local n%
Local sp$

	If SHGetSpecialFolderLocation(0,folder_id,BankBuf(idl)) = 0		
		SHGetPathFromIDList PeekInt( idl,0), BankBuf(pathbank)
		
		For n= 0 To 259
			sp$ = sp$ + Chr(PeekByte(pathbank,n))
		Next
	EndIf
	Return Trim(sp$) + ""
		
End Function



Print GetSpecialFolder(CSIDL_PROGRAMS)
Print GetSpecialFolder(CSIDL_PERSONAL)
Print GetSpecialFolder(CSIDL_DESKTOP)

Input


It works in both in XP and in 98 SE, so it should(?) in Vista.