valueType argument to specify what type of data caller wants to get and value argument where the caller should provide a buffer, and the function will write the result to. Table 1 shows type of buffer the caller should provide depending on the valueType for sdaiGetADBValue, and it works similarly for all get-functions. Note: with SDAI API it is impossible to check buffer type at compilation or execution time and this is responsibility of a caller to ensure that requested valueType is matching with the value argument, a mismatch will lead to unpredictable results. The Table 2 shows what valueType can be fulfilled depending on actual model data. If a get-function cannot get a value it will return 0, it may happen when model item is unset ($) or incompatible with requested valueType. To separate these cases you can use engiGetInstanceAttrType(BN), sdaiGetADBType and engiGetAggrType. On success get-function will return non-zero. More precisely, according to ISO 10303-24-2001 on success they return content of value argument (*value) for sdaiADB, sdaiAGGR, or sdaiINSTANCE or value argument itself for other types (it has no useful meaning for C#).

Table 1 – Required value buffer depending on valueType (on the example of sdaiGetADBValue but valid for all get-functions)

valueType               C/C++                                               C#

sdaiINTEGER             int_t val;                                          int_t val;
                        sdaiGetADBValue (ADB, sdaiINTEGER, &val);           ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiINTEGER, out val);

sdaiREAL or sdaiNUMBER  double val;                                         double val;
                        sdaiGetADBValue (ADB, sdaiREAL, &val);              ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiREAL, out val);

sdaiBOOLEAN             bool val;                                           bool val;
                        sdaiGetADBValue (ADB, sdaiBOOLEAN, &val);           ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiBOOLEAN, out val);

sdaiLOGICAL             const TCHAR* val;                                   string val;
                        sdaiGetADBValue (ADB, sdaiLOGICAL, &val);           ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiLOGICAL, out val);

sdaiENUM                const TCHAR* val;                                   string val;
                        sdaiGetADBValue (ADB, sdaiENUM, &val);              ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiENUM, out val);

sdaiBINARY              const TCHAR* val;                                   string val;
                        sdaiGetADBValue (ADB, sdaiBINARY, &val);            ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiBINARY, out val);

sdaiSTRING              const char* val;                                    string val;
                        sdaiGetADBValue (ADB, sdaiSTRING, &val);            ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiSTRING, out val);

sdaiUNICODE             const wchar_t* val;                                 string val;
                        sdaiGetADBValue (ADB, sdaiUNICODE, &val);           ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiSTRING, out val);

sdaiEXPRESSSTRING       const char* val;                                    string val;
                        sdaiGetADBValue (ADB, sdaiEXPRESSSTRING, &val);     ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiEXPRESSSTRING, out val);

sdaiINSTANCE            SdaiInstance val;                                   int_t val;
                        sdaiGetADBValue (ADB, sdaiINSTANCE, &val);          ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiINSTANCE, out val);

sdaiAGGR                SdaiAggr aggr;                                      int_t aggr;
                        sdaiGetADBValue (ADB, sdaiAGGR, &aggr);             ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiINSTANCE, out aggr);

sdaiADB                 SdaiADB adb = sdaiCreateEmptyADB();                 int_t adb = 0;  //  it is important to initialize
                        sdaiGetADBValue (ADB, sdaiADB, adb);                ifcengine.sdaiGetADBValue (ADB, ifcengine.sdaiADB, out adb);        
                        sdaiDeleteADB (adb);

                        SdaiADB adb = nullptr;  //  it is important to initialize
                        sdaiGetADBValue (ADB, sdaiADB, &adb);
TCHAR is “char” or “wchar_t” depending on setStringUnicode. (Non-standard behavior) sdaiLOGICAL behaves differently from ISO 10303-24-2001: it expects char* while standard declares int_t (Non-standard extension) sdiADB in C++ has an option to work without sdaiCreateEmptyADB and sdaiDeleteADB as shown in the table
Table 2 - valueType can be requested depending on actual model data.

valueType       Works for following values in the model
                  integer      real     .T. or .F.     .U.      other enum    binary      string     instance      list      $ (empty)
sdaiINTEGER         Yes         Yes *        .           .           .           .           .           .           .           .
sdaiREAL            Yes         Yes          .           .           .           .           .           .           .           .
sdaiNUMBER          Yes         Yes          .           .           .           .           .           .           .           .
sdaiBOOLEAN          .           .          Yes          .           .           .           .           .           .           .
sdaiLOGICAL          .           .          Yes         Yes          .           .           .           .           .           .
sdaiENUM             .           .          Yes         Yes         Yes          .           .           .           .           .
sdaiBINARY           .           .           .           .           .          Yes          .           .           .           .
sdaiSTRING          Yes         Yes         Yes         Yes         Yes         Yes         Yes          .           .           .
sdaiUNICODE         Yes         Yes         Yes         Yes         Yes         Yes         Yes          .           .           .
sdaiEXPRESSSTRING   Yes         Yes         Yes         Yes         Yes         Yes         Yes          .           .           .
sdaiINSTANCE         .           .           .           .           .           .           .          Yes          .           .
sdaiAGGR             .           .           .           .           .           .           .           .          Yes          .
sdaiADB             Yes         Yes         Yes         Yes         Yes         Yes         Yes         Yes         Yes          .
Note: sdaiGetAttr, stdaiGetAttrBN, engiGetElement will success with any model data, except non-set($) (Non-standard extensions) sdaiGetADBValue: sdaiADB is allowed and will success when sdaiGetADBTypePath is not NULL, returning ABD value has type path element removed.


public const string ifcenginedll = @"ifcengine.dll";

[DllImport(IFCEngineDLL, EntryPoint = "sdaiGetADBValue")]
public static extern Int32 sdaiGetADBValue(int_t ADB, int_t valueType, out bool value);

[DllImport(IFCEngineDLL, EntryPoint = "sdaiGetADBValue")]
public static extern Int32 sdaiGetADBValue(int_t ADB, int_t valueType, out int_t value);

[DllImport(IFCEngineDLL, EntryPoint = "sdaiGetADBValue")]
public static extern Int32 sdaiGetADBValue(int_t ADB, int_t valueType, out double value);

[DllImport(IFCEngineDLL, EntryPoint = "sdaiGetADBValue")]
public static extern Int32 sdaiGetADBValue(int_t ADB, int_t valueType, out IntPtr value);

public static Int32 sdaiGetADBValue(int_t ADB, int_t valueType, out string value)
            value = null;
            valueType = getStringType(valueType);
            if (valueType != 0)
                IntPtr ptr = IntPtr.Zero;
                var ret = sdaiGetADBValue(ADB, valueType, out ptr);
                if (ret != 0 && ptr != IntPtr.Zero)
                    value = marshalPtrToString(valueType, ptr);
                    return ret;
            return 0;

Property ADB

Size: 32 bit / 4 byte (reference)

Property valueType

Size: 32 bit / 4 byte (value)

Property value

Size: 32 bit / 4 byte (reference)

Example (based on pure API calls)

Here you can find code snippits that show how the API call sdaiGetADBValue can be used.

using RDF;      //  include at least engine.cs within your solution

//  ENTITY IfcProperty;
//      Name                     : IfcIdentifier;
//      Description              : OPTIONAL IfcText;
//      PropertyForDependance    : SET OF IfcPropertyDependencyRelationship FOR DependingProperty;
//      PropertyDependsOn        : SET OF IfcPropertyDependencyRelationship FOR DependantProperty;
//      PartOfComplex            : SET [0:1] OF IfcComplexProperty FOR HasProperties;
//  ENTITY IfcSimpleProperty;
//  ENTITY IfcPropertySingleValue;
//      NominalValue             : OPTIONAL IfcValue;
//      Unit                     : OPTIONAL IfcUnit;
void GetIfcPropertySingleValue(Int64 model, Int64 ifcPropertySingleValue)
    //  for example:
    //    #31313 = IFCPROPERTYSINGLEVALUE('Category',$,IFCLABEL('Rooms'),$);
    IntPtr namePtr = IntPtr.Zero,
           descriptionPtr = IntPtr.Zero,
           nominalValuePtr = IntPtr.Zero,
           typePathPtr = IntPtr.Zero,
           unitPtr = IntPtr.Zero;
    Int64 nominalValueADB = 0;

    IfcEngine.x64.sdaiGetAttrBN(ifcPropertySingleValue, System.Text.Encoding.UTF8.GetBytes("Name"), IfcEngine.x64.sdaiUNICODE, out namePtr);                   //  name = 'Category'
    IfcEngine.x64.sdaiGetAttrBN(ifcPropertySingleValue, System.Text.Encoding.UTF8.GetBytes("Description"), IfcEngine.x64.sdaiUNICODE, out descriptionPtr);     //  description = 0

    IfcEngine.x64.sdaiGetAttrBN(ifcPropertySingleValue, System.Text.Encoding.UTF8.GetBytes("NominalValue"), IfcEngine.x64.sdaiADB, out nominalValueADB);
    IfcEngine.x64.sdaiGetADBTypePath(nominalValueADB, 0, out typePathPtr);                                  //  typePath = 'IFCLABEL'
    string typePath = Marshal.PtrToStringAnsi(typePathPtr);
    switch  (IfcEngine.x64.sdaiGetADBType(nominalValueADB)) {
        case  IfcEngine.x64.sdaiSTRING:
            IfcEngine.x64.sdaiGetADBValue(nominalValueADB, IfcEngine.x64.sdaiUNICODE, out nominalValuePtr);
            string nominalValue = Marshal.PtrToStringUni(nominalValuePtr);                                  //  nominalValue = 'Rooms'



    IfcEngine.x64.sdaiGetAttrBN(ifcPropertySingleValue, System.Text.Encoding.UTF8.GetBytes("Unit"), IfcEngine.x64.sdaiUNICODE, out unitPtr);                   //  unit = 0