Resolving WinCC C-Script Faceplate Visibility Errors
Siemens WinCC Graphics Designer C-scripts that switch between two picture windows or faceplate instances are a common source of intermittent runtime defects. The most frequent failure mode is an asymmetric control flow in an if / else branch: one branch calls SetVisible(...) while the other does not. When the inactive branch executes, the picture window stays hidden and the operator sees nothing happen, even though the underlying tag value changed correctly. This reference documents the exact bug pattern, the WinCC APIs involved, and a hardened coding practice that prevents the issue class entirely.
1. Problem Description
A WinCC picture is configured with a picture-window object named ObjectControl inside the parent process picture DegermTitle.PDL. A button click triggers the OnClick C-event. The script reads a process bit WholeGrain and, depending on its state, opens either DegermBuhler5Control_a.PDL (bit = 1) or DegermBuhler5Control.PDL (bit = 0) in the picture window. It also writes a tag DegermBuhler_Name used by the child faceplate to look up its configuration block.
Observed behavior:
- Click while
WholeGrain == 0: child picture appears, tag is set, visibility is TRUE. Works. - Click while
WholeGrain == 1:SetPictureNameexecutes, tag is set, but the picture window is still hidden from the previous state. No visible change.
On a second click the picture appears because the previous branch set SetVisible(... TRUE). The defect is therefore intermittent and depends on operator click sequence, which is why it survives factory acceptance testing and surfaces only in production.
2. Root Cause Analysis
The C-script uses a stale-state pattern: the visibility of the picture window is set in the else branch but forgotten in the if branch. WinCC picture windows are stateful graphical objects — once a property is written by a script, the new value persists across subsequent events until the next script overwrites it. A script that only calls SetVisible(...) on the cold path leaves the warm path with whatever visibility the picture window had before the click.
Three contributing factors make this defect easy to write:
-
API symmetry assumption. Engineers often assume that calling
SetPictureNameimplicitly makes the target picture window visible. It does not.SetPictureNameonly changes the PictureName property of the picture-window object; the Visible property is independent and must be set separately. - No compiler warning. WinCC's built-in C compiler (Visual C++ 6.0-derived pre-7.4, MSVC 2008/2010 in WinCC 7.4–7.5) accepts unbalanced property writes without diagnostics. There is no lint pass for "missing setter".
-
No watchdog on hidden picture windows. The WinCC runtime does not raise an alarm or event if a
SetPictureNamecall resolves to a hidden object. The script returnsBOOL TRUEregardless of whether the user can see the change.
SetPictureName() for a user-facing picture window must also call SetVisible(..., TRUE) on the same window, unless a previous code path in the same event has already done so. A function helper is the cleanest enforcement mechanism.
3. The Fixed Script
The minimum-blast-radius fix is to mirror the SetVisible() call in both branches. The corrected script is shown below.
#include "apdefap.h"
#define TAGNAME "DP_WholeCornScaler2E"
void OnClick(char* lpszPictureName,
char* lpszObjectName,
char* lpszPropertyName)
{
int TAG_1;
TAG_1 = GetTagBit("WholeGrain");
if (TAG_1 == 1)
{
SetPictureName("DegermTitle.PDL",
"ObjectControl",
"DegermBuhler5Control_a.PDL");
SetTagChar("DegermBuhler_Name", TAGNAME);
}
else
{
SetPictureName("DegermTitle.PDL",
"ObjectControl",
"DegermBuhler5Control.PDL");
SetTagChar("DegermBuhler_Name", TAGNAME);
}
/* Always make the target window visible. */
SetVisible("DegermTitle.PDL", "ObjectControl", TRUE);
}
Key changes:
- The visibility call is hoisted out of the conditional and runs unconditionally after the picture name and tag have been written. This guarantees the operator sees the result of every click.
- The
SetVisiblecall no longer relies on the previous state of the window, so the script is idempotent. - Picture-name strings are normalized to upper case (
.PDL) on all branches to match the case WinCC stores in the picture tree. Mixed-case strings occasionally resolve correctly and sometimes fail to load depending on the project's PDL cache.
4. Recommended Hardened Version
For projects with three or more faceplate states, prefer a lookup table plus a single setter helper. This eliminates the entire class of "missing setter" defects.
#include "apdefap.h"
#define TAGNAME_WHOLE "DP_WholeCornScaler2E"
#define HOST_PICTURE "DegermTitle.PDL"
#define WINDOW_OBJECT "ObjectControl"
/* Lookup table: bit value -> PDL to load. */
static const char* g_aplFaceplates[] = {
"DegermBuhler5Control.PDL", /* WholeGrain = 0 */
"DegermBuhler5Control_a.PDL" /* WholeGrain = 1 */
};
/* Helper that always performs the visibility write. */
static void ShowFaceplate(const char* pdlName)
{
SetPictureName(HOST_PICTURE, WINDOW_OBJECT, (char*)pdlName);
SetVisible(HOST_PICTURE, WINDOW_OBJECT, TRUE);
}
void OnClick(char* lpszPictureName,
char* lpszObjectName,
char* lpszPropertyName)
{
int idx = GetTagBit("WholeGrain");
if (idx < 0) idx = 0;
if (idx > 1) idx = 1;
SetTagChar("DegermBuhler_Name", TAGNAME_WHOLE);
ShowFaceplate(g_aplFaceplates[idx]);
}
Benefits:
- Adding a third faceplate requires one new array entry, not a new
else ifblock. - The setter helper enforces the property-write pairing in one place.
- Indexing is bounds-checked, eliminating the off-by-one risk when
GetTagBitever returns an unexpected value under a corrupt PLC connection.
5. WinCC C-Script API Reference for the Call Chain
The following tables summarize the APIs touched in this defect class. All four functions are declared in apdefap.h, which WinCC auto-includes for graphics-designer C-scripts when the project option Generate global C functions is enabled.
| Function | Header | Return | Side Effect | Thread |
|---|---|---|---|---|
GetTagBit(const char* tag) |
apdefap.h | int (0/1) or -1 on error | Reads tag, may block briefly on PLC | GUI |
SetTagChar(const char* tag, const char* val) |
apdefap.h | BOOL | Writes string tag, triggers any linked events | GUI |
SetPictureName(const char* pic, const char* obj, const char* pdl) |
apdefap.h | BOOL | Sets the PictureName property; does not change visibility | GUI |
SetVisible(const char* pic, const char* obj, BOOL show) |
apdefap.h | BOOL | Sets the Visible property; can hide a still-loaded picture | GUI |
Notes on each function:
5.1 GetTagBit
Returns the current bit value as an int. A return of -1 indicates a tag-management error (tag not configured, AS connection down, or wrong data type). The WinCC V7.5 manual WinCC Information System > Working with WinCC > ANSI-C function descriptions > Tag functions documents the full error matrix. The error return is not always propagated to the script's BOOL return; downstream code should check for it explicitly as in the hardened version above.
5.2 SetTagChar
Writes a string tag. Triggers any tag-triggered events configured on DegermBuhler_Name, including picture-window parameter updates. Writing from the GUI thread is synchronous, but downstream picture windows do not redraw until the next event-loop tick, so always combine with an explicit SetVisible or redraw call if the operator must see immediate feedback.
5.3 SetPictureName
Loads a PDL into a picture-window object. The picture name is the third argument, with the host picture and the picture-window object name as the first two. WinCC requires the host picture name to match the picture currently on screen (use lpszPictureName if the script is attached to a child picture). When the picture window's Independent window attribute is set, the host argument is ignored and a new top-level window is created — in that case SetVisible is still required for the new window.
5.4 SetVisible
Direct property write on the Visible attribute. The third argument is a BOOL; WinCC accepts 0/1, TRUE/FALSE, or true/false depending on the C-runtime in use. For WinCC 7.5 the runtime is MSVC 2010, so use TRUE/FALSE macros for portability. The call fails silently if the object does not exist on the host picture; check the project picture tree before referencing object names.
6. Verification Procedure
After deploying the fixed script, perform the following five-step validation. Each step is a control against one of the defect's contributing factors.
-
Compile clean. In Graphics Designer, right-click the script and choose Compile. Confirm zero warnings, zero errors. WinCC 7.5 outputs the build log to
<Project>\<Computer>\WinCC\diagnose\*.log. -
Runtime tag check. Use the WinCC tag simulator (Start > SIMATIC > WinCC > Tools > Tag Simulation) to toggle
WholeGrainbetween 0 and 1 while watching the picture window in the activated runtime. -
Click in each direction. Click the button with
WholeGrain = 0; confirmDegermBuhler5Control.PDLappears. Then set the bit to 1 and click; confirmDegermBuhler5Control_a.PDLappears. Repeat five times — no missed loads is the pass criterion. - Toggle-then-click sequence. Toggle the bit in the PLC without clicking. The picture window should retain its last state. Click; it should switch immediately, with no animation flicker or blank frame.
-
Tag value check. Open the Tag Monitor in the activated runtime and confirm
DegermBuhler_NamereadsDP_WholeCornScaler2Eafter each click. This validates theSetTagCharcall.
7. Common C-Script Pitfalls in WinCC
The faceplate/visibility defect is one of several recurring failure modes. The matrix below lists the pitfalls most often observed in commissioning.
| Pitfall | Symptom | Defensive Pattern |
|---|---|---|
Picture-name case mismatch (e.g. .Pdl vs .PDL) |
Picture fails to load; no log entry | Always uppercase the extension; quote the exact name from the PDL tree |
| Object name typed as caption instead of ObjectName |
SetVisible returns FALSE silently |
Use the property dialog to copy the object name verbatim |
| Reading a tag whose name changed during refactor |
GetTagBit returns -1, if branch becomes the cold path |
Validate GetTagBit return against -1 and log to GSC |
Mixing SetVisible with picture-window Adapt picture set to No
|
Picture loads at original size, partially off-screen | Set Adapt picture = Yes on the picture window |
Calling SetTagChar with a string literal shorter than the tag length |
Tag value truncated, child faceplate shows default config | Pad to declared length with strncpy + explicit null |
Forgetting to declare apdefap.h in project-level functions |
Compiler error: undeclared identifier SetVisible
|
Always include apdefap.h as the first non-comment line |
| Writing to a picture window that has been removed in a recent redraw | Script succeeds but no effect on screen | Re-check the picture tree after every graphics revision |
8. Debugging Techniques
WinCC provides three layers of diagnostics for C-scripts. Use them in order of cost; the runtime APDiag and GSC traces are the fastest way to localize the faceplate defect class.
8.1 APDiag Internal Tags
For WinCC V7.4 SP1 and later, APDiag exposes internal diagnostic tags. Enable them in Computer Properties > Graphics Runtime > APDiag. The relevant tags for this defect are:
-
@ScriptErrCount— increments on any script runtime exception. -
@LastScriptError— string with the last error message. -
@TagSetErrCount— increments onSetTagfamily failures.
8.2 Global Script Console (GSC)
Insert printf or sysprintf calls in the C-script to write to the GSC. Open it with WinCC Explorer > Tools > Global Script Console. A debug skeleton:
printf("OnClick: WholeGrain=%d\r\n", GetTagBit("WholeGrain"));
For WinCC 7.5 the GSC output is also mirrored to <Project>\<Computer>\WinCC\diagnose\GSC.log for offline review.
8.3 Picture Tree Browser
The Picture Tree tool in Graphics Designer lists every object in the active picture, with its ObjectName, ObjectType, and current property values. Use it to confirm that the object passed to SetVisible exists in the picture referenced as the first argument. A typo in the host picture name is the single most common reason for a silent no-op.
9. Picture Window vs. Faceplate Architecture
The example uses the term "faceplate" loosely — the loaded picture is a regular PDL opened inside a picture-window object. A true WinCC faceplate (introduced in TIA Portal WinCC and supported in WinCC 7.4 via the WinCC Faceplate Designer) encapsulates the picture-window plus its tag interface into a reusable type. The same defect class appears in faceplate instantiation, with two additional failure modes:
-
Instance visibility binding. Faceplate properties (including visibility) are bound to instance properties on the parent. If the visibility is bound to a tag, the script's
SetVisiblecall is overridden by the next tag write. Resolve by writing the bound tag instead of the picture-window property directly. -
Multi-instance contamination. A single script attached to a faceplate instance i may unintentionally toggle visibility of a sibling instance j if it uses a hard-coded object name. Always use the
lpszObjectNameparameter from the event signature for faceplate-internal scripts.
10. Performance and Best Practices
For HMI panels with limited memory (Comfort Panels, Unified Comfort Panels), follow these rules when scripting faceplate loads:
- Pool faceplates. Configure all operator screens as members of a small pool (typically 4–8 PDLs) and reuse them across many process tags. Loading an uncached PDL triggers a compile pass and can take 200–800 ms on a 4-inch panel.
-
Pre-load on picture open. Call
SetPictureNamewith the most common PDL in the parent picture's Open event, then control onlySetVisiblefrom button clicks. This eliminates the load latency on the warm path. - Avoid scripting in the hot loop. Move cyclic work from C-scripts to direct tag connections wherever possible. Scripts in OnTimer events at sub-500 ms intervals cause CPU spikes on TIA Unified panels with the OpenES runtime.
- Validate strings before use. When a script writes a configuration block identifier into a tag, validate that the identifier exists in the project dictionary. A typo there will manifest as a faceplate that opens but shows "no data" instead of a hard error.
-
Use configuration files, not literals. A project with 50+ faceplates should read its lookup table from a CSV or INI file via the WinCC file API. Hard-coded
#definetables force a code change for every new equipment instance.
11. Migration Notes: WinCC 7.x to TIA Portal WinCC
The C-script API in TIA Portal WinCC (Unified) differs in three ways from classic WinCC 7.x:
-
JavaScript is the primary language. TIA Unified uses ECMAScript with WinCC-specific global functions (
UI.OpenScreen,Screen.Items("ItemName").Visible). The C-scripts from classic WinCC do not migrate automatically. -
No
apdefap.h. The header file and the global function header convention are gone. Each screen has its own JavaScript module. -
Async picture loading.
UI.OpenScreenis asynchronous; the previous pattern ofSetPictureName+SetVisiblecollapses into a single awaited call. The C-script defect class does not exist in TIA Unified.
For projects that must bridge the two generations, the official Siemens tool WinCC Script Migration Tool (shipped with SIMATIC WinCC V7.5 SP2) translates 70–80% of common C-scripts to JavaScript, with the remainder requiring manual review. The faceplate-visibility pattern shown in section 4 is the recommended target form during manual review.
SetTagChar call shown above is safe in both MBCS and Unicode builds because the tag name is ASCII-only.
12. FAQ
Why does SetPictureName not show the new picture even though it returns TRUE?
SetPictureName only changes the PictureName property of the picture-window object. The Visible property is independent. A previous script event may have set Visible to FALSE, and the new call does not override it. Always pair SetPictureName with SetVisible(..., TRUE) on the same object.
How do I find the exact object name to pass to SetVisible in a WinCC C-script?
Open the picture in Graphics Designer, right-click the picture-window or faceplate object, and choose Properties. The ObjectName field in the Properties dialog shows the string to pass as the second argument. Avoid using the caption text — the caption is for display only and is localized.
Can I call GetTagBit from a faceplate instance script safely?
Yes, but only if the faceplate exposes the tag as a property or the tag name is global. Reading a tag that the faceplate does not own will work, but it creates a hidden coupling that breaks the moment the faceplate is reused for a different equipment. Prefer the faceplate's instance-property interface over direct tag reads.
What is the correct file extension case for the third argument of SetPictureName?
Use the upper-case form .PDL in every script. WinCC's PDL cache is case-sensitive on some installations and case-insensitive on others, which leads to nondeterministic load failures. The picture tree in Graphics Designer always shows the upper-case form, so use that as the reference.
How do I confirm that apdefap.h is the right include for my project?
apdefap.h is auto-generated by WinCC and located under the project's ap_lib directory. It is the correct include for all graphics-designer C-scripts. For project-global functions stored in the Global Script editor, include the equivalent header generated for the project. Missing the include causes compiler errors such as "undeclared identifier SetVisible".