ID: Q159041
- Microsoft COM libraries included with:
- Microsoft Windows NT, version 4.0
- Microsoft Windows 95
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.
The following file is available for download from the Microsoft Software Library:
~ Eventh.ex
For more information about downloading files from the Microsoft Software
Library, please see the following article in the Microsoft Knowledge Base:
ARTICLE-ID: Q119591
TITLE : How to Obtain Microsoft Support Files from
Online Services
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.
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.)
S_OK Success.
E_INVALIDARG Invalid argument.
E_OUTOFMEMORY Memory allocation failed.
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.
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.
S_OK Success
E_OUTOFMEMORY Memory Allocation failure
Errors returned by failure of SafeArrayCopy and SafeArrayAccessData.
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 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.
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:
Article ID: Q149231
TITLE: 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.
Article ID: Q158582
TITLE : Configuring a non-DCOM server and client to use DCOM
Additional reference words: kbfile
Version : 4.00
Platform : NT WINDOWS
Last Reviewed: December 7, 1998