Overview
WinCC Professional and WinCC Runtime Advanced (TIA Portal) expose the entire PLC tag namespace to VBScript through the SmartTags object. When the underlying tag is a structured PLC data type (UDT / DB of type STRUCT) and that structure is part of an array, the string passed to SmartTags() must follow a strict delimiter rule: no whitespace is allowed between the tag prefix, the bracket block, the dot operator, and the member name. A single space inside the resolved string is enough to make WinCC return runtime error 14h / "Invalid procedure call or argument" or "Tag not found".
This reference documents the exact syntax, the supported iteration pattern, the WinCC versions where it applies, the configuration prerequisites on the PLC side, and a verification procedure that catches the failure before going to production.
Tags(), HMIRuntime) and does not use SmartTags.Problem Definition: SmartTags Struct Array Access Failure
A standard WinCC HMI tag is bound to a PLC tag of type ARRAY[0..n] OF "UDT_Segment" where UDT_Segment contains at least the Boolean field IsEnabled. The following naive VBScript returns a runtime error when i = 0 and silently returns wrong values (or Empty) at other indices:
' ❌ INCORRECT - spaces are tolerated by the editor but rejected by the runtime parser
Dim bValue
bValue = SmartTags("WorkingData.Segment [" & i &"] . IsEnabled")
The same tag accessed with a hard-coded index works, which proves the binding, the PLC datatype, and the HMI tag are configured correctly:
' ✔ Works, but cannot be parameterized
Dim bValue
bValue = SmartTags("WorkingData.Segment[0].IsEnabled")
The discrepancy is the whitespace introduced by the string concatenation. The WinCC tag resolver performs a strict string match against the tag name collected from the configured connections; any inserted space (" ", tab, line break) causes the lookup to fail because the configured tag name in the project tree never contains spaces around the brackets or the dot.
Root Cause: WinCC Tag Name String Parsing Rules
When the HMI engineering station generates the tag database from the PLC, the qualified name of a struct-member-array element is built from the concatenation:
<DB name>.<STRUCT name>[<index>].<MEMBER name>
The parser tokenises on:
- the dot character
.— only ONE dot character between identifiers, no leading or trailing dot - square brackets
[and]— must be adjacent to the identifier (no space before the open bracket, no space after the close bracket) - no whitespace anywhere in the resolved string
The variant in the question that failed — SmartTags("WorkingData.Segment [" & i &"] . IsEnabled") — produces the literal string WorkingData.Segment [0] . IsEnabled after concatenation. WinCC cannot find a tag whose name contains "Segment [0]" with surrounding spaces and therefore throws the lookup error.
Correct VBScript Syntax for Struct Array Access
The accepted form removes every space that does not belong to an identifier. Brackets, dots, and the dynamic index are concatenated directly to the surrounding strings:
' ✔ CORRECT - no whitespace adjacent to brackets or dots
Dim i, bValue
i = 3
bValue = SmartTags("WorkingData.Segment[" & i & "].IsEnabled")
' ✔ Equivalent using a local variable for the tag prefix
Dim sTag, sPrefix
sPrefix = "WorkingData.Segment["
sTag = sPrefix & i & "].IsEnabled"
bValue = SmartTags(sTag)
For multi-character member names the same rule applies:
SmartTags("RecipeData.Ingredients[" & idx & "].ConcentrationPct")
SmartTags("AxisData.Position[" & axisNo & "].Actual_mm")
If a string variable is assembled from user input, validate it against the configured array bounds before calling SmartTags — the runtime does not bounds-check, and an out-of-range index will raise Error 424h ("Object required") rather than Nothing:
If idx >= 0 And idx <= UBound_Segment Then
bValue = SmartTags("WorkingData.Segment[" & idx & "].IsEnabled")
End If
Iterating Struct Arrays in a For Loop
The canonical pattern is a For loop with the array lower/upper bound read once into local variables. Two boundary strategies are common:
- Hard-coded bounds (preferred for fixed-size recipe / segment arrays)
- Dynamic bounds read from a separate configuration tag (preferred when the array is resized at runtime)
' Strategy 1: fixed array [0..9] of UDT_Segment
Dim i, bEnabled, sName
For i = 0 To 9
bEnabled = SmartTags("WorkingData.Segment[" & i & "].IsEnabled")
If bEnabled = True Then
sName = SmartTags("WorkingData.Segment[" & i & "].Label")
' ... process element i ...
End If
Next
' Strategy 2: dynamic bounds
Dim iLow, iHigh, k
iLow = SmartTags("WorkingData.LoIndex")
iHigh = SmartTags("WorkingData.HiIndex")
For k = iLow To iHigh
SmartTags("WorkingData.Segment[" & k & "].Processed") = True
Next
SmartTags() call performs a tag database lookup; the cost of string concatenation is negligible, but the lookup is not. For very large arrays (1000+ elements) batch through a configured raw byte buffer or use SmartTags("MyArray") as a Variant() and read UBound from the returned array.Reading the Whole Array as a Variant
If the HMI connection supports array-of-struct read, a single call returns the entire array:
Dim vArray, i
vArray = SmartTags("WorkingData.Segment")
' vArray is a VBScript array of Variants; each element is a Dictionary-like
' object (or a struct wrapper) whose members can be read with member access.
For i = LBound(vArray) To UBound(vArray)
If vArray(i).IsEnabled = True Then
Trace "Element " & i & " label = " & vArray(i).Label
End If
Next
Array-of-struct read is supported on S7-1200/1500 connections in WinCC Professional V14+ and on PC Runtime with the appropriate HMI tag configuration. See the TIA Portal Help on "Reading array tags" and "Structured data types".
Multi-Dimensional and Nested Struct Arrays
For a 2-D array, brackets chain with no spaces:
SmartTags("Matrix[" & row & "][" & col & "].Value")
SmartTags("Grid[" & x & "," & y & "].State") ' also valid
For nested UDTs (a UDT that contains another UDT as a member), the dot chain extends naturally and every dot must be free of whitespace:
SmartTags("JobData.Header[" & i & "].Operator.Name")
SmartTags("JobData.Header[" & i & "].Operator.Role")
Maximum nesting depth in WinCC is platform-dependent:
| Runtime | Max UDT nesting | Max array rank |
|---|---|---|
| WinCC RT Advanced (Comfort Panel) | 6 levels | 6 dimensions |
| WinCC RT Professional (PC) | 8 levels | 6 dimensions |
| WinCC Unified (V17+) | 8 levels (JS API) | 6 dimensions |
PLC Data Type (UDT) Configuration Requirements
Before the HMI can address a struct-array element, the PLC project must expose a data block whose declaration matches the WinCC tag binding. The minimum S7-1500 declaration for the example:
TYPE UDT_Segment
STRUCT
IsEnabled : Bool;
Label : String[32];
Processed : Bool;
END_STRUCT;
END_TYPE
DATA_BLOCK WorkingData
STRUCT
Segment : ARRAY[0..9] OF UDT_Segment;
LoIndex : Int;
HiIndex : Int;
END_STRUCT;
BEGIN
END_DATA_BLOCK
On the HMI side, configure the connection to "HMI tags of the S7-1500". Add a tag named WorkingData of data type Struct with sub-tags Segment[0..9] (also Struct) and members IsEnabled (Bool), Label (WString), Processed (Bool). The HMI tag browser must show the fully qualified name WorkingData.Segment[0].IsEnabled — if the dot is missing, the PLC connection was not rebuilt after the UDT changed.
Common configuration mistakes that look like the same error
- The DB is non-optimised on S7-300/400 but the connection expects symbolic names (or vice-versa for S7-1200/1500, which require optimised block access).
- The HMI connection is configured for "absolute addressing" while the script uses the symbolic name.
- The UDT was modified in STEP 7 but the HMI was not recompiled — the tag browser shows stale members.
- "Permit access with PUT/GET communication" is disabled on the S7-1200/1500 CPU properties, blocking the HMI from reading the array.
Common Error Patterns and Anti-Patterns
| Pattern | Result | Why |
|---|---|---|
"Segment [" & i & "]" |
Error | Spaces around brackets |
"Segment[" & i & "]. IsEnabled" |
Error | Space after dot |
"Segment(" & i & ")" |
Error | Round brackets, not square |
"segment[" & i & "].isenabled" |
Error | Case mismatch on S7-1500 (case-sensitive) |
"Segment[" & i & "]." & sMem |
Error if sMem is empty | Trailing dot fails the parser |
"Segment[" & i & "].IsEnabled" |
OK | Reference implementation |
WinCC Version Compatibility Matrix
| TIA Portal | WinCC Script | SmartTags struct-array support | Notes |
|---|---|---|---|
| V13 / V13 SP1 | VBScript | Yes | Original behaviour, struct-array access via dot+bracket |
| V14 / V14 SP1 | VBScript | Yes | Optimised block access required for S7-1500 |
| V15 / V15.1 | VBScript | Yes | Performance improvement for array read |
| V16 | VBScript + JS (Unified) | Yes (Classic) / separate API (Unified) | First Unified release |
| V17 | VBScript + JS | Yes | Unified ODK improvements |
| V18 | VBScript + JS | Yes | Last VBScript-centric release line |
For projects on WinCC Unified (Comfort panels v18+ and Unified PC Runtime), switch to the Tags() / HMIRuntime JavaScript API; SmartTags is not available in Unified.
Verification and Testing Procedure
- Open the HMI tag browser in TIA Portal and confirm the fully qualified name
WorkingData.Segment[0].IsEnabledis listed (no spaces). - Add a temporary "Diagnostics" screen with a 10-element table bound to
WorkingData.Segment[0..9].IsEnabled. The table should populate from the live PLC before any script runs. - Create a test script that reads
Segment[0].IsEnabledwith the static string and again with the dynamic string fori = 0..9. Compare to the table values; both must match for every index. - Force one PLC value (e.g.
Segment[3].IsEnabled = TRUE) from a watch table and confirm the script readsTrue. - Run the script with
OnError Resume Nextduring commissioning to log the exact failing string; replace with explicit error handling before deployment.
Dim sTag, v
On Error Resume Next
For i = 0 To 9
sTag = "WorkingData.Segment[" & i & "].IsEnabled"
v = SmartTags(sTag)
If Err.Number <> 0 Then
Trace "Lookup failed for: '" & sTag & "' Err=" & Hex(Err.Number)
End If
Next
On Error Goto 0
Performance and Best Practices
- Hoist the constant prefix out of the loop:
sPrefix = "WorkingData.Segment["and concatenate only the index + member suffix per iteration. - Avoid
SmartTagscalls insideTimerevents fired faster than 250 ms — batch the work and cache the array bounds. - Prefer reading the whole array as a Variant when the connection is symbolic (S7-1500) — one round-trip vs. n round-trips.
- Use
WStringon S7-1500 instead ofStringto avoid codepage conversion; SmartTags round-trips Unicode cleanly only for WString. - Document the array lower bound in a constant tag (e.g.
WorkingData.LoIndex) so the script can read it instead of hard-coding0.
Troubleshooting Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| "Invalid procedure call or argument" for every index | Whitespace in tag string | Strip spaces around brackets and dots |
| Works for index 0, errors for others | Loop variable scope, or array lower bound is 1 | Set Option Base 1 or use LBound
|
Reads Empty but no error |
Tag access right disabled on CPU | Enable "Permit access with PUT/GET" |
| Error after PLC UDT change | HMI project not recompiled | Right-click PLC > "Compile and download"; recompile HMI |
| Tag browser shows red entry | Connection lost, wrong subnet, or wrong CPU selected | Verify S7 connection / PROFINET name |
| Case mismatch error after migration | Symbolic name changed case | Match case to PLC declaration exactly |
Frequently Asked Questions
Why does SmartTags fail with a hard-coded index but succeed with the same index in a loop variable?
The hard-coded form has no whitespace, while "Segment [" & i & "]. IsEnabled" introduces spaces around the brackets and dot. Strip the spaces: SmartTags("WorkingData.Segment[" & i & "].IsEnabled").
Can I use round brackets like Segment(i) instead of Segment[i]?
No. The WinCC SmartTags resolver requires square brackets. Round brackets are VBScript function-call syntax and cause "Object required" or "Wrong number of arguments" errors.
Are the WinCC tag names case-sensitive when the PLC is an S7-1500?
Yes, from TIA Portal V14 onward the S7-1500 symbolic name is case-sensitive in WinCC scripting. The HMI tag browser shows the canonical case; match it exactly in your VBScript strings.
How do I read the whole array in one call instead of looping?
Use vArray = SmartTags("WorkingData.Segment"). The returned Variant is a VBScript array whose elements expose the struct members directly: vArray(0).IsEnabled. This is supported on symbolic S7-1200/1500 connections in WinCC V14+.
Does the same syntax work in WinCC Unified?
No. WinCC Unified uses a JavaScript API; SmartTags is not available. The Unified equivalent is Tags("WorkingData.Segment[" + i + "].IsEnabled").Read().
What is the maximum nesting depth of a UDT inside a script-accessible tag?
WinCC RT Advanced supports 6 levels of nested UDTs; WinCC RT Professional and Unified support 8. Each level adds one dot chain, all of which must be whitespace-free.