(*****************************************************************************)
(* MODULE: BTRWOBJ*                                                          *)
(* RIGHTS: Reggatta Systems, Inc. - COPYRIGHT 1995 - 2000                    *)
(* DESCR.: This module contains the Btrieve Table Object                     *)
(*                                                                           *)
(*                                                                           *)
(* NOTES :                                                                   *)
(*                                                                           *)
(* TWinBtr:            This object is the Btrieve Table Object.              *)
(*                                                                           *)
(*                                                                           *)
(* CHANGES:                                                                  *)
(* ------------------------------------------------------------------------- *)
(*                                                                           *)
(* 11/02/95 - PGB      Added support for Data only files.  When the table is *)
(*                     opened, the flag FDataOnly is set to TRUE if the table*)
(*                     has no indexes.  The calls First, Last, Next, and     *)
(*                     Previous have been changed to test the flag, and if   *)
(*                     set, then use the Step operations accordingly.        *)
(*                                                                           *)
(* 11/18/95 - PGB      Changed call to Btrieve interface to use the BtrCall  *)
(*                     function.  Previously, this function was called       *)
(*                     indirectly with the length of the key hard-coded to   *)
(*                     255 characters.  Now the current key length is used   *)
(*                     which should result in faster response.               *)
(*                                                                           *)
(* 11/20/95 - PGB      Added support to open call for Owner name.  Changes   *)
(*                     were also made in BTRTABLE to extract the Owner from  *)
(*                     the TableName property of the TTable.                 *)
(*                                                                           *)
(* 01/20/95 - PGB      Added new Property VarBufferSize which can be used to *)
(*                     temporarily set the buffer length to a smaller size   *)
(*                     for use with Btrieve note fields.  Please note that   *)
(*                     the setting only works for the next call to low_level *)
(*                     and then is reset to the normal size. This property   *)
(*                     behaves like the IOResult variable in Delphi where    *)
(*                     once it is read, it is reset.                         *)
(*                                                                           *)
(*****************************************************************************)
Unit BtrWObj;
{$I BSE.INC}
{$I BAPI.INC}
Interface
Uses
  Windows,

  BseTypes,
  BtrTypes,
  BtrIntrf;

{$I BTRIEVE.INC}
  {$OPTIMIZATION OFF}    { Without this, Delphi 2.0 gets rid of Btrieve FCB }

Type
  PBtrBookMark = ^TBtrBookMark;
  TBtrBookMark =
  Packed Record
    Position : Longint;
    Buffer   : TttKeyBuffer;
  end;

  PBtrClientID = ^TBtrClientID;
  TBtrClientID = Array[1..16] of Byte;

  TWinBtr =
  Class( TObject )
    Private
      FStatus       : SmallInt;
      FBuffSize     : LongInt;
      FVariableSize : LongInt;
      FActBuffSize  : LongInt;
      FInternalBuff : Pointer;
      FCurrentBuff  : Pointer;
      FisOpen       : Boolean;
      FKeyBuffer    : TttKeyBuffer;
      FPosBlock     : File_FCB_Type;
      FFileStats    : TFileSpecs;
      FKeyNumber    : ShortInt;
      FLockBias     : SmallInt;
      FLockRec      : Longint;
      FDataOnly     : Boolean;
      FIgnoreSize   : Boolean;
      FClientID     : TBtrClientID;
      FUseClientID  : Boolean;

      Procedure   SetBufferSize( BS : LongInt );
      Procedure   SetBufferAddress( P : Pointer );
      Function    WasSuccess : Boolean;
      Function    GetRecords : Longint;
      Function    GetIndexes : Word;
      Function    Item_Position : Longint;
      Procedure   SetToItem( P : Longint );
      Function    WasPartialRec : Boolean;
      Function    GetStatus : SmallInt;
      Procedure   SetVarRecSize( Size : LongInt );
      Function    GetVarRecSize : LongInt;

    Public
      Property BufferSize : LongInt
        Read  FBuffSize
        Write SetBufferSize;
      Property BufferAddress : Pointer
        Read  FInternalBuff
        Write SetBufferAddress;
      Property Indexes : Word
        Read  GetIndexes;
      Property IsOpen : Boolean
        Read  FisOpen
        Write FisOpen;
      Property IgnoreSizeError : Boolean
        Read  FIgnoreSize
        Write FIgnoreSize;
      Property ActualBufferSize : LongInt
        Read  FActBuffSize;
      Property LockBias : SmallInt
        Read  FLockBias
        Write FLOckBias;
      Property LockedRec : Longint
        Read  FLockRec
        Write FLockRec;
      Property KeyNumber : ShortInt
        Read  FKeyNumber
        Write FKeyNumber;
      Property KeyBuffer : TttKeyBuffer
        Read  FKeyBuffer
        Write FKeyBuffer;
      Property PartialRec : Boolean
        Read  WasPartialRec;
      Property Records : Longint
        Read  GetRecords;
      Property RecPosition : LongInt
        Read  Item_Position
        Write SetToItem;
      Property Status : SmallInt
        Read  GetStatus
        Write FStatus;
      Property Success : Boolean
        Read WasSuccess;
      Property VarBufferSize : LongInt
        Read GetVarRecSize
        Write SetVarRecSize;

      Constructor Create( pClientID : pBtrClientID );
      Destructor  Destroy; Override;

      Procedure   LowLevel(  Operation : SmallInt );
      Procedure   Special( Op : SmallInt; P : Pointer; Size : LongInt );
      Procedure   GetVersion( Var Version, Revision : SmallInt; Var EngType : Char );

      Procedure   Open( Name, TableOwner : PChar; Open_Mode : ShortInt );
      Procedure   Close;

      Procedure   First_Item;
      Procedure   Last_Item;
      Procedure   Next_Item;
      Procedure   Previous_Item;
      Procedure   Insert_Item;
      Procedure   Update_Item;
      Procedure   Delete_Item;

      Procedure   ClearKeyBuffer( Size : Word );
      Procedure   Find_Item( P : Pointer; Size : Word; Key : ShortInt );
      Procedure   Find_Item_Special( action : SmallInt; P : Pointer; Size : Word; Key : ShortInt );

      Procedure   RemoveBuffer;

      Procedure   ResetLockBias;
      Procedure   Lock_Item;
      Procedure   UnLock_Item;

      Procedure   Item_Direct( P : Longint );

      Procedure   LoadFileStats;
      Procedure   GetFileStats( Var T : TFileSpecs );

      Procedure   Record_Size( var size : LongInt );
      Procedure   Record_Count( var count : Longint );

      Procedure   Index_Count( var count : Word );
      Procedure   Page_Size( var count : Word );

      Function    IndexHasACS : Boolean;
      Procedure   GetIndexACS( P : pACSSpec );

      Procedure   BeginTransaction( Concurrent : Boolean );
      Procedure   EndTransaction;
      Procedure   AbortTransaction;

      Procedure   AddIndex( P : Pointer; Segments : Word; IndexNo : SmallInt );
      Procedure   DropIndex( i : ShortInt );

      Procedure   FindPercentage( ByKeyPos : Boolean; Var Percentage : Longint );
      Procedure   GetByPercentage( ByKeyPos : Boolean; Percentage : Longint );

      Procedure   CloneTable( NewName : PChar );
      Function    IsRecordLocked : Boolean;
      Procedure   ShutDownClientSession;

      Procedure   SetDirectory( Directory : PChar );
      Procedure   GetDirectory( Directory : PChar; Size : Word );
  end;

Const
  CONCURRENTTRANSACTWAITBIAS : SmallInt = ISAM_NOWAIT_TRANSACT_BIAS;

Implementation
Uses
  SysUtils,
  BseUtils,

  BtrErrs;


Constructor TWinBtr.Create( pClientID : pBtrClientID );
begin
  Inherited Create;
  KeyNumber := WBTRV_DEFAULT_KEY;
  ResetLockBias;
  FUseClientID := ( pClientID <> NIL );
  If FUseClientID then
    Move( pClientID^, FClientID, SizeOf( FClientID ) );
end;


Destructor TWinBtr.Destroy;
begin
  If FisOpen then
    Close;
  RemoveBuffer;
  Inherited Destroy;
end;


Function TWinBtr.WasPartialRec : Boolean;
begin
  Result := ( FStatus = ISAM_WRONGBUFFERSIZE );
end;


Procedure TWinBtr.SetBufferSize( BS : LongInt );
begin
  FStatus := ISAM_SUCCESS;
  if ( BS <> FBuffSize ) then
  begin
    RemoveBuffer;
    {$I-} GetMem( FInternalBuff, BS ); {$I+}
    If ( IOResult = 0 ) then
    begin
      FBuffSize     := BS;
      FVariableSize := BS;
      FCurrentBuff  := FInternalBuff;
    end
    else
    begin
      FVariableSize := 0;
      FStatus       := ISAM_WRONGBUFFERSIZE;
    end;
  end;
