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:
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.
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...
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...