How to troubleshoot ActiveX control crashes in Internet Explorer

This article was previously published under Q247845
This article has been archived. It is offered "as is" and will no longer be updated.
Occasionally when you are using an ActiveX control (either one you developed yourself or a third-party control) inside an HTML page, Internet Explorer suffers a General Protection Fault (GPF), either midway through execution or while you are shutting down the browser. There are several known issues that can cause this to occur:
  • Your control is single threaded.
  • Your control hosts many other nested controls, each with its own window (hWnd) (Windows 95 and Windows 98 only).
  • Your control is not cleaning up resources properly.

Your control is single threaded

Beginning with version 4.0, Internet Explorer requires that all ActiveX controls it hosts be apartment-threaded. Apartment threading is a concept from COM; it means that each control exists within its own protected execution context, or apartment. Internet Explorer requires controls to use at least a Single-Threaded Apartment (STA), in which all threads except the control's creating thread can access the control only by posting messages. STAs make it easy to add concurrency to your ActiveX control with little programmatic overhead.

Non-apartment threaded controls exhibit uneven behavior between different instances of Internet Explorer. On some machines, the control may appear to work fine; on others, its performance slows to a crawl; and on others, it crashes.

To check whether or not a control is apartment threaded, consult the Registry entry for the control, and look for the ThreadingModel value underneath the InprocServer32 key:
HKEY_CLASSES_ROOT\CLSID\{Your Control's CLSID}\InprocServer32\ThreadingModel					
This value should be set equal to Apartment.

If ThreadingModel is not set, your control is single-threaded. Fortunately, converting your custom control to apartment threading is an easy change. Consult the topic "apartment-model threading" in the MSDN Library for more information. If you are using a third-party component, you cannot just change this registry setting and expect the control to work; you must get a new version of the control from your component vendor.
For more information on COM threading models, click the following article number to view the article in the Microsoft Knowledge Base:
150777 INFO: Descriptions and workings of OLE threading models

Your control hosts many other nested controls

Tools like Visual Basic make it easy to create complex ActiveX controls that contain other controls to multiple levels of embedding. It is not uncommon to see a developer create a Visual Basic UserControl with dozens of constituent controls and an embedding hierarchy of seven or eight levels. However, such controls appear to perform worse on Windows 95 and Windows 98 systems as time goes on, generally causing the browser to crash after about 30 minutes to an hour of dedicated use.

In this case, your control is using up too many system resources, particularly window handles. Windows 95 and Windows 98 have a limited amount of space for window handles, which are stored in a heap contained in the USER32 library. This heap's size is dynamic on Windows NT, but limited to 32K per process on Windows 95 and 98. Excessive window handles, combined with a failure to clean up control resources properly (see below), can quickly exhaust Internet Explorer's window handle limit.
One quick way to solve this problem is to make your controls windowless. Windowless controls save time and resources by forsaking ownership of a window handle; in this case, the control's container handles message-passing for the control through a set of OLE interfaces. Making controls windowless in Visual Basic, and in Visual C++ frameworks like Active Template Library (ATL), is very simple. See "Windowless Controls" in the MSDN Library for the details. For more information on the architecture of windowless controls, and what containers must do to support them, see the OLE Controls 96 specification.

Developers should also re-evaluate their control's design at this point. Such mammoth controls are hard to maintain and debug, and developers would best be served by breaking these giant control into several separate controls.

Your control is not cleaning up resources properly

The more you use complex components (components that contain n other components), the more likely you are to create circular references. A circular reference occurs when Control A contains Control B, and Control B also has a reference back to Control A (say, via a Parent property). In this case, neither object is destroyed, and thus the DLL containing your control is never unloaded. It will continue to consume more and more operating system memory, possibly destabilizing the entire computer.

This is another compelling argument for keeping the design of your controls flat and simple. In a control with more than four levels of containment, circular references are hard to track down, requiring tons of manual code instrumentation and debugging over several days. If breaking up the control is impossible, formulate a rigorous testing strategy, and verify the safety of each complex component--starting with the simplest controls and working up--before building on top of them.

Article ID: 247845 - Last Review: 12/05/2015 17:45:54 - Revision: 2.3

Microsoft Internet Explorer 4.01 Service Pack 2, Microsoft Internet Explorer 5.0, Microsoft Internet Explorer 5.5, Microsoft Internet Explorer 6.0

  • kbnosurvey kbarchive kbhowto KB247845