Microsoft KB Archive/269400

From BetaArchive Wiki

Article ID: 269400

Article Last Modified on 5/11/2006



APPLIES TO

  • Microsoft Internet Explorer 5.5



This article was previously published under Q269400

SYMPTOMS

When you host the Microsoft Dynamic HTML (DHTML) Editing Component ActiveX control in a Microsoft Foundation Classes (MFC) application, the following assert message is generated in the Occcont.cpp file (line 385 for Microsoft Visual C++ 6.0 Service Pack 3) at the COleControlContainer::OnUIActivate function:

Debug Assertion Failed!

Program: XXX.exe
File: occcont.cpp
Line: 385

Note The assert only occurs in debug builds.

If you ignore the assert, the following access violation occurs when you click the control:

Unhandled exception in xxx.exe (MFC42D.DLL): 0xC00000FD: Stack Overflow.

CAUSE

This problem occurs because the DHTML Edit control calls the IOleInPlaceSite::OnUIActivate notification method in the MFC host, even though the control is already UI Activated and the function has already been called. MFC does not handle unnecessary calls to OnUIActivate well.

RESOLUTION

To resolve this problem, override COleControlContainer::OnUIActivate to ignore the notification call if the control is already UI Activated. You can derive your own COleControlContainer and COccManager classes so that you can replace the default OnUIActivate with the following additions:

void CMyOleControlContainer::OnUIActivate(COleControlSite* pSite)
{
    if (pSite == m_pSiteUIActive)   // workaround
        return;

    if (m_pSiteUIActive != NULL)
        m_pSiteUIActive->m_pInPlaceObject->UIDeactivate();

    ASSERT(m_pSiteUIActive == NULL);    // did control call OnUIDeactivate?
    m_pSiteUIActive = pSite;
}
                

For additional information about how to derive your own COleControlContainer and COccManager classes, click the article number below to view the article in the Microsoft Knowledge Base:

196835 HOWTO: Override the MFC Default Control Containment


Note You do not need to provide your own COleControlSite class, nor do you need to override any interfaces. The following source code is similar to what you add:

Myolectrlcont.h

// Your header file for CMyOleControlContainer
class CMyOleControlContainer : public COleControlContainer
{
public:
    CMyOleControlContainer(CWnd* pWnd) :
        COleControlContainer(pWnd) {};

    virtual void OnUIActivate(COleControlSite* pSite)
    {
        if (pSite == m_pSiteUIActive)   // Workaround
            return;

        if (m_pSiteUIActive != NULL)
            m_pSiteUIActive->m_pInPlaceObject->UIDeactivate();

        ASSERT(m_pSiteUIActive == NULL);    // Did the control call OnUIDeactivate?
        m_pSiteUIActive = pSite;
    }
};
                

Myoccmanager.h

// Your header file for CMyOccManager
class CMyOccManager : public COccManager
{
public:
    CMyOccManager() {}

    virtual COleControlContainer* CreateContainer(CWnd* pWnd)
    {
        // Advanced control container applications may want to override.
        return new CMyOleControlContainer(pWnd);
    } 
};
                

Test.cpp

// Your implementation file for the application object (this is for a 
// dialog-based application).

#include "stdafx.h"
#include "test.h"
#include "testDlg.h"
#undef AFX_DATA
#define AFX_DATA AFX_DATA_IMPORT
#include <..\src\occimpl.h>
#undef AFX_DATA
#define AFX_DATA AFX_DATA_EXPORT 

#include "myolectrlcont.h"
#include "myoccmanager.h"

...
CTestApp theApp;
CMyOccManager theManager;

