API Conventions

Type Definitions

The file A3DSDKTypes.h provides essential fixed-size numeric types used throughout the API:



Standard Type Equivalent


Boolean descriptor. Can be A3D_TRUE or A3D_FALSE



Unsigned integer type with width of exactly 8 bits

unsigned char


Signed integer type with width of exactly 8 bits



Unsigned integer type with width of exactly 16 bits

unsigned short


Signed integer type with width of exactly 16 bits



Signed integer type with width of exactly 32 bits

implementation dependent


Unsigned integer type with width of exactly 32 bits

implementation dependent


IEEE 754 64-bits floating-point number



IEEE 754 32-bits floating-point number



Void type Void type



Void pointer type type Void pointer type type



UTF-8 character type



The HOOPS Exchange architecture is closely tied to its naming design. Most data in your HOOPS application are manipulated through entities, such as PRC, features, or BIM entities. Each entity type consists of:

  • An enumerator value within A3DEEntityType used for identification.

  • A handle type that uniquely identifies the entity within HOOPS.

  • Optionally, a data structure for retrieving or editing the entity’s state.

Additionally, the API may provide CRUD-like functions for each entity type to manipulate its content. Not all entity types offer all functions, depending on relevance and indirect operations.

The following table illustrates the strict naming convention used for an entity type with some examples:

Model File

BIM Data


Topo Body

Handle Type



























Querying the Entity Type of a Handle

When you have an entity handle and need to determine its underlying type, use A3DEntityGetType and match the result to A3DEEntityType. For example, to check if pHandle is a model file:

A3DEEntityType eType = kA3DTypeUnknown;
A3DEntityGetType(pHandle, &eType);
assert(eType == kA3DTypeAsmModelFile);

Retrieving the Data of an Entity

The most common operation on an entity is retrieving its data for reading. This involves initializing the data structure, retrieving the entity data, and disposing of the data structure when no longer needed. Here’s an example function that retrieves and prints the number of children product occurrences:

void PrintChildrenPO(const A3DAsmProductOccurrence* pHandle)
  A3DAsmProductOccurrenceData sData;
  A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sData);
  A3DAsmProductOccurrenceGet(pHandle, &sData);

  printf("Number of children: %d\n", pData->m_uiPOccurrencesSize);

  A3DAsmProductOccurrenceGet(0, &sData);

Let’s detail this code line by line. To initialize a data structure, declare it as a non-const variable use the A3D_INITIALIZE_DATA macro:

A3DAsmProductOccurrenceData sData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sData); // don't use &

Once the structure is initialized, use the Get function to retrieve the data. In the following line, pHandle is of type const A3DAsmProductOccurrence*.

A3DAsmProductOccurrenceGet(pHandle, &sData);

Then, when the data is not needed anymore, give the data back to the API by calling the same function. Set the handle parameter to 0.

A3DAsmProductOccurrenceGet(0, &sData);


Why disposing the data structure?

HOOPS Exchange structures may contains heap allocated data such as arrays and strings. It is essentials to remain memory consistent by letting the API releasing it. See the section about memory management for more.

Arrays as struct Fields

Lists in HOOPS Exchange offer access to different data fields, like product occurrences in a model file or representation items in an A3DRiSet. To work with these lists, HOOPS Exchange uses standard C sequential array types. Each array is composed of two parts: an A3DUns32 field to store the array’s size and a pointer to the array itself.

typedef struct {
    // ...
    A3DUns32 m_uiPOccurrencesSize;
    A3DAsmProductOccurrences** m_ppOccurrences;
    // ...
} A3DAsmModelFile;

Some array size specifiers can describe multiple arrays, illustrating their close relationship.

Entity Hierarchy

The HOOPS architecture incorporates an abstraction and specialization mechanism for its entities. For instance, all entities can be abstracted as an A3DEntity type, while the majority of entities are specializations of A3DRootBase. In practical terms, this means that when an entity can be abstracted into another type, it can be safely manipulated as the abstract type..

Certain abstract types also have their own data structures. For example, any product occurrence represented as an A3DAsmProductOccurrence is also considered a root base entity, specifically an A3DRootBase. Therefore, the code remains valid even if pHandle is an instance of A3DAsmProductOccurrence*.

A3DRootBaseData sData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sData);
A3DRootBaseGet(pHandle, &sData);

Conversely, it’s possible to pass a handle of type A3DRootBase* to a function that anticipates an A3DAsmProductOccurrence*. In such cases, the responsibility falls upon the caller to ensure the entity’s correct type. For instance, this example verifies the type of pHandle before passing it to the PrintChildrenPO function, as shown in the previous example.

A3DEEntityType eType = kA3DTypeUnknown;
A3DEntityGetType(pHandle, &eType);

if (eType == kA3DTypeAsmProductOccurrence) {

Any API call using an unexpected entity type will return A3D_INVALID_ENTITY_TYPE.


Because it’s similar to but not exactly like object-oriented programming (OOP), the way entities are organized can be something confusing. Another way to understand the relationship between entity types is to think of HOOPS Exchange as a database. For instance, in this example, the term “pHandle” would be like a key that exists in both the “ProductOccurrence” and “A3DRootBase” tables.

Structural Hierarchy

Many complex structures in HOOPS Exchange are organized like trees. For instance, the PRC tree contains all the parts that make up a model file. And the Feature tree arranges all the steps a CAD application takes to create the final part. Within these structures, one entity instance can be the “parent” of one or more other entities.

Although there’s no direct connection between the structural and type hierarchies, it’s worth noting that entities in the same tree usually belong to the same entity type. For example, entities in a PRC tree can be things like A3DAsmProductOccurrence, A3DRiRepresentationItem, or A3DRiPart (and others), but they’re all types of A3DRootBase.

Memory Management

Since HOOPS Exchange is a C API, you need to explicitly free any memory that’s allocated during runtime after you’re done using it. Many functions and data structures provide such memory, but it’s up to your application to decide when to release it.

One common scenario for memory cleanup is when you’re retrieving entity data, as shown in the example for entity data retrieval. If the Get function allocates memory, it’s important to note that these memory blocks are specific to that particular function call. For example, in the following case, sData0.m_pcName and sData1.m_pcName point to different memory locations, even though they belong to the same entity. This happens because the Name of a root base is copied into the A3DRootBaseData parameter internally.

A3DRootBaseData sData0, sData1;

A3DRootBaseGet(pHandle, &sData0);

A3DRootBaseGet(pHandle, &sData1);
assert(sData0.m_pcName != sData1.m_pcName);

After you’ve finished using the code, you need to return both sData0 and sData1 to the library so that it can properly clean up the allocated memory. You can do this by making another call to A3DRootBaseGet with 0 as the handle.

A3DRootBaseGet(0, &sData1);
A3DRootBaseGet(0, &sData0);


Even if a data structure currently doesn’t use dynamically allocated memory, it might in future API versions. To ensure your code remains robust and avoids tricky memory leaks due to changes, it’s a good practice to always clean up your data structures, regardless of their type.

Certain functions also provide dynamically allocated memory using “out parameters” In these cases, you can find details on how to release that memory in the function’s documentation.

Providing the Memory Functions

If you want to control how memory is allocated within HOOPS API functions, you can set your own allocation and deallocation functions:

A3DPtr CustomAlloc(size_t uiSize)
  return malloc(uiSize);

A3DVoid CustomFree(A3DPtr pBlock) {

A3DDllSetCallbacksMemory(CustomAlloc, CustomFree);

A3DDllSetCallbacksMemory must be called before A3DDllInitialize.

Deleting Entities

Deleting an entity itself isn’t a common operation in HOOPS Exchange, but some entity types do offer a delete function.

When you use A3DModelFileDelete() on a model file entity, it gets entirely removed. This action includes all the A3DRootBase entities that make up the PRC structure. Most of the time, this is the only delete function you need.

The more general-purpose A3DEntityDelete() function can be used to delete a specific entity. It removes the entity itself and any child entities in the case of an A3DRootBase. It’s important to note that this function doesn’t check whether the given entity exists somewhere in the PRC tree.

Some specific entities provide their own Delete() function:

  • A3DFaceUVPointInsideManagerDelete

  • A3DFileContextDelete

  • A3DMiscCascadedAttributesDelete

  • A3DMkpRTFDelete

  • A3DMkpRTFFieldDelete

  • A3DProjectPointCloudManagerDelete

Garbage Collection

When you shut down the library, the HOOPS context takes care of releasing any remaining memory blocks. This includes internal buffers and unlinked entities.

Error Management

HOOPS manages errors by returning a status code from all its functions. If a function completes without errors, it returns the value A3D_SUCCESS (which is 0). Any non-zero value indicates an error.

You can find a comprehensive list of error codes in the A3DStatus enumeration within the A3DSDKErrorCodes.h file.

It’s important to note that the same error code might have different meanings depending on the function that returns it. For detailed information about a value returned by a specific function call, consult the documentation of that function.

A3DMiscGetErrorMsg() can be used to obtain a description of the error code:

// ...
A3DStatus iStatus = A3DAsmModelFileLoadFromFile(pcPath, &sLoadData, &pHandle);

if (iStatus) {
  fprintf(stderr, "Cannot load model file: '%s'\n", A3DMiscGetErrorMsg(iStatus));

String Encoding

HOOPS uses standard C-Strings for handling text, which are in-memory arrays of characters with a null-termination character (0).

When dealing with character data, HOOPS Exchange adopts UTF-8 encoding. Therefore, any function or structure that needs strings as input must ensure proper conversion to UTF-8 before use. The API offers utility functions for these conversions:

  • A3DMiscUTF16ToUTF8

  • A3DMiscUTF8ToUTF16

  • A3DMiscUTF8ToUnicode

  • A3DMiscUnicodeToUTF8

Code Conventions

HOOPS Exchange is a C API, which means any source code, including our headers, is assured to compile with a C or C++ compliant compiler. To get detailed information about the compiler requirements, you can refer to the platform requirements page.

Header Files

All the header files can be found directly under the include/ folder of your HOOPS installation. These files are named using PascalCase and have one of the following prefixes:

  • A3DSDK for most of our SDK.

  • A3DPDF for files specific to the HOOPS Publish SDK.

  • A3DCommon for code that is common to both APIs.

The only exception is hoops_license.h. This file should be replaced with the one typically obtained from the license file generator.

All our header files contain only the declarations and inclusions they need for compilation. They are also designed to be self-sufficient, meaning they don’t depend on the inclusion context to work correctly, as long as the #include directive is at the global scope.

To compile a source file using HOOPS declarations, you only need to include the relevant header file that contains the declaration you require. For example, including A3DSDKStructure.h is sufficient to compile a source code that uses the A3DAsmModelFileData structure.

If you want to include all API header files in one go, you can use the convenience header A3DSDKIncludes.h. This file is also included within A3DSDKLoader.h to ensure that all functions are loaded correctly during initialization.

Naming Conventions

The API follows certain naming conventions:

  • Symbol names are in PascalCase, with the exception of macro definitions and A3DStatus values, which use CAPITAL_CASE.

  • Variables, formal parameters, and struct members use a naming convention known as Systems Hungarian Notation:

    • Struct members begin with m_, followed by:

    • p for pointer type, and then

    • A prefix based on the data type:

      • b for A3DBool

      • i for A3DInt8, A3DInt16, and A3DInt32

      • ui for A3DUns8, A3DUns16, and A3DUns32

      • f and d for A3DFloat and A3DDouble, respectively

      • c for A3DUTF8Char

      • e for enumerations

      • s for structures


All data types and functions are organized using a series of prefixes.

The primary prefix is always A3D, and it’s followed by additional prefixes to create sub-namespaces for functions and related symbols.

For example, A3DTess3DCreate() and A3DTessMarkupCreate() share the same base name but belong to different sub-namespaces, namely Tess3D and TessMarkup, respectively.

Associated symbols also follow the same naming pattern: