{****************************************************************** JEDI-VCL Demo Copyright (C) 2002 Project JEDI Original author: Contributor(s): You may retrieve the latest version of this file at the JEDI-JVCL home page, located at http://jvcl.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1_1Final.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. ******************************************************************} {*******************************************************} { } { Borland Delphi Unit } { TUTILITY.DLL Class Unit } { } { Copyright (c) 1996 AO ROSNO } { Copyright (c) 1997 Master-Bank } { } {*******************************************************} Unit TUtil; {$I jvcl.inc} interface {$IFDEF WIN32} uses {$IFDEF COMPILER10_UP} DBCommonTypes, {$ENDIF COMPILER10_UP} Windows, DB, BDE, SysUtils, DBTables; {$ELSE} uses {$IFDEF COMPILER10_UP} DBCommonTypes, {$ENDIF COMPILER10_UP} WinTypes, WinProcs, DB, DbiTypes, DbiProcs, DbiErrs, SysUtils, DbTables; {$ENDIF} type HTUses = Word; PHTUses = ^HTUses; { Verify Callback processes } TUVerifyProcess = (TUVerifyHeader, TUVerifyIndex, TUVerifyData, TUVerifySXHeader, TUVerifySXIndex, TUVerifySXData, TUVerifySXIntegrity, TUVerifyTableName); { Call back info for Verify Callback function } PUVerifyCallBack = ^TUVerifyCallBack; TUVerifyCallBack = packed record PercentDone: SmallInt; TableName: DBIPath; Process: TUVerifyProcess; CurrentIndex: Word; TotalIndex: Word; end; { TUtility error } ETUtilityError = class(EDBEngineError) public constructor Create(ErrorCode: DBIResult); end; { Check and repair modes } TCheckRepair = (crNoRepair, crAutoRepair, crConfirmRepair); TVerifyOption = (vfAppendErrors, vfBypassSecondaryIndexes, vfIgnoreWarnings, vfVerifyHeaderOnly, vfNoLockTable, vfDialogHide); TVerifyOptions = set of TVerifyOption; TTUAction = procedure of object; { TTUtility } TTUtility = class(TObject) private FSession: HTUses; FCheckErrorTable, FErrorTable, FProblemTable, FKeyViolationTable, FBackupTable, FTableName: DBIPATH; FPassword: DBINAME; FTblDesc: CRTblDesc; FOptDataLen: Word; FCheckRepair: TCheckRepair; FVerifyOptions: TVerifyOptions; FShowNoError: Boolean; procedure SetTabName(const TabName: string; const Dest: DBIPATH); function CheckOpen(Status: DBIResult): Boolean; procedure Check(Status: DBIResult); function ProgressCallback(CBInfo: Pointer): CBRType; function VerifyFlag: Integer; function GetPassword: string; procedure SetPassword(const Value: string); function GetCheckErrorTable: string; procedure SetCheckErrorTable(const Value: string); function GetErrorTable: string; procedure SetErrorTable(const Value: string); function GetProblemTable: string; procedure SetProblemTable(const Value: string); function GetKeyViolationTable: string; procedure SetKeyViolationTable(const Value: string); function GetBackupTable: string; procedure SetBackupTable(const Value: string); function GetTableName: string; procedure SetTableName(const Value: string); function TULastErrorMessage: string; procedure CheckBackupTable; function ShowPasswordDialog: Boolean; protected procedure RunTUtility(Action: TTUAction); procedure FillTblDesc; procedure ClearTblDesc; procedure DoCheckTable; virtual; procedure DoRepairTable; virtual; function VerifyTable: Cardinal; property BackupTable: string read GetBackupTable write SetBackupTable; public constructor Create; destructor Destroy; override; function ErrorString(ErrorCode: DBIResult): string; procedure DefaultBackupNames; procedure CheckTable; procedure RepairTable; procedure DropErrorTable; property CheckRepair: TCheckRepair read FCheckRepair write FCheckRepair default crConfirmRepair; property CheckErrorTable: string read GetCheckErrorTable write SetCheckErrorTable; property ErrorTable: string read GetErrorTable write SetErrorTable; property KeyViolationTable: string read GetKeyViolationTable write SetKeyViolationTable; property ProblemTable: string read GetProblemTable write SetProblemTable; property Password: string read GetPassword write SetPassword; property ShowNoError: Boolean read FShowNoError write FShowNoError; property TableName: string read GetTableName write SetTableName; property VerifyOptions: TVerifyOptions read FVerifyOptions write FVerifyOptions default [vfIgnoreWarnings]; end; { Utility routines } procedure CheckTables(const TablesDir: string; Repair: TCheckRepair); procedure CheckTable(const TableName: string; Repair: TCheckRepair); implementation uses Classes, Controls, Dialogs, Forms, JvDBUtils, JvBdeUtils, JvBDEProgress, JvJCLUtils, JvJVCLUtils; const { Verify table options } TU_APPEND_ERRORS = 1; { append errors to an existing errors table } TU_BYPASS_SECONDARY_INDEXES = 2; { bypass secondary indexes } TU_IGNORE_WARNINGS = 4; { prevents reporting of warning errors } TU_VERIFY_HEADER_ONLY = 8; { verify table header only } TU_DIALOG_HIDE = 16; { hide TUtility dialogs } TU_NO_LOCK = 32; { lock table being verified (recommended) } { Verify table error codes } VFE_WARNING = 0; { warning error } VFE_DAMAGE_VERIFY = 1; { table is damaged, verification can continue } VFE_DAMAGE_NOT_VERIFY = 2; { table is damaged; verification cannot continue } VFE_REBUILD_MANUALLY = 3; { table must be rebuilt manually } VFE_CANNOT_REBUILD = 4; { table cannot be rebuilt; restore from a backup } const {$IFDEF WIN32} TULib = 'TUTIL32.DLL'; {$ELSE} TULib = 'TUTILITY.DLL'; {$ENDIF} var TUHandle: THandle = 0; TUInit: function (hTUSession: PHTUses): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; TUVerifyTable: function (hTUSession: HTUses; pszTableName, pszDriverType, pszErrTableName, pszPassword: PChar; iOptions: Integer; var piErrorLevel: Cardinal): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; TURebuildTable: function (hTUSession: HTUses; pszTableName, pszDriverType, pszBackupTableName, pszKeyviolName, pszProblemTableName: PChar; pCrDesc: pCRTblDesc): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; TUGetCRTblDescCount: function (hTUSession: HTUses; pszTableName: PChar; var iFldCount,iIdxCount, iSecRecCount, iValChkCount, iRintCount, iOptParams, iOptDataLen: Word): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; TUFillCRTblDesc: function (hTUSession: HTUses; pCrDesc: pCRTblDesc; pszTableName, pszPassword: PChar): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; TUFillCURProps: function (hTUSession: HTUses; pszTableName: PChar; tblProps: pCURProps): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; TUExit: function (hTUSession: HTUses): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; TUGetErrorString: function (iErrorCode: DBIResult; pszError: PChar): DBIResult {$IFDEF WIN32} stdcall {$ENDIF}; {$IFDEF COMPILER3_UP} resourcestring {$ELSE} const {$ENDIF} STUNotLoaded = 'Unable to load %s library'; STUNoTables = 'No Paradox tables to verify'; STUVerifyComplete = 'Verification successful. '; STUVerifyOk = 'Table %s verify complete. No errors found.'; STUDamage = 'Table %s is damaged. Rebuild it.'; STURebuild = 'Table %s is damaged. Rebuild?'; STURebuildManual = 'Table %s is damaged and must be rebuilt manually.'; STUNoRebuild = 'Table %s is damaged and cannot be rebuilt; restore from a backup.'; STUUnknownError = 'Unknown %s error, code %d'; STUPwDlgCaption = 'Enter Table Password'; STUPwDlgPrompt = 'Enter master password for table %s:'; function TUtilityLoaded: Boolean; begin Result := TUHandle >= HINSTANCE_ERROR; end; function LoadTUtility: Boolean; var OldError: Word; Path: string; {$IFNDEF WIN32} P: array[0..255] of Char; {$ENDIF} begin OldError := SetErrorMode(SEM_NOOPENFILEERRORBOX); try Path := NormalDir(GetBdeDirectory) + TULib; {$IFDEF WIN32} TUHandle := LoadLibrary(PChar(Path)); {$ELSE} TUHandle := LoadLibrary(StrPCopy(P, Path)); {$ENDIF} if not TUtilityLoaded then begin Path := TULib; {$IFDEF WIN32} TUHandle := LoadLibrary(PChar(Path)); {$ELSE} TUHandle := LoadLibrary(StrPCopy(P, Path)); {$ENDIF} end; if TUtilityLoaded then begin @TUInit := GetProcAddress(TUHandle, 'TUInit'); @TUVerifyTable := GetProcAddress(TUHandle, 'TUVerifyTable'); @TURebuildTable := GetProcAddress(TUHandle, 'TURebuildTable'); @TUGetCRTblDescCount := GetProcAddress(TUHandle, 'TUGetCRTblDescCount'); @TUFillCRTblDesc := GetProcAddress(TUHandle, 'TUFillCRTblDesc'); @TUFillCURProps := GetProcAddress(TUHandle, 'TUFillCURProps'); @TUExit := GetProcAddress(TUHandle, 'TUExit'); @TUGetErrorString := GetProcAddress(TUHandle, 'TUGetErrorString'); end else TUHandle := 1; finally SetErrorMode(OldError); end; Result := TUtilityLoaded; end; procedure FreeTUtility; far; begin if TUtilityLoaded then FreeLibrary(TUHandle); TUHandle := 0; end; procedure CheckTU; begin if not TUtilityLoaded then raise EDatabaseError.CreateFmt(STUNotLoaded, [TULib]); end; { ETUtilityError } function TrimMessage(Msg: PChar): PChar; var Blank: Boolean; Source, Dest: PChar; begin Source := Msg; Dest := Msg; Blank := False; while Source^ <> #0 do begin if Source^ <= ' ' then Blank := True else begin if Blank then begin Dest^ := ' '; Inc(Dest); Blank := False; end; Dest^ := Source^; Inc(Dest); end; Inc(Source); end; if (Dest > Msg) and (Dest[Word(-1)] = '.') then Dec(Dest); Dest^ := #0; Result := Msg; end; type EDBEngineErrorHack = class(EDatabaseError) private FErrors: TList; end; constructor ETUtilityError.Create(ErrorCode: DBIResult); var ErrorIndex: Integer; NativeError: Longint; Msg, LastMsg: DBIMSG; begin inherited Create(0); {$IFDEF WIN32} if not Session.Active then Exit; {$ENDIF} with EDBEngineErrorHack(Self) do begin if FErrors <> nil then begin for ErrorIndex := FErrors.Count - 1 downto 0 do TDBError(FErrors[ErrorIndex]).Free; FErrors.Clear; end; end; ErrorIndex := 1; try TUGetErrorString(ErrorCode, Msg); TDBError.Create(Self, ErrorCode, 0, Msg); TrimMessage(Msg); if Msg[0] = #0 then Message := Format(STUUnknownError, [TULib, ErrorCode]) else Message := StrPas(Msg); while True do begin StrCopy(LastMsg, Msg); ErrorCode := DbiGetErrorEntry(ErrorIndex, NativeError, Msg); if (ErrorCode = DBIERR_NONE) or (ErrorCode = DBIERR_NOTINITIALIZED) then Break; TDBError.Create(Self, ErrorCode, NativeError, Msg); TrimMessage(Msg); if (Msg[0] <> #0) and (StrComp(Msg, LastMsg) <> 0) then Message := Format('%s. %s', [Message, Msg]); Inc(ErrorIndex); end; except Message := Format(STUUnknownError, [TULib, ErrorCode]); end; end; { TTUtility } constructor TTUtility.Create; begin inherited Create; FCheckRepair := crConfirmRepair; FVerifyOptions := [vfIgnoreWarnings]; end; destructor TTUtility.Destroy; begin ClearTblDesc; inherited Destroy; end; procedure TTUtility.RunTUtility(Action: TTUAction); var FCallback: TJvDBCallback ; begin CheckTU; Check(TUInit(@FSession)); try FCallback := TJvDBCallback .Create(Self, cbGENPROGRESS, SizeOf(TUVerifyCallBack), ProgressCallback, dcChain); try Action; finally FCallback.Free; end; finally TUExit(FSession); end; end; function TTUtility.CheckOpen(Status: DBIResult): Boolean; begin Result := True; case Status of DBIERR_NONE: Result := True; DBIERR_NOTSUFFTABLERIGHTS: begin if not Session.GetPassword then Check(Status); Result := False; end; else if (Status <> 0) then Check(Status); end; end; procedure TTUtility.Check(Status: DBIResult); var ErrInfo: DBIErrInfo; begin if Status <> 0 then begin DbiGetErrorInfo(True, ErrInfo); if (ErrInfo.iError = Status) then DbiError(Status) else raise ETUtilityError.Create(Status); end; end; function TTUtility.ProgressCallback(CBInfo: Pointer): CBRType; begin Result := cbrCONTINUE; with PUVerifyCallBack(CBInfo)^ do begin StrPCopy(TableName, Self.TableName); if (PercentDone = 0) then PercentDone := -1; end; end; function TTUtility.ErrorString(ErrorCode: DBIResult): string; var Msg: DBIMSG; begin CheckTU; TUGetErrorString(ErrorCode, Msg); TrimMessage(Msg); if Msg[0] = #0 then Result := Format(STUUnknownError, [TULib, ErrorCode]) else Result := StrPas(Msg); end; function TTUtility.VerifyFlag: Integer; const VerifyFlags: array[TVerifyOption] of Integer = (TU_APPEND_ERRORS, TU_BYPASS_SECONDARY_INDEXES, TU_IGNORE_WARNINGS, TU_VERIFY_HEADER_ONLY, TU_NO_LOCK, TU_DIALOG_HIDE); var I: TVerifyOption; begin Result := 0; for I := Low(TVerifyOption) to High(TVerifyOption) do if I in FVerifyOptions then Result := Result or VerifyFlags[I]; end; procedure TTUtility.SetTabName(const TabName: string; const Dest: DBIPATH); var P: PChar; begin P := @Dest[0]; if ChangeFileExt(TabName, '') <> StrPas(Dest) then begin if TabName <> '' then StrPLCopy(Dest, AnsiUpperCase(ChangeFileExt(TabName, '')), SizeOf(Dest) - 1) else FillChar(P^, SizeOf(Dest), #0); end; end; function TTUtility.GetPassword: string; begin Result := StrPas(FPassword); end; procedure TTUtility.SetPassword(const Value: string); begin if Value <> Password then begin if Value <> '' then StrPLCopy(FPassword, Value, SizeOf(FPassword) - 1) else FillChar(FPassword, SizeOf(FPassword), 0); end; end; function TTUtility.GetCheckErrorTable: string; begin Result := StrPas(FCheckErrorTable); end; procedure TTUtility.SetCheckErrorTable(const Value: string); begin SetTabName(Value, FCheckErrorTable); end; function TTUtility.GetErrorTable: string; begin Result := StrPas(FErrorTable); end; procedure TTUtility.SetErrorTable(const Value: string); begin SetTabName(Value, FErrorTable); end; function TTUtility.GetProblemTable: string; begin Result := StrPas(FProblemTable); end; procedure TTUtility.SetProblemTable(const Value: string); begin SetTabName(Value, FProblemTable); end; function TTUtility.GetKeyViolationTable: string; begin Result := StrPas(FKeyViolationTable); end; procedure TTUtility.SetKeyViolationTable(const Value: string); begin SetTabName(Value, FKeyViolationTable); end; function TTUtility.GetBackupTable: string; begin Result := StrPas(FBackupTable); end; procedure TTUtility.SetBackupTable(const Value: string); begin SetTabName(Value, FBackupTable); end; function TTUtility.GetTableName: string; begin Result := StrPas(FTableName); end; procedure TTUtility.SetTableName(const Value: string); begin SetTabName(Value, FTableName); end; function TTUtility.ShowPasswordDialog: Boolean; var S: string; begin S := Password; Result := InputQuery(STUPwDlgCaption, Format(STUPwDlgPrompt, [ExtractFileName(TableName)]), S); if Result then Password := S; end; procedure TTUtility.FillTblDesc; begin FillChar(FTblDesc, SizeOf(FTblDesc), 0); Check(TUGetCRTblDescCount(FSession, FTableName, FTblDesc.iFldCount, FTblDesc.iIdxCount, FTblDesc.iSecRecCount, FTblDesc.iValChkCount, FTblDesc.iRintCount, FTblDesc.iOptParams, FOptDataLen)); StrPCopy(FTblDesc.szTblName, TableName); StrCopy(FTblDesc.szTblType, szPARADOX); StrPCopy(FTblDesc.szErrTblName, ErrorTable); GetMem(FTblDesc.pFldDesc, FTblDesc.iFldCount * SizeOf(FldDesc)); GetMem(FTblDesc.PIdxDesc, FTblDesc.iIdxCount * SizeOf(IdxDesc)); GetMem(FTblDesc.pSecDesc, FTblDesc.iSecRecCount * SizeOf(SecDesc)); GetMem(FTblDesc.pVchkDesc, FTblDesc.iValChkCount * SizeOf(VchkDesc)); GetMem(FTblDesc.pRintDesc, FTblDesc.iRintCount * SizeOf(RintDesc)); GetMem(FTblDesc.pfldOptParams, FTblDesc.iOptParams * SizeOf(FldDesc)); GetMem(FTblDesc.pOptData, FOptDataLen * DBIMAXSCFLDLEN); try while not CheckOpen(TUFillCRTblDesc(FSession, @FTblDesc, FTableName, FPassword)) do {Retry}; except ClearTblDesc; raise; end; end; procedure TTUtility.ClearTblDesc; begin if FTblDesc.pFldDesc <> nil then FreeMem(FTblDesc.pFldDesc, FTblDesc.iFldCount * SizeOf(FldDesc)); if FTblDesc.PIdxDesc <> nil then FreeMem(FTblDesc.PIdxDesc, FTblDesc.iIdxCount * SizeOf(IdxDesc)); if FTblDesc.pSecDesc <> nil then FreeMem(FTblDesc.pSecDesc, FTblDesc.iSecRecCount * SizeOf(SecDesc)); if FTblDesc.pVchkDesc <> nil then FreeMem(FTblDesc.pVchkDesc, FTblDesc.iValChkCount * SizeOf(VchkDesc)); if FTblDesc.pRintDesc <> nil then FreeMem(FTblDesc.pRintDesc, FTblDesc.iRintCount * SizeOf(RintDesc)); if FTblDesc.pFldOptParams <> nil then FreeMem(FTblDesc.pFldOptParams, FTblDesc.iOptParams * SizeOf(FldDesc)); if FTblDesc.pOptData <> nil then FreeMem(FTblDesc.pOptData, FOptDataLen * DBIMAXSCFLDLEN); FillChar(FTblDesc, SizeOf(FTblDesc), 0); end; procedure TTUtility.DoRepairTable; var CurProp: CURProps; PasswordEmpty: Boolean; begin if TableName = '' then Exit; while not CheckOpen(TUFillCURProps(FSession, FTableName, @CurProp)) do {Retry}; PasswordEmpty := Password = ''; if CurProp.bProtected and PasswordEmpty then if not ShowPasswordDialog then Exit; { no password specified - no repair } try VerifyTable; FillTblDesc; try Screen.Cursor := crHourGlass; try {$IFNDEF WIN32} CheckBackupTable; {$ENDIF} while not CheckOpen(TURebuildTable(FSession, FTableName, szPARADOX, FBackupTable, FKeyViolationTable, FProblemTable, @FTblDesc)) do {Retry}; finally Screen.Cursor := crDefault; end; finally ClearTblDesc; end; finally if PasswordEmpty then Password := ''; end; end; function TTUtility.VerifyTable: Cardinal; begin CheckTU; { TUtility must be re-initialized for each verification } Check(TUExit(FSession)); Check(TUInit(@FSession)); Screen.Cursor := crHourGlass; try while not CheckOpen(TUVerifyTable(FSession, FTableName, szPARADOX, FCheckErrorTable, FPassword, VerifyFlag, Result)) do {Retry}; finally Screen.Cursor := crDefault; end; end; procedure TTUtility.DoCheckTable; function TabName: string; begin Result := ExtractFileName(ChangeFileExt(TableName, '.DB')); end; var ErrMsg: string; begin if TableName = '' then Exit; case VerifyTable of VFE_WARNING: if FShowNoError then MessageDlg(Format(STUVerifyOk, [TabName]), mtInformation, [mbOk], 0); VFE_DAMAGE_VERIFY, VFE_DAMAGE_NOT_VERIFY: begin ErrMsg := TULastErrorMessage; case FCheckRepair of crNoRepair: MessageDlg(ErrMsg + Format(STUDamage, [TabName]), mtError, [mbOk], 0); crAutoRepair: RepairTable; crConfirmRepair: if MessageDlg(ErrMsg + Format(STURebuild, [TabName]), mtError, [mbYes, mbNo], 0) = mrYes then RepairTable; end; end; VFE_REBUILD_MANUALLY: begin ErrMsg := TULastErrorMessage; MessageDlg(ErrMsg + Format(STURebuildManual, [TabName]), mtError, [mbOk], 0); end; VFE_CANNOT_REBUILD: begin ErrMsg := TULastErrorMessage; MessageDlg(ErrMsg + Format(STUNoRebuild, [TabName]), mtError, [mbOk], 0); end; end; end; procedure TTUtility.CheckTable; begin RunTUtility(DoCheckTable); end; procedure TTUtility.RepairTable; begin RunTUtility(DoRepairTable); end; function TTUtility.TULastErrorMessage: string; var Table: TTable; begin Result := ''; if CheckErrorTable = '' then Exit; Table := TTable.Create(Application); try Table.TableName := ChangeFileExt(CheckErrorTable, '.DB'); try Table.Open; Table.Last; Result := Table.FieldByName('Error Message').AsString; if Result <> '' then Result := Result + '. '; except Result := ''; end; finally Table.Free; end; if Result = '' then Result := STUVerifyComplete; end; procedure TTUtility.DropErrorTable; begin if CheckErrorTable = '' then Exit; with TTable.Create(Application) do try TableName := ChangeFileExt(CheckErrorTable, '.DB'); if FileExists(TableName) then DeleteTable; finally Free; end; end; procedure TTUtility.CheckBackupTable; var TabPath: string; begin TabPath := ChangeFileExt(TableName, ''); if TabPath <> '' then begin Delete(TabPath, Length(TabPath), 1); BackupTable := TabPath + '_.DB'; end else BackupTable := ''; end; procedure TTUtility.DefaultBackupNames; var TabPath: string; begin TabPath := NormalDir(GetEnvVar('TEMP')); if (TabPath = '') then TabPath := NormalDir(ExtractFilePath(TableName)); CheckErrorTable := TabPath + 'VERIFY.DB'; ErrorTable := TabPath + 'REBUILD.DB'; ProblemTable := TabPath + 'PROBLEM.DB'; KeyViolationTable := TabPath + 'KEYVIOL.DB'; CheckBackupTable; end; { Utility routines } function GetPxTableNames(const DirectoryName: string; List: TStrings): string; var hDB: HDBIDb; Cursor: HDBICur; DirName: string; Desc: FILEDesc; DbPath: DBIPATH; begin {$IFDEF WIN32} Session.Active := True; {$ENDIF} DirName := DirectoryName; if not IsDirectory(DirName) then DirName := GetAliasPath(DirName); Result := DirName; Check(DbiOpenDatabase(nil, nil, dbiREADWRITE, dbiOPENSHARED, nil, 0, nil, nil, hDB)); try Check(DbiSetDirectory(hDB, StrPLCopy(DbPath, DirName, SizeOf(DbPath) - 1))); List.BeginUpdate; try List.Clear; Check(DbiOpenFileList(hDB, '*.db', Cursor)); try while DbiGetNextRecord(Cursor, dbiNOLOCK, @Desc, nil) = 0 do begin if (DirName[Length(DirName)] <> '\') and (Length(DirName) > 1) then DirName := DirName + '\' else if Length(DirName) = 1 then DirName := DirName + ':\'; List.Add(Format('%s%s', [DirName, StrPas(Desc.szFileName)])); end; finally DbiCloseCursor(Cursor); end; finally List.EndUpdate; end; finally DbiCloseDatabase(hDB); end; end; procedure CheckTable(const TableName: string; Repair: TCheckRepair); var TU: TTUtility; begin CheckTU; if not FileExists(ChangeFileExt(TableName, '.DB')) then DatabaseError(STUNoTables); TU := TTUtility.Create; try TU.CheckRepair := Repair; TU.ShowNoError := True; try TU.TableName := TableName; TU.DefaultBackupNames; TU.CheckTable; TU.DropErrorTable; except on E: ETUtilityError do begin if TUtilityLoaded then Application.HandleException(TU) else raise; end; else raise; end; finally TU.Free; end; end; procedure CheckTables(const TablesDir: string; Repair: TCheckRepair); var List: TStrings; TU: TTUtility; I: Integer; begin CheckTU; TU := TTUtility.Create; try List := TStringList.Create; try GetPxTableNames(TablesDir, List); if List.Count <= 0 then DatabaseError(STUNoTables); TU.CheckRepair := Repair; TU.ShowNoError := False; for I := 0 to List.Count - 1 do try TU.TableName := List[I]; TU.DefaultBackupNames; TU.CheckTable; except on E: ETUtilityError do begin if TUtilityLoaded then Application.HandleException(TU) else raise; end; else raise; end; TU.DropErrorTable; finally List.Free; end; finally TU.Free; end; end; initialization LoadTUtility; {$IFNDEF WIN32} AddExitProc(FreeTUtility); {$ENDIF} end.