SAMPLE: Helper Functions to Add Event Support to Server

ID: Q159041


The information in this article applies to:
  • Microsoft COM libraries, used with:
    • Microsoft Windows NT 4.0
    • Microsoft Windows 95


SUMMARY

The Eventh.exe sample provides helper functions that allow easy implementation of event-handling support in a COM server. It also provides a COM server that uses these functions and a COM client that uses the server.


MORE INFORMATION

The following file is available for download from the Microsoft Download Center. Click the file name below to download the file:

Eventh.exe
For more information about how to download files from the Microsoft Download Center, please visit the Download Center at the following Web address
http://www.microsoft.com/downloads/search.asp
and then click How to use the Microsoft Download Center.

After downloading the file, run it in an empty directory with the -d switch to set up the directory structure:
EVENTH.EXE -d
This sample provides helper functions that allow easy implementation of event-handling support in a COM server that fires events. A COM server must implement the following interfaces to fire events:

   IConnectionPointContainer
   IConnectionPoint
   EnumConnectionPoints
   EnumConnections 
This sample provides a function called CreateStdCPContainer() that implements the above interfaces and a function called FireEvent() that the server can use to fire events to all clients who have connected to a connection point. The helper functions can be found in the Event.cpp and Event.h files and can be used by 32-bit applications only. These files are self-contained and can be added to any 32-bit project.

This sample also provides a COM server that uses the helper functions to implement event-handling support and a COM client that uses the server. The COM server is the HELLO automation server sample that ships with the Win32 SDK with added event-handling support. The COM client is the HELCTRL automation client sample that ships with the Win32 SDK with added event-handling support.

To implement event-handling support in a COM server, the server must aggregate with the IConnectionPointContainer implementation provided by the helper function, CreateStdCPContainer. Following is the documentation of this function:

   HRESULT CreateStdCPContainer(
       IUnknown* punkController,
       ITypeInfo* aptinfo[],
       ULONG cTypeInfos,
       DWORD dwFlags,
       IUnknown** ppunkCPC) 
The function creates a connection-point container object with connection points corresponding to the array of typeinfos passed in. The newly created object, which supports IConnectionPointContainer, is aggregated with punkController. The implementation uses SAFEARRAYs as the data structure to store the connection-point objects and the event sink pointers provided by the COM clients.

Parameters

punkController
[in] Points to the server's IUnknown. The connection-point container created by this function aggregates with this IUnknown.
aptinfo
[in] Array of pointers to typeinfos. Each one corresponds to an event interface/dispinterface that the object supports. Typically, an object has only one event interface/dispinterface.
cTypeInfos
[in] Size of aptinfo array. This is typically 1, unless the object has multiple event interfaces.
dwFlags
[in] Indicates the type of connection-point container to create. The two values allowed are CPTYPEFLAG_MULTICAST and CPTYPEFLAG_SINGLECAST. CPTYPEFLAG_MULTICAST indicates that multiple clients can connect their sinks to each connection point and the event will be fired to all those clients. CPTYPEFLAG_SINGLECAST indicates that only one client can connect its sink to each connection point and the event will be fired only to that client. These constants are defined in Event.h in this sample.
ppunkCPC
[out] Returns IUnknown* of the created connection-point container object. (This is the private unknown of the aggregate.)

Return Value

S_OK Success.
E_INVALIDARG Invalid argument.
E_OUTOFMEMORY Memory allocation failed.

Example

In this code example, ptinfo is the typeinfo of the event interface (obtained from the type library) and riidEvents is the GUID of that interface. The COM server should call this code in its creation routine. This server has one event interface. It saves the returned pointer to the IUnknown* of the connection-point container object in the m_punkCPContainer data member. It also saves the pointer to the connection point in the m_pcp data member:

   CreateStdCPContainer(this, &ptinfo, 1, CPTYPEFLAG_MULTICAST,
   &m_punkCPContainer);
   m_punkCPContainer->QueryInterface(IID_IConnectionPointContainer,
   (void**)&pcpc);
   pcpc->;FindConnectionPoint(riidEvents, &m_pcp); 
The COM server should implement its IUnknown::QueryInterface. Following is an example of how to handle a request for IID_IConnectionPointContainer:

   if (iid == IID_IConnectionPointContainer)
        return m_punkCPContainer->QueryInterface(iid, ppv); 
After the server has aggregated with the connection-point container object provided by CreateStdCPContainer, it can use the FireEvent() helper function to fire events to the clients who have connected to a connection point. Following is the documentation of FireEvent():

   STDAPI FireEvent(IConnectionPoint FAR *pcp,
         DISPID dispidMember,
         REFIID riid,
         LCID lcid,
         WORD wFlags,
         DISPPARAMS FAR* pdispparams,
         VARIANT FAR* pvarResult,
         EXCEPINFO FAR* pexcepinfo,
         UINT FAR* puArgErr) 
This fires the event specified by dispidMember to all sinks connected to the pcp connection point. IDispatch::Invoke fires the event. Consequently, the event sink in the client must implement IDispatch for this function to work. If you do not want to use IDispatch to fire events, you must rewrite this function but you can still use CreateStdCPContainer(). This function does not stop firing events if the call to a specific event sink fails.

Parameters

pcp
[in] The connection point for which events are going to be fired. This connection point must be obtained from the connection-point container created by CreateStdCPContainer().
The other parameters are the same as the IDispatch::Invoke parameters and include the DISPID of the event to be fired and the parameters of the event.

Return Value

S_OK Success
E_OUTOFMEMORY Memory Allocation failure
Errors returned by failure of SafeArrayCopy and SafeArrayAccessData.

Example

In the following example, m_pcp is the variable referenced in the example section of the CreateStdCPContainer documentation:

   FireEvent(m_pcp, dispid, IID_NULL, LOCALE_USER_DEFAULT,
             DISPATCH_METHOD, &dispparamsNoArgs, NULL, NULL, NULL); 

To Compile the Samples

To compile an ANSI-debug version of the sample for Windows NT and Windows 95, use the following command:
nmake
To compile a Unicode-debug version of the sample for Windows NT only, use the following command:
nmake HOST=NT
See the makefile header comments for other make options.

Compile the HELLO sample before compiling the HELCTRL sample because HELCTRL uses HELLO's Tlb.h file. In this sample, the HELCTRL client application uses the server's type library to implement the IDispatch interface of the event sink. Note that the client can also use its own type library for this purpose.

To Run the Samples

Change Hello.reg to provide the full path of Hello.exe and Hello.tlb. Register Hello.reg in the registration database by double-clicking it in Explorer. Run Helctrl.exe and use its menu to control the HELLO server. You can use CreateHello to create a new instance of HELLO. You can use GetHello to bind to a running instance of HELLO. Use the Visible menu item to make the server visible if required. Use InvokeSayHello to invoke the SayHello method. The server fires the SaidHello event when SayHello is invoked. The client displays a message box indicating that it received the fired event.

Windows NT 4.0 and Windows 95 with DCOM have system-provided marshaling code for the event interfaces (IConnectionPointContainer, IConnectionPoint, EnumConnectionPoints and EnumConnections). Without DCOM, Windows NT 3.51 and Windows 95 do not have system-provided marshaling code for these interfaces. If you want to run these samples on Windows 95 without DCOM and Windows NT 3.51, install the marshaling code provided in the following sample from the Microsoft Knowledge Base. Make sure that you carefully read the installation instructions in the sample before installing the marshaling code:
Q149231 Marshaling Code for Connection Point Interfaces
If you would like to run the server on a remote computer and you want to gain access to it from the client using DOCM, read the following article in the Microsoft Knowledge Base. If you do this, make sure that the client application provides access permission to the user on the server computer, which is where the server application runs. Otherwise, the server application cannot fire events to the client application.
Q158582 Configuring a non-DCOM server and client to use DCOM

Additional query words: kbfile

Keywords : kbsample KbClientServer kbCOMt kbDCOM kbNTOS400 kbServer kbWinOS95 kbGrpCom kbDSupport
Version : :
Platform : NT WINDOWS
Issue type :


Last Reviewed: December 7, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.