Older Version Newer Version

Alyce Alyce Feb 21, 2012

Safe Directories for File Writing

- Alyce Alyce
Safe Directories for File Writing | UAC and Files | Safe Directories | Special Variables | Trailing Backslash in DefaultDir$ | My Docments | Trailing Backslash | Temporary Files and Folders

For an eBook or printed book on using the API with Liberty BASIC, see:
APIs for Liberty BASIC


UAC and Files

User Account Control in versions of Windows starting with Windows Vista prohibits programs from writing files to many disk locations unless the program is run "as administrator". The reason for this restriction is as follows, quoted from the Wikidpedia article:

Safe Directories

Do not attempt to write files in the folder from which your program is running. The "Program Files" folder is not available for normal file writing operations and attempts to write files there will generate errors.

Instead, write files to the user's "My Documents" folder, temporary folder, or application data folder.

Special Variables

Applications write data to a user's data folder. Application data includes information needed by the program, such as data files and initialization files.

The following quote from the Liberty BASIC helpfile explains how to use the special variables DefaultDir$ (user's data) and StartupDir$ (installation folder)








Trailing Backslash in DefaultDir$

The special variable StartupDir$ points to the folder from which a Liberty BASIC program is running. Do not use it to write files. StartupDir$ includes a trailing backslash.

To access the user's data folder, write files to DefaultDir$. The special variable DefaultDir$ does not include a trailing backslash. In your code, check for a trailing backslash and add it if it doesn't exist, as in the following example.

 print DefaultDir$ 'no trailing backslash 
print StartupDir$ 'has trailing backslash

if right$(DefaultDir$,1)<>"\" then
DefaultDir$=DefaultDir$+"\"
end if

print DefaultDir$

'write a file:
open DefaultDir$+"mytestfile.txt" for output as #f
print #f, "Test"
close #f

My Docments

Windows has long included a folder called "My Documents" which is meant to be the location where users create and save files. You can retrieve this location with the API from shell32.dll called SHGetSpecialFolderLocation , using a value of 5 for the desired folder. This is the value assigned to the "My Documents" folder. An additional API is required to retrieve the folder name. It is SHGetPathFromIDListA . Both API calls are wrapped in a function:

 Function GetSpecialfolder$(CSIDL) 
'CSIDL.PERSONAL = 5 : My Docments = GetSpecialfolder$(CSIDL.PERSONAL)
struct IDL,cb As Long, abID As short
calldll #shell32, "SHGetSpecialFolderLocation",_
0 as long, CSIDL as long, IDL as struct, ret as long
if ret=0 then
Path$ = Space$(512)
id=IDL.cb.struct
calldll #shell32, "SHGetPathFromIDListA",id as long, Path$ as ptr, ret as long
GetSpecialfolder$ = Left$(Path$, InStr(Path$, Chr$(0)) - 1)
else
GetSpecialfolder$ = "Error"
end if
End Function

Trailing Backslash

The folder name for "My Docments" does not include a trailing backslash. To assure that the backslash is included in the folder name, check for it and append it if it is not there. Here is a demo that retrieves the location of "My Docments", adds a trailing backslash, and writes a test file there.

 CSIDL.PERSONAL = 5 'My Docments Folder 

myDocuments$ = GetSpecialfolder$(CSIDL.PERSONAL)

print "My Documents folder location is: "
print myDocuments$

if right$(myDocuments$,1)<>"\" then
myDocuments$=myDocuments$+"\"
end if

open myDocuments$ + "testxxxx.txt" for output as #f
print #f, "Test"
close #f

end

Function GetSpecialfolder$(CSIDL)
struct IDL,cb As Long, abID As short
calldll #shell32, "SHGetSpecialFolderLocation",_
0 as long, CSIDL as long, IDL as struct, ret as long
if ret=0 then
Path$ = Space$(512)
id=IDL.cb.struct
calldll #shell32, "SHGetPathFromIDListA",id as long, Path$ as ptr, ret as long
GetSpecialfolder$ = Left$(Path$, InStr(Path$, Chr$(0)) - 1)
else
GetSpecialfolder$ = "Error"
end if
End Function

Temporary Files and Folders

To assure that your program writes temporary files to the Windows folder reserved for temporary files, use GetTempPathA and GetTempFileNameA. These functions are explained here:

GetTempPathA
GetTempFileNameA

 yourPrefix$ = "xxx" 'prefix you choose 
TempFileName$ = GetTempFileName$(yourPrefix$)
print "Temporary File Name is ";TempFileName$
end

function GetTempFileName$(prefix$)
TempPath$=GetTempPath$()
TempFile$ = space$(256)+chr$(0)

calldll #kernel32, "GetTempFileNameA",_
TempPath$ as ptr,_ 'directory for temp file
prefix$ as ptr,_ 'desired prefix for temp filename
0 as ulong,_ '0=file created,nonzero=you must create file
TempFile$ as ptr,_ 'string buffer to hold qualified path and filename
result as ulong 'nonzero=success
end function

Function GetTempPath$()
CallDLL #kernel32, "GetTempPathA",_
0 as long,_
_NULL as long,_
length as long

buf$ = space$(length)

CallDLL #kernel32, "GetTempPathA",_
length as long,_
buf$ as ptr,_
ret as long

GetTempPath$ = buf$
End Function

Safe Directories for File Writing | UAC and Files | Safe Directories | Special Variables | Trailing Backslash in DefaultDir$ | My Docments | Trailing Backslash | Temporary Files and Folders