1. WinCC Scripting Architecture Overview
Siemens WinCC (SIMATIC WinCC V7.x and the TIA Portal WinCC Professional / Comfort / RT Advanced variants) exposes two distinct scripting engines to the developer:
- VBScript (VBS) — interpreted, late-bound, and the only language allowed in user-defined menus, dynamic dialogs, and the global actions configured in the Graphics Designer that must reach user-interface elements.
- ANSI-C — compiled, strongly typed, and the language used for picture-specific C actions, global C actions, and background polling tasks where predictable execution timing matters.
The two engines are not interchangeable. Menu editors, custom menu entries, and standard dynamic dialogs only accept VBScript, while some background triggers and project-wide hooks perform far better in C. Understanding this split is the foundation for resolving the three recurring issues in WinCC projects: stopping the Runtime from a menu, opening a picture from a menu, and reading/writing tags from a C script.
2. VBScript vs ANSI-C: Where Each Language Runs
| Editor / Trigger | VBScript allowed? | C allowed? | Notes |
|---|---|---|---|
| User-defined menu (Menu → Configure) | Yes | No | Hard limit in Graphics Designer |
| Button mouse action | Yes | Yes | Either engine selectable |
| Picture events (Open / Close) | Yes | Yes | Picture-level hooks |
| Global action (cyclic / tag trigger) | Yes | Yes | Background processing |
| Dynamic dialog | Yes (formula) | No | Direct tag / expression |
| Tag logging / alarm scripting | No | Yes | C is the only choice |
When a developer wants a clickable menu entry to do anything beyond toggling a tag through a dynamic dialog, VBScript is the only path. Trying to paste a C block into a menu property produces a compile error such as "Function expected / Unknown identifier". The workaround is therefore to place all logic in VBScript, or to use VBScript to invoke a compiled C function via the WinCC project DLL.
3. Shutting Down WinCC Runtime from a Menu
The standard WinCC RT shutdown call from VBScript is the HMIRuntime.Stop method, available since WinCC V7.0 SP3. Place the snippet below on the Mouse click event of the custom menu item:
' Menu → Configure → your custom entry → Mouse click (left)
' Triggers a clean shutdown of WinCC Runtime on the local station
Sub OnClick(ByVal Item)
Dim answer
answer = MsgBox("Shut down WinCC Runtime?", vbYesNo + vbQuestion, "Confirm Exit")
If answer = vbYes Then
HMIRuntime.Stop
End If
End Sub
For projects where the user must be authenticated before the Runtime can be closed, gate the call on a WinCC user level:
Sub OnClick(Byval Item)
If HMIRuntime.Authorization.Check("RT_Stop") = False Then
MsgBox "Insufficient privileges to stop Runtime.", vbCritical
Exit Sub
End If
HMIRuntime.Stop
End Sub
For passivation-style shutdown (close the Runtime but keep the project in Configuration mode), use HMIRuntime.DeactivateRT. The full method list is in the WinCC V7.5 SP2 manual "Working with WinCC — VBScript", entry ID 109973200.
3.1 External Shutdown with CCStartStop.exe
When a separate tool (alarm dispatcher, third-party HMI scheduler, service-mode launcher) must stop the Runtime, use the bundled CCStartStop.exe located at %ProgramFiles%\Siemens\Automation\WinCC\bin\. The executable accepts the parameters /start, /stop, and /activate:
# Stop Runtime from a service or scheduled task
"C:\Program Files\Siemens\Automation\WinCC\bin\CCStartStop.exe" /stop
# Start Runtime back up (project on same station)
"C:\Program Files\Siemens\Automation\WinCC\bin\CCStartStop.exe" /start /project:MyProject
Return codes: 0 = success, 1 = project not found, 2 = access denied, 3 = Runtime already in requested state. Always run the executable under the same Windows account that owns the WinCC project to avoid error 2.
4. Opening a PictureScreen from a Custom Menu
The C-equivalent SSMOpenScreen cannot be called from a menu because menus reject C. The VBScript equivalent is HMIRuntime.BaseScreenName = "MyPicture.PDL" (for the base screen) or HMIRuntime.ActiveScreen for picture windows. For a direct screen change with a return-to-previous stack push, use HMIRuntime.Trace + ScreenItems("ScreenWindow").Screen = "...":
' Menu entry → Mouse click → open a picture in the primary screen window
Sub OnClick(Byval Item)
HMIRuntime.BaseScreenName = "Overview.PDL"
End Sub
' Open in a named picture window (most common in modern projects)
Sub OnClick(Byval Item)
Dim scr
Set scr = HMIRuntime.ScreenItems("MainPictureWindow")
scr.Screen = "Detail_1.PDL"
End Sub
Picture names are case-sensitive in WinCC V7 and TIA WinCC Professional; overview.pdl will not resolve to Overview.PDL. The same restriction applies to C code (see Section 5). If the picture must be loaded with a tag-prefix override (multi-language, multi-client), use the full path:
HMIRuntime.Trace = "::PROJECT::PlantA::Overview.PDL"
4.1 Why C Scripts Are Blocked in Menus
Menu definitions live in the Graphics Designer and are serialized as text into the project database *.PNL and *.MCP files. WinCC parses these files with a VBScript engine only; C source requires a separate compile step that the menu loader does not invoke. The behavior is unchanged from WinCC V6.2 through V8.0.
5. Reading and Writing Tags from C Script
The single most common source of "the C script generates errors" messages is a missing include and the wrong tag-name format. A minimal, correct C script that reads a process tag looks like this:
#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
double dValue;
/* Always call the Get*Wait variant when the script runs
from a button / menu because the asynchronous variant
may return 0 on the first poll. */
dValue = GetTagDoubleWait("PlantA_Temperature");
if (dValue > 80.0) {
SetTagDouble("PlantA_AlarmHigh", 1.0);
} else {
SetTagDouble("PlantA_AlarmHigh", 0.0);
}
}
5.1 Header and Type Rules
-
apdefap.hresolves allGetTag*,SetTag*, andDM_*prototypes. Skipping it produces the linker error "unresolved external symbol GetTagDouble". - Tag name is a plain string in C. Do not prefix with
\or::— those prefixes are VBScript-only. - Match the data type:
GetTagDoublefor floats,GetTagWordfor unsigned 16-bit,GetTagBitfor booleans,GetTagCharfor raw byte,GetTagStringfor text.
5.2 Internal vs External Tags
External (PLC) tags read through the configured channel driver without extra work. Internal tags (WinCC-only) require a WinCC variable to exist in the Tag Management; if the tag is missing, the call returns 0 (numeric) or an empty string and sets the system variable @SR_GetTagError to 1:
/* Best-practice read with error guard */
#include "apdefap.h"
void ReadAndCheck(void)
{
DWORD dwErr;
double v = GetTagDoubleWaitEx("PlantA_Temperature", &dwErr);
if (dwErr != 0) {
printf("Tag read failed, code %u\n", dwErr);
return;
}
/* process v */
}
Common GetTagDoubleWaitEx error codes (hex):
| Hex code | Meaning | Remediation |
|---|---|---|
| 0x8004xxxx | Tag not found in DM | Add the tag in Tag Management; check spelling and case |
| 0x8005xxxx | Wrong data type | Use the matching type-specific Get* call |
| 0x8006xxxx | Connection lost to PLC | Check channel diagnostic, CP, network |
| 0x8007xxxx | Access denied (no authorization) | Configure user level on the WinCC user |
5.3 Address Syntax for Internal Tags
Internal tags behave like PLC tags from the C API. The address column in Tag Management is irrelevant for C; the WinCC-side name is what the script passes. To differentiate WinCC-side limits (e.g. 32.767 for 16-bit signed) the script must enforce them itself, or define a structure tag with a matching data type.
6. Common C Script Compilation and Runtime Errors
| Symptom | Root cause | Fix |
|---|---|---|
| Unresolved external symbol GetTagDouble |
apdefap.h not included |
Add #include "apdefap.h" at the top |
| Function 'GetTagBit' not found | Header search path missing | Project → Properties → Include paths must contain applib and library
|
| Script returns 0 but VBScript returns the real value | Used GetTagDouble (async) before first poll |
Use GetTagDoubleWait on first call |
| Tag not found on a tag that exists in Tag Management | Case mismatch; trailing space; project prefix missing | Match the string exactly; check @PROJECT_PREFIX@
|
Compiler complains about lpszPictureName
|
Wrong function signature for a button event | Use the standard 3-arg signature shown in Section 5 |
| Runtime: Stack overflow after script edit | Infinite recursion between two C actions | Audit call graph; introduce a guard tag |
| Script does nothing on a menu | Menus reject C | Move logic to VBScript, or to a button |
7. C Script API Quick Reference
| Operation | C call | Return / side effect |
|---|---|---|
| Read double, blocking | double GetTagDoubleWait(const char*); |
Returns value; 0 on error |
| Read double, async | double GetTagDouble(const char*); |
Returns 0 on first poll |
| Read with code | double GetTagDoubleWaitEx(const char*, DWORD*); |
Sets *pdwError
|
| Write double | BOOL SetTagDouble(const char*, double); |
TRUE on success |
| Read bit / word |
BOOL GetTagBit, WORD GetTagWord
|
Matches type |
| Read string (max 256) | BOOL GetTagString(const char*, char*, DWORD); |
Copies into buffer |
| Open picture in window | BOOL SSMOpenScreen(LPCTSTR pic, LPCTSTR screen, LPCTSTR window); |
From C only |
| Trigger screen change | BOOL SSMChangeScreen(LPCTSTR pic, LPCTSTR screen, LPCTSTR window); |
Same |
| Stop Runtime | BOOL DeactivateRT(void); |
Use sparingly, no confirm |
| Internal tag create / set |
DM_CREATE_VAR, DM_SET_VALUE
|
For runtime-created tags |
The full API surface is documented in WinCC V7.5 SP2 — ANSI-C for Creating Functions and Actions, manual entry ID 109973200 at the Siemens Industry Online Support portal.
8. Hybrid Strategies: C Inside VBScript Menus
When the logic must run in C (deterministic timing, complex math, OS-level calls) but the trigger is a menu, expose the C function as a project DLL and call it from VBScript via WinCC\_COM_ style wrappers or the newer HMIRuntime.Scripting bridge. The cleanest pattern is:
- Build a C DLL with a flat C ABI:
__declspec(dllexport) void __cdecl ShutdownRT(void); - Register the DLL in the project directory
<Project>\library\. - Declare it in VBScript:
Declare Sub ShutdownRT Lib "MyProjectExt.dll" () - Call from the menu:
Call ShutdownRT()
' Menu entry VBScript wrapper for a C DLL
Declare Sub ShutdownRT Lib "MyProjectExt.dll" ()
Sub OnClick(Byval Item)
If HMIRuntime.Authorization.Check("RT_Stop") = False Then Exit Sub
Call ShutdownRT()
End Sub
This pattern keeps the menu VBScript-only (legal) while still benefiting from C execution. It also avoids the legacy MScriptControl route, which is 32-bit only and unsupported on WinCC V8 x64 hosts.
9. Verification, Diagnostics, and Logging
After deploying a script, follow this checklist:
- Open WinCC Explorer → Tools → Status of Drivers and Connections; verify the tag in question is OK, not Disconnected.
- Add
printf/sysprintfat strategic points; output is mirrored to the APDIAG directory inDiagnosticsfileWinCC_Sys_..log - For VBScript, set
HMIRuntime.Trace = "MyTag='" & value & "'"and view in the diagnostic screen of the Graphics Designer. - From the WinCC RT menu, Tools → Debug Scripts shows the last error code and the source line number when Project Properties → Options → Activate script debugger is enabled.
- Compile the C script with the Compile button on the C editor toolbar. Compile errors appear with a Click for details hyperlink that opens the
apdiag.txtlog.
%ProgramData%\Siemens\Automation\WinCC\WinCC RT <N>\WinCC_Sys.log. Tail that file with PowerShell Get-Content -Wait during commissioning for live traces.10. Version Notes and Migration
| WinCC version | C-API behavior | VBScript behavior | Notes |
|---|---|---|---|
| V7.0 / V7.0 SP3 | Classic Get* / Set* | HMIRuntime.Stop, Authorization | Stop added in SP3 |
| V7.3 | Adds *WaitEx variants |
Adds TagSet collection |
Recommended baseline |
| V7.4 SP1 | Async I/O for big tags | Script debugger stabilized | |
| V7.5 / V7.5 SP2 | 64-bit aware | Improved object model | Latest V7 branch |
| TIA WinCC Professional V16–V18 | Different namespace | Use HMIRuntime from V17+ |
Cross-load only via export |
| WinCC Unified (V17+) | JavaScript replaces both | No VBScript or C | No migration of VBS/C as-is |
For WinCC Unified (the Web-based successor), both C and VBScript are replaced by JavaScript; the menu restriction is moot because menus are now declarative widgets. The migration utility shipped with V17 (and refined in V18) rewrites simple VBScript into JS but cannot port the C actions — those must be re-implemented as user-defined functions in JS.
11. Practical Decision Flowchart
Use the flow below when you are unsure which language and which API to call:
12. Field-Commissioning Notes
-
Numeric locale. In a German-locale project, the VBScript call
CDbl("1,5")succeeds; the C callatof("1,5")returns 1.0 because C uses the C-locale. Always pass numeric values directly from the tag, not from text input. -
Authority check. Always wrap
HMIRuntime.StopinHMIRuntime.Authorization.Check. Operators have been known to call the exit menu accidentally. -
Redundancy. On a redundant WinCC pair, the menu-driven stop should also call
HMIRuntime.Traceto log the user and timestamp; the partner server will take over and the local stop may otherwise be invisible to the audit trail. -
Service-mode Runtime. When WinCC RT runs as a Windows service,
CCStartStop.exestill works but the calling script must be elevated. The service wrapper logs return codes toWinCC_RT_Service.log. -
Watchdog tags. Create a heartbeat tag (e.g.
RT_Heartbeat) written by a 1-second cyclic C action. If the tag stops changing, the alarm system can flag a frozen Runtime even when the screen looks healthy.
Why does my menu click do nothing when I paste a C script there?
WinCC menus only accept VBScript. C scripts are silently rejected at parse time. Move the logic to a button, wrap the C in a DLL and call it via Declare Sub … Lib "…" from the menu's VBScript, or rewrite the logic in VBScript directly.
How do I stop WinCC Runtime from a custom menu entry?
Place HMIRuntime.Stop on the menu item's Mouse click event, ideally gated by an authorization check. For external callers use CCStartStop.exe /stop from the WinCC bin directory and run it under the same Windows account as the project.
Why does my C script get "unresolved external symbol GetTagDouble"?
The mandatory header apdefap.h is missing. Add #include "apdefap.h" at the top of the action. The header pulls in all GetTag*, SetTag*, and DM_* prototypes that the C compiler otherwise cannot resolve.
My C script returns 0 but VBScript returns the correct value. Why?
You are calling the asynchronous variant GetTagDouble on a script that runs before the first poll of the tag. Use GetTagDoubleWait or GetTagDoubleWaitEx for the first read so the script blocks until the driver has a value.
Can I use the same C code in WinCC V7 and TIA Portal WinCC Professional?
No. The C-API namespaces and project structures differ; the V7 APIs live in apdefap.h from the V7 install, while TIA WinCC Professional uses the SIMATIC Script runtime with a different API. Plan a rewrite when migrating to TIA WinCC, and a complete re-implementation in JavaScript for WinCC Unified (V17+).