/************************************************************************ * * * HUGEARR.DLL * * * * Huge array support for Microsoft Visual Basic * * * * By Mike Warning * * * * Modifications by Jonathan Zuck. * * Modifications by Stephen Schmidt. * * Modifications by End User Computing, Ltd. * * * ************************************************************************/ #include /* Define NOCOMM so that MSC compiler does not generate messages using Warning Level 4. */ #define NOCOMM #include struct ArrayDesc { HANDLE handle; /* handle to global memory array */ int recsize; /* record size of array */ long ubound; /* upper bound of array */ int perseg; /* #elements per segment */ int redim; /* whether or not GlobalRealloc was successful */ long bsize; /* actual size in bytes of memory block allocated for array element storage */ }; typedef struct ArrayDesc *pDescrip; typedef double currency; /* currency and double are the same size and will be treated the same */ /* All of the C comments which begin with "VBI:" or "VBB:" are placed into the files HUGEARR.VBI and HUGEARR.BAS. */ /* VBI: ' An alternate set of definitions with more consistent names that you may want */ /* VBI: ' to consider using instead of those in HUGEARR.BAS. */ /* VBI: Global Const HA_OK = 0 */ /* VBI: Global Const HA_OUTOFMEMORY = -1 */ /* VBI: Global Const HA_TOMANYARRAYS = -2 */ /* VBI: Global Const HA_BADELEMENTSIZE = -3 ' no longer possible; left for backward compatibility. */ /* VBI: Global Const HA_SUBSCRIPT = -4 */ /* VBI: Global Const HA_BADARRAY = -5 */ /* VBI: Global Const HA_FILEOPENERROR = -7 */ /* VBI: Global Const HA_FILEWRITEERROR = -8 */ /* VBI: Global Const HA_FILEREADERROR = -9 */ /* VBB: ' The original set of definitions. */ /* VBB: Global Const HA_OK = 0 */ /* VBB: Global Const HA_OUTOFMEMORY = -1 */ /* VBB: Global Const HA_TOMANYARRAYS = -2 */ /* VBB: Global Const HA_BADELEMENTSIZE = -3 ' no longer possible; left for backward compatibility. */ /* VBB: Global Const HA_SUBSCRIPT = -4 */ /* VBB: Global Const HA_BADARRAY = -5 */ /* VBB: Global Const HA_FILEOPENERROR = -7 */ /* VBB: Global Const HA_FILEWRITEERROR = -8 */ /* VBB: Global Const HA_FILEREADERROR = -9 */ #define HA_OK 0 #define HA_OUTOFMEMORY -1 #define HA_TOMANYARRAYS -2 #define HA_BADELEMENTSIZE -3 /* no longer possible; left for backward compatibility */ #define HA_SUBSCRIPT -4 #define HA_BADARRAY -5 #define HA_FILEOPENERROR -7 #define HA_FILEWRITEERROR -8 #define HA_FILEREADERROR -9 HANDLE hLocalMem; /* handle to local memory */ int NumArrays; /* total number of arrays */ /************************************************************************ * LibMain - * * Standard DLL constructor. Allocates all of local heap to store * * array descriptors and then set the total number of arrays possible. * ************************************************************************/ int FAR pascal _export LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine) { if (cbHeapSize > 0) UnlockData(0); /* Allocate memory for array descrips. */ hLocalMem = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, LocalCompact((WORD) 65500)); if (hLocalMem == NULL) /* Something happened, bomb out */ return 0; /* calc total number of arrays */ NumArrays = (int) (LocalSize(hLocalMem) / sizeof(struct ArrayDesc)); return 1; } /************************************************************************ * WEP - * * Standard DLL destructor. Free up local memory and quit. * ************************************************************************/ int FAR pascal _export WEP(int bSystemExit) { LocalFree(hLocalMem); return 1; } /******************************************************************** * GetFreeArray - * * Searches the array descriptor table looking for a free entry. * * It returns the index into the table if an entry is free or * * HA_TOMANYARRAYS otherwise. pArray is the pointer to the start of * * the table. * ********************************************************************/ int GetFreeArray(pDescrip pArray) { int i = 0; /* loop until found or out of entries */ while (i < NumArrays && pArray -> handle != NULL) { ++pArray; ++i; } if (i == NumArrays) /* didn't find a spot */ return HA_TOMANYARRAYS; /* found one, return index to it */ return i; } #define HugeElementOffset(ELEMNO, PERSEG, RECSIZE) \ ELEMNO / (long) PERSEG * 0x10000L \ + ELEMNO % (long) PERSEG * (long) RECSIZE /******************************************************************** * HugeAlloc - * * Allocates (or reallocates) global memory for an array. The size * * of the array is recsize * (ubound + 1) bytes. The information * * for the array is stored in the array descriptor pointed to by * * 'pArray'. * ********************************************************************/ int HugeAlloc(pDescrip pArray, int recsize, long ubound, BOOL realloc) { int perseg; /* #elements per segment */ long newsiz; /* actual size of array */ HANDLE handle; /* temp handle for alloc */ /* ubound = #elements - 1 */ ++ubound; /* #elements per segment. */ perseg = (int) (0x10000L / (long) recsize); /* size of array in bytes */ newsiz = HugeElementOffset(ubound, perseg, recsize); if (!realloc) /* allocate a new array */ handle = GlobalAlloc(GMEM_MOVEABLE || GMEM_ZEROINIT, newsiz); else #ifndef REDIMUAES /* attempt to reallocate the existing array */ /* TO HUGEARR USERS RECEIVING UAE'S DURING CALLS TO HugeRedim: Define REDIMUAES somehow then recompile. */ if ((handle = GlobalReAlloc(pArray -> handle, newsiz, GMEM_MOVEABLE || GMEM_ZEROINIT)) != NULL) pArray -> redim = TRUE; else #endif /* existing array could not be reallocated--attempt to create a new one */ if ((handle = GlobalAlloc(GMEM_MOVEABLE || GMEM_ZEROINIT, newsiz)) != NULL) /* new array to replace the existing one was allocated okay */ { BYTE _huge *FmBegin; BYTE _huge *ToBegin; long numcopy; /* minimum of #elements in old & new array */ long curelem; /* current element during copy */ long ElemOff; /* offset of current elements for copy */ /* get pointers to the beginning of the existing and new arrays */ FmBegin = (BYTE _huge *) GlobalLock(pArray -> handle); ToBegin = (BYTE _huge *) GlobalLock(handle); /* size of original array is pArray->ubound + 1; size of new one is ubound */ numcopy = (ubound < pArray->ubound + 1L) ? ubound : pArray->ubound + 1L; /* copy each element from old array to new array, up to the min. # of elements in both arrays. */ for (curelem = 0; curelem < numcopy; curelem++) { /* byte offset of current numbered element from beginning of memory block */ ElemOff = HugeElementOffset(curelem, perseg, recsize); _fmemcpy(ToBegin + ElemOff, FmBegin + ElemOff, recsize); } GlobalUnlock(handle); GlobalUnlock(pArray -> handle); /* free old array */ GlobalFree(pArray -> handle); pArray -> redim = FALSE; } if (handle == NULL) /* out of memory */ return HA_OUTOFMEMORY; pArray -> bsize = GlobalSize(handle); /* save new handle */ pArray -> handle = handle; /* save element size */ pArray -> recsize = recsize; /* ubound = #elements - 1 */ pArray -> ubound = ubound - 1; pArray -> perseg = perseg; return HA_OK; } /************************************************************************ * HugeDim - * * Dimensions a new array. The size of the array is * * (recsize * ubound+1). Recsize is the size in bytes of each element in * * the array and ubound is the upper bound of the array. All arrays have * * a lower bound of 0. * ************************************************************************/ /* VBI: Declare Function MSHugeDim% Lib "hugearr.dll" Alias "HugeDim" (ByVal recsize%, ByVal limit&) */ /* VBB: Declare Function HugeDim% Lib "hugearr.dll" (ByVal recsize%, ByVal limit&) */ int FAR pascal _export HugeDim(int recsize, long ubound) { int hArray; /* handle to array to dimension */ pDescrip pArray; /* pointer to array descriptor */ int ret; /* return value from HugeAlloc */ pArray = (pDescrip) LocalLock(hLocalMem); /* find a free array */ if ((hArray = GetFreeArray(pArray)) == HA_TOMANYARRAYS) { /* couldn't find one, return error.*/ LocalUnlock(hLocalMem); return HA_TOMANYARRAYS; } /* allocate new array */ ret = HugeAlloc(pArray + hArray, recsize, ubound, FALSE); LocalUnlock(hLocalMem); /* if an error occured during alloc */ if (ret < 0) /* return the error, else */ return ret; else /* return the handle to the array */ /* VB users think handles start at 1 */ return hArray + 1; } #define DecCheckHandle \ /* VB users think hArray begins at 1 */ \ if (--hArray < 0 || hArray >= NumArrays) \ /* illegal array handle */ \ return HA_BADARRAY; #define CheckNotAllocYet \ if (pArray -> handle == NULL) \ { \ /* array hasn't been allocated */ \ LocalUnlock(hLocalMem); \ return HA_BADARRAY; \ } #define CheckSubscript(MAX) \ if (pArray -> ubound < MAX || element < 0) \ { \ /* subscript out of range */ \ LocalUnlock(hLocalMem); \ return HA_SUBSCRIPT; \ } /************************************************************************ * HugeRedim - * * Redimenions the given array to have the new 'ubound'. The old * * recsize is kept. All data in the array is preserved and any new data * * (created by expanding the array) is initialized to 0. * ************************************************************************/ /* VBI: Declare Function MSHugeRedim% Lib "hugearr.dll" Alias "HugeRedim" (ByVal hArray%, ByVal limit&) */ /* VBB: Declare Function HugeRedim% Lib "hugearr.dll" (ByVal hArray%, ByVal limit&) */ int FAR pascal _export HugeRedim(int hArray, long ubound) { pDescrip pArray; /* pointer to array desciptor */ register ret; /* return code of HugeAlloc */ DecCheckHandle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; if (pArray -> handle != NULL) /* reallocate array */ ret = HugeAlloc(pArray, pArray -> recsize, ubound, TRUE); else /* array has never been allocated */ ret = HA_BADARRAY; LocalUnlock(hLocalMem); return ret; } /******************************************************************** * GetHugeEl - * * Retrieves an element of the array storing it into the buffer * * pointed to by 'buffer'. hArray is the index into the descriptor * * table of the array, element is the element to get. * * * * NOTE: there is absolutely no type checking done on the buffer. * * It is up to the programmer to make sure it points to the * * correct data type. * ********************************************************************/ /* VBI: Declare Function MSHugeGet% Lib "hugearr.dll" Alias "GetHugeEl" (ByVal Index%, ByVal el&, buffer As Any) */ /* VBB: Declare Function GetHugeEl% Lib "hugearr.dll" (ByVal Index%, ByVal el&, buffer As Any) */ int FAR pascal _export GetHugeEl(int hArray, long element, BYTE FAR *buffer) { BYTE _huge *ptr; /* pointer to array element */ pDescrip pArray; /* pointer to array descriptor */ DecCheckHandle /* point to proper descriptor */ pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet CheckSubscript(element) /* calculate pointer to element */ ptr = (BYTE _huge *) GlobalLock(pArray -> handle); /* add offset of element */ ptr += HugeElementOffset(element, pArray->perseg, pArray->recsize); /* copy data */ _fmemcpy(buffer, ptr, pArray -> recsize); GlobalUnlock(pArray -> handle); LocalUnlock(hLocalMem); return HA_OK; } /* Same as GetHugeEl, except that it can copy multiple elements at one time. */ /* VBI: Declare Function MSHugeGetNum% Lib "hugearr.dll" Alias "GetHugeNEl" (ByVal Index%, ByVal el&, ByVal nelem%, buffer As Any) */ /* VBB: Declare Function GetHugeNEl% Lib "hugearr.dll" (ByVal Index%, ByVal el&, ByVal nelem%, buffer As Any) */ int FAR pascal _export GetHugeNEl(int hArray, long element, int nelem, BYTE FAR *buffer) { BYTE _huge *ToBegin; BYTE _huge *ToElem; /* pointer to array element */ pDescrip pArray; /* pointer to array descriptor */ DecCheckHandle /* point to proper descriptor */ pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet CheckSubscript(element + nelem - 1) /* calculate pointer to element */ ToBegin = (BYTE _huge *) GlobalLock(pArray -> handle); while (nelem-- > 0) { ToElem = ToBegin + HugeElementOffset(element, pArray->perseg, pArray->recsize); /* copy one element of data */ _fmemcpy(buffer, ToElem, pArray -> recsize); /* increment pointer to VB array to point to next element. */ buffer += pArray -> recsize; element ++; } GlobalUnlock(pArray -> handle); LocalUnlock(hLocalMem); return HA_OK; } /******************************************************************** * SetHugeEl - * * Sets the value of an array element. This routine is exactly * * the same as 'GetHugeEl' except that the memory copy is resversed. * ********************************************************************/ /* VBI: Declare Function MSHugeSet% Lib "hugearr.dll" Alias "SetHugeEl" (ByVal Index%, ByVal el&, buffer As Any) */ /* VBB: Declare Function SetHugeEl% Lib "hugearr.dll" (ByVal Index%, ByVal el&, buffer As Any) */ int FAR pascal _export SetHugeEl(int hArray, long element, BYTE FAR *buffer) { BYTE _huge *ptr; /* pointer to array element */ pDescrip pArray; /* pointer to array descriptor */ DecCheckHandle /* point to proper descriptor */ pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet CheckSubscript(element) /* calculate pointer to element */ ptr = (BYTE _huge *) GlobalLock(pArray -> handle); /* add offset of element */ ptr += HugeElementOffset(element, pArray->perseg, pArray->recsize); /* copy data */ _fmemcpy(ptr, buffer, pArray -> recsize); GlobalUnlock(pArray -> handle); LocalUnlock(hLocalMem); return HA_OK; } /* Same as SetHugeEl, except that it can copy multiple elements at one time. */ /* VBI: Declare Function MSHugeSetNum% Lib "hugearr.dll" Alias "SetHugeNEl" (ByVal Index%, ByVal el&, ByVal nelem%, buffer As Any) */ /* VBB: Declare Function SetHugeNEl% Lib "hugearr.dll" (ByVal Index%, ByVal el&, ByVal nelem%, buffer As Any) */ int FAR pascal _export SetHugeNEl(int hArray, long element, int nelem, BYTE FAR *buffer) { BYTE _huge *ToBegin; BYTE _huge *ToElem; /* pointer to array element */ pDescrip pArray; /* pointer to array descriptor */ DecCheckHandle /* point to proper descriptor */ pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet CheckSubscript(element + nelem - 1) /* calculate pointer to element */ ToBegin = (BYTE _huge *) GlobalLock(pArray -> handle); while (nelem-- > 0) { ToElem = ToBegin + HugeElementOffset(element, pArray->perseg, pArray->recsize); /* copy one element of data */ _fmemcpy(ToElem, buffer, pArray -> recsize); /* increment pointer to VB array to point to next element. */ buffer += pArray -> recsize; element ++; } GlobalUnlock(pArray -> handle); LocalUnlock(hLocalMem); return HA_OK; } /******************************************************************** * HugeErase - * * Deletes an array and marks it as free in the descriptor table. * * 'hArray' is the array to erase. * ********************************************************************/ /* VBI: Declare Function MSHugeErase% Lib "hugearr.dll" Alias "HugeErase" (ByVal hArray%) */ /* VBB: Declare Function HugeErase% Lib "hugearr.dll" (ByVal hArray%) */ int FAR pascal _export HugeErase(int hArray) { pDescrip pArray; /* pointer to array descriptor */ DecCheckHandle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet /* free the memory */ GlobalFree(pArray -> handle); pArray -> handle = NULL; LocalUnlock(hLocalMem); return HA_OK; } /******************************************************************** * NumHugeArrays - * * Returns the number of free entries in the array descriptor table* ********************************************************************/ /* VBI: Declare Function MSHugeNumArrays% Lib "hugearr.dll" Alias "NumHugeArrays" () */ /* VBB: Declare Function NumHugeArrays% Lib "hugearr.dll" () */ int FAR pascal _export NumHugeArrays(void) { pDescrip pArray; /* pointer to current descriptor */ int num, i; /* number free so far */ pArray = (pDescrip) LocalLock(hLocalMem); for (i = 0, num = 0; i < NumArrays; i++, pArray++) if (pArray -> handle == NULL) ++num; LocalUnlock(hLocalMem); return num; } /******************************************************************** * HugeUbound - * * Returns the upper bound of a given array * ********************************************************************/ /* VBI: Declare Function MSHugeUbound& Lib "hugearr.dll" Alias "HugeUBound" (ByVal hArray%) */ /* VBB: Declare Function HugeUbound& Lib "hugearr.dll" (ByVal hArray%) */ long FAR pascal _export HugeUbound(int hArray) { pDescrip pArray; /* pointer to array descriptor */ long ubound; /* upper bound of array */ DecCheckHandle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet ubound = pArray -> ubound; LocalUnlock(hLocalMem); return ubound; } /******************************************************************** * HugeInt - * * Same as GetHugeEl except that it explicitly returns an integer. * * Use this function when you are in an expression such as: * * i% = 5 * HugeInt(4, 5) * * * * NOTE: Because the user could store anything in the array element, * * they will not know if the value returned is a real value or * * if an error occured. Use GetHugeEl if the error code must * * be checked. * ********************************************************************/ /* VBI: Declare Function MSHugeGetInt% Lib "hugearr.dll" Alias "HugeInt" (ByVal hArray%, ByVal el&) */ /* VBB: Declare Function HugeInt% Lib "hugearr.dll" (ByVal hArray%, ByVal el&) */ int FAR pascal _export HugeInt(int hArray, long element) { int retval; GetHugeEl(hArray, element, (BYTE FAR *) &retval); return retval; } /******************************************************************** * HugeLong - * * Returns an element of a long integer array. (re. HugeInt) * ********************************************************************/ /* VBI: Declare Function MSHugeGetLong& Lib "hugearr.dll" Alias "HugeLong" (ByVal hArray%, ByVal el&) */ /* VBB: Declare Function HugeLong& Lib "hugearr.dll" (ByVal hArray%, ByVal el&) */ long FAR pascal _export HugeLong(int hArray, long element) { long retval; GetHugeEl(hArray, element, (BYTE FAR *) &retval); return retval; } /******************************************************************** * HugeSingle - * * Returns an element of a single precesion array. (re. HugeInt) * ********************************************************************/ /* VBI: Declare Function MSHugeGetSingle! Lib "hugearr.dll" Alias "HugeSingle" (ByVal hArray%, ByVal el&) */ /* VBB: Declare Function HugeSingle! Lib "hugearr.dll" (ByVal hArray%, ByVal el&) */ float FAR pascal _export HugeSingle(int hArray, long element) { float retval; GetHugeEl(hArray, element, (BYTE FAR *) &retval); return retval; } /******************************************************************** * HugeDouble - * * Returns an element of a double precesion array. (re. HugeInt) * ********************************************************************/ /* VBI: Declare Function MSHugeGetDouble# Lib "hugearr.dll" Alias "HugeDouble" (ByVal hArray%, ByVal el&) */ /* VBB: Declare Function HugeDouble# Lib "hugearr.dll" (ByVal hArray%, ByVal el&) */ double FAR pascal _export HugeDouble(int hArray, long element) { double retval; GetHugeEl(hArray, element, (BYTE FAR *) &retval); return retval; } /******************************************************************** * HugeCurrency - * * Returns an element of a currency array. (re. HugeInt) * ********************************************************************/ /* VBI: Declare Function MSHugeGetCurrency@ Lib "hugearr.dll" Alias "HugeCurrency" (ByVal hArray%, ByVal el&) */ /* VBB: Declare Function HugeCurrency@ Lib "hugearr.dll" (ByVal hArray%, ByVal el&) */ currency FAR pascal _export HugeCurrency(int hArray, long element) { currency retval; GetHugeEl(hArray, element, (BYTE FAR *) &retval); return retval; } #ifdef DEBUG /* Functions left from when I was debugging my own HugeRedim problems. --SJS */ /* Return 1 if the last HugeRedim successfully called GlobalRealloc, or return 0 if it had to call HugeAlloc and copy over elements. */ int FAR pascal _export HugeRedimOk(int hArray) { pDescrip pArray; /* pointer to array descriptor */ int RtnVal; DecCheckHandle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; RtnVal = pArray -> redim; LocalUnlock(hLocalMem); return RtnVal; } /* Return actual size in bytes of the global memory block that was allocated for storing array elements */ long FAR pascal _export HugeSize(int hArray) { pDescrip pArray; /* pointer to array descriptor */ long RtnVal; DecCheckHandle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; RtnVal = pArray -> bsize; LocalUnlock(hLocalMem); return RtnVal; } #endif /******************************************************************** * HugeSave - Saves the specified number of elements to a file * * Returns the number of items saved. * * * * NB! HugeSave does not Erase the Huge Array. * ********************************************************************/ /* VBI: Declare Function MSHugeSave& Lib "hugearr.dll" Alias "HugeSave" (ByVal hArray%, ByVal NEl&, ByVal RecLen%, ByVal Fn$) */ /* VBB: Declare Function HugeSave& Lib "hugearr.dll" (ByVal hArray%, ByVal NEl&, ByVal RecLen%, ByVal Fn$) */ long FAR pascal _export HugeSave(int hArray, long nelements, int OutLen, LPSTR FileSpec) { int hSaveFile; /* handle to the save file */ BYTE _huge *FmBegin; /* pointer for first element */ BYTE _huge *FmElem; /* pointer to array element */ long element; /* element in the huge array */ pDescrip pArray; /* pointer to array descriptor */ DecCheckHandle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet if (pArray -> ubound + 1 < nelements || nelements < 0) { /* subscript out of range */ LocalUnlock(hLocalMem); return HA_SUBSCRIPT; } /* Open the file */ hSaveFile = _lopen(FileSpec, OF_WRITE); if (hSaveFile < 0) { LocalUnlock(hLocalMem); return HA_FILEOPENERROR; } /* calculate pointer to element */ FmBegin = (BYTE _huge *) GlobalLock(pArray -> handle); for(element = 0L; element < nelements; element++) { FmElem = FmBegin + HugeElementOffset(element, pArray->perseg, pArray->recsize); /* Write out the record */ if(_lwrite(hSaveFile, FmElem, OutLen) < 0) { element = HA_FILEWRITEERROR; break; } } /* Wrap up and return */ GlobalUnlock(pArray -> handle); LocalUnlock(hLocalMem); _lclose(hSaveFile); return element; } /******************************************************************** * HugeLoad - Loads a Huge Array from the specified file * * Returns the number of elements loaded * * * * NB! The array must have been allocated and be of sufficient * * NB! size to hold the array. * ********************************************************************/ /* VBI: Declare Function MSHugeLoad& Lib "hugearr.dll" Alias "HugeLoad" (ByVal hArray%, ByVal RecLen%, ByVal Fn$) */ /* VBB: Declare Function HugeLoad& Lib "hugearr.dll" (ByVal hArray%, ByVal RecLen%, ByVal Fn$) */ long FAR pascal _export HugeLoad(int hArray, int InLen, LPSTR FileSpec) { int BytesRead; /* number of bytes read from the file */ int hLoadFile; /* handle to the save file */ BYTE _huge *ToBegin; /* pointer for first element */ BYTE _huge *ToElem; /* pointer to array element */ long element; /* element in the huge array */ pDescrip pArray; /* pointer to array descriptor */ DecCheckHandle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; CheckNotAllocYet /* Open the file */ if((hLoadFile = _lopen(FileSpec, OF_READ)) < 0) { LocalUnlock(hLocalMem); return HA_FILEOPENERROR; } ToBegin = (BYTE _huge *) GlobalLock(pArray -> handle); for(element = 0L; element <= pArray -> ubound ; element++) { /* calculate pointer to element */ ToElem = ToBegin + HugeElementOffset(element, pArray->perseg, pArray->recsize); /* Read the record */ BytesRead = _lread(hLoadFile, ToElem, InLen); if (BytesRead < 0) element = HA_FILEREADERROR; if (BytesRead <= 0) break; } /* Wrap up and return */ GlobalUnlock(pArray -> handle); LocalUnlock(hLocalMem); _lclose(hLoadFile); return element; }