A control can support as many event sets as it wants by describing their outgoing interfaces in its type information, marking each as a "source" in the control's coclass section. Only one of these source interfaces can also be marked "default," which makes it the control's primary event set.
Not all outgoing interfaces are event sets, as is the case with IPropertyNotifySink. Event sets are those interfaces that have meaning only to the particular control that defines them in its type information. A container that wants to process events in an event set and take action on them must somehow provide, usually at run time, an implementation of that particular interface. For this reason, controls almost always define an event set as a dispinterface. This allows a container to implement, at compile time, a sink object whose IDispatch can handle any arbitrary dispinterface at run time. The container uses the object's type information usually to display a list of events to the user or developer, allowing that person to assign actions to those events. The sink does little more than map an event dispID to some action to execute—it doesn't need to know the semantics of the event itself.
A simple container such as Patron can choose to support only a control's primary event set. Sophisticated containers should support all source interfaces that a control defines for itself, allowing a user or a developer to assign actions to all events.
OLE Controls classifies event types as request, before, after, and do events. A control sends a request event before the control does anything with the event itself, allowing the container to prevent further processing. IPropertyNotifySink::OnRequestEdit is an example. An edit control, as another example, might send an OnValidate event before processing every character typed into it, or it might send such an event before it loses the focus. The return value of such an event is obviously important. When a control doesn't allow the container a choice in the matter, it will send a before event prior to something happening. (The Windows message WM_INITMENUPOPUP is a good example; it is sent before a menu becomes visible.) Controls ignore any return code for such events. In the same manner, a control will ignore a return value for an after event, which is really only a notification to tell the container to do whatever it wants. Finally, a do event is one that allows the container to supplement or override the control's default behavior. Do events usually involve more complex arguments and return values.
Keep in mind that controls maintain no persistent state themselves for events—they simply fire events to any connected sinks. The actions taken on particular events are entirely an issue for the container, which must maintain the assignments as part of a form's persistent state. The container, of course, also provides whatever user interface or language mechanisms are appropriate for assigning actions to events in the first place.