Engineer field notes for manipulating individual bits of a 32-bit DWORD tag from VBScript inside a Siemens WinCC runtime. The same logic applies to any unsigned integer tag (BYTE, WORD, DWORD, LWORD) by adjusting the bit-mask width. All examples use the HMIRuntime object model that ships with WinCC V7.x and TIA Portal WinCC Professional; a JavaScript equivalent for WinCC Unified Comfort/Edge panels is summarized at the end.
1. Overview
Inside a WinCC runtime, every configured tag is exposed to scripting through the HMIRuntime COM object. A common requirement is to set, clear, or toggle one specific bit inside a DWORD tag from a button click or scheduled action. Because VBScript (VBScript 5.x as documented in Microsoft Learn: Using VBScript) has no native &, |, or ^ operators, bit manipulation is performed with integer exponentiation 2 ^ n combined with the built-in And, Or, and Xor arithmetic operators.
Microsoft has formally deprecated VBScript as a standalone runtime on Windows client and server SKUs (see Wikipedia: VBScript). WinCC, however, continues to ship its own embedded VBScript host for runtime logic, and the scripting API described here remains the supported path for WinCC V7.x and TIA Portal WinCC Professional projects.
The script patterns below cover: read-modify-write with Read/Write, idempotent bit-set, idempotent bit-clear, click-toggle, multi-bit mask, and bit-test. The same helpers used in C-Script can be ported to VBScript with no algorithmic change.
2. Prerequisites and Project Setup
Confirm the following before authoring the script:
-
Runtime target: WinCC V7.x SP3 or later, or TIA Portal V16+ with WinCC Professional. WinCC Runtime Advanced does not expose
HMIRuntime; see section 10. -
Tag configuration: A DWORD tag named, for example,
MyFlagsis present in the HMI tag table. Internal tags, PLC pointers, and structured tag fields all work; only the data type matters. - Connection: For PLC-backed tags, the HMI connection is online and the tag is reachable. For internal tags, the tag type is set to "Internal tag" with the DWORD data type selected.
- Screen element: A Button (or any object exposing click events) is placed on the process screen and the "Click" event is wired to a VBScript action.
- Editor access: The VBScript editor is reachable from the button's Events tab, or globally under "VBScripts" in the project tree.
3. VBScript Runtime Environment Inside WinCC
The VBScript host embedded in WinCC is a 32-bit Windows Script Host (WSH) process. The relevant characteristics for bit math are:
| Characteristic | Value | Note |
|---|---|---|
| Language version | VBScript 5.x | Matches the legacy cscript/wscript host documented by Microsoft |
| Integer width | 32-bit signed (Variant subtype VT_I4) | Effective range −2,147,483,648 to +2,147,483,647 |
| Bitwise operators | None at language level | Use And/Or/Xor/Not with integer values |
| Exponentiation |
^ operator |
2 ^ 8 returns 256 |
| Decimal type | Variant/Decimal | Use CLng() to coerce to 32-bit long before bit math |
| String/byte handling | COM BSTR | Convert with CStr, CInt, CLng
|
The And, Or, Xor, and Not operators in VBScript perform bitwise operations on integer values and boolean logic on non-integer values. Always coerce to Long with CLng() before applying them, or assign the result of a 2 ^ n expression to an explicit Long variable.
For an authoritative language reference see Microsoft Learn: Using VBScript. For lifecycle and deprecation context see Wikipedia: VBScript.
4. HMIRuntime Object Model and Tag Access
All scripting inside WinCC Runtime Professional resolves through the global HMIRuntime object. The relevant sub-objects and members for tag manipulation are listed below.
| Member | Type | Description |
|---|---|---|
HMIRuntime |
Object | Root runtime object. Pre-instantiated; do not Set it. |
HMIRuntime.Tags(name) |
Method (returns Tag) | Resolves a tag by name. The name is the fully qualified tag path. |
tag.Read |
Method | Pulls the current value from the source. Required before reading tag.Value for most tag types. |
tag.Write |
Method | Pushes tag.Value back to the source. Required after assigning a new value. |
tag.Value |
Property | Read/write the current tag value. Type is Variant. |
tag.QualityCode |
Property | Numeric OPC quality code. 192 (0xC0) = Good, 0 = Bad. |
tag.Error |
Property | HMI error code; non-zero indicates a write/read failure. |
tag.LastError |
Property | Human-readable error description. |
The canonical read-modify-write template is:
Dim tag
Set tag = HMIRuntime.Tags("MyFlags")
tag.Read
' --- modify tag.Value here ---
tag.Write
Note the use of the Set keyword for object assignment. For a primitive Variant property assignment (tag.Value = 256) the Set keyword is not used.
In TIA Portal WinCC Professional, the tag resolution is identical, but the editor is reached through the picture's "Events" tab on the HMI object. Internal tags and external PLC tags share the same HMIRuntime.Tags access path; only the underlying data source differs.
5. Bitwise Arithmetic in VBScript
VBScript does not implement &, |, <<, or >>. Bit manipulation is therefore expressed through integer exponentiation and the language's built-in arithmetic And/Or/Xor/Not operators. The relevant identities are:
| Operation | Formula | Effect |
|---|---|---|
| Set bit n | value = value Or (2 ^ n) |
Force bit n to 1, leave others unchanged |
| Clear bit n | value = value And Not (2 ^ n) |
Force bit n to 0, leave others unchanged |
| Toggle bit n | value = value Xor (2 ^ n) |
Flip bit n, leave others unchanged |
| Test bit n | (value And (2 ^ n)) <> 0 |
True if bit n is 1 |
| Mask bits | value And mask |
Extract a bit pattern |
The mask values for the first 16 bits are:
' Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
' Mask: 32768 16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1
' Hex: 8000 4000 2000 1000 0800 0400 0200 0100 0080 0040 0020 0010 0008 0004 0002 0001
Bit indexing is zero-based. Bit 0 is the least significant bit (LSB), worth decimal 1. Bit 31 is the most significant bit (MSB), worth 2,147,483,648. The example "set the 8th bit" in the field report corresponds to bit index 7 (LSB-relative count) or bit index 8 (one-based count); the mask is 256 either way as long as the convention is consistent. The helpers in section 7 use zero-based indexing to match typical C and STL convention.
Always coerce the result with CLng() when the value approaches 2^31, because VBScript promotes the ^ result to a Double and silent precision loss occurs above 2^31 − 1.
Dim mask
mask = CLng(2 ^ n) ' forces 32-bit long
6. Reading, Setting, Clearing, and Toggling Individual Bits
The flow below shows the canonical read-modify-write cycle for any bit operation triggered from the HMI.
6.1 Read the current value
Dim tag
Set tag = HMIRuntime.Tags("MyFlags")
tag.Read
Dim current
current = tag.Value
' current is now the 32-bit DWORD value
If the tag is an internal HMI tag, Read is a no-op for the value itself but still refreshes the QualityCode. For PLC tags, Read issues a synchronous read against the configured update cycle and is therefore a blocking call.
6.2 Set a single bit (idempotent)
Setting the 8th bit (bit index 7, mask 128) is achieved with the canonical read-modify-write pattern:
Dim tag, bitIndex
bitIndex = 7 ' 0-based; bit 7 has mask 2^7 = 128
Set tag = HMIRuntime.Tags("MyFlags")
tag.Read
tag.Value = CLng(tag.Value) Or CLng(2 ^ bitIndex)
tag.Write
Idempotent means calling the script twice produces the same observable result: the bit ends up at 1 regardless of its previous state. The Or with the existing value guarantees this property.
6.3 Clear a single bit (idempotent)
Dim tag, bitIndex
bitIndex = 7
Set tag = HMIRuntime.Tags("MyFlags")
tag.Read
tag.Value = CLng(tag.Value) And Not CLng(2 ^ bitIndex)
tag.Write
After this script runs, bit 7 is guaranteed to be 0, and all other bits are preserved.
6.4 Toggle a bit on each click
The field report requested inverted behavior on repeated clicks. The Xor operator provides exactly that:
Dim tag, bitIndex
bitIndex = 7
Set tag = HMIRuntime.Tags("MyFlags")
tag.Read
tag.Value = CLng(tag.Value) Xor CLng(2 ^ bitIndex)
tag.Write
Click 1 flips the bit from 0 to 1; click 2 flips it from 1 to 0. The other 31 bits are untouched. This is the most common operator-station pattern.
6.5 Test a bit
Dim tag, bitIndex, isSet
bitIndex = 7
Set tag = HMIRuntime.Tags("MyFlags")
tag.Read
isSet = (CLng(tag.Value) And CLng(2 ^ bitIndex)) <> 0
' isSet is True when the bit is 1, False otherwise
Use the result of the test to drive a status lamp, conditional write, or a pop-up message.
6.6 Multi-bit mask (set or clear a pattern)
For simultaneously setting or clearing multiple bits, use a precomputed mask:
Dim tag, mask
mask = CLng(2 ^ 0) Or CLng(2 ^ 3) Or CLng(2 ^ 7) ' bits 0, 3, 7
Set tag = HMIRuntime.Tags("MyFlags")
tag.Read
tag.Value = CLng(tag.Value) Or mask ' set all three
' tag.Value = CLng(tag.Value) And Not mask ' clear all three
tag.Write
Combine up to 32 individual bits into a single write to minimize HMI/PLC traffic on event-driven control panels.
7. SetBitInTag / GetBitInTag Helper Library
Reusable functions reduce per-button script maintenance. The four helpers below wrap the patterns from section 6. Place them in a project-wide VBScript module and call them from any button or scheduled action.
' ---------- BIT HELPERS ----------
Sub SetBitInTag(tagName, bitNum)
Dim t
Set t = HMIRuntime.Tags(tagName)
t.Read
t.Value = CLng(t.Value) Or CLng(2 ^ bitNum)
t.Write
End Sub
Sub ClearBitInTag(tagName, bitNum)
Dim t
Set t = HMIRuntime.Tags(tagName)
t.Read
t.Value = CLng(t.Value) And Not CLng(2 ^ bitNum)
t.Write
End Sub
Sub ToggleBitInTag(tagName, bitNum)
Dim t
Set t = HMIRuntime.Tags(tagName)
t.Read
t.Value = CLng(t.Value) Xor CLng(2 ^ bitNum)
t.Write
End Sub
Function GetBitInTag(tagName, bitNum)
Dim t
Set t = HMIRuntime.Tags(tagName)
t.Read
GetBitInTag = (CLng(t.Value) And CLng(2 ^ bitNum)) <> 0
End Function
' ---------- USAGE FROM A BUTTON CLICK ----------
' SetBitInTag "MyFlags", 7 ' force bit 7 to 1
' ClearBitInTag "MyFlags", 7 ' force bit 7 to 0
' ToggleBitInTag "MyFlags", 7 ' flip bit 7
' If GetBitInTag("MyFlags", 7) Then MsgBox "Bit 7 is set"
The helpers follow the naming suggested in the field report. Because VBScript passes strings by reference, tagName can be a string literal or a variable. Bit indices are zero-based and must lie in the range 0–31 for a DWORD; values outside this range raise an overflow at the 2 ^ n expression.
Or/And/Xor result to be silently wrong because 2 ^ 32 becomes a Double and the high bit is lost. Validate the parameter in production code or widen the target tag to LWORD.8. Button Event Wiring and MsgBox Behavior
8.1 Wiring a Click event
Open the screen editor, select the button, and in the Properties pane under Events click the entry for "Click". Choose "VBScript" and the IDE opens a code editor. The minimal handler that sets bit 7 is:
SetBitInTag "MyFlags", 7
For the inverted-status behavior the field report described, change the body to:
ToggleBitInTag "MyFlags", 7
TIA Portal WinCC Professional persists the script in the screen's events table; WinCC V7.x stores it under the picture's "Events" tab in Graphics Designer. Re-compilation is automatic on save.
8.2 Toggle state machine
8.3 MsgBox from VBScript vs C-Script
The field report explicitly asked why VBScript is required: MsgBox is a built-in VBScript statement. The equivalent in WinCC C-Script requires calling MessageBox through the Win32 API, which is more verbose and notoriously sensitive to include paths in protected C-script projects. For operator confirmations, alarms, and short text feedback, VBScript is therefore the pragmatic choice.
Example operator confirmation:
If GetBitInTag("MyFlags", 7) Then
MsgBox "Bit 7 is currently SET. Click OK to clear it.", vbExclamation, "Confirm"
ClearBitInTag "MyFlags", 7
End If
Note that MsgBox blocks the runtime while the dialog is open. Do not use it inside the scheduler of a high-frequency cycle, and prefer HMIRuntime.Trace for diagnostic logging that should not pause the screen.
9. Error Handling, Quality Codes, and Performance
9.1 On-Error handling
VBScript supports On Error Resume Next (suppress and continue) and On Error Goto 0 (restore default). Tag-access errors (invalid name, connection loss, type mismatch) raise runtime error 0x8004... in the VBScript host. Use the pattern:
On Error Resume Next
Set t = HMIRuntime.Tags("MyFlags")
If Err.Number <> 0 Then
HMIRuntime.Trace "Tag resolve failed: " & Err.Description & vbCrLf
Exit Sub
End If
t.Read
If t.Error <> 0 Then
HMIRuntime.Trace "Tag read error code: " & t.Error & " " & t.LastError & vbCrLf
Exit Sub
End If
t.Value = CLng(t.Value) Or CLng(2 ^ 7)
t.Write
On Error Goto 0
HMIRuntime.Trace writes to the WinCC diagnostic window (apdiag.exe) and to the WinCC_Sys_<XX>.log file on disk, depending on the project configuration.
9.2 OPC quality codes
tag.QualityCode returns the standard OPC HDA quality code. The values relevant to bit-manipulation logic are:
| Code | Name | Meaning |
|---|---|---|
| 0xC0 (192) | Good | Value is current and valid |
| 0x40 (64) | Uncertain | Value is stale or substituted |
| 0x00 (0) | Bad | Source unavailable; do not act on value |
Skip the bit operation when quality is not Good to avoid writing garbage to the PLC.
9.3 Performance and update cycles
Each Read and Write call crosses the tag-caching layer and, for PLC tags, the configured connection. Recommended practices:
- Resolve the tag object once per script invocation; do not re-call
HMIRuntime.Tags(...)inside a loop. - Batch multiple bit changes into a single mask and a single
Writeinstead of issuing one write per bit. - Trigger the script on operator action (button click, value change) rather than on a high-frequency cycle.
- For periodic refreshes, prefer the standard update cycle over a polled script to avoid double-fetching.
10. WinCC Unified Equivalents, Troubleshooting, and Verification
10.1 WinCC Unified (JavaScript)
WinCC Unified Comfort Panels and WinCC Unified PC Runtime use JavaScript (ECMAScript 2020+) instead of VBScript. The native |, &, ^, and << operators are available, and the tag API is different:
let tag = Tags("MyFlags");
tag.Read();
tag.Value |= (1 << 7); // set bit 7
tag.Write();
The remainder of the script (toggle, clear, multi-bit mask) is the same with |=, &= ~, and ^=. The HMIRuntime object is still present in Unified, but tag access is preferred through the Tags() global function for clarity and IDE auto-completion.
10.2 Troubleshooting matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| Click does nothing; no error in script log | Event is wired to a C-action, not a VBS action | Re-wire the Click event to a VBScript action |
| Runtime error "Object required: HMIRuntime" | Script runs in WinCC Runtime Advanced, which lacks HMIRuntime
|
Port to Unified, or upgrade the panel to Professional |
| Bit does not change on PLC side | Tag is configured as read-only, or PLC area is write-protected | Check the connection's "Write" right in the tag properties |
| Bit always reads back as 0 | Tag is signed (INT/DINT) and the high bit is the sign bit | Reconfigure the tag as DWORD; do not bit-mask signed tags |
| High bits (≥24) write 0 silently | Missing CLng() coercion; Double precision loss |
Wrap the 2 ^ n expression with CLng()
|
| MsgBox not visible on Runtime PC | Runtime is on a different session/terminal server | Use HMIRuntime.Trace or an internal tag for cross-session feedback |
"Type mismatch" on Or
|
tag.Value returned a String subtype |
Coerce: CLng(tag.Value & "") or fix the tag data type |
| Tag name "not found" error | Tag is project-qualified; use full path | Use HMIRuntime.Tags("Picture::MyFlags") or the global prefix |
10.3 Verification checklist
- Open the WinCC project in runtime, click the button once, and verify the bit changes from 0 to 1 in the HMI tag diagnostics view.
- Click the button a second time and confirm the bit returns to 0 (toggle) or stays at 1 (set) depending on the operator you chose.
- In the PLC online view, watch the addressed data block or output word and confirm the same bit toggles there within one update cycle.
- Open
apdiag.exeand confirm notag.Errorlines are logged during the operation. - Disconnect the PLC connection; verify the script skips the write and logs a "Bad quality" trace line instead of crashing.
- Reconnect the PLC; verify the script resumes normal behavior without restarting the runtime.
10.4 Reference table: bit index → mask → hex
| Bit | Mask (dec) | Mask (hex) |
|---|---|---|
| 0 | 1 | 0x00000001 |
| 1 | 2 | 0x00000002 |
| 2 | 4 | 0x00000004 |
| 3 | 8 | 0x00000008 |
| 4 | 16 | 0x00000010 |
| 5 | 32 | 0x00000020 |
| 6 | 64 | 0x00000040 |
| 7 | 128 | 0x00000080 |
| 8 | 256 | 0x00000100 |
| 15 | 32 768 | 0x00008000 |
| 16 | 65 536 | 0x00010000 |
| 23 | 8 388 608 | 0x00800000 |
| 24 | 16 777 216 | 0x01000000 |
| 31 | 2 147 483 648 | 0x80000000 |
For bit indices 24–31 always wrap the mask with CLng() to avoid the silent Double-precision collapse described in section 9.
FAQ
How do I set a single bit in a DWORD tag from a WinCC VBScript button click?
Resolve the tag with Set t = HMIRuntime.Tags("MyFlags"), call t.Read, assign t.Value = CLng(t.Value) Or CLng(2 ^ bitIndex), and call t.Write. Wrap the script in a reusable SetBitInTag tagName, bitNum subroutine for project-wide reuse.
Why does VBScript not have bitwise operators like C does?
VBScript 5.x is a high-level scripting language that exposes only the four arithmetic bitwise operators And, Or, Xor, and Not. There is no shift, no unsigned right-shift, and no compound assignment. The language is described in Microsoft Learn: Using VBScript and its lifecycle in Wikipedia: VBScript.
Why is my high bit (≥24) writing as 0 even though my mask is correct?
Without CLng() the 2 ^ n expression promotes to a Double, and Double precision runs out at bit 31. Force 32-bit integer arithmetic with CLng(2 ^ n) for any mask that equals or exceeds 2^24 (16,777,216).
Can I bit-mask a signed INT or DINT tag?
Yes, but treat bit 31 (the sign bit) with care. For simple boolean flags in the lower 31 bits the same scripts work unchanged. For status words that encode negative values, prefer a DWORD or LWORD tag to avoid sign-extension surprises.
What is the difference between WinCC V7.x, WinCC Professional, and WinCC Unified for this task?
WinCC V7.x and TIA WinCC Professional use VBScript with the HMIRuntime object described in this article. WinCC Unified Comfort Panels and Unified PC Runtime use JavaScript and the global Tags() function with native |=, &=, and ^= operators. The algorithm is identical; only the language and tag API differ.