Steps to Reproduce Behavior
- In Visual C++ 6.0, generate a new MFC dialog-based application as follows:
- On the File menu, click New.
- On the Projects tab, click MFC AppWizard (exe), type the Project Name, and then click OK.
- Change the application type to Dialog Based, click Finish, and then click OK.
- Insert the DHTML Edit control from the Components and Controls Gallery into your project as follows:
- On the Project menu, click Add To Project, and then click Component and Controls.
- Under Registered ActiveX controls, click DHTML Edit Control for IE5, click Insert, and then click OK.
- 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.
- Click Close to return to the workspace.
- In the dialog resource editor, place a DHTML Edit control onto the dialog.
- Build the control for the debug target.
- 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. - 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);
}