Using Createfile Readfile and Writefile


for dynamic GFA Basic ListBoxes



This example demonstrates directly loading a file to a GFA Basic 32

ListBox object with Readfile and Writefile. It will then add a text line

to the ListBox, then close and re-dimension the file memory buffer and

create a new file. It will then write the expanded Listbox contents to

the new buffer in memory and Save the buffer content to the new file.

Finally, it will load the new file back into the Listbox.


This example uses the Microsoft recommended method for allocating

virtual 32 bit memory in Windows. It is virtual because the memory

locations exist only in operating system code and are not the same

as the locations in the actual physical RAM , so that the application

will think that it has a linear addressing memory, that is not chunked

up into segments like 16 bit windows.


The allocated memory buffer is properly released and redimensioned

as required, so there is no buildup of unreleased memory or “leakage”

while the application is in use or after the application has closed.



The zip file contains the listbox testLB.txt file for the example.


Click here to download ListBox_ReadfileWritefileDirect.zip




By Allan Shura 2009


'use CreateFile first before Readfile and Writefile


'for direct reading and writing and redimensioning of

'text items from file

'for GFA Basic 32 listboxes


Global dwFileSize As Double

Global dwError As Double 'error code variable

Global lpBuffer As Long


@DefineW32Constants


LoadForm frm1

Ocx ListBox lb1 = "", 0, 0, 420, 260

lb1.ScrollBars = 3

lb1.Sorted = False


Global MemoryBuffer$

MemoryBuffer$ = "W32MemBuff"

@InitArr


Global FileName As String

FileName = App.Path + "\testLB.txt"


@GB_ReadFile_TextToListbox_W32MemBufCreate(FileName)


'change the filename and add to the listbox text

'and also create a new file

FileName = App.Path + "\testhello.txt"


@GB_WriteFile_TextFromListbox_W32MemBufCreate(FileName)


'see the expanded listbox from the new file

@GB_ReadFile_TextToListbox_W32MemBufCreate(FileName)


@AppCloseArr 'release all buffer memory


Do : Sleep : Until Me Is Nothing


End


Function GB_ReadFile_TextToListbox_W32MemBufCreate(FileName As String)


'CreateFile Parameters

Dim lpFileName As Long 'pointer to name of the file

Dim dwDesiredAccess As Double 'access (GENERIC_READ or GENERIC_WRITE) mode or 0 query attributes

Dim dwShareMode As Double 'share mode (FILE_SHARE_READ FILE_SHARE_WRITE)

Dim lpSecurityAttributes As Long 'pointer to security attributes

Dim dwCreationDistribution As Double 'CREATE_NEW Creates a new file. Fails if exists.

Dim dwFlagsAndAttributes As Double 'file attributes

'ReadFile Parameters

Dim hFile As Handle

Dim nNumberOfBytesToRead As Double

Dim lpNumberOfBytesRead As Long

Dim lpOverlapped As Long

'SetFilePointer Parameters

Dim lDistanceToMove As Long 'number of bytes to move file pointer

Dim lpDistanceToMoveHigh As Long 'address of high-order word of distance to move

Dim dwMoveMethod As Double 'how to move


lDistanceToMove = Null

lpDistanceToMoveHigh = Null

dwMoveMethod = 3


Dim ret As Double 'return variable


'Initialize file handle and error variable.

hFile = -1

dwError = 0

'Open for for read

hFile = CreateFile(FileName, GENERIC_READ Or GENERIC_WRITE , FILE_SHARE_READ Or FILE_SHARE_WRITE, Null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)


'If we couldn't open the file, get the last error.

If hFile = -1 Then

dwError = Err.LastDllError 'point to Win 32 system error code

Else 'Existing was sucessfully opened

MsgBox "OK the file was opened."

'useing lpFileSizeHigh=Null=max size=_maxInt=&HFFFFFFFF

dwFileSize = GetFileSize(hFile, Null) 'simular to LOF(#)


If dwFileSize = _maxInt '_maxInt special GB32 Variable

MsgBox "File Too large."

Exit Func

EndIf

If dwFileSize = 0

MsgBox "A zero Byte file was opened."

Exit Func

EndIf


Try

arrszW32MemBuff% = dwFileSize

MemoryBuffer$ = "W32MemBuff"

@ReDimArr 'redimension with memory released

Catch

MsgBox "Error W32 Memory Buffer"

EndCatch


lpBuffer = sadrW32MemBuff%

nNumberOfBytesToRead = dwFileSize

lpNumberOfBytesRead = lpBuffer - 4

'oddly enough

'the pointer is moved back to account for the

' 4 bytes of array discriptor

lpOverlapped = Null 'the read is limited to _maxInt

'here we can end the 32k selector memory model

'(chunking) by implementing ReadFile

ret = SetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod)


Try


ret = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped) // address of structure for data


'***ListBox Reading Text lines only***


Local n%, m%, a$

lb1.Clear

For n% = 0 To dwFileSize


a$ = ""


Repeat

a$ = a$ + Chr(Peek(lpBuffer + n%))

Inc n%

Until (Peek(lpBuffer + n%) = 13) _

And (Peek(lpBuffer + n% + 1) = 10) _

Or n% = dwFileSize

Inc n%

If n% < dwFileSize - 1

lb1.AddItem a$

EndIf


Next n%


MsgBox Str(ret) + " = Readfile Success"


Catch

If dwError <> 0

dwError = Err.LastDllError

MsgBox "Read of file failed: " + Str(dwError)

EndIf

EndCatch


~CloseHandle(hFile)

DoEvents


End If


If dwError <> 0

@FileIOErrorMsg

EndIf


End Function

Function GB_WriteFile_TextFromListbox_W32MemBufCreate(FileName As String)


'CreateFile Parameters

Dim lpFileName As Long 'pointer to name of the file

Dim dwDesiredAccess As Double 'access (GENERIC_READ or GENERIC_WRITE) mode or 0 query attributes

Dim dwShareMode As Double 'share mode (FILE_SHARE_READ FILE_SHARE_WRITE)

Dim lpSecurityAttributes As Long 'pointer to security attributes

Dim dwCreationDistribution As Double 'CREATE_NEW Creates a new file. Fails if exists.

Dim dwFlagsAndAttributes As Double 'file attributes

'WriteFile Parameters

Dim hfwrite As Handle

Dim nNumberOfBytesToWrite As Double

Dim lpNumberOfBytesWritten As Double

Dim lpOverlapped As Long

'SetFilePointer Parameters

Dim lDistanceToMove As Long 'number of bytes to move file pointer

Dim lpDistanceToMoveHigh As Long 'address of high-order word of distance to move

Dim dwMoveMethod As Double 'how to move

lDistanceToMove = Null

lpDistanceToMoveHigh = Null

dwMoveMethod = 3


Dim ret As Double 'return variable


'Initialize file handle and error variable.

hfwrite = 0

dwError = 0


'***IMPORTANT CHANGE Constant

'CREATE_ALWAYS

'***************************


'Open for for Writing

hfwrite = CreateFile(FileName, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, Null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)


'If we couldn't open the file, get the last error.

If hfwrite = 0 Then

dwError = Err.LastDllError //point to Win 32 system error code

Else 'Existing was sucessfully opened

MsgBox "OK the file was opened."


If dwFileSize = _maxInt ' _maxInt special GB32 Variable

MsgBox "File Too large."

Exit Func

EndIf

If dwFileSize = 0

MsgBox "A zero Byte file was opened."

Exit Func

EndIf


'**redimension buffer before writing

lb1.AddItem "Hello World"


'Count the buffer size

Local a$

Local n%, ListBoxTextBytes%

For n% = 0 To lb1.ListCount - 1

ListBoxTextBytes% = ListBoxTextBytes% + Len(Str(lb1.List(n%))) + 2 'add the 2 text eol chars

Next n%


'add 4 discriptor bytes

ListBoxTextBytes% = ListBoxTextBytes% + 4


Try

arrszW32MemBuff% = ListBoxTextBytes%

MemoryBuffer$ = "W32MemBuff"

@ReDimArr

Catch

MsgBox "Error W32 Memory Buffer"

EndCatch

W32MemBuff_ofs% = sadrW32MemBuff%

For n% = 0 To lb1.ListCount - 1

a$ = Str(lb1.List(n%))

MemCpy(V:a$, W32MemBuff_ofs%, Len(a$))

W32MemBuff_ofs% = W32MemBuff_ofs% + Len(a$)

Poke W32MemBuff_ofs%, 13

Inc W32MemBuff_ofs%

Poke W32MemBuff_ofs%, 10

Inc W32MemBuff_ofs%

Next n%


lpBuffer = sadrW32MemBuff%

nNumberOfBytesToWrite = ListBoxTextBytes%

lpNumberOfBytesWritten = 0


lpOverlapped = Null 'the Written is limited to _maxInt

'here we can end the 32k selector memory model

'(chunking) by implementing WriteFile

ret = SetFilePointer(hfwrite, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod)


'**** return **** 0 = True ***

Try

~WriteFile(hfwrite, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, 0) // address of structure for data

Catch

EndCatch


dwError = Err.LastDllError

If dwError <> 0

MsgBox "Write of file failed: " + Str(dwError)

@FileIOErrorMsg

Else

MsgBox " = Writefile Success"

EndIf


~CloseHandle(hfwrite)

DoEvents


EndIf


If dwError <> 0

@FileIOErrorMsg

EndIf


End Function

Procedure FileIOErrorMsg

If dwError = 2 'ERROR_FILE_NOT_FOUND

MsgBox "ERROR_FILE_NOT_FOUND"

Else If dwError = 3 'ERROR_PATH_NOT_FOUND

MsgBox "ERROR_PATH_NOT_FOUND"

Else If dwError = 4 'ERROR_TOO_MANY_OPEN_FILES

MsgBox "ERROR_TOO_MANY_OPEN_FILES"

Else If dwError = 5 'ERROR_ACCESS_DENIED

MsgBox "ERROR_ACCESS_DENIED"

Else If dwError = 6 'ERROR_INVALID_HANDLE

MsgBox "ERROR_INVALID_HANDLE"

Else If dwError = 32 'ERROR_SHARING_VIOLATION

MsgBox "ERROR_SHARING_VIOLATION"

Else If dwError = 33 'ERROR_LOCK_VIOLATION

MsgBox "ERROR_LOCK_VIOLATION"

Else If dwError = 110 'ERROR_OPEN_FAILED

MsgBox "ERROR_OPEN_FAILED"

Else If dwError = 111 'ERROR_BUFFER_OVERFLOW

MsgBox "ERROR_BUFFER_OVERFLOW"

Else If dwError = 112 'ERROR_DISK_FULL

MsgBox "ERROR_DISK_FULL"

Else

' MsgBox "Unspecified error on opening file: " + Str(dwError)

EndIf

Return

Procedure DefineW32Constants

Global Const MOVEFILE_REPLACE_EXISTING = &H100

'check reference

Global Const FILE_ATTRIBUTE_NORMAL = &H000

Global Const FILE_ATTRIBUTE_READONLY = &H001

Global Const FILE_ATTRIBUTE_HIDDEN = &H002

Global Const FILE_ATTRIBUTE_SYSYEM = &H004

Global Const FILE_ATTRIBUTE_DIRECTORY = &H010

Global Const FILE_ATTRIBUTE_ARCHIVE = &H020

'check reference

Global Const FILE_ATTRIBUTE_TEMPORARY = &H100

Global Const FILE_BEGIN = 0

Global Const FILE_SHARE_READ = &H1

Global Const FILE_SHARE_WRITE = &H2

Global Const CREATE_NEW = 1

Global Const CREATE_ALWAYS = 2 'Creates a new file. Overwrites the file if it exists.

Global Const OPEN_EXISTING = 3

Global Const GENERIC_READ = &H80000000

Global Const GENERIC_WRITE = &H40000000

Return

Procedure InitArr

If MemoryBuffer$ = "W32MemBuff"

Global hmemW32MemBuff As Handle

Global badW32MemBuff%

Global sadrW32MemBuff%

Global arrszW32MemBuff%, arrdimW32MemBuff%

Global W32MemBuff_index%, W32MemBuff_ofs%

Global FlagFirstCreateArr_W32MemBuff| = 0

Global FlagArrActive_W32MemBuff| = 0

EndIf

Return

Procedure CreateArr

If MemoryBuffer$ = "W32MemBuff"

badW32MemBuff% = -1

hmemW32MemBuff = GlobalAlloc(0, arrszW32MemBuff%)'GMEM_FIXED is 0

sadrW32MemBuff% = GlobalLock(hmemW32MemBuff) //casting return value

badW32MemBuff% = IsBadReadPtr(sadrW32MemBuff%, arrszW32MemBuff%) // address of memory block

FlagArrActive_W32MemBuff| = 1 'flag for program and end release

If badW32MemBuff% = -1

MsgBox "Bad Pointer W32MemBuff"

Else 'flush buffer

MemZero sadrW32MemBuff%, arrszW32MemBuff%

EndIf

EndIf

Return

Procedure ReleaseArr

If MemoryBuffer$ = "W32MemBuff"

MemZero sadrW32MemBuff%, arrszW32MemBuff% 'flush

~GlobalUnlock(hmemW32MemBuff)

hmemW32MemBuff = GlobalFree(hmemW32MemBuff)

FlagArrActive_W32MemBuff| = 0

EndIf

Return

Procedure ReDimArr

If MemoryBuffer$ = "W32MemBuff"

If FlagFirstCreateArr_W32MemBuff| = 0

@CreateArr

FlagFirstCreateArr_W32MemBuff| = 1

Else

If FlagArrActive_W32MemBuff| = 1

@ReleaseArr

EndIf

@CreateArr

EndIf

EndIf

Return

Procedure AppCloseArr

If FlagArrActive_W32MemBuff| = 1

MemoryBuffer$ = "W32MemBuff"

@ReleaseArr

EndIf

Return