Problem Overview
WinCC V7 graphics designers rely on the ComboBox control to provide operators with a single-click mechanism for switching between base pictures, faceplates, or trend views. A typical implementation pairs the ComboBox SelectionChanged / OnPropertyChanged event with an OpenPicture() call (C-script) or with HMIRuntime.BaseScreenName (VBScript). When the ComboBox is paired with a separate cyclic C-script scheduled on a 1-second timer that also calls GetTagFloat / SetTagDouble, the ComboBox frequently stops responding to user input. Selection changes are silently dropped, the dropdown still opens, but no picture change is executed, and no GSC error is logged in the standard output window.
The failure presents the following field-proven symptoms:
- ComboBox dropdown list opens normally and selection highlighting works.
- On click, no
OnPropertyChangedcallback reaches the C-script editor, or the callback reaches it butOpenPicture()never executes. - The cyclic timer script continues running every second without failure.
- Disabling the cyclic timer immediately restores ComboBox navigation.
- Enabling the timer again causes the regression to return.
This article walks through the root cause analysis, the runtime model behind the failure, the data-type corrections required, and the rewrite procedures that resolve the issue. Every recommendation is tied back to the WinCC V7 Scripting Reference and the SIMATIC WinCC V7.4 System Manual.
Root Cause Analysis
Three independent defects converge in this scenario. Each defect on its own can degrade a ComboBox; together they create a hard RT-block that prevents any event-driven script from executing while the cyclic timer is armed.
| # | Root Cause | Mechanism | Visible Symptom |
|---|---|---|---|
| 1 | Blocking do-while loop in gscAction
|
The cyclic script enters a non-terminating loop while waiting for the current tag to leave a threshold band. The script never returns; the WinCC RT dispatcher treats gscAction as still running. |
ComboBox selection is queued but never dispatched. The GSC Diagnostic window shows the script as running indefinitely. |
| 2 | Data-type mismatch in SelIndex comparison |
Item.SelIndex is a VARIANT of subtype VT_I4 (Long). Comparing it with a quoted numeric literal (= "1") forces an implicit BSTR conversion that always evaluates false. |
Every If branch is skipped; HMIRuntime.BaseScreenName is never assigned. |
| 3 | Cyclic 1-second timer monopolizing the dispatcher | Even after the loop is fixed, a 1 s schedule that performs synchronous tag polling can starve the dispatcher during heavy operator interaction, delaying but not blocking the event. | Intermittent picture changes; laggy dropdown; event scripts run 1–2 s late. |
The fix is a sequence: (a) eliminate the blocking loop, (b) remove quotation marks from the numeric literals, (c) lower the timer cadence or move polling to a scheduled tag-log trigger instead of a scripting timer.
WinCC V7 Scripting Runtime Model
WinCC V7 supports two distinct scripting languages in the runtime: VBScript and ANSI-C. Both are dispatched from the same graphics-runtime thread, but each is hosted in its own interpreter instance. The WinCC V7 Scripting Reference describes the dispatch rules:
- VBScript events are bound at design time through the object's Events tab and run synchronously when the runtime raises the event. They execute to completion before the dispatcher returns to the message loop.
- ANSI-C global scripts (
gscAction) are scheduled by a configurable timer. Each invocation must complete within the configured time slice. A script that overruns the slice is logged and aborted by the watchdog, but the runtime does not preempt a script that has entered a tight Cwhileloop with no system call. The dispatcher treats the script as still running until it returns.
According to the SIMATIC WinCC V7.4 Scripting Reference (VBS, ANSI-C, VBA), every ANSI-C function called from a cyclic timer is expected to be cooperative: it must perform a bounded amount of work and return. A while / do-while construct that depends on an external tag changing to terminate violates this contract and produces the field-observed behavior.
Important: The WinCC V7 RT thread that hosts ANSI-C global scripts is the same dispatcher thread that processes VBScript events. A non-returning gscAction blocks all event-driven scripts, including ComboBox OnPropertyChanged, until the watchdog terminates it (default 5 s timeout in WinCC V7.4 SP1).
Data Type Mismatch: Long vs String
The ComboBox control exposes two key properties on the scripting side:
| Property | VBScript Return Type | ANSI-C Equivalent | Description |
|---|---|---|---|
SelIndex |
Long (VT_I4) |
GetLinkedProperty(lpszPictureName, lpszObjectName, "SelIndex") → long
|
Zero-based numeric index of the selected item. |
SelText |
String (BSTR) |
GetLinkedProperty(...,"SelText") → char*
|
Display string of the selected item. |
Text |
String (BSTR) | GetPropText(...,"Text") |
Editable text when DropDownStyle = Editable. |
The most common defect in this scenario is comparing SelIndex with a quoted numeric literal:
If ScreenItems("Combobox2").SelIndex = "1" Then ' WRONG: forces BSTR compare
Because SelIndex is a Long, the right-hand side is converted to Long for the comparison. The string "1" converts to 1, so this case actually works. The dangerous case is when the user writes:
If ScreenItems("Combobox2").SelIndex = "01" Then ' WRONG: "01" converts to 1, but visually mismatched
If ScreenItems("Combobox2").SelIndex = "two" Then ' WRONG: "two" -> 0, branch never taken
Whenever a numeric literal is wrapped in quotes, the comparison may succeed by accident, but it is not type-safe. The recommended pattern is to use unquoted numeric literals and to verify the type before any logic executes:
' Add at the top of the event script
MsgBox TypeName(ScreenItems("Combobox2").SelIndex) ' -> "Long"
' Correct comparison
If ScreenItems("Combobox2").SelIndex = 1 Then
HMIRuntime.BaseScreenName = "SM1"
End If
For the C-script side, the equivalent is to use GetPropWord / GetPropLong and compare against an int constant:
long idx;
idx = GetPropLong(lpszPictureName, lpszObjectName, "SelIndex");
switch (idx) {
case 0: OpenPicture("SM1"); break;
case 1: OpenPicture("SM2"); break;
case 2: OpenPicture("SMA4"); break;
case 3: OpenPicture("SMA5"); break;
case 4: OpenPicture("SMA6"); break;
}
The do-while Loop Trap and RT Deadlock Risk
The original ANSI-C global script attempts to wait for an external tag to leave a threshold band before continuing:
current = GetTagFloat("Current_a_1");
if (current > 0.5) {
SetTagDouble("Control_Tag", 295);
do {
current = GetTagFloat("Current_a_1");
} while (current > 0.5); // <-- BLOCKING
}
This construct is unsafe in a cyclic timer because:
- The
do-whileloop has no upper bound. If the tag never leaves the threshold, the script runs forever. - The loop performs no system call that would yield to the dispatcher. It is a tight
GetTagFloat→ compare → branch loop that consumes 100 % of the RT thread. - The dispatcher cannot deliver any queued VBScript or C-script event to any other script while the current
gscActionis in the loop. - When the watchdog eventually times out, the abort is logged but the next invocation of the timer starts a fresh blocking loop, re-creating the issue.
The correct pattern is to remember the desired state and let the next cycle of the timer apply it when the precondition is satisfied. A single-pass state machine is preferred:
static int g_target = 0;
int gscAction(void) {
float current;
int desired;
current = GetTagFloat("Current_a_1");
if (current > 0.5) desired = 295;
else if (current < 0.5) desired = 381;
else desired = 381; // exact 0.5 case
if (desired != g_target) {
SetTagDouble("Control_Tag", desired);
g_target = desired;
}
return 0;
}
This script runs in O(1) per cycle, never blocks, and is fully cooperative with the dispatcher. The equivalent VBScript scheduled task is equally simple:
Sub OnTimer()
Dim cur : cur = HMIRuntime.Tags("Current_a_1").Read
If cur > 0.5 Then
HMIRuntime.Tags("Control_Tag").Write 295
Else
HMIRuntime.Tags("Control_Tag").Write 381
End If
End Sub
Rewriting the C Script Without Blocking Loops
For the OpenPicture() side of the ComboBox, the cleanest C-script pattern is a switch on the cached index. Cache the index in a project-wide tag so that the timer script can drive picture changes from the polling context, while the ComboBox only updates the index:
// ComboBox event: OnPropertyChanged (C-script)
void OnPropertyChanged(char* lpszPictureName, char* lpszObjectName,
char* lpszPropertyName, long value)
{
// 'value' is the new SelIndex, already a Long
switch (value) {
case 0: SetTagWord("Nav_Index", 0); break;
case 1: SetTagWord("Nav_Index", 1); break;
case 2: SetTagWord("Nav_Index", 2); break;
case 3: SetTagWord("Nav_Index", 3); break;
case 4: SetTagWord("Nav_Index", 4); break;
default: break;
}
}
// Timer script: gscAction (1 s)
int gscAction(void) {
static unsigned short lastIdx = 0xFFFF;
unsigned short idx;
idx = GetTagWord("Nav_Index");
if (idx == lastIdx) return 0; // no change
lastIdx = idx;
switch (idx) {
case 0: OpenPicture("SM1"); break;
case 1: OpenPicture("SM2"); break;
case 2: OpenPicture("SMA4"); break;
case 3: OpenPicture("SMA5"); break;
case 4: OpenPicture("SMA6"); break;
}
return 0;
}
This architecture separates intent (the ComboBox writes the navigation index) from action (the timer script performs the picture change). It is robust against dispatcher contention because the event-side script runs in O(1) and the timer side performs at most one OpenPicture per state change.
VBScript Alternative: Item.SelText and BaseScreenName
If the application does not require C-script for the navigation logic, VBScript is the recommended path. VBScript is dispatched synchronously from the graphics thread and is not subject to the cyclic timer watchdog. The single-line pattern is the cleanest:
Sub SelText_Change(ByVal Item)
HMIRuntime.BaseScreenName = Item.SelText
End Sub
This works only when the ComboBox entries are populated with the actual picture names (SM1, SMA4, …). The selection change automatically writes the chosen picture name into BaseScreenName, and WinCC raises the picture-change event. The benefits are:
- No
Ifchain required. - No
ScreenItems(...)lookup required. - Works for any number of entries without code changes.
For the case where the entries are display labels rather than picture names, the VBScript equivalent of the original C-script is:
Sub SelText_Change(ByVal Item)
Select Case Item.SelIndex
Case 0 HMIRuntime.BaseScreenName = "SM1"
Case 1 HMIRuntime.BaseScreenName = "SM2"
Case 2 HMIRuntime.BaseScreenName = "SMA4"
Case 3 HMIRuntime.BaseScreenName = "SMA5"
Case 4 HMIRuntime.BaseScreenName = "SMA6"
End Select
End Sub
This should be entered on the ComboBox Events tab under Miscellaneous → Selected text, as documented in the WinCC V7 Graphics Designer manual.
Optimal Object References: Item vs ScreenItems
Inside an object-bound event script (any language), the implicit Item parameter always refers to the object that owns the event. Using ScreenItems("Combobox2") performs an additional lookup in the screen-items collection at runtime. The recommended convention, documented in the WinCC V7 Scripting Reference, is to use Item whenever the script is bound to an event of that object:
| Pattern | Performance | Readability | Portability |
|---|---|---|---|
Item.SelIndex |
Best — direct member access | Best — context is clear | Best — rename-safe |
ScreenItems("Combobox2").SelIndex |
Slower — collection lookup per call | Fragile — rename breaks it | Worst — requires constant string match |
HMIRuntime.ActiveScreen.ScreenItems("Combobox2").SelIndex |
Worst — double indirection | Verbose | Acceptable for cross-screen reference |
For the ComboBox itself, the additional gain from using Item.SelText directly is that the display string is preserved across localization changes — no numeric mapping table needs to be maintained.
Debugging with GSC Diagnostics and printf
WinCC V7 ships a built-in diagnostic window that exposes the state of every scheduled global script. To enable it:
- Open the target picture in Graphics Designer.
- From the Object Palette, choose Smart Objects → Application Window.
- Select Global Script → GSC Diagnostics and place the window in a non-operational corner of the screen (typically a hidden overlay popped up with a hotkey).
- Compile and download to the RT.
The GSC Diagnostics window displays, in real time, the execution state of every gscAction function, its last return code, the number of times it has run, and any printf output. Add printf statements liberally during commissioning:
printf("gscAction enter, idx=%d, current=%.3f\n", GetTagWord("Nav_Index"), GetTagFloat("Current_a_1"));
If the diagnostic window shows gscAction stuck on running, the blocking loop is the cause. If it shows the script returning normally but the ComboBox still does not respond, the bug is on the event side (data-type mismatch or wrong event hookup).
Tip: Use SetTagWord("DBG_GscRunning", 1) at the top of gscAction and SetTagWord("DBG_GscRunning", 0) at the bottom. Then read the tag from WinCC TagSpy or from a faceplate to confirm the script reaches its end within the dispatcher slice.
Verification Procedure
After applying the rewrite, validate the fix in this sequence. Each step is observable from the WinCC RT without restarting the runtime:
- Compile and download the project. In the WinCC Explorer, verify the build completes with zero C-script and zero VBScript compile errors.
- Activate the project. Open the picture that contains the ComboBox.
-
Confirm the GSC Diagnostics window shows
gscActioncycling at exactly 1 s, with running toggling to idle each cycle. - Click the ComboBox and select a different entry. Verify that the base picture changes within < 200 ms (well under one timer cycle).
-
Toggle the cyclic timer off via the GSC Diagnostics or via a project-level switch tag. Verify that ComboBox selection still drives
BaseScreenNameimmediately. -
Toggle the cyclic timer back on. Verify that ComboBox selection continues to drive
BaseScreenNamewithout lag or loss. -
Type-check the comparison: place
MsgBox TypeName(Item.SelIndex)in a one-shot test script and confirm Long. - Inspect the GSC log for any Watchdog timeout entries. None should appear.
- Stress-test by changing ComboBox selection 20 times in 10 s. All 20 changes must result in a picture change; the timer must continue to fire every 1 s in parallel.
Field-Proven Pitfalls Summary
| Pitfall | Detection | Resolution |
|---|---|---|
do-while waits on external tag |
GSC shows script "running" indefinitely | Replace with single-pass state machine |
| Quoted numeric literal in VBS comparison | Branch never taken, silent failure | Use unquoted numeric literal or CLng()
|
| ComboBox entries not equal to picture names | Picture name mismatch error | Either rename entries or use Select Case SelIndex
|
| Cyclic timer set to 100 ms | Dispatcher starvation, laggy events | Increase to 500 ms–1 s or move to scheduled tag |
| ComboBox event bound to wrong property | Event never fires | Bind to Selected text under Miscellaneous |
| Mixing VBA and VBS in the same project | Compile error | Use VBS for runtime, VBA only for engineering automation |
Reference: The WinCC V7 Scripting Reference notes that VBA is intended for engineering automation (e.g., bulk object creation in Graphics Designer), while VBScript and ANSI-C are the two runtime-supported languages. Mixing VBA code in a runtime event script will fail to compile.
Extension to WinCC Unified / TIA Portal
The same architectural principles apply to WinCC Unified (TIA Portal V17 and later), although the API surface differs:
- JavaScript replaces VBScript as the primary event language;
Screen.ItemsreplacesScreenItems. - C-scripts are not used in WinCC Unified; instead, scheduled tasks are configured as Scheduled tasks on the HMI device.
- The ComboBox exposes
SelectedIndex(zero-based integer) andSelectedText(string).
The SIMATIC WinCC Unified Programming and Operating Manual documents the new model. The single-line pattern analogous to HMIRuntime.BaseScreenName = Item.SelText is:
UI.RootWindow.Screen = Item.SelectedText;
FAQ
Why does my WinCC ComboBox stop responding when a cyclic C-script is running?
The cyclic C-script is monopolizing the WinCC V7 dispatcher thread. A blocking do-while or while loop inside gscAction prevents the dispatcher from delivering the ComboBox OnPropertyChanged event. Replace the blocking loop with a single-pass state machine and the ComboBox resumes normal operation.
What is the data type of SelIndex in WinCC ComboBox scripting?
SelIndex is a Long (zero-based numeric). Comparing it with a quoted numeric literal (= "1") works by accident because VBScript coerces the string to a number, but the safe pattern is If SelIndex = 1 Then with unquoted numeric literals. Verify with TypeName(Item.SelIndex) which always returns Long.
Can I use VBA inside a WinCC runtime event script?
No. VBA is reserved for engineering automation in the Graphics Designer (e.g., bulk object creation). Runtime events must use either VBScript or ANSI-C. Combining VBA statements in a runtime VBS event causes a compile error in the WinCC Explorer build.
How do I diagnose a blocked C-script in WinCC V7?
Insert a GSC Diagnostics Application Window from the Smart Objects palette into the target picture. The window shows the live state of every gscAction, its execution count, and its printf output. A script stuck in running state with no return indicates a blocking loop. Add printf statements at strategic points to localize the stall.
Is there a one-line way to bind a ComboBox to picture navigation?
Yes. In VBScript, bind to the Selected text event of the ComboBox and write HMIRuntime.BaseScreenName = Item.SelText. This works whenever the ComboBox entries are populated with the exact target picture names (e.g., SM1, SMA4), eliminating the need for an If chain entirely.