end;


Procedure TWinBtr.RemoveBuffer;
begin
  If Assigned( FInternalBuff ) then
  begin
    {$I-} FreeMem( FInternalBuff, FBuffSize ); {$I+}
    FStatus := IOResult;
  end;
  FInternalBuff := NIL;
  FCurrentBuff  := NIL;
  FBuffSize     := 0;
end;


Procedure TWinBtr.SetBufferAddress( P : Pointer );
begin
  if Assigned( P ) then
    FCurrentBuff  := P;
end;


Function TWinBtr.WasSuccess : Boolean;
begin
  Result := ( Status = ISAM_SUCCESS );
end;


Function TWinBtr.GetStatus : SmallInt;
begin
  If ( FStatus = ISAM_WRONGBUFFERSIZE ) and FIgnoreSize then
    FStatus := ISAM_SUCCESS;
  Result := FStatus;
end;


Procedure TWinBtr.SetVarRecSize( Size : LongInt );
begin
  FVariableSize := Size;
end;


Function TWinBtr.GetVarRecSize : LongInt;
begin
  Result        := FVariableSize;
  FVariableSize := FBuffSize;
end;




Procedure TWinBtr.LowLevel( Operation : SmallInt );
var
  KeyLen     : ShortInt;
  doing_lock : Boolean;
begin
  If ( Operation in [ ISAM_INSERT, ISAM_UPDATE ] ) then
    FActBuffSize := VarBufferSize
  else
    FActBuffSize := FBuffSize;
  doing_lock := ( FLockBias <> ISAM_NO_LOCK_BIAS );
  if ( doing_lock ) then
  begin
    Inc( Operation, FLockBias );
    ResetLockBias;
  end;
  KeyLen := ShortInt( $FF );
  If FUseClientID then
    FStatus := BtrCallID( Operation, FPosBlock, FCurrentBuff^,
                 FActBuffSize, FKeyBuffer, KeyLen, FKeyNumber, FClientID )
  else
  FStatus := BtrCall( Operation, FPosBlock, FCurrentBuff^,
               FActBuffSize, FKeyBuffer, KeyLen, FKeyNumber );
  if Success then
  begin
    { This Code handles filling to the end of variable length records }
    if ( FActBuffSize < FBuffSize ) then
      MoveZero( MemPtr( FCurrentBuff )^[ FActBuffSize ], FBuffSize - FActBuffSize );
    FCurrentBuff := FInternalBuff;
    if ( doing_lock ) then
      FLockRec := Item_Position;
  end
  else
    ThrowBtrieveException( FStatus );
end;


Procedure TWinBtr.Special( Op : SmallInt; P : Pointer; Size : LongInt );
var
  KeyLen  : ShortInt;
begin
  KeyLen  := ShortInt( $FF );
  If FUseClientID then
    FStatus := BtrCallID( Op, FPosBlock, P^, Size, FKeyBuffer, KeyLen, FKeyNumber, FClientID )
  else
  FStatus := BtrCall( Op, FPosBlock, P^, Size, FKeyBuffer, KeyLen, FKeyNumber );
  If ( FStatus <> ISAM_SUCCESS ) then
    ThrowBtrieveException( FStatus );
end;


Procedure TWinBtr.GetVersion( Var Version, Revision : SmallInt; Var EngType : Char );
Var
  VerInfo : TVersionInfo;
begin
  Special( ISAM_VERSION, @VerInfo, SizeOf( VerInfo ) );
  Version  := VerInfo.Version;
  Revision := VerInfo.Revision;
  EngType  := VerInfo.EngType;
end;

Procedure TWinBtr.Open( Name, TableOwner : PChar; Open_Mode : ShortInt );
const
  NULL_CHAR : Char = #0;
var
  KeyLen : ShortInt;
begin
  if FisOpen then
    Close;

  If ( TableOwner = NIL ) then
    TableOwner := @NULL_CHAR;

  FActBuffSize := StrLen( TableOwner );
  If ( FActBuffSize > 0 ) then
    Inc( FActBuffSize );

  KeyLen := ShortInt( $FF );

  If FUseClientID then
    FStatus  := BtrCallID( ISAM_OPEN, FPosBlock, TableOwner^, FActBuffSize,
                  Name^, KeyLen, Open_Mode, FClientID )
  else
  FStatus  := BtrCall( ISAM_OPEN, FPosBlock, TableOwner^, FActBuffSize,
                Name^, KeyLen, Open_Mode );
  If Success then
  begin
    FisOpen    := TRUE;
    KeyNumber  := WBTRV_DEFAULT_KEY;
    Record_Size( FActBuffSize );
    BufferSize := FActBuffSize;
    FIsOpen    := Success;
    FDataOnly  := ( Indexes = 0 );
  end
  else
    ThrowBtrieveExceptionMsg( FStatus, StrPas( Name ) );
end;


Procedure TWinBtr.Close;
var
  Temp : Longint;
begin
  if FisOpen then
  begin
    Special( ISAM_CLOSE, @Temp, SizeOf( Temp ) );
    FisOpen := FALSE;
    RemoveBuffer;
    MoveZero( FFileStats, SizeOf( FFileStats ) );
  end
  else
    ThrowBtrieveException( ISAM_FILE_NOT_OPEN );
end;


Procedure TWinBtr.First_Item;
(* The new code below is faster according to Danny Thorpe's book *)
(* It's harder to read, but the compiler generates faster code   *)
(* than the old code which used a normal If..then construct.     *)
Const
  PARAM : Array[ Boolean ] of SmallInt = ( ISAM_GET_FIRST, ISAM_STEP_FIRST );
begin
  LowLevel( PARAM[ FDataOnly ] );
end;


Procedure TWinBtr.Last_Item;
Const
  PARAM : Array[ Boolean ] of SmallInt = ( ISAM_GET_LAST, ISAM_STEP_LAST );
begin
  LowLevel( PARAM[ FDataOnly ] );
end;


Procedure TWinBtr.Next_Item;
Const
  PARAM : Array[ Boolean ] of SmallInt = ( ISAM_GET_NEXT, ISAM_STEP_NEXT );
begin
  LowLevel( PARAM[ FDataOnly ] );
end;


Procedure TWinBtr.Previous_Item;
Const
  PARAM : Array[ Boolean ] of SmallInt = ( ISAM_GET_PREVIOUS, ISAM_STEP_PREVIOUS );
begin
  LowLevel( PARAM[ FDataOnly ] );
end;


Procedure TWinBtr.ClearKeyBuffer( Size : Word );
begin
  If ( Size > 0 ) and ( Size <= SizeOf( TttKeyBuffer ) ) then
    MoveZero( FKeyBuffer, Size );
end;


Procedure TWinBtr.Find_Item( P : Pointer; Size : Word; Key : ShortInt );
begin
  Find_Item_Special( ISAM_GET_EQUAL, P, Size, Key );
end;


Procedure TWinBtr.Find_Item_Special( action : SmallInt; P : Pointer;
           Size : Word; Key : ShortInt );
begin
  If Assigned( P ) then
  begin
    KeyNumber := Key;
    If ( Size > SizeOf( FKeyBuffer ) ) then
      ThrowBtrieveException( ISAM_INVALID_KEY_SIZE );
    Move( P^, FKeyBuffer, Size );
    LowLevel( action );
  end
  else
    ThrowBtrieveException( ISAM_NULL_KEY_PATH );
end;


Procedure TWinBtr.Insert_Item;
begin
  LowLevel( ISAM_INSERT );
end;


Procedure TWinBtr.Update_Item;
begin
  LowLevel( ISAM_UPDATE );
  UnLock_Item;
end;




Procedure TWinBtr.Delete_Item;
begin
  LowLevel( ISAM_DELETE );
end;


Procedure TWinBtr.ResetLockBias;
begin
  FLockBias := ISAM_NO_LOCK_BIAS;
end;


Procedure TWinBtr.Lock_Item;
begin
  FLockBias := ISAM_SINGLE_NOWAIT_LOCK_BIAS;
end;


Procedure TWinBtr.UnLock_Item;
begin
  if ( FLockRec <> 0 ) then
  begin
    Special( ISAM_UNLOCK, @FLockRec, SizeOf( FLockRec ) );
    FLockRec := 0;
  end;
end;


Function TWinBtr.Item_Position : Longint;
begin
  Special( ISAM_GET_POSITION, @Result, SizeOf( Result ) );
  FCurrentBuff := FInternalBuff;
end;


Procedure TWinBtr.Item_Direct( P : Longint );
begin
  Move( P, FCurrentBuff^, SizeOf( Longint ) );
  LowLevel( ISAM_GET_DIRECT );
end;


Procedure TWinBtr.SetToItem( P : Longint );
Var
  i : LongInt;
begin
  i := SizeOf( LongInt ) * 3;     { This code handles new Btrieve behavior }
  If ( i > FBuffSize ) then       { with GetDirect operation.              }
    i := FBuffSize;
  MoveZero( FInternalBuff^, i );
  Move( P, FInternalBuff^, SizeOf( P ) );
  FCurrentBuff := FInternalBuff;
  LowLevel( ISAM_GET_DIRECT );
end;


Procedure TWinBtr.LoadFileStats;
Var
  OldFlag : Boolean;
  OldKey  : ShortInt;
begin
  OldKey      := FKeyNumber;
  FKeyNumber  := -1; { Makes 6.0 & 7.0 return file version info }
  OldFlag     := FIgnoreSize;
  FIgnoreSize := TRUE;
  Try
    Special( ISAM_STAT, @FFileStats, SizeOf( FFileStats ) );
  Finally
    FKeyNumber  := OldKey;
    FIgnoreSize := OldFlag;
  end;
end;


Procedure TWinBtr.GetFileStats( Var T : TFileSpecs );
begin
  LoadFileStats;
  T := FFileStats;
end;


Procedure TWinBtr.Record_Size( Var Size : LongInt );
begin
  if FisOpen then
  begin
    if ( FFileStats.Header.Record_Length = 0 ) then
      LoadFileStats;
    Size := FFileStats.Header.Record_Length;
  end
  else
    Size := 0;
end;


Procedure TWinBtr.Record_Count( Var Count : LongInt );
begin
  if FisOpen then
  begin
    LoadFileStats;
    Count := FFileStats.Header.Records;
  end
  else
    Count := 0;
end;


Procedure TWinBtr.Index_Count( var count : Word );
begin
  if FisOpen then
  begin
    LoadFileStats;
    Count := FFileStats.Header.NumIndexes;
  end
  else
    Count := 0;
end;


Function TWinBtr.IndexHasACS : Boolean;
begin
  Result := ( ( FFileStats.Keys[ FKeyNumber ].Key_Flags and BtrIdxHasACS ) = BtrIdxHasACS );
end;


Procedure TWinBtr.GetIndexACS( P : pACSSpec );
var
  tmp    : Pointer;
  Size   : LongInt;
  Spec   : PChar;
  ACSNum : Byte;
  i      : SmallInt;
  Limit  : SmallInt;
begin
  Limit := FFileStats.Header.NumIndexes;
  Size  := SizeOf( TFileSpecs ) + ( SizeOf( TACSSpec ) * Limit );
  tmp   := AllocMem( Size );
  Try
    Special( ISAM_STAT, tmp, Size );
    Spec := tmp;
    Inc( Spec, SizeOf( TFileHeader ) );
    Inc( Spec, SizeOf( TKeySpecs ) * FKeyNumber );
    ACSNum := PKeySpecs( Spec )^.ACS_Number;
    Spec := tmp;
    Inc( Spec, SizeOf( TFileHeader ) );
    i := 0;
    Repeat
      If ( ( TKeySpecs( Pointer( Spec )^ ).Key_Flags And BtrIdxSegmented ) = 0 ) then
        Inc( i );
      Inc( Spec, SizeOf( TKeySpecs ) );
    Until ( i = Limit );
    Inc( Spec, SizeOf( TACSSpec ) * ACSNum );
    Move( Spec^, P^, SizeOf( TACSSpec ) );
  Finally
    FreeMem( tmp, Size );
  end;
end;


Procedure TWinBtr.Page_Size( var count : Word );
begin
  if FisOpen then
  begin
    if ( FFileStats.Header.Record_Length = 0 ) then
      LoadFileStats;
    Count := FFileStats.Header.Page_Size;
  end
  else
    Count := 0;
end;


Procedure TWinBtr.BeginTransaction( Concurrent : Boolean );
var
  op : SmallInt;
begin
  if Concurrent then
    op := ISAM_BEGIN_TRANSACTION + ISAM_CONCURRENT_TRANSACT_BIAS +
          CONCURRENTTRANSACTWAITBIAS
  else
    op := ISAM_BEGIN_TRANSACTION;
  Special( Op, NIL, 0 );
end;


Procedure TWinBtr.EndTransaction;
begin
  LowLevel( ISAM_END_TRANSACTION );
end;


Procedure TWinBtr.AbortTransaction;
begin
  LowLevel( ISAM_ABORT_TRANSACTION );
end;




Function TWinBtr.GetRecords : Longint;
begin
  Try
    Record_Count( Result );
  Except
    on E:EBtrieveEngineError do
      Result := 0;
  end;
end;


Function TWinBtr.GetIndexes : Word;
begin
  Try
    Index_Count( result );
  Except
    on E:EBtrieveEngineError do
      Result := 0;
  end;
end;


Procedure TWinBtr.AddIndex( P : Pointer; Segments : Word; IndexNo : SmallInt );
begin
  if ( IndexNo <> 0 ) then
    KeyNumber := ShortInt( IndexNo or BtrKeyNoSpecBias );
  Special( ISAM_ADD_INDEX, P, SizeOf( TKeySpecs ) * Segments );
  LoadFileStats;
end;


Procedure TWinBtr.DropIndex( i : ShortInt );
begin
  KeyNumber := i;
  LowLevel( ISAM_DROP_INDEX );
  LoadFileStats;
end;


Procedure TWinBtr.FindPercentage( ByKeyPos : Boolean; Var Percentage : Longint );
var
  OldKeyNum : ShortInt;
  OldPos    : LongInt;
begin
  Try
    OldKeyNum  := FKeyNumber;
    OldPos     := Item_Position;
    If not ByKeyPos then
    begin
      Percentage := OldPos;
      FKeyNumber := -1;
    end;
    Try
      Special( ISAM_FIND_PERCENTAGE, @Percentage, SizeOf( Percentage ) );
    Finally
      FKeyNumber := OldKeyNum;
    end;
    Item_Direct( OldPos )
  Except
    on E:EBtrieveEngineError do
      Percentage := 0;
  end;
end;


Procedure TWinBtr.GetByPercentage( ByKeyPos : Boolean; Percentage : Longint );
var
  OldKeyNum : ShortInt;
begin
  OldKeyNum  := FKeyNumber;
  If not ByKeyPos then
    FKeyNumber := -1;
  Try
    Move( Percentage, FCurrentBuff^, SizeOf( Percentage ) );
    LowLevel( ISAM_GET_BYPERCENTAGE );
  Finally
    FKeyNumber := OldKeyNum;
  end;
end;


Procedure TWinBtr.CloneTable( NewName : PChar );
var
  KeyLen : ShortInt;
begin
  LoadFileStats;
  FActBuffSize := SizeOf( FFileStats );
  KeyLen       := ShortInt( $FF );
  If FUseClientID then
    FStatus := BtrCallID( ISAM_CREATE, FPosBlock, FFileStats, FActBuffSize,
                 NewName^, KeyLen, NORMAL, FClientID )
  else
    FStatus := BtrCall( ISAM_CREATE, FPosBlock, FFileStats, FActBuffSize,
                 NewName^, KeyLen, NORMAL );
  If ( FStatus <> ISAM_SUCCESS ) then
    ThrowBtrieveException( FStatus );
end;


Function TWinBtr.IsRecordLocked : Boolean;
var
  Position : LongInt;
  LastLock : LongInt;
begin
  Result := FALSE;
  FCurrentBuff := FInternalBuff;
  Position := Item_Position;
  if ( Position <> 0 ) then
  begin
    If ( Position <> FLockRec ) then
    begin
      LastLock := FLockRec;
      Lock_Item;
      Try
        Item_Direct( Position );
      Except
        on E:EBtrieveEngineError do
          Result := TRUE;
      end;
      Unlock_Item;
      FLockRec := LastLock;
    end
    else
      Result := TRUE;
  end;
end;


Procedure TWinBtr.ShutDownClientSession;
var
  KeyLen    : ShortInt;
  KeyBuf    : Pointer;
  tmpBuffer : TVersionInfo;
begin
  FActBuffSize := SizeOf( tmpBuffer );
  KeyLen       := 0;
  KeyBuf       := NIL;
  If FUseClientID then
    FStatus := BtrCallID( ISAM_STOP, FPosBlock, tmpBuffer, FActBuffSize,
                 KeyBuf, KeyLen, NORMAL, FClientID )
  else
    FStatus := BtrCall( ISAM_STOP, FPosBlock, tmpBuffer, FActBuffSize,
                 KeyBuf, KeyLen, NORMAL );
end;


Procedure TWinBtr.SetDirectory( Directory : PChar );
var
  tmp : Integer;
begin
  tmp := Succ( StrLen( Directory ) );
  Move( Directory, FKeyBuffer, tmp );
  LowLevel( ISAM_SET_DIRECTORY );
end;


Procedure TWinBtr.GetDirectory( Directory : PChar; Size : Word );
begin
  FKeyNumber := 0;
  ClearKeyBuffer( Size );
  LowLevel( ISAM_GET_DIRECTORY );
end;


End.










