Article ID: 202009
Article Last Modified on 5/11/2006
APPLIES TO
- Microsoft Internet Explorer 5.0
This article was previously published under Q202009
SYMPTOMS
A DHTML control created with the ATL Object Wizard fails with the following script error when accessing window.external from Internet Explorer 5.0:
CAUSE
A DHTML control contains two IDispatch interfaces, a default interface for scripting and another for the window.external methods. The WebBrowser control incorrectly uses the default IDispatch interface when invoking window.external methods.
RESOLUTION
Implement the window.external IDispatch method in a separate COM object.
Use the following steps to implement a sub-object for a default ATL DHTML control project:
- Add HTML Control to project (Ctrl).
- Add Simple Object to project, use default of "dual interface" (UIObj).
Remove original UI dispatch interface (ICtrlUI) from ctrl.h: From class derivation list:
public IDispatchImpl<ICtrlUI, &IID_ICtrlUI, &LIBID_DHTMLCONTROLLib>,
From COM_MAP, replace the following two lines:
COM_INTERFACE_ENTRY(ICtrlUI) COM_INTERFACE_ENTRY2(IDispatch, ICtrl) with ) COM_INTERFACE_ENTRY(IDispatch)
Move the example OnClick method from ctrl.h to uiobj.h:
// ICtrlUI public: // Example method called by the HTML to change the <BODY> background color STDMETHOD(OnClick)(IDispatch* pdispBody, VARIANT varColor) { CComQIPtr<IHTMLBodyElement> spBody(pdispBody); if (spBody != NULL) spBody->put_bgColor(varColor); return S_OK; }
Modify dhtmlcontrol.idl to reflect above changes: Move OnClick method from ICtrlUI to IUIObj interface definition:
// Example method that will be called by the HTML HRESULT OnClick([in]IDispatch* pdispBody, [in]VARIANT varColor);
Remove original ICtrlUI interface from interface definition:
[ object, dual, uuid(C3920EDB-BAD6-11D2-AFA1-00A0C9C9E6C5), helpstring("ICtrlUI Interface"), pointer_default(unique) ] interface ICtrlUI : IDispatch { };
Remove original ICtrlUI interface from Ctrl coclass:
interface ICtrlUI;
Modify OnCreate method in Ctrl.h:
#include "uiobj.h" ... LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { CAxWindow wnd(m_hWnd); HRESULT hr = wnd.CreateControl(IDH_CTRL); if (SUCCEEDED(hr)) { // Create sub-object - this implements our window.external methods to be called from HTML hr = CComObject<CUIObj>::CreateInstance( &m_pUI ); if ( SUCCEEDED(hr) ) { CComQIPtr<IDispatch> pDisp(m_pUI); hr = wnd.SetExternalDispatch(pDisp); } } if (SUCCEEDED(hr)) hr = wnd.QueryControl(IID_IWebBrowser2, (void**)&m_spBrowser); return SUCCEEDED(hr) ? 0 : -1; } CComObject<CUIObj>* m_pUI;
- In addition, you can specify that this simple object should not be creatable with CoCreateInstance by marking the object as non-creatable.
Add the [noncreatable] attribute in the IDL file for the simple object's coclass. Don't forget the comma after the help string attribute
[ uuid(....), help string("UIObj class"), noncreatable ] coclass UIObj { ... }
- Change OBJECT_ENTRY(CLSID_UIObj, CUIObj)macro in the object map to OBJECT_ENTRY_NON_CREATEABLE(CUIObj) for the simple object.
STATUS
Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.
MORE INFORMATION
Microsoft Active Template Library (ATL), Version 3.0, allows developers to write Dynamic HTML (DHTML) controls. A DHTML control is an ActiveX control which hosts the Internet Explorer WebBrowser control to display an HTML file. The HTML file is stored in the control as a resource and can contain DHTML and script to create an interactive user interface.
One additional feature of the DHTML control is that it's methods can be invoked from the HTML page by means of the DHTML window.external object. When any method is invoked from script using window.external, the WebBrowser control obtains the IDispatch for these methods by calling the host implementation of IDocHostUIHandler::GetExternal(). The correct IDispatch interface is set by a call to CAxWindow::SetExternalDispatch() in the control's OnCreate message handler.
The problem occurs because the WebBrowser control uses the IDispatch interface to query for IDispatchEx. If this fails, the host is queried for the default IDispatch instead of using the original interface.
Steps to Reproduce Behavior
- From Microsoft Visual C++ 6.0, From the File menu select New to create a new ATL project with default settings
- From the Insert menu select New ATL Object to insert an object of type HTML Control or Lite HTML Control. Use the default settings.
- Build the control and open the generated HTML file which contains the OBJECT tag for this control.
- The default DHTML control implements an OnClick() method which is invoked by clicking one of the three HTML buttons on the page.
REFERENCES
For more information about developing Web-based solutions for Microsoft Internet Explorer, visit the following Microsoft Web sites:
For more information about ATL DHTML controls, please refer to the Microsoft Visual C++ 6.0 online documentation.
For additional information, please refer to the following article in the Microsoft Knowledge Base:
188015 TITLE: HOWTO: Access Methods/Properties of Container from Script
(c) Microsoft Corporation 1999, All Rights Reserved. Contributions by Mark Davis, Microsoft Corporation.
Additional query words: kbDSupport kbbeta
Keywords: kbbug kbwebbrowser kbmshtml kbdhtml kbpending KB202009