Microsoft KB Archive/238721

{|
 * width="100%"|

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

 * }

Q238721

-

The information in this article applies to:


 * Microsoft Windows NT Server version 4.0
 * Microsoft Windows NT Workstation version 4.0

-

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.

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:

"Q164166 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 
 * 1) include 

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; }