Signup · Login
Stardeveloper.com  
Home · Tutorials · Forums · Web Hosting Plans · Faisal Khan's Blog · Contact
Search Stardeveloper.com
Stardeveloper RSS Feed
Newsletter
Enter your email address below to be informed every time a new article is posted at Stardeveloper.com:

You can follow Faisal Khan on Twitter
Article Categories
.NET  .NET
  ASP (16)
  ASP.NET (41)
  ADO (16)
  ADO.NET (10)
  COM (6)
  Web Services (4)
  C# (1)
  VB.NET (3)
  IIS (2)

J2EE  J2EE
  JSP (15)
  Servlets (9)
  Web Services (1)
  EJB (4)
  JDBC (4)
  E-Commerce (1)
  J2ME (1)
  Products (1)
  Applets (1)
  Patterns (1)
Log In
UserName Or Email:

Password:

Auto-Login:

Miscellaneous Links
  Submit Article

Hosted by Securewebs.com
 
Home : .NET : COM : Beginning ATL 3 COM Programming
 

The Component Object Model
The component object model is built around the notions of components(often called coclasses), objects, and interfaces. These three different entities are defined and related as follows:

  • Loosely, as we have just been discussing, a coclass (named from component object class) is a piece of binary code that implements some kind of functionality. Coclasses can be distributed in DLLs, or in executable files. It is possible for a single module (DLL or executable) to contain more than one coclass.
  • A COM object is an instance of a coclass that gets loaded into memory. (By the same token, one might say that a coclass is a 'blueprint' for a COM object.) It is not unreasonable (indeed, it is quite common) for more than one object of a given coclass to be active at a time.
  • COM interfaces are the means — the only means — by which other components and other programs get access to the functionality of a COM component. An interface is a set of definitions of logically-related methods that will control one aspect of the component's operation. Each component can have one or more interfaces.
Note: You should have a good understanding of the concepts behind terms like "class" and "object" from your experience of object-oriented programming with C++. These concepts are not altered by COM, but you should be careful not to assume that there is a complete, one-to-one mapping that encapsulates all the secondary meanings of these terms. A coclass can be defined in C++ using a single C++ class, but it could also be defined with many C++ classes, or without any C++ classes at all (COM classes can be created in plain old C, for example). Remember that COM is a language-neutral protocol.

These definitions are accurate, but they probably haven't done a great deal to straighten things out in your mind — for a start, they're written in terms of one another. Let's start again with a closer look at the most important of the three: the COM interface.

Depending on the context in which it's being used, the word "interface" can have slightly different meanings. In the broadest possible terms, a COM interface is a group of definitions of methods that are usually related in the operations they perform. The methods in an interface can be called by using a pointer to that interface, and doing so results in the execution of the code in a COM object.

A "human" component, for example, might have interfaces called IMouth and IHand. These interfaces would group different methods — for example, IMouth might contain methods called Eat(),Talk(), and Kiss(), and IHand might contain Write(), Point() and Scratch().

Choosing our words a little more carefully, we can say that an interface is an abstraction. The definition of an interface includes the syntax of the methods it contains (return types, parameter types and calling conventions), and the semantics of how to use them. To see how the latter can be important, consider that there are often restrictions placed upon implementers and users of an interface that just can't be described in code. A requirement such as the need to call an 'Init()' method on the interface before calling any other method needs to be clearly documented, and forms the semantic part of the interface definition.

More carefully still, an interface actually has a very specific structure: it is an array of pointers to the implementations of the functions it contains — this is the binary standard that we mentioned earlier. Because the implementation of each function in the interface is accessed by a pointer in an array, the precise order of the items in that array is an important part of the interface's definition. Pictorially, we have a situation like this:

COM Interface
COM Interface

The array of function pointers associated with an interface is usually known as a vtable because it has the same structure as that produced by most compilers for the virtual function table of a C++ class.

Notice that the definition of an interface does not include an implementation of its methods. When a component says that it's going to implement an interface, it's up to that component to do so in a way that is both appropriate to itself and in accordance with the semantics defined for that interface. This separation leads to more robust design: interfaces can be reused in different situations, and a component that makes a particular interface available can be swapped with another component that makes available (exposes) the same interface. As a client, if you know that you need the functions of a particular interface, all you need to do is find an object that implements it.

We began this chapter by talking about the desire to build reusable components, but from the point of view of the user (usually called the client), the important aspect is not what the component is, but what it can do. Because interfaces are the only way of making a component do anything at all, we can say that the functionality of a component is defined by the interfaces it exposes. For example, if you want to say that a coclass is both a lawyer and a philanthropist (and if you don't feel that's an oxymoron), you can do so by having it expose interfaces called (say) 'ILawyer' and 'IPhilanthropist'.

By convention, the names of all interfaces start with 'I'. For fun, you can give your interfaces names like 'IAmTheWalrus', 'IRobot', 'ICLAVDIVS', or 'IDo', but you may find that the joke soon wears thin.

The COM specification includes details of a number of standard interfaces that Microsoft has defined. By implementing one of these interfaces, a component states that it supports some kind of functionality, or that it will work in some given situation. For example, a coclass that implements 'ISupportErrorInfo' is able to return rich error information, while a component implementing 'IDataObject' is capable of allowing data to be pasted or dropped into another application.

Interfaces As Contracts
As we've explained, COM enforces complete encapsulation of the data and implementation of a component. You can only call methods on the interfaces exposed by a component; you never get direct access to its data. This fact is what makes interfaces so fundamental, and when we link it to our earlier assertion about COM allowing easy customization and upgrading of applications, we can reach a couple of important conclusions:

  • An interface, once defined, must never change. Published interfaces are immutable.
  • Once a component has said that it exposes an interface, any future version of that component should also support that interface, to avoid existing clients from malfunctioning.

The interfaces that a component exposes represent a 'contract' between the component and its clients. A consequence of the second of these points when taken in the context of the first is that changes made to the contract in order to 'update' a component will surely break any existing clients, and so any revisions must be made with care. We'll return to this subject in the next chapter.

The Component Object Model
The component object model is built around the notions of components(often called coclasses), objects, and interfaces. These three different entities are defined and related as follows:

  • Loosely, as we have just been discussing, a coclass (named from component object class) is a piece of binary code that implements some kind of functionality. Coclasses can be distributed in DLLs, or in executable files. It is possible for a single module (DLL or executable) to contain more than one coclass.
  • A COM object is an instance of a coclass that gets loaded into memory. (By the same token, one might say that a coclass is a 'blueprint' for a COM object.) It is not unreasonable (indeed, it is quite common) for more than one object of a given coclass to be active at a time.
  • COM interfaces are the means — the only means — by which other components and other programs get access to the functionality of a COM component. An interface is a set of definitions of logically-related methods that will control one aspect of the component's operation. Each component can have one or more interfaces.
Note: You should have a good understanding of the concepts behind terms like "class" and "object" from your experience of object-oriented programming with C++. These concepts are not altered by COM, but you should be careful not to assume that there is a complete, one-to-one mapping that encapsulates all the secondary meanings of these terms. A coclass can be defined in C++ using a single C++ class, but it could also be defined with many C++ classes, or without any C++ classes at all (COM classes can be created in plain old C, for example). Remember that COM is a language-neutral protocol.

These definitions are accurate, but they probably haven't done a great deal to straighten things out in your mind — for a start, they're written in terms of one another. Let's start again with a closer look at the most important of the three: the COM interface.

Depending on the context in which it's being used, the word "interface" can have slightly different meanings. In the broadest possible terms, a COM interface is a group of definitions of methods that are usually related in the operations they perform. The methods in an interface can be called by using a pointer to that interface, and doing so results in the execution of the code in a COM object.

A "human" component, for example, might have interfaces called IMouth and IHand. These interfaces would group different methods — for example, IMouth might contain methods called Eat(),Talk(), and Kiss(), and IHand might contain Write(), Point() and Scratch().

Choosing our words a little more carefully, we can say that an interface is an abstraction. The definition of an interface includes the syntax of the methods it contains (return types, parameter types and calling conventions), and the semantics of how to use them. To see how the latter can be important, consider that there are often restrictions placed upon implementers and users of an interface that just can't be described in code. A requirement such as the need to call an 'Init()' method on the interface before calling any other method needs to be clearly documented, and forms the semantic part of the interface definition.

More carefully still, an interface actually has a very specific structure: it is an array of pointers to the implementations of the functions it contains — this is the binary standard that we mentioned earlier. Because the implementation of each function in the interface is accessed by a pointer in an array, the precise order of the items in that array is an important part of the interface's definition. Pictorially, we have a situation like this:

COM Interface
COM Interface

The array of function pointers associated with an interface is usually known as a vtable because it has the same structure as that produced by most compilers for the virtual function table of a C++ class.

Notice that the definition of an interface does not include an implementation of its methods. When a component says that it's going to implement an interface, it's up to that component to do so in a way that is both appropriate to itself and in accordance with the semantics defined for that interface. This separation leads to more robust design: interfaces can be reused in different situations, and a component that makes a particular interface available can be swapped with another component that makes available (exposes) the same interface. As a client, if you know that you need the functions of a particular interface, all you need to do is find an object that implements it.

We began this chapter by talking about the desire to build reusable components, but from the point of view of the user (usually called the client), the important aspect is not what the component is, but what it can do. Because interfaces are the only way of making a component do anything at all, we can say that the functionality of a component is defined by the interfaces it exposes. For example, if you want to say that a coclass is both a lawyer and a philanthropist (and if you don't feel that's an oxymoron), you can do so by having it expose interfaces called (say) 'ILawyer' and 'IPhilanthropist'.

By convention, the names of all interfaces start with 'I'. For fun, you can give your interfaces names like 'IAmTheWalrus', 'IRobot', 'ICLAVDIVS', or 'IDo', but you may find that the joke soon wears thin.

The COM specification includes details of a number of standard interfaces that Microsoft has defined. By implementing one of these interfaces, a component states that it supports some kind of functionality, or that it will work in some given situation. For example, a coclass that implements 'ISupportErrorInfo' is able to return rich error information, while a component implementing 'IDataObject' is capable of allowing data to be pasted or dropped into another application.

Interfaces As Contracts
As we've explained, COM enforces complete encapsulation of the data and implementation of a component. You can only call methods on the interfaces exposed by a component; you never get direct access to its data. This fact is what makes interfaces so fundamental, and when we link it to our earlier assertion about COM allowing easy customization and upgrading of applications, we can reach a couple of important conclusions:

  • An interface, once defined, must never change. Published interfaces are immutable.
  • Once a component has said that it exposes an interface, any future version of that component should also support that interface, to avoid existing clients from malfunctioning.

The interfaces that a component exposes represent a 'contract' between the component and its clients. A consequence of the second of these points when taken in the context of the first is that changes made to the contract in order to 'update' a component will surely break any existing clients, and so any revisions must be made with care. We'll return to this subject in the next chapter.


Previous ( 1 Gone )( 5 Remaining ) Next

See all comments and questions (post-ad) posted for this tutorial.


Buy This Book From Amazon
Title: Beginning ATL 3 COM Programming
Publisher: Wrox Press Inc
Price: $59.99
Pages: 521
DatePublished: October 1999



Comments/Questions ( Threads: 1, Comments: 2 )
    Contains 1 or more replies by the Author of this Article.
    Contains 1 or more replies by Faisal Khan.

  1. Make something FREE ( 1 Reply ) This thread contains 1 reply by Faisal Khan.

Post Comments/Questions

In order to post questions/comments, you must be logged-in. If you are not a member yet, then signup, otherwise login. Once you login then come back to this page and you'll see a form right here which will allow you to post comments/questions.

Please note, one of the benefits of signing up is to be notified immediately by email everytime you receive a reply to the thread you have subscribed to.

 
© 1999 - 2009 Stardeveloper.com, All Rights Reserved.