Troubleshooting WinCC Combobox Failure Caused by C Scripts

David Krause13 min read
SiemensTroubleshootingWinCC
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

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 OnPropertyChanged callback reaches the C-script editor, or the callback reaches it but OpenPicture() 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 C while loop 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:

  1. The do-while loop has no upper bound. If the tag never leaves the threshold, the script runs forever.
  2. 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.
  3. The dispatcher cannot deliver any queued VBScript or C-script event to any other script while the current gscAction is in the loop.
  4. 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 If chain 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:

  1. Open the target picture in Graphics Designer.
  2. From the Object Palette, choose Smart Objects → Application Window.
  3. 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).
  4. 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:

  1. Compile and download the project. In the WinCC Explorer, verify the build completes with zero C-script and zero VBScript compile errors.
  2. Activate the project. Open the picture that contains the ComboBox.
  3. Confirm the GSC Diagnostics window shows gscAction cycling at exactly 1 s, with running toggling to idle each cycle.
  4. Click the ComboBox and select a different entry. Verify that the base picture changes within < 200 ms (well under one timer cycle).
  5. Toggle the cyclic timer off via the GSC Diagnostics or via a project-level switch tag. Verify that ComboBox selection still drives BaseScreenName immediately.
  6. Toggle the cyclic timer back on. Verify that ComboBox selection continues to drive BaseScreenName without lag or loss.
  7. Type-check the comparison: place MsgBox TypeName(Item.SelIndex) in a one-shot test script and confirm Long.
  8. Inspect the GSC log for any Watchdog timeout entries. None should appear.
  9. 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.Items replaces ScreenItems.
  • 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) and SelectedText (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.

Back to blog