While the BDE might be deprecated by Borland, there are still many developers using it to build various database applications.
Recently, I had to move some (very old) FoxPro tables over to a database server (Interbase). The natural choice for the component to do the task was the TBatchMove. This powerful component performs database operations on groups of records or entire tables using the BDE.
Progress of a Batch Move operation?
When you set the properties of the BatchMove component (Source, Destination, Mode, etc.) and call the Execute method, the actuall process happens "behind the scenes".Suppose you need to move 1 milion records from one database table to another (database). No metter how fast the machine is, some time will pass before the operation finishes.
To let the user know that the application is running, you might want to add the progress bar to show the actuall progress value.
Since the TBatchMove does not provide any event to handle, in order to get the progress value, and as the Help system suggest, the only way to show a progress indicator is to "dive" into BDE callbacks.
TBDECallback & cbGENPROGRESS
The TBDECallback class is a wrapper for a Borland Database Engine callback function.
When you install a callback function to the BDE, the BDE will "call back" to a function in your application, letting your application know when certain events take place, and in some cases, allow your application to return information back to the BDE.
While TBDECallback's constructor might look scary, it's not so hard to "crack".
There are 3 main points you need to know in order to create a BDE callback for a BDE operation progress value:
- The CBType parameter should be set to cbGENPROGRESS.
- The CBBuf parameter (and CBBufSize) should "point" to the correct callback descriptor defined in the BDE.pas unit. In the cbGENPROGRESS case this is CBPROGRESSDesc.
- The CallbackEvent parameter points to the function that the BDE will call. The CBInfo it gets maps to the CBPROGRESSDesc record.
The CBPROGRESSDesc structure contains the following two fields: szMsg and iPercentDone.
If the iPercentDone of the callback structure is greater than -1, then the percentage is correct and you can update your progress bar. If the percentage reported is less than zero, the callback has received a text message in the szTMsg field containing a message that
includes the number of records processed ("Records appended: XYZ").
BatchMove Progress Example
Drop a TBacthMove ("BatchMove1") component on a form ("Form1") along with two TTable objects ("TableSRC" and "TableDesc"). A button named "ExecuteButton" will start a "batCopy" operation on the tables.
procedure TForm1.ExecuteButtonClick(Sender: TObject) ;
var
bdec : TBDECallback;
cbDataBuff : CBPROGRESSDesc;
begin
ProgressBar1.Position := 0;
with BatchMove1 do
begin
Source := TableSRC;
TableDEST.TableName := TableSRC.TableName + '_copy';
Destination := TableDEST;
Mode := batCopy;
RecordCount := 0; //all
try
bdec := TBDECallback.Create(nil,TableSRC.Handle,cbGENPROGRESS,@cbDataBuff, SizeOf(cbDataBuff),BatchProgressCallback,true) ;
try
Execute;
ShowMessage(Format('%d records copied.',[MovedCount])) ;
finally
FreeAndNil(bdec) ;
end;
except on E:Exception do
begin
showmessage(E.Message) ;
end;
end;
end;
end; //ExecuteButtonClick
function TForm1.BatchProgressCallback(CBInfo: Pointer): CBRType;
var
s : string;
begin
if pCBPROGRESSDesc(cbInfo).iPercentDone < 0 then
begin
//"Records appended: XYZ"
s := pCBPROGRESSDesc(cbInfo).szMsg;
Delete(s, 1, Pos(': ', s) + 1) ;
ProgressBar1.Position := Round((StrToInt(s) / TableSRC.RecordCount) * 100) ;
end
else
begin
ProgressBar1.Position := pCBPROGRESSDesc(cbInfo).iPercentDone;
end;
result := cbrCONTINUE;
end; //BatchProgressCallback
And that's all.


