PRB: CTL3D Cannot Be Used with Shared MFC DLL

Last reviewed: July 22, 1997
Article ID: Q126719
1.00 1.50 1.51 WINDOWS kbprg kbcode kbprb

The information in this article applies to:

  • The Microsoft Foundation Classes (MFC), included with: Microsoft Visual C++ for Windows, versions 1.00, 1.50, and 1.51

SYMPTOMS

The CTL3D documentation "Adding 3-D Effects to Controls" indicates that you should not use CTL3D with the DLL version of the Microsoft Foundation Classes (MFC). If you try to use CTL3D with the MFC DLL, one of the following symptoms may occur:

  • Applications that don't register CTL3D have 3-D effects added to all or some of the controls.
  • Applications may crash when the application that registered the CTL3D terminates.
  • Debug versions of applications fail an assertion in CWnd::GetSuperWndProcAddr().

CAUSE

MFC versions 2.x rely on every control of a certain type having the same window procedure, which is not the case with CTL3D. The window procedure changes depending on whether the control has been subclassed or not.

The problem is that MFC uses a static variable per class to remember the previous window procedure when it subclasses a window that is newly created or one that is being subclassed with CWnd::SubclassWindow. This static variable is returned by the virtual function CWnd::GetSuperWndProcAddr(). If the static is already non-zero and is different from the window procedure that the new window had before subclassing occurred, GetSuperWndProcAddr() will assert.

In release builds, the MFC DLL is shared by multiple applications, so every control of a certain type used by all the MFC applications that use the MFC DLL use the same window procedure. However, if the control is subclassed, the window procedure being used may belong to one of the applications. If this application terminates, controls in other applications will suddenly have an invalid window procedure. Also, if one application uses CTL3D but others do not, the applications that do not use CTL3D may reference the CTL3D window procedure anyway.

RESOLUTION

To work around this behavior, you must override GetSuperWndProcAddr for any windows you intend to subclass that may also be subclassed by CTL3D. In your override, return a pointer to a class member variable that holds the subclassed window procedure for the object's associated window.

For example, if you want to subclass a ComboBox that may also be subclassed by CTL3D, perform these steps:

  1. Derive a class from CComboBox.

  2. Add a member variable, m_lpfnSuper, to the class.

  3. Override GetSuperWndProcAddr for the class and return &m_lpfnSuper.

The class definition will look like this:

   // combo3d.h

   class C3dComboBox : public CComboBox
   {
   public:
      virtual WNDPROC* GetSuperWndProcAddr();
      WNDPROC m_lpfnSuper;
   };

The source file for the class will look like this:

   // combo3d.cpp

   #include "combo3d.h"

   WNDPROC* C3dComboBox::GetSuperWndProcAddr()
   {
      return &m_lpfnSuper;
   }

Now it is safe to subclass and create from this new class, even if CTL3D subclasses the control.

You should do this same procedure for all the control classes you subclass. If you also turn CTL3D effects off for selected dialogs, you should follow this procedure for the CDialog class as well.

STATUS

This behavior is by design.

MORE INFORMATION

MFC 3.0, included with Visual C++ version 2.0, is designed differently. It corrects this problem by adding the member variable m_pfnSuper to the CWnd class. CWnd::GetSuperWndProcAddr() returns the address of this member variable, instead of returning the address of a static member variable. With this change to MFC, it is no longer necessary to override GetSuperWndProcAddr() for every CWnd-derived class.


Additional reference words: 1.00 1.50 1.51 2.00 2.50 2.51
KBCategory: kbprg kbcode kbprb
KBSubCategory: MfcUI
Keywords : kb16bitonly kbcode kbprb kbprg
Technology : kbMfc
Version : 1.00 1.50 1.51
Platform : WINDOWS


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 22, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.