Click here to Skip to main content
Licence 
First Posted 23 Jan 2005
Views 39,814
Bookmarked 24 times

An introduction to callbacks and connection points with ATL

By | 23 Jan 2005 | Article
Article giving a general perspective on implement callback interfaces and general notion of connectable objects and connection points.

A general callback scenario

Introduction

Programming COM with ATL and MFC has always been somewhat cryptic considering the ease with which Visual Basic creates them for us. Perhaps one of the most used but feared is the callback features. This article tries to understand a bit more about callbacks rather than jeopardize the readers with mighty names like source and sinks.

Background

I assume that most of the readers favour ATL for COM development and are comfortable with interfaces, editing IDL file and fiddling with methods and properties of an interface without much help from the wizard!

Description

Consider a very typical client server scenario with the server being the COM component (may be anything in process, out of process, service, etc.) and the client being a VC++ or a VB program that wants to make use of the services provided by your COM server. Consider that your client program calls the method of the server, consider for example add() (Wow!!!). Suppose that the server starts with the time consuming job of 'adding'. Your client application may go on with it's work and when it requires the result back from the server...now that's a real problem! Conventional interfaces provide for one way communication from the client to the server. Now, how will the server notify the client that it is ready with the result. In a typical COM terminology, we call the server interface as "SOURCE" and client side event handler as "SINK". We will use these terms where they are more appropriate, for remaining parts of discussions we can well stick with our 'client-server' common names. Now we have a wide range of alternatives. If you are good in Computer Organization and Architecture, you may be knowing of things like polling, interrupt based I/O, etc.

  1. The first choice at our disposal is similar to the polling technique. The client continuously checks with a property or a boolean method that will indicate if the operation is complete. The client is stuck in a loop till a 'true' is returned flagging the completion (success or failure) of the operation at the server side. However simple, this definitely is not an efficient or elegant solution. A better option would be for the server to be able to notify the client that it is done with its job and the results may be taken back by the client.
  2. This method is similar to the interrupt based I/O (no direct comparison expected). Add an interface to your server's .idl file. This interface declares the function that is to be executed once the results are available with the server. The server's IDL file declares the interface but does not implement it.

    The job of implementation of this interface is left to the client. Such a client needs to provide the function definition to handle the result given by the server. Consider that the server is providing an interface called _IServerEvents, the VB6 client code can be written as:

    Option Explicit
    
    Implements _IServerEvents
    
    Private Sub _IServerEvents_CallbackFunction()
      ...
    End Sub

    Similarly, for a C++ client assume that we have a class CMyClient available. This class is inherited from your _IServerEvents interface. The class overrides the CallbackFunction() to handle the post callback handling.

            class CMyClient: public _IServerEvents
            {
            public:
                STDMETHODIMP CallbackFunction()
                {
                    //Your code goes here
                    ...
                }
            };
  3. Although the solution in previous step is satisfying enough, it puts an added restriction on your client to implement the provided interfaces. A much transparent solution is offered by ATL wizard when we add a class to the project.

    Enable connection points in out CoClass

Now open your project's IDL file and add the following to it:

        dispinterface _IServerEvents
        {
        properties:
        methods:
        };

In the coclass tag, add the following lines:

        [
        uuid(xxxxxxxxx),
        helpstring("...")
        ]
        [default,source] dispinterface _IServerEvents;

Add a method to the dispinterface just like any conventional interface. In our case let it be CallbackFunction. Now the most important thing, in the class view, right click on the CoClass and choose 'Implement Connection Point...'. A single dialog will pop up. Press OK and you are done.

Implement the connection point

You will see that the function Fire_CallbackFunction(...) is implemented for you. Whenever you need to notify the client, you call this function with the required parameter. Remember that the IDL file should have attribute [in] for the parameter of the callback function.

The last part is to implement a client in VB6. This is real easy. While declaring the variable for the server class, use 'WithEvents' to enable your application to receive events from the server. Now that makes things really easy in VB.

However, the code for implementing the client in VC++ is not that straight forward. As this article is just to give you a taste of callbacks, I will prefer not to delve into unnecessary details. However, if any one is determined enough to code the client in VC++ I will be more than happy to help out. Please post me a message and I will answer you or even post a separate article describing the process.

My observations

While writing the code for a project, I needed to pass back a variant through the callback function. When I compiled my code (VC++ 6.0 with SP5 !!!), I got a warning: conversion to bool, possible loss of data. On running my client I found that it was actually getting value as 'True'. The callback function worked perfectly fine for BSTR, double, int, etc! Ultimately I figured out that, I had to use the InternalCopy() method of CComVariant class to copy the parameter value to the CComVariant array. Please be careful and never assume that wizard generated code is never error prone :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Mayur Mahajan

Engineer

United States United States

Member

Doing MS in Computer Science at State University of New York at Stony Brook.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralMy vote of 1 PinmemberMember 11204448:05 9 Dec '08  
Questionhi PinmemberNajmuddin Khan4:41 24 Dec '07  
GeneralNeed the client in C++ Pinmembernigs_krec21:01 21 Nov '06  
GeneralGreat Article! Pinmembervextant12:38 28 Oct '06  
GeneralImplent Interface Problem PinmemberBaldelicious8212:03 18 Sep '06  
AnswerRe: Implent Interface Problem PinmemberMayur Mahajan13:43 18 Sep '06  
GeneralRe: Implent Interface Problem Pinmemberdhanu_kapp23:44 11 Dec '06  
Questionfire event inside thread Pinmembernskwok8:07 16 Feb '06  
GeneralOne question Pinmemberpaulstandard23:21 12 Dec '05  
GeneralPassing an interface Pointer PinmemberCSpaceBob19:40 5 Jun '05  
GeneralRe: Passing an interface Pointer PinmemberMayur Mahajan2:23 6 Jun '05  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120517.1 | Last Updated 23 Jan 2005
Article Copyright 2005 by Mayur Mahajan
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid