Overview
Siemens WinCC (both WinCC V7 and WinCC Professional inside TIA Portal) executes user actions in two distinct languages: C for the legacy ANSI-C script editor, and VBScript (VBS) for the modern VBS Action editor used on graphic objects, global actions, and scheduled tasks. The two languages share a common runtime host but differ fundamentally in their type systems. Source code copy-pasted from external VB6, VBA, or VB.NET samples, or from the WinCC Graphics Designer (which uses VBA, not VBS), will frequently fail to compile inside a WinCC VBS Action with the message “Expected end of statement” pointing at a Dim line that contains an As clause. This article traces that error to its source, documents the exact syntactical differences between the three “Basic” dialects encountered in a WinCC project, and provides copy-paste-correct VBScript templates that compile under F7 syntax check and execute without runtime type-mismatch errors.
WinCC Scripting Environments: VBScript vs VBA vs C
WinCC exposes three different script hosts to the engineer, and confusing them is the root cause of nearly every “stupid” syntax error raised in the VBS Action editor:
| Host | Language | File / Editor | Type System | Typical Use |
|---|---|---|---|---|
| Global Script – C Editor | ANSI C (WinCC extension) | *.c actions, project functions | Statically typed | High-performance tag I/O, alarm loops |
| Global Script – VB Editor | VBScript | *.bmo actions, project functions | Variant only (typeless) | HMI logic, screen math, recipes |
| Graphics Designer – VBA | Visual Basic for Applications 7.1 | Embedded in Graphics Designer | Statically typed (VB6 dialect) | Property events at design time |
| WinCC OA Ctrl scripts | CTRL (C-like) | Panel/event scripts | Weakly typed | SCADA events (out of scope here) |
The decisive row is the middle one: Global Script – VB Editor. This is where a button-click or scheduled action lives, and the engine that compiles it is the Windows Script Host (WSH) VBScript engine bundled with WinCC. VBScript, in turn, is a stripped-down, interpreted, typeless descendant of VB6 with no native integer / long / string / boolean distinction. Every variable in VBScript is internally a VT_VARIANT whose effective subtype is decided at the moment a value is assigned, not at the moment the variable is named.
By contrast, the VBA macro engine inside Graphics Designer compiles against the full VB6 type library and accepts declarations such as Dim i As Integer or Dim s As String without complaint. Code lifted from a VBA procedure and pasted into a VBS Action therefore brings a dialect feature the new host cannot parse.
Root Cause: VBScript Is a Typeless Language
Microsoft formally documents that VBScript is a typeless language with a single data type, Variant. The Dim statement in VBScript supports only the variable name and the optional Preserve modifier for arrays; it does not accept an As <type> suffix. The official grammar reads (paraphrased):
Dim varname [()] [, varname [()]] … [Preserve]There is no slot in the grammar for As. The token As has no defined role inside a Dim statement, so the parser reaches it, finds nothing on the production stack that consumes it, and raises a syntax error.
The error is rendered inside the WinCC VBS editor as:
Expected end of statement(6): Dim something As String
^
The number in parentheses (6) is a positional indicator that the WinCC VBS editor appends to the F7 syntax-check output. The exact meaning – character offset from the start of the line, column number, or WinCC-internal code – depends on the WinCC version, but it is not a VBScript error number. VBScript compile errors do not carry numeric codes the way runtime errors do (e.g. 13 = Type Mismatch, 9 = Subscript Out of Range, 11 = Division By Zero). The number simply points the engineer at the offending token on the highlighted line.
Decoding the “Expected end of statement” Error
Whenever the F7 syntax check inside the WinCC VBS editor fails with “Expected end of statement” followed by a parenthesised integer, the diagnostic is identical: a token exists on the line that the VBScript parser cannot consume. Common offenders, with their parenthesised offsets on a single-space-indented Dim line:
| Line content | Bad token | Char offset (approx.) | Dialect confused with VBS |
|---|---|---|---|
Dim x As Long |
As |
7 | VBA / VB6 |
Dim s As String |
As |
7 | VBA / VB6 |
Dim flag As Boolean |
As |
9 | VBA / VB6 |
Const MAX As Long = 100 |
As |
10 | VBA / VB6 |
Dim i%, s$ |
% / $
|
6 | VB6 type-suffix characters |
Dim arr(10) As Integer |
As |
13 | VBA / VB6 |
Each row fails for the same reason: the suffix is grammatical sugar that VBScript does not implement. The fix in every case is to drop the suffix.
Solution 1: Remove Datatype Suffixes from Dim Statements
Replace every typed declaration with the untyped equivalent. The table below shows the mechanical translation:
| VBA / VB6 syntax (invalid in VBS) | VBScript syntax (compiles in WinCC) |
|---|---|
Dim i As Integer |
Dim i |
Dim l As Long |
Dim l |
Dim s As String |
Dim s |
Dim b As Boolean |
Dim b |
Dim d As Double |
Dim d |
Dim o As Object |
Dim o |
Dim arr(10) As Variant |
Dim arr(10) |
Dim arr() As String |
Dim arr() |
Once the suffix is removed, F7 syntax check passes and the variables become runtime Variant containers that re-coerce on each assignment. The WinCC Online Help entry for Dim explicitly states that no type declaration is permitted and that the variable is initialised to Empty until first assignment.
Solution 2: Remove the Set Keyword for Non-Object Values
After the Dim fix, the original engineer reported a second, runtime error: the line Set obicni = "CLASS …" failed when the action was executed. Set in VBScript has a narrow, mandatory meaning: it binds the variable on its left to an object reference (a COM IUnknown*). The expression on the right of Set must evaluate to an object – a tag object, an HMIRuntime interface, a recordset, a dictionary, etc.
When the right-hand expression is a string literal – a primitive, not an object – VBScript raises runtime error Type mismatch (decimal 13 / hex 0x800A000D) at the line that contains Set. This is the same Microsoft-documented error that also appears when a numeric comparison is attempted on a string that cannot be coerced; the diagnosis and fix are covered in the Microsoft Learn article “VBScript type mismatch error”. The corrective rule is therefore:
Set only for object assignments. Use bare = for primitives (string, number, boolean, date, empty, null).The corrected assignment is simply:
obicni = "CLASS In(11, 12, 13, 14, 15, 16) And TYPE In(161, 177, 193, 194, 195, 209, 210, 211, 225, 241) And PVALUE9 >= 0 And PVALUE9 <= 65535"With the trailing quotes, the entire boolean-style filter expression is now stored in the variant obicni as a literal string. If the intent is to evaluate the filter and return a Boolean, the code must be rewritten to use WinCC’s filter object model (for example HMIRuntime.Tags with tag.Filter) – but that is a structural change, not a syntax fix.
Solution 3: Avoid Reserved or System-Used Variable Names
The discussion thread notes a secondary issue: the variable name x triggered an undocumented clash with internal function names that the WinCC graphics editor pre-registers. WinCC does not publish a full reserved-word list for VBScript actions, but the following names are known to be re-used by the graphics runtime when an action fires and should be avoided as local variable names:
| Reserved / system name | Reason | Safe alternative |
|---|---|---|
x, y, z
|
Used by internal evaluation contexts of the WinCC action dispatcher |
xPos, yPos
|
result |
Implicit return variable in property-return actions | retVal |
Item |
Used in collection enumerations (Tags, Screens) | tagItem |
obj, o
|
Frequently pre-bound by wizard-generated code | myObj |
i, j
|
Safe, but easy to collide in nested loops |
idx, rowIdx
|
Renaming the local variable from x to p cleared the runtime error, which is the field-proven workaround. The deeper fix is to give every variable a project-prefixed name (for example proj_filterExpression).
Working VBScript Action Examples for WinCC
The three minimal, F7-clean VBS Actions below are derived from the original snippet and address every issue identified above.
Example 1 – Bare Dim and string assignment
' WinCC VBS Action (button Click event)
Dim obicni
obicni = "CLASS In(11,12,13,14,15,16) And TYPE In(161,177,193,194,195,209,210,211,225,241) And PVALUE9 >= 0 And PVALUE9 <= 65535"
HMIRuntime.Trace "Filter stored: " & obicni & vbNewLine
Example 2 – Object assignment with Set (for contrast)
' WinCC VBS Action
Dim tagObj ' Variant, holds an object reference
Set tagObj = HMIRuntime.Tags("MyTag")
tagObj.Read
HMIRuntime.Trace "Value = " & tagObj.Value & vbNewLine
This is the only legal use of Set: the right-hand side is the Tag object returned by the WinCC runtime, not a primitive value.
Example 3 – Loop with array declared without type
' WinCC VBS Action
Dim i
Dim values(5)
For i = 0 To 4
values(i) = i * i
Next
HMIRuntime.Trace "values(4) = " & values(4) & vbNewLine
Note the absence of As, %, or $ suffix characters on either the loop counter or the array.
Runtime Type Coercion and Variant Behavior
Once variables are declared without types, VBScript resolves the actual subtype at the moment of first use. The VBScript runtime uses the following coercion rules, in order of precedence:
- If the literal is enclosed in double quotes, the variant becomes
String. - If the literal is a numeric token with a decimal point, the variant becomes
Double. - If the literal is a bare integer, the variant becomes one of the integer subtypes (typically
Long) depending on magnitude. - If the literal is
TrueorFalse, the variant becomesBoolean. - If the variable has not yet been assigned, the variant is
Empty; the first read returns 0 in arithmetic context and "" in string context.
Coercion is implicit in mixed-type expressions, which is the mechanism behind the Microsoft-documented “VBScript type mismatch error”: when the engine tries to use a string that does not parse as a number in a numeric comparison (for example "abc" > 5), it raises runtime error 13. The same error fires when Set is applied to a primitive as discussed above.
The conversion functions CInt, CLng, CStr, CBool, CDbl, and CDate are the only sanctioned way to force a subtype at runtime, and they too can raise error 13 if the literal cannot be parsed. IsNumeric is the canonical pre-check.
Common Syntax Pitfalls Reference Table
| Bad line | Symptom | Why | Fix |
|---|---|---|---|
Dim s As String |
Expected end of statement | Type suffix in typeless language | Dim s |
Set s = "hello" |
Type mismatch 13 at runtime |
Set requires an object |
s = "hello" |
Dim x in graphic action |
Undefined symbol at runtime | Name collision with internals | Rename to xPos or similar |
Dim i% |
Expected end of statement | Type-suffix characters are VB-only | Dim i |
Const PI As Double = 3.14 |
Expected end of statement | Typed Const not allowed |
PI = 3.14 (declare as Variant) |
Dim o As New Dictionary |
Expected end of statement |
New in Dim is VB-only |
Dim o : Set o = CreateObject("Scripting.Dictionary") |
Dim s, i As String |
Expected end of statement |
As not allowed on multi-name Dim |
Dim s, i (both Variants) |
Function F(x As Long) |
Expected end of statement | Typed parameters are VB-only | Function F(x) |
Verification and Syntax Check Procedure
- Open the VBS Action in the WinCC Graphics Designer (right-click the object → Properties → Events → Click).
- Strip every
As <type>suffix fromDimandConstlines. - Strip every
Setkeyword that sits in front of a string, number, boolean, or date literal. - Press F7 in the editor. A clean compile returns no dialog and a status-bar message “No errors”. A residual error highlights the offending token.
- Save the picture (Ctrl+S), activate the runtime (Start Runtime), and trigger the event. The action log under
HMIRuntime.Trace(visible in the WinCC Explorer “Diagnostics” view) shows the output. - For scheduled or global actions, run the WinCC “RT (runtime) – Action trace” tool with a 5-second cycle to capture the first call.
- For project-wide safety, run Project → Compiler → Check All in the WinCC Explorer; any leftover
Asclauses in other actions surface in one pass.
Related VBScript Errors in WinCC
Once the Dim As problem is fixed, the next class of failures is runtime, and they share the same VBScript engine. The most common are:
| Error number | Message | Typical WinCC cause |
|---|---|---|
| 13 | Type mismatch |
Set on a primitive, or numeric op on non-numeric string |
| 424 | Object required | Calling a method on a variant that turned out to be Empty |
| 429 | ActiveX component can’t create object | Missing COM registration for a vendor DLL |
| 462 | Remote server machine does not exist | Tag read on a server tag while the partner is offline |
| 70 | Permission denied | Writing to a read-only tag or an internal WinCC tag |
| 9 | Subscript out of range | Array index out of bounds, or unknown tag name |
| 11 | Division by zero | Denominator tag reads 0.0 at action time |
| 500 | Variable is undefined | Reference to a name that was never declared with Dim under Option Explicit
|
Error 13 in particular is the downstream symptom of the same anti-pattern that produces the “Expected end of statement” compile error: assuming a typed language where there is none. The Microsoft Learn article on the VBScript type mismatch error walks through numeric-comparison scenarios that are functionally identical to the Set s = "string" situation: a primitive value is being placed where the engine expects a typed reference.
Best Practices for WinCC VBScript Development
-
Declare without types.
Dim foois the only form that compiles. Use naming conventions (Hungarian-style prefixes such assfor string,nfor numeric,bfor boolean,ofor object) to make the intended subtype visible to the reader, since the engine will not enforce it. -
Use
Setonly for objects. Reserve the keyword for COM objects returned by WinCC (HMIRuntime.Tags(...),HMIRuntime.Screens(...),HMIRuntime.ActiveScreen) or instances created viaCreateObject. -
Prefix all action variables. A picture-wide prefix (
p1_,p2_) or a project prefix (proj_) prevents collisions with internal symbols and makes the variable findable in the action trace. - Validate with F7 on every change. WinCC caches the compiled action; F7 forces a fresh syntax check and catches the issue at edit time, not at runtime.
-
Trace liberally during commissioning.
HMIRuntime.Trace ">> value=" & value & vbNewLinecosts almost nothing and shortens fault-finding from hours to minutes. -
Mind the 32-bit limit. VBScript integers are 16-bit and long integers are 32-bit. Tag values above 2,147,483,647 must be stored in a
CDblor kept as a string. -
Avoid
Option Expliciton shared globals. WinCC global actions share a namespace; turning onOption Explicitin one action and forgetting it in another is a frequent source of “Variable is undefined” runtime errors. -
Keep
Setand=on separate lines when first learning the language – it makes the object/primitive distinction visually obvious in the code review.
FAQ
Why does “Dim x As String” fail in WinCC VBS actions but compile fine in the Graphics Designer VBA macro?
WinCC VBS actions are executed by the VBScript engine (a typeless, Variant-only dialect), whereas the Graphics Designer macros are executed by the VBA engine (a typed VB6 dialect). The Graphics Designer accepts Dim x As String because VBA supports the As clause; the VBScript engine does not and raises “Expected end of statement” at the As token. Use Dim x in any action and reserve the typed form for VBA macros only.
What is the (6) in “Expected end of statement(6)” – is it a WinCC or VBScript error code?
It is a positional indicator that the WinCC VBS editor appends to the F7 syntax-check output (character offset, column number, or WinCC-internal code, depending on the WinCC version). It is not a Microsoft or VBScript error number. VBScript compile errors carry descriptive text only; numeric codes appear in runtime errors, for example 13 = Type Mismatch, 9 = Subscript Out of Range, 11 = Division By Zero, 70 = Permission Denied, 424 = Object Required, 429 = Cannot Create Object.
Why does “Set myVar = 'literal'” fail at runtime with Type Mismatch 13?
The Set keyword binds the variable on its left to an object reference on its right. A string literal is a primitive value, not an object, so the VBScript engine raises runtime error 13 (Type Mismatch). Use myVar = "literal" for string, numeric, boolean, and date assignments; reserve Set for objects such as HMIRuntime.Tags("MyTag") or instances created with CreateObject. The error and its fix are described in the Microsoft Learn article on the VBScript type mismatch error.
Are “As Long”, “As Integer”, or “As Boolean” ever legal in a WinCC VBS action?
No. The VBScript language reference defines a single data type, Variant, and the Dim grammar contains no slot for an As clause. Every typed declaration form (suffix or keyword) is rejected at compile time. If type discipline is required, apply the check at the point of use with the VBScript conversion functions: CInt, CLng, CStr, CBool, CDbl, CDate, optionally guarded by IsNumeric.
My variable name “x” causes a hidden runtime error – what names are reserved in WinCC actions?
WinCC does not publish a complete reserved-word list, but the names x, y, z, result, and Item are known to be re-used by the action dispatcher and the property-event evaluator. The field-proven fix is to rename local variables with a project prefix (e.g. proj_filter) or a domain prefix (e.g. p1_xCoord). This also prevents accidental overwrites when several graphic objects share an action.