Sometimes, it is desirable to start a second thread in an ActiveX control that will fire events to the container. Because MFC ActiveX controls use the Apartment-threading model, special consideration must be taken when firing events from a secondary thread.
Visual C++ .NETRelease Date: 2-Jul-2002
For more information about how to download Microsoft support files, click the following article number to view the article in the Microsoft Knowledge Base:
An MFC-based ActiveX control supports events by implementing the IConnectionPointContainer and IConnectionPoint interfaces, as well as supplying information about its event interface in its type information. When an MFC-based ActiveX control is embedded in a container that supports events, that container will dynamically construct a sink interface that has all of the methods specified in the control's type information for its event interface. Once the container constructs its sink interface, it will pass a pointer to that interface to the ActiveX control. The ActiveX control will use its implementation of IConnectionPoint to communicate through the now-hooked-up sink interface that was constructed by the container. This sample will demonstrate how to call methods of the container's sink interface from a second thread.
The two most important things to consider when starting a new thread to fire events from an ActiveX control are:
- MFC-based ActiveX controls are in-process objects (implemented in a DLL).
- MFC-based ActiveX controls use the Apartment-threading model.
There are two possible ways to fire events from a second thread in an ActiveX control (or any other in-proc server that implements connection points) under the Apartment-threading model. The first is to make the interface call from the second thread by calling the event sink's method from the second thread. The second is to have the second thread post a message to the first thread when it is ready to fire the event, and have the first thread fire the event.
The first method mentioned above is not the optimal way to fire an event from a second thread: For the second thread to fire the event, it must make a call on an interface pointer that is held by the thread that initialized the control. Therefore, the interface pointer that will be used to fire the event must be marshaled to the second thread that will cause OLE to set up hidden windows to communicate between the threads. Windows messages will be used to communicate between the threads.
The MFC ActiveX control framework is not set up to fire events from a second thread easily. It is possible to override the default MFC code to marshal the sink interface pointers to the second thread, but this is not recommended because Windows is going to create hidden windows and use PostMessage to send messages between threads anyway. It makes more sense for the second thread to post its own messages to the first thread and have that thread fire the event. This code can be set up easily in an MFC ActiveX control. Use the following steps to add a second thread that fires events to the container in an MFC ActiveX control:
- Create your control project.
- Using ClassWizard, add a method that will start a second thread and return. The following code shows a method that starts a second thread and returns immediately in an MFC ActiveX control. A global function to serve as the second thread's work function is also declared:
LONG ThreadProc(LPVOID pParam);
HANDLE threadHandle = CreateThread(NULL,NULL,
(LPVOID)this, NULL, &dwID);
TRACE("Started the thread %x\n",dwID);
- Add any events you wish to fire from the second thread using ClassWizard.
- Define a custom message to be sent from the second thread. Also, add a message map entry to the control's message map that will call the message-handling function when the custom message is received. This message handler will fire the desired event. A sample of how to do this in an MFC ActiveX control follows:
//define a custom message:
#define WM_THREADFIREEVENT WM_APP+101
//add an entry for the message to the message map of the control
ON_MESSAGE(WM_THREADFIREEVENT,OnFireEventForThread) //custom handler
//add a handler for the custom message that will fire our event
LRESULT CFireeventCtrl::OnFireEventForThread(WPARAM wParam,
- In the thread procedure for the second thread, when it's time for the second thread to fire the event, post the custom message defined in step 3 back to the main thread. The event will be fired. The following code demonstrates:
LONG ThreadProc(LPVOID pParam)
Sleep(2000); //simulate lengthy processing
CFireeventCtrl *pCtrl = (CFireeventCtrl*)pParam;
Article ID: 157437 - Last Review: May 22, 2008 - Revision: 1