November 24, 2020, 05:56:30 AM

Author Topic: [bmx] Save settings to correct location on Windows by BlitzSupport [ 1+ years ago ]  (Read 642 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
Title : Save settings to correct location on Windows
Author : BlitzSupport
Posted : 1+ years ago

Description : This system allows you to save your application's preferences in the correct location on Windows Vista, 7/8 and upwards, whereas trying to save into your application's own folder may fail due to UAC settings/other filesystem behaviours on these OSes.

Just amend ApplicationName and PrefsFilename globals to suit, then call LoadSettings (), SaveSettings () and GetPrefsFile ().

Try the demo! Recommend reading the Usage notes first...

For real-world usage, you'll have to modify LoadSettings and WriteSettingsFile to accommodate your game's variables/structure (eg. your variables may be in a class/Type rather than globals).


Code :
Code: BlitzMax
  1. ' ----------------------------------------------------------
  2. ' Reads and writes save-files in correct location on Windows!
  3. ' ----------------------------------------------------------
  4.  
  5. Rem
  6.  
  7.         Usage:
  8.        
  9.         1)      Modify the ApplicationName and PrefsFilename globals to suit
  10.         your application. Can be left as defaults for demo.
  11.        
  12.         2)      Use only the three functions below:
  13.  
  14.         LoadSettings () -       loads your settings file, if it exists
  15.  
  16.         SaveSettings () -       creates folder in correct location (if needed);
  17.                                                 creates prefs file in folder (if needed);
  18.                                                 saves prefs!
  19.  
  20.         GetPrefsFile () -       returns path of prefs file, based on
  21.                                                 ApplicationName and PrefsFilename.
  22.  
  23.                                                 Modify these two globals below to suit yourself!
  24.  
  25.                                                 Note on application name/prefs filename:
  26.  
  27.                                                 To avoid conflict with other applications,
  28.                                                 probably best to use your developer/studio
  29.                                                 name for ApplicationName (this is the folder
  30.                                                 name) and the name of your game for
  31.                                                 PrefsFilename (eg. "Rocket Raiders.cfg")
  32.  
  33.         3)      On running the demo, navigate to the folder name returned by GetPrefsFile ()
  34.                 to see the folder/prefs file. Delete the folder to clean up after playing
  35.                 around! Try re-running several times, and try deleting prefs file/folder
  36.                 and re-running...
  37.                
  38. End Rem
  39.  
  40. ' ----------------------------------------------------------
  41. ' N O T E S . . .
  42. ' ----------------------------------------------------------
  43.  
  44. ' Just call SaveSettings to set up your save folder/file for the first time.
  45.  
  46. ' You'll have to amend LoadSettings to accommodate your game's variables and/or structure.
  47.  
  48. ' Amend WriteSettingsFile to suit your game. (SaveSettings is just a wrapper around this.)
  49.  
  50. SuperStrict
  51.  
  52. ?Win32 ' Windows only!
  53.  
  54. Global ApplicationName:String = "AAA Example Game"
  55. Global PrefsFilename:String = "prefs.txt"
  56.  
  57. ' Some example variables to be saved/loaded:
  58.  
  59. Global Example_Lives:Int = 0
  60. Global Example_Level:String = ""
  61.  
  62. ' Uses an example save file of the form:
  63.  
  64. Rem
  65.  
  66.         LIVES:Integer
  67.         LEVEL:String
  68.        
  69.         ... eg.
  70.        
  71.         LIVES:5
  72.         LEVEL:Space
  73.  
  74. End Rem
  75.  
  76. ' Windows special path constants:
  77.  
  78. Const CSIDL_PERSONAL:Int = $5 ' Use this instead of CSIDL_MYDOCUMENTS. I don't know why! Ask Microsoft...
  79. Const CSIDL_APPDATA:Int = $1A
  80.  
  81. ' From http://www.blitzbasic.com/codearcs/codearcs.php?code=2815
  82. ' See URL for more special folder locations!
  83.  
  84. Function GetSpecialFolder:String (folder:Int)
  85.  
  86.         ' Shell32 functions...
  87.        
  88.         Global SHGetSpecialFolderLocation_      (hwndOwner:Byte Ptr, nFolder:Int, pidl:Byte Ptr) "win32"
  89.         Global SHGetPathFromIDList_                     (pidl:Byte Ptr, bytearray:Byte Ptr) "win32"
  90.        
  91.         ' OLE32 functions...
  92.        
  93.         Global CoTaskMemFree_ (pv:Byte Ptr)
  94.        
  95.         ' Assign function pointers...
  96.        
  97.         Local shell32:Int       = LoadLibraryA ("shell32.dll")
  98.         Local ole32:Int         = LoadLibraryA ("ole32.dll")
  99.  
  100.         Local result:Int = False
  101.        
  102.         If shell32
  103.  
  104.                 SHGetSpecialFolderLocation_     = GetProcAddress (shell32, "SHGetSpecialFolderLocation")
  105.                 SHGetPathFromIDList_            = GetProcAddress (shell32, "SHGetPathFromIDList")
  106.  
  107.                 If (Not SHGetSpecialFolderLocation_) Or (Not SHGetPathFromIDList_)
  108.                         DebugLog "Failed to assign shell32 function pointer!"
  109.                         Return ""
  110.                 EndIf
  111.  
  112.         Else
  113.  
  114.                 DebugLog "Failed to open shell32.dll!"
  115.                 Return ""
  116.  
  117.         EndIf
  118.  
  119.         If ole32
  120.  
  121.                 CoTaskMemFree_ = GetProcAddress (ole32, "CoTaskMemFree")
  122.  
  123.                 If Not CoTaskMemFree_
  124.                         DebugLog "Failed to assign ole32 function pointer!"
  125.                         Return ""
  126.                 EndIf
  127.  
  128.         Else
  129.  
  130.                 DebugLog "Failed to open ole32.dll!"
  131.                 Return ""
  132.  
  133.         EndIf
  134.  
  135.         Function GetSpecialFolder_Sub:String(folder_id:Int) ' JoshK's code brutally hacked-in!
  136.  
  137.                 Local idl:TBank = CreateBank (8)
  138.                 Local pathbank:TBank = CreateBank (260)
  139.                 Local n%
  140.                 Local sp$
  141.                 Local b:Int
  142.  
  143.                 If SHGetSpecialFolderLocation_ (Null, folder_id, BankBuf (idl)) = 0            
  144.  
  145.                         SHGetPathFromIDList_ Byte Ptr PeekInt (idl, 0), BankBuf (pathbank)
  146.  
  147.                         For n = 0 To 259
  148.                                 b = PeekByte (pathbank, n)
  149.                                 If b = 0
  150.                                         CoTaskMemFree_ (Byte Ptr PeekInt (idl, 0))
  151.                                         Return sp
  152.                                 EndIf
  153.                                 sp$ = sp$ + Chr (b)
  154.                         Next
  155.                 Else
  156.                         Return ""
  157.                 EndIf
  158.                
  159.                 CoTaskMemFree_ (Byte Ptr PeekInt (idl, 0))
  160.                
  161.                 Return sp.Trim ()
  162.                
  163.         End Function
  164.  
  165.         If SHGetSpecialFolderLocation_ And SHGetPathFromIDList_ And CoTaskMemFree_
  166.                 Return GetSpecialFolder_Sub (folder)
  167.         EndIf
  168.  
  169. End Function
  170.  
  171. ' Helper function...
  172.  
  173. Function Quoted:String (in:String)
  174.         Return "~q" + in + "~q"
  175. End Function
  176.  
  177. ' Retrieves location of prefs file based on ApplicationName and PrefsFilename,
  178. ' whether or not they've been created yet...
  179.  
  180. Function GetPrefsFile:String ()
  181.  
  182.         Local folder:String = GetSpecialFolder (CSIDL_APPDATA)
  183.  
  184.         If folder = ""
  185.  
  186.                 folder = GetSpecialFolder (CSIDL_PERSONAL)
  187.  
  188.                 If folder = ""
  189.                         folder = "C:" ' Gah! What's up with your system?!
  190.                 EndIf
  191.  
  192.         EndIf
  193.        
  194.         If Right (folder, 1) <> "" And Right (folder, 1) <> "/"
  195.                 folder = folder + ""
  196.         EndIf
  197.        
  198.         Return folder + ApplicationName + "" + PrefsFilename
  199.        
  200. End Function
  201.  
  202. ' ----------------------------------------------------------
  203. ' Deletes settings file...
  204. ' ----------------------------------------------------------
  205.  
  206. Function DeleteSettings ()
  207.         DeleteFile (GetPrefsFile ())
  208. End Function
  209.  
  210. ' ----------------------------------------------------------
  211. ' Loads settings, if settings file exists...
  212. ' ----------------------------------------------------------
  213.  
  214. ' Use SaveSettings to set up prefs folder/file!
  215.  
  216. Function LoadSettings ()
  217.  
  218.         Local loadprefs:TStream = ReadFile (GetPrefsFile ())
  219.        
  220.         If loadprefs
  221.        
  222.                 While Not Eof (loadprefs)
  223.                        
  224.                         Local info:String = ReadLine (loadprefs)
  225.  
  226.                         ' Example line:
  227.                        
  228.                         ' LEVEL:Space
  229.                        
  230.                         Local splitter:Int = Instr (info, ":")
  231.                        
  232.                         Local entry:String = Trim (Left (info, splitter - 1))
  233.                         Local value:String = Trim (Mid (info, splitter + 1))
  234.                        
  235.                         ' Amend the Case entries and Example_Variables to suit your game!
  236.                        
  237.                         Select entry
  238.  
  239.                                 Case "LIVES"
  240.                                
  241.                                         ' Read an Int...
  242.                                        
  243.                                         Example_Lives = Int (value)
  244.  
  245.                                 Case "LEVEL"
  246.                                
  247.                                         ' Read a String...
  248.                                        
  249.                                         Example_Level = value
  250.  
  251.                                 Default
  252.  
  253.                         EndSelect
  254.                        
  255.                 Wend
  256.  
  257.                 CloseFile loadprefs
  258.  
  259.         Else
  260.                 Print "Couldn't load preferences file! Does " + Quoted (GetPrefsFile ()) + " exist?"
  261.         EndIf
  262.  
  263. End Function
  264.  
  265. ' ----------------------------------------------------------
  266. ' Save settings. Modify the highlighted section to suit!
  267. ' ----------------------------------------------------------
  268.  
  269. Function WriteSettingsFile (folder:String)
  270.  
  271.         If Right (folder, 1) = "" Or Right (folder, 1) = "/"
  272.                 folder = folder [..Len (folder) - 1] ' FileType doesn't like end slashes on folders!
  273.         EndIf
  274.        
  275.         Local savefile:String = folder + "" + PrefsFilename
  276.  
  277.         If FileType (folder) = FILETYPE_DIR
  278.        
  279.                 Local created:Int = CreateFile (savefile)
  280.                
  281.                 If created
  282.                
  283.                         Local saveprefs:TStream = WriteFile (savefile)
  284.                        
  285.                         If saveprefs
  286.  
  287.                                 ' ----------------------------------------------------------
  288.                                 ' *** MODIFY ME! ***
  289.                                 ' ----------------------------------------------------------
  290.                
  291.                                 ' ----------------------------------------------------------
  292.                                 ' The settings save section - amend to suit your game!
  293.                                 ' ----------------------------------------------------------
  294.  
  295.                                 WriteLine saveprefs, "LIVES:" + Example_Lives
  296.                                 WriteLine saveprefs, "LEVEL:" + Example_Level
  297.  
  298.                                 ' ----------------------------------------------------------
  299.                                 ' *** END OF MODIFY ME! ***
  300.                                 ' ----------------------------------------------------------
  301.  
  302.                                 CloseFile saveprefs
  303.  
  304.                         Else
  305.  
  306.                                 Print "Unable to create preferences file " + Quoted (savefile)
  307.                         EndIf
  308.  
  309.                 EndIf
  310.        
  311.         Else
  312.                 Print "Unable to locate preferences folder " + Quoted (folder)
  313.                 Print "Folder is " + FileType (folder)
  314.                 Print "Folder is " + FileType ("C:UsersJamesAppDataRoamingAAA Example Game")
  315.                 Print "Folder is " + FileType ("C:UsersJamesAppDataRoamingAAA Example Game")
  316.         EndIf
  317.  
  318. End Function
  319.  
  320. ' ----------------------------------------------------------
  321. ' Wrapper for WriteSettingsFile...
  322. ' ----------------------------------------------------------
  323.  
  324. Function SaveSettings ()
  325.        
  326.         Local folder:String = ExtractDir (GetPrefsFile ())
  327.        
  328.         folder = Replace (folder, "/", "") ' WTF, ExtractDir?!
  329.  
  330.         CreateDir folder$
  331.  
  332.         Select FileType (folder$)
  333.        
  334.                 Case 0
  335.                
  336.                         Print "Unable to create preferences folder " + Quoted (folder)
  337.                        
  338.                 Case FILETYPE_DIR
  339.                
  340.                         WriteSettingsFile folder
  341.                        
  342.                 Case FILETYPE_FILE ' Unlikely!
  343.                
  344.                         Print "Unable to create preferences folder + " + Quoted (folder) + "; file with same name already exists!"
  345.                        
  346.         EndSelect
  347.        
  348. End Function
  349.  
  350. ? ' End of ?Win32 section!
  351.  
  352. ' ----------------------------------------------------------
  353. ' D E M O . . .
  354. ' ----------------------------------------------------------
  355.  
  356. ' Some random level names for saving...
  357.  
  358. Local Level_Name:String [10]
  359.  
  360. Level_Name [0] = "Snow World"
  361. Level_Name [1] = "Eiffel Tower"
  362. Level_Name [2] = "Egypt"
  363. Level_Name [3] = "Space"
  364. Level_Name [4] = "Moon"
  365. Level_Name [5] = "Hell"
  366. Level_Name [6] = "Desert"
  367. Level_Name [7] = "Circus"
  368. Level_Name [8] = "Inca"
  369. Level_Name [9] = "Alien Planet"
  370.  
  371. SeedRnd MilliSecs ()
  372.  
  373. Print ""
  374. Print "Using " + GetPrefsFile () ' Just for info
  375.  
  376. ' ----------------------------------------------------------
  377. ' Load settings... expected to fail if not already saved!
  378. ' ----------------------------------------------------------
  379.  
  380. Print ""
  381. Print "Attempting to load settings..."
  382. Print ""
  383.  
  384. LoadSettings
  385.  
  386. ' ----------------------------------------------------------
  387. ' Show loaded settings... will be default null on first run
  388. ' ----------------------------------------------------------
  389.  
  390. Print ""
  391. Print "Loaded settings:"
  392. Print ""
  393. Print "~t~tLives: " + Example_Lives
  394. Print "~t~tLevel: " + Example_Level
  395. Print ""
  396.  
  397. ' ----------------------------------------------------------
  398. ' Randomly change settings...
  399. ' ----------------------------------------------------------
  400.  
  401. Print ""
  402. Print "Randomly changing settings..."
  403. Print ""
  404.  
  405. Example_Lives = Rand (1, 10)
  406. Example_Level = Level_Name [Rand (0, 9)]
  407.  
  408. ' ----------------------------------------------------------
  409. ' Save settings...
  410. ' ----------------------------------------------------------
  411.  
  412. Print ""
  413. Print "Saving new settings..."
  414. Print ""
  415.  
  416. SaveSettings
  417.  
  418. ' ----------------------------------------------------------
  419. ' Reload saved settings...
  420. ' ----------------------------------------------------------
  421.  
  422. Print ""
  423. Print "Attempting to reload saved settings..."
  424. Print ""
  425.  
  426. LoadSettings
  427.  
  428. ' ----------------------------------------------------------
  429. ' Show loaded settings...
  430. ' ----------------------------------------------------------
  431.  
  432. Print ""
  433. Print "Loaded settings:"
  434. Print ""
  435. Print "~t~tLives: " + Example_Lives
  436. Print "~t~tLevel: " + Example_Level
  437. Print ""


Comments : none...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal