PRB: Common Controls Might Behave Unpredictably in an Interactive Service after Logoff (238721)



The information in this article applies to:

  • Microsoft Win32 Application Programming Interface (API), when used with:
    • the operating system: Microsoft Windows NT 4.0

This article was previously published under Q238721

SYMPTOMS

In Microsoft Windows NT 4.0, if an interactive service creates a window containing common controls, some of the controls may behave unpredictably when an interactive user logs off and then logs back on. This behavior can include the loss of data within the controls and the failure of the controls to display correctly.

CAUSE

The common controls library, the Comctl32.dll file, uses global atoms internally to store data associated with some of its controls. When the interactive user logs off the computer, the interactive desktop and its global atom table are destroyed and the data that was stored by the common controls library is lost. Because a service continues to run even when there is no interactive user, it may later attempt to retrieve the data associated with its common controls. The behavior of these controls is undefined after a failure to retrieve the atom data.

RESOLUTION

Implementing a user interface within a service process is not recommended. Whenever possible, a service process should be shielded from the actions of an interactive user. If a service needs to receive input or display output to the interactive user, a separate process should be implemented to run within the same logon session as the interactive user. That process can communicate with the service through the standard Win32 methods of interprocess communication.

If you decide to include a user interface and common controls within your service, make sure that the service loads and initializes the Comctl32.dll file only when it needs to show the window containing the common controls. The service should close the window and completely unload the common controls library before the user logs off. The sample code in the "More Information" section of this article demonstrates how to dynamically load and initialize the Comctl32.dll file.

STATUS

This behavior is by design on Microsoft Windows NT 4.0.

In Microsoft Windows 2000, the common controls library has been redesigned and this behavior does not occur. Implementing a user interface within a service process, however, is still not recommended.

MORE INFORMATION

An interactive service is a service that interacts with the currently logged-on user through a typical Windows-based user interface.

The common controls library contains many enhanced Windows controls, like the List View, Tree View, and ComboBoxEx controls.

An atom table is a system-defined table that stores strings and corresponding identifiers. An application places a string in an atom table and receives a 16-bit integer, named an atom, which can be used to access the string from any thread within the same desktop.

A desktop is a kernel object contained within a window station object. A desktop has a logical display surface and contains windows, menus, hooks, and a global atom table. This atom table can be used to uniquely identify data that is shared among other threads running in the same desktop.

For additional information about the interactive desktop, click the article number below to view the article in the Microsoft Knowledge Base:

327618 INFO: Security, Services and the Interactive Desktop

Problems Using Microsoft Foundation Class Library Within Services

The Microsoft Foundation Class (MFC) library loads and initializes the Comctl32.dll file when an MFC dialog is initialized; this occurs even when no common control is used within the dialog. In addition, the MFC library itself uses global atoms to store data for subclassing windows. For these reasons, you should not use MFC within a service. For additional information, click the article number below to view the article in the Microsoft Knowledge Base:

164166 PRB: Assert in Wincore.cpp with MFC in a Windows NT Service

Sample Code

The following sample code implements a useful function, CCDialogBox, which you can use to create a dialog box that contains common controls. The CCDialogBox function dynamically loads and initializes the common controls library. When the dialog box closes, the library is unloaded.

The first four parameters for the CCDialogBox function are identical to the parameters passed to the DialogBox function. The last parameter, dwICC, should contain the bit flags that indicate which common control classes to load. For the possible flag values, see the online documentation for the INITCOMMONCONTROLSEX structure.

Here is the sample code:
#include <Windows.h>
#include <CommCtrl.h>

typedef BOOL (STDMETHODCALLTYPE FAR * LPFNINITCOMCTL32) (
      LPINITCOMMONCONTROLSEX lpInitCtrls
);

INT_PTR CCDialogBox(
      HINSTANCE hInstance,    // handle to module
      LPCTSTR   lpTemplate,   // dialog box template
      HWND      hWndParent,   // handle to owner window
      DLGPROC   lpDialogFunc, // dialog box procedure
      DWORD     dwICC ) {     // bit flags for common control classes
                              // to load

   HMODULE hComCtl32 = NULL;
   INT_PTR iResult   = -1;

   __try {

      INITCOMMONCONTROLSEX icce;
      LPFNINITCOMCTL32     InitComCtl32;

      hComCtl32 = LoadLibrary("comctl32.dll");
      if (!hComCtl32)
         __leave;

      InitComCtl32 = (LPFNINITCOMCTL32) GetProcAddress(hComCtl32, 
            "InitCommonControlsEx");
      if (!InitComCtl32)
         __leave;

      icce.dwSize = sizeof(icce);
      icce.dwICC  = dwICC;
      InitComCtl32(&icce);

      iResult = DialogBox(hInstance, lpTemplate, hWndParent, lpDialogFunc);

   } __finally {

      if (hComCtl32)
         FreeLibrary(hComCtl32);
   }

   return iResult;
}
				

REFERENCES

For more information about services, common controls, window stations, desktops, and atom tables, see the MSDN Library.

Modification Type:MajorLast Reviewed:11/3/2003
Keywords:kbKernBase kbprb kbService KbUIDesign KB238721