How to start a second thread in an MFC-based ActiveX control to fire events in Visual C++
2012-11-15 10:07
2621 查看
Article ID: 157437 - View products that this article applies to.
This article was previously published under Q157437
Note Microsoft Visual C++ 2008, Microsoft Visual C++ 2005, and Microsoft Visual C++ .NET 2003 support both the managed code model that is provided by the Microsoft .NET Framework and the unmanaged native Microsoft Windows code model. The information
in this article applies only to unmanaged Visual C++ code.
Expand all | Collapse
all
MFC-based ActiveX controls typically fire their events from the same thread that implements the sink interface of the container that the events are being fired to.
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.
The following files are available for download from the Microsoft Download Center:
Download Fireevvcnet.exe now
Release 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:
119591 How to obtain Microsoft support files from online services
Microsoft scanned this file for viruses. Microsoft used the most current virus-detection software that was available on the date that the file was posted. The file is stored on security-enhanced servers that help prevent any unauthorized changes to the file.
NOTE: Use the -d option when running Fireev.exe to decompress the file and Re-create the proper directory structure.
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.
The Apartment-threading model specifies that all threads that want to use OLE services must initialize OLE in their thread prior to using OLE services. Also, if a thread wants to use a pointer to an interface that is either implemented by a different thread
of the same process or has been previously marshaled to a different thread of the same process, that pointer must be marshaled to the requesting thread. In the Apartment- threading model, hidden windows are created to synchronize requests from other threads
to the thread being called. This means that all communication between threads will be done by using hidden windows and Windows messages in the Apartment 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:
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:
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:
Notice in the sample code above that the window handle of the ActiveX control is used as the target to which the message from the second thread will be posted. In most cases, an MFC based ActiveX control will be in-place active when its methods are called and
will have a window handle. It is possible, however, for an ActiveX control to not have a window handle, such as in the case of a window-less control. One way to work around this is to create a hidden window that could be used to communicate between threads.
That window could then be destroyed when the thread terminated. The FIREEV sample has code that is commented out in its StartLengthyProcess method and ThreadProc thread work function that demonstrates creating a window wrapped by the CMyWindow class that serves
this purpose. Also notice that PostMessage is used instead of PostThreadMessage. MFC's message maps are set up to intercept thread messages in CWinThread derived classes only. Because MFC ActiveX controls are derived from CWnd, they will not have messages
sent with PostThreadMessage routed to them. Messages sent with PostThreadMessage will have a NULL hWnd.
This article was previously published under Q157437
Note Microsoft Visual C++ 2008, Microsoft Visual C++ 2005, and Microsoft Visual C++ .NET 2003 support both the managed code model that is provided by the Microsoft .NET Framework and the unmanaged native Microsoft Windows code model. The information
in this article applies only to unmanaged Visual C++ code.
Expand all | Collapse
all
SUMMARY
MFC-based ActiveX controls typically fire their events from the same thread that implements the sink interface of the container that the events are being fired to.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.
MORE
INFORMATION
The following files are available for download from the Microsoft Download Center:Visual C++ .NET
Download Fireevvcnet.exe now
Release 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:
119591 How to obtain Microsoft support files from online services
Microsoft scanned this file for viruses. Microsoft used the most current virus-detection software that was available on the date that the file was posted. The file is stored on security-enhanced servers that help prevent any unauthorized changes to the file.
NOTE: Use the -d option when running Fireev.exe to decompress the file and Re-create the proper directory structure.
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.
The Apartment-threading model specifies that all threads that want to use OLE services must initialize OLE in their thread prior to using OLE services. Also, if a thread wants to use a pointer to an interface that is either implemented by a different thread
of the same process or has been previously marshaled to a different thread of the same process, that pointer must be marshaled to the requesting thread. In the Apartment- threading model, hidden windows are created to synchronize requests from other threads
to the thread being called. This means that all communication between threads will be done by using hidden windows and Windows messages in the Apartment 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); void CFireeventCtrl::StartLengthyProcess() { DWORD dwID; HANDLE threadHandle = CreateThread(NULL,NULL, (LPTHREAD_START_ROUTINE)ThreadProc, (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 BEGIN_MESSAGE_MAP(CFireeventCtrl, COleControl) //{{AFX_MSG_MAP(CFireeventCtrl) //}}AFX_MSG_MAP ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties) ON_MESSAGE(WM_THREADFIREEVENT,OnFireEventForThread) //custom handler END_MESSAGE_MAP() //add a handler for the custom message that will fire our event LRESULT CFireeventCtrl::OnFireEventForThread(WPARAM wParam, LPARAM lParam) { FireLengthyProcessDone(); return TRUE; }
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; PostMessage(pCtrl->m_hWnd, WM_THREADFIREEVENT, (WPARAM)NULL, (LPARAM)NULL); return TRUE; }
Notice in the sample code above that the window handle of the ActiveX control is used as the target to which the message from the second thread will be posted. In most cases, an MFC based ActiveX control will be in-place active when its methods are called and
will have a window handle. It is possible, however, for an ActiveX control to not have a window handle, such as in the case of a window-less control. One way to work around this is to create a hidden window that could be used to communicate between threads.
That window could then be destroyed when the thread terminated. The FIREEV sample has code that is commented out in its StartLengthyProcess method and ThreadProc thread work function that demonstrates creating a window wrapped by the CMyWindow class that serves
this purpose. Also notice that PostMessage is used instead of PostThreadMessage. MFC's message maps are set up to intercept thread messages in CWinThread derived classes only. Because MFC ActiveX controls are derived from CWnd, they will not have messages
sent with PostThreadMessage routed to them. Messages sent with PostThreadMessage will have a NULL hWnd.
相关文章推荐
- How to get IOleSite interface of the WebBrowser in an ActiveX control
- How to create MFC applications that do not have a menu bar in Visual C++(MFC单文档和多文档程序中去掉菜单栏)(转)
- How_to_Handle_Pointer_Events_in_a_Custom_Control(转)
- How to cover an IE windowed control (Select Box, ActiveX Object, etc.) with a DHTML layer.
- How to embed Lua in C++ on Visual Studio
- How To Use a DataReader Against an Oracle Stored Procedure in Visual C# .NET
- Simple way to expose a .NET WinForm control as an ActiveX control in any HTML page
- How to increment version information after each build in Visual C++
- How to Use MFC Tab Control in Developing VC++ Applications
- (在做报文编辑器时右键菜单老不出来)This article explains how to display a context menu for a tree control in MFC
- How to Start Firestarter Automatically in Ubuntu 7.04[转]
- How to use Intel C++ Compiler in Visual Studio 2008
- How to use an ActiveX script task to create a loop in DTS
- how to open property manager in Visual C++ 2010 express edition
- HOWTO: How to Provide Your Own DllMain in an MFC Regular DLL
- How to control printer orientation(Landscape / Portrait) for an AX report in X++
- How to use the System Restore API to save and to restore system data in Visual C++
- How to use an external dll file in VisualStudio project
- How to build an OLE DB application for SQL Server CE in Visual Studio 2005
- How do you copy the contents of an array to a std::vector in C++ without looping? (From stack over flow)