When two clients call a procedure of an ActiveX EXE
component at the same time, and this procedure calls another procedure of a
MultiUse class in an ActiveX dynamic-link library (DLL), if this class accesses
a procedure in a GlobalMultiUse class in another ActiveX DLL, the ActiveX EXE
component stays in memory; that is, the process fails to terminate, even after
all the references to it have been released.
This behavior does not
occur in Visual Basic 6.0 Service Pack 3 (SP3) or earlier.
This problem occurs because the DllCanUnloadNow function of the GlobalMultiUse DLL returns FALSE if it is
currently being called by another thread. This means that the GlobalMultiUse
DLL may not be able to release itself in a multithreaded environment.
A supported hotfix is now available from Microsoft, but it is only intended to correct the problem that this article describes. Apply it only to systems that are experiencing this specific problem.
Note You must have a Visual Studio license agreement to obtain this hotfix.
To resolve this problem, contact Microsoft Product Support Services to obtain the hotfix. For a complete list of Microsoft Product Support Services telephone numbers and information about support costs, visit the following Microsoft Web site:
Note In special cases, charges that are ordinarily incurred for support calls may be canceled if a Microsoft Support Professional determines that a specific update will resolve your problem. The usual support costs will apply to additional support questions and issues that do not qualify for the specific update in question. The English version of
this fix should have the following file attributes or later:
Date Time Version Size File name
---------------------------------------------------------
29 May 2001 3:32:23 PM 6.0.92.37 1.32 MB Msvbvm60.dll
Create a new ActiveX DLL project with a default class,
Class1.
From the Project menu, click Project1 Properties. Change the project name to GMultiUseDll,
and then click OK.
In the Properties dialog box, set the Instancing property of Class1 to 6 -
GlobalMultiUse.
Copy and paste the following code to Class1's code module:
Public Function ClassName() As String
ClassName = "Class1"
End Function
From the File menu, click Make GMultiUseDll.dll to compile the project. GMultiUseDll.dll is created.
Create the DLL with a MultiUse Class
Create a new ActiveX DLL project with a default class,
Class1.
From the Project menu, click Project1 Properties. Change the project name to MultiUseDll,
and then click OK.
From the Project menu, click References, select the GMultiUseDll.dll check box, and then click OK.
Copy and paste the following code to Class1's code module:
Public Function GetString() As String
GetString = ClassName
End Function
From the File menu, click Make MultiUseDll.dll to compile the project. MultiUseDll.dll is created.
Create the ActiveX EXE Project
Create a new ActiveX EXE project with a default class,
Class1.
From the Project menu, click Project1 Properties. Change the project name to TestServer,
and then click OK.
From the Project menu, click References, select the MultiUseDll.dll check box, and then click OK.
From the Project menu, click TestServer Properties. On the General tab, set the Thread Pool to 10 threads.
Copy and paste the following code to Class1's code module
Public Sub DoSomething()
Dim obj As MultiuseDll.Class1
Set obj = New MultiuseDll.Class1
obj.GetString
End Sub
From the File menu, click Make TextServer.exe to compile the project. TextServer.exe is created.
Create the Client Project
Create a new Standard EXE project with a default form,
Form1.
From the Project menu, click Project1 Properties. Change the project name to TestClient,
and then click OK.
Add a Label (Label1), a TextBox (Text1) and two
CommandButtons (Command1 and Command2) to Form1.
Copy and paste the following code to Form1's code module:
Dim bStop As Boolean
Private Sub Command1_Click()
Dim oServer As Object
Set oServer = CreateObject("TestServer.Class1")
WaitTRUEinFile Text1.Text
oServer.DoSomething
Set oServer = Nothing
Label1.Caption = "The reference was released"
End Sub
' The purpose of this function is to synchronize the call to the
' GlobalMultiUse DLL through the file Sync.txt.
Private Sub WaitTRUEinFile(sFile As String)
Dim sFlag As String
Label1.Caption = "Waiting for 'TRUE' in " & sFile
Do While bStop = False
Open sFile For Input As #1
Line Input #1, sFlag
Close #1
If UCase(Trim(sFlag)) = "TRUE" Then
Exit Do
End If
DoEvents
Loop
End Sub
Private Sub Command2_Click()
bStop = True
End Sub
Private Sub Form_Load()
Text1.Text = "c:\sync.txt"
Command1.Caption = "Start"
Command2.Caption = "Stop"
bStop = False
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
bStop = True
End Sub
From the File menu, click Make TestClient.exe to compile the project. TestClient.exe is created.
Run the Test
Open Notepad. Add the letter "t" to the first position, and
save the file as Sync.txt in the root of drive C.
Start two instances of TestClient.exe. Notice that two
TestClient.exe processes are running in Task Manager.
Click Start for both instances of TestClient.
Open Sync.txt. Change the first line to "true," and
save.
After you save the file, notice the TestServer.exe process in
Task Manager.
Click Stop for both instances of TestClient, and close the forms. Notice
that there are no instances of TestClient.exe running. At this point,
TestServer.exe stays loaded.
For
additional information on issues related to multithreading in Visual Basic,
click the article number below to view the article in the Microsoft Knowledge
Base: