3D PLM Enterprise Architecture |
Middleware Abstraction - Object Modeler |
The CAA V5 IDL CompilerDescribing the CAA V5 IDL and converting your interfaces to C++ abstract classes |
Technical Article |
AbstractThe 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 (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):
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 |
::= |
( comDecl | automationDecl )* <EOF> | |
::= |
aliasDecl | |
| |
comInterfaceDecl | |
| |
automationInterfaceDecl | |
| |
interfaceFwd | |
| |
enumDecl | |
| |
structDecl | |
::= |
libraryDecl | |
| |
libraryExport | |
::= |
interfaceFwd | |
| |
automationInterfaceDecl | |
| |
enumDecl | |
::= |
repidPragma repbeginPragma ( libraryExport )* rependPragma | |
::= |
"interface" identifier ";" | |
::= |
idPragma "interface" identifier ( ":" identifier )? "{" ( comFunctionDecl )* "}" ";" | |
::= |
comRetType identifier "(" ( comParamDecl ( "," comParamDecl )* )? ")" ";" | |
::= |
comParamAttribute comParamType declarator | |
::= |
"in" | |
| |
"out" | |
| |
"inout" | |
::= |
"interface" identifier ( ":" identifier )? "{" ( automationFunctionDecl )* "}" ";" idPragma dualPragma idPragma aliasPragma | |
::= |
( propertyPragma )? automationParamType identifier "(" ( automationParamDecl ( "," automationParamDecl )* )? ")" ";" | |
::= |
automationParamAttribute automationParamType identifier | |
::= |
"in" | |
| |
"out" ( "/*IDLRETVAL*/" )? | |
| |
"inout" ("/*IDLRETVAL*/" )? | |
::= |
"enum" identifier "{" identifier ( "," identifier )* "}" ";" | |
::= |
structType ";" | |
::= |
( idPragma )? "typedef" aliasType declarator ";" | |
::= |
comParamType | |
| |
"void" | |
::= |
comBaseType | |
| |
identifier | |
::= |
comBaseType | |
| |
sequenceType | |
| |
structType | |
| |
identifier | |
::= |
"float" | |
| |
"double" | |
| |
"short" | |
| |
"long" | |
| |
"char" | |
| |
"boolean" | |
| |
"any" | |
| |
"string" | |
| |
( "unsigned" ( "short" | "long" ) ) | |
::= |
"sequence" "<" comParamType ">" | |
::= |
automationBaseType | |
| |
identifier | |
::= |
"float" | |
| |
"double" | |
| |
"short" | |
| |
"long" | |
| |
"char" | |
| |
"boolean" | |
| |
"CATBSTR" | |
| |
"CATVariant" | |
| |
"CATSafeArrayVariant" | |
| |
"HRESULT" | |
::= |
arrayDeclarator | |
| |
identifier | |
::= |
identifier ( "[" <DECIMALINT> "]" )+ | |
::= |
"struct" identifier "{" ( member )+ "}" | |
::= |
comParamType declarator ( "," declarator )* ";" | |
::= |
<ID> | |
::= |
"#pragma" "REPID" identifier <DCEID> | |
::= |
"#pragma" "REPBEGIN" identifier | |
::= |
"#pragma" "REPEND" identifier | |
::= |
"#pragma" "REPREQ" identifier | |
::= |
"#pragma" "ID" identifier <DCEID> | |
::= |
"#pragma" "DUAL" identifier | |
::= |
"#pragma" "ALIAS" identifier identifier | |
::= |
"#pragma" "PROPERTY" identifier |
[Top]
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]
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]
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:
INFITF
is the type library nameCATIApplication.idl
, CATIPageSetup.idl
and CATIWindow.idl
the files containing the interfacesREPID
, REPBEGIN
and REPEND
are
keywords to declare respectively the type library name and its GUID, the
beginning and the end of the interfaces to include in the type libraryREPREQ
declares the prerequisite type libraries.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]
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]
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]
A string is mapped to the C++ char *
[Top]
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:
in
: the parameter is passed from the calling application to
the called objectout
: the parameter is passed from the called object to the
calling applicationinout
: the parameter is passed from the calling application
to the called object and is passed back from the called object to the
calling application when the called method returns.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 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:
#include
and the #define
statements are expanded.#include
statements are inserted at the right place. The included files must be
generated before by the IDL compiler. The #define
statements
remain expanded.The following figure shows these three IDL compiler steps
[Top]
The IDL compiler is included into the building tool mkmk. Your C++ abstract classes are then automatically created when you use mkmk.
[Top]
You may want to use the IDL compiler with the following restrictions or specificities:
CATIXX
interface needs the CATNeighbor
class which has no IDL
interface. You just need to include interface CATNeighbor
in CATIXX
.idl,
compile it and add #include "CATNeighbor.h"
in the
generated CATIXX.h
file.
[Top]
The IDL compiler has the following behavior or generates error messages in the following cases:
idl
. Example: CATIXX.idl
where the
class name is CATIXX
syntax error
. It provides the file and the number
of the line where the error is foundNYI
DSLIM
[Top]
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]
[1] | Creating Interfaces for Automation |
[2] | What Is HRESULT? |
[3] | The CAA V5 IDL Compiler |
[Top] |
Version: 1 [May 2000] | Document created |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.