Below is a generic (with some limits) search function that works on expression tags of dBase files.
It is alpha code, barely tested, so use at your own risk <s>. Do let me know if you have a problem. I may not be able to help you as I can be rather busy, but at least, I'll know about it, and in time, may be able to solve the bugs.
The main limit is that it currently only supports character and date fields in the expression. If your expression contains other fields, the function will not work. I may expand it if the need arises for me, or you can try to expand it if you need the extra capability.
A second limit is that each field can only be used once in the expression.
The next enhancement of this will optionally permit SoftSeeks (i.e. seek on the closest value instead of on a specific value).
The next enhancement should also allocate memory for the right size of the Key, instead of putting an arbitrary value of 250 bytes.
Here is an example of how to call the generic SearchExpr function:
{current index key expression is 'DTOS(CRT_DATE)+CRT_CODE'}
Table1.SetKey;
Table1.FieldByName('CRT_DATE').AsString := '2/2/94'; {assign
search values}
Table1.FieldByName('CRT_CODE').AsString := 'T002';
{assign search values}
if SeekExpr(Table1.Handle, [Table1.FieldByName('CRT_DATE'),
Table1.FieldByName('CRT_CODE')] ) then
ShowMessage('Found!')
else
ShowMessage('Not found!');
{note that the record pointer is now on the record it found, if any}
Here is the code for the generic search function:
function TDBFTest1.SeekExpr(hTable: HDBIcur;
aFlds: array of TField): boolean;
const
KeyBufSize = 250;
{maximum size of key}
var
pRecBuf: pByte;
{contains a record in memory}
pKeyBuf: pByte;
{contains actual key}
TblProps: CURProps;
{table properties }
rslt:
DBIResult; {result of BDE call}
i:
integer; {counter}
tmpPSZ: PCHAR;
tmpDate: LongInt;
begin
{get size of record buffer}
DbiGetCursorProps(hTable, TblProps);
{allocate memory for record buffer}
GetMem(pRecBuf, TblProps.iRecBufSize
* sizeof(BYTE));
GetMem(pKeyBuf, KeyBufSize); {allocate
mem for key}
{initialize record buffer}
DbiInitRecord(hTable, pRecBuf);
{set search values in record buffer}
for i := 0 to High(aFlds) do
begin
{TStringField}
if (aFlds[i] is TStringField)
then
begin
GetMem(tmpPSZ, Length(aFlds[i].AsString)+1);
StrPCopy(tmpPSZ, aFlds[i].AsString);
DbiPutField(hTable,
{TTable}
aFlds[i].FieldNo, {TField}
pRecBuf,
{pointer to record buffer}
(tmpPSZ));
{pointer to value}
FreeMem(tmpPSZ, Length(aFlds[i].AsString)+1);
end
{TDateField}
else if (aFlds[i] is TDateField)
then
begin
tmpDate := Trunc(aFlds[i].AsDateTime);
DbiPutField(hTable,
{TTable}
aFlds[i].FieldNo, {TField}
pRecBuf,
{pointer to record buffer}
(@tmpDate)); {pointer to
value}
end
end;
{create a key for the above values}
DbiExtractKey(hTable, pRecBuf, pKeyBuf);
{search using this key (stored in pKeyBuf)}
table1.updatecursorpos;
rslt := DbiGetRecordForKey(hTable, True,
0, 0, pKeyBuf, nil);
table1.refresh; {update data aware components}
if rslt <> 0 then
Result := False
else
result := True;
ShowRecord; {display new record number -- see below}
{free memory allocated for buffer}
FreeMem(pRecBuf, TblProps.iRecBufSize
* sizeof(BYTE));
FreeMem(pKeyBuf, KeyBufSize);
end;
procedure TDBFTest1.ShowRecord;
{Show a dBase record number}
{NOTE: it assumes there is a label component named
RecordNo.}
var
myrecprop: RECprops;
recno: integer;
begin
table1.updatecursorpos;
recno := 0;
dbiGetRecord(table1.handle, dbiNOLOCK,
nil, @myrecprop);
recno := myrecprop.iPhyRecNum;
RecordNo.Caption := inttostr(recno);
end;