Attribute Overview

 

Available types of attributes are enumerated in the API_AttrTypeID structure. The definition of an attribute is described in the API_Attribute structure, which is in fact a union of all types of attributes. All of the attribute structures begin with a common header structure, named API_Attr_Head.

  • The typeID field identifies the type of the attribute.
  • The index field gives the current database index of the given attribute. References to any attribute are done through these indices.
  • The guid field gives the global unique ID of the given attribute. You can also refer to any attribute through its guid.
  • The flags field describes some attribute type dependent information. Possible values are listed at the same place where the given attribute structure is.
  • The name field gives the name of the attribute which appears in the appropriate dialogs.
  • The modiTime field tells you when the attribute was last modified.

Many attribute related functions use the API_Attribute structure on the parameter list. As a general rule, you have to fill the required fields in the union, then ARCHICAD parses the request based on the values and passes the return parameters in the same parameter. This is why most of the functions do not have the const directive in the prototypes.


Retrieving an attribute

Let’s see a simple example. Assume you are interested in the definition of the second line type of the data structure. In this case you should use a variable with the type API_Attribute structure.


API_Attribute    attrib;
GSErrCode        err;

BNZeroMemory (&attrib, sizeof (API_Attribute));
attrib.header.typeID = API_LinetypeID;
attrib.header.index  = 2;

err = ACAPI_Attribute_Get (&attrib);

The description of the attribute is returned in the attrib.linetype part of the union. With this function call, you get the basic data of the given attribute, such as the name, the flags, the defined scale, etc., but you do not get the definition of the actual shape of the line type. Since producing this data may be a relatively a long conversion process, this information can be obtained with an additional function call.


API_AttributeDef    defs;
err = ACAPI_Attribute_GetDef (API_LinetypeID, 2, &defs);

In this case, you have all of the additional data related to the particular attribute. The API_AttributeDef structure is a collection of several handles (dynamic memory). If any of them are allocated it contains data. If you do not need the data any more, you have to free the allocated memory blocks to avoid memory leaks. The suggested way is the following:


ACAPI_DisposeAttrDefsHdls (&defs);

If you use this function, it is ensured that all of the dynamic data will be freed, and also that there will be no compatibility problems if your add-on is installed to a newer version of ARCHICAD.

It is very important to examine the error codes returned by the API functions, and parse the returned value.

A typical situation is when you want to go through the instances of a particular attribute type in the database. The following example gives a good template to do that.


API_Attribute  attrib;
short      nLin, i;
GSErrCode  err;

BNZeroMemory (&attrib, sizeof (API_Attribute));
attrib.header.typeID = API_LinetypeID;
err = ACAPI_Attribute_GetNum (API_LinetypeID, &nLin);
for (i = 1; i <= nLin && err == NoError; i++) {
    attrib.header.index = i;
    err = ACAPI_Attribute_Get (&attrib);
    if (err == NoError) {
        /* do what you want */
    }
    if (err == APIERR_DELETED)
        err = NoError;
}

First you need to get the number of line types in the database. You can do that with the ACAPI_Attribute_GetNum function, but be careful. This function returns the largest index used in the database, not the number of installed attributes, because instances may be deleted. Deleted attributes are not purged from the database immediately, which means that the valid index range is not (always) continuous. This is why the APIERR_DELETED return code has to be handled.


Creating an attribute

The attribute creation process is also fairly simple. All you have to do is to fill the appropriate part of the API_Attribute, and optionally the API_AttributeDefExt structure. The ACAPI_Attribute_CreateExt function does the following:

  • It checks the data for possible inconsistency. If some problem is encountered it may be corrected automatically or an error code is generated.
  • It ignores for example, the index field in the header structure, you cannot influence which index the attribute should be referenced by. This value is automatically generated and returned to you.
  • If an attribute exists with the same name in the database, the existing index will be returned. The matching procedure ignores the differences of the attribute definition. Multiple attributes with the same name are not allowed.
  • The generated attribute is placed in the data structure and it can be referenced in any subsequent API call.

It is very important that ARCHICAD does not free any dynamic data structure you have allocated and passed to ARCHICAD. They must be freed by your code.

Another important note is the following. Every data structure filled by you must be initialized to zero, for forward compatibility. Fillers may become real data fields in the later versions of the API, so if they are not initialized to zero, the result may be unpredictable.

The template to create an attribute is the following:


API_Attribute       attrib;
API_AttributeDefsExt   defs;
short               ltypeIndex;
GSErrCode           err;

BNZeroMemory (&attrib, sizeof (API_Attribute));
BNZeroMemory (&defs, sizeof (API_AttributeDefsExt));

attrib.header.typeID = API_LinetypeID;
/* fill attrib.linetype */
/* fill defs for dashed and symbol line types */

err = ACAPI_Attribute_CreateExt (&attrib, &defs);
ltypeIndex = attrib.header.index;

ACAPI_DisposeAttrDefsHdlsExt (&defs);