/*
Filename.....: vistaIni.cc
ClassName....: vistaIni
Purpose......: Create, read, and write to a file with
ini file type methods. Default the folder used
to the xp, vista preferred folder of
User\Application Data\Publisher\Application
Auto create the folder and file (if necessary).
Programmer...: Rick Miller.
Date.........: August 15, 2008.
Notes........: See Notes below.
Written for..: dBASE 32 bit.
Rev. History.: None.
Dependencies.: shfolder.dll.
API Calls....: see x_InitializeExterns method.
Called by....: Any.
Usage........: set procedure to vistaIni.cc additive
----------------------------------------------------------------
Example:
----------------------------------------------------------------
oIni = new vistaIni("Application", "Publisher")
oIni.set("Grid", "Column1Field", "CUSTOMER")
oIni.release()
oIni := null
Notes:
----------------------------------------------------------------
1) the 2 parameters at initialization are required.
2) a subFolder of application can be used by assigning
the subfolder property.
3) when working with number values:
a) the set method will round based upon the
current set("decimals") value.
b) the getNumber, and setNumber methods will round
based upon the current set("decimals") value or
the decimals parameter when passed.
c) the getInt and setInt methods always drop all
decimals with no rounding.
d) when debugging using the ? command, the display is
always based upon the current set("decimals") value,
even when there are more decimals present.
4) the deleteFolders method may return false when
there are multiple applications using this object
with the same publisher property value.
5) it is not recommended to change the publisher property
after initialization.
----------------------------------------------------------------
Properties:
----------------------------------------------------------------
application <char> initialized at creation from parameter.
filename <char> initialized at creation to user name.
publisher <char> initialized at creation from parameter.
subfolder <char> ""
----------------------------------------------------------------
Methods:
----------------------------------------------------------------
close()
calls to release(), and close this file.
delete()
returns true/false (success/fail).
delete the file this object uses.
this method may be used when a temporary file is wished
or a resetting of the file is desired.
deleteApplicationFolder()
returns true/false (success/fail).
delete this.publisher + "\" + this.application directory.
deleteFolders()
returns true/false (success/fail).
delete all folders that may have been created.
deletePublisherFolder()
returns true/false (success/fail).
delete this.publisher directory.
deleteSubfolder()
returns true/false (success/fail).
delete this.subfolder directory(ies).
flush()
returns true/false (success/fail).
flush writes that may be in cache.
fullFilename()
returns <char>.
the fullpath\filename this object is using.
get(<char> section, <char> name)
returns <char> from this.filename.
getInt(<char> section, <char> name)
returns <int> from this.filename.
getNumber(<char> section, <char> name[, <int> decimals])
returns <number> from this.filename.
release()
destroy this object.
rootFolder()
returns <char> User\Application Data
set(<char> section, <char> name, <char> value)
returns true/false (success/fail).
write a <char> to this.filename.
setInt(<char> section, <char> name, <numeric> value)
returns true/false (success/fail).
write an <int> to this.filename.
setNumber(<char> section, <char> name,;
<number> value[, <int> decimals])
returns true/false (success/fail).
write a <number> to this.filename.
setRoot(<int> CSIDL folder)
returns true/false (success/fail).
assign a proper root folder to use.
----------------------------------------------------------------
*/
#define _VINI_CLASS_ "vistaIni"
#define _VINI_VERSION_ "1.00"
#define ALLTRIM(c) ltrim(trim(c))
#define ALLTRIMINI(c) iif(c.indexOf(".") == -1,;
ALLTRIM(c) + ".ini",;
ALLTRIM(c))
#define ALLTRIMSUB(c) iif(empty(c),;
"",;
ALLTRIM(c) + "\")
#define MAX_LINELENGTH 1024
#define MAX_PATH 260
#define MAX_USERNAME 256
#define CSIDL_APPDATA 0x001a // <user>\Application Data
#define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data
#define CSIDL_LOCAL_APPDATA 0x001c // <user>\Local Settings\Application Data (non roaming)
#define ZEROS(n) replicate(chr(0), n)
//---------------------------------------------------------------//
// constructor.
//---------------------------------------------------------------//
class vistaIni(Application, Publisher)
protect x_DeleteDirectory, x_GetDirectory,;
x_GetDirectoryApplication, x_GetDirectoryPublisher,;
x_GetFilename, x_GetUserName,;
x_InitializeExterns, x_ValidateDirectory
protect ~root
this.~root = CSIDL_APPDATA
this.classname = _VINI_CLASS_
this.version = _VINI_VERSION_
if PCount() == 2
this.x_InitializeExterns()
this.application = "" + Application
this.publisher = "" + Publisher
this.subfolder = ""
this.filename = this.x_GetUsername()
else
msgbox( ;
"Invalid initialization of " + this.classname + chr(13) +;
"the Application name and" + chr(13) +;
"the Publisher name" + chr(13) +;
"are required parameters", this.classname + " " +;
this.version + " Message", 16)
endif
//------------------------------------------------------------//
// end of constructor.
// public methods below.
//------------------------------------------------------------//
function close
this.release()
try
close procedure (program(1))
catch(exception e)
endtry
return
//------------------------------------------------------------//
// delete the file used with this object.
function delete
Local bRet, cFile, oFile
cFile = this.x_GetFilename()
oFile = new file()
if oFile.exists(cFile)
oFile.delete(cFile)
endif
bRet = iif(oFile.exists(cFile), false, true)
oFile := null
return iif(bRet, true, false)
//------------------------------------------------------------//
// delete the all folders that may have been created.
function deleteFolders
Local bRet
bRet = false
if this.deleteSubfolder()
if this.deleteApplicationFolder()
if this.deletePublisherFolder()
bRet := true
endif
endif
endif
return iif(bRet, true, false)
//------------------------------------------------------------//
// delete this.publisher + "\" + this.application directory.
function deleteApplicationFolder
return this.x_DeleteDirectory(this.x_GetDirectoryApplication())
//------------------------------------------------------------//
// delete this.publisher directory.
function deletePublisherFolder
return this.x_DeleteDirectory(this.x_GetDirectoryPublisher())
//------------------------------------------------------------//
// delete this.subfolder directory(ies).
function deleteSubfolder
Local bRet
if empty(this.subfolder)
bRet = true
else
Local cFold, i, nCnt, nPos
nCnt = 1
nPos = this.subfolder.indexOf("\")
do while nPos > -1
nCnt ++
nPos := this.subfolder.indexOf("\", nPos + 1)
enddo
nPos = 0
cFold = this.x_GetFilename()
for i = 1 to nCnt
cFold := cFold.left(cFold.lastIndexOf("\"))
if this.x_DeleteDirectory(cFold)
nPos ++
endif
endfor
bRet = iif(nCnt == nPos, true, false)
endif
return iif(bRet, true, false)
//------------------------------------------------------------//
// flush file writes that are in the cache.
function flush
Local bRet, cFile, oFile
bRet = false
cFile = this.x_GetFilename()
oFile = new file()
if oFile.exists(cFile)
oFile.open(cFile, "W")
if not oFile.handle == -1
bRet := RMM_FlushFileBuffers(int(oFile.handle))
endif
oFile.close()
endif
release object oFile
oFile := null
return iif(bRet, true, false)
//------------------------------------------------------------//
function fullFilename
return this.x_GetFilename()
//------------------------------------------------------------//
// return a value with a read.
function get(cSection, cName)
Local cFile, cRet, nLen
cRet = ""
cFile = this.x_GetFilename()
if this.x_ValidateDirectory(cFile, false)
cRet = space(MAX_LINELENGTH)
nLen = MAX_LINELENGTH
// returns number of characters copied to the buffer,
// not including the terminating null character.
nLen := RMM_GetIniString( ;
"" + cSection, "" + cName, "", cRet, nLen, cFile)
cRet = left(cRet, nLen)
endif
return cRet
//------------------------------------------------------------//
// return an int value.
function getInt(cSection, cName)
return int(val(this.get(cSection, cName)))
//------------------------------------------------------------//
// return a numeric value.
function getNumber(cSection, cName, nDecimals)
Local nRet, nDeci, nValu
if ("" + nDecimals) == "false"
nRet = val(this.get(cSection, cName))
else
nValu = int(val("" + nDecimals))
if nValu > 18
nValu := 18
elseif nValu < 0
nValu := 0
endif
nDeci = set("decimals")
set decimals to (nValu)
nRet = val("" + this.get(cSection, cName))
set decimals to (nDeci)
endif
return nRet
//------------------------------------------------------------//
function release
try
release object this
catch(exception e)
endtry
return
//------------------------------------------------------------//
// return the user\application data folder.
function rootFolder
return this.x_GetDirectory(this.~root)
//------------------------------------------------------------//
// write a value.
function set(cSection, cName, value)
Local bRet, cFile
bRet = false
cFile = this.x_GetFilename()
if this.x_ValidateDirectory(cFile, true)
bRet := RMM_WriteIniString( ;
"" + cSection, "" + cName, "" + value, cFile)
endif
return iif(bRet, true, false)
//------------------------------------------------------------//
// write an int.
function setInt(cSection, cName, value)
return this.set(cSection, cName,;
ltrim(str(int(val("" + value)), 10, 0, "")))
//------------------------------------------------------------//
// write a numeric value with the specified decimals.
function setNumber(cSection, cName, value, nDecimals)
Local bRet, nDeci, nValu
nDeci = set("decimals")
if ("" + nDecimals) == "false"
bRet = this.set(cSection, cName,;
ltrim(str(val("" + value), 20, nDeci, "")))
else
nValu = int(val("" + nDecimals))
if nValu > 18
nValu := 18
elseif nValu < 0
nValu := 0
endif
set decimals to (nValu)
bRet = this.set(cSection, cName,;
ltrim(str(val("" + value), 20, nValu, "")))
set decimals to (nDeci)
endif
return iif(bRet, true, false)
//------------------------------------------------------------//
// restrict folder to an xp/vista compliant folder.
// additional valid root folders can be added in here.
function setRoot(nCsid)
Local bRet
bRet = true
if nCsid == CSIDL_APPDATA
// <user>\Application Data.
// used for user specific files and tables.
elseif nCsid == CSIDL_COMMON_APPDATA
// All Users\Application Data.
// used for shared data files and tables.
elseif nCsid == CSIDL_LOCAL_APPDATA
// <user>\Local Settings\Application Data (non roaming).
// this is commonly a hidden folder.
else
bRet := false
endif
if bRet
this.~root := nCsid
endif
return iif(bRet, true, false)
//------------------------------------------------------------//
// end of public methods.
// private methods melow.
//------------------------------------------------------------//
function x_DeleteDirectory(cFolder)
if not RMM_RemoveDirectory(cFolder)
// try 1 more time due to caches.
RMM_RemoveDirectory(cFolder)
endif
return empty(funique(cFolder + "\????????.txt"))
//------------------------------------------------------------//
// return the directory for nCsid using shfolder.dll.
function x_GetDirectory(nCsid)
Local cRet, nCsid, nLen
nLen = MAX_PATH
cRet = space(nLen)
// next line returns 0 for success.
nLen := RMM_SHGetFolderPath( ;
null, nCsid, 0, null, cRet)
if nLen == 0
// cRet holds the folder in a long name.
if cRet.right(1) == "\"
cRet := cRet.left(cRet.length - 1)
endif
else
cRet := ""
endif
return cRet
//------------------------------------------------------------//
function x_GetDirectoryApplication
return this.x_GetDirectory(this.~root) + "\" +;
ALLTRIM(this.publisher) + "\" +;
ALLTRIM(this.application)
//------------------------------------------------------------//
function x_GetDirectoryPublisher
return this.x_GetDirectory(this.~root) + "\" +;
ALLTRIM(this.publisher)
//------------------------------------------------------------//
function x_GetFilename
return this.x_GetDirectoryApplication() + "\" +;
ALLTRIMSUB(this.subfolder) +;
ALLTRIMINI(this.filename)
//------------------------------------------------------------//
// use the user name logged into windows
// for the default filename.
function x_GetUserName
Local cRet, sBuff, sLen
sBuff = ZEROS(MAX_USERNAME + 1)
cRet = "Default"
sLen = ZEROS(4)
// put the length value into a pointer.
sLen.setByte(0, bitand(MAX_USERNAME, 0xFF))
sLen.setByte(1, bitand(bitzrshift(MAX_USERNAME, 8), 0xFF))
sLen.setByte(2, bitand(bitzrshift(MAX_USERNAME, 16), 0xFF))
sLen.setByte(3, bitand(bitzrshift(MAX_USERNAME, 24), 0xFF))
if RMM_GetUserName(sBuff, sLen)
// the variable pointed to by sLen contains the number
// of characters copied to the buffer,
// including the terminating null character.
// ignore sLen and just find the first chr(0).
cRet := sBuff.left(sBuff.indexof(chr(0)))
endif
return cRet
//------------------------------------------------------------//
function x_InitializeExterns
if not type("RMM_CreateDirectory") == "FP"
extern CLOGICAL RMM_CreateDirectory( ;
CSTRING, CPTR) ;
kernel32 from "CreateDirectoryA"
endif
if not type("RMM_RemoveDirectory") == "FP"
extern CLOGICAL RMM_RemoveDirectory( ;
CSTRING) ;
kernel32 from "RemoveDirectoryA"
endif
if not type("RMM_FlushFileBuffers") == "FP"
extern CLOGICAL RMM_FlushFileBuffers(CHANDLE) ;
kernel32 from "FlushFileBuffers"
endif
if not type("RMM_GetIniString") == "FP"
extern CULONG RMM_GetIniString( ;
CSTRING, CSTRING, CSTRING, CSTRING, CULONG, CSTRING) ;
kernel32 from "GetPrivateProfileStringA"
endif
if not type("RMM_WriteIniString") == "FP"
extern CLOGICAL RMM_WriteIniString( ;
CSTRING, CSTRING, CSTRING, CSTRING) ;
kernel32 from "WritePrivateProfileStringA"
endif
if not type("RMM_GetUserName") == "FP"
extern CLOGICAL RMM_GetUserName(CSTRING, CPTR) ;
advapi32.dll from "GetUserNameA"
endif
if not type("RMM_SHGetFolderPath") == "FP"
try
extern CLONG RMM_SHGetFolderPath( ;
CHANDLE, CINT, CHANDLE, CULONG, CSTRING) ;
shfolder from "SHGetFolderPathA"
catch(exception e)
msgbox( ;
"Invalid initialization of " +;
this.classname + chr(13) +;
"the required file (shfolder.dll) is missing" +;
chr(13),;
this.classname + " " + this.version + " Message",;
16)
endtry
endif
return
//------------------------------------------------------------//
// validate a directory with a file name.
// optionally create the directory.
function x_ValidateDirectory(cFile, bMake)
Local bRet, cTemp, cTest, nPos
bRet = false
if cFile.indexOf(".") > 0
// strip off the filename extension.
cTemp = cFile.left(cFile.indexOf("."))
else
cTemp = "" + cFile
endif
nPos = cTemp.lastIndexOf("\")
if nPos == -1
cTest = "" + cTemp
else
cTest = cTemp.left(nPos)
endif
// there should always be at least 3 "\" characters.
nPos = cTemp.indexOf("\", 3)
do while not (nPos == -1)
cTest := cTemp.left(nPos)
if empty(funique(cTest + "\????????.txt"))
if bMake
RMM_CreateDirectory(cTest, null)
endif
endif
nPos := cTemp.indexOf("\", nPos + 1)
enddo
return not empty(funique(cTest + "\????????.txt"))
//------------------------------------------------------------//
// end of private methods.
//------------------------------------------------------------//
endclass
//---------------------------------------------------------------//
// end of vistaIni class.
//---------------------------------------------------------------//