PRB: CBT_CREATEWND Struct Returns Invalid Class Name

ID: Q106079

The information in this article applies to:

SUMMARY

The CBT_CREATEWND structure contains information passed to a WH_CBT hook callback function before a window is created in the system. The lpszClass field of this CBT_CREATEWND structure may return an invalid class name, particularly for windows created internally by the system.

SYMPTOMS

The code to get to the window class name via the CBT_CREATEWND structure in a CBT callback function may look like the following:

   int FAR PASCAL CBTProc (int nCode, WPARAM wParam, LPARAM lParam)
    {
         LPCBT_CREATEWND  CreateWndParam;

           if (nCode >= 0)
           {
                switch (nCode)
                {
                   case HCBT_CREATWND:
                        CreateWndParam = (LPCBT_CREATEWND)lParam;
                        OutputDebugString ("ClassName = ");
                        OutputDebugString (lParam->lpcs->lpszClass);
                        OutputDebugString ("\r\n");
                        break;
                     :
                     :
                }
           }

           return (int)CallNextHookEx (hHook, nCode, wParam, lParam);
    }

However, this code may or may not output the correct class name, depending on what the call to CreateWindow() (for the window about to be created) looks like.

RESOLUTION

Windows provides the GetClassName() function to allow applications to retrieve a window's class name. This function takes the handle to the window as a parameter, as well as a buffer to receive the null-terminated class name string. This function is a more reliable and a more recommended means to obtain window class name information than the CBT callback function's CBT_CREATEWND structure.

MORE INFORMATION

Whenever a window is about to be created, Windows checks to see if a WH_CBT hook is installed anywhere in the system. If it finds one, it calls the CBTProc() callback function with hook code set to HCBT_CREATEWND, and with the lParam parameter containing a long pointer to a CBT_CREATEWND structure.

The CBT_CREATEWND structure is defined in WINDOWS.H as follows

   typedef struct tagCBT_CREATEWND {
       CREATESTRUCT FAR* lpcs;
       HWND hwndInsertAfter;
   } CBT_CREATEWND;

with the CREATESTRUCT structure defined in the same file as:

   typedef struct tagCREATESTRUCT {
      void FAR* lpCreateParams;
         :
      LPCSTR  lpszClass;    // Null-terminated string specifying window
                            // class name
      DWORD  dwExStyle;
   } CREATESTRUCT;

When Windows internally creates windows (such as predefined controls in a dialog box, for example), it uses atoms for lpszClass instead of the actual string to minimize overhead. This makes it a little less straightforward (sometimes impossible) to get to the actual class name directly from the lpszClass field of the CREATESTRUCT structure.

To cite one particular example, when an application is minimized in Windows, Windows calls CreateWindow() for the icon title, specifying a class name of

   (LPSTR)MAKEINTATOM (ICONTITLECLASS == 0x8004)

where MAKEINTATOM() is defined in WINDOWS.H as:

   #define MAKEINTATOM (i)    ((LPCSTR) MAKELP (NULL, i))

Given this, to get to the actual class name, GetAtomName() must be called in this manner:

   char szBuf [10];

   GetAtomName (LOWORD (lpszClass), szBuf, 10);
   OutputDebugString (szBuf);

This outputs a class name of #32772 for the IconTitleClass.

For predefined controls, such as "static", "button", and so forth, in a dialog box, the Dialog Manager calls CreateWindow() on each control, similarly using atoms for lpszClass. The Dialog Manager, however, creates these atoms in a local atom table in USER's default data segment (DS), thus making it impossible for other applications to get to these class names.

[Note the difference between local and global atom tables, where global atom tables are stored in a shared DS, and are therefore accessible to all applications, while local atom tables are stored in USER's default DS. DDE uses global atom tables so that Excel, for example, can use GlobalAddAtom() to add a string to the atom table, and another program could use GlobalGetAtomName() to obtain the character string for that atom.]

More information on atoms can be found by searching on the following word in the Microsoft Knowledge Base:

   atoms

More Information can also be found in the Windows version 3.1 online Help file under the heading Function Groups, under the Atom Functions subheading.

Additional query words:

Keywords          : kbHook kbNTOS kbGrpUser kbWinOS kbWndw kbWndwClass 
Issue type        : kbprb

Last Reviewed: December 26, 1998