With the assistance of this forum, I have been able to create my first 64-bit plugin for JPSoftware's Take Command Console.
The next thing I wanted to convert from PowerBasic was the ability to low-level read a dBASE .dbf without any external programs (ODBC, third-party drivers, etc.)
So, here it is.
It's just a simple demo, which I have tried with three different .dbf files on my system.
The comments in the code are for me, so that I can pursue those items at a later time, but if someone wants to make this code better, go for it.
Joe
Code: Select all
EnableExplicit
Global dbf$
Global hndFile.l
Global *MemoryID
Global *RecordBuffer
Global RecordNumber.l
Global RecordOffset.l
Global bytes.l
Structure DBFHeadStruc
Version.a
Year.a
Month.a
Day.a
RecordCount.l
RecordLength.c
FirstRec.c
EndStructure
Global DBFHead.DBFHeadStruc
; Your .dbf (fullpath + .dbf name)
; dbf$ = "e:\utils\orders.dbf"
; dbf$ = "e:\utils\trans.dbf"
dbf$ = "e:\utils\lottario.dbf"
; TODO: Check For existence of file before proceeding
; Allocate enough memory to get the dbf header information up to and including byte 11
*MemoryID = AllocateMemory(11)
; Returns nonzero if the file was opened successfully and zero if there was an error.
; If #PB_Any was used As the #File parameter then the new generated number is returned on success.
hndFile = ReadFile(#PB_Any, dbf$)
bytes = ReadData(hndFile, *MemoryID, 11)
;
; ShowMemoryViewer(*MemoryID,10)
;
DBFHead\Version = PeekA(*MemoryID + 0)
DBFHead\Year = PeekA(*MemoryID + 1)
DBFHead\Month = PeekA(*MemoryID + 2)
DBFHead\Day = PeekA(*MemoryID + 3)
DBFHead\RecordCount = PeekL(*MemoryID + 4)
DBFHead\FirstRec = PeekC(*MemoryID + 8)
DBFHead\RecordLength = PeekC(*MemoryID + 10)
; I could have had only one OpenConsole() in my program, but I didn't
If OpenConsole()
Print(" DBF Name: ")
PrintN(dbf$)
PrintN("Byte 0: Version: " + Str(DBFHead\Version))
PrintN("Byte 1: Year: " + Str(DBFHead\Year))
PrintN("Byte 2: Month: " + Str(DBFHead\Month))
PrintN("Byte 3: Day: " + Str(DBFHead\Day))
PrintN("Byte 4-7: Record Count: " + Str(DBFHead\RecordCount))
PrintN("Byte 8-9: First Record Offset: " + Str(DBFHead\FirstRec))
PrintN("Byte 10-11: Record Length: " + Str(DBFHead\RecordLength))
PrintN("")
CloseConsole()
EndIf
If *MemoryID
FreeMemory(*MemoryID)
EndIf
; Allocate enough memory for the entire .dbf file.
; As this can be up to 2GB in size, thinking their might be a better way to do this.
; However, what if I wanted to get the last record in a 2GB file?
*MemoryID = AllocateMemory(Lof(hndFile))
*RecordBuffer = AllocateMemory(DBFHead\RecordLength)
; Change this to the record number of your choosing.
RecordNumber = 16
If RecordNumber <= DBFHead\RecordCount
RecordOffset = ((RecordNumber - 1) * DBFHead\RecordLength) + DBFHead\FirstRec
FileSeek(hndFile, RecordOffset)
Debug "Position: " + Str(Loc(hndFile))
If *RecordBuffer
bytes = ReadData(hndFile, *RecordBuffer, DBFHead\RecordLength)
Debug PeekS(*RecordBuffer, DBFHead\RecordLength, #PB_Ascii)
; I could have had only one OpenConsole() in my program, but I didn't
If OpenConsole()
PrintN("Record Number: " + Str(RecordNumber))
PrintN(PeekS(*RecordBuffer, DBFHead\RecordLength, #PB_Ascii))
CloseConsole()
EndIf
FreeMemory(*RecordBuffer)
EndIf
Else
; I could have had only one OpenConsole() in my program, but I didn't
If OpenConsole()
PrintN("Record Number exceeds Record Count")
CloseConsole()
EndIf
EndIf
If *MemoryID
FreeMemory(*MemoryID)
EndIf
CloseFile(hndFile)