SAMPLE: ATLCPImplMT encapsulates ATL event firing across COM apartments (280512)



The information in this article applies to:

  • The Microsoft Active Template Library (ATL) 3.0

This article was previously published under Q280512

SUMMARY

ATL-based ActiveX COM objects (including Automation objects and ActiveX controls) typically fire events from the same thread in which they were created.

Sometimes it is desirable to start secondary threads in the COM object that fire events to the container. ATLCPImplMT.h provides an enhanced implementation of the ATL IConnectionPointImpl class, IConnectionPointImplMT, that provides this capability.

Because IConnectionPointImplMT uses the Global Interface Table, it requires Windows NT 4.0 Service Pack 3 or later, or Windows 95 (or later) with DCOM version 1.1 or later.

MORE INFORMATION

The following file is available for download from the Microsoft Download Center:
DownloadDownload the ATLCPImplMT.exe package now. Release Date: Apr-26-2001

For additional 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 to prevent any unauthorized changes to the file. The ATLCPImplMT.EXE (or ATLCPImplMT.hqx) file contains the following files:
ATLCPImplMT.h6 KB

Using ATLCPImplMT.h in Your ATL Project

Notes
  • The following steps must be performed on files containing implementations of proxy classes generated through the Implement Connection Point Wizard. These classes are named CProxy{EventInterfaceName} by convention, and your ATL COM class would derive from them. For additional information, see the following Microsoft Web page:
  • Because the Connection Point Wizard overwrites the generated proxy classes every time it is invoked, these steps must be repeated at that point.
  1. Copy the file ATLCPImplMT.h to your project folder.
  2. Add the following #include statement near the top of the wizard-generated files:
    #include "ATLCPImplMT.h"
    					
  3. Derive the proxy class, CProxy{EventInterfaceName}, from IConnectionPointImplMT, instead of IConnectionPointImpl. IConnectionPointImplMT has the same set of parameters. For example:
    1. If you are using Visual Studio 6.0, use the following code:
      // Derive from IConnectionPointImplMT, instead of IConnectionPointImpl:
      // template <class T>
      // class CProxy_IEvntFirerEvents : public IConnectionPointImpl<T, &DIID__IEvntFirerEvents, CComDynamicUnkArray>
      template <class T>
      class CProxy_IEvntFirerEvents : public IConnectionPointImplMT<T, &DIID__IEvntFirerEvents, CComDynamicUnkArray>
    2. If you are using Visual Studio .NET, use the following code:
      // Derive from IConnectionPointImplMT, instead of IConnectionPointImpl:
      // template<class T> 
      // class CProxy_IEvntFirerEvents : public IConnectionPointImpl<T, &__uuidof(_IEvntFirerEvents), CComDynamicUnkArray> 
      template <class T>
      class CProxy_NicEvents : public IConnectionPointImplMT<T, &__uuidof(_IEvntFirerEvents), CComDynamicUnkArray>
  4. For each generated function (named Fire_{EventName}) within the proxy class: Comment out the following lines within the generated for loop:
    1. If you are using Visual Studio 6.0, use the following code:
      			// pT->Lock();
      			// CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
      			// pT->Unlock();
      						
      Insert the following lines in their place:
      			CComPtr<IUnknown> sp;
      			sp.Attach (GetInterfaceAt(nConnectionIndex));
      					
    2. If you are using Visual Studio .NET, use the following code:
      			// pT->Lock();
      			// CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); 
      			// pT->Unlock(); 
      
      Insert the following lines in their place:
      			CComPtr<IUnknown> punkConnection; 
      			punkConnection.Attach (GetInterfaceAt(iConnection));
  5. The Fire_{EventName} functions can now be called from any other COM thread (in the same apartment, or a different apartment) that has access to the object in question.

Procedure to Use ATLCPImplMT.h in a sample project

  1. Follow Steps 1 through 7 in the "Steps to Create an ATL Project with Visual C++" section in the following Microsoft Knowledge Base article:

    196026 PRB: Firing event in second Thread causes IPF or GPF

  2. Add the following code to the MyAtl.cpp file. In the code below, the event is being fired through the worker thread in the multi-threaded apartment (MTA), not through the thread in the main single-threaded apartment (STA):
          DWORD WINAPI justDoIt(LPVOID lpParameter)
          {
             // Initialize COM, 
             // MTA worker thread:
             HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    
             CMyAtl *myAtl = (CMyAtl*)lpParameter;
    
             long result;
             for (int i = 1; i <= myAtl->m_number; ++i)
                result = i * 2;
    
             myAtl->Fire_TaskFinished(result);
    
    	::CoUninitialize ();
    
             return 0;
          }
    					
  3. Follow steps 9 and 10 in the "Steps to Create an ATL Project with Visual C++" section in article Q196026.
  4. Follow the steps outlined in this article in the "Using ATLCPImplMT.h Within Your ATL Project" section to add support for IConnectionPointImplMT.
  5. Build the ATL project, and the control will be registered automatically.
  6. Follow the steps outlined under the "Steps to Create the Visual Basic 6.0 Project" heading in article Q196026. Notice that when you click the CommandButton, unlike in article Q196026, the event firing works correctly.

REFERENCES

For additional information, click the following article numbers to view the articles in the Microsoft Knowledge Base:

157437 Fireev.exe fires events from a second thread

196026 PRB: Event in second thread causes IPF or GPF


Modification Type:MinorLast Reviewed:8/10/2004
Keywords:kbdocerr kbfile kbQFE kbSample KB280512 kbAudDeveloper