Microsoft KB Archive/241896

= Threading issues with Visual Basic 6.0 ActiveX components =

Article ID: 241896

Article Last Modified on 8/7/2007

-

APPLIES TO


 * Microsoft Visual Studio 6.0 Service Pack 3
 * Microsoft Visual Studio 6.0 Enterprise Edition
 * Microsoft Visual Basic 6.0 Professional Edition
 * Microsoft Visual Basic 6.0 Enterprise Edition

-



This article was previously published under Q241896



SYMPTOMS
When using Visual Basic 6.0 ActiveX components in a multi-threaded environment, you should be aware of the following potential problems:

ActiveX DLL hosted in a multi-threaded client

 * Access Violation inside MSVBVM60.DLL.
 * Client enters a deadlock state.

You may see these two symptoms if a Visual Basic ActiveX DLL is hosted in a multi-threaded environment, for example, IIS, MTS, or a multi-threaded client, and the Retain In Memory option is not enabled. To enable this option, follow the steps below:
 * 1) From Project menu, select Project Properties.
 * 2) On the General tab, make sure that the Threading Model is Apartment Threaded, then select the Unattended Execution and Retain In Memory checkboxes*.
 * 3) Save the project and compile the DLL.

*Note The Unattended Execution option is not available if the project contains any user interface elements, such as forms or controls. The Retain In Memory option is not available if Unattended Execution is not selected.

Note Prior to Service Pack 3 for Visual Studio 6.0, it was possible to get an AV during process shutdown with Retain in Memory enabled. This has been fixed in the latest Visual Studio 6.0 service pack:

http://msdn2.microsoft.com/en-us/vstudio/aa718364.aspx'

If an ActiveX DLL or UserControl project contains API declarations, you may experience deadlocks during process/thread shut down or object creation, even if the Unattended Execution check box has been selected in the case of an ActiveX DLL. To workaround this problem, you can use a Type Library instead of Declare in Visual Basic. For additional information on how to use a Type Library, click the article number%2 below to view the article%2 in the Microsoft Knowledge Base:

189133 HOWTO: Make C DLL More Accessible to VB with a Type Library

ActiveX EXE accessed by a multi-threaded client or by multiple single- or multi-threaded clients
Runtime error '7': out of memory and sometimes followed by a disk operation error.

Run-time error '430': Class does not support Automation or does not support expected interface.

Run-time error '424': Object required.

Run-time error '-2147023170 (800706be)': Automation error. The remote procedure call failed.

Run-time error '-2147287010 (8003001e)': Automation error. This is a "A disk error occurred during a read operation." based on ErrLook.

Additional server processes (ThreadTest.EXE) are created even though the Instancing property of Class1 is marked MultiUse.

You may see the error messages listed above if you have an ActiveX EXE server with a thread pool greater than one (1), and a multi-threaded client or multiple single- or multi-threaded clients rapidly creating and destroying objects inside the server. To work around this problem, you can create an empty class in the local server and have the client keep a reference to it as shown in the "More Information" section below.



STATUS
This behavior is by design.In Visual Studio 6 Service Pack 5, if a project contains any public class that has MTSTransactionMode set to anything other than 0, the Unattended Execution option and the Retain In Memory option are automatically selected.



A: Creating the server
 Create an ActiveX EXE project and rename it ThreadTest. From Project menu, select Project Properties and on the General tab, select a Thread Pool of two (2).  Add the following code to the default class (Class1): Private strClassName As String Public Property Let ClassName(ByVal vData As String) strClassName = vData End Property Public Property Get ClassName As String ClassName = strClassName End Property  Save and compile the project (ThreadTest.EXE).

B: Creating the client and testing
 Start a Standard EXE project and rename it Client.</li> Add a command button and a textbox to the default form (Form1).</li>  Add the following code to Form1: Private Sub Command1_Click Dim i As Long, j As Long Dim o As Object j = Val(Text1.Text) For i = 1 To j     DoEvents Set o = CreateObject("ThreadTest.Class1") o.ClassName = i     Me.Caption = o.ClassName Set o = Nothing Next End Sub Private Sub Form_Load Text1.Text = 1000 Command1.Caption = "Start" End Sub </li> Compile the project (Client.EXE).</li> Start three or more instances of Client.EXE and press the Start button on each form. Note that you see one or more of the error messages above.</li></ol>

C: Implementing the workaround
 Open the ThreadTest project.</li> Add another class module (Class2) with no code.</li> Save and re-compile the project (ThreadTest.EXE).</li> Open the Client project.</li>  Replace the code in Form1 with the following: Private p As Object Private Sub Command1_Click Dim i As Long, j As Long Dim o As Object j = Val(Text1.Text) For i = 1 To j     DoEvents Set o = CreateObject("ThreadTest.Class1") o.ClassName = i     Me.Caption = o.ClassName Set o = Nothing Next End Sub Private Sub Form_Load Text1.Text = 1000 Command1.Caption = "Start" Set p = CreateObject("ThreadTest.Class2") End Sub Private Sub Form_Unload(Cancel As Integer) Set p = Nothing End Sub </li> Save and re-compile the project (Client.EXE).</li> Run three or more instances of Client.EXE and press the Start button on each form. Note that you should see no error messages.</li></ol>

When an ActiveX EXE with a thread pool greater than one is accessed by multiple clients through DCOM, the workaround described in part C of the "More Information" section does not work. As a consequence, Visual Basic 6.0 ActiveX EXE servers are not suitable for DCOM servers with multiple clients rapidly creating and destroying objects. If your server application needs to handle this scenario, it is strongly recommended that you use ActiveX DLLs in MTS instead. When designing ActiveX DLLs to be hosted in MTS, you should make sure that the Unattended Execution and Retain In Memory checkboxes are both selected. These checkboxes and located on the Project menu, when you choose Properties, and select the General tab.

Do not use the GlobalMultiUse Instancing property for a class when you intend to use the ActiveX component under MTS or COM+. The interface for the GlobalMultiUse object is cached in a per thread-based table and is not freed until the thread terminates. As a result, if a call comes in with a different context (although on the same thread), it fails with RPC_E_WRONG_THREAD. To use components in MTS and COM+, you should design your classes in such a way that the objects are stateless.

Keywords: kbprb kbthread kbtophit KB241896

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.