# MxAccess API notes

Reverse-engineered from the shipped `ArchestrA.MxAccess.dll` (assembly version `3.2.0.0`, file at `C:\Program Files (x86)\ArchestrA\Framework\Bin\ArchestrA.MXAccess.dll`) plus its sibling type libraries `MXAccess.tlb` / `MXAccess20.tlb` / `MXAccess32.tlb`. AVEVA does not publish a single canonical online reference for this assembly, which is why this file exists.

The assembly is registered in the GAC at `C:\Windows\assembly\GAC_MSIL\ArchestrA.MxAccess\3.2.0.0__23106a86e706d0ae\`. Strong name: `PublicKeyToken=23106a86e706d0ae`.

## Threading model

`LMXProxyServerClass` is a COM proxy. **All calls — and the events the proxy fires — run on the apartment that called `Register`.** The CLI's `Program.Main` is `[STAThread]` for this reason; if you call into MxAccess from a non-STA thread you'll observe:

- `Register()` returns a handle but events never fire.
- `Write()` queues but `OnWriteComplete` never reaches your handler.

A deeper STA pump is unnecessary for one-shot CLI invocations because CliFx's `ICommand.ExecuteAsync` runs on the entry thread synchronously, and the COM marshaller pumps the calling apartment while waiting on `WaitOne`.

## Type catalog

The full public surface from reflection:

```text
class  LMXProxyServerClass    -- the entry point (newable)
class  LMXProxyServer         -- alias / synonym
iface  ILMXProxyServer        -- v1 method set (Register, AddItem, Advise, Write, WriteSecured, AuthenticateUser)
iface  ILMXProxyServer2       -- adds  ArchestrAUserToId
iface  ILMXProxyServer3       -- adds  AddItem2
iface  ILMXProxyServer4       -- adds  Write2, WriteSecured2, Suspend, Activate, AdviseSupervisory
iface  ILMXProxyServer5       -- adds  AddBufferedItem, SetBufferedUpdateInterval

iface  _ILMXProxyServerEvents          -- OnDataChange, OnWriteComplete, OperationComplete
iface  _ILMXProxyServerEvents2         -- OnBufferedDataChange

struct MxStatus              -- success:int16, category:MxStatusCategory, detectedBy:MxStatusSource, detail:int16
struct MXSTATUS_PROXY        -- same fields; passed to event handlers as an array
enum   MxStatusCategory      -- 10 values; see `mxa info`
enum   MxStatusSource        -- 7 values; "who detected this status"
enum   MxDataType            -- MxNoData / MxBoolean / MxInteger / MxFloat / MxDouble / MxString / MxTime / MxElapsedTime / MxReferenceType / MxStatusType / MxDataTypeEnum / MxSecurityClassificationEnum / MxDataQualityType / MxQualifiedEnum / MxQualifiedStruct / MxInternationalizedString / MxBigString / MxDataTypeEND / MxDataTypeUnknown
```

## Lifecycle methods

```csharp
int  Register(string clientName);           // returns hServer
void Unregister(int hServer);

int  AddItem(int hServer, string itemRef);  // returns hItem
int  AddItem2(int hServer, string itemRef, string itemContext);
int  AddBufferedItem(int hServer, string itemRef, string itemContext);
void RemoveItem(int hServer, int hItem);

void Advise(int hServer, int hItem);
void UnAdvise(int hServer, int hItem);
void AdviseSupervisory(int hServer, int hItem);    // higher-rate / mxsupv updates
void SetBufferedUpdateInterval(int hServer, int intervalMs);
```

`Suspend` / `Activate` toggle update delivery on a per-item basis without losing the AddItem handle.

## Write methods

```csharp
void Write   (int hServer, int hItem, object value, int userId);
void Write2  (int hServer, int hItem, object value, object timestamp, int userId);
void WriteSecured  (int hServer, int hItem, int currentUserId, int verifierUserId, object value);
void WriteSecured2 (int hServer, int hItem, int currentUserId, int verifierUserId, object value, object timestamp);
```

`userId = 0` is unauthenticated. For attributes with **Operate**, **Tune**, **Configure**, **View Only**, **Free Access**, **Secured Write**, or **Verified Write** classifications (see [`../../aot/dev-guide/appendix-e-security-classifications.md`](../../aot/dev-guide/appendix-e-security-classifications.md)):

- **Free Access** — `Write` succeeds with `userId = 0`.
- **Operate / Tune / Configure** — `Write` requires a real `userId` from `AuthenticateUser`.
- **Secured Write** — must call `WriteSecured` with the same user as both `currentUserId` and `verifierUserId` (or use `Write` after `AuthenticateUser` if Galaxy security allows).
- **Verified Write** — must call `WriteSecured` with two distinct authenticated user ids (operator + verifier).

## Authentication helpers

```csharp
int AuthenticateUser(int hServer, string verifyUser, string verifyUserPwd);
int ArchestrAUserToId(int hServer, string userIdGuid);
```

`AuthenticateUser` returns a non-zero user id when credentials match the Galaxy security configuration, or 0 on failure. `ArchestrAUserToId` resolves a Galaxy user GUID to its numeric id.

## Events

All events fire on the registering apartment. The CLI bridges them to a `ConcurrentQueue<MxUpdate>` plus an `AutoResetEvent` so command code uses `WaitForUpdate(predicate, timeout, out update)` rather than dealing with the COM event signature directly.

```csharp
event OnDataChange(int hServer, int hItem,
                   object value, int quality, object timestamp,
                   ref MXSTATUS_PROXY[] statuses);

event OnWriteComplete(int hServer, int hItem, ref MXSTATUS_PROXY[] statuses);

event OperationComplete(int hServer, int hItem, ref MXSTATUS_PROXY[] statuses);
                                              // fires on AddItem completion etc.

event OnBufferedDataChange(int hServer, int hItem, MxDataType dataType,
                           object value, object quality, object timestamp,
                           ref MXSTATUS_PROXY[] statuses);
                                              // only when AddBufferedItem was used
```

`timestamp` arrives as a Win32 `FILETIME` boxed inside an `object` (decimal/Int64-shaped). The CLI converts via `DateTime.FromFileTimeUtc(Convert.ToInt64(...))` and exposes it as a local-time `DateTime?`; if conversion fails the field is `null`.

`quality` on `OnDataChange` is the legacy 16-bit OPC quality value (e.g. `192 = 0xC0` for "Good"). The richer state lives in the `statuses[]` array, especially `Category` and `DetectedBy`.

## Status semantics

`MxStatusCategory` values, in roughly ascending severity:

| Category | Meaning |
| --- | --- |
| `MxCategoryOk`                  | Operation succeeded. |
| `MxCategoryPending`             | Operation accepted, working on it; not an error. |
| `MxCategoryWarning`             | Soft issue (e.g. value clamped); operation proceeded. |
| `MxCategoryCommunicationError`  | LMX/NMX / engine reach failure. |
| `MxCategoryConfigurationError`  | Reference unresolved, attribute missing, type mismatch. |
| `MxCategoryOperationalError`    | Object not OnScan, attribute read-only, etc. |
| `MxCategorySecurityError`       | Secured / Verified attribute and credentials insufficient. |
| `MxCategorySoftwareError`       | Bug in the LMX runtime — usually rare. |
| `MxCategoryOtherError`          | Catch-all. |
| `MxStatusCategoryUnknown`       | Couldn't classify. |

`MxStatusSource` tells you *who* set the category — useful when the same code (e.g. `MxCategoryConfigurationError`) can come from the requesting LMX (your client side) versus the responding automation object (the server side):

```
MxSourceRequestingLmx           - this CLI's local LMX
MxSourceRespondingLmx           - the LMX hosting the target
MxSourceRequestingNmx           - cross-node messaging on this side
MxSourceRespondingNmx           - cross-node messaging on the target side
MxSourceRequestingAutomationObject
MxSourceRespondingAutomationObject
MxSourceUnknown
```

A `statuses` array often has multiple entries — one per layer that touched the request. The CLI emits all of them so an agent can pinpoint which layer rejected the call.

## Buffered items

`AddBufferedItem` returns updates batched at `SetBufferedUpdateInterval` (milliseconds) intervals via `OnBufferedDataChange`. Useful for high-rate tags where you want time-bucketed snapshots instead of every tick. The CLI does not expose this surface yet — adding a `subscribe --buffered <ms>` option is straightforward.

## Type libraries

| File | Use |
| --- | --- |
| `MXAccess.tlb`     | v1 — minimal interface, legacy clients. |
| `MXAccess20.tlb`   | adds events. |
| `MXAccess32.tlb`   | full v3.x surface — what `ArchestrA.MxAccess.dll 3.2.0.0` projects. |

If you need to consume MxAccess from a different language (C++, Python via comtypes, etc.), import `MXAccess32.tlb` rather than the older versions — they expose subsets.

## What the CLI does not (yet) cover

- `Suspend` / `Activate` — easy to add as a sub-command.
- `AddItem2` with explicit context — the CLI passes a single tag reference; if your environment needs context (cross-galaxy, role-based) wrap it.
- `WriteSecured` / `WriteSecured2` — adding a `--verifier-id <int>` option to `WriteCommand` is the natural extension.
- `AdviseSupervisory` and `AddBufferedItem` — opt-in performance modes.
