The GETDISPINFO notifications tell you what information they want

Date:March 8, 2007 / year-entry #85
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20070308-00/?p=27703
Comments:    1
Summary:The XXN_GETDISPINFO notifications used by the common controls are used when the control asks its parent to generate information that had been marked as delay-rendered, either explicitly via values such as LPSTR_TEXTCALLBACK or implicitly by being an owner-data control, for example. In fact the control is really just the middle man between the code that...

The XXN_GETDISPINFO notifications used by the common controls are used when the control asks its parent to generate information that had been marked as delay-rendered, either explicitly via values such as LPSTR_TEXTCALLBACK or implicitly by being an owner-data control, for example.

In fact the control is really just the middle man between the code that requested information about an item (via a message like LVM_GETITEM) and the code that generates it (your LVN_GETDISPINFO handler). In other words, the code flow goes like this:

Somebody interested in retrieving data from a list view creates a LVITEM structure and initializes the LVITEM.mask and other fields as necessary, based on the mask. (For example, if the LVIF_TEXT flag is set, then LVITEM.pszText and LVITEM.cchTextMax must also be set to the buffer and its size.) it then sends a LVM_GETITEM message to the list view control.

The list view control looks at the LVITEM.mask to see what information needs to be filled in. Some of the information the list view can provide on its own. Other parts of the information require help from the list view control's parent. For example, if the LVITEM.mask has the LVIF_TEXT flag set, and the item has its text set to LPSTR_TEXTCALLBACK, then the list view needs to consult its parent to get the text.

The list view control sends the LVN_GETDISPINFO message to its parent, saying, "Hey, somebody is looking for information; please provide the information that is requested in the LVITEM.mask member."

After the parent handles the message, the results are returned back to the original caller.

There's a little bonus step that occurs just before the results are returned: If the parent set the LVIF_DI_SETITEM flag in the LVITEM.mask, then the returned values are also saved into the list view control as if you had sent a LVM_SETITEM message. For example, if you set the LVIF_DI_SETITEM flag in response to a request for LVIF_TEXT, then the text you return will be saved into the list view item, overwriting the previous value of LPSTR_TEXTCALLBACK. This is handy if you only want to compute the result once and let the list view cache the result from the on.

Notice that throughout this process, the LVITEM.mask controls what information is being requested by the original caller of the list view as well as what is being requested by the list view of its parent. If you make the mistake of changing the value of LVITEM.mask (aside from setting the LVIF_DI_SETITEM flag, as noted in the "bonus step"), then you interfere with this game of "pass the buck".

After the parent handles the message, the results are returned back to the original caller. But if you have modified the LVITEM.mask, then the results being returned back to the caller aren't the same as the ones the caller requested! For example, if the list view sees the LVIF_TEXT flag set, then it will copy the string provided by the parent back into the caller's buffer. But wait a second, if the parent is the one who set the LVIF_TEXT flag, that means that the original caller didn't ask for the text. There is no buffer to copy the results back into. The list view copies the string to an unintialized pointer, and all sorts of memory corruption occurs as a result.

Moral of the story: When responding to a XXN_GETDISPINFO notification, respect the mask. It's the bookkeeping that specifies what information you're being asked to provide (and therefore what information will be copied back to the original caller). If you change this bookkeeping, the original caller is in for a big surprise. It's like being the cook in a restaurant modifying the customer's order. "Oh, you didn't want the salad; let me give you the veal instead."


Comments (1)
  1. Jules says:

    What I don’t understand (and maybe I’m being dense here) is why the poster’s problem only shows up when he compiles in Unicode mode.

    [I’ll leave that as an exercise. Hint: Thunk. -Raymond]

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index