Strange uses for window class atoms

When you register a window class (with the RegisterClass or RegisterClassEx function), you get an ATOM back. What use is this atom?

Not much.

You can use this atom in many places where a window class name can be used; just convert it to a string with the MAKEINTATOM macro. Let's change our scratch program to illustrate:

ATOM g_atmClass;

    g_atmClass = RegisterClass(&wc);
    if (!g_atmClass) return FALSE;

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,
                   LPSTR lpCmdLine, int nShowCmd)

        hwnd = CreateWindow(
            MAKEINTATOM(g_atmClass),        /* Class Name */
            "Scratch",                      /* Title */
            WS_OVERLAPPEDWINDOW,            /* Style */
            CW_USEDEFAULT, CW_USEDEFAULT,   /* Position */
            CW_USEDEFAULT, CW_USEDEFAULT,   /* Size */
            NULL,                           /* Parent */
            NULL,                           /* No menu */
            hinst,                          /* Instance */
            0);                             /* No special parameters */


We save the atom returned by the RegisterClass function and use it (in the form of a MAKEINTATOM) in place of the class name. if you run this program, you'll see that it works exactly the same as the old version that used the class name. The class atom is valid as long as the class remains registered.

Functions that accept a MAKEINTATOM as the class name include CreateWindow, FindWindow, GetClassInfo, and UnregisterClass (and the Ex versions of them).

Why would you do this?

Well, there really isn't much reason. The string name works just as well as the atom, so the atom is just one more thing to keep track of. However, even though you don't use it, you have to be aware that other people might. For example, the lpszClass member of the CREATESTRUCT structure is usually a pointer to a string, but it could be a MAKEINTATOM if somebody decided to pass an atom instead of a string to CreateWindow. Those of you who've read the first Bonus Chapter of my book are already familiar with the program that crashed when somebody created a window via an atom.

There is one interesting thing you can do with the atom: If you have a valid class atom, you can quickly tell whether a window belongs to that class by checking the window word for the atom:

if (GetWindowWord(hwnd, GWW_ATOM) == atom) ...

This technique saves you the trouble of calling GetClassName and then doing a string comparison, reducing it instead to an integer comparison. This technique makes it very simple to write a TestIfWndIsDialog function:

BOOL TestIfWndIsDialog(HWND hwnd)
  return GetWindowWord(hwnd, GWW_ATOM) == (ULONG_PTR)WC_DIALOG;

Exercise: Discuss the limitations of the above TestIfWndIsDialog function.

Comments (24)
  1. Jack Mathews says:


    1) Just because it’s a "dialog" doesn’t mean it’s a modal dialog.  Someone could have created a "dialog" as a tool window just to use dialog resources, and you wouldn’t know the difference.  And you can’t just check by seeing if the parent’s disabled, because that could be because a real model dialog is up as well.

    2) Some real dialogs will subclass the dialog window class.  This will not find those.

    3) Related to number 1, anyone can use a dialog in any way that they want to, so even if you know something "is" a dialog, it doesn’t mean that you can manipulate it like standard dialogs.

  2. Ivo says:

    How do I get the atom for an existing class?

    In my case I want to know if a control is a combo box and I want to avoid GetClassName.

    GetClassInfo doesn’t return the atom, and GetClassLong requires an already created window.

  3. Rick C says:

    a (standard) combo box has a known class name.

  4. Eric C Brown says:

    Ivo – how are you locating the control without also getting the window?

  5. Mike Dimmick says:

    @Jack Mathews:

    4) CreateDialogIndirect/DialogBoxIndirect allow you to use a DLGTEMPLATEEX structure, which allows you to specify your own window class for your shiny new dialog.

  6. Yuhong Bao says:

    Another use for the atom returned by RegisterClass:

    CreateWindow((LPCTSTR)(ULONG)RegisterClass(…), …);

    Note the casts, needed because just a cast to LPCSTR would put DS in the high word in 16-bit Windows.

    [Wait I thought I already mentioned that. Yes, the entire first half of the article. Not sure what your point is. Maybe you just like hearing yourself talk. -Raymond]
  7. Yuhong Bao says:

    [Wait I thought I already mentioned that. Yes, the entire first half of the article. Not sure what your point is. Maybe you just like hearing yourself talk. -Raymond]

    I mean you can’t do this with strings.

    [Not sure what “this” is. All you did was expand the MAKEINTATOM macro. -Raymond]
  8. Yuhong Bao says:

    Because you don’t return a pointer as a return value often, because what about the memory used, while with an atom you don’t have to worry about that.

    [Not sure what that has to do with expanding the MAKEINTATOM macro inline. Please do not post multiple comments in rapid succssion – it’s a violation of the ground rules. You’re the only person who violates it regularly. -Raymond]
  9. Yuhong Bao says:

    Lets rewrite this code as:

    CreateWindow(MAKEINTATOM(RegisterClass(…)), …);

  10. Yuhong Bao says:

    expanding the MAKEINTATOM macro inline is not my point.

  11. Ens says:

    I’m a bit confused about what your point actually is.  If it’s not the MAKEINTATOM macro, then what remains is you’re inlining RegisterClass and not explicity storing a variable (relying on compiler magic to take care of the mean old nested function call).  Oh, and made it less readable.  I guess if it helps you remember the format of your one-off hwnds, then alright.

  12. Yuhong Bao says:

    “what remains is you’re inlining RegisterClass and not explicity storing a variable (relying on compiler magic to take care of the mean old nested function call).”

    That is exactly my point, and you can’t do this with strings.

    [That point has nothing to do with the article. Oh, and you can inline strings too:
    PCTSTR pszClassName = TEXT(“Scratch”);
    CreateWindow(pszClassName, …);


    CreateWindow(TEXT(“Scratch”), …)

    Woo-hoo, I inlined the string. What this has to do with the article I have no idea. All you did was perform by hand what the compiler does automatically. -Raymond]

  13. Yuhong Bao says:

    I am not talking about inlining strings, I am talking about inlining a function call.

    [I give up. Woo-hoo, you can inline a function call. I would never have thought of that. You’re so smart. -Raymond]
  14. Brian says:

    My mind has just been boggled.

  15. Ivo says:

    @Eric Brown: I have a window (HWND). I want to check if it is a combo box or not. I can call GetClassName and see if it returns WC_COMBOBOX. I can also call GetWindowWord(GWW_ATOM) and compare it with the atom for the combo box, which is hopefully faster. But how to get the atom corresponding to WC_COMBOBOX?

  16. chrismcb says:

    @Ivo: As Eric stated a combo box has a standard class name. So call FindAtom on that name?

    @Yuhong yeah you can’t do it with strings because RegisterClass doesn’t return a string. But so what? What did you save?

  17. IUnknown says:

    There’s more! You can actually inline functions!

    inline BOOL isNull( const INT_PTR x )


       return x == 0;


    (That’s probably the most useless function I wrote, ever.)

  18. MadQ1 says:

    Ivo: You can use Active Accessibility to find out if a window is a combobox, but this only works for windows that have already processed the WM_CREATE message. The nice thing is that it also works for superclassed windows (hi, Windows Forms! ;) Oh, and make sure to never try this with windows that do not have the WS_CHILD style.

    if( 65536+5 == SendMessage(hWnd, WM_GETOBJECT, NULL, OBJID_QUERYCLASSNAMEIDX) )

       then it’s a combobox;

    See ms-help://MS.MSDNQTR.v90.en/msaa/msaapndx_5at4.htm if you have the VS 2008 MSDN library, or

    Erm, and lest I be "mostly wrong anyway" again, I should say something on topic… you see, this way you don’t even have to mess with ATOMs, thereby avoiding any of the Exercise’s limitations.

  19. Ivo says:

    chrismcb: FindAtom is exactly what I need. Thanks.

  20. scorpion007 says:

    Raymond, it seems that GetWindowWord is deprecated in favour of GetWindowLong, and GetWindowLong’s documentation don’t mention GWW_ATOM or anything similar.

    Should we still rely on it?

  21. KenW says:

    @Yuhong Bao: I am not talking about inlining strings, I am talking about inlining a function call.

    No, you’re not even talking about that – you’re talking about *nested* function calls, which like every other post you make here has nothing to do with Raymond’s original subject.

    Are you just really dense? Or are you just *trying* to be annoying and irritating?

  22. Johann Gerell says:

    @ IUnknown:

    (That’s probably the most useless function I wrote, ever.)

    Nooooo. You’ve just turned a blackbox expression to an easy testable nugget. Just toss in an ASSERT before the return!


  23. IUnknown says:

    @Johann: Wow, I never thought of that! Yeah, lets crash on null pointers! For free! :)

  24. Napalm says:

    For those of you who dont want to use the depreciated call GetWindowWord(hwnd, GWW_ATOM) you can use GetClassLong(hwnd, GCW_ATOM) instead. I am not too sure why Raymond didn’t choose this in the first place. Maybe it was his love of 16bit Windows?

    @Raymond: Please tell us.


Comments are closed.