BOOL CTestApp::InitInstance()
{
    AfxEnableControlContainer(&theManager);

    ...
                

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

This bug was corrected in Internet Explorer 5.5 Service Pack 1.

MORE INFORMATION

Steps to Reproduce Behavior

  1. In Visual C++ 6.0, generate a new MFC dialog-based application as follows:
    1. On the File menu, click New.
    2. On the Projects tab, click MFC AppWizard (exe), type the Project Name, and then click OK.
    3. Change the application type to Dialog Based, click Finish, and then click OK.
  2. Insert the DHTML Edit control from the Components and Controls Gallery into your project as follows:
    1. On the Project menu, click Add To Project, and then click Component and Controls.
    2. Under Registered ActiveX controls, click DHTML Edit Control for IE5, click Insert, and then click OK.
    3. In the Confirm Classes dialog box, clear everything except the CDHTMLEdit class (you do not need to add the other extra source code), and then click OK.
    4. Click Close to return to the workspace.
  3. In the dialog resource editor, place a DHTML Edit control onto the dialog.
  4. Build the control for the debug target.
  5. Run the program, and you receive the following assert message:

    Debug Assertion Failed!

    Program: my.exe
    File: occcont.cpp
    Line: 385

    in the following code:

    void COleControlContainer::OnUIActivate(COleControlSite* pSite)
    {
        if (m_pSiteUIActive != NULL)
            m_pSiteUIActive->m_pInPlaceObject->UIDeactivate();
            ASSERT(m_pSiteUIActive == NULL);    // Did the control call OnUIDeactivate?
        m_pSiteUIActive = pSite;
    }
                            

    Note Release builds do not generate the assert message.

  6. Ignore the error. When you click the DHTML control to in-place activate it, you receive the following access violation due to a stack overflow:

    Unhandled exception in xxx.exe (MFC42D.DLL): 0xC00000FD: Stack Overflow.

ActiveX controls should call IOleInPlaceSite::OnUIDeactivate when they are deactivated to balance the calls to IOleInPlaceSite::OnUIActivate. To some degree, MFC control containers rely on this behavior.

Infinite Recursion During In-Place Activation

The DHTML Edit control runs into a stack overflow when it is in-place activated. This problem occurs in release builds of MFC as well as debug builds. The in-place event triggers an extra call to OnUIActivate by the control. Because MFC tries to deactivate the currently activated control, it deactivates the same control, which causes the entire in-place activation process to execute again without returning. The workaround in the "Resolution" section addresses this problem.

Subsequent Assert When You Click a Select Box

If the DHTML Edit control is on a dialog-based application, another problem occurs when you fix the problem above. If you display an HTML page with a select box and you click the select box, you generate an assertion in Winocc.cpp line 331 in the CWnd::SetFocus function. This occurs because the WM_LBUTTONDOWN message is handled first by the DHMTL Edit control by creating the drop-down portion of the select box. Then, MFC UI Activates the control, which destroys the drop-down list box. As a result, the assert occurs because MFC tries to set focus on the missing control. If you ignore the assert or run the release mode version of the application, the drop-down list box flickers and never stays up.

To reproduce this behavior, set the DHTML Edit control to browse mode, and then browse to an HTML page that displays a select box. Click the select box for a drop-down list box.

The following sample shows an MFC dialog-based application that hosts the DHMTL Edit control:

BOOL CDhtmlDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Set the icon for this dialog. The framework does this automatically
    //  when the application's main window is not a dialog.
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    // TODO: Add extra initialization here.
    m_dedit.SetBrowseMode(TRUE);
    m_dedit.LoadURL("http://adamki2/Customer/test.htm");
    return TRUE;  // Return TRUE unless you set the focus to a control.
}
                

To work around this problem, you need to prevent the dialog manager from translating the WM_LBUTTONDOWN message because the dialog manager allows the DHTML Edit control to handle the message too early. To do this, override the CDialog::PreTranslateMessage method as follows:

BOOL CDhtmlDlg::PreTranslateMessage(MSG* pMsg) 
{
    if (pMsg->message == WM_LBUTTONDOWN)
        return FALSE;
    return CDialog::PreTranslateMessage(pMsg);
}
                

REFERENCES

For more information about the DHTML Editing component, see the following Microsoft Web Workshop site:

For more information about developing Web-based solutions for Microsoft Internet Explorer, visit the following Microsoft Web sites:


Additional query words: dhtmled.ocx dhtmled IDHTMLEdit UIDeactivate UIActivate 0xC00000FD Debug Assertion Failed

Keywords: kbbug kbfix kbdhtml kbie550sp1fix KB269400