BUG: Error Accessing Window.external in ATL DHTML Control (202009)



The information in this article applies to:

  • Microsoft Internet Explorer (Programming) 5

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:
'Object doesn't support this property or method'

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:
  1. Add HTML Control to project (Ctrl).
  2. Add Simple Object to project, use default of "dual interface" (UIObj).
  3. 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)
    						
  4. 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;
       }
    						
  5. 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;
    						
  6. 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;
    						
  7. 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

  1. From Microsoft Visual C++ 6.0, From the File menu select New to create a new ATL project with default settings
  2. From the Insert menu select New ATL Object to insert an object of type HTML Control or Lite HTML Control. Use the default settings.
  3. Build the control and open the generated HTML file which contains the OBJECT tag for this control.
  4. 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.


Modification Type:MajorLast Reviewed:5/11/2006
Keywords:kbBug kbDHTML kbMSHTML kbpending kbWebBrowser KB202009