Sunday, August 24, 2008

Connection Points

Adding an Event to an ATL controls

Now we will add a and a event to your ATL control. You will fire the ClickFirstpane( ) event if the user clicks within the first pane of the control and fire ClickSecondPane( ) if the user clicks within second pane. Building a component in ATL is a four-step process:

(a) Creating a module
(b) Adding a component to the module
(c) Adding methods to the component
(d) Adding properties to the component.

We would create a module (usually a DLL) called 'conpoint'. Then we will create a component called mycon within this server. Let us carry out these steps now.

Creation Of Module

To create a module the Developer Studio provides an ATL COM AppWizard. This is the easiest of jobs. Carry out the following steps:

(a) Select ‘New’ from the ‘File menu. From the dialog that pops up select ‘ATL COM AppWizard’ as the project. Type ‘conpoint’ as the project name and click ‘OK’ to continue.
(b) Select type of module as ‘Dynamic Link Library’ and click ‘Finish’.
(c) Now a ‘New Project Information’ dialog is displayed which lists the name of files that the wizard would create. Click on ‘OK’. Now that the module stands created let us add a component to it.

Adding Component To The Module

To add component to the module we can use ‘ATL Object Wizard’. Carry out the following steps for adding the component named ‘Calculator’ using this wizard:

(a) Select ‘Insert | New ATL Object’ menu item. This would display the ‘ATL Object Wizard’ dialog.Select 'controls' from the categories List box and Select ‘Full control’ from the various object categories and click on ‘Next’.
(b) An ‘ATL Object Wizard Properties’ dialog is displayed
(c) The property sheet contains two tabs-Names and Attributes.

The Names tab is divided into two sections. The first section displays the ‘C++ names’ and the second section the ‘COM names’. Enter the ‘Short Name’ as mycon. As soon as you do this all other edit controls would be filled automatically . The names filled under the edit controls of ‘C++ names’ indicate that the class Cmycon will implement the object mycon in the files ‘mycon.h’ and ‘mycon.cpp’.The names filled under the edit controls of ‘COM names’ indicate that the CoClass name (component class) remains the same as the short name. The Interface name will be Imycon. The type is a description for the class. The ProgID will be 'compoint.mycon' and from the attributes tab, you selected the Support Connection Points check box. This created the ImyconEvents interface in your .idl file. Note that the interface name starts with an underscore. This is a convention to indicate that the interface is an internal interface. Thus, programs that allow you to browse COM objects can choose not to display the interface to the user. Also notice in the .idl file that Support Connection Points added a line to indicate that ImyconEvents is the default source interface. The source attribute indicates that the control is the source of the notifications, so it will call this interface on the container. When the ‘OK’ button is clicked, the class Cmycon and the interface Imycon are created. They can be viewed from the class view tab. Now you should add the ClickFirstPane( ) and ClickSecondPane( ) methods to the ImyconEvents interface: Right click on ImyconEvents in ClassView and selecting Add Method from the popup menu. From the Add Method dialog box, select a Return Type of void. Type ClickFirstPane in the Method Name box. Enter [in] long x, [in] long y in the Parameters box. Click OK. Check the '.idl' file to see that the code was added as a method to the ImyconEvents dispinterface. Then use the same procedure to define a ClickSecondPane method with the same parameters and return type. The ImyconEvents dispinterface in your .idl file should now look like this:

dispinterface _ImyconEvents
{

properties:
methods:
[id(1), helpstring("method ClickFirstPane")] void ClickFirstPane(int x,int y);
[id(2), helpstring("method ClickSecondPane")] void ClickSecondPane(int x, int y);

} ;

The ClickFirstPane( ) and ClickSeconePane( ) methods that take the x and y coordinates of the clicked point as parameters.Now generate your type library. To do this you can either rebuild your project or right-click the '.idl' file in FileView and click Compile 'conpiont.idl'. This will create the mycon.tlb file, which is your type library. Next, implement a connection point interface and a connection point container interface for your control. (In COM, events are implemented through the mechanism of connection points. To receive events from a COM object, a container establishes an advisory connection to the connection point that the COM object implements. Since a COM object can have multiple connection points, the COM object also implements a connection point container interface. Through this interface, the container can determine which connection points are supported.) The interface that implements a connection point is called IConnectionPoint and the interface that implements a connection point container is called IConnectionPointContainer. To help implement IConnectionPoint, use ClassView to access a connection point wizard. This wizard generates the IConnectionPoint interface by reading your type library and implementing a function for each event that can be fired. To run the wizard, follow these steps: Go to ClassView (on the View menu, click Workspace to see ClassView). Right click on your control's implementation class, in this case Cmycon. In the shortcut menu, select Implement Connection Point. Select _ImyconEvents from the Interfaces list then click OK and a proxy class for the connection point will be generated, in this case, CProxy_ImyconEvents. This is shown in below figure.



If you look at the generated 'conpointCP.h' file in FileView, you see it has a class called CProxy_ImyconEvents that derives from IConnectionPointImpl. 'conpointCP.h' also defines the two methods Fire_ClickFirstPane( ) and Fire_ClickSecondPane( ), which take the two coordinate parameters. These are the methods you call when you want to fire an event from your control. The wizard also added the CProxy_ImyconEvents and IConnectionPointContainerImpl to your control's multiple inheritance list. The wizard also exposed IConnectionPointContainer for you by adding appropriate entries to the COM map. You are finished implementing the code to support events. Now, add some code to fire the events at the appropriate moment. Remember, you are going to fire a ClickFirstPane or ClickSecondPane event when the user clicks the left mouse button in the control. To find out when the user clicks the button, first add a handler for the WM_LBUTTONDOWN message. In ClassView, right click on the Cmycon class and select 'Add Windows Message Handler' from the shortcut menu. Then select WM_LBUTTONDOWN from the list on the left and click the 'Add Handler' button. Click OK. Next, add new code to the OnLButtonDown( ) function in mycon.h (deleting any code placed by the wizard) so that OnLButtonDown( ) now looks like this:

LRESULT OnLButtonDown ( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{

// TODO : Add Code for message handler. Call DefWindowProc if necessary.

POINT pt ;

pt.x = LOWORD ( lParam ) ;

pt.y = HIWORD ( lParam ) ;

if ( PtInRect(&r1,pt ) )

Fire_ClickFirstPane(pt.x,pt.y) ;

else

Fire_ClickSecondPane(pt.x,pt.y) ;

return 0;

}

Since you have already calculated the points of the two panes in the OnDraw( ) function, use them in OnLButtonDown( ), use the PtInRect( ) API function to determine whether the clicked point is in first pane or not. Now try out your events. Build the control and start ActiveX Control Test Container . This time, view the event log window. To route events to the output window, select Logging from the Options menu and select Log to output window. Now insert the control and try clicking in the window. Notice that ClickFirstPane( ) is fired if you click within the first pane and ClickSecondPane( ) is fired when you click in second panet.


No comments: