PRB: Threading Issues with Visual Basic 6.0 ActiveX Components

ID: Q241896


The information in this article applies to:
  • Microsoft Visual Studio, Enterprise Edition versions 6.0, 6.0 SP3


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 C 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.

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.


MORE INFORMATION

Steps to Reproduce the Behavior

A: Creating the server

  1. Create an ActiveX EXE project and rename it ThreadTest.


  2. From Project menu, select Project Properties and on the General tab, select a Thread Pool of two (2).


  3. Add the following code to the default class (Class1):


  4. 
    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 
  5. Save and compile the project (ThreadTest.EXE).


B: Creating the client and testing

  1. Start a Standard EXE project and rename it Client.


  2. Add a command button and a textbox to the default form (Form1).


  3. Add the following code to Form1:


  4. 
    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<BR/>
       Next
    End Sub
    Private Sub Form_Load()
       Text1.Text = 1000
       Command1.Caption = "Start"
    End Sub 
  5. Compile the project (Client.EXE).


  6. 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.


C: Implementing the workaround

  1. Open the ThreadTest project.


  2. Add another class module (Class2) with no code.


  3. Save and re-compile the project (ThreadTest.EXE).


  4. Open the Client project.


  5. Replace the code in Form1 with the following:


  6. 
    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 
  7. Save and re-compile the project (Client.EXE).


  8. Run three or more instances of Client.EXE and press the Start button on each form. Note that you should see no error messages.


Additional query words:

Keywords : kbActiveX kbThread kbVBp600 kbGrpVB kbWinDNA kbDSupport
Version : WINDOWS:6.0,6.0 SP3
Platform : WINDOWS
Issue type : kbprb


Last Reviewed: February 2, 2000
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.