InitCommonControlsEx

Declaration

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;

Parameters

The picce argument provides the address of a small structure that specifies which common controls to initialise.

Return Value

The function returns TRUE for success, else FALSE.

Behaviour

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.

Initialisation for WINLOGON

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.

Activation Contexts

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.

Window Class Redirection

Recent developments in USER32 take away much of the reason that InitCommonControlsEx exists.

IN PROGRESS

Initialisation Algorithms

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.

Implied Use

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?

Availability

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.