/************************************************************************ * * * HUGEARR.DLL * * * * Huge array support for Microsoft Visual Basic * * * * By Mike Warning * * * ************************************************************************/ #include #include #include "hugearr.h" 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 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) return 0; // Something happened, bomb out // 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 WEP(int bSystemExit) { LocalFree(hLocalMem); return (1); } /************************************************************************ * 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. * * * * Note: If total size of the array is greater than 64k, recsize should * * be an integer power of two (1,2,4,8,16,etc.) Otherwise, the * * huge pointers will not be added correctly. * ************************************************************************/ int FAR pascal 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) { LocalUnlock(hLocalMem); // couldn't find one, return (HA_TOMANYARRAYS); // return error. } // allocate new array ret = HugeAlloc(pArray + hArray, recsize, ubound, FALSE); LocalUnlock(hLocalMem); if (ret < 0) // if an error occured during alloc return (ret); // return the error, else else return (hArray); // return the handle to the array } /************************************************************************ * 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. * * * * Note: The recsize must be an integer power of two if the total array * * size is greater than 64k. * ************************************************************************/ int FAR pascal HugeRedim(int hArray, long ubound) { pDescrip pArray; // pointer to array desciptor register ret; // return code of HugeAlloc if (hArray < 0 | hArray >= NumArrays) return (HA_BADARRAY); // illegal array handle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; if (pArray -> handle != NULL) // reallocate array ret = HugeAlloc(pArray, pArray -> recsize, ubound, TRUE); else ret = HA_BADARRAY; // array has never been allocated LocalUnlock(hLocalMem); return (ret); } /******************************************************************** * 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); return (i); // found one, return index to it } /******************************************************************** * 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. * ********************************************************************/ int FAR pascal GetHugeEl(int hArray, long element, BYTE FAR *buffer) { BYTE _huge *ptr; // pointer to array element pDescrip pArray; // pointer to array descriptor if (hArray < 0 || hArray >= NumArrays) return (HA_BADARRAY); // illegal array handle // point to proper descriptor pArray = (pDescrip) LocalLock(hLocalMem) + hArray; if (pArray -> handle == NULL) { LocalUnlock(hLocalMem); return (HA_BADARRAY); // array hasn't been allocated } if ((pArray -> ubound < element) || (element < 0)) { LocalUnlock(hLocalMem); return (HA_SUBSCRIPT); // subscript out of range } // calculate pointer to element ptr = (BYTE _huge *) GlobalLock(pArray -> handle); ptr = ptr + element * pArray->recsize; _fmemcpy(buffer, ptr, pArray -> recsize); // copy data 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. * ********************************************************************/ int FAR pascal SetHugeEl(int hArray, long element, BYTE FAR *buffer) { BYTE _huge *ptr; // pointer to array element pDescrip pArray; // pointer to array descriptor if (hArray < 0 || hArray >= NumArrays) return (HA_BADARRAY); // illegal array handle // point to proper descriptor pArray = (pDescrip) LocalLock(hLocalMem) + hArray; if (pArray -> handle == NULL) { LocalUnlock(hLocalMem); return (HA_BADARRAY); // array hasn't been allocated } if ((pArray -> ubound < element) || (element < 0)) { LocalUnlock(hLocalMem); return (HA_SUBSCRIPT); // subscript out of range } // calculate pointer to element ptr = (BYTE _huge *) GlobalLock(pArray -> handle); ptr = ptr + element * pArray->recsize; _fmemcpy(ptr, buffer, pArray -> recsize); // copy data 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. * ********************************************************************/ int FAR pascal HugeErase(int hArray) { pDescrip pArray; // pointer to array descriptor if (hArray < 0 || hArray >= NumArrays) return (HA_BADARRAY); // illegal array handle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; if (pArray -> handle == NULL) { LocalUnlock(hLocalMem); return (HA_BADARRAY); // array hasn't been allocated yet } GlobalFree(pArray -> handle); // free the memory pArray -> handle = NULL; LocalUnlock(hLocalMem); return (HA_OK); } /******************************************************************** * NumHugeArrays - * * Returns the number of free entries in the array descriptor table* ********************************************************************/ int FAR pascal 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 * ********************************************************************/ long FAR pascal HugeUbound(int hArray) { pDescrip pArray; // pointer to array descriptor long ubound; // upper bound of array if (hArray < 0 || hArray >= NumArrays) return (HA_BADARRAY); // illegal array handle pArray = (pDescrip) LocalLock(hLocalMem) + hArray; if (pArray -> handle == NULL) { LocalUnlock(hLocalMem); return (HA_BADARRAY); // array hasn't been allocated yet } 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. * ********************************************************************/ int FAR pascal 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) * ********************************************************************/ long FAR pascal 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) * ********************************************************************/ float FAR pascal 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) * ********************************************************************/ double FAR pascal 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) * ********************************************************************/ currency FAR pascal HugeCurrency(int hArray, long element) { return((currency) HugeDouble(hArray, element)); } /******************************************************************** * 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'. * * * * Note: See HugeDim for a discussion on array size limitations. * ********************************************************************/ int HugeAlloc(pDescrip pArray,int recsize,long ubound, BOOL realloc) { HANDLE handle; // temp handle for alloc ++ubound; // ubound = #elements - 1 if (recsize * ubound > 0xffff) // is size integer power two? if ((recsize <= 0) || (((recsize - 1) & recsize) != 0)) return (HA_BADELEMENTSIZE); if (realloc) // allocate array handle = GlobalReAlloc(pArray -> handle, recsize * ubound, GMEM_MOVEABLE || GMEM_ZEROINIT); else handle = GlobalAlloc(GMEM_MOVEABLE || GMEM_ZEROINIT, recsize * ubound); if (handle == NULL) return (HA_OUTOFMEMORY); // out of memory pArray -> handle = handle; // save new handle pArray -> recsize = recsize; // record element size pArray -> ubound = ubound - 1; return (HA_OK); }