Today, I'm not actually going to say anything new. I'm just going to collate information I've already written under a better title to improve search engine optimization.

A customer reported that they did the following but found that it didn't work:

#define MDM_SETITEMCOUNT WM_USER

INT_PTR CALLBACK MyDlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
{
  switch (wm) {
  ...
  case MDM_SETITEMCOUNT:
    SetDlgItemInt(hwnd, IDC_ITEMCOUNT, (UINT)wParam, FALSE);
    return TRUE;
  ...
  }
  return FALSE;
}

"I send the MDM_SET­ITEM­COUNT message to my dialog, but the value doesn't stick. At random times, the value resets back to zero."

As we saw some time ago, window messages in the WM_USER range belong to the window class. In the case of a dialog box, the window class is the dialog class, and the owner of the class is the window manager itself. An application which tries to use the WM_USER message is using window messages it does not own.

It so happens that the dialog manager already defined the WM_USER message:

#define DM_GETDEFID         (WM_USER+0)

We saw this problem some time ago when we tried to find a message we could use for custom use in a dialog box.

What the customer is seeing is that whenever the dialog manager sends a DM_GET­DEF­ID message to the dialog box to get the default control ID, the MyDlgProc function mistakenly thinks that it's a MDM_SET­ITEM­COUNT message and sets the item count to whatever happens to be in the wParam (which happens to be zero). On top of that, it claims to have handled the message, which means that the current value of DWL_MSG­RESULT is returned to the sender (probably zero), so the dialog manager thinks that there is no default ID on the dialog.

The solution, as noted in that same article, is to use WM_APP instead of WM_USER. Because you don't have permission to define messages in the WM_USER range if you aren't the owner of the window class.