3D PLM Enterprise Architecture

Middleware Abstraction - Object Modeler

Creating Interfaces for Automation

Making your interfaces available from scripting languages
Technical Article

Abstract

Automation Interfaces are special interfaces that allow CAA V5 programming from simple scripting languages and macro recording and replay. In this article, we describe what these interfaces require from a technical standpoint, as well as the proper methodology to create them..


Making Interfaces for Automation

Declaring objects by means of interfaces is nice and the benefits that we could get from this are the following: objects are accessed by client applications through their interfaces, and actual implementations are never directly manipulated. Interface inheritance, implementation inheritance, and extensions are key features that make the CAA V5 model powerful, versatile, incremental, which enable to customize and extend the objects it provides, as well as enable data distribution.

Another key topic is to enable them for Automation and for journalling. Automation means that interfaces can be accessed from a scripting language and thus be used by user scripts. Journalling means recording a script from an interactive user scenario. This script can be replayed as is, or after modifications, to automate repetitive tasks. Interfaces making this possible are called CAA V5 interfaces for Automation. This is possible thanks to the interface exposition, which makes it possible to access CAA V5 interface and their methods from macros written in interpreted languages such as Visual Basic, VB Script, JScript, and Basic Script. The CAA V5 interfaces for Automation have this ability because the signatures of their methods have specific limitations to match scripting language calling possibilities.

CAA V5 runs on Windows and hosts the scripting engine for VBScript. It runs also on UNIX and hosts the scripting engine for Basic Script. Other scripting engines can be used out-process for Automation with Windows. But for journalling, only the VB syntax is currently available, and it is Basic Script that is generated in journalized macros. These scripting languages are not fully compatible. In order to make interfaces that can be called in both environments, and to create macros on Windows that can be run on UNIX or the reverse, the rules stated in this article must strictly be observed. Otherwise, macro portability cannot be guaranteed.

[Top]

Interface Exposition

Up to now, we have declared interfaces in such a way that they can take advantage of the CAA V5 model features, but we did nothing for exposition. Let's call these interfaces standard interfaces. Two other kinds of interfaces deal with interface exposition, explained below in capability growing order:

  1. Exposed interfaces can be called from a scripting language and are available for Automation. You need to include them in a tplib file to indicate to mkmk to generate the type library.
  2. Journalizable interfaces: in addition to exposed interface capabilities, they can be used for journalling user interactive scenarios to build scripts. These scripts can be replayed as is for test, debug, or analyze purposes, but are usually used as skeletons to write more comprehensive scripts.

From the client application programmer standpoint, there is no difference between a standard interface and an interface belonging to one of the two kinds above. However, exposed and journalizable interface IDL files include CAA V5 pragma directives that request to generate a type library used by scripting languages to retrieve these interfaces and execute the code of their methods to which they point.

[Top]

IDispatch, CATBaseDispatch and CATIABase

The base interface for exposed and journalizable interfaces is IDispatch, supplied by CAA V5 for UNIX and by the Component Object Model (COM) for Windows. IDispatch derives from IUnknown and provides the following methods, as shown in the IDispatch.idl file:

#include "IUnknown.idl"
#pragma ID IDispatch "DCE:00020400-0000-0000-C000000000000046"

interface IDispatch
{
  HRESULT GetTypeInfoCount(out unsigned long oNumberOfTypeInfo);

  HRESULT GetTypeInfo(in unsigned long iindex,
                      in unsigned long ilangId,
                      out unsigned long opTypeInfo);

  HRESULT GetIDsOfNames(in IID forFuture,
                        in WCHAR iArrayOfNames,
                        in unsigned long iNbNames,
                        in unsigned long iLangId,
                        out long oArrayOflong);

  HRESULT Invoke(in long ilongMember,
                 in IID  forFuture,
                 in unsigned long iLangId,
                 in unsigned short iFlags, 
                 in DISPPARAMS iPdisparams,
                 in unsigned long oPvaresult,
                 in EXCEPINFO oPexcepinfo,
                 in unsigned long oPuArgErr);
};

The IDispatch interface supplied by CAA V5 is exactly the same that the one of COM, making interfaces portable from UNIX to Windows for OLE and the reverse. The CATBaseDispatch interface derives from IDispatch, since both CAA V5 and Windows use a #define statement to see this interface as a structure to gain inheritance capabilities.

#define interface struct

With Windows, the CATBaseDispatch class provides an implementation for GetTypeInfoCount, GetTypeInfo, GetIdsOfNames and Invoke, exposed as pure virtual functions in the IDispatch.h header file, avoiding to implement them whenever you implement an exposable, exposed or journalizable interface and thus contributing to code factorization.

Let's have a look at GetIdsOfNames and Invoke. Given a method name, GetIdsOfNames returns its dispatch ID, or DISPID, which is a long integer (and not a GUID [1]). The DISPID is the identifier of the method inside the interface. Invoke uses then the DISPID as first argument to call the concerned method. This is called late binding, and is a run time binding, because the actual method to call is determined at run time using a call to GetIdsOfNames and not thanks to a build time mechanism. This matches the need of interpreted languages.

It is quite different with a build time mechanism, such as the one used with C++. Interfaces are represented using abstract classes. An abstract class is represented in memory as an area accessible using a pointer, which is the interface pointer. This pointer gives access to a table storing pointers to the methods of the TIE object that ties the interface to its current implementation. This table is called vtbl, short for class virtual function table. When the client calls a method using an interface pointer, this pointer is the pointer to the vtbl of the interface base class, and the appropriate method is called thanks to a shift of the appropriate offset to locate the pointer to this method. The vtbl is created when the abstract class is built, and the call in the client application is transformed into the appropriate call instruction when the client is compiled. So everything is created at build time. This is known as the vtbl binding, and is a build time binding.

vtbl binding is much faster than late binding in common situations, namely when objects are not distributed. 

The CATIABase interface derives from the CATBaseDispatch interface and is the base interface from which all the interfaces you will publish must derive if you want to make them exposed or journalizable, except your collection interfaces that you must derive from CATIACollection.

The CATIABase interface is implemented by the CATBaseObject class, for two purposes:

  1. The main purpose is to provide the ObjFromId method to determine reference to objects the first time these objects are met
  2. The second purpose is to provide the following methods for Visual Basic with OLE to manage unresolved object retrieval:

The CATIACollection interface is implemented by the CATBaseCollection class and provides the following method implementations:

[Top]

The Type Library

To provide type information at run time for the scripts, COM offers the type library. This makes it possible for the interpreted language to access the methods by means of the virtual function table of the object and to ensure run time type checking like C++ run time does.

The type library is a compiled version of a set of IDL files. It contains the description of all the interfaces, all the method prototypes, properties, and all the parameters they require along with their types. It is built using the CAA V5 IDL compiler [2].

You can scan a type library thanks to the OLE/COM Object Viewer with Windows.

[Top]

Publishing Your Interfaces

All the CAA V5 interfaces are coded using the IDL, acronym for the Interface Definition Language. Some CAA V5 pragmas enable to declare in the IDL file the kind of the interface described and the objects to build.

[Top]

Exposed Interfaces

They derive from CATIABase and include in their IDL file a ID declaration.

#pragma ID CATIAExposed "DCE:7c1b4ba8-5c25-0000-0280020bcb000000"
#pragma DUAL CATIAExposed
#pragma ID AccessName "DCE:73a1e08a-d8c4-11d0-a59f00a0c9575177"
#pragma ALIAS CATIAExposed AccessName
interface CATIAExposed : CATIABase {
...
};

An exposed interface must be declared in the type library.

[Top]

Journalizable Interfaces

To make a journalizable interface from an exposed interface, just add the comment /*IDLREP*/ in the IDL file, preferably as the first line of the file.

/*IDLREP*/
#pragma ID CATIJournalizable "DCE:7c1b4ba8-5c25-0000-0280020bcb000000"
#pragma DUAL CATIJournalizable
#pragma ID AccessName "DCE:73a1e08a-d8c4-11d0-a59f00a0c9575177"
#pragma ALIAS CATIJournalizable AccessName
interface CATIJournalizable : CATIABase

...
};

As an exposed interface, a journalizable interface must be declared in the type library.

[Top]

Declaring for Automation

If you want to take advantage of Automation capabilities, you need to declare the interfaces in a type library source file, suffixed by tplib. This is an example of such a file:

/*IDLREP*/
#pragma REPID INFITF "DCE:14f197b2-0771-11d1-a5b100a0c9575177"
#pragma REPBEGIN INFITF

#pragma REPREQ PreReqTypeLib

#include "CATIApplication.idl"
#include "CATIPageSetup.idl"
#include "CATIWindow.idl"

#pragma REPEND INFITF

where:

The IDL compiler [2] builds the run time type library from such a source file and stores it in a shared library with UNIX or a DLL with Windows.

[Top]

Creating the IDL Files

[Top]

