Geoff Chappell - Software Analyst
This function sets a new capacity for a DPA.
BOOL DPA_Grow ( HDPA pdpa, int cpCapacity);
The pdpa argument provides a handle to the DPA.
The cpCapacity argument provides the new capacity for the array, measured as a number of pointers.
The function returns TRUE to indicate success, else FALSE for failure.
The function fails if the given DPA handle is NULL or if the desired capacity is negative. The function cannot reduce the memory used for the pointer array: it succeeds trivially if cpCapacity is not greater than the existing capacity.
Otherwise, the function arranges for the given DPA to have at least the given capacity for storing pointers. If the DPA has no memory currently allocated to its pointer array, the function seeks fresh memory from whichever heap was specified or implied when the DPA was created. If memory exists already for the pointer array but is not as large as wanted, the function seeks a reallocation. Either way, the capacity sought is calculated by rounding up from cpCapacity to a multiple of the current allocation unit. The function fails if the rounded-up capacity would be too large for a positive signed integer.
The allocation unit is set when the DPA is created, but this function may change it (including when called internally for other DPA functions). Specifically, after a successful allocation or reallocation of memory for the pointer array, if the allocation unit is less than 256 pointers, it gets doubled.
Defence against a NULL pdpa argument begins in a build of version 4.0. Specifically, there is no defence in the version 4.0 from Windows 95, or in any earlier version, but there is in the version 4.0 for Internet Explorer 3.00 for Windows NT. (I have no copy of an Internet Explorer 3.00 for Windows 95. See the list of COMCTL32 versions found for this survey.)
Doubling the allocation unit dates from version 4.70.
For later versions of the function, Microsoft’s programmers make rather heavy work of the possibility of arithmetic overflow when rounding up the desired capacity. Historically, the function has a simple computation in signed arithmetic:
int capacity = (cpCapacity + pdpa -> cpGrow - 1) / pdpa -> cpGrow * pdpa -> cpGrow;
The versions 5.82 and 6.0 from Windows Server 2003 SP2 introduce an explicit defence against a negative cpCapacity, and change to unsigned arithmetic, and require that the result be less than 0x3FFFFFFF:
UINT capacity = (UINT) (cpCapacity + pdpa -> cpGrow - 1) / pdpa -> cpGrow * pdpa -> cpGrow; if (capacity >= MAXSIZE_T / sizeof (PVOID)) return FALSE;
The version 5.82 from Windows Vista retains the defence against a negative capacity, but calls a function (named DXA_RoundUp according to the symbol files) to do the rounding up. The effect of the function, if inlined into DPA_Grow, would be:
UINT temp = cpCapacity + pdpa -> cpGrow - 1; if (temp < (UINT) cpCapacity) return FALSE; int capacity = temp / pdpa -> cpGrow * pdpa -> cpGrow; if ((UINT) capacity > (UINT) MAXINT) return FALSE;
Though version 6.10 is contemporaneous with the version 5.82 from Windows Vista, it removes the explicit defence against a negative capacity, and changes the arithmetic yet again:
UINT temp = cpCapacity + pdpa -> cpGrow - 1; if (temp < (UINT) cpCapacity) return FALSE; if (temp > (UINT) MAXINT) return FALSE; int capacity = (int) temp / pdpa -> cpGrow * pdpa -> cpGrow;
Is it a relief that even Microsoft’s programmers, presumably even from among their best and brightest (to be trusted with an executable as important as COMCTL32), have so much trouble with signed versus unsigned integers and with arithmetic overflow?
The DPA_Grow function is exported from COMCTL32.DLL as ordinal 330 in version 3.50 and higher. The implementation for version 6.10 and higher is built into a statically linked library and thence is also exported from the Internet Explorer module IERTUTIL.DLL as ordinal 84 in version 7.0 and higher.
Though this function dates from as long ago as 1995, it was still not documented by Microsoft in the MSDN Library at least as late as the CD edition dated January 2004.
This function did, however, get documented in 2006. This article now uses Microsoft’s nomenclature.