| Home | Table of Contents | Please view with Internet Explorer (version 5.00 or higher) and enable scripting. For reasons, see Browsing This Web Site. |
BOOL InitCommonControlsEx (INITCOMMONCONTROLSEX const *picce);
Since the INITCOMMONCONTROLSEX structure is apparently used only for this function, its definition is as well given here:
typedef struct tagINITCOMMONCONTROLSEX {
DWORD dwSize;
DWORD dwICC;
} INITCOMMONCONTROLSEX, *LPINITCOMMONCONTROLSEX;
The picce argument provides the address of a small structure that specifies which common controls to initialise.
The function returns TRUE for success, else FALSE.
The function fails if the picce argument is NULL. Otherwise, this argument is taken as addressing an INITCOMMONCONTROLSEX structure. The function fails if the dwSize member is not the size, in bytes, of this structure. The dwICC member is then interpreted as bit flags. The function fails if any invalid flags are set. The valid flags select initialisations to perform. If any initialisation fails, then so does the function.
Each of these initialisations registers a window class for a control (except in one undocumented case, which is now retired). If the registration fails, except because the class is already registered, then the initialisation fails. Note that the initialisations are repeatable, as when the same flag is set in multiple calls to the function. The purpose of the function is thus to ensure that the window classes for the wanted types of common control are registered in advance of trying to create any of the controls.
The following table lists the valid flags. Each flag is shown with the controls whose window classes are to be registered if the flag is set. The table is also a convenient place in which to summarise which COMCTL32 versions support which flags. The phrase “4.00 (NT)” is meant to indicate that although the function first appears in at least one build of COMCTL32 version 4.00, it is not in all builds of that version, and is specifically not in the build of version 4.00 from the original Windows 95.
| Symbolic Name | Value | Controls to Register | Applicable Versions |
|---|---|---|---|
| ICC_LISTVIEW_CLASSES | 0x01 | List-View Control Header Control |
4.00 (NT) and higher |
| ICC_TREEVIEW_CLASSES | 0x02 | ToolTip Control Tree-View Control |
4.00 (NT) and higher |
| ICC_BAR_CLASSES | 0x04 | Toolbar Control ToolTip Control Status Bar Trackbar Control |
4.00 (NT) and higher |
| ICC_TAB_CLASSES | 0x08 | ToolTip Control Tab Control |
4.00 (NT) and higher |
| ICC_UPDOWN_CLASS | 0x10 | Up-Down Control | 4.00 (NT) and higher |
| ICC_PROGRESS_CLASS | 0x20 | Progress Bar Control | 4.00 (NT) and higher |
| ICC_HOTKEY_CLASS | 0x40 | Hot Key Control | 4.00 (NT) and higher |
| ICC_ANIMATE_CLASS | 0x80 | Animation Control | 4.00 (NT) and higher |
| ICC_DATE_CLASSES | 0x0100 | Month Calendar Control Date and Time Picker Control |
4.00 (NT) and higher |
| DropDown | 6.10 and higher | ||
| ICC_USEREX_CLASSES | 0x0200 | ComboBoxEx Control | 4.00 (NT) and higher |
| ICC_COOL_CLASSES | 0x0400 | Rebar Control | 4.70 and higher |
| ICC_INTERNET_CLASSES | 0x0800 | IP Address Control | 4.71 and higher |
| ICC_PAGESCROLLER_CLASS | 0x1000 | Pager Control | 4.71 and higher |
| ICC_NATIVEFNTCTL_CLASS | 0x2000 | Native Font Control | 4.71 and higher |
| ICC_STANDARD_CLASSES | 0x4000 | Button Control Static Control Edit Control ListBox Control ComboBox Control ComboLBox Control Scroll Bar Reader Mode Control |
6.00 and higher |
| ICC_LINK_CLASS | 0x8000 | SysLink Control | 6.00 and higher |
Version 4.00 does not guard against invalid flags.
Though not shown above, the ICC_STANDARD_CLASSES flag is supported in versions 5.80 and 5.81, but trivially. It is not rejected as invalid, but neither does it select an initialisation to perform. In version 5.82, the flag becomes invalid again.
An undocumented flag, 0x80000000, is supported in version 5.81 and higher. It is unusual in not causing COMCTL32 to register a window class. It appears to be intended for use by WINLOGON.EXE to arrange a reset of COMCTL32. Useful details would seem to require more study of the COMCTL32 subclassing functions than is presently within the scope of these notes.
The 0x80000000 flag is supported in builds for Windows Vista, both in version 5.82 and 6.10, but only in the sense that it is not rejected as invalid.
One of the points, if not the main point, to the SxS versions of COMCTL32 is to redirect the window classes for some controls that would otherwise be implemented in USER32. An important piece of background is that the USER32 functions that work with window classes, e.g., RegisterClass but also GetClassInfo, vary their behaviour depending on the current activation context (not that you would know this from Microsoft’s documentation of those functions). The same name may represent a different window class implemented in a different module, depending on which activation context, if any, is current when the function is called. The implication for COMCTL32 is that when InitCommonControlsEx registers window classes, it matters which activation context is current.
The first builds of versions 5.82 and 6.00 leave InitCommonControlsEx to the caller’s choice of activation context. This is surely a bug. For late 5.82 and 6.00 builds and higher, COMCTL32 imposes its own activation context while InitCommonControlsEx registers classes.
Recent developments in USER32 take away much of the reason that InitCommonControlsEx exists.
IN PROGRESS
The history of COMCTL32 includes some subtle changes to the algorithm for initialising each control. By subtle here is meant that the variations might ordinarily be uninteresting, even really uninteresting, yet they do turn out to have a practical consequence, which Microsoft certainly has realised yet doesn’t document.
In most COMCTL32 versions, the algorithm for initialising each control is to register the class if it is not already registered. Specifically, if the class is already registered (in the sense that GetClassInfo succeeds), then the initialisation succeeds. Otherwise, registration is attempted, and the initialisation succeeds or fails accordingly. A slight variation applies to the controls represented by ICC_DATE_CLASSES, such that only the class for the Month Calendar Control is checked before attempting registration of classes for both that control and the Date and Time Picker Control.
In late 5.82 builds, the initialisations just register the window classes, ignoring whether the registration succeeds or fails.
The algorithm in version 6.00 is different yet again. Registration is attempted first, and only if this fails does COMCTL32 check whether the window class is already registered (again, according to GetClassInfo). At least, this is the change for most controls. The initialisation for the Scroll Bar is just to register the class. If this registration fails, then so does the initialisation. Note the practical consequence for the affected builds of version 6.00: in multiple calls to InitCommonControlsEx with ICC_STANDARD_CLASSES set, the first will succeed (typically) but the repeats will fail (because the class is already registered).
For late 6.00 builds, Microsoft seems to have realised that there is a problem but not yet to have settled on what to do about it (and perhaps not even on what the problem actually is). For most controls, initialisation now succeeds if registration succeeds or if the error code from the registration is ERROR_CLASS_ALREADY_EXISTS. That’s not much of a change, but still the Scroll Bar is treated differently. Its initialisation is still just to register the window class, but now any failure is ignored.
Version 6.10 finally puts the Scroll Bar on equal terms. In earlier versions, the initialisation procedure for each control does its own class registration. Version 6.10 limits this procedure just to preparing the data for class registration. For all controls, the initialisation succeeds if registration succeeds or if the error code from the registration is ERROR_CLASS_ALREADY_EXISTS.
The InitCommonControlsEx function can be called automatically at process attachment, such that its explicit use by the programmer is often redundant.
That this implied call exists at all may be for backwards compatibility. In COMCTL32 versions that precede the InitCommonControlsEx function, all the supported controls are initialised automatically. If any of the initialisations fail, then so does the process attachment. The introduction of InitCommonControlsEx preserved this behaviour by calling the function at process attachment, to initialise those same controls that are supported in earlier versions and which are now represented by the flags in ICC_WIN95_CLASSES (0xFF). An early difference, however, is that failure of the initialisation is not failure for the process attachment.
All subsequent versions of COMCTL32 continue making this implied call at process attachment, but there is significant variation in the flags that are used for the call, in whether the call is made only in particular circumstances, and in whether failure of the initialisation is failure for the process attachment.
| Versions | Flags | Conditions | Failure |
|---|---|---|---|
| 4.00 (NT) and 4.70 | ICC_WIN95_CLASSES | ignored | |
| 4.71 to 5.81 | ICC_WIN95_CLASSES | ||
| 5.82 (Windows XP) | all valid documented flags (0x3FFF) | ||
| 5.82 (Windows Server 2003) 5.82 (Windows Vista) |
ICC_WIN95_CLASSES | if 16-bit process | ignored |
| 6.00 (Windows XP) | all valid documented flags (0xFFFF) | ignored | |
| 6.00 (Windows Server 2003) 6.10 |
all valid documented flags (0xBFFF) except ICC_STANDARD_CLASSES |
if 16-bit process | ignored |
All that Microsoft’s documentation finds to say about any of these cases is:
Windows XP: If a manifest is used, InitCommonControlsEx is not required.
Although the statement is true, it would be true even without the bit about using a manifest. Perhaps the author at Microsoft had something else in mind entirely, but the simple fact is that the Windows XP builds of COMCTL32, for both version 5.82 and 6.00, already have called InitCommonControlsEx for all valid documented flags before the programmer’s own code has a chance. The InitCommonControlsEx function is redundant for the Windows XP builds, whether a manifest is used or not. Even for COMCTL32 versions from before Windows XP, the implied call means that InitCommonControlsEx is redundant for the controls that pre-date the function.
Moreover, Microsoft’s documentation conveniently understates a problem. In the early builds of version 6.00, not only is InitCommonControlsEx “not required” when a manifest is used, it is better left alone. For the programmer who thinks to include ICC_STANDARD_CLASSES among the set flags, the function will be nothing but trouble. Because of the implied call, which will almost certainly have succeeded, the programmer’s explicit call will fail. Microsoft cannot be ignorant of this case, nor of the trouble it may cause, so why isn’t it documented?
The InitCommonControlsEx function is exported by name from COMCTL32.DLL in version 4.70 and higher, but also in one build of version 4.00. The function is certainly not exported from COMCTL32 in the original Windows 95, but is in 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.)
The function has long been documented, but not always. Its only mention in the January 1997 edition of the MSDN Library on CD is in two articles from Microsoft Systems Journal which promote development for Internet Explorer as the way to get “new and improved common controls” for arbitrary Windows programs. Note that version 4.70 had been on retail release for much of 1996, both in Windows NT 4.0 and Windows 95 OSR2.
The documentation puts the “minimum DLL version” at 4.70 for the InitCommonControlsEx function but at 4.71 for the INITCOMMONCONTROLSEX structure. This discrepancy is present at least as early as the January 1999 edition of the MSDN Library on CD.