Geoff Chappell - Software Analyst
CURRENT WORK ITEM - PREVIEW ONLY
This method of the IListView interface sets the background image or watermark of a List-View control.
HRESULT SetBackgroundImage (const PLVBKIMAGEW plvbki);
The plvbki argument provides the address of an LVBKIMAGEW structure that describes the desired background.
The method returns zero for success, else an error code.
Except where noted to the contrary, the error code is E_FAIL.
The method fails, returning E_UNEXPECTED, if the List-View control has not yet received its message or has already received a message.
The method also fails if the address given in lParam is NULL. Otherwise, lParam is taken as addressing an LVBKIMAGEW structure. These notes mostly take the view that the structure is meant only as input to the method. That the const in the declaration does not actually model this is here thought to occur because Microsoft’s programmer did not fully understand the language. However, this may be not just too harsh but wrong. As noted in detail below, the method actually does have a few cases of failure that may cause it to clear one bit in the structure—and perhaps this actually is by design not inattention.
A List-View control can have simultaneously both a background image and a watermark. Though only one or the other is displayed at any one time (the background image having precedence), they can be set and cleared independently. Whether the method operates on the background image or the watermark depends on the LVBKIF_TYPE_WATERMARK bit in the ulFlags member on input.
If LVBKIF_TYPE_WATERMARK is set, the method sets or clears a watermark. The only other valid bit in ulFlags is LVBKIF_FLAG_ALPHABLEND and the message fails unless all other bits are clear. The hbm member supplies the bitmap handle for the watermark, or is NULL for no watermark. No other members are meaningful.
Whether setting or clearing, the method invalidates any previously set watermark. If setting a watermark, the method fails if hbm is not a bitmap handle. (Actually, it does not test that hbm is specifically a bitmap handle. It fails if GetObject cannot produce at least 0x18 bytes of information from the given handle.) If clearing a watermark, the method fails always. It may be that giving NULL in hbm is not actually intended as the way to clear the watermark—but if not, then what is?
Note that if the method gets as far as invalidating any previously set watermark, then whether it subsequently succeeds or fails, it invalidates the control’s client area, including to erase the background. Thus, the old watermark disappears from view, even if what is given as the new watermark turns out not to be usable. (Contrast with setting a background colour, as through the SetBackgroundColor method, which allows an old background colour to remain on show.)
A quirk of the method is that although LVBKIF_FLAG_ALPHABLEND is meaningful, and is acted upon when the background is redrawn, it is not retrieved if a subsequent GetBackgroundImage asks about the watermark.
With LVBKIF_TYPE_WATERMARK clear in ulFlags, the method sets or clears a background image. This may in turn be specified either by a bitmap handle or a URL. The choice is determined by the LVBKIF_SOURCE_MASK bits in ulFlags:
|LVBKIF_SOURCE_NONE||clear the background image|
|LVBKIF_SOURCE_HBITMAP||set the background image from a bitmap handle|
|LVBKIF_SOURCE_URL||set the background image from a URL|
If the source bits mask to anything else, the method fails. In all the supported cases, the method first releases any previously set background image.
When clearing the background image, the method saves the ulFlags, xOffsetPercent and yOffsetPercent members, such that a subsequent GetBackgroundImage will retrieve them, though with the exception of the source bits they are surely all better regarded as meaningless.
The method always fails when clearing the background image, but this is perhaps a coding oversight. What is the point of coding non-trivially for LVBKIF_SOURCE_NONE in the input if not to provide the way to specify (successfully) that there is to be no background image? Despite treating this case as failure, the effect certainly is to clear the background image: the control’s client area is invalidated, including to erase the background.
When setting the background image from a URL, the pszImage member provides the address of the URL.
If the given address is NULL or if the Unicode string at this address is empty, the method fails. However, this case of failure has some curiosities. It changes the ulFlags so that the source bits mask to LVBKIF_SOURCE_NONE on output. It then saves these ulFlags, presumably so that a subsequent GetBackgroundImage will report that no background image is set. It also saves the xOffsetPercent and yOffsetPercent members, such that a subsequent GetBackgroundImage will retrieve them though they are surely meaningless. Finally, it invalidates the control’s client area, including to erase the background. None of this cleanup applies to any later failure while setting the background from a URL. The effect may be deliberate, if obtuse: specifying LVBKIF_SOURCE_URL as the source bits in ulFlags but with NULL as pszImage is another way to set the control to have no background image.
The method saves a copy of the given URL, apparently only for retrievability by GetBackgroundImage. Failure to get memory for the copy is failure for the method.
To set the background image from a URL, the method needs help from outside, specifically through the COM machinery to create an instance of the IImgCtx class. The method fails if this external assistance is unavailable, e.g., if COM initialisation has not been performed or if the IImgCtx class is not properly registered. The ordinarily configured server for this class is MSHTML. Thus, setting a background image from a URL requires Internet Explorer, even if the URL is for a file on the local computer, such that no Internet access is required, and even if the user has chosen some web browser other than Internet Explorer.
The method asks the IImgCtx instance to load the image from the given URL, with the image to be mirrored if the List-View control has the WS_EX_RTLREADING extended style. Failure of the IImgCtx instance’s Load method is failure for the SetBackgroundImage method. Note however that the IImgCtx implementation may—and the one in MSHTML certainly can—load the image asynchronously. A difficulty with the URL, such as being badly formed or there being no usable image at the URL, typically will not be discovered as part of the SetBackgroundImage method.
Given that the image-load does not fail this early, the method saves the ulFlags, xOffsetPercent and yOffsetPercent members, various combinations of which are meaningful for the style and placement of the image. The IImgCtx instance is asked for a palette and a callback is set for notification of when the image-load has completed. Only once COMCTL32 learns through this notification that the image has loaded without an error and without being stopped does the image become set in the sense of being used when drawing the background. Curiously, even if this notification reports a difficulty, the image remains set in the sense that it will be reported by a subsequent GetBackgroundImage, with no indication of the known trouble.
When setting the background image from a bitmap handle, the hbm member provides the bitmap handle.
If hbm is NULL, the method fails. Except that it fails, it means that specifying LVBKIF_SOURCE_HBITMAP as the source bits in ulFlags but with NULL as hbm is yet another way to set the control to have no background image.
In all cases of failure when setting from a bitmap handle, the method performs the following cleaning up. It changes the ulFlags so that the source bits mask to LVBKIF_SOURCE_NONE on output. It then saves these ulFlags, presumably so that a subsequent GetBackgroundImage will report that no background image is set. It also saves the xOffsetPercent and yOffsetPercent members, such that a subsequent GetBackgroundImage will retrieve them though they are surely meaningless. Finally, it invalidates the control’s client area, including to erase the background.
To set the background image from a bitmap handle, COMCTL32 implements its own IImgCtx interface. This has the obvious merit that except for the purpose of describing the background image for a subsequent GetBackgroundImage, it becomes essentially irrelevant whether the background image is set from a URL or from a bitmap handle.
The COMCTL32 implementation of IImgCtx is much simpler than the definitive one in MSHTML. The given bitmap handle is retained only indirectly, in the form of a pattern brush. The method fails if it cannot create a pattern brush from the given handle. It also fails if hbm is not a bitmap handle. (Actually, it does not test that hbm is specifically a bitmap handle. It fails if GetObject cannot produce at least 0x18 bytes of information from the given handle.)
The method saves the ulFlags, xOffsetPercent and yOffsetPercent members, various combinations of which are meaningful for the style and placement of the image.
First call SetBackgroundImage to set a background image from a bitmap handle and again to to set a new image from a URL. If the second call fails for lack of COM initialisation or such other things as improper registration of the IImgCtx class, then incomplete cleanup leaves the control having released the old image while keeping flags that indicate it has a background image known by a bitmap handle. A call to GetBackgroundImage will produce ulFlags that say a background image is known from a bitmap handle, but hbm will be NULL.
Although setting a watermark invalidates any previously set watermark, it does not invalidate any previously set background image. The latter has precedence when the background is drawn. This may be a coding oversight or it may be that a background image is intended to have precedence over a watermark. Either way, it isn’t documented and the behaviour may puzzle. To change a List-View control from having a background image to having a watermark, first send oneto clear the background image, then send another to set the watermark.
The preceding notes describe the implementation by COMCTL32 version 6.10 for Windows Vista. Some variations through early versions are plainly significant, but please bear in mind that it is far beyond the scope of these notes to examine every old version and the following observations are intended only as a sketch.
Support for watermarks dates from COMCTL32 version 6.00, as does the defence against lParam being NULL.
Though the LVBKIMAGE structure seems to have provided for the LVBKIF_SOURCE_HBITMAP flag and the hbm member since the beginning, the ability to set a background image from a bitmap handle does not actually work until version 6.00.
The SetBackgroundImage method of the IListView interface is implemented by COMCTL32 versions 6.10 and higher.
In versions 4.71 and higher, the functionality of the SetBackgroundImage method is available through the windowing system, by sending the message.
Note that the primary case, that of setting a background image by giving a URL, is not handled by COMCTL32 just with the aid of modules that are ordinarily regarded as lower-level. In practice therefore, support for this message also requires the presence of MSHTML versions 4.71 and higher. This may be what Microsoft means when listing “Windows NT 4.0 with Internet Explorer 4.0” among the minimum operating systems for this message: Windows NT 4.0 has COMCTL32 version 4.71, starting at least with Service Pack 4, but Internet Explorer 4.0 is needed for MSHTML.