Responding to COM Events

team lib

This section assumes youre familiar with the way in which COM implements events using connection points, as well as the way in which .NET implements events using delegates. A brief overview of the COM mechanism follows , but if you need more information, consult Inside COM , by Dale Rogerson (Microsoft Press, 1997).

For more information on delegates and events, consult a book appropriate to your .NET programming language, such as Inside C# by Tom Archer or Programming Microsoft Visual Basic .NET by Francesco Balena, both published by Microsoft Press.

Connection Points

The COM connection point mechanism provides a standard way for COM clients to receive event notifications from COM objects. A client implements a callback interface on an internal component called an event sink, and the notifying object calls the interface methods as events occur. The source component publishes details of its callback interface or interfaces by marking IDL interfaces with the [source] attribute. This attribute indicates that the component acts as a source of calls to the interface rather than implementing the interface and receiving calls.

 coclassMyObject{ [default]interfaceIOne; [source]interfaceMyEvents; }; 

Source interfaces are commonly dispinterfaces so that they can be handled easily by automation clients.

Connection points are implemented using two interfaces: IConnectionPointContainer , and IConnectionPoint . These two interfaces are used as follows:

  • The client-side event sink queries a server object for IConnectionPointContainer . If the object returns an interface pointer, it is a sign that the coclass supports connection points.

  • The sink uses methods on IConnectionPointContainer to locate the IConnectionPoint interface representing a specific event source interface. Since a server can support multiple outgoing interfaces, a client must match its sink to the interface identifier (IID) of a particular connection point interface.

  • Once it has obtained the correct connection point object, the event sink calls IConnectionPoint:: Advise to register its sink interface pointer. The event source holds the connection (and raises events to it) until the client breaks the connection by calling IConnectionPoint::Unadvise .

Handling Events from a COM Source

When the type library importer sees an interface marked with the [source] attribute, it generates the necessary delegates in metadata that you use in your managed client. In fact, the importer can generate several classes and interfaces to implement the connection point to the .NET transition:

  • A .NET interface equivalent to the COM source interface, which has an _Event suffix . This interface contains the same members as the COM interface but is declared as a .NET interface.

  • A delegate for each method on the source interface. These methods have an _EventHandler suffix.

  • A class with a _SinkHelper suffix. This class implements the .NET interface so that .NET clients dont see the underlying COM connection-point mechanism.

  • A class with an _EventProvider suffix. This class deals with talking to the COM components IConnectionPointContainer interface and obtaining an IConnectionPoint interface.

    Note 

    Not all of these classes and interfaces show up in the Object Browser.

Events Example

You handle events from a COM component exactly as you handle events from a .NET component. As an example, Ill show how to handle events from the Internet Explorer ActiveX control, using it as a non-UI COM component in a C# console application. In the next section, youll see how to use this ActiveX control in Windows Forms applications.

The first step is to create an interop assembly for the component. The Explorer control is housed in shdocvw.dll, which lives in the Windows System32 directory. Once youve created a C# console application in Visual Studio .NET, you can add a reference to the component by the usual method (that is, right-clicking on the solution name and choosing Add Reference from the context menu). Youll find the control on the COM tab, under the name Microsoft Internet Controls . Once the interop assembly has been generated, you can examine it in the Object Browser. This is a large component with a number of source interfaces. The names of these interfaces start with D and end with Events . You can see a number of them in Figure 3-3:

click to expand
Figure 3-3: The interop assembly for shdocvw.dll, viewed in the Object Browser

The importer has generated the interfaces and classes described in the previous section. For instance, the DShellWindowsEvents source interface is represented by the following:

  • The DShellWindowsEvents and DShellWindowsEvents_Event interfaces.

  • The DShellWindowsEvents_EventProvider and DShellWindowsEvents_SinkHelper private classes. Note that the Object Browser doesnt show the EventProvider class.

  • The DShellWindowsEvents_WindowRegisteredEventHandler and DShellWindowsEvents_WindowRevokedEventHandler delegates, which handle the events in client code.

Listing 3-3 contains a sample program that uses the interop assembly to open an Internet Explorer window and navigate to a URL. You can find this program in the Chapter03\TestEvents1 folder in the companion content.

Listing 3-3: TestEvents1
start example
 usingSystem; usingSHDocVw; namespaceTestEvents1 { classClass1 { //ReferencestointerfacesontheExplorerobject staticprivateInternetExplorerexp=null; staticprivateIWebBrowserAppbrw=null; //EventhandlersforExplorerevents staticvoidOnTitleChange(Strings) { Console.WriteLine("Explorerevent:Titlechangedto{0}",s); } staticvoidOnDownloadComplete() { Console.WriteLine("Explorerevent:Downloadcomplete"); } [STAThread] staticvoidMain(string[]args) { try { //CreateanExplorer exp=newInternetExplorer(); //Wireupaneventhandler.Thenameofthesinkevent //interfaceisDWebBrowserEvents2. DWebBrowserEvents2_DownloadCompleteEventHandlerevt= newDWebBrowserEvents2_DownloadCompleteEventHandler (OnDownloadComplete); exp.DownloadComplete+=evt; DWebBrowserEvents2_TitleChangeEventHandlerevt1= newDWebBrowserEvents2_TitleChangeEventHandler (OnTitleChange); exp.TitleChange+=evt1; //NavigatetoaURL brw=(IWebBrowserApp)exp; brw.Visible=true; strings= "http://www.microsoft.com"; objecto=null; brw.Navigate(s,refo,refo,refo,refo); Console.Write("Hitentertoquit: "); s=Console.ReadLine(); brw.Quit(); } catch(Exceptione) { Console.WriteLine("{0}",e.Message); return; } } } } 
end example
 

The program starts by creating an InternetExplorer object, using the wrapper class generated by Visual Studio .NET. Before doing anything with this object, I need to hook up event handlers, and I do this using the standard .NET event mechanism. Two source interfaces define events generated by the browser DWebBrowserEvents and DWebBrowserEvents2 . For this sample program, Ive chosen to handle two events from DWebBrowserEvents2 : TitleChange , which is fired when the text in the Explorer title bar has changed, and DownloadComplete , which is fired each time the download from a URL completes. The delegates for each of these events has been given a name by the import process, using the standard naming convention: the interface name followed by the event name and the suffix EventHandler .

Once the events have been hooked up, I can obtain a reference to the IWebBrowserApp interface on the Explorer object and use its standard methods to navigate to a URL. When you build and run the application, youll see events being reported in the console window. Youll also see that the application serves to show how the import mechanism completely hides COM connection points from the .NET programmer.

 
team lib


COM Programming with Microsoft .NET
COM Programming with Microsoft .NET
ISBN: 0735618755
EAN: 2147483647
Year: 2006
Pages: 140

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net