WinCC User Login Report with C Scripts and Alarm Logging
Recording who logged in, when, and from which operator station is a baseline requirement for any audited HMI/SCADA installation. In Siemens WinCC Runtime (V7.x and the WinCC portion of TIA Portal) there is no built-in "User Login Report" wizard, so the audit trail must be assembled from three runtime components: a Global C Action that watches the @CurrentUser system tag, two Internal Tags that act as rising-edge triggers, and an Alarm Logging configuration that captures the events under a dedicated Message Class so they can be filtered, archived, and exported independently of process alarms.
This guide walks through the complete configuration: script authoring, tag creation, trigger wiring, alarm configuration, message-class filtering, archive setup, and runtime verification.
1. Prerequisites
- Siemens WinCC V7.4 SP1 or later (V7.5 SP2 recommended). Procedure also applies to WinCC Runtime Professional V15.1 and higher inside TIA Portal with minor menu-path differences. Reference: WinCC V7.5 SP2 Information System.
- WinCC project is in Runtime-compatible state (no compile errors in Graphics Designer, Alarm Logging, or Global Script editor).
- User Administration is enabled in the project (Project Properties > User Administration > Activate User Administration).
- At least one operator station is configured in WinCC Explorer and the user has administrator rights to modify Global Scripts and Alarm Logging.
- The
kernel32.dllis available on the Runtime PC for theSleep()call (standard on all Windows OS supported by WinCC).
2. Architecture Overview
The audit pipeline is intentionally simple. The C Action polls @CurrentUser; on every change of user it asserts one of two transient bits. Those bits are wired as triggers in Alarm Logging, which produces timestamped, archivable messages that include the operator name from @CurrentUser in the "Logged user" column.
3. Create the Internal Tags
Open WinCC Explorer > Tag Management > Internal Tags and add two binary tags. The exact data type must be Binary Tag (1 bit); do not use a Word or Byte tag because the C API expects a bit address.
| Tag Name | Data Type | Length | Update | Initial Value | Purpose |
|---|---|---|---|---|---|
LoginBit |
Binary Tag | 1 bit | On change | 0 | Rising edge = user just logged in |
LogoutBit |
Binary Tag | 1 bit | On change | 0 | Rising edge = user just logged out |
@OldUser |
Text tag (8-bit) | 32 chars | On change | "" | Stores the previous logged-in user for comparison |
@CurrentUser against a stored @OldUser. Without it, a fresh Runtime start where @CurrentUser transitions from empty-string to a real user would still be detected, but a redundant trigger on every tag scan would be impossible to suppress. @OldUser gives the script a state variable.4. Author the Global C Action
Open WinCC Explorer > Global Script > C-Editor and create a new Action (not a function). Actions run on the WinCC scheduler; functions must be called. Name the action login_logut.pas. Configure its trigger (Info > Trigger) to fire on tag change of @CurrentUser:
- In the C-Editor, right-click the new
login_logut.pasnode and choose Info / Trigger. - Click Add, select Tag, and pick
@CurrentUserfrom the tag list. - Set the trigger cycle to On change (default). Save the trigger configuration.
Replace the body of the action with the following code. Do not wrap it in main() or in { } braces — WinCC actions are inserted into a pre-generated wrapper, so the file must contain only declarations and the if/else body.
// =====================================================================
// WinCC Global C Action: login_logut.pas
// Purpose: Generate LoginBit / LogoutBit edges on user change
// Trigger: @CurrentUser (on change)
// Tested: WinCC V7.4 SP1 / V7.5 SP2
// =====================================================================
// Import Sleep() from kernel32.dll
#pragma code ("kernel32.dll")
void Sleep(int milliseconds);
#pragma code ()
// ---- Local variables ----
char* NewUser;
char* OldUser;
NewUser = GetTagChar("@CurrentUser");
OldUser = GetTagChar("@OldUser");
// ---- Login detected (NewUser is non-empty and differs from OldUser) ----
if (strlen(NewUser) != 0)
{
// Clear any pending logout pulse
SetTagBit("LogoutBit", 0);
// Re-arm login edge
SetTagBit("LoginBit", 0);
// 1-second debounce so Alarm Logging registers the rising edge
Sleep(1000);
// Generate rising edge on LoginBit
SetTagBit("LoginBit", 1);
// Remember who is now logged in
SetTagChar("@OldUser", NewUser);
}
else
{
// Logout detected (@CurrentUser is empty)
SetTagBit("LoginBit", 0);
Sleep(1000);
SetTagBit("LogoutBit", 1);
// Clear stored user
SetTagChar("@OldUser", "");
}
4.1 Why the Sleep(1000) call is mandatory
Alarm Logging's trigger mechanism in WinCC uses an edge detection on the configured tag. If you only call SetTagBit("LoginBit", 1), the bit will stay high and no new edge will fire on the next login. By first setting the bit to 0, sleeping 1 s, and then setting it to 1, the action guarantees a clean rising edge every time. The same pattern is used in the official Siemens WinCC Global Script sample "CreateTriggerForAlarms.pas" referenced in the WinCC V7.5 SP2: Working with WinCC > ANSI-C in Global Scripts manual.
{ or } at the top or bottom of the file. WinCC wraps the body of an Action in its own scope; manually added braces will produce exactly this error. Remove any extra braces and recompile.4.2 Generate header / compile
- In the C-Editor, right-click
login_logut.pasand choose Header. This generates the matchinglogin_logut.hstub used by Alarm Logging and other C functions. - Right-click the file and choose Compile. The output window should report 0 error(s), 0 warning(s).
- Save the project. The action will auto-load on the next Runtime start.
5. Configure the Alarm Logging Message Class
The reason a dedicated message class is used (rather than reusing the default "Errors" or "System" class) is twofold: (1) the Alarm Control view can be filtered to show only login events, and (2) the archive export (CSV, SQL, RDB) can be configured to back up login events with a different retention policy than process alarms.
Open WinCC Explorer > Alarm Logging.
5.1 Create a new Message Class
- In the navigation tree, right-click Message Classes and choose New Message Class.
- Name it
User Login. Set the Type to Event (no acknowledgment required) — logins are informational and must not be queued for operator action. - Set the Status colors: incoming = green, outgoing = gray, acknowledged = blue (or your house standard). Save the class.
5.2 Add two Single Messages to the class
| Field | Message 1 (Login) | Message 2 (Logout) |
|---|---|---|
| Message Number | 100001 | 100002 |
| Message Class | User Login | User Login |
| Message Text | User <%s> logged in | User <%s> logged out |
| Trigger Tag | LoginBit | LogoutBit |
| Trigger Bit | 0 (rising edge) | 0 (rising edge) |
| Status Tag | LoginBit | LogoutBit |
| Status Bit | 0 (track the bit itself) | 0 (track the bit itself) |
| Logged user | @CurrentUser | (blank / system) |
| Process Value Block 1 | @CurrentUser | @OldUser |
For each message, configure the Process Value Block tab: enable one PVB, link it to @CurrentUser for the login message and to @OldUser for the logout message, set format to %s and length to 32. The PVB becomes the argument substituted into the <%s> placeholder in the message text, so the operator's actual WinCC user name is stamped on the event.
Reference: WinCC V7.5 SP2: Alarm Logging > Configuring Messages.
6. Create a Filtered Alarm View
To display only login events on a screen, drop a WinCC Alarm Control on a process picture and configure its Selection dialog to enable the Message Class filter and select only User Login. The control's toolbar exposes a button that opens the selection dialog at Runtime so operators can change the filter on the fly.
- Open Graphics Designer, insert an Alarm Control (OCX) on a picture named e.g.
AuditLog.pdl. - Right-click the control > Configuration Dialog > Select.
- Tick Message Class, click Add, and select the
User Loginclass. Untick all other classes. - Tick Logged user and Process value block as visible columns.
- Apply, save the picture.
7. Archive Configuration
By default, Alarm Logging stores messages in the segment circular archive. To produce a true login report you typically want a separate export. Two common approaches:
7.1 CSV export via the Alarm Control toolbar
At Runtime, click the export button on the Alarm Control and choose Export to CSV. The exported file includes columns: Date, Time, Msg-Nr, Class, Status, Text, User, PVB. This is enough for an Excel-based audit report.
7.2 Long-term archive via the Archive Server
Open WinCC Explorer > Archive Configuration > Alarm Logging Archive. Add a backup segment with a 30-day retention or your site standard. For the User Login class you can also enable Swap out so messages are copied to a backup path nightly, producing daily login logs.
7.3 Programmatic export via the WinCC OLE-DB provider
For automated reports, query the WinCC archive database directly. The standard SQL is:
SELECT DATETIME, MSGNR, CLASSNAME, TEXT1, TEXT2, USERNAME, PVVALUE
FROM ALGVIEWDEU :P (or ALGVIEWENU, ALGVIEWFRA, ...)
WHERE CLASSNAME = 'User Login'
AND DATETIME BETWEEN '2024-01-01 00:00:00' AND '2024-12-31 23:59:59'
ORDER BY DATETIME DESC;
Reference: WinCC V7.5 SP2: Connectivity Pack > OLE-DB Provider for Archives.
8. Runtime Verification
- Open the WinCC project on the Runtime server. Activate the project.
- Open the picture containing the filtered Alarm Control. It should be empty (no login events yet).
- In the WinCC menu, choose User > Log On. Log in as
adminwith the project password. - Within ~1 second a new row should appear: User admin logged in in green, with admin in the Logged user column.
- Log off (User > Log Off). Within ~1 second a new row: User admin logged out in gray, with admin still shown in the Logged user column (this is the value of
@OldUserat the moment of logout). - Log in again as
operator. A second User operator logged in event should be generated. - Export the Alarm Control to CSV and confirm all three rows are present with correct timestamps.
9. Troubleshooting Matrix
| Symptom | Root Cause | Fix |
|---|---|---|
| Compile error "<ident> expected before <eof>" | Stray { or } in the .pas file because the file was opened in the global C scope |
Remove all top-level braces. WinCC actions live inside a generated wrapper. |
| No alarm is generated on login | Trigger in the C Action not configured to @CurrentUser on change |
Right-click the action > Info/Trigger > add tag trigger for @CurrentUser. |
| Alarm fires once, then never again | The LoginBit stayed at 1 after the first fire; Alarm Logging does not re-trigger on a level |
Add the SetTagBit("LoginBit", 0); Sleep(1000); sequence before the rising edge, as in the sample. |
| "Logged user" column is empty on login | The Process Value Block is not linked to @CurrentUser, or the <%s> placeholder is missing |
Open the message > Process Value Block tab and add @CurrentUser with format %s; include <%s> in the message text. |
| Login events appear in the process alarm view | The User Login class was not created and the message was placed in the default "Errors" class |
Create the User Login class and move the message to it. Re-filter the Alarm Control. |
| Login events appear in the wrong language | WinCC uses the runtime language to look up multilingual text; the <%s> substitution is the only language-independent field |
Add translations of the message text in Text Library for every configured runtime language (EN, DE, FR, ES, IT, ZH). |
| Alarm Control toolbar shows no events at all | Selection filter was set during configuration but no messages match yet, or the time range is wrong | Click the toolbar's Selection button, broaden the time range to "Today + 1 h" and untick the class filter temporarily. |
| SQL query returns 0 rows | Wrong language suffix in the view name (e.g. ALGVIEWENU vs ALGVIEWDEU) |
Use the suffix matching the Windows display language of the WinCC server, or query ALG\* views in SQL Server Management Studio to find the right one. |
10. Edge Cases and Field-Proven Caveats
10.1 Multiple simultaneous logins (web navigator / softnet)
If you are using WinCC WebNavigator or WinCC DataMonitor, each thin client maintains its own @CurrentUser on the server. The single global C Action fires for each session change, which is exactly what you want for an audit log. Confirm by logging in from two browser tabs with different users and verifying two distinct events appear.
10.2 Forced logoff on timeout
If a user is auto-logged-off by the WinCC User Administration inactivity timer, @CurrentUser becomes the empty string and the script's else branch fires, producing a logout event with the previously stored user. The @OldUser in the logout message tells you who was forcibly logged off, not who is currently logged in.
10.3 Redundant server pairs (WinCC redundancy)
On a redundant WinCC server pair, Alarm Logging is automatically synchronized by the Redundancy option. Login events generated on the standby server after a failover will appear in the same archive, but with a 1-2 second gap caused by the archive sync. Tag-triggered actions themselves do not need to be duplicated; the package deployment on both servers is enough.
10.4 User disabled in runtime
If the project disables a hot user via LPAD_UMC (User Management Console), existing sessions are terminated and the action fires the logout branch. New logins by that user are rejected by User Administration before @CurrentUser is set, so no event is generated — the audit gap is the rejection itself, which can be caught by enabling the UMC audit channel separately.
10.5 Performance impact
The C Action uses Sleep(1000), which blocks the Global Script scheduler for up to one second. Do not add more than two or three login/logout actions on the same trigger; with 10+ sleeping actions, the scheduler can be starved and other time-critical actions (e.g. control loop overhead) will be delayed. For high-density audit logging, use the WinCC/Audit option which is non-blocking.
11. Upgrading to WinCC/Audit (if needed)
If the customer requirement is a tamper-proof, hash-chained audit log (e.g. for 21 CFR Part 11, GAMP 5, or similar), the alarm-based approach above is not sufficient because operators with Alarm Logging rights can acknowledge and modify entries. Replace the entire chain with WinCC/Audit (option for WinCC V7.5):
- Install the WinCC/Audit option on the engineering station and on all Runtime servers.
- Open WinCC Explorer > Audit Editor and create an Audit Trail Configuration.
- Add a User Logon event template, mapped to the
UMC:UserLogonserver event. - Configure the Audit DB path and the SQL Server used as the back end (mandatory: SQL Server 2016 or higher).
- Activate the project. The audit log is now signed with a SHA-256 hash chain; any tampering invalidates the chain at the next validation run.
Reference: WinCC V7.5 SP2: WinCC/Audit > Configuration Manual.
12. Frequently Asked Questions
Why do I get "<ident> expected before <eof>" when compiling login_logut.pas?
The C-Editor error means a stray opening or closing brace is present in the file. WinCC actions are wrapped in a generated scope, so manually placed { or } at the top or bottom of the .pas file produces this error. Delete the extra braces and recompile; the file should contain only declarations and the if/else body, no outer { } pair.
Can I trigger the alarm on a level instead of an edge?
No. Alarm Logging in WinCC fires on a transition (edge) of the configured trigger tag. If you set LoginBit to 1 and leave it there, only the first login event will be generated. Use the SetTagBit("LoginBit", 0); Sleep(1000); SetTagBit("LoginBit", 1); sequence shown in the sample to create a clean rising edge on every login.
Do I have to create LoginBit and LogoutBit in Internal Tags?
Yes. They must be Internal Tags of type Binary Tag, 1 bit. The C Action's SetTagBit() function can only write to internal tag addresses; external (PLC) tags would be read-only from the script side. Declare them in WinCC Explorer > Tag Management > Internal Tags before compiling the action.
How do I get the actual user name into the message text?
Enable the Process Value Block on the message, link PVB1 to the @CurrentUser system tag, and put <%s> in the message text where you want the name to appear. At Runtime, WinCC substitutes the PVB value into the placeholder. The "Logged user" column in the Alarm Control is filled automatically from the same tag.
Can I export the login log to a database or Excel automatically?
Yes. Use the WinCC Connectivity Pack OLE-DB provider to query the ALGVIEW* view filtered by the User Login class. From Excel, use a Data Connection pointing to the same OLE-DB provider. For scheduled CSV exports, configure the Alarm Logging archive's Swap out to copy daily segments to a shared path and ingest them with a PowerShell or SQL Server Integration Services job.