Getting Past the 2 Gb File Limit

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

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.
  • {Security}: Security Access. (You don’t use this for this module, although you can add it according to your needs.)

  • {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.

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.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read