Non-psychic debugging: If you can’t find something, make sure you’re looking in the right place


This isn't psychic debugging, but it's the sort of dumb mistake everybody makes and which you can't see when re-reading your code because your brain shows you what you want to see, not what's really there.

I'm trying to respond to the PSN_QUERYINITIALFOCUS notification, but it's not working. What am I doing wrong?

INT_PTR CALLBACK DlgProc(HWND hdlg, UINT uMsg,
                         WPARAM wParam, LPARAM lParam)
{
 switch (uMsg) {
 ...
 case WM_NOTIFY:
  switch (reinterpret_cast<NMHDR*>(lParam)->code) {
  ...
  case PSN_QUERYINITIALFOCUS:
   {
    PSHNOTIFY *ppsn = reinterpret_cast<PSHNOTIFY*>(lParam);
    SetWindowLongPtr(ppsn->hdr.hwndFrom, DWLP_MSGRESULT,
                    (LPARAM)GetDlgItem(ppsn->hdr.hwndFrom, IDC_MYCONTROL));
   }
   return TRUE;
  ...
  }
  break;
 }
 return FALSE;
}

You can stare at this code for ages and completely overlook that the wrong window handle is being passed to GetDlgItem and SetWindowLongPtr. The hwndFrom of a WM_NOTIFY message is the window that is generating the notification; in this case, the PSN_QUERYINITIALFOCUS is generated from the property sheet frame window. But the result of a dialog message needs to be stored in the extra bytes of the dialog that's receiving the message, not the one that's sending it. And when you call GetDlgItem, the window manager searches for the control among the children of the window you pass as the first parameter—but here, IDC_MYCONTROL is a child of the property sheet page, not the property sheet frame.

The correct code should read

    SetWindowLongPtr(hdlg, DWLP_MSGRESULT,
                    (LPARAM)GetDlgItem(hdlg, IDC_MYCONTROL));

This phenomenon of missing the obvious because your brain shows you what you want to see (rather than what's actually there) reminds me of a time one of my colleagues called me into his office to help figure out why one of his loops was iterating only once. He called the function up on the screen and talked me through it. "Okay, now the variables are set up for the loop, so while we haven't found the entry, we grab the next item from the list..."

I hesitatantly interrupted. "Um, 'while'? The code says 'if'."

"Oops. Um, nevermind. Nothing to see here. Move along now."

This is the same reason you want to have somebody else proofread your writing. Since you wrote it, your brain will show you what you meant to write, not necessarily what you actually wrote.

Comments (21)
  1. required says:

    I once wrote:

    if (bSomething);

    {

    }

    and had the entire team crowded around my desk trying to debug it.

  2. Caliban Darklock says:

    I’ve done that!

    The "if();" one, not the big complicated smart one. All of my coding errors are very, very stupid.

  3. Doug says:

    mis-spell default: in a switch statement.  Like defualt:.

    No whines, because it is a jump label…

  4. Some Developer from Edmonton says:

    I’ve lost count of the number of times I’ve made a dumb coding mistake, only to find it (or have it pointed out to me) when I dragged someone else in to help me find the bug.

    It’s not even that I needed a second set of eyes sometimes – I just need to vocalize what I want the code to do and compare what I’m saying to what I’m seeing. Talking to yourself doesn’t always produce a coherent dialogue.

  5. mikeb says:

    "Oops. Um, nevermind…"

    That’s my personal motto.

  6. Russell Silva says:

    s/hesitatantly/hesitantly/.

  7. Craig says:

    When I was a TA for a ‘Fortran for Engineers’ class, my favorite question from a student was:  "Why is my ‘IF’ loop only executing once?"

  8. Ken Hagan says:

    "Oops. Um, nevermind. Nothing to see here. Move along now."

    He really said that? I’m impressed. I never recover my poise that quickly when I goof up.

  9. Craig says:

    Doug: Many compilers can now warn of unused jump labels – something that’s saved me from that same thing.

  10. Foo says:

    mis-spell default: in a switch statement.

    Like defualt:.

    >

    No whines, because it is a jump label…

    That’s what you get when you use an uncivilised editor with no syntax highlighting.

  11. Nick says:

    In PHP a while ago I was working on a large OOP framework and in a class about halfway down the hierarchy, I did this:

    public function __construct()

    {

      ….

      parent::__costruct();

    }

    (In PHP the parent constructor is not implicitly called if a child has a constructor defined.)

    The results were so odd that it took me several hours to find the cause, and I probably read over that code at least a dozen times.

    I do find sometimes it helps to actually read the code aloud.  For me at least, it seems to force my brain to acknowledge what’s actually *on* the screen and not what I had intended to put there.

  12. Anders Dalvander says:

    I once asked my fellow teammates: "My while loop is only running once, could you please help me?"

    while (some-rather-long && complex-statement);

    {

    }

    Ashamed when finding the extra semicolon? Nooo, not at all… :)

  13. Jonathan says:

    Sometimes One has to just vocalize it around:

    Me: "Hi, what do you think of idea x, where you take A and B and… You’re right, B doesn’t belong there, it’s never gonna work, thanks."

    Other guy: "Um… Glad to have been of assistance?"

  14. Harvey Pengwyn says:

    Someone I used to work with, said that in a previous job they had a life-size cardboard cut-out of Superman and would go and ask him their questions, the act of asking ‘him’ the question would often mean they though of the solution.

  15. Joe Butler says:

    Where can we get life-sized cutouts of Raymond Chen?

  16. Dewi Morgan says:

    if() ; {

    }

    doesn’t tend to happen. This is one of several reasons why I prefer this bracing style, and avoid:

    if()

      blah;

    Asking other people questions definitely helps. 90% of the time, when I go into a programming channel in IRC, I leave again without asking a question. The process of phrasing the question clearly, and stripping the problem down to a minimal case, finds my problem. In the remaining 10% of the time, either everyone is afk, or they don’t know the answer.

  17. It’s called asking the janitor to help you fix your program.  As you take baby steps walking through your code, the solution reveals itself.  If there’s no janitor around, a neighboring colleague can help in a pinch, but might know too much.

  18. Joe Schober says:

    I once spent an embarrassing amount of time trying to figure out…

    if (SomeFunction)

      DoWhatever();

    …why SomeFunction was always returning true but my breakpoints in that function weren’t firing.  It should’ve been blatantly obvious (and of course would have been if SomeFunction had taken arguments), but extended runs of 16 hour work days do weird things to the mind.

  19. Paul Campbell says:

    Similar to the spot you helped me out on the other week where I was passing wParam and lParam to DefWindowProc in the wrong order. The problem was much more interesting when I thought that DefWindowProc was handling WM_NCCREATE incorrectly. :)

  20. Mark says:

    This is one of the reasons that debugging at the assembly level is good – you can usually quickly spot errors in the source code (like using if (); or if instead of while) when you look at the disassembly.

    Your brain can’t lie to you quite as easily when you move down to a lower level of abstraction :)

  21. Steve says:

    My favorite "stupid mistake" was writing something like

    strcpy(buffer, "multiplenull-terminatedstrings");

    It took hours of banging my head against the wall to track that one down.

Comments are closed.

Skip to main content