3D PLM Enterprise Architecture

Middleware Abstraction - Object Modeler

The CAA V5 IDL Compiler

Describing the CAA V5 IDL and converting your interfaces to C++ abstract classes
Technical Article

Abstract

The IDL (Interface Definition Language) used by CAA V5 is a bit different from both OMG IDL of CORBA, and MIDL of Microsoft. This article describes the main types and characteristics of CAA V5 IDL and explains how to compile your interfaces expressed using CAA V5 IDL to generate the corresponding C++ header files of the abstract classes used as interfaces for C++. The IDL language is mosly used to describe CAA V5 interfaces for Automation. Since Automation interfaces are COM interfaces, the IDL compiler also contains some elements that are COM-specific, though of no use to the end user.


The CAA V5 IDL

The CAA V5 IDL (Interface Definition Language) is the language you will use to write your interfaces. It is closely derived from the OMG IDL of CORBA and allows the declaration of how your interfaces will behave regardless how and using which language they will be implemented.

The CAA V5 IDL uses the following object types (the definitions are those of CORBA if they exist):

  1. The interfaces: an interface is a set of possible operations that a client may request of an object. It is converted into C++ as a class that contains no data members, but only methods.
  2. The types: a type is an identifiable entity with an associated predicate (a single-argument mathematical function with a boolean result) defined over values. Types can be basic types, such as integer or float, and constructed type such as structure or interface.
  3. The operations: an operation is an identifiable entity that denotes a service that can be requested

Some lexical conventions are required by IDL to accommodate mapping for several programming languages:

Remind also that any object declaration must be located before using it.

Below is the BNF grammar of all the constructed types available with the CAA V5 IDL.

specification ::= ( comDecl )* <EOF>
preproDecl ::= <LINENUM> <DECIMALINT> <STRING>
comDecl ::= journalDecl
| disableDecl
| aliasDecl
| comInterfaceDecl
| libraryDecl
| automationInterfaceDecl
| interfaceFwd
| enumDecl
| structDecl
| preproDecl
libExport ::= journalDecl
| disableDecl
| aliasDecl
| comInterfaceDecl
| automationInterfaceDecl
| interfaceFwd
| enumDecl
| preproDecl
libraryDecl ::= <PRAGMA> "REPID" <ID> <DCEID> <PRAGMA> "REPBEGIN" <ID> ( repreqPragma )* ( libExport )* <PRAGMA> "REPEND" <ID>
interfaceFwd ::= "interface" <ID> <SEMICOLON>
comInterfaceDecl ::= <PRAGMA> "ID" <ID> <DCEID> "interface" <ID> ( ":" <ID> )? "{" ( comFunctionDecl )* "}" <SEMICOLON>
comFunctionDecl ::= comRetType <ID> "(" ( comParamDecl ( <COMMA> comParamDecl )* )? ")" <SEMICOLON>
comParamDecl ::= comParamAttribute comParamType declarator
comParamAttribute ::= "in"
| "out"
| "inout"
automationInterfaceDecl ::= "interface" <ID> ( ":" <ID> )? "{" ( automationFunctionDecl )* "}" <SEMICOLON> <PRAGMA> "ID" <ID> <DCEID> <PRAGMA> "DUAL" <ID> <PRAGMA> "ID" <ID> <DCEID> <PRAGMA> "ALIAS" <ID> <ID>
automationFunctionDecl ::= ( <PRAGMA> "PROPERTY" <ID> )? automationParamType <ID> "(" ( automationParamDecl ( <COMMA> automationParamDecl )* )? ")" <SEMICOLON>
automationParamDecl ::= automationParamAttribute automationParamType <ID>
automationParamAttribute ::= "in"
| "out" ( <IDLRETVAL> )?
| "inout" ( <IDLRETVAL> )?
enumDecl ::= "enum" <ID> "{" <ID> ( <COMMA> <ID> )* "}" <SEMICOLON>
structDecl ::= structType <SEMICOLON>
aliasDecl ::= ( <PRAGMA> "ID" <ID> <DCEID> )? "typedef" aliasType declarator <SEMICOLON>
comRetType ::= comParamType
| "void"
comParamType ::= comBaseType
| <ID>
aliasType ::= comBaseType
| sequenceType
| structType
| <ID>
comBaseType ::= "float"
| "double"
| "short"
| "long"
| "char"
| "octet"
| "boolean"
| "any"
| ( "unsigned" ( "short" | "long" ) )
sequenceType ::= "sequence" "<" comParamType ( <COMMA> <DECIMALINT> )? ">"
automationParamType ::= automationBaseType
| <ID>
automationBaseType ::= "float"
| "double"
| "short"
| "long"
| "char"
| "boolean"
| "CATBSTR"
| "CATVariant"
| "CATSafeArrayVariant"
declarator ::= arrayDeclarator
| <ID>
arrayDeclarator ::= <ID> ( "[" <DECIMALINT> "]" )+
structType ::= "struct" <ID> "{" ( member )+ "}"
member ::= comParamType declarator ( <COMMA> declarator )* <SEMICOLON>
repreqPragma ::= <PRAGMA> "REPREQ" <ID>
journalDecl ::= <IDLREP>
disableDecl ::= <IDLNOGEN>
errorSkipTo ::= java code
specification ::= ( comDecl )* <EOF>
preproDecl ::= <LINENUM> <DECIMALINT> <STRING>
comDecl ::= journalDecl
| disableDecl
| aliasDecl
| comInterfaceDecl
| libraryDecl
| automationInterfaceDecl
| interfaceFwd
| enumDecl
| structDecl
| preproDecl
libExport ::= journalDecl
| disableDecl
| aliasDecl
| comInterfaceDecl
| automationInterfaceDecl
| interfaceFwd
| enumDecl
| preproDecl
libraryDecl ::= <PRAGMA> "REPID" <ID> <DCEID> <PRAGMA> "REPBEGIN" <ID> ( repreqPragma )* ( libExport )* <PRAGMA> "REPEND" <ID>
interfaceFwd ::= "interface" <ID> <SEMICOLON>
comInterfaceDecl ::= <PRAGMA> "ID" <ID> <DCEID> "interface" <ID> ( ":" <ID> )? "{" ( comFunctionDecl )* "}" <SEMICOLON>
comFunctionDecl ::= comRetType <ID> "(" ( comParamDecl ( <COMMA> comParamDecl )* )? ")" <SEMICOLON>
comParamDecl ::= comParamAttribute comParamType declarator
comParamAttribute ::= "in"
| "out"
| "inout"
automationInterfaceDecl ::= "interface" <ID> ( ":" <ID> )? "{" ( automationFunctionDecl )* "}" <SEMICOLON> <PRAGMA> "ID" <ID> <DCEID> <PRAGMA> "DUAL" <ID> <PRAGMA> "ID" <ID> <DCEID> <PRAGMA> "ALIAS" <ID> <ID>
automationFunctionDecl ::= ( <PRAGMA> "PROPERTY" <ID> )? automationParamType <ID> "(" ( automationParamDecl ( <COMMA> automationParamDecl )* )? ")" <SEMICOLON>
automationParamDecl ::= automationParamAttribute automationParamType <ID>
automationParamAttribute ::= "in"
| "out" ( <IDLRETVAL> )?
| "inout" ( <IDLRETVAL> )?
enumDecl ::= "enum" <ID> "{" <ID> ( <COMMA> <ID> )* "}" <SEMICOLON>
structDecl ::= structType <SEMICOLON>
aliasDecl ::= ( <PRAGMA> "ID" <ID> <DCEID> )? "typedef" aliasType declarator <SEMICOLON>
comRetType ::= comParamType
| "void"
comParamType ::= comBaseType
| <ID>
aliasType ::= comBaseType
| sequenceType
| structType
| <ID>
comBaseType ::= "float"
| "double"
| "short"
| "long"
| "char"
| "octet"
| "boolean"
| "any"
| ( "unsigned" ( "short" | "long" ) )
sequenceType ::= "sequence" "<" comParamType ( <COMMA> <DECIMALINT> )? ">"
automationParamType ::= automationBaseType
| <ID>
automationBaseType ::= "float"
| "double"
| "short"
| "long"
| "char"
| "boolean"
| "CATBSTR"
| "CATVariant"
| "CATSafeArrayVariant"
declarator ::= arrayDeclarator
| <ID>
arrayDeclarator ::= <ID> ( "[" <DECIMALINT> "]" )+
structType ::= "struct" <ID> "{" ( member )+ "}"
member ::= comParamType declarator ( <COMMA> declarator )* <SEMICOLON>
repreqPragma ::= <PRAGMA> "REPREQ" <ID>
journalDecl ::= <IDLREP>
disableDecl ::= <IDLNOGEN>
errorSkipTo ::= java code

specification

::=

( comDecl | automationDecl )* <EOF>

comDecl

::=

aliasDecl

|

comInterfaceDecl

|

automationInterfaceDecl

|

interfaceFwd

|

enumDecl

|

structDecl

automationDecl

::=

libraryDecl

|

libraryExport

libraryExport

::=

interfaceFwd

|

automationInterfaceDecl

|

enumDecl

libraryDecl

::=

repidPragma repbeginPragma ( libraryExport )* rependPragma

interfaceFwd

::=

"interface" identifier ";"

comInterfaceDecl

::=

idPragma "interface" identifier ( ":" identifier )? "{" ( comFunctionDecl )* "}" ";"

comFunctionDecl

::=

comRetType identifier "(" ( comParamDecl ( "," comParamDecl )* )? ")" ";"

comParamDecl

::=

comParamAttribute comParamType declarator

comParamAttribute

::=

"in"

|

"out"

|

"inout"

automationInterfaceDecl

::=

"interface" identifier ( ":" identifier )? "{" ( automationFunctionDecl )* "}" ";" idPragma dualPragma idPragma aliasPragma

automationFunctionDecl

::=

( propertyPragma )? automationParamType identifier "(" ( automationParamDecl ( "," automationParamDecl )* )? ")" ";"

automationParamDecl

::=

automationParamAttribute automationParamType identifier

automationParamAttribute

::=

"in"

|

"out" ( "/*IDLRETVAL*/" )?

|

"inout" ("/*IDLRETVAL*/" )?

enumDecl

::=

"enum" identifier "{" identifier ( "," identifier )* "}" ";"

structDecl

::=

structType ";"

aliasDecl

::=

( idPragma )? "typedef" aliasType declarator ";"

comRetType

::=

comParamType

|

"void"

comParamType

::=

comBaseType

|

identifier

aliasType

::=

comBaseType

|

sequenceType

|

structType

|

identifier

comBaseType

::=

"float"

|

"double"

|

"short"

|

"long"

|

"char"

|

"boolean"

|

"any"

|

"string"

|

( "unsigned" ( "short" | "long" ) )

sequenceType

::=

"sequence" "<" comParamType ">"

automationParamType

::=

automationBaseType

|

identifier

automationBaseType

::=

"float"

|

"double"

|

"short"

|

"long"

|

"char"

|

"boolean"

|

"CATBSTR"

|

"CATVariant"

|

"CATSafeArrayVariant"

|

"HRESULT"

declarator

::=

arrayDeclarator

|

identifier

arrayDeclarator

::=

identifier ( "[" <DECIMALINT> "]" )+

structType

::=

"struct" identifier "{" ( member )+ "}"

member

::=

comParamType declarator ( "," declarator )* ";"

identifier

::=

<ID>

repidPragma

::=

"#pragma" "REPID" identifier <DCEID>

repbeginPragma

::=

"#pragma" "REPBEGIN" identifier

rependPragma

::=

"#pragma" "REPEND" identifier

repreqPragma

::=

"#pragma" "REPREQ" identifier

idPragma

::=

"#pragma" "ID" identifier <DCEID>

dualPragma

::=

"#pragma" "DUAL" identifier

aliasPragma

::=

"#pragma" "ALIAS" identifier identifier

propertyPragma

::=

"#pragma" "PROPERTY" identifier

[Top]

Types

IDL provides C-language like declarations that associate an identifier with a type. A type can be a basic type, such as an integer or a float, that is an object whose internal structure is known, or a type can be a constructed type, such as a structure, or even an interface, or finally a type can be a template type.

Basic types are:

These types are mapped to C++ types as follows:

OMG IDL C++
short short
long long
float float
double double
char char
boolean boolean (This is: typedef unsigned char boolean;)
any any (not yet implemented. any will be implemented as a class)

Constructed types can be constructed from the following basic types:

[Top]

Interface

The interface gathers a list of operations available for requests on an object. The interface is equivalent to the public part of a class in C++, or to a list in CATIA. An interface is declared as follows:

// CAA V5 IDL
#pragma ID A "DCE:00020400-0000-0000-C000000000000046"
interface A
{
...
};

and is converted into C++ as:

// C++
class A : public CATBaseUnknown
{
  CATDeclareInterface;
  public :
  ...
};

The interfaces support inheritance as in C++. For example, the interface B is declared as inheriting from the interface A:

// CAA V5 IDL
#pragma ID A "DCE:00020400-0000-0000-C000000000000046"
#pragma DUAL A;
interface A
{
...
};
#pragma ID B "DCE:00020400-0000-0000-C000000000000047"
#pragma DUAL B;
interface B : A {
...
};

is converted into C++ as follows:

// C++
class A : public CATIABase
{
  CATDeclareInterface;
  public :
  ...
};
class B : public A
{
  CATDeclareInterface;
  public :
  ...
};

According to CAA V5 Object Model rules, the multi-inheritance is not allowed.

It is possible to use the forward declaration to declare an interface before it is fully declared:

// CAA V5 IDL
interface A;
#pragma ID B "DCE:00020400-0000-0000-C000000000000047"
#pragma DUAL B;
interface B : A {
...
};
#pragma ID A "DCE:00020400-0000-0000-C000000000000046"
#pragma DUAL A;
interface A
{
...
};

is translated as follows:

// C++
class A;
class B : public A
{
  public :
  ...
};
class A : public CATIABase {
  public :
  ...
};

[Top]

Automation Library or Typelib

To provide type information at run time for the scripts, Microsoft COM offers the type library, which does not exist with CORBA. 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. In addition, it is much faster than the late binding. 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.

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:

#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 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]

Enumeration

The enumeration consists in a finite ordered list of identifiers. For example:

// CAA V5 IDL
enum color {cyan, yellow, magenta, black};

is converted into C++ as:

// C++
enum color {cyan, yellow, magenta, black};

Find the difference!

[Top]

Alias (typedef)

You can create aliases for any data types. The typedef keyword associates a name with a data type. You should associate a GUID to each created alias, as follows:

// CAA V5 IDL
#pragma ID Name "DCE:00020500-0000-0000-C000000000000046"
typedef Name String

[Top]

String

A string is mapped to the C++ char *

[Top]

Operation and Operation Arguments

An operation maps to a C++ function with the same name as the operation.

The objects that can be declared as operation arguments are the types, the constants, the attributes, and the exceptions.

The parameters passed as operation arguments must be declared along with their passing modes belonging to one of the following:

Depending on the passing mode chosen, the signature generated will change. The following table shows the basic argument types and the passing result:

OMG IDL Type In Inout Out Return
short short short & short & short
long long long & long & long
float float float & float & float
double double double & double & double
boolean boolean boolean & boolean & boolean
char char char & char & char
enum enum enum & enum & enum
interface reference ptr intref_ptr intref_ptr & intref_ptr & intref_ptr

You should pay attention when choosing the passing mode. Mapping in arguments leaves the caller deal with memory allocation and deallocation for these arguments. Mapping inout and out arguments is more difficult. For variable length arguments, the callee must allocate part or all of the required storage. For fixed length arguments, the caller allocation is preferable. In addition, all storage areas for variable length arguments allocated by the callee must be deallocated.

[Top]

The IDL Compiler

The IDL compiler allows you to generate C++ source code for your interface classes from IDL sources which describe the interfaces. The IDL compiler runs in three steps:

  1. The first step uses the C++ preprocessor to preprocess the IDL sources and to generate an expanded IDL source. The #include and the #define statements are expanded.
  2. The second step generates the C++ header file for the class. The C++ #include statements are inserted at the right place. The included files must be generated before by the IDL compiler. The #define statements remain expanded.
  3. The third step generates the C++ header file for the TIE class.

The following figure shows these three IDL compiler steps

[Top]

How to Invoke the IDL Compiler

The IDL compiler is included into the building tool mkmk. Your C++ abstract classes are then automatically created when you use mkmk.

[Top]

Openness of the IDL Compiler

You may want to use the IDL compiler with the following restrictions or specificities:

[Top]

About the IDL Compiler Behavior and Error Messages

The IDL compiler has the following behavior or generates error messages in the following cases:

[Top]


In Short

The CAA V5 IDL (Interface Definition Language) is dedicated to create programming language independent interfaces that you can use from both a compiled language such as C++, and scripting languages such as Visual Basic and JScript with Windows, and Basic Script with UNIX.

The IDL compiler inntegrated with mkmk generates both the C++ abstract classes used as interfaces for C++, and the type library to access these interfaces from a scripting languages.

[Top]


References

[1] Creating Interfaces for Automation
[2] What Is HRESULT?
[3] The CAA V5 IDL Compiler
[Top]

History

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

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