Resolving VBScript Dim As String Syntax Error in Siemens WinCC

David Krause14 min read
HMI / SCADASiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

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:

Rule: Use 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:

  1. If the literal is enclosed in double quotes, the variant becomes String.
  2. If the literal is a numeric token with a decimal point, the variant becomes Double.
  3. If the literal is a bare integer, the variant becomes one of the integer subtypes (typically Long) depending on magnitude.
  4. If the literal is True or False, the variant becomes Boolean.
  5. 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

  1. Open the VBS Action in the WinCC Graphics Designer (right-click the object → Properties → Events → Click).
  2. Strip every As <type> suffix from Dim and Const lines.
  3. Strip every Set keyword that sits in front of a string, number, boolean, or date literal.
  4. 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.
  5. 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.
  6. For scheduled or global actions, run the WinCC “RT (runtime) – Action trace” tool with a 5-second cycle to capture the first call.
  7. For project-wide safety, run Project → Compiler → Check All in the WinCC Explorer; any leftover As clauses 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

  1. Declare without types. Dim foo is the only form that compiles. Use naming conventions (Hungarian-style prefixes such as s for string, n for numeric, b for boolean, o for object) to make the intended subtype visible to the reader, since the engine will not enforce it.
  2. Use Set only for objects. Reserve the keyword for COM objects returned by WinCC (HMIRuntime.Tags(...), HMIRuntime.Screens(...), HMIRuntime.ActiveScreen) or instances created via CreateObject.
  3. 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.
  4. 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.
  5. Trace liberally during commissioning. HMIRuntime.Trace ">> value=" & value & vbNewLine costs almost nothing and shortens fault-finding from hours to minutes.
  6. 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 CDbl or kept as a string.
  7. Avoid Option Explicit on shared globals. WinCC global actions share a namespace; turning on Option Explicit in one action and forgetting it in another is a frequent source of “Variable is undefined” runtime errors.
  8. Keep Set and = 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.

Back to blog