Caché Activate gives Caché applications an easy way to interoperate with ActiveX (also known as COM) components from within a Caché server. By means of wrapper classes, ActiveX components are made available as instances of Caché object classes and can be used in the same manner as any other class. Caché Activate provides the ability to instantiate an external COM object and manipulate it as if it were a native Caché object.
The terms “ActiveX” and “COM” are used interchangeably within this document.
Caché Activate is available only on platforms that support ActiveX (both 32-bit and 64-bit versions of Microsoft Windows).
Caché Activate works as follows:
Using the Caché Activate Wizard, you can create one or more wrapper classes. These are Caché classes that provide methods that correspond to the interface of an ActiveX component.
Within a Caché application, you can create an instance of an ActiveX wrapper class. Caché Activate transparently creates an instance of the appropriate ActiveX component within the same process. When you invoke the methods of the wrapper class, it automatically dispatches them to a method of the appropriate ActiveX interface.
You must exercise caution when using ActiveX components within Caché. Caché is designed to provide a safe environment for running application code. Every Caché server process runs an instance of the Caché virtual machine, is isolated from other service processes, and can handle application errors quite safely. ActiveX, unfortunately, is not a safe technology. Using ActiveX incorrectly or using poorly implemented ActiveX components can lead to memory leaks or unexpected application crashes. If you are using ActiveX components within a critical application, you should take extra care to ensure that you are using the interfaces of the component interfaces correctly and that the components have been thoroughly tested. It is a good idea to test any components using a tool such as Visual Basic before using them within your application.
Caché Activate consists of the following components:
The Caché Activate Wizard: This provides a simple graphical interface that lets you choose from the ActiveX components on your Caché server and automatically creates Caché wrapper classes for the components you select. The Caché Activate Wizard is accessible from the Add-Ins item on the Tools menu of the Atelier development environment. The Activate Wizard is available only on Windows systems.
The Caché Activate Class Hierarchy: These are helper classes used by the generated wrapper classes in order to communicate with ActiveX.
The Caché ActiveX Gateway: This is a shared library (DLL) loaded by and used by a Caché process to perform operations (loading, invoking methods, and releasing) on ActiveX components.
Overview of ActiveX / COM
The following is a simple overview of ActiveX / COM component architecture as it relates to Caché. If you intend to make use of ActiveX within your application, you should consult one of the many published works on the subject.
What Is a COM Object?
A COM object is a piece of code that conforms to the COM specification and provides one or more services that may be consumed by client programs. A certain class of COM objects, those which support the notion of Automation, are specially designed to be easily accessible from high-level programming languages such as VisualBasic, Delphi and now Caché. Such automation objects may be implemented as a dynamic link library and provide a simple function such as encryption of a text string or they may be full-blown executable applications such as Microsoft Excel or Microsoft Word which provide dozens of different services.
COM objects expose their functionality as interfaces. An interface is simply a collection of methods and properties that encapsulate some particular functionality. For example, a word processing object may provide a spell checking interface as well as a printing interface. Each implementation of a COM object is given a unique identifier in the form of a class id and each interface which it exposes also has a unique identifier referred to as an interface id. Once the class id of a particular object and the interface id of the required interface is known, it is possible for a client application to instantiate the COM object and avail itself of the services provided by the requested interface. By convention, when the name of an interface is written it is preceded by a capital “I”, so the SpellCheck interface becomes ISpellCheck.
The IDispatch Interface
Different programing languages have different internal data types which are incompatible at a binary level. For example, a Caché local variable has a completely different implementation from that of a VisualBasic string or a C++ string. This makes it difficult to call an object written in one language from another, because conversion has to be done from say, a C++ data type to a Caché variable and vice versa. To solve this problem and enable different programming languages to communicate, the notion of the VARIANT data type and the IDispatch interface was developed.
At its simplest, IDispatch provides the ability to call a method or access a property in an external COM object by specifying the name of the method or parameter and passing the appropriate arguments. Arguments are represented by a VARIANT type, which is a standardized data type that the operating system supports. This standardized type is “understood” by all programming languages that support the use of COM automation.
By creating a COM object and requesting its IDispatch interface, a client program or language, such as Caché, can easily access the functionality exposed by the object.
Although IDispatch provides a generic means to access a COM Automation object, it is really intended as a technique that a programming language uses internally to provide COM object services via the particular constructs of that language. In other words, the high-level language should abstract the details of calling IDispatch and provide programming language constructs to ease use of external objects. Ideally such COM objects should act as if they are native objects within a programming environment. In Caché Activate, the key to this is to exploit the information contained in a COM objects type library.
Most, if not all, COM Automation objects expose their metadata, i.e., a description of the types, methods and properties, in the form of a type library. The type library may be bound into a .DLL (dynamic link library), within an executable file as a binary resource, or it may exist in a separate file with an extension such as .tlb. Within the type library, each object is identified by a class id and is known as a CoClass. A CoClass may expose at most one IDispatch-derived interface known as the default interface. (Another interface known as the source interface may or may not be present. However it is not directly callable, and can safely be ignored for now). Some objects do not implement an IDispatch-derived interface at all and consequently are not callable via the IDispatch based mechanisms.
Caché Activate exploits the metadata contained in the type library by reading and decoding the information and creating Caché classes that expose the methods and properties defined therein. A type-library may contain one or more CoClass objects and potentially many IDispatch-derived interface definitions. There may be many interfaces because, although a CoClass may not expose more than a single IDispatch derived interface as its default interface, it is free to define methods and properties that either return or are typed as interfaces. In fact, this situation is common where a single CoClass (object) may define a rich object model. Consider a word processor for instance. It may provide a default interface of IApplication, which has methods such as AboutBox, Exit, etc. It also may provide a collection of documents (IDocuments*) as property called Documents.
Many COM interfaces are quite complex; they may contain hundreds of methods and may use many additional COM objects as parameters. If your application needs to use only a small subset of a specific interface, you should consider building a wrapper COM component (for example using Visual Basic) to expose only the interfaces you actually need and to pass any requests to these interfaces to the original COM component.