Overview
This reference describes how to read the selected entry of a text list or graphic list in a Siemens WinCC HMI runtime using VBScript, how to compare that selection against another bit or value (PLC tag or internal HMI tag), and how to apply multiplexing so the same script can address any one of N indexed list entries without leaving the HMI. The patterns apply to WinCC Comfort/Advanced and WinCC Professional runtime targets configured in TIA Portal V16 through V19, including Comfort Panels, PC Runtime Advanced, and PC Runtime Professional. (Unified Comfort Panels use a JavaScript API and are not covered here.)
Three recurring questions are answered end-to-end:
- How do you read which entry of a text or graphic list is currently selected, and how do you recover the displayed text or graphic index from VBScript?
- How do you compare that selection to another bit or value in the PLC (or an internal HMI tag) and write a result back from the script?
- How do you use multiplexing (an index-driven pointer into a group of tags) to address one of many list sources from a single script?
All code blocks use the SmartTags and HMIRuntime object models documented in the WinCC TIA Portal scripting help. The multiplexing pattern is the canonical workaround for the absence of first-class indirect addressing in WinCC VBScript.
Prerequisites
| Item | Version / Detail |
|---|---|
| TIA Portal | V16, V17, V18, or V19 (scripting API is stable across these releases) |
| HMI Runtime | WinCC Runtime Advanced, WinCC Runtime Professional, or a Comfort Panel |
| Panel firmware | Must match the TIA Portal project version. Mismatched firmware is a leading cause of script errors at runtime |
| Scripting language | VBScript (Project → Properties → Runtime settings → Scripts → Active script language = VBScript) |
| Tags | At least one HMI tag bound to a text or graphic list; at least one external or internal tag to compare against |
| Authoring access | Local help files installed with TIA Portal for the VBScript reference and the text/graphic list configuration help |
Text Lists and Graphic Lists in TIA Portal
A text list is a configuration object that maps an integer value to a display string. A graphic list maps an integer to a graphics file (.png, .bmp; .svg is supported on Unified only). The integer lives in the HMI tag; the displayed value is the list entry at that index.
| Property | Text list | Graphic list |
|---|---|---|
| Tag type | Int (Word) or DInt | Int or DInt |
| Configuration path | HMI tags → Text and graphic lists → Text list | HMI tags → Text and graphic lists → Graphic list |
| Range entries | Default value + range (e.g. 0 = "Stop", 1 = "Run", 2 = "Fault") | Default graphic + range (e.g. 0 = lamp_off.png, 1 = lamp_on.png) |
| Bound to | Symbolic I/O field, button label, status display | Graphic I/O field, graphic view |
| Selection feedback at runtime | Tag value = index, displayed text = entry at index | Tag value = index, displayed graphic = entry at index |
| Localized | Yes — multiple language rows per index | No (graphics are language-neutral) |
Because the list is bound to a tag, the integer in the tag is the selection. There is no separate "selected text" register to read — the text is purely a presentation of the integer. To compare a selection in VBScript, compare the integer. To display the corresponding text, let the HMI render the list. This is a frequent point of confusion for engineers familiar with desktop list controls, where a list box holds both a value and a displayed string as separate fields.
WinCC VBScript Object Model: The Parts You Need
Three objects cover virtually every HMI scripting task:
-
SmartTags— a project-global collection of all HMI tags.SmartTags("TagName")reads the tag;SmartTags("TagName") = valuewrites it. For array tags,SmartTags("ArrayName")(i)reads/writes elementi.SmartTagsis the only object you need for tag-only logic. -
HMIRuntime— the runtime root. ExposesTags,Screens,Trace, and the alarm/Logging subsystems. -
HMIRuntime.Screens("ScreenName").ScreenItems("ItemName")— a specific screen item. Use this to read or write control properties such as.Text,.Value,.Selection,.OutputValue, and.BackColor.
' Pattern: read a tag
Dim v
v = SmartTags("ModeIndex")
' Pattern: write a tag
SmartTags("MatchFound") = 1
' Pattern: read element i of an array tag
Dim i, elem
i = SmartTags("MuxIndex")
elem = SmartTags("MuxArray")(i)
' Pattern: read a screen item property (WinCC Professional)
Dim oItem, sText
Set oItem = HMIRuntime.Screens("Main").ScreenItems("ModeIOField")
sText = oItem.Text
OutputValue on a configured symbolic I/O field); use the property picker in the TIA Portal script editor to confirm the exact name for your firmware version.Reading the Selection in VBScript
The basic read pattern addresses the HMI tag through the SmartTags collection. The tag may be an internal HMI tag or a pointer into the PLC.
' Read the integer index of the text list selection
Dim iSelection
iSelection = SmartTags("ModeIndex") ' tag bound to a text list
' Read the bit/word to compare against
Dim iRefValue
iRefValue = SmartTags("RefValue") ' PLC tag or internal tag
' Drive a result tag back to the PLC
If iSelection = iRefValue Then
SmartTags("MatchFound") = 1
Else
SmartTags("MatchFound") = 0
End If
This is the smallest useful pattern: read a list selection, compare it to a reference, and write a result. Both tags must exist in the HMI tag table; the script will throw a runtime error if a referenced tag is missing, or if the connection to the PLC is not established when the script first runs.
Reading the displayed text, not just the index
If you need the text that the HMI is rendering (for logging, for forwarding to a string tag, or for string comparison against a fixed label), you must read it from the screen item, because the HMI list itself is not directly addressable as a VBScript object. The general approach mirrors the technique documented for retrieving the inner text of a list or dropdown element (see Microsoft DevBlogs: How Can I Get the Actual Text of a List Box or Dropdown List Option?) — the value is one thing, the displayed text is another, and the script must read the visible property rather than the value.
On WinCC Comfort/Advanced (symbolic I/O field bound to a text list):
' Get the displayed text of the symbolic I/O field "ModeField"
Dim sText
sText = SmartTags("ModeField") ' the .Text / .OutputValue property of the I/O field
On WinCC Professional, screen items are addressable as HMIRuntime.Screens("ScreenName").ScreenItems("ItemName"):
Dim oItem, sText
Set oItem = HMIRuntime.Screens("Main").ScreenItems("ModeIOField")
sText = oItem.Text ' or .OutputValue, depending on the control
Multiplexing: One Script, Many List Sources
Multiplexing is the technique of using an index tag to select which of N underlying values the script should act on. In Siemens HMI scripting it is the standard workaround for the absence of full indirect addressing — VBScript cannot dereference a pointer in the way that, for example, a C script with an HMI_TAG_POINTER can.
Pattern A — array tag with index
Configure a tag as a one-dimensional array (DInt array of N elements) and read element iIndex:
Dim iIndex, iValue
iIndex = SmartTags("MuxIndex") ' 0..N-1
iValue = SmartTags("MuxArray")(iIndex) ' element access
Array tags must be declared as a one-dimensional array in the HMI tag table. The size of the array is fixed at project compile time. If iIndex is out of range, VBScript raises a runtime error — guard the read.
Pattern B — string-built tag name
When the data is stored as separate scalar tags (no array), build the tag name as a string and use the indirect read:
Dim iIndex, sTagName, vValue
iIndex = SmartTags("MuxIndex")
sTagName = "MuxValue_" & CStr(iIndex)
vValue = SmartTags(sTagName)
This requires that tags MuxValue_0, MuxValue_1, …, MuxValue_N-1 exist in the HMI tag table. The script will fail if the constructed name does not match a real tag, so the multiplexer index must be bounded by the project's tag count. Use this pattern when you must multiplex across structurally different data sources that cannot be arrayed (for example, a mix of Bool, Int, and String tags).
Pattern C — array of pointer names plus indirect read
For more complex cases where the multiplexer picks a tag by name, store both the source tag name and the value in coordinated arrays:
Dim iIndex, sName, vValue
iIndex = SmartTags("MuxIndex")
sName = SmartTags("MuxNames")(iIndex) ' array of strings (tag names)
vValue = SmartTags(sName) ' then indirect read
Pattern C is the most flexible — it lets the multiplexer point at any tag in the project — but the most error-prone. It is the right pattern when the multiplexer must be reconfigured at runtime by the operator (e.g. selecting which recipe source drives a comparison), and the wrong pattern when a fixed set of pointers will do.
Sizing the multiplexer
Choose N (the number of multiplexer positions) based on the use case:
| Use case | Recommended N | Notes |
|---|---|---|
| Mode selection (Auto/Manual/Service) | 3–8 | Pattern A with DInt[8] is typical |
| Recipe source (one of 16 recipe slots) | 16–32 | Pattern A or B; array of DInt[16] is typical |
| Alarm routing (one of many source tags) | Variable | Pattern C with string-name array |
| Page selector (jump to one of many screens) | 8–32 | Pattern B with "Screen_" & iIndex naming |
The array-tag approach (Pattern A) is the fastest at runtime because the HMI runtime holds the array in memory. The string-built approach (Pattern B) is slower because the runtime must resolve the tag name on every read, but it allows tag types to differ per index.
Comparing a Selection to a Bit or Value
The comparison is the same regardless of whether the second operand is a Bool, an integer, a real, or a string tag. VBScript coerces types implicitly; declare the comparison variables explicitly to avoid type-mismatch errors at runtime.
' --- Bit comparison ---
If SmartTags("ModeIndex") = 1 And SmartTags("EnableBit") = True Then
SmartTags("RunEnable") = 1
End If
' --- Value comparison with tolerance (real) ---
Dim rPV, rSP, rTol
rPV = SmartTags("ProcessValue")
rSP = SmartTags("Setpoint")
rTol = 0.5
If Abs(rPV - rSP) <= rTol Then
SmartTags("InBand") = 1
Else
SmartTags("InBand") = 0
End If
' --- String comparison (only valid for tags typed as WString) ---
If SmartTags("RecipeName") = "RUN_42" Then
SmartTags("RecipeOK") = 1
End If
True/False works, but a literal = 1 / = 0 is the convention used in production WinCC code. Mixing the two is a common source of subtle bugs in code review.Step-by-Step Implementation
The following procedure produces a working selection-comparison script bound to a button event, including multiplexing.
-
Declare tags in the HMI tag table.
-
ModeIndex— Int, bound to a text list (e.g. 0 = "Auto", 1 = "Manual", 2 = "Service") -
RefValue— Int, external PLC tag -
MatchFound— Bool, internal HMI tag, written back to the PLC -
MuxIndex— Int, internal, 0..7, controlled by the operator or by the PLC -
MuxArray— DInt[8] array, internal or external -
MuxError— Bool, internal, set to 1 on out-of-range index
-
- Add a text list in HMI tags → Text and graphic lists. Map 0 → "Auto", 1 → "Manual", 2 → "Service".
-
Place a symbolic I/O field on the screen and bind its Value property to
ModeIndex. Bind its Display to the text list from step 2. -
Place an I/O field for the multiplexer bound to
MuxIndex. Set a configured range of 0 to 7 and a step of 1. - Add a button "Evaluate". In the Events tab, configure the Click event to run a VBScript.
- Paste the script from the snippet below into the Click event of the button.
- Compile the project (Ctrl+F7 in TIA Portal) and download to the HMI. Update the panel firmware first if the runtime version requires it.
-
Test by changing
ModeIndexandMuxIndexfrom the screen, then pressing Evaluate and observingMatchFoundin the HMI tag monitor and on the PLC (TIA Watch table or the PLC online view).
' ----- Evaluate button Click event -----
Dim iMode, iRef, iMux, vMuxValue, iResult
' Read the current text-list selection
iMode = SmartTags("ModeIndex")
iRef = SmartTags("RefValue")
' Read the multiplexed value at MuxIndex
iMux = SmartTags("MuxIndex")
If iMux < 0 Or iMux > 7 Then
SmartTags("MuxError") = 1
Exit Sub
Else
SmartTags("MuxError") = 0
End If
vMuxValue = SmartTags("MuxArray")(iMux)
' Combine the conditions: list selection AND value match
If iMode = iRef And vMuxValue > 0 Then
iResult = 1
Else
iResult = 0
End If
' Write the result back to the PLC-visible tag
SmartTags("MatchFound") = iResult
Using the Script in a Scheduled Task
If the comparison must run continuously rather than on a button press, attach the same script body to a scheduled task on the HMI (Schedules → Add → Trigger = "Cyclic", Update = 500 ms). Scheduled VBScript runs in the global script context, so SmartTags continues to work and no screen reference is required.
Cross-Screen and Cross-Panel Patterns
When the selection lives on Screen A and the comparison runs on Screen B, you can keep the script identical by attaching it to a button on either screen, because SmartTags is global to the HMI project. The screen-item text access path is the only piece that is screen-local; replace the screen name accordingly.
' Cross-screen text access (WinCC Professional)
Dim sText
sText = HMIRuntime.Screens("Overview").ScreenItems("ModeIOField").Text
For an aggregation screen that displays a multiplexer-driven value, use the same array-index read as in Pattern A. The same multiplexer index tag can be read from any screen; only the bound display control changes.
Logging the Result
A common follow-up requirement is to log the match to the alarm or audit trail. Write a short message to an HMI tag that the alarm log has been configured to capture, or use HMIRuntime.Trace for a development trace:
HMIRuntime.Trace "Mode match: iMode=" & iMode & " vMux=" & vMuxValue & " result=" & iResult & vbCrLf
SmartTags("LastTraceMessage") = "Mode=" & iMode & "; Mux=" & vMuxValue & "; Result=" & iResult
MsgBox in production runtime. It blocks the HMI thread and forces operator intervention. Reserve it for the TIA simulation during commissioning. Use a status tag or alarm log entry in production.Edge Cases and Performance Notes
- Type coercion at the boundary. If a Bool PLC tag is wired to an HMI Int tag, both reads return 0/1 but the type info is lost. Use the HMI tag type that matches the PLC variable type to keep the boundary clean.
- Power Tags (WinCC Professional / Unified). Marking a tag as a Power Tag changes update behavior; multiplexer arrays benefit noticeably from Power Tag status, but each Power Tag consumes a license.
- String tag length. WString tags are typically limited to 255 characters; longer strings require a custom PLC data type and a different HMI tag type. Comparison against a literal in VBScript is then case-sensitive by default.
- Cyclic vs on-demand scripts. A button-click event is the simplest hook. Use a cyclic scheduled task only if the comparison must be continuous — the script will otherwise idle for hours between operator actions, consuming scheduler slots.
- Localization. Text lists can be localized. The integer index is stable across languages, but the displayed text is not. Always compare on the integer; do not hardcode language-specific text in a script that will be deployed to a multi-language HMI.
-
Tag name length. Siemens HMI tag names are limited to 128 characters. The string-concatenation pattern (
"MuxValue_" & CStr(iMux)) must not exceed that limit; use numeric indices wherever possible. -
Set
MuxErrorbeforeExit Sub. A failed array access will throw, but the operator should see the diagnostic state. Set the error tag first, then exit.
Troubleshooting Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| "Tag not found" or similar at script start | Tag missing in HMI tag table, or the project has not been compiled/recompiled | Add the tag, full compile (Ctrl+F7), redownload to the HMI |
"Subscript out of range" on MuxArray
|
MuxIndex outside the array bounds |
Add the guard If iMux < 0 Or iMux > UBound(arr) Then SmartTags("MuxError") = 1 : Exit Sub
|
| Tag value reads, but the comparison never matches | Type mismatch (Int vs DInt, signed vs unsigned, BCD on PLC side) | Match the tag data type in TIA Portal to the PLC; check the PLC data block type |
| Script runs in TIA simulation but not on the panel | Panel firmware older than project, or scripting disabled in runtime settings | Update firmware, enable VBScript in project properties |
"Object variable not set" on ScreenItems(...)
|
Wrong screen name, wrong item name, or item not configured with the expected property | Use the object picker in the TIA Portal script editor to confirm names |
| Tag value toggles rapidly between two list entries | HMI tag connected to a noisy PLC bit; no debounce in script | Add a hysteresis timer or a debounce counter before writing the result |
| Multiplexer index never updates on the screen | Tag is write-protected or not connected to a configurable control | Check the I/O field's "Operability" property and the tag's acquisition mode |
Script runs but MatchFound stays at its previous value |
The result tag is read-only or not declared as a writable PLC point | Confirm the tag has a direction of "read/write" in the HMI tag table and is mapped to a writable PLC address |
| Array element always reads 0 | The multiplexer index is being reset by another script or by the PLC faster than the script reads it | Snapshot the index into a local variable at the start of the script, then read the array element from that snapshot |
Verification
After download, perform the following checks before signing off the change:
- Open the HMI tag simulation in TIA Portal (Online → HMI Tag Simulation) and force
ModeIndexto each configured value. Confirm the text list displays the right string on the screen. - Force
RefValueto matchModeIndex; press the Evaluate button; verifyMatchFoundbecomes 1 in the HMI tag monitor and in the PLC (using TIA Watch table or the PLC online view). - Force
RefValueto a different value; verifyMatchFoundreturns to 0. - Set
MuxIndexto 0..7 in turn, with a non-zeroMuxArrayelement at each index, and confirm the result is correct. Then setMuxIndexto 8 — confirm the script raisesMuxErrorand does not write garbage toMatchFound. - Disconnect the PLC and confirm the script handles a connection loss gracefully: the comparison will run against the last-cached value;
MatchFoundshould reflect that cache, not freeze or throw. - If the script runs on a scheduled cycle, log the cycle time from the trace and confirm it stays below the configured update interval. A script that runs longer than its cycle interval will backlog on a Comfort Panel.
FAQ
How do I read the currently selected entry of a text list in VBScript?
Read the HMI tag that the list is bound to with SmartTags("ModeIndex"). The integer value of the tag is the selection index; the displayed text is the list entry at that index and is rendered automatically by the HMI. To recover the actual text, read the .Text property of the screen item (WinCC Professional) or the I/O field's OutputValue (WinCC Comfort/Advanced).
Can I compare the text string directly, not the integer index?
Not reliably. The list maps an integer to a text; the text is presentation. Always compare on the integer — string comparison breaks under localization, where the same integer can display different texts per language, and is fragile across firmware updates where label text may be reworded.
What is multiplexing in a Siemens HMI script?
Multiplexing uses an index tag to choose which of N values the script acts on. In VBScript the two practical implementations are (a) an array tag plus an index read (SmartTags("MuxArray")(iIndex)) and (b) a string-built tag name (SmartTags("MuxValue_" & iIndex)) for an indexed set of scalar tags. Pattern A is faster; Pattern B supports mixed tag types.
Why does my script throw "Subscript out of range" on the array read?
Because the index tag moved outside the array bounds. Guard the read with a range check and write a diagnostic to an error tag before exiting. Example: If iMux < 0 Or iMux > UBound(arr) Then SmartTags("MuxError") = 1 : Exit Sub. A mismatched multiplexer index is the most common cause in production code.
Does this work on a Unified Comfort Panel?
No — Unified Panels use JavaScript for screen-side scripting, not VBScript. The multiplexing and comparison logic transfers directly, but the tag access syntax changes (use the Unified JS API or the item property model). This article covers WinCC Comfort/Advanced and WinCC Professional, which use VBScript.
How do I avoid MsgBox blocking the HMI at runtime?
Replace MsgBox with writes to an HMI tag that is bound to a status display, or with HMIRuntime.Trace for development. MsgBox in a runtime script pauses the entire HMI and forces operator interaction — it is acceptable only in the simulation for debugging and must be removed before deployment.