VB6 has its little bugs and quirks; we have all learnt to program around them. In recent times, it’s become necessary to work with extremely large files, some that may break the 2 Gb barrier that VB has. So, to start, look closer at the VB 6 IDE and why you have this barrier.
When working in the IDE, any numbers that are entered are limited to a Long variable type. Actually, as far I’ve found, the IDE uses Longs for most numeric storage within the projects that you write.
Okay, so what’s the problem with Longs? Well, by definition they are a signed 4-byte variable, in hex &H7FFFFFFF, with a lower limit of -2,147,483,648 and an upper limit of 2,147,483,647 (2 Gb). &H80000000 stores the sign of the value. Even when you enter values in Hex, they are stored in a Long.
Working with random access files, you quite often use a Long to store the filesize and current position, completely unaware that if the file you access is just one byte over the 2 Gb size, you can cause our application to corrupt the file when writing to it.
Unfortunately, there is no quick fix for this. To get around the problem, you need to write your own file handling module, one that uses windows APIs to open, read, write, and close any file.
Note: C++ apparently has a similar problem; the process described here can be exactly duplicated into C++. Simple code is included in C++. The first inspection of VB .NET does not seem to suffer with the same IDE restrictions, but for the interest of it, a VB .NET module is also included. The methods described here can be used on any Win32 Language IDE that has a 2 Gb file limit.
The first API you will look at is CreateFile:
Declaration
CreateFile ({FileName} as String, {Access} as (uInt32), _ {ShareMode} as (uInt32), {Security} as Any, _ {Disposition} as (uInt32), {Attributes} as (uInt32), _ {TemplateFile} as (uInt32)) as (uInt32)
When you look at it the first time, it looks very intimidating, but there’s not much to it. CreateFile is used to open files, existing or new.
- {FileName}: The file to be opened, including full path name.
- {Access}: Read and/or write access requirement.
- {ShareMode}: Share mode for file access.
- {Disposition}: Opening method. In other words: Create new, open existing.
- {Attributes}: Additional file attributes. (Again unused here, but you can add according to your needs.)
- {TemplateFile}: File handle of a template file when creating a new file. (Again unused here, but you can add according to your needs.)
- {Returns}: The file handle of the opened file.
{Security}: Security Access. (You don’t use this for this module, although you can add it according to your needs.)
Before using CreateFile and a few other APIs. you need to define a few variables, namely:
VB6
Const MOVEFILE_REPLACE_EXISTING = &H1 Const FILE_ATTRIBUTE_TEMPORARY = &H100 Const FILE_BEGIN = 0 Const FILE_SHARE_READ = &H1 Const FILE_SHARE_WRITE = &H2 Const CREATE_NEW = 1 Const CREATE_ALWAYS = 2 Const OPEN_EXISTING = 3 Const OPEN_ALLWAYS = 4 Const GENERIC_READ = &H80000000 Const GENERIC_WRITE = &H40000000
VB .NET
Const MOVEFILE_REPLACE_EXISTING As Short = &H1s Const FILE_ATTRIBUTE_TEMPORARY As Short = &H100s Const FILE_BEGIN As Short = 0 Const FILE_SHARE_READ As Short = &H1s Const FILE_SHARE_WRITE As Short = &H2s Const CREATE_NEW As Short = 1 Const CREATE_ALWAYS As Short = 2 Const OPEN_EXISTING As Short = 3 Const OPEN_ALLWAYS As Short = 4 Const GENERIC_READ As Integer = &H80000000 Const GENERIC_WRITE As Integer = &H40000000
And then, you need to define the function.
VB6
Private Declare Function CreateFile Lib "kernel32" _ Alias "CreateFileA" (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, _ ByVal lpSecurityAttributes As Any, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long) As Long
VB .NET
Private Declare Function CreateFile Lib "kernel32" _ Alias "CreateFileA" (ByVal lpFileName As String, _ ByVal dwDesiredAccess As uInteger, _ ByVal dwShareMode As uInteger, _ ByVal lpSecurityAttributes As Integer, _ ByVal dwCreationDisposition As uInteger, _ ByVal dwFlagsAndAttributes As uInteger, _ ByVal hTemplateFile As uInteger) As uInteger
In C++, there is no need to define the API function.
Later in the article, you will start writing your modules; but, for now, you will look at the individual usages.
FileHandle = CreateFile(FileName, GENERIC_READ Or GENERIC_WRITE, _ FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, OPEN_EXISTING, 0, 0)
VB .NET
FileHandle = CreateFile(FileName, GENERIC_READ Or GENERIC_WRITE, _ FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
C++
HANDLE FileHandle = CreateFile(Filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0&, 0&);
Note: When using CreateFile with the OPEN_EXISTING option, and the file does not exist, CreateFile returns an error. Take care in using the CREATE_ALWAYS option for Disposition; this will completely erase the named file, and create a new 0-byte file. CREATE_NEW will return a error if the named file exists.
The next API you will look at is GetFileSize. This API simply returns the current size of the opened file.
Declaration
GetFileSize ({FileHandle} as (uInt32), _ { FileSizeHigh } as (uInt32)) as (uInt32)
- {FileHandle}: File Handle of the opened file
- {FileSizeHigh}: Returns the high 32bits of the file size
- {Returns}: The Low 32bits of the file size
Definition
VB6
Private Declare Function GetFileSize Lib "kernel32" _ (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
VB .NET
Private Declare Function GetFileSize Lib "kernel32" _ (ByVal hFile As uInteger, lpFileSizeHigh As uInteger) As uInteger
Usage
VB6 and VB .NET
FileSizeL = GetFileSize (FileNumber, FileSizeH)
C++
DWORD FileSizeL = GetFileSize (FileNumber, FileSizeH);
Next, you look at SetFilePointer. This API is used to set the current position in the open file. This function is very important because any reads or writes to the file do not automatically forward the file position.
Declaration
SetFilePointer ({FileHandle} as (uInt32), _ { FilePosLow } as (uInt32), { FilePosHigh } as (uInt32), _ {MoveMethod} as (uInt32)) as (uInt32)
- {FileHandle}: File Handle of the opened file
- {FilePosLow}: The Low 32bits of the file pos
- {FilePosHigh}: The High 32bits of the file pos
- {MoveMethod}: The Method to use when setting a new position
- {Returns}: Error Code
Definition
VB6
Private Declare Function SetFilePointer Lib "kernel32" _ (ByVal hFile As Long, ByVal lDistanceToMove As Long, _ lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
VB .NET
Private Declare Function SetFilePointer Lib "kernel32" _ (ByVal hFile As uInteger, ByVal lDistanceToMove As uInteger, _ lpDistanceToMoveHigh As uInteger, _ ByVal dwMoveMethod As Integer) As Integer
Usage
VB6 and VB .NET
Ret = SetFilePointer(FileNumber, PosL, PosH, FILE_BEGIN)
C++
SetFilePointer (FileNumber, PosL, PosH, FILE_BEGIN);
On the next page, you will start writing some of your own functions in your module using the above three APIs. Also, you look at how to get your upper and lower 32-bit variables to use in the APIs.