2

I saw this piece of code below in here. I tested it and it works all right.

// g_hLink is the handle of the SysLink control.
case WM_NOTIFY:
    switch (((LPNMHDR)lParam)->code)            // CAST TO NMHDR*
    {
        case NM_CLICK:          // Fall through to the next case.
        case NM_RETURN:
        {
            PNMLINK pNMLink = (PNMLINK)lParam;  // CAST TO NMLINK*
            LITEM   item    = pNMLink->item;
            if ((((LPNMHDR)lParam)->hwndFrom == g_hLink) && (item.iLink == 0))
            {
                ShellExecute(NULL, L"open", item.szUrl, NULL, NULL, SW_SHOW);
            }
            else if (wcscmp(item.szID, L"idInfo") == 0)
            {
                MessageBox(hDlg, L"This isn't much help.", L"Example", MB_OK);
            }
            break;
        }
    }
    break;

The parameter lParam is casted to both NMHDR* and NMLINK* types. The documentation of WM_NOTIFY message says that lParam can be casted to NMHDR*, but NMLINK is a different structure which encapsulates NMHDR.

What does actually happen when we cast lParam to an arbitrarily chosen structure between these two?

hkBattousai
  • 10,583
  • 18
  • 76
  • 124
  • The structure is not arbitrary, it depends on the `code` value. If you read the documentation for [SysLink control notifications](https://msdn.microsoft.com/en-us/library/windows/desktop/hh270406.aspx), `NM_CLICK` and `NM_RETURN` send a `NMLINK*` pointer in `lParam`. – Remy Lebeau Oct 11 '15 at 17:19

1 Answers1

6

NMLINK contains NMHDR as its first element:

struct NMLINK {
  NMHDR hdr;
  LITEM item;
};

And so pointer to NMLINK equals to the pointer to its first member (which is NMHDR structure sitting at offset 0), they are the same. It means that you can cast NMHDR* to NMLINK*.

c-smile
  • 26,734
  • 7
  • 59
  • 86
  • Is this a C/C++ language rule which is always true? – hkBattousai Oct 11 '15 at 04:55
  • Struct members are stored in the order they are declared - this is mandated by the C99 standard. Padding may apply but not in this case (structs in Windows API are pretty much always rounded to nearest integer size so no padding required ) – c-smile Oct 11 '15 at 05:39
  • Padding just doesn't matter. – Hans Passant Oct 11 '15 at 07:10
  • 3
    Padding matters, but not for the first member of the structure. It always starts at offset 0 of the front of the structure. – Remy Lebeau Oct 11 '15 at 17:21