Properties and Methods

A property is equivalent to a data member in C++. A property is accessed from scripting languages using the property name, but the IDL file includes two functions with the reserved prefixes get_ and put_ to get the property value and to set it respectively. These functions have one and only one argument.

[Top]

The Rules to Follow for Macro Portability

These rules deal with the  types, the way complex types are handled, the interface inheritance, and the signature types.

[Top]

The Supported Parameter Types

Compared to C++, scripting languages have parameter type support restrictions. The parameters of the method signatures must be of the following types.

Exposed Type Name Type Description CAA V5 IDL Syntax for that Type
Boolean Can take the two values True and False boolean
Integer Signed integer coded using 16 bits short
Long Signed integer coded using 32 bits long
Single Floating number coded using 32 bits float
Double Floating number coded using 64 bits double
BSTR Character string coded using the Unicode CATBSTR
Variant Can contain any of the above types CATVariant
SafeArray(Variant) Variant array. This type can be used as an input, or as an input/output parameter only CATSafeArrayVariant
Object OLE Automation interface <interface name>
Error code Error code coded on 32 bits HRESULT
Enum Enumeration Enum

The following OLE Automation types are not supported

Exposed Type Name Type Description
Byte Non signed integer coded using 32 bits
Currency Amount expressed in a given currency
SafeArray(<type>) Array of <type>, where type is not Variant
Decimal High precision decimal number coded using 16 bytes
Date Date

[Top]

The Complex Type Handling

The complex types, that is BSTR, SafeArray(Variant), and Variant are never handled directly, but only using the CAA V5 types, that is CATUnicodeString, any[], and any respectively. Functions to convert from/to these types are provided. For example, the CATUnicodeString class provides the BuildFroBSTR method to build a CATUnicodeString class instance from a BSTR, and ConvertToBSTR to convert a CATUnicodeString class instance into a BSTR. The CATAutoConversions.h file provides global functions to convert Variants.

[Top]

The Interface Inheritance

All the exposed interfaces must derive from one out of the two following interfaces:

These interfaces expose methods to match some of the scripting engine requirements. This is explained in IDispatch, CATBaseDispatch and CATIABase.

[Top]

The Parameter Directional Attribute

The method parameter types must be coded with IDL in the method signature with a directional attribute. An input parameter is declared with the in directional attribute, while an output parameter is declared with the out directional attribute. A parameter passed in both directions is declared with inout. For example:

HRESULT MyExposedMethod(in    <type> iparameter,
                        inout <type> ioparameter);

MyExposedMethod has an in parameter and an inout parameter.

[Top]

The Signature Types

The methods exposed in an interface fall among one of the four following types:

  1. Property reading functions. They are prefixed using get_. This prefix is dedicated to property reading functions and must not be used for any other function. Property reading functions have a single parameter preceded by out /*IDLRETVAL*/ which returns the read property value. Their signatures is as follows:
    HRESULT get_<propertyName> ( (out /*IDLRETVAL*/) <type> <parameterName> );

    For example:

    HRESULT get_FileName(out/*IDLRETVAL*/ CATBSTR oString);
  2. Property writing functions. They are prefixed using put_. This prefix is dedicated to property writing functions and must not be used for any other function. Property writing functions have a single parameter preceded by in which passes the property value. Their signatures is as follows:
    HRESULT put_<propertyName> ( (in) <type> <parameterName> );

    For example:

    HRESULT put_FileName(in CATBSTR iString);
  3. Sub procedures. They perform actions, but don't return a value.Their signatures is as follows:
    HRESULT <subProcName> ( ((in|out|inout)  <type> <parameterName>) * );

    For example:

    HRESULT Update(in iTimeStamp);
  4. Function procedures. Like Sub procedures, Function procedures perform actions, but also return a value. One of the parameters for IDL and C++ is designated as the scripting language function return value. This parameter must be preceded by out /*IDLRETVAL*/ and must be the last parameter in the signature.
    HRESULT <functionProcName> ( ((in|out|inout) <type> <parameterName>)* , out /*IDLRETVAL*/ <type> <returnedParameterName>);

    For example:

    HRESULT GetLastItemInList(in CATIACollection iList, out /*IDLRETVAL*/ CATIABase oItem);

You cannot put two methods with the same name and different signatures in the same interface: method overloading is not supported.

[Top]

Properties

A read/write property is created by declaring the property using a #pragma, and a couple of get_/put_ methods. For example:

#pragma PROPERTY Name
  HRESULT get_Name (out /*IDLRETVAL*/ CATBSTR oNameValue);
  HRESULT put_Name (in  CATBSTR iNameValue);

The Name property is declared using the #pragma PROPERTY. The two methods show that is is a read/write property. The get_Name method parameter is declared as out and /*IDLRETVAL*/ forces the parameter as a return value for the scripting function.

A read/only property is created by declaring the property using a #pragma, and a single get_ method. For example:

#pragma PROPERTY ActiveDocument
  HRESULT get_ActiveDocument (out /*IDLRETVAL*/ CATIADocument oDocument);

The Name property is declared using the #pragma PROPERTY. The get_ method shows that it is a read/only property. As for a read/write property, the get_Name method parameter is declared as out and /*IDLRETVAL*/ forces the parameter as a return value for the scripting function.

[Top]

The Interface Coding Check-List

Refer to the following check-list to make sure that the interfaces you write will match IDL, COM, CORBA, and CAA V5 rules. This check-list includes Visual Basic compatibility requirements.

  1. Use one file per interface, suffixed with idl. Example: MyInterface.idl
  2. An exposed interface derives from CATBaseDispatch
  3. A journalizable interface is an exposed interface with the following comment as first line:
    /*IDLREP*/
  4. Each interface method returns an HRESULT
  5. Each interface method parameter is declared as in, out or inout parameter

    in <type> means for C++ <type> * if type is an interface

    out <type> means for C++ <type> * & if type is an interface or <type> & if type is a base type.

  6. Any identifier must not begin with put_ or get_, except for properties
  7. An interface cannot have optional parameters
  8. int and void * types are not available
  9. A method can not be overloaded: two methods with the same name and different signatures cannot exist in an interface
  10. Properties are declared with #pragma PROPERTY statements
    #pragma PROPERTY PropertyName
      HRESULT get_PropertyName (out /*IDLRETVAL*/ <type> oPropertyValue);
      HRESULT put_PropertyName (in  <type> iPropertyValue);
    
  11. An IDL file can not define a constant
  12. CATSafeArray type used as method parameters can not have more than one dimension
  13. CATBSTR type must always be used for character strings
  14. An enum can be defined if it meets the three conditions below:
  15. Check that your declared types for parameters and returned values match the following table for methods. No other type is available:
    Visual Basic CAA V5 IDL CAA V5 C++
    Integer short short
    Long long long
    Single float float
    Double double double
    Byte octet octet
    Boolean boolean boolean
    HRESULT HRESULT
    String CATBSTR CATBSTR
    Object CATBaseDispatch * CATBaseDispatch *
    Array CATSafeArray CATSafeArray
    Variant CATVariant CATVariant
  16. Check that your declared types for parameters and returned values match the following table for property get_ and put_ methods. No other type is available:
    Visual Basic CAA V5 IDL CAA V5 C++
    Integer short short
    Long long long
    Single float float
    Double double double
    Byte octet octet
    Boolean boolean boolean
    HRESULT HRESULT
    String CATBSTR CATBSTR
    Object CATBaseDispatch * CATBaseDispatch *
    Array CATSafeArray CATSafeArray
    Variant CATVariant CATVariant
  17. An exposed or a journalizable interface must have an ID, must be declared as dual, and must have an exposed name:
    #pragma ID CATIAExposed "DCE:7c1b4ba8-5c25-0000-0280020bcb000000"
    #pragma DUAL CATIAExposed
    #pragma ID AccessName "DCE:73a1e08a-d8c4-11d0-a59f00a0c9575177"
    #pragma ALIAS CATIAExposed AccessName

The CATVariant stands for the Variant in Visual Basic, and for the any type of IDL, but you must use CATVariant in your IDL file. You should use it whenever you don't know the type of the parameter that Visual Basic will use, or if this type may vary.

[Top]


In Short

To be available form a scripting language, an interface must derive from CATIABase, or CATIACollection, and the class that implements it must derive from CATBaseDispatch, or CATBaseCollection, which provides an implementation of the methods declared by IDispatch. Its methods must also comply with the specific Automation signature restrictions.

Depending on the statements you put in the interface's IDL file, your interface can be exposable, exposed, or journalizable. It can include properties and methods the client applications can use on instances of objects implementing the interface.

The Interface Coding Check-List helps you to be right the first time.

[Top]


References

[1] About Globally Unique IDentifiers
[2] The CAA V5 IDL Compiler
[Top]

History

Version: 1 [May 2000] Document created
[Top]

Copyright © 2000, Dassault Systèmes. All rights reserved.