|
Beginning ASP Components, page 2 Author: Richard Anderson Contents
Interfaces and Implementation So far, we've talked only in general terms about how we can pass some relevant values to a component and ask it to perform a task for us. We haven't yet talked about how we tell the component what we want it do, or how we pass in the required values. That's what this section is about. One of the key characteristics of all COM components is that they are able to perform tasks for us without telling us how the task is going to be performed. To achieve this, the component must give us clearly defined information saying what the component can do, what type of information it expects us to pass, and what it will return when the task is complete. In other words, we need to know what methods the component exposes, the parameters that each method expects, and the return value from each method. In order to facilitate this, COM distinguishes the description of a component's functionality from its internal workings.
An interface is really nothing more than a list of methods, properties and events (you'll meet the second and third of these terms in a moment). When we want to use the component, the interface tells us how to do it. The interface doesn't give any details of the component's implementation, but its existence implies a promise that the functionality it describes will always be available. The distinction between interface and implementation is an important one. It's the interface that provides the link between our applications and the component itself. We can replace an old component with a new one that has a different implementation, provided that the new component provides the same interface as the old one. Otherwise, applications designed to use the original interface may break. Understanding Interfaces To help us understand interfaces, let's think about cars. We're going to model a car in terms of a component. If you want to be really imaginative, you can pretend that you're an ASP page (rather than a human being) driving the car. The car component provides functionality that can be defined by a number of interfaces. For example, the component has an interface that defines how you drive the car-we'll call it IDrive (by convention, interface names often begin with I). Methods The IDrive interface has these methods:
The methods are the object's way of allowing us to use it to perform a task. The methods above allow us to accelerate, brake, and steer the car. By using the object's methods to perform the tasks, we don't need to worry about what is going on inside the object. If we want to turn the car to the left, we don't need to get under the car to find out how the steering mechanism works-we just sit in the driver's seat and call its SteerLeft() method (equivalent to turning the steering wheel). Some methods need additional information, and will adjust their behavior accordingly. For example, the SteerLeft method would need to be told just how far to turn the steering wheel to the left. To this end, such methods are capable of receiving parameters - values required to execute the method. Properties Properties are the settings or stored values that are contained within an object, some of which are exposed to the user. These values tell us about the appearance or behavior of the object-and we can change some properties too. The IDrive interface might include properties that tell us the temperature of the engine, and the amount of gas in the tank. There are three types of properties: read-only properties, write-only properties, and read-write properties. For example, the car probably has a read-only property that tells us what mileage it has done. You can affect the values of some read-only properties indirectly-driving the car will increase the mileage-but you're not permitted to set the mileage directly. The tripometer (which tells you how far you have gone) would be a read-write property-you can write to it by pressing the button that resets it to 0, and you can read it by looking at the display that tells you how far you traveled since you last pressed the button. Events We should also briefly mention events. If methods are our way of telling an object what to do, events are the object's way of telling us that something has happened. For example, many modern cars have a device that is capable of monitoring the amount of gas in the tank. If the gas level falls below a certain level, the device fires an event, which informs the object that the gas level is low. This allows the object to react to the event-in this case by displaying a bright-red warning sign on the dashboard. Reacting to an event in this way is called event handling. Using the Interface The nice thing about cars is that generally, once you know how to drive one, you know how to drive them all. All cars use a steering wheel to steer; you make them go faster by pressing the accelerator pedal, and slower by pressing the brake pedal. The same is true for trucks and juggernauts. How does this relate to components? Well, we can have lots of different types of component that all expose the same interface. The car component exposes the IDrive interface, but so do the truck component and the juggernaut component. Once we know the methods and properties exposed by the IDrive interface, we know roughly how to use that interface on any component that exposes it. You will often see methods written with parentheses after them, like this:
BrakeHard()
Within the parentheses, you might need to include one or more other items-these are the parameters we mentioned earlier. The BrakeHard() method doesn't have any parameters (when we ask the car to brake hard, it will stop quickly-the car doesn't need any more information than that). By contrast, when we accelerate we'll need to tell the car by how much we want to accelerate-and to do that we use a parameter like this:
Accelerate(3)
This will work provided that the object knows what we mean by an acceleration unit of 3. This should be defined in the documentation for the component: "Insert an integer as the first parameter and I'll convert that into miles per hour and increase the speed by that amount". Again, as a driver we don't mind how the car component achieves this acceleration-we just have the promise that it will. Lollipop Diagrams To represent the interfaces that a COM component supports, we use a simple, pictorial technique called lollipop diagrams. A lollipop diagram represents the component in the form of a box; the interfaces extrude from the left side of the component. A name that appears within the box is the name of the component. The single line sprouting from the top of box represents an interface called IUnknown - this is a rather special interface in COM, so it gets special attention in lollipop diagrams. Every component implements IUnknown, but programming languages like Visual Basic shield us from IUnknown and other COM-specific workings on the supposition that they're difficult to understand. We could explain IUnknown here, but there's no gain, as Visual Basic will be used in Chapter 10. Chapter 10 talks about IUnknown in some detail, when we start using C++. To read Chapter 10 buy the book. The following figure shows the lollipop diagrams for the car and the truck in our example. Both components provide all the basic functionality needed to drive such a vehicle. It's not a great diagram, but it clearly shows what we can do with our vehicles. Let's look at a more realistic lollipop diagram for our car example. Interfaces generally group together related functionality, so in the following we have three interfaces (or four, if you include IUnknown extruding from the top): One interface provides methods for driving the car, another for controlling the locks and the alarm, and yet another for controlling the in-car music system. Identifying the Component IDrive is quite a nice name for our driving interface. The trouble is, it's such an obvious name that it wouldn't be at all surprising if someone else designed an interface of their own that did something similar, and they might call it IDrive as well. That's going to cause severe problems if a component that exposes my IDrive gets installed on the same machine as a component that exposes this other developer's IDrive interface. An application could easily end up talking to the 'wrong' interface-which will almost inevitably cause it to crash. COM resolves such problems by ensuring that each COM interface (and, for that matter, each component) has a 'real' name that is guaranteed to be unique. An interface's unique name is called an interface identifier (IID), and a component's unique name is called a class identifier (CLSID). IIDs and CLSID are both types of globally unique identifier (GUID); a GUID is a 128-bit number that can be generated with special a utility supplied by Microsoft. For example, the IID for my IDrive might be 67741683-547D-11D0-8236-00A0C908DB96. Inspection alone should tell you that it's more than a little unlikely anyone else will come up with that name by chance. The utility that generates GUIDs does so partly at random, and partly by scrambling information like the address of the Ethernet card in the machine on which it's running and the current time (to 100 nanosecond intervals). The algorithm used has been carefully designed to guarantee that identical GUIDs will not be accidentally generated for at least several thousand years. This should guarantee that there won't be any confusion between interfaces! |
Where Are Components Stored Normally, when you run a program, you're actually running an executable file. The executable file might call up some other files called dynamic-link libraries (or DLLs) to perform some tasks. A DLL is like an executable file, in that it contains instructions that the computer can run directly. But a DLL differs from an executable file because a DLL cannot be run independently. A DLL really is like a library that can be called up by any executable that's already running. Executables can also call upon the functionality contained in other files, such as OLE control extensions (or OCXs). An OCX is essentially a DLL that implements a visual interface. We won't deal with OCXs in this book. COM is designed to allow any application or component to call up any other component, no matter where the other component is. This means that COM components can be stored within executable files or as DLLs. When you create a component in Visual Basic or by using the Visual C++ ATL Wizards, you get to choose what type of file you'd like to host the component-a .dll or a .exe file. There are several factors to consider when choosing which type you want, but broadly speaking an executable offers greater security, while a DLL can give greater performance. This is because an executable will run in a separate process, which means that in order to use the component within the calling application, COM has to spend time passing data back and forth between the application's process and the component's process. A DLL-hosted component doesn't run in a separate process, so for components hosted in DLLs, this overhead is not normally an issue. Because of this, components hosted in DLLs are referred to as in-process components, while those located in executables are referred to as out-of-process components. COM Servers One of the slightly confusing aspects of COM is that there are several different names for some of the concepts involved. For example, what we have been referring to as a component, a Visual Basic programmer might call an "externally creatable class module". To confuse matters even further, C++ programmers may refer to the same thing as a "COM server", or a "COM object". We'll generally stick to the term component here. Strictly speaking, a COM server is a file (such as a DLL or an EXE) that contains all the executable code for one or more COM components, like this. One corollary of this is that related components can be hosted within the same COM server if necessary. Next Page....Using Components from ASP Buy the book!! This article is the first chapter of the book 'Beginning ASP Components' from Wrox Press. Order Beginning ASP Components from Amazon UK/Europe Today! Contribute to IDR: To contribute an article to IDR, a click here.
|
|