Overview
Siemens WinCC Professional (TIA Portal V16 and later) supports ANSI-C as one of its two scripting languages (the other being VB Script). Engineers migrating from WinCC V7 into WinCC Professional frequently encounter three classes of errors in the C editor:
- Function-prototype mismatches between
int gscAction(void)(V7) and the Professional generator naming convention (void CFunction_1()). - Missing or unresolved
#include "apdefap.h"preprocessor directives. - Compile errors on the
voidkeyword that disappear when the return type is changed tovoid*.
All three errors trace back to misunderstandings about the C language itself, not WinCC. This reference explains the language semantics behind each error, then maps them onto the specific naming and project conventions enforced by WinCC Professional V16 Update 6 (and SP variants of V17/V18 that retain the same scripting engine).
void vs void* in C: Language Semantics
The root cause of the third error is a basic C type-system distinction that has nothing to do with WinCC. Per the ISO/IEC 9899 C standard (summarized on Wikipedia's C language reference), C is a statically typed procedural language in which every function must declare exactly one return type.
| Type | Meaning | Return value | Typical use |
|---|---|---|---|
void |
Function returns nothing | None (empty return) | Procedures, side-effect routines, WinCC actions, callbacks |
void* |
Function returns a generic pointer | Address of an unspecified object |
malloc(), bsearch(), low-level allocation |
int |
Function returns an integer status code | Numeric (typically 0 = OK) |
main(), gscAction(), error reporting |
When the compiler reports "error on void" but accepts void*, the engineer has almost always inserted an asterisk by mistake, or has read a forum post that suggested returning void* as a workaround. Both behaviours are wrong: a WinCC C action is invoked by the runtime scheduler and the scheduler does not inspect a return value. The correct signature is void, not void*. A void* return causes the compiler to embed an EAX/register return sequence that the scheduler never reads, wastes one register, and is misleading to any other engineer reading the script.
void. Use void* only when the caller will cast the returned address back into a concrete type.Why WinCC Reports an Error on Plain void
In WinCC Professional, the C script body you type is automatically wrapped by the code generator into a function whose prototype matches the script type. For a scheduled action the wrapper looks like:
void ScheduledAction_1(void)
{
/* user code begins */
...
/* user code ends */
}
The wrapper itself is void. If you also type int or void* as the leading return type inside the editor, you create a nested function definition, which is a C syntax error. The solution is to leave the first line of the script blank or to start directly with declarations and statements. Do not type a return type at the top of a WinCC script body unless you are writing a function block (FB-style) callable from another script.
WinCC Professional C Scripting Environment
WinCC Professional places the C editor under HMI Tags > [screen] > Events > [event] > C-Action, and under Schedules for periodic actions. The runtime engine compiles the script at startup with the bundled MSVC-compatible C compiler shipped with the WinCC Runtime Professional binaries.
Script Types
| Script kind | Trigger | Wrapper prototype | Use case |
|---|---|---|---|
| Project function | Call from VB or C | void ProjectFunction(void) |
Reusable utility |
| Scheduled action | Cyclic timer / event | void ScheduledX_N(void) |
Polling, periodic logic |
| Tag-triggered action | Tag change | void TagTriggered_N(void) |
Reactive logic |
| Window event | Open/close/click | void WindowEvent_N(void) |
HMI event handling |
Each wrapper is generated by the WinCC code generator based on the script's name. The visible editor in TIA Portal only shows the body between the braces; the wrapper is appended automatically and is not editable. Therefore the engineer never needs (and should never include) a return type or function name at the top of the script.
Function Prototype Conversion from WinCC V7 to WinCC Professional
WinCC V7 exposes a different API surface. In V7 the user enters the full function signature, including int gscAction(void), because the V7 generator does not auto-wrap the body. The runtime invokes the action through a global symbol whose name is the script name (e.g. gscAction) and checks the integer return code.
In Professional the global-scheme no longer exists; the generator owns the wrapper. The correct migration rule is:
- Delete the
int gscAction(void)line entirely. - Delete the matching trailing
}. - Insert the remaining body verbatim into a Professional scheduled action.
- Configure the trigger (cycle, event, tag change) in the schedule dialog instead of inside the script.
Side-by-Side Conversion Example
WinCC V7 source:
int gscAction(void)
{
int iValue = GetTagWord("Motor_Speed");
SetTagFloat("Motor_Speed_FLT", (float)iValue);
return 0;
}
WinCC Professional target (project function form):
/* Project Function: ConvertMotorSpeed */
{
DWORD dwValue = 0;
float fResult = 0.0f;
dwValue = GetTagWordState("Motor_Speed", NULL);
if (dwValue == 0)
{
fResult = (float)GetTagWord("Motor_Speed");
SetTagFloat("Motor_Speed_FLT", fResult);
}
}
GetTagWord() retains its name, but state-aware variants use the *State suffix. Always confirm the API in the Siemens Online Support WinCC Professional reference manual for the target firmware version.Header Includes in WinCC C Scripts
The #include "apdefap.h" directive originates from WinCC V7. In V7, apdefap.h defines the prototypes for the Graphics Designer runtime API, including GetTag*, SetTag*, SetPicture, and other block-mode functions. The header lives in the V7 project subdirectory \Library\apdefap.h.
Why the Include Fails in WinCC Professional
WinCC Professional does not ship apdefap.h in the TIA project tree. The WinCC Professional compiler ships its own headers as a precompiled set inside the WinCC Runtime Professional installation directory. The script editor links against those internal headers automatically; the user does not write any #include for the standard WinCC API.
Typing #include "apdefap.h" at the top of a Professional script produces one of two errors:
- Cannot find file 'apdefap.h' – the project does not contain the file.
- Redefinition of GetTagWord – the user added the header from an old V7 project into the TIA project, but the runtime also defines the same prototypes, causing duplicate symbol errors.
Correct Approach in WinCC Professional
- Delete the
#include "apdefap.h"line. - Call the standard API functions directly (
GetTagDWord,SetTagFloat, etc.). - If a custom header is required for project-wide constants, add it to the project's Scripts > C-Scripts > Project Headers node so the generator picks it up from the project path.
Creating a Custom Header
If you genuinely need a project header, place a plain C header in the project path and reference it. For example, create project_includes.h:
#ifndef PROJECT_INCLUDES_H
#define PROJECT_INCLUDES_H
#define MAX_RETRIES 3
#define PUMP_TAG "Pump_01_Status"
#endif
Reference it as #include "project_includes.h". The Professional generator adds the project's script folder to the include path automatically.
Global Actions vs Scheduled Tasks
WinCC V7 exposes a tree node called Global Scripts in the project. Engineers can drop C files into the global action pool; each file becomes a standalone function callable by name. WinCC Professional replaces this with the Schedules node.
| Concept | WinCC V7 | WinCC Professional |
|---|---|---|
| Container | Global Scripts | Schedules |
| Entry name | gscAction |
User-defined, e.g. CFunction_1
|
| Signature typed by user | Yes (full prototype) | No (body only) |
| Trigger configured | Inside code via API | In the schedule trigger dialog |
| Hot reload | Manual recompile | Compile on save in TIA |
The visible difference is in the trigger model. In V7, a global action either ran once on startup (if named gscAction) or was invoked from another script. In Professional, every scheduled action must be bound to a trigger – cycle (e.g. every 500 ms), tag change, or window event. There is no "fire-once on startup" idiom; engineers either set a 1-second cycle and gate with a static flag, or trigger on the HMI Started event of the runtime.
Step-by-Step Migration from WinCC V7 to WinCC Professional
Prerequisites
- TIA Portal V16 Update 6 (or later SP) installed with WinCC Professional.
- Source V7 project archived (
.sav) and accessible. - WinCC Professional license key matching the number of tags and PowerTags.
Migration Procedure
- Open the V7 project in WinCC Explorer, export all global actions to
.pastext files via Global Scripts > right-click > Export. - Create a new TIA Portal project. Add a WinCC Professional HMI station.
- Navigate to HMI > Schedules > Add new schedule. Create one schedule per V7 action, naming each according to the V7 function name for traceability.
- Open each schedule, set the trigger (cycle / event), and paste the V7 script body into the C editor.
- Remove the first line (
int gscAction(void)) and the closing brace of the V7 function. - Delete any
#include "apdefap.h"directive. - Replace V7-only APIs (e.g.
PWRTAuthenticate) with the Professional equivalents listed in the TIA WinCC Professional reference manual. - Compile the HMI station. Resolve any remaining warnings.
- Download to the runtime and verify in the diagnostics view.
Verification
- The schedule appears in Schedules > Active after download.
- WinCC Runtime Professional diagnostic window shows no C compile errors.
- The first execution cycle matches the configured trigger interval.
- Tags read/written by the script update as expected.
Common Compile Errors and Resolutions
| Error message | Cause | Resolution |
|---|---|---|
| Syntax error: nested function definition | Typed a return type at top of script body | Delete the leading int/void* line |
| Cannot find include file 'apdefap.h' | V7 header imported into Professional | Remove the include; use the auto-linked Professional API |
| Redefinition of GetTagWord | apdefap.h added AND Professional headers auto-linked | Remove the V7 header |
| Undeclared identifier 'gscAction' | V7 entry name still referenced | Rename call sites to new Professional function name |
| Function should return a value | Body ends without return on non-void function |
Confirm wrapper is void; remove stray prototype |
| Type mismatch: DWORD vs INT | Mixed WinCC API variants | Use GetTagDWord with DWORD cast |
Best Practices for WinCC Professional C Scripts
- One action per concern. Split large V7 monoliths into multiple Professional schedules; each schedule should perform one logical task.
- Prefer project functions over inline code. Centralise tag-name strings and constants in a project function or header to ease renaming during tag refactors.
-
Avoid global state. WinCC Professional restarts the runtime cleanly; any
staticvariable resets. Use HMI tags for cross-cycle state instead. -
Guard tag I/O. Wrap every
GetTag*call with the corresponding*Statevariant when status is critical for control logic. - Cycle budget. A 100 ms cycle consumes noticeably more CPU than a 500 ms cycle; size the trigger to the actual process need.
-
Disable in test mode. Use the runtime's Simulation / Test toggle or a project-side
#ifdef _DEBUGto skip heavy logic during commissioning.
Diagnostic Workflow When Scripts Fail to Compile
- Open Project Tree > HMI > Diagnostics and expand the C-Script node.
- Read the first error – subsequent errors are frequently cascaded.
- Open the offending script in the C editor and locate the line referenced.
- If the error mentions
apdefap.h, search the entire script for#includedirectives; remove all V7-specific ones. - If the error mentions
void, scroll to the top of the script body and confirm no return type has been typed. - Recompile. Verify the error count drops.
- If unresolved, export the script to a standalone file and compile with the WinCC Runtime Professional C compiler in isolation for a more detailed error log.
FAQ
Why does my WinCC Professional script accept void* but reject void?
The rejection is a symptom, not the cause. You have typed a return type at the top of the script body, which creates a nested function definition. Remove the typed return type; the Professional generator supplies the wrapper automatically, so the body must start with declarations or statements, not with a prototype.
Where do I put apdefap.h for WinCC Professional?
You do not. WinCC Professional does not require apdefap.h. The runtime compiles against internal headers automatically. Delete the #include "apdefap.h" line and call the API functions directly.
How do I migrate int gscAction(void) from WinCC V7 to Professional?
Delete the int gscAction(void) header line and the closing brace. Paste the remaining body into a Professional schedule. Configure the trigger in the schedule dialog instead of inside the script. The wrapper becomes void ScheduledX_N(void), owned by the generator.
Can I run a WinCC V7 script unchanged inside WinCC Professional?
No. WinCC Professional uses a different API surface and a different trigger model. The C syntax is similar, but wrapper generation, header conventions, and tag-access functions all differ. Always migrate the body and adapt the wrapper per the procedure above.
What trigger replaces WinCC V7 startup-once global actions?
Use a Professional schedule with the "HMI Started" event trigger for one-time startup actions, or a tag change on a startup-complete flag. There is no equivalent of the implicit V7 gscAction invocation; every Professional action must declare its trigger explicitly.