This article was previously published under Q196026
On This Page
SYMPTOMS
In Visual Basic, an event fired by an ActiveX component
from a thread other than the main thread will sometimes cause an Invalid Page
Fault (IPF) or General Protection Fault (GPF). Usually it seems to work fine in
the Visual Basic IDE but fails when it runs as a standalone EXE.
Visual Basic uses an apartment threading model.
Cross-thread function calls need to be marshalled. Visual Basic does not
support events fired directly from any thread other than the main thread
created by a Visual Basic project without marshalling.
The thread being spun off needs to call
CoInitialize/CoUnInitialize.
2.
The sink interface being called back on in the thread must
be marshalled over to that thread with
CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream.
Instead of firing an event from a secondary thread, post a
message back to the main thread and fire the event there. An example of this
method is given later in this article.
The following example first creates an ATL project, then a Visual
Basic 6.0 project. It then uses these to demonstrate the proper way to have a
secondary thread request that the primary thread fire an event.
Create a new ATL COM AppWizard Project named MyAtlDll and
keep the default settings.
2.
In the class view, right-click the project name and select
New ATL Object. Select Simple Object in the displayed dialog box and click
Next. Type in "MyAtl" as the C++ short name. Click the Attribute tab and select
Support Connection Points. Click OK and a new ATL object is added.
3.
In the class view, right-click the IMyAtl and choose Add
Method. Type "InitTask" in the Method Name text box and "[in] long number" in
the parameters text box. Click OK.
4.
In the class view, right-click _IMyAtlEvents and select Add
Method. Select "void" from return type drop-down list box. Type "TaskFinished"
in the Method Name text box and "[in] long result" in the parameters text box.
Click OK.
5.
In the class view, right-click CMyAtl and choose Add member
variable. Type "long" in the variable type text box and "m_number" in the
variable name text box.
6.
Build the project to generate the type library needed for
step 10.
7.
In the class view, expand and double-click CMyAtl ->
IMyAtl -> InitTask. Edit the InitTask function to make it appear as follows:
DWORD WINAPI justDoIt(LPVOID lpParameter)
{
CMyAtl *myAtl = (CMyAtl*)lpParameter;
long result;
for (int i = 1; i <= myAtl->m_number; ++i)
result = i * 2;
myAtl->Fire_TaskFinished(result);
return 0;
}
9.
Add the following code right above the line "#endif
//__MYATL_H_" in MyAtl.h file:
DWORD WINAPI justDoIt(LPVOID lpParameter);
10.
In the class view, right-click CMyAtl and select Implement
Connection Point. Select _IMyAt-Events in the displayed dialog box. Click OK.
11.
Build the ATL project and the control will be registered
automatically.
Create a new Standard EXE project. Form1 is created by
default.
2.
Choose References from the Project menu, select "MyAtlDll
1.0 Type library," and click OK.
3.
Add a CommandButton to the form and keep the default name
(command1).
4.
Add the following code to the code window of form1:
Option Explicit
Private WithEvents vbATL As MYATLDLLLib.MyAtl
Private Sub Command1_Click()
vbATL.InitTask 11111
End Sub
Private Sub Form_Load()
Set vbATL = New MYATLDLLLib.MyAtl
End Sub
Private Sub vbATL_TaskFinished(ByVal result As Long)
MsgBox result
End Sub
5.
Press the F5 key to run the project. Click Command1 and you
will get 22222 in a message box.
6.
Build the project to be an EXE and run the EXE outside the
IDE. You will get an error message when you click the CommandButton.
Note that it may work sometimes, but it does not work consistently. To fix the
problem in this specific sample, you need to derive the CMyAtl from
CWindowImpl, and add a message map. Make sure the window is hidden. Now,
instead of firing an event from the secondary thread, you can post a message to
the main thread, and fire the event in the message handler.
For additional information about firing an event
from a second thread and about the PostMessage method, click the following
article numbers to view the articles in the Microsoft Knowledge Base:
157437 (http://support.microsoft.com/kb/157437/EN-US/)
FILE: Fireev.exe Fires Events from a Second Thread
280512 (http://support.microsoft.com/kb/280512/EN-US/) SAMPLE: ATLCPImplMT Encapsulates ATL Event Firing Across COM
Need More Help? Contact a Support professional by Email, Online or Phone.
Customer Service For non-technical assistance with product purchases, subscriptions, online services, events, training courses, corporate sales, piracy issues, and more.
Newsgroups Pose a question to other users. Discussion groups and Forums about specific Microsoft products, technologies, and services.