Files
wwtools/aot/dev-guide/appendix-a-ref-guide.md
T
Joseph Doherty 32f26272ae Initial commit: Wonderware / System Platform tools and reference
Five tools under one repo, all docs organized per DOCS-GUIDE.md:

- aalogcli: .NET 4.8 / x86 CliFx CLI for reading System Platform binary
  logs (*.aaLGX) for LLM debugging, built on aaOpenSource/aaLog. Commands:
  last, tail, range, unread, fields. Stable JSON envelope under --llm-json.
  Build template under lib/build/ for rebuilding aaLogReader.dll.

- aot: ArchestrA Object Toolkit 2014 v4.0 reference material. Dev guide
  (Markdown converted from CHM), API reference for the ArchestrA.Toolkit
  namespace, and the Monitor / Watchdog VS sample solutions.

- graccesscli: .NET 4.8 / x86 CliFx CLI that automates Galaxy
  configuration via the ArchestrA GRAccess COM interop. Includes session
  daemon, IPC protocol, and llm-json envelope contract.

- grdb: SQL/DDL exploration of the Galaxy Repository database. DDL
  captures, reusable queries, hierarchy / contained-name <-> tag-name
  translation notes.

- histdb: LLM-oriented reference for AVEVA Historian retrieval. INSQL
  linked-server, extension tables, every wwXxx time-domain extension,
  every retrieval mode, alarm/event SQL recipes, REST API. Distilled
  from the 243-page Historian Retrieval Guide.

Root contains:
- CLAUDE.md: thin index pointing into each tool's README.
- DOCS-GUIDE.md: doctrine for organizing docs for LLM consumption.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:22:20 -04:00

38 KiB
Raw Blame History

Programming Techniques

Use the following workflow and programming techniques to code within the ArchestrA Object Toolkit (AOT).

Programming Workflow

Using the AOT, you can seamlessly modify the object shape as the object is coded. The AOT also supports changing the ArchestrA attribute data type and renaming ArchestrA attributes and child primitives. This functionality, referred to as round-tripping, has been implemented by configuring the object shape in code. The code is parsed at build time to form the objects aaDEF file that defines its shape.

Use the Object Designer to modify the the object shape code. The Designer parses the object shape from the code. Modifications made in the Object Designer are then written back to the code. The Object Designer also enables you to perform tasks that impact multiple code sections simultaneously, such as renaming ArchestrA attributes, adding local primitives, and making changes associated with modifying an objects major version.

The basic steps of the workflow are:

  1. Define the object shape using either the ArchestrA Object Toolkit Designer or in code directly.
  2. Code the Configtime.
  3. Code the Editor for the object.
  4. Code the Runtime.
  5. Build and import the object.
  6. Test and debug the object.

Note

We recommend that you define the object shape with the ArchestrA Object Toolkit Designer and use code only when necessary. Refer to Advanced Techniques for information on coding the shape of the object.

Configuring Internal and External Names

Internal names apply to objects, primitives, and attributes. Internal names are used in code and must be C# compliant.

Do not use .NET keywords, names of classes in the ArchestrA Object Toolkit, or names used in other libraries that are used in your code as internal names for objects, primitives, and attributes.

Internal names are used in code to refer to the primitive or attribute in C# through provided wrapper classes.

The maximum length of an objects internal name is 255 characters.

The external name is used in the ArchestrA IDE and can be used to create default names for object instances. Each name should be meaningful and suggest the meaning of the object, primitive, or attribute.

External names must be ArchestrA compliant and cannot have any of the following characters: (space) + - * / \ = ( ) ` ~ ! % ^ & @ [ ] { } | : ; " , < > ? "

Note

For the sake of brevity, do not use the word "Object" or "Template" in an object's name.

Providing Wrappers for Referencing ArchestrA Attributes

Attribute wrappers provide the following functionality for non-dynamic local attributes and non-virtual child primitive attributes:

  • Strongly typed attribute references
  • Automatic renaming of attribute references
  • IntelliSense

Note

Renaming an attribute property causes Visual Studio to rename all references to the attribute in code except for string based references. For example, renaming Attribute1 does not modify “GetValue(“Attribute1”)”.

Modifying an attribute internal name using the Object Designer renames the Attribute property (known also as the attribute wrapper).

Using the Object Designer to modify the child primitive internal name, that is, the fully scoped name of the referenced attribute, also renames the Attribute property.

Note

Wrappers are updated each time the solution is parsed, that is, when the Object Designer is opened, the object is built, the Object Design View is refreshed, or Code Validate is selected.

Config Time Coding

Use the following techniques to code for the Configtime project.

The Configtime project is used to provide all logic related to configuring the attributes of the object within the Galaxy database.

Config Time Set Handler

Use the config time set handler to implement any logic required for setting the value of an attribute at configuration time.

This logic could include, for example, range checking and adding or removing virtual primitives.

You can add a Configtime set handler to an attribute by adding a set handler delegate and associated method to the Configtime class.

The Configtime class template provides commented out examples of a set handler delegate and method.

The set handler registration and associated methods are not renamed when the attribute is renamed in code. To remove the set handler, comment out or delete the registration. The Set Handler method can exist without the set handler registration; however, the method is not called.

In the following examples Attribute1 represents the internal and external name of the attribute.

The Configtime set handler is triggered when an attribute is changed at configuration time. It can be used for validation or to trigger a special action such as adding virtual primitives.

For additional information, see Configuring Run Time Set Handlers.

Set Handler Code

Attribute1.SetHandlerValue enables the set handler code to appear the same for both array and non-array attributes. You can take more control of setting the value by using the following code examples:

  • Non-array attribute:
    Attribute1 = e.Value;

  • Array attributes:
    if (!e.IsArrayElement)
    {
    Attribute1 = e.Value;
    }
    else
    {
    Attribute1[e.attributeHandle.shIndex1] = e.Value;
    }

Performing Config Time Validation with the ConfigtimeValidate() Method

Use this method to validate the entire object as a whole when it is being saved. The method can put the object in a warning or error state by using EPACKAGESTATUS enum.

Example:

private void AOTObject4Configtime_ConfigtimeValidate(object sender, ref EPACKAGESTATUS status)
    {
        //  By default set the object status to Good
        if (HiLimit < LoLimit)
            {
                status = EPACKAGESTATUS.ePackageBad;
                AddErrorMessage("Hi Limit must be greater than or equal to Lo Limit");
            }
            else
            {
                status = EPACKAGESTATUS.ePackageGood;
            }
        }

Adding a Virtual Primitive at Config Time with AddPrimitive

You can test the ability to add an instance of a virtual primitive at config time using the following function (Boolean result):

bool CanAddPrimitive(string virtualPrimitiveName, string internalName, string externalName);

The following example uses CanAddPrimitive to check before adding a primitive:

if (CanAddPrimitive("c1", "MyCP1InternalName", "MyCP1ExternalName"))
{
AddPrimitive("c1", "MyCP1InternalName", "MyCP1ExternalName");
}

Where:

  • c1 is the internal name of the virtual primitive.
  • MyCP1InternalName is the internal name of the Primitive Instance.
  • MyCP1ExternalName is the external name of the primitive instance.

You can add an instance of a virtual primitive at config time and check the result using PrimitiveResult.message as shown in the following example:

private void Attribute1SetHandler(object sender, ref ConfigtimeSetHandlerEventArgs e)
{
Attribute1.SetHandlerValue = e;

if (e.Value)
{
if (!AddPrimitive("c1", "MyCP1InternalName", "MyCP1ExternalName"))
{
e.Message = PrimitiveResult.message;
return; // Add failed
}
}
}

Where:

  • c1 is the internal name of the virtual primitive
  • MyCP1InternalName is the internal name of the Primitive instance
  • MyCP1ExternalName is the external name of the Primitive instance
  • Attribute1 is a Boolean Attribute with a config time set handler.

Note

PrimitiveResult.message returns a message only on failure. To return status, use PrimitiveResult.status (EPRIMITIVEOPSTATUS).

Use to following example to iterate through the child primitives or child virtual primitives:

object primitives;
this.Site.ChildVirtualPrimitives(ThisPrimitive, out primitives);
foreach (IPrimitiveShape ips in (IEnumerable)primitives)
{
    LogInfo(ips.FullName);
}

Removing a Virtual Primitive at Config Time with DeletePrimitive

You can test the ability to delete an instance of a virtual primitive at config time using the following function (Boolean result):

bool CanDeletePrimitive(string internalName);

Note

CanDelete checks the lock status of the primitive being deleted.

Example:

if (CanDeletePrimitive("MyCP1InternalName"))
{
DeletePrimitive("MyCP1InternalName");
}

Where:

MyCP1InternalName is the primitive instance being deleted.

You can delete an instance of a virtual primitive at config time and check the result using PrimitiveResult.message as shown in the following example:

private void Attribute1SetHandler(object sender, ref ConfigtimeSetHandlerEventArgs e)
{
Attribute1.SetHandlerValue = e;

if (!e.Value)
{
if (!DeletePrimitive("MyCP1InternalName"))
{
e.Message = PrimitiveResult.message;
return; // Delete failed
}
}
}

Where:

  • c1 is the internal name of the virtual primitive.
  • MyCP1InternalName is the internal name of the Primitive instance.
  • MyCP1ExternalName is the external name of the primitive instance.
  • Attribute1 is a Boolean attribute with a config time set handler.

Note

PrimitiveResult.message only returns a message on failure. To return status use PrimitiveResult.status (EPRIMITIVEOPSTATUS).

Accessing Data in Attributes at Config Time

For static attributes, use attribute wrappers based on internal name to read/write value.

For dynamic attributes or attributes in a virtual primitive, use the GetValue and SetValue methods.

Examples:

If the static float attribute is named HiLimit:

float myVal;
myVal = HiLimit;

If the dynamic float attribute is named HiLimit:

float myVal;
myVal = GetValue(HiLimit);

Accessing Data in Other Primitives at Config Time

For static primitives, use primitives and attributes wrappers based on internal name to read/write value.

For attributes in a virtual primitive, use the GetValue and SetValue methods.

Examples:

To access a float attribute with an internal name of HiLimit, of a static child primitive with the internal name Limits:

float myVal;
myVal = Limits.HiLimit;

To access a float attribute with an external name of HiLimit, of an instance of a virtual child primitive with the external name Limits:

float myVal;
myVal = GetValue(Limits.HiLimit);

Adding and Deleting Dynamic Attributes at Config Time

Use the following code to add/remove a dynamic attribute.

bool status = AddAttribute("dynAttr1", MxAttributeCategory.MxCategoryCalculated, MxDataType.MxDouble, false);
DeleteAttribute("dynAttr1");

For more information on these methods, see the ArchestrA Object Toolkit Reference Guide.

Run Time Coding

Use the following techniques to code for run time. For more information on these methods, see the ArchestrA Object Toolkit Reference Guide.

Runtime SetHandler

Use a run time set handler to implement any logic required to set an attribute value at run time, including range checking and accepting or rejecting the set.

You can add a run time set handler to an attribute by adding a set handler delegate and associated method to the Runtime class.

The Runtime class template provides commented out examples of a set handler delegate and method.

The set handler registration and associated methods are not renamed when the attribute is renamed in code. To remove the set handler, comment out or delete the registration. The Set Handler method can exist without the set handler registration; however, the method is not called.

In the following examples Attribute1 represents the attribute internal and external name.

The run time set handler registration appears in the Runtime class in the following region:

#region Runtime Set Handler Registration - Toolkit generated code
#endregion Runtime Set Handler Registration

The run time Set Handler registration for Attribute1 appears as:

this.RegisterRuntimeSetHandler("Attribute1.ex", new RuntimeSetHandlerDelegate(Attribute1SetHandler));

Remarks

The delegate is registered to the external name of the Attribute. In this example, the text "Attribute1.ex" represents the external name for Attribute1.

The run time set handler method for Attribute1 appears at the end of the Runtime class as:

private void Attribute1SetHandler(object sender, ref RuntimeSetHandlerEventArgs e)
{
Attribute1.SetHandlerValue = e;
}

For additional information, see Configuring Run Time Set Handlers.

Set Handler Code

Attribute1.SetHandlerValue enables the set handler code to appear the same for both array and non-array Aattributes. You can take more control of setting the value by using the following code examples:

  • Non-array attribute:
    Attribute1 = e.Value;

  • Array attributes:
if (!e.IsArrayElement)
    {
    Attribute1 = e.Value;
    }
    else
    {
    Attribute1[e.attributeHandle.shIndex1] = e.Value;
    }

SetInfo Structure Event Arguments

Event arguments to provide the run time set handler event with the required data:

public class RuntimeSetHandlerEventArgs : SetHandlerEventArgs
{
    // an attribute to pass in the Set Info:
    SetInfo attributeInfo;
    
    // an attribute to pass out the status:
    MxStatus status;
    
    // Constructor
    RuntimeSetHandlerEventArgs(AttributeHandle pAttributeHandle, SetInfo pInfo, MxStatus _status, IMxValue pMxValue);
}

Coding a RuntimeExecute() Method

Use this method to get inputs, perform calculations, set outputs, and set alarm Booleans.

Note

This is the most important run time method, but it needs to be efficient and not time-consuming, or it could cause scan overruns.

Example:

If the object is called Test:

Test_RuntimeExecute()

Returning an Error Status String at Run Time

Use the RuntimeGetStatusDesc method to return an error message string associated with a previously returned error code from a sethandler.

Example:

private void xxx_RuntimeGetStatusDesc(object sender, ref RuntimeGetStatusDescEventArgs e)
    {
        //----------------------------------------------
        
        //  TODO: Runtime Event - GetStatusDesc
        //
        //  This routine provides a String for an
        //  error code when a client requests it.
        //  By default this method looks for an entry
        //  in the dictionary that has the
        //  DetailedErrorCode as the PhraseID.
        //
        //  You need to change this implmentation if
        //  you want to provide embedded values
        //  within your messages, or you want to use
        //  string PhraseIDs instead of integer
        //  PhraseIDs.
        //----------------------------------------------
        
        switch (e.detailedErrorCode)
        {
            default:
            e.status = GetText((int)e.detailedErrorCode);
            break;
        }
    }

RuntimeGetStatusDesc Event

Delegates added to this event are called when the event is fired by ArchestrA:

event RuntimeGetStatusDescDelegate RuntimeGetStatusDesc;

Event Handler for Get Status Description

Use the following to provide the GetStatusDescription event with the required data:

class RuntimeGetStatusDescEventArgs : EventArgs
{
    // an attribute to pass out the detailed error code:
    short detailedErrorCode;
    
    // an attribute to pass out the status:
    string status;
    
    // Constructor:
    RuntimeGetStatusDescEventArgs();
}

Manipulating Data Quality at Run Time

Use code to read data quality from and write data quality to attributes.

Example:

myAttribute = Input1.Value.Value;
myAttribute.Quality = Input1.Value.Quality;

if( myAttribute.Quality.isBad )
{
// then do something like set alarm
...
}

Manipulating the Timestamp at Run Time

Use code to read and write the time stamp at run time.

Example:

myAttribute = Input1.Value.Value;
myAttribute.Time = Input1.Value.Time;

Getting Input (I/O) Values Using Utility Primitives at Run Time

Use code to read input value, status and quality from Input or InputOutput utility primitives. Use wrapper classes if the utility primitive is static; otherwise, use GetValue.

Examples:

Input primitive:

myAttribute = Input1.Value.Value;
CMxStatus myStatus = Input1.ReadStatus;

InputOutput primitive:

myAttribute = InputOutput1.ReadValue;
CMxStatus myStatus = InputOutput1.ReadStatus;
myAttribute.Quality = InputOutput1.ReadValue.Quality;
myAttribute.Time = InputOutput1.ReadValue.Time;

Setting Output (I/O) Values Using Utility Primitives at Run Time

Code utility primitives to write output value and read status from Output or InputOutput Utility Primitive. Use wrapper classes if the Utility Primitive is static; otherwise, use SetValue.

Examples:

Output primitive:

Output1.Value = myValue;
Output1.Value.Time = myTime;

InputOutput primitive:

InputOutput1.WriteValue = myValue;
InputOutput1.WriteValue.Time = myTime;

Writing to the Quality of the Input, Output, or InputOutput primitive wrapper is not supported. The Quality of Value, WriteValue, and ReadValue is read-only. For example, attempting to set InputOutput1.WriteValue.Quality = SomeAttribute.Quality may result in an erroneous value (InputOutput1.WriteValue.Value) to be written to the output location.

Accessing Data in Attributes at Run Time

For static attributes, use attribute wrappers based on the internal name to read or write values, quality, and time stamps.

Example:

If attribute is called Attribute1, just use Attribute1 in code.

int i = Attribute1;

For dynamic attributes or attributes in a virtual primitive, use the GetValue and SetValue methods.

Example:

For virtuals and dynamics:

GetValue("attribute1");

or

GetValue( primitiveId, attributeId);

See the AObjectBase class definition for further details on the GetValue member.

Accessing Data in Other Primitives at Run Time

For static primitives, use primitives and attributes wrappers based on the internal name to read/write value, quality, and time stamp.

For attributes in a virtual primitive, use the GetValue and SetValue methods.

Examples:

prim1.attribute1 = 23.0; // for static primitives and attributes
int i = GetValue("prim1.attribute1");  // for dynamic primitives and attributes
SetValue("prim1.attribute1",23.0); // for dynamic primitives and attributes

Adding and Deleting Dynamic Attributes at Run Time

Use the following code to add/remove a dynamic attribute in run time code.

bool status = AddAttribute("dynAttr1", MxAttributeCategory.MxCategoryCalculated, MxDataType.MxDouble, false);
DeleteAttribute("dynAttr1");

Supporting AdviseOnlyActive at Run Time

Application Server can suspend the input polling required for an attribute when that attribute is not currently being used, such as when it is not being viewed by a client, alarmed, script-referenced, or historized. For more information on the AddAttribute methods and overloads, see the ArchestrA Object Toolkit Reference Guide.

The Advise Only Active feature of the run time infrastructure determes whether an attribute is currently being used or not, and can suspend and activate that attribute at the appropriate time.

The ApplicationObject must determine which attributes are eligible candidates to be suspended when not being used. The ApplicationObject must also turn off the input polling required for an attribute when suspended, and turn the input polling back on when the attribute is activated.

To enable AdviseOnlyActive:

  1. Determine whether or not the Object should support Advise Only Active functionality. If so, enable the Advise Only Active supported check box in the Object Editor.
  2. Determine for each primitive being developed what attributes are eligible for Advise Only Active functionality. These typically will only be attributes that are updated or associated with “live” updates from external sources, usually from input type primitives. They can also be subscriptions using MX.
  3. In either the code or the object editor, set “Advise Only Active” in the selected attributes to True.

Note

In the Runtime Startup method, the auto-generated code checks whether AdviseOnlyActiveEnabled is enabled for the object. If AdviseOnlyActiveEnabled is enabled , the auto-generated code calls SuspendLocalAttribute() for each attribute supporting Advise Only Active.

  1. Implement the body of the provided AttributeName_AdviseOnlyActive() method for each attribute supporting Advise Only Active: a. The method shell is auto-generated. b. Fill in code in this method to take necessary actions to activate or suspend updates of polled data related to the specified attribute being activated. Typically, an Input primitive or InputOutput primitive wrapper is called, such as:
        
        Input1.ActivateUpdatesList()
        
        InputOutput1.ActivateUpdatesList()
  1. You can also choose to take other actions, including: a. Activate/suspend updates on an attribute in another object using CMxIndirect.Activate() or CMxIndirect.Suspend(). b. Activate/suspend updates on an attribute in another primitive using the ActivatePrimitiveAttribute() or SuspendPrimitiveAttribute() methods.

Note

In Runtime Shutdown method, if AdviseOnlyActiveEnabled is enabled, the auto-generated code calls ActivateLocalAttribute() for each attribute supporting AdviseOnlyActive.

AdviseOnlyActiveEnabled

Use this method or property to determine whether the object has AdviseOnlyActive functionality enabled. If disabled, the object must not call functions to use AdviseOnlyActive. The AOT prevents functions such as SuspendLocalAttribute() from being used if AdviseOnlyActive functionality is disabled. This method or property determines if AdviseOnlyActive functionality is enabled.

Other AOT Wrappers for AdviseOnlyActive

In addition to the wrappers indicated in the previous section, the AOT adds the following wrapper function for AdviseOnlyActive.

IO Utilities

Input and InputOutput utility primitives class wrappers provide methods to SuspendUpdatesList() and ActivateUpdatesList() that suspend and activate the input polling for the utility primitive.

Triggering an Alarm at RunTime

Set the Boolean attribute representing the alarm to True to trigger the alarm. Set the attribute to False to clear the alarm condition.

Example:

myCondition = true;

Note

The Boolean attribute must have an alarm extension added to it in the Object Designer.

Providing Access to External Attributes (BindTo)

The BindTo method of RuntimeBase provides a simplified method for accessing attributes in other objects at run time using CMxIndirect. For more information, see CMxIndirect.

You can use BindTo to:

  • Read the value, time, and quality of an attribute or property.
  • Set the value and time of an attribute. Quality cannot be set.

The Value, Quality, Datatype, Length, and Time of the external attribute can be accessed by the properties:

myIndirect.Value
myIndirect.DataQualityOfLastRead
myIndirect.Value.GetDataType
myIndirect.Value.Length
myIndirect.TimeStampOfLastRead

Like value, time can be set across object boundaries. You can access time without having to access value, but you must do this by binding to the Time property directly.

Example:

myIndirect = RuntimeBase.BindTo( obj.attr.time, “”);
myIndirect.Value = DateTime.Now();
myTime = myIndirect.Value;     // where myTime is a System.DateTime variable

You can set both time and value together in one call:

myIndirect.Set( x,  myTime );

Value and time can be set together as a pair.

Example:

private CMxIndirect myIndirect = null;
.
.
.
myIndirect = BindTo("MyTestObject.Attribute1", "", true);
if (myIndirect != null )
{
myIndirect.Set( 180, DateTime.Now() );    // sets V, T in one call
}

The developer can get both Time and Value together in one call:

if (myindirect.StatusOfLastRead.success == -1 && myindirect.StatusOfLastRead.Category == MxStatusCategory.MxCategoryOk)
{
    myIndirect.Get( out x, out myTime, out myQuality );
}

After the BindTo operation, check the status before accessing the value as shown in the previous example.

Note

Declaring the CMxIndirect in the Runtime Declarations Section makes the indirect available to all methods in the Runtime, that is, to Startup and Execute.

CMxIndirect

Used for referencing external attributes. For more information, see Providing Access to External Attributes (BindTo).

public class CMxIndirect
{
public CMxIndirect(string _fullRefString, string _context, IMxSupervisoryConnection _superConn, RuntimeBase _rb, int _refHandle, short _statusId, int _statusIndex);

    public MxStatus CallBackStatus { get; }
    public string Context { get; }
    public short DataQuality { get; }
    public string FullReferenceString { get; }
    public bool IsGood { get; }
    public int RefHandle { get; }
    public MxStatus Status { get; }
    public short StatusId { get; }
    public int StatusIndex { get; }
    public CMxValue Value { get; set; }
    public CMxTime Time { get; set; }
    public void Set { CMxValue value, CMxTime time };
    public void Get { out CMxValue value, out CMxTime time, out short quality };
}

Associating an ArchestrA Editor Control with an Attribute in Code

Normally, ArchestrA editor controls are statically configured to point to a single attribute to be configured on the editor tab.

However, on occassion, and especially with virtual primitives, it is useful to dynamically bind the editor control to a particular attribute by setting the Attribute property of the control.

For example, with a text box control, the following shows how to set the attribute name in code:

aaTextBox1.Attribute = "myAttribute1";

Referencing Attributes Using GetValue and SetValue

The AOT enables the use of SetValue and GetValue to reference the following types of attributes:

  • Child primitive attributes
  • Dynamic attributes
  • Virtual primitive attributes

You can reference these attributes using SetValue and GetValue with a relative string reference. The string reference is relative to the primitive that contains the code, and can be prefixed with the following modifiers:

  • “me”
  • “myparent”
  • “myobject”

Note

The prefix “me” is implied when no prefix is provided.

The GetValue and SetValue methods use the primitive external name and attribute external name as shown in the following example:

GetValue(PrimitiveExternalName.AttributeExternalName)

Examples included in this section are based on the following hierarchy:

Local References

To reference any local attributes, use the attribute name with no prefixes or scope.

Using the me prefix explicitly sets the reference to local and can be used to make it clear what type of reference is required.

Either of the following statements in Child2 gets the value of AOTObjectx1.Child2.Attribute1:

GetValue("Attribute1");
GetValue("me.Attribute1");

Referencing Down (child)

To reference attributes of a child primitive, prefix the reference string with the name of the child primitives.

The following statement in Child2 gets the value of AOTObjectx1.Child2.Child4.Attribute1:

GetValue("Child4.Attribute1");

The following statement in AOTobjectx1 gets the value of AOTObjectx1.Child2.Child4.Attribute1:

GetValue("Child2.Child4.Attribute1");

Referencing Up (parent)

To reference attributes of a parent primitive use the myparent prefix.

The following statement in Child2 gets the value of AOTObjectx1.Attribute1:

GetValue("myparent.Attribute1");

The following statement in Child4 gets the value of AOTObjectx1.Child2.Attribute1

GetValue("myparent.Attribute1");

The myparent prefix cannot be used more than once in a reference. To reference attributes of objects or primitives more than one level higher, you must use myobject to locate the reference to the top of the hierarchy and then work relative to that location.

The following statement in Child4 gets the value of AOTObjectx1.Attribute1:

GetValue("myobject.Attribute1");

The following statement in Child4 gets the value of AOTObjectx1.Child1.Child3.Attribute1:

GetValue("myobject.Child1.Child3.Attribute1");

Array Usage

// Increment the 3rd element of an array
FloatArray1[3]++;
// Increment all the elements of an array
for (short counter = 1; counter <= FloatArray2.Length; counter++)
{
    FloatArray2[counter]++;
}

The External Build Process

The build process is made up of many stages. In general, these stages all occur as a single event.

Sometimes you may want to execute only part of the build process or to add additional events in the middle of the process. To support this, you can start a solution build from the command line as well as repackage the object with the Packager application.

Note

The project must be built before you execute the Packager, because the Packager requires the aaDEF file and associated assemblies create by the build.

Command Line Recompile Object

Perform these processes from a command prompt with the Visual Studio Environment variables loaded.

Build Process - Recompile (debug version)

C:\>devenv "C:\ Projects\AOTObject88\AOTObject88.sln" /build Debug

Build Process - Recompile (release version)

C:\>devenv "C:\ Projects\AOTObject88\AOTObject88.sln" /build Release

Command Line Repackage Object

The AOT includes a utility called Packager.

The Packager packages the object using the files created by the build, that is, it packages the aaDEF files and assemblies created by the build. This allows a build process to repackage the aaPDF after the object is rebuilt using the command line build.

You can start the Packager as a Windows Form application or execute it from the command line using the following switches:

/q - command line mode, no Form.

/f - The name of a text file containing information needed by DesignServer to repackage the Object.

The file is automatically generated in the Output directory when the AOT builds the object using the name DesignServerInfo.txt. It contains the name of the root aaDEF file and all of the paths to the core object dlls as relative paths, that is, the project is portable.

Example

C:\Program Files\ArchestrA\Toolkits\AOT\Bin>packager /q /f "C:\ Projects\AOTObject90\Output\designserverinfo.txt" /a "C:\Utility Dlls\"

Note

This feature allows you to modify the aaDEF file and repackage the Object.

Advanced Techniques

Use these techniques to configure an object or primitive completely in code using C# attributes. Using the integrated Object Desiger causes these C# attributes declarations to be automatically added to the code.

Configuring an ArchestrA Attribute in Code

You can add ArchestrA attributes to the object. They can be used locally in code as C# variables.

The ArchestrA attributes are declared in the object project as C# variables using a CMx Data Type.

When the object is parsed, properties are automatically added to the Runtime and Configtime class for each ArchestrA attribute defined in the Object class. Parsing occurs while:

  • Refreshing the AOT Object Design View
  • Opening the AOT Object Designer
  • Saving an object in the AOT Object Designer
  • Executing build or code validation

The attribute properties allow you to access ArchestrA attributes as though they were strongly typed C# values.

When you reference the ArchestrA attribute in code, the property provides a C# typed wrapper to the attribute using SetValue and GetValue access. The wrapper provides access to Quality, Time, Data Type, and Array Length.

The following table lists the data types and associated C# conversions.

ArchestrA Data Type C# Data Type
Boolean bool
Integer int
Float float
Double double
Time DateTime
Elapsed Time TimeSpan
String string
Big String string
Attribute Reference string
Custom Enumeration string array
DataType ArchestrA.Core.MxDataType
Custom Structure ArchestrA.Core.MxCustomStruct
MxStatus ArchestrA.Core.MxStatus
Variant CMxValue
InternalDumpLoadData ArchestrA.Core.MxCustomStruct (special)
InternalFailoverData ArchestrA.Core.MxCustomStruct (special)

Note

There is no direct conversion from an internationalized string to a C# type. The internationalized string can be represented as an internationalized string structure (string value, locale) or by setting the locale for the attribute, which then allows you to reference the attribute as a C# string.

The variable declaration can be decorated with C# attributes to enable the configuration of the following attribute properties (excluding special data types):

  • External Name
  • Category
  • Security
  • Calculated Quality and Time
  • Frequently Accessed
  • Alarm Extension
  • History Extension

Note

The special data types of CMxInternalDumpLoadData and CMxInternalFailoverData are created and maintained by the toolkit. These data types are not intended for general use. These ArchestrA attributes store data for recreating dynamic attributes and child primitive instances on dump/load and failover.

Specifying the ArchestrA Attribute Array Length

You can set and get the array length of an attribute array (static) at config time or run time using the following syntax:

Syntax

AttributeName.Length = n;
n  = AttributeName.Length;

Parameters

AttributeName

Represents the array attribute name.

n

Represents an integer value.

Remarks

You can set the array length of a dynamic attribute array at config time or run time using one of the following Get and Set methods:

n = GetNumElements("AttributeName");
n = GetNumElements(AttributeID, PrimitiveID);
SetNumElements("AttributeName", n);
SetNumElements(AttributeID, PrimitiveID, n);

Where, AttributeName is the array attribute name and n is an integer value.

You can apply the GetNumElements and SetNumElements methods to attributes. However, when you rename an attribute using the Object Designer, the attribute name referenced by these methods is not updated.

Referencing Attributes from the Editor of the Object

To reference attributes directly from the Editor Project of the object, you must implement the GetData() and SetData() methods provided by the framework.

Even if the config-time dynamic attribute is located on OnObject, you cannot use Editor functions SetData and GetData, and Runtime functions Set and Get, if the attribute reference contains an object name. For example, myTestAOT_001.myuda.

For more information, see Enabling Buffered Data for a Config-time Dynamic Attribute.

In the examples, Attribute1 is a float array with four elements, Attribute2 represents is a float.

Attribute Get Example:

//Get an Attribute value
float MyData2 = (float)Convert.ToDecimal(GetData("Attribute2"));

Attribute Set Example:

//Set an Attribute value
SetData("Attribute2", 9.0);

Array Attribute Get Example:

//Get a single value of an Array Attribute
float MyData = (float)Convert.ToDecimal(GetData("Attribute1[1]"));
//Get an Array Attribute
object[] MyArrayValues = new object[4];
MyArrayValues = (object[])GetData("Attribute1");

Array Attribute Set Example

//Set an Array Attribute using a locally declared array
object[] MyArrayValues = new object[4];
MyArrayValues[0] = 1.0;
MyArrayValues[1] = 1.1;
MyArrayValues[2] = 1.2;
MyArrayValues[3] = 1.3;
SetData("Attribute1", MyArrayValues);

Note

The array index is 1-based. There are no errors or warnings to indicate that a zero value has been passed to the array index from the editor of the object.

Local Attribute Wrappers

Based on the attribute category, AOT adds an Attribute property to the Configtime class or the Runtime class for each attribute declared in the Object class. You can use the local attribute wrapper to access attributes using the attributes name attribute_internalname.

The following code example represents an auto-generated Attribute property added to the Configtime or Runtime class for an attribute that supports read and write. In the example, the Set statement would be excluded if the attribute were read-only.

private CMxBoolean Attribute1
{
get { return InternalReferenceOnly.Attribute1; }
set { InternalReferenceOnly.Attribute1.Set(value); }
}

The get property provides access to the attribute wrapper and allows you to access the features of the wrapper, such as quality and security.

The set property is limited to setting the value. This is how the property is used when the attribute is on the left side of an assignment operator, for example, Attribute1 = 10. You can assign values using this short method. It provides type checking and automatic type conversion of the value.

The property does not provide any other set access to the wrapper.

The following table shows the relationship between the attribute category and the attribute properties Get and Set added to the Configtime and Runtime classes.

Attribute Category Configtime Class Runtime Class
PackageOnly Get and Set - -
PackageOnly_Lockable Get and Set - -
Constant Get Only Get Only
Writeable_C_Lockable Get and Set Get Only
Writeable_UC Get and Set Get and Set
Writeable_UC_Lockable Get and Set Get and Set
Writeable_USC Get and Set Get and Set
Writeable_USC_Lockable Get and Set Get and Set
Calculated - - Get and Set
Calculated_Retentive - - Get and Set
Writeable_S - - Get and Set
Writeable_U - - Get and Set
Writeable_US - - Get and Set
SystemInternal Unsupported Unsupported
SystemSetsOnly Unsupported Unsupported
SystemWriteable Unsupported Unsupported