Paradox Community
Search:

 Welcome |  What is Paradox |  Paradox Folk |  Paradox Solutions |
 Interactive Paradox |  Paradox Programming |  Internet/Intranet Development |
 Support Options |  Classified Ads |  Wish List |  Submissions 


Paradox Programming Articles  |  Beyond Help Articles  |  Tips & Tricks Articles  


Paradox BDE API
Reading and Updating the BDE Configuration File
© 2003 Rick Kelly
www.crooit.com

Preface

A library and example script of all OPAL methods presented is available here in Paradox 9 format. If you have another version, open the PW32BDE library first and save it before running the script.

It is well known that an incorrectly configured BDE can be a source of problems, that together with Windows registry options for items such as opportunistic locking, can lead to application failure and/or table problems requiring repair.

This article deals with using the BDE API exposed in idapi32.dll to interrogate the currently loaded configuration file and make changes under programmatic control. Normally, applications must include initialization and exit calls to BDE. Paradox itself is taking care of these details so our approach can concentrate on using the BDE API knowing we've got a working and validated BDE session.

Be aware that it is up to each application to ensure that BDE options are updated correctly. The presented methods only include basic error checking. Paradox and other BDE applications will require a shutdown/restart before applied changes are used.

For additional BDE information, see the following articles:

BDE Configuration Suggestions by Liz Woodhouse

FAQ:PdoxWin:Net File Rules:2000.01.18

FAQ:PdoxWin:Paradox & BDE Limitations:2002.07.18

General BDE Limits

The following topics are presented in this article:
  1. Retrieval of basic BDE environmental values
  2. Retrieval of BDE configuration options
  3. Updating of BDE configuration options

BDE and Win32 API

Many functions use structures which are not directly supported in Paradox. Pascal Hutton pioneered the basic technique for using structures and you are encouraged to review his article at:

http://www.thedbcommunity.com/code/structures.htm

This is the basic technique used in this series in passing and retrieving structures when calling Win32 and BDE functions. The following Win32 API’s USES clauses are not addressed in this article.
Uses "kernel32.dll"
  GlobalAlloc(
    wFlags cLong,
    dwBytes cLong) cLong [stdcall]
  GlobalFree(hMem cLong) cLong [stdcall]
  GetStringSize(cString cLong) cLong [stdcall "lstrlenA"]
  MoveFromMemory(
    wDestination cPtr,
    wSource cLong,
    wLength cLong) cLong [stdcall "RtlMoveMemory"]
  MoveToMemory(
    wDestination cLong,
    wSource cPtr,
    wLength cLong) cLong [stdcall "RtlMoveMemory"]
  GetModuleHandle(lpstrModule cPtr) cLong [stdcall "GetModuleHandleA"]
  VerLanguageName(
    wLang cLong,
    szLang cPtr,
    nSize cLong) cLong [stdcall "VerLanguageNameA"]
endUses
Uses "version.dll"
  GetFileVersionInfoSize(
    lptstrFilename cPtr,
    lpdwHandle cPtr) cLong [stdcall "GetFileVersionInfoSizeA"]
  GetFileVersionInfo(
    lptstrFilename cPtr,
    dwHandle cLong,
    dwLength cLong,
    lpData cLong) cLong [stdcall "GetFileVersionInfoA"]
  VerQueryValue(
    pBlock cLong,
    lpSubBlock cPtr,
    lpBuffer cPtr,
    puLen cPtr) cLong [stdcall "VerQueryValueA"]
endUses
Our basic USES clause for the BDE API is:
Uses "idapi32.dll"
  DbiGetErrorString(
    lpError cLong,
    lpDescription cLong) cLong [stdcall]
  DbiGetSysVersion(lpVersion cLong) cLong [stdcall]
  DbiGetSysInfo(lpSysInfo cLong) cLong [stdcall]
  DbiGetSysVersion(lpVersion cLong) cLong [stdcall]
  DbiGetSysInfo(lpSysInfo cLong) cLong [stdcall]
  DbiGetSysConfig(lpSysConfig cLong) cLong [stdcall]
  DbiOpenCfgInfoList(
    hCfg cLong,
    eOpenMode cLong,
    eConfigMode cLong,
    lpstrCfgPath cPtr,
    lphCur cPtr) cLong [stdcall]
  DbiSetToBegin(hCur cLong) cLong [stdcall]
  DbiGetNextRecord(
    hCur cLong,
    eLock cLong,
    lpRecBuf cLong,
    lpRecProps cLong) cLong [stdcall]
  DbiModifyRecord (
    hCursor cLong,
    pRecBuf cLong,
    bFreeLock cLong) cLong [stdcall]
  DbiCloseCursor(hCur cLong) cLong [stdcall]
endUses
Constants referenced throughout our examples are:
Const
;
; Milliseconds in one day
;
  cnOneDay    = 86400000.0
;
; BDE Error Codes
;
  cnDBIErrorNone   = 0
  cnDBIErrorEOF   = 8706
;
; BDE API Options
;
  cnDBIReadOnly   = 0
  cnDBIReadWrite   = 1
  cnDBINoLock   = 0
  cnDBIReadLock   = 1
  cnDBIWriteLock   = 2
  cnFreeLock    = 1
;
; BDE Structure Sizes
;
  cnSysInfo    = 14
  cnSysVersion   = 12
  cnSysConfig    = 346
endConst
Generally, the BDE API return BDE error codes for a failure. The method DbiGetErrorString takes a BDE error code and returns its associated descriptive text. The following method is available when the descriptive text is needed.
method GetBDEErrorMessage(liError LongInt) String
;
; Given an error code, get the description
;
var
  stErrorMessage  String
  liMemory        LongInt
  liReturn        LongInt
endVar
;
; Check for any of our own error codes first
;
  switch
    case liError = -1 :
      stErrorMessage = "Unable to locate idapi32.dll"
    otherwise :
      liMemory = cmW32GlobalAlloc(256)
      liReturn = DbiGetErrorString(
        liError,
        liMemory)
      switch
        case liReturn = cnDbiErrorNone :
          stErrorMessage = cmW32MoveFixedStringFromMemory(
            liMemory,
            256)
        otherwise :
          stErrorMessage = "Unknown"
      endSwitch
      liReturn = cmW32GlobalFree(liMemory)
  endSwitch
  return "[" + strval(liError) + "]" + stErrorMessage
endMethod

Retrieval of Basic BDE Environmental Values

The following BDE API’s are used to retrieve session statistics.
  1. DbiGetSysVersion
    1. BDE Version
    2. Client Version
    3. BDE Date and Time
  2. DbiGetSysInfo
    1. Buffer Space (KB)
    2. Heap Space (KB)
    3. Number Active Drivers
    4. Number Active Clients
    5. Number Active Sessions
    6. Number Active Databases
    7. Number Active Cursors
  3. DbiGetSysConfig
    1. Net Protocol
    2. Net Share
    3. Net Type
    4. Net User Name
    5. Net Configuration File Path and Name
    6. Net Language
Additionally, we will return the date, version and path of the idapi32.dll file itself. The following Paradox Record Type is defined as the returned structure.
Type
  BDESessionInfo =
    Record
      Idapi32DLLPath    String
      Idapi32DLLDate    DateTime
      Idapi32DLLVersion String
      BDEVersion        String
      BDEClientVersion  String
      BDEDate           DateTime
      BufferSpace       SmallInt
      HeapSpace         SmallInt
      ActiveDrivers     SmallInt
      ActiveClients     SmallInt
      ActiveSessions    SmallInt
      ActiveDatabases   SmallInt
      ActiveCursors     SmallInt
      NetProtocol       SmallInt
      NetShare          Logical
      NetType           String
      NetUserName       String
      NetConfigFile     String
      NetLanguage       String
    endRecord
endType
The most reliable indicator of which BDE version is running is the idapi32.dll file. Generally, the timestamp indicates the version, i.e. 5.11 pm for version 5.11. A better way to check is to right click the idapi32.dll file, select Properties and view the Version tab. In our included method, we will first attempt to retrieve the version information from idapi32.dll, and if that fails, use the timestamp. The Win32 API calls and procedure for interrogating the idapi32.dll are fairly complicated. Developers of EXE/DLL file types have the option of including versioning using the MS standard methodology and multiple languages and code pages are supported. As I do not have availability to non-English BDE versions, it may be necessary to modify the code for the language and code page values. See comments in the PW32BDE library procedure cmGetFileVersionInfo for comments on how to check the available language and code pages if necessary.

The basic steps involved are:
  1. Retrieve the file version info structure
  2. Retrieve the default language and code page values
  3. Build an interrogation key
  4. Interrogate the file version info structure and retrieve the version string
The following OPAL procedures are used.
Proc cmGetFileVersionInfo(stFileName String) String
var
  liHandle     LongInt
  liSize       LongInt
  liReturn     LongInt
  liPointer    LongInt
  liBufferSize LongInt
  liBuffer     LongInt
  liString     LongInt
  siLanguage   SmallInt
  siCodePage   SmallInt
  stSubBlock   String
  stVersion    String
endVar
  liHandle = 0
  stVersion = blank()
  liSize = cmW32GetFileVersionInfoSize(stFileName,liHandle)
  switch
    case liSize < 1 :
    otherwise :
;
; Allocate file info version structure
;
      liPointer = cmW32GlobalAlloc(liSize)
      liReturn = cmW32GetFileVersionInfo(
        stFileName,
        liHandle,
        liSize,
        liPointer)
      switch
        case liReturn = 1 :
;
; Retrieve the Language and CodePage values
;
          liBuffer = 0
          liBufferSize = 0
          liReturn = cmW32VerQueryValue(
            liPointer,
            "\\VarFileInfo\\Translation",
            liBuffer,
            liBufferSize)
          switch
            case liReturn = 0 or liBufferSize = 0 :
              siLanguage = 1033
              siCodePage = 1252
            otherwise :
              siLanguage = 0
              siCodePage = 0
              siLanguage =
                cmW32MoveSmallIntFromMemory(liBuffer)
              siCodePage = cmW32MoveSmallIntFromMemory(liBuffer + 2)
          endSwitch
;
; Build the SubBlock Key
;
          stSubBlock =
            cmGetFileInfoSubBlock(siLanguage,siCodePage)
;
; Allocate space for file info strings
;
          liString = cmW32GlobalAlloc(100)
;
; Retrieve File Version
;

          stVersion = cmGetFileInfoString(
            liPointer,
            liString,
            stSubBlock,
            "FileVersion")

;
; Free memory used for file info string
;
          cmW32GlobalFree(liString)
      endSwitch
;
; Free memory used for file info version structure
;
      cmW32GlobalFree(liPointer)
  endSwitch
  return stVersion
endProc
Proc cmGetFileInfoSubBlock(
  siLanguage SmallInt,
  siCodePage SmallInt) String
;
; Build the SubBlock Key
;
var
  stAny      String
  stSubBlock String
endVar
  stAny = toHex(siLanguage)
  stSubBlock = stAny.substr(7,4)
  stAny = toHex(siCodePage)
  return stSubBlock + stAny.substr(7,4)
endProc
Proc cmGetFileInfoString(
  var liPointer LongInt,
  var liString LongInt,
  stSubBlock String,
  stStringType String) String
;
; Retrieve file info strings from version block
; pointed to by liPointer
;
var
  liReturn     LongInt
  liStringSize LongInt
  stAny        String
endVar
  liStringSize = 0
  stAny = blank()
  liReturn = cmW32VerQueryValue(
    liPointer,
    "\\StringFileInfo\\" +
    stSubBlock +
    "\\" +
    stStringType,
    liString,
    liStringSize)
  switch
    case liReturn = 0 or
      liStringSize < 2 :
    otherwise :
      stAny = cmW32MoveStringFromMemory(liString)
  endSwitch
  return stAny
endProc
Proc cmW32GetFileVersionInfo(
  stFileName String,
  var liHandle LongInt,
  var liSize LongInt,
  var liBuffer LongInt) LongInt
;
; Retrieve file version info structure
;
  return GetFileVersionInfo(
    stFileName,
    liHandle,
    liSize,
    liBuffer)
endProc
Proc cmW32GetFileVersionInfoSize(
  stFileName String,
  var liHandle LongInt) LongInt
  return GetFileVersionInfoSize(stFileName,liHandle)
endProc
Proc cmW32GetModuleHandle(stModuleName String) LongInt
  return GetModuleHandle(stModuleName)
endProc
Proc cmW32VerLanguageName(siLanguage LongInt) String
;
; Return name of given language id
;
var
  stAny    String
  liReturn LongInt
endVar
  stAny = space(256)
  liReturn = VerLanguageName(
    siLanguage,
    stAny,
    256)
  return stAny.rTrim()
endProc
Proc cmW32VerQueryValue(
  var liVersionBlock LongInt,
  stSubBlock String,
  var liBuffer LongInt,
  var liBufferSize LongInt) LongInt
  return VerQueryValue(
    liVersionBlock,
    stSubBlock,
    liBuffer,
    liBufferSize)
endProc
Now we are ready to search for the idapi32.dll date and version. The basic steps are:
  1. Retrieve the path of idapi32.dll from the registry
  2. Retrieve the version using the Win32 api’s
  3. If the version is not available, use the timestamp
Proc cmIdapi32Info(
  var SessionInfo BDESessionInfo,
  var liError LongInt) Logical
;
; Retrieve Idapi32.dll datetime stamp and version
;
var
  loReturn Logical
  fs       FileSystem
endVar
;
; Locate Idapi32.dll using path stored in registry
;
  SessionInfo.Idapi32DLLPath = getRegistryValue(
    "software\\borland\\database engine",
    "dllpath",
    regKeyLocalMachine)
;
; See if we can extract the version directly from Idapi32.dll
;
  SessionInfo.Idapi32DLLVersion =
    cmGetFileVersionInfo(SessionInfo.Idapi32DLLPath + "\\idapi32.dll")
  loReturn = fs.findFirst(SessionInfo.Idapi32DLLPath + "\\idapi32.dll")
  switch
    case loReturn = True :
      SessionInfo.Idapi32DLLDate = fs.time()
;
; If version was not extracted earlier, use the timestamp as the version
;
      switch
        case SessionInfo.Idapi32DLLVersion.isBlank() = True :
          SessionInfo.Idapi32DLLVersion =
            format("W4.2",
              ((hour(SessionInfo.Idapi32DLLDate) * 100.0)
              + minute(SessionInfo.Idapi32DLLDate))
              / 100.0)
      endSwitch
    otherwise :
    liError = -1
  endSwitch
  return loReturn
endProc
DbiGetSysVersion

DbiGetSysVersion returns:
  1. BDE Version
  2. Client Version
  3. BDE Date and Time
The versions returned typically reflect the BDE major version, i.e 4 or 5. In the following procedure that uses DbiGetSysVersion, cnOneDay is a constant equal to 86400000.0 which is the number of milliseconds in one day used to calculate a DateTime Type.
Proc cmDbiGetSysVersion(
  var SessionInfo BDESessionInfo,
  var liError LongInt) Logical
;
; Retrieve BDE version, date and time
;
var
  liMemory LongInt
  liReturn LongInt
  daAny    Date
endVar
  liMemory = cmW32GlobalAlloc(cnSysVersion)
  liError = DbiGetSysVersion(liMemory)
  switch
    case liError = cnDBIErrorNone :
      SessionInfo.BDEVersion =
        format("W4.2",cmW32MoveSmallIntFromMemory(liMemory) /
          100.0)
      SessionInfo.BDEClientVersion =
        format("W4.2",cmW32MoveSmallIntFromMemory(liMemory + 2)
          / 100.0)
      daAny = date(cmW32MoveLongIntFromMemory(liMemory + 4))
;
; BDE 5.2 returns a bogus year of 1901
;
      switch
        case year(daAny) < 1950 :
          daAny = date(
            month(daAny),
            day(daAny),
            year(daAny) + 100)
      endSwitch
      SessionInfo.BDEDate = datetime(number(daAny) * cnOneDay) +
        cmW32MoveLongIntFromMemory(liMemory + 8)
  endSwitch
  liReturn = cmW32GlobalFree(liMemory)
  return liError = cnDBIErrorNone
endProc
DbiGetSysInfo

DbiGetSysInfo returns:
  1. Buffer Space (KB)
  2. Heap Space (KB)
  3. Number Active Drivers
  4. Number Active Clients
  5. Number Active Sessions
  6. Number Active Databases
  7. Number Active Cursors
These are basic BDE statistics that may fluctuate with each call.
Proc cmDbiGetSysInfo(
  var SessionInfo BDESessionInfo,
  var liError LongInt) Logical
;
; Retrieve Session Statistics
;
var
  liMemory LongInt
  liReturn LongInt
endVar
  liMemory = cmW32GlobalAlloc(cnSysInfo)
  liError = DbiGetSysInfo(liMemory)
  switch
    case liError = cnDBIErrorNone :
      SessionInfo.BufferSpace =
        cmW32MoveSmallIntFromMemory(liMemory)
      SessionInfo.HeapSpace =
        cmW32MoveSmallIntFromMemory(liMemory + 2)
      SessionInfo.ActiveDrivers =
        cmW32MoveSmallIntFromMemory(liMemory + 4)
      SessionInfo.ActiveClients =
        cmW32MoveSmallIntFromMemory(liMemory + 6)
      SessionInfo.ActiveSessions =
        cmW32MoveSmallIntFromMemory(liMemory + 8)
      SessionInfo.ActiveDatabases =
        cmW32MoveSmallIntFromMemory(liMemory + 10)
      SessionInfo.ActiveCursors =
        cmW32MoveSmallIntFromMemory(liMemory + 12)
  endSwitch
  liReturn = cmW32GlobalFree(liMemory)
  return liError = cnDBIErrorNone
endProc
DbiGetSysConfig

DbiGetSysConfig returns:
  1. Net Protocol
  2. Net Share
  3. Net Type
  4. Net User Name
  5. Net Configuration File Path and Name
  6. Net Language
The configuration file path and name returned is the one currently in use by Paradox. It can be the BDE default or another supplied via the -o option on the startup command line.
Proc cmDbiGetSysConfig(
  var SessionInfo BDESessionInfo,
  var liError LongInt) Logical
;
; Retrieve Configuration
;
var
  liMemory LongInt
  liReturn LongInt
endVar
  liMemory = cmW32GlobalAlloc(cnSysConfig)
  liError = DbiGetSysConfig(liMemory)
  switch
    case liError = cnDBIErrorNone :
      SessionInfo.NetProtocol =
        cmW32MoveSmallIntFromMemory(liMemory + 2)
      SessionInfo.NetShare =
        iif(cmW32MoveSmallIntFromMemory(liMemory + 4) =
          1,True,False)
      SessionInfo.NetType =
        cmW32MoveFixedStringFromMemory(liMemory + 6,32)
      SessionInfo.NetUserName =
        cmW32MoveFixedStringFromMemory(liMemory + 38,15)
      SessionInfo.NetConfigFile =
        cmW32MoveFixedStringFromMemory(liMemory + 53,260)
      SessionInfo.NetLanguage =
        cmW32MoveFixedStringFromMemory(liMemory + 314,32)
  endSwitch
  liReturn = cmW32GlobalFree(liMemory)
  return liError = cnDBIErrorNone
endProc
Now that we have all the supporting routines for setting our BDESessionInfo record structure, let’s put it all together.
method GetBDESessionInfo(
  var SessionInfo BDESessionInfo,
  var liError LongInt) Logical
;
; Retrieve Session configuration and statistics
;
var
  loReturn Logical
endVar
;
; Initialize variables
;
  loReturn = False
  liError = 0
  SessionInfo.Idapi32DLLPath = blank()
  SessionInfo.Idapi32DLLDate = blank()
  SessionInfo.Idapi32DLLVersion = blank()
  SessionInfo.BufferSpace = 0
  SessionInfo.HeapSpace = 0
  SessionInfo.ActiveDrivers = 0
  SessionInfo.ActiveClients = 0
  SessionInfo.ActiveSessions = 0
  SessionInfo.ActiveDatabases = 0
  SessionInfo.ActiveCursors = 0
  SessionInfo.NetProtocol = 0
  SessionInfo.NetShare = False
  SessionInfo.NetType = blank()
  SessionInfo.NetUserName = blank()
  SessionInfo.NetConfigFile = blank()
  SessionInfo.NetLanguage = blank()
;
; Retrieve session configurations
;
  switch
;
; Idapi32.dll Info
;
    case cmIdapi32Info(SessionInfo,liError) = False :
    case cmDbiGetSysVersion(SessionInfo,liError) = False :
    case cmDbiGetSysInfo(SessionInfo,liError) = False :
    otherwise :
      loReturn = cmDbiGetSysConfig(SessionInfo,liError)
  endSwitch
  return loReturn
endMethod

Retrieval of BDE Configuration Options

Anyone who has used the BDE Configuration Editor has seen the many options supported in BDE configuration files. Generally, a subset of these are of concern to Paradox applications. Our approach will allow access to the full set of options and our examples will show access to the most common subset.

The BDE configuration file is structured much like the Windows registry. In the Windows registry, there are several hives such as HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE. Think of the BDE configuration file as having one, unnamed hive. Access is by providing a key path which allows the retrieval of named values all which are of String Type. When we supply a path, it works like a filter for the associated cursor.

Common paths of interest might be:
  1. \system\init
    1. AUTO ODBC
    2. DATA REPOSITORY
    3. DEFAULT DRIVER
    4. LANGDRIVER
    5. LOCAL SHARE
    6. LOW MEMORY USAGE LIMIT
    7. MAXBUFSIZE
    8. MAXFILEHANDLES
    9. MEMSIZE
    10. MINBUFSIZE
    11. MTS POOLING
    12. SHAREDMEMLOCATION
    13. SHAREDMEMSIZE
    14. SQLQRYMODE
    15. SYSFLAGS
    16. VERSION
  2. \system\formats\date
    1. FOURDIGITYEAR
    2. LEADINGZEROD
    3. LEADINGZEROM
    4. MODE
    5. SEPARATOR
    6. YEARBIASED
  3. \system\formats\time
    1. AMSTRING
    2. MILSECONDS
    3. PMSTRING
    4. SECONDS
    5. TWELVEHOUR
  4. \system\formats\number
    1. DECIMALDIGITS
    2. DECIMALSEPARATOR
    3. LEADINGZERON
    4. THOUSANDSEPARATOR
  5. \drivers\paradox\init
    1. LANGDRIVER
    2. NET DIR
    3. TYPE
    4. VERSION
  6. \drivers\paradox\table create
    1. BLOCKSIZE
    2. FILLFACTOR
    3. LEVEL
    4. STRICTINTEGRITY
Using OPAL, a common way to search a table involves a scan/endScan loop with an open TCursor. Our access to the BDE configuration file works much the same way. The basic approach is:
  1. Open a cursor for the configuration file
  2. Set the cursor to the beginning or root path
  3. Scan using our cursor
  4. Save the named values found
  5. Close our cursor
We will use a DynArray to store our found named values. The value name is the key and the value is associated. To pass a Dynarray Type around, the following definition is used.
Type
 dyConfig = DynArray[] String
endType
Opening the BDE Configuration File

DbiOpenConfigInfoList is the BDE API to open the configuration file. The following procedure supports this API.
Proc cmOpenConfigFile(
  stPath String,
  liOpenMode LongInt,
  liConfigMode LongInt,
  var liCursor LongInt,
  var liError LongInt) Logical
;
; Open BDE Configuration File
;
; Returns a cursor handle to an in-memory table
;
  liError = DbiOpenCfgInfoList(
    0,
    liOpenMode,
    liConfigMode,
    stPath,
    liCursor)
  return liError = cnDbiErrorNone
endProc
liOpenMode is set for either read-only or write access. stPath is the access key or filter, and if successful, a cursor is returned in liCursor.

Setting Cursor To Beginning

After a successful open, the BDE API DbiSetToBegin positions the cursor to the beginning of our in-memory table.
Proc cmSetToBegin(
  var liCursor LongInt,
  var liError LongInt) Logical
;
; Position cursor to beginning of table
;
  liError = DbiSetToBegin(liCursor)
  return liError = cnDbiErrorNone
endProc
Scanning Our Cursor

The BDE API DbiGetNextRecord will sequentially retrieve records using a supplied cursor. Optionally, we can also request a record lock. The record is returned in a record buffer referenced by liMemory.
Proc cmGetNextRecord(
  var liCursor LongInt,
  var liMemory LongInt,
  liLockOption LongInt,
  var liError LongInt) Logical
;
; Retrieve Next Record
;
  liError = DbiGetNextRecord(
    liCursor,
    liLockOption,
    liMemory,
    0)
  return liError = cnDbiErrorNone
endProc
Closing Our Cursor

If we have an open cursor, it is good practice to close it and release any associated resources.
Proc cmCloseCursor(var liCursor LongInt)
;
; Close cursor and release resources
;
var
  liReturn  LongInt
endVar
  liReturn = DbiCloseCursor(liCursor)
endProc
Putting it all together

Now we are ready to retrieve BDE configuration values and build our returned DynArray. Note that the DynArray is not emptied first. This is to support a sequence of calls to different portions of the BDE configuration file and accumulate all values into a single DynArray.
method ReadBDEConfigurationFile(
  stPath String,
  var dyFields dyConfig,
  var liError LongInt) Logical
;
; Read BDE Configuration File
;
; Returns all the nodes in the configuration
; file accessible by stPath
;
;
var
  liCursor LongInt
  loReturn Logical
  loScan   Logical
  liMemory LongInt
  liReturn LongInt
endVar
  loReturn = False
  liCursor = 0
  switch
    case cmOpenConfigFile(
      stPath,
      cnDbiReadOnly,
      0,
      liCursor,
      liError) = False :
    case cmSetToBegin(
      liCursor,
      liError) = False :
    otherwise :
      liMemory = cmW32GlobalAlloc(1024)
      loScan = True
      while loScan = True
        switch
          case cmGetNextRecord(
              liCursor,
              liMemory,
              cnDBINoLock,
              liError) = True :
            dyFields[cmW32MoveFixedStringFromMemory(liMemory,160)] =
              cmW32MoveFixedStringFromMemory(liMemory + 162,160)
          otherwise :
            loScan = False
            switch
              case liError = cnDBIErrorEOF :
                loReturn = True
                liError = cnDbiErrorNone
            endSwitch
        endSwitch
      endWhile
      liReturn = cmW32GlobalFree(liMemory)
   endSwitch
;
; Close cursor, if opened
;
  switch
    case liCursor <> 0 :
      cmCloseCursor(liCursor)
  endSwitch
  return loReturn
endMethod

Updating of BDE Configuration Options

Review the previous section on retrieval of BDE configuration options. For updating, we need only introduce one additional BDE API. DbiModifyRecord is used to update a record previously retrieved by DbiGetNextRecord.
Proc cmModifyRecord(
  var liCursor LongInt,
  var liMemory LongInt,
  liFreeLock LongInt,
  var liError LongInt) Logical
;
; Update Record
;
  liError = DbiModifyRecord(
    liCursor,
    liMemory,
    liFreeLock)
  return liError = cnDbiErrorNone
endProc
In the cursor scan process, we will be retrieving records with a write lock and releasing the lock after the update. If the update is successful, the value name is removed from the passed DynArray. This will allow the caller to examine the DynArray upon successful return and see if there were values that could not be found.
method UpdateBDEConfigurationFile(
  stPath String,
  var dyFields dyConfig,
  var liError LongInt) Logical
;
; Read BDE Configuration File
;
; Updates all the nodes in the configuration
; file accessible by stPath and referenced
; in dyFields
;
var
  liCursor    LongInt
  loReturn    Logical
  loScan      Logical
  liMemory    LongInt
  liReturn    LongInt
  stNodeName  String
  stNodeValue String
  liNodeSize  LongInt
endVar
  loReturn = False
  liCursor = 0
  switch
    case cmOpenConfigFile(
      stPath,
      cnDBIReadWrite,
      0,
      liCursor,
      liError) = False :
    case cmSetToBegin(
      liCursor,
      liError) = False :
    otherwise :
      liMemory = cmW32GlobalAlloc(1024)
      loScan = True
      while loScan = True
        switch
          case cmGetNextRecord(
              liCursor,
              liMemory,
              cnDBIWriteLock,
              liError) = True :
            stNodeName =
              cmW32MoveFixedStringFromMemory(liMemory,160)
            switch
;
; If item is found in dyFields, update BDE configuration
;
              case dyFields.contains(stNodeName) = True :
                stNodeValue = dyFields[stNodeName]
                liNodeSize = stNodeValue.size() + 1
                MoveToMemory(
                  liMemory + 162,
                  stNodeValue,
                  liNodeSize)
                loScan = cmModifyRecord(
                  liCursor,
                  liMemory,
                  cnFreeLock,
                  liError)
;
; Remove item. This is so caller can check if there were
; items not found.
;
                dyFields.removeItem(stNodeName)
            endSwitch
          otherwise :
            loScan = False
            switch
              case liError = cnDBIErrorEOF :
                loReturn = True
                liError = cnDbiErrorNone
            endSwitch
        endSwitch
      endWhile
      liReturn = cmW32GlobalFree(liMemory)
  endSwitch
;
; Close cursor, if opened
;
  switch
    case liCursor <> 0 :
      cmCloseCursor(liCursor)
  endSwitch
  return loReturn
endMethod

Acknowledgments

Rodney Wise for his feedback, enthusiasm and tireless effort in testing.


Conclusion

We now have methods that support interrogation and updating of many BDE session and configuration options that allow Paradox applications to better manage and control their runtime environment.


Discussion of this article


 Feedback |  Paradox Day |  Who Uses Paradox |  I Use Paradox |  Downloads 


 The information provided on this Web site is not in any way sponsored or endorsed by Corel Corporation.
 Paradox is a registered trademark of Corel Corporation.


 Modified: 03 Jun 2003
 Terms of Use / Legal Disclaimer


 Copyright © 2001- 2003 Paradox Community. All rights reserved. 
 Company and product names are trademarks or registered trademarks of their respective companies. 
 Authors hold the copyrights to their own works. Please contact the author of any article for details.