Done It! Shared Data on Windows Vista in code!

BlitzMax Forums/BlitzMax Programming/Done It! Shared Data on Windows Vista in code!

Grey Alien(Posted 2007) [#1]
I'd like to thank Indiepath and Gman and GfK who directly contributed to the solution and all the people today who tried to help me with my crap API fumbling: Azathoth, Noel, Brucey, Kev, and some others. Thanks!

What does it do? It creates a FULL ACCESS folder in CODE in Vista so that you don't need to rely on an Installer to do it. This has been the holy grail of getting your Blitz games to properly share High Score data and profiles etc. over different user accounts in Windows Vista, and now it's solved!

OK so you you need to make a file called fullaccess.cpp and put it in the same folder as the bmx source code. Here's what's in fullaccess.cpp:

#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;
}


Then make some bmx source code in the same folder and call it what you want. Turn off Build GUI App under Program/Build Options in the IDE so that you can see the Print commands.

Import "fullaccess.cpp"
Import "-ladvapi32"

Extern "Win32"
Function SHGetSpecialFolderLocation(hwndOwner, nFolder, pIdl:Byte Ptr)
Function SHGetPathFromIDList(pidList, lpBuffer:Byte Ptr)
Function CreateFile(lpString:Byte Ptr,dwDesiredAccess:Int,dwShareMode:Int,..
	lpSecurityAttributes:Byte Ptr,dwCreationDisposition:Int,dwFlagsAndAttributes:Int,hWnd:Int)
End Extern

Extern
	Function GiveDirectoryUserFullAccess:Int(lpPath$z)
EndExtern

Const CSIDL_DESKTOP = $0
Const CSIDL_INTERNET = $1
Const CSIDL_PROGRAMS = $2
Const CSIDL_CONTROLS = $3
Const CSIDL_PRINTERS = $4
Const CSIDL_PERSONAL = $5
Const CSIDL_FAVORITES = $6
Const CSIDL_STARTUP = $7
Const CSIDL_RECENT = $8
Const CSIDL_SENDTO = $9
Const CSIDL_BITBUCKET = $A
Const CSIDL_STARTMENU = $B
Const CSIDL_DESKTOPDIRECTORY = $10
Const CSIDL_DRIVES = $11
Const CSIDL_NETWORK = $12
Const CSIDL_NETHOOD = $13
Const CSIDL_FONTS = $14
Const CSIDL_TEMPLATES = $15
Const CSIDL_COMMON_STARTMENU = $16
Const CSIDL_COMMON_PROGRAMS = $17
Const CSIDL_COMMON_STARTUP = $18
Const CSIDL_COMMON_DESKTOPDIRECTORY = $19
Const CSIDL_APPDATA = $1A
Const CSIDL_PRINTHOOD = $1B
Const CSIDL_LOCAL_APPDATA = $1C
Const CSIDL_ALTSTARTUP = $1D
Const CSIDL_COMMON_ALTSTARTUP = $1E
Const CSIDL_COMMON_FAVORITES = $1F
Const CSIDL_INTERNET_CACHE = $20
Const CSIDL_COOKIES = $21
Const CSIDL_HISTORY = $22
Const CSIDL_COMMON_APPDATA = $23

Function GetSpecialFolder:String(folder_id) 
	Local  idl:TBank = CreateBank (8) 
	Local  pathbank:TBank = CreateBank (260) 
	If SHGetSpecialFolderLocation(0,folder_id,BankBuf(idl)) = 0		
		SHGetPathFromIDList PeekInt( idl,0), BankBuf(pathbank)
		Return String.FromCString(pathbank.Buf()) + "\"
	EndIf
End Function

'Get the correct path
Local path$ = GetSpecialFolder(CSIDL_COMMON_APPDATA)+"Grey Alien Games\My Game\"
Print path

'If the path does not exist, create it with full permissions!
If ReadDir(path) = 0 Then
	Print "Creating New Folder..."
	Print "CreateDir="+CreateDir(path,True) 'create subfolders
	
	Print "FullAccess="+GiveDirectoryUserFullAccess(path)
Else
	Print "Folder already exists"
EndIf

Local f:TStream = WriteStream(path+"test.txt")

If f Then
	Print "Text File Writing..."
	WriteString(f,"testing123")
	CloseStream(f)
	Print "Done"
Else
	Print "Cannot Write"
EndIf

While Not KeyHit(Key_Escape)
Wend




So what does it do?

1) It gets the path to CSIDL_COMMON_APPDATA which works on Vista and XP (haven't tested on 2000 or Server 2003, but it should work. Don't know about 98/ME, can test on ME tomorrow).

2) Then it makes a Grey Alien Games folder with a sub folder for My Game.

3) Then it gives the folder full access permissions for all users.

4) Then it makes a text file in that folder.

Simple, but here's how to test it out...

1) Logon to Vista with User1 (make sure UAC is ON).
2) Run the app. You'll see that it writes that text file no problems.
3) Switch user to User2.
4) Locate the My Game folder, edit the text file and SAVE IT - it should save no problems.
5) The SAVE step does NOT work if you didn't run my special code.
6) To compare with a non-working method: Try going back up a level and making a new folder manually with a text file in it. Then go back to User 1 and edit that text file. When you click SAVE it ERRORS!

Tada. Phew am I glad this is sorted. I'll be building it into my framework so it automatically stores game data in the correct place. And I'll be testing it with my highscores file in my current game tomorrow.

Please let me know if you see any problems with this method. Thanks. Now I can go to sleep...


FlameDuck(Posted 2007) [#2]
This should be made Sticky somewhere. We should probably get a "Vista" forum along with all the other platforms (Linux, Mac etc.).


Grey Alien(Posted 2007) [#3]
Well someone finally noticed it, wooo ;-)


xlsior(Posted 2007) [#4]
I don't use vista myszelf yet, but this will definitely go into my save folder. Thanks for sharing!


MGE(Posted 2007) [#5]
The HOLY GRAIL has been found! Thanks for sharing GA! Hats off to the others for taking the time to help out. I havn't done anything serious on Vista yet, but can this be used as is for XP and Vista? Aagin, HUGE thanks!


Grey Alien(Posted 2007) [#6]
Thanks guys.

Yep, I wrote it all on XP and tested on that fine (will test on ME on Monday). Then I went and ran it all on Vista too and it's fine - I went "wooo!". Indiepath has a raised a possible concern (but it could be a red herring) in my other Vista thread but I'm waiting for a reply from him.


MGE(Posted 2007) [#7]
Fingers are crossed. ;)


Qube(Posted 2007) [#8]
Cool stuff Jake and to those who helped out.

What's the latest position on this routine - Does it work on 98, Me and 2000 too?

What about Indiepath's error, is that a red herring?

Above all, thanks for sharing a solution :)

*edit*

Doesn't vista allow you to write to the installation folder with UAC on?


Grey Alien(Posted 2007) [#9]
Haven't tested on ME yet, will do soon and will post back, thanks for reminding me. Can also test on 2000 soon. Can't test on 98 SE, but it should be like Me.

I think Indiepath's thing is a red herring, he said he'd test some code for me but hasn't yet, I could chase him...

With UAC on you can't write to the installation folder, well actually when you try the writes (and later reads) just get virtualised somewhere else in a hidden folder within the current user's folder. That's what the problem is and what I have got round. You *could* probably write to the installation folder if your INSTALLER made the path accessibly to ALL users but I wrote this code because you can't depend on portals (and other 3rd parties) making their installer scripts correctly.


TartanTangerine (was Indiepath)(Posted 2007) [#10]
I've tested, here are the results - I've tested in a plugin environment and in a standalone (igloader and harmony). If I test within the plugin, in IE7 protected, then I get virtualised unless I use GetEnvironmentVar. If I run jakes code as is within Blitzmax then all is well. I don't know why things are different but they are on both my Vista laptops (yeah I purchased a new one to test on :P).

My suggestion would be to forget about writing incidental files to the "shared" directory and just install your game there and don't worry about it (but as jake says, you can't rely on the portal to do it right).

Sorry if you feel I've dropped a red-fish into the equation but all things considered there are still issues - certainly with what I'm testing.


Grey Alien(Posted 2007) [#11]
Thanks for testing dude! I'd rather know about potential problems and then have them cleared up than be in the dark, so no worries.


TartanTangerine (was Indiepath)(Posted 2007) [#12]
Hey, sorry I've taken so long - I've been purchased to do work on a new site and I'm kinda busy.. keep your eyes on www.zangbezang.com (and no I did not design it - I'm the guy who makes it work server-side).


MGE(Posted 2007) [#13]
So for us noobs...is the code good to go then and if so what are the potential snags if any? Thanks again GA and IP!


Grey Alien(Posted 2007) [#14]
Yep it's good to go (no known snags). Runs on Vista and XP and I just tested it on Me and it works fine (it won't share the folder with all users but you don't need to, it just creates it and writes the text file into it.)

[edit] Also tested on 2000 and it's fine. Path is the same as XP.

Here are the different paths you get with CSIDL_COMMON_APPDATA on different OSes:

	WinMe = C:\Windows\All Users\Application Data
	WinXP/2000 = C:\Documents and Settings\All Users\Application Data
	Vista = C:\ProgramData


Awaiting 98SE results...


MGE(Posted 2007) [#15]
As soon as this is added to your framework, I'm going to buy it. :) Any ETA when this will be added? Thanks!


Grey Alien(Posted 2007) [#16]
It's already added. I just haven't released V1.05 yet. If you want you can have a pre-release.


MGE(Posted 2007) [#17]
What else will be in v1.05? I'm not good on updating, do I'd rather have as much current as possible when I purchase. lol..


Grey Alien(Posted 2007) [#18]
Loads, it's the biggest update yet. Why don't you email me so we don't derail this thread into a framework advert?


JoshK(Posted 2007) [#19]
Don't all these precaution and precaution overrides result in no net safety benefit, but increasing complexity?


Grey Alien(Posted 2007) [#20]
Certainly Vista has forced game makers into more complex ways of saving data. Without my code you would have still been able to write to the Application Data folder BUT another user wouldn't have been able to write to that folder (to update high scores etc), so I'm not sure that's a big safety issue that's been overridden because I'm SUPPOSED to write in that folder and not somewhere else. Vista's UAC will warn you though if an unexpected program tries to write to places it shouldn't so that's good if you are the kind of user that installs any old crap and fills your PC up with spyware.


Chroma(Posted 2007) [#21]
How about add this to the archives and unsticky this. There's like 4 stickies on this forum and it's really looking cluttered.

Just a friendly, logical suggestion. :)


Amon(Posted 2007) [#22]
How about add this to the archives and unsticky this. There's like 4 stickies on this forum and it's really looking cluttered.


I think it's fine here insetad of the archives. It's more accessable as a sticky in this forum.

[edit] Good work Grey. :) Now for a GA Framework Light edition. :)


Chroma(Posted 2007) [#23]
I think it's fine here insetad of the archives. It's more accessable as a sticky in this forum.


Erm...that makes absolutely NO sense Amon. The archives are for...archiving code. It's just as accessible in the archives as it is here.


FlameDuck(Posted 2007) [#24]
It's just as accessible in the archives as it is here.
For real? Have you ever used the archives, and managed to find what you were looking for?


Chroma(Posted 2007) [#25]
So you're saying the archives are worthless? It's where people go when they can't figure something out themselves. I'm sure you've used them on several occasions. In fact, I'm 100% positive. ;)


Grey Alien(Posted 2007) [#26]
I google the archives as it's much easier to find stuff there than using the site's Search facility. Anyway it can only go in the archives if I can be bothered to make an archive post which I haven't done cos I'm pretty busy right now...


Chroma(Posted 2007) [#27]
I'll do it for ya and put your name in it.


Grey Alien(Posted 2007) [#28]
Just wait and I'll do it eventually. I want another "point" on code archive entries ;-)

Please don't derail this thread any more. It's supposed to be about a Vista fix and any related issues. Thanks.


Chroma(Posted 2007) [#29]
Lol I didn't derail anything. I just pointed out that you should archive this so it can be unstickied. ;-)


Grey Alien(Posted 2007) [#30]
9 (now 10) posts about something being unsticked = derailed in my book. We've all derailed it, so I just throught it would be best back on track now.


Ghost Dancer(Posted 2008) [#31]
Thanks for posting this Grey. I've just been trying to use it for something I'm working on but I'm getting the following error:

Build Error: failed to compile fullaccess.cpp

Not the most helpful of error messages. I've tried it using an exact copy of your example. Any ideas what might causing the error?


Grey Alien(Posted 2008) [#32]
You are welcome. You need to install MinGW in order to compile that cpp file (I only realised this recently when someone told me as I already had it installed from ages ago). Check out this thread:

http://www.blitzbasic.com/Community/posts.php?topic=72892


Ghost Dancer(Posted 2008) [#33]
Thanks for the info. I did have MinGW isntalled but had not set the environment path etc. However, I have now set it up as detailed in that thread but I'm getting the same error. Any ideas?


GfK(Posted 2008) [#34]
There's a few extra things you may need to do to get MinGW to work correctly.

I wrote a full guide on www.syntaxbomb.com - will see if I can find it.

[edit] http://www.syntaxbomb.com/forums/showthread.php?t=1808


Ghost Dancer(Posted 2008) [#35]
Ah, I had done that but just rechecked - a pesky space appeared in the path string. Thanks for your help, it's compiling ok now :)


Grey Alien(Posted 2008) [#36]
Thanks GfK. I'll link to that via my forum.


Midnight(Posted 2008) [#37]
Just a quick note - I'm looking for a way to do the equivalent in Blitz3D.

I've posted here: http://blitzbasic.co.nz/Community/posts.php?topic=76077

Cheers,
Patrick


Midnight(Posted 2008) [#38]
With thanks to Kev, this is now also available for Blitz3D. I've uploaded it to my site for anyone to use.

Check my post again for the download of the equivalent of the above code (find special folders and enable write access).
http://blitzbasic.co.nz/Community/posts.php?topic=76077

Cheers,
Patrick