Geoff Chappell - Software Analyst
From the very start, with version 3.50, even before the original Windows 95, COMCTL32 provided a set of functions for working with arrays of pointers as a way to manage ordered lists of arbitrary items. Apart from adding a handful of functions in version 4.71 and another in version 6.10, the interface has since been stable:
At the most abstract, a DPA is an ordered list of arbitrary items. The storage, lifetime and internal structure of an item are no concern to the list. An item can appear in any number of lists simultaneously. Items are put into a list only by reference: each item is represented by a pointer. Items are ordered within the list by keeping the pointers in an array. Memory for this array of pointers grows and shrinks as items are added or removed—hence the name Dynamic Pointer Array.
The DPA_Create and DPA_CreateEx functions set up an empty list, with no memory yet allocated for a pointer array, but with a choice of initial size for the allocation unit by which memory for the pointer array can grow or shrink. The DPA_Grow function forces memory to be found for at least a given size of pointer array (and may increase the allocation unit). The DPA_GetSize function reports how much memory is presently held for the array.
The DPA_Clone function prepares a list with the same items in the same order as another list. The DPA_LoadStream function creates a list of items by reading from a stream such as written by the DPA_SaveStream function. The DPA_Merge function blends the items of one list into another.
The DPA_Destroy and DPA_DestroyCallback functions destroy a list (though not, of course, the items that were listed in it).
Items are referenced within a list by giving their 0-based index in the current ordering. The DPA_GetPtr function retrieves an item from its index. Its inverse of sorts is DPA_GetPtrIndex, which finds an index for an item. The DPA_EnumCallback function enumerates the list by calling a user-supplied “callback” function for each item in turn. Through similar means, the DPA_Search function either finds an item in the list or finds where the item would appear, and the DPA_Sort function reorders whatever items are already in the list.
The DPA_InsertPtr and DPA_SetPtr functions put an item on the list. The DPA_DeletePtr function removes an item from the list. The DPA_DeleteAllPtrs function empties the list.
Though 13 of the 19 DPA functions date from as far back as Win32s, Windows NT 3.51 and the original Windows 95, and all but one of the others from Internet Explorer 4.0 (released in 1997), none were documented until late 2002 as Settlement Program Interfaces. Even then, Microsoft documented only 11, and declared these as requiring Windows 2000 as the minimum operating system.
As with much of the documentation that results from that settlement, Microsoft’s effort is extraordinarily grudging and miserly. This documentation comes with no overview of the functionality. Barely all that is offered is that for each function, such little information as a competent reader might discern from uncommented C-language prototypes is repackaged in the standard form of MSDN documentation. The C-language prototypes anyway do not seem to have been released (in COMMCTRL.H, as supplied with the Platform SDK) until 2003.
For compliance with Section III.D of the Final Judgment in a well-publicised anti-trust suit by various U.S. governments, Microsoft must document all API functions that are implemented in components of Windows and used by components of so-called Microsoft Middleware and particularly of Internet Explorer. Of the 18 pre-existing DPA functions, 15 are used by SHDOCVW.DLL, i.e., by the essence of Internet Explorer. Another, DPA_CreateEx, is used by WEBCHECK.DLL and one more, DPA_GetPtrIndex, by MSIEFTP.DLL. Only one DPA function, DPA_Grow, is plausibly an internal Windows API, whose only known use is by other components of Windows that are not components of anything that the judgement defines as a Microsoft Middleware Product.
How then can Microsoft possibly have come up with its selection of only 11 to document for the settlement? On what grounds did Microsoft omit DPA_Clone, DPA_CreateEx, DPA_GetPtrIndex, DPA_LoadStream, DPA_Merge and DPA_SaveStream? Did the relevant compliance authorities call Microsoft to account for such omission? If so, when, and where is the public record? If not, then on what grounds?
In April 2005, apparently after a contributor to a blog by Dave Massy (at Microsoft) cited DPA_LoadStream as a counter-example to Dave Massy’s insistence that all Windows API functions used by Internet Explorer are now documented, Microsoft added DPA_LoadStream and DPA_SaveStream to the list of DPA functions that Microsoft has condescended to document. As far as I know, Microsoft has not troubled to explain what principle guided the original selection of functions to document as Settlement Program Interfaces, nor to explain how or why these two were omitted for so long.
Note also how specific is Microsoft’s attention to functions that may need to be documented for the settlement. The calls to DPA_LoadStream and DPA_SaveStream are not even 500 bytes apart in the SHDOCVW executable and are implemented in the same source file. Between them, and therefore surely hard to miss in even a half-serious attempt to meet obligations, is a call to DPA_Merge. This function was literally over-looked in Microsoft’s supposedly great effort at compliance with the settlement.
Four more DPA functions got documented still later, possibly in 2005, but certainly by the August 2006 edition of the MSDN Library on CD. These newly documented functions are DPA_Clone, DPA_CreateEx, DPA_GetPtrIndex and (finally) DPA_Merge. All are said correctly to date from Windows 95, except that for DPA_Merge Microsoft sticks to the line about Windows 2000 being the minimum. For three of the four, the documentation is said to be “preliminary and subject to change” (which warning has been removed in time for the Windows Vista SDK dated January 2007).
Of the DPA functions that existed at the time of the settlement—indeed, of the original DPA functions from 1995—the last got documented even more recently, just in time for the the Windows Vista Software Development Kit (SDK) in January 2007. Through who could know what reasoning, DPA_Grow is there said to have Windows Vista as the minimum operating system.
Whether the post-settlement documentation was a low-profile correction of oversight may never be known. In some very strict sense that probably only lawyers can understand while keeping a straight face, it is now only of historical interest, not because the functions all eventually did get documented but because Microsoft has now arranged that Internet Explorer no longer calls the DPA functions in COMCTL32.
Starting with Internet Explorer 7, including as supplied with Windows Vista, Internet Explorer still uses the DPA functions but it doesn’t call them in COMCTL32. It instead calls copies that are built into a new Internet Explorer module named IERTUTIL. The code in COMCTL32 and IERTUTIL is exactly the same. Indeed, the DPA functions are all built into a statically linked library, which Microsoft’s symbol files name as comctl32_v6_static.lib. COMCTL32 and IERTUTIL each acquire the same code for the same DPA functions from this same library. But since Internet Explorer calls the copies in IERTUTIL, these previously undocumented Windows functions in COMCTL32 are no longer being used by Internet Explorer. Some would call this a sleight of hand. That it appears to have been sanctioned by the courts, wittingly or not, is to the shame of everyone involved.
To demonstrate what might reasonably be expected of Microsoft, with all its resources and all its talk of taking its obligations seriously, I returned in 2005 to a documentation sample that I prepared in 1997 for the 13 original DPA functions. I have extended this to the remaining functions (that were all introduced with Internet Explorer 4.0) and have updated it, both to match Microsoft’s nomenclature and to fit the format that I have used throughout this study of the Windows shell.