May 1st, 2008

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;
BOOL
InitApp(void)
{
    ...
    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.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.