WinCC V7.3 C-Script Run Code Only When a Specific User Is Logged

David Krause12 min read
HMI ProgrammingSiemensTutorial / How-to
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

Overview

Siemens WinCC V7.3 exposes the currently logged-on operator as a built-in internal tag named @CurrentUser. The tag is a WinCC text variable (8-bit character set, TEXT_8BIT_CHAR) maintained by the User Administrator component and updated by the runtime whenever a user logs in, logs out, or the system is started. Because the value is written automatically by the WinCC runtime, you can read it from any C-script, VBScript, or direct tag connection without configuring a separate driver connection.

The typical use case is to gate change-event code on an I/O field, a picture window, or a global action so that, for example, a recipe download, a tag writeback, or a system command only fires when a specific user is logged in. The pattern is straightforward:

  1. Read @CurrentUser with the C function GetTagChar().
  2. Compare the result against the authorized user name with the standard C function strcmp().
  3. Wrap the protected code in an if block that runs only when strcmp() returns 0.

Below is the complete reference for implementing that pattern in WinCC V7.3, including the exact API call, the internal-tag behavior, login/logout state transitions, error handling, and verification steps.

Prerequisites

Item Requirement
WinCC version WinCC V7.3 (or compatible runtime within the V7.x line; behavior is identical from V7.0 SP3 onward)
WinCC license WinCC RT Basic, RT Client, or RC licensing per the engineering station
User Administrator Installed (default component) and at least one operator account created
Project editor WinCC Explorer with a configured C-editor (the default C/VB editor is installed by default in V7.3)
Scripting runtime Global Script Runtime must be loaded on the target station; verify in the project properties under "Computer → Startup"
Authoring knowledge ANSI C conventions; familiarity with WinCC internal tag namespace (@* prefix)

Before authoring, confirm the WinCC V7.3 script documentation is installed locally or reachable from Siemens Industry Online Support. The internal tag list and C function reference is published in the WinCC V7.3 documentation set under "Working with WinCC → Reference → Internal Tags" and "ANSI-C for Creating Functions and Actions".

How the @CurrentUser Internal Tag Works

Every WinCC runtime automatically provisions a set of internal tags beginning with @. @CurrentUser is one of the system tags in the "System" connection, so it is available in every project without manual configuration. Its behavior is defined by the runtime:

Runtime state @CurrentUser value Length
No user logged in (startup / after logout) Empty string ("") 0 characters
User logged in The exact login name string (case-sensitive) Up to 24 characters (WinCC default user-name limit)
Auto-login user active The configured auto-login name Same as above

The tag is a TEXT_8BIT_CHAR with a default length of 24 characters; the user administrator will reject user names longer than this value. Always treat the return from GetTagChar() as a null-terminated C string and never assume a non-empty value before comparison.

Case sensitivity: WinCC stores the user name exactly as it was entered in the User Administrator. Comparisons using strcmp() are case-sensitive. If you need case-insensitive comparison, normalize both strings with strupr() or strlwr() before calling strcmp().

Step-by-Step: Implement the User-Gated Change Event

Step 1 - Open the I/O Field Properties

In the Graphics Designer, select the I/O field that should trigger the script. Open the configuration dialog and switch to the "Event" tab. Locate the change event (typically labeled "Change" or "Output/Input change" depending on configuration).

Step 2 - Assign a C-Action

Click the lightning-bolt icon next to the change event and choose "C-Action..." from the context menu. The WinCC C-editor opens with a stub function. WinCC will wrap your code inside a void function named after the picture, the object, and the event (for example void OnClick_Picture1_IOField1(void)).

Step 3 - Author the User-Gated Code

Use GetTagChar() to read @CurrentUser and gate your script with strcmp(). The canonical implementation is:

// C-action: change event of the I/O field
if (strcmp(GetTagChar("@CurrentUser"), "XYZuser") == 0)
{
    // Authorized user is logged in - run the protected code here
    // Example: write to an internal tag, trigger an archive, etc.
    SetTagDWord("MyAuthorizedCounter", GetTagDWord("MyAuthorizedCounter") + 1);
}
// If the user does not match, the block is silently skipped

The strcmp() call returns 0 when both strings are identical and non-zero otherwise, which is the conventional C "match" test. The protected block runs only when the active user is exactly "XYZuser".

Step 4 - Authorize Multiple Users

To allow several operators, compare against each in turn or build a small table of allowed names:

// Multiple authorized users
const char* allowed[] = { "Operator1", "Supervisor", "EngineerA" };
int i;
char* currentUser = GetTagChar("@CurrentUser");
for (i = 0; i < 3; ++i)
{
    if (strcmp(currentUser, allowed[i]) == 0)
    {
        // Authorized: run the protected code
        break;
    }
}

This avoids repeating the same block for each user and is easier to maintain when the authorized list changes.

Step 5 - Distinguish "No User" from "Wrong User"

Because the runtime writes an empty string when nobody is logged in, you can detect the difference explicitly:

char* currentUser = GetTagChar("@CurrentUser");
if (currentUser[0] == '\0')
{
    // No user is logged in - do not run the script
}
else if (strcmp(currentUser, "XYZuser") == 0)
{
    // Authorized user - run the protected code
}
else
{
    // Wrong user - optional: log the attempt or display a system message
}

This three-way split is useful when an audit trail must record both unauthenticated and unauthorized events.

Step 6 - Compile and Save

Press F7 in the C-editor, or use "File → Compile", to compile the action. The status bar at the bottom of the editor will show "Compiled without errors" when the syntax is correct. Save the picture and rebuild the runtime via "File → Save All" in the Graphics Designer.

Reading @CurrentUser From VBScript (Cross-Reference)

If you also maintain VBScript actions in the same project, the equivalent pattern uses HMIRuntime.Tags and Read:

' VBScript: change event
Dim currentUser
currentUser = HMIRuntime.Tags("@CurrentUser").Read
If currentUser = "XYZuser" Then
    ' Authorized code
End If

Both languages read the same internal tag. The choice between C and VBScript is typically driven by existing project conventions and by the need for C-style performance on high-frequency events.

User Administration Setup

The @CurrentUser value is the name configured under "User Administrator → Users" in the WinCC Explorer. To create the authorized user referenced in the script:

  1. Open WinCC Explorer and double-click "User Administrator".
  2. Create a new user (for example, login name XYZuser).
  3. Assign a password and select at least one authorization level (e.g., level 5 "Operator") in the "Authorizations" tab.
  4. Close the dialog. The new user is now available at runtime on the logon dialog.

When the operator logs in through a logon dialog or via PWRTSilentLogin in C-script, the runtime writes the supplied name into @CurrentUser. Logging out (manually or via timeout) clears the tag back to an empty string. Auto-login, if configured under "Computer → Properties → Startup", populates the tag with the auto-login user at runtime start.

Authorization levels are separate from script gating. The WinCC authorization system uses numeric levels (0-999) to gate individual controls; @CurrentUser only identifies who is logged in, not what they may do. You can combine both - read @CurrentUser for the person, and use GetTagDWord("@CurrentAuthorization") for the active level - to enforce fine-grained rules.

Verification

To confirm the gate works, follow this commissioning procedure on a WinCC Runtime station:

  1. Activate the project on the target computer.
  2. Without logging in, change the value of the I/O field. The protected code must not execute. Inspect any tag the script increments - it must remain at its previous value.
  3. Log in as a different user (not XYZuser). Change the I/O field. The protected code must not execute.
  4. Log in as XYZuser. Change the I/O field. The protected code must execute (for example, the counter increments by 1).
  5. Log out, change the I/O field, and confirm the protected code does not run again.

To trace the script during commissioning, enable the WinCC GSC runtime diagnostic by checking "Debug → GSC Debug" in the Graphics Designer before activation, or by enabling the GSC trace in the WinCC Explorer under "Computer → Properties → Runtime → Diagnostic". The trace file WinCC_Sys_.log contains every printf and Debug output from the C-action.

Troubleshooting Matrix

Symptom Likely cause Fix
Script never runs even when XYZuser is logged in Tag name misspelled in GetTagChar; internal namespace requires the leading @ Verify spelling is exactly @CurrentUser; case-sensitive
Script always runs Compared against the wrong constant or forgot the == 0 test on strcmp Check the comparison: strcmp(a, b) == 0 is a match
Script runs only for partial match (e.g., "XYZu") Used strncmp or compared single characters by mistake Use full strcmp() with both the login name and the constant
Compilation error "function not declared" Forgot to include the WinCC apdefap.h header (added automatically in C-Editor) Recreate the action through the Graphics Designer wizard so the standard includes are inserted
Empty-string comparison fails unexpectedly Compared to a literal null pointer rather than "" Use strcmp(GetTagChar("@CurrentUser"), "") == 0 or check the first character for '\0'
Script runs after logout Stale buffer from a previous trigger held the user name Always re-read @CurrentUser at the top of the action; do not cache the value
Runtime error "Tag not found" The @CurrentUser tag was accidentally deleted from the tag management Right-click the tag group, select "Restore deleted tags" or restart the project so the runtime re-provisions internal tags

Performance and Best Practices

Reading @CurrentUser is a low-overhead operation because the tag is held in process memory by the runtime. Still, follow these practices in production code:

  • Read once per event. Call GetTagChar("@CurrentUser") at the top of the action and store the pointer in a local variable. Do not call it multiple times within the same event.
  • Avoid the comparison in tight loops. If the script is a cyclic action, hoist the user check out of the inner loop so the comparison is performed only when the user state can change.
  • Treat the return as read-only. The buffer returned by GetTagChar is owned by the WinCC runtime; do not free it and do not modify it in place. Copy with strncpy if a mutable buffer is needed.
  • Use authorization levels for UI gating. @CurrentUser is best for audit logging and conditional script execution; use the built-in authorization levels to hide or disable controls in the picture.
  • Log all sensitive executions. Combine the user check with an audit tag or an alarm logging call to record when the protected code ran and under which account.

Comparison: User-Gating Strategies in WinCC

Strategy How it works Best for
@CurrentUser string compare Read the internal tag and compare against an allowed name list Audit-grade identification of which operator ran a script
Authorization level check Read @CurrentAuthorization and compare against a numeric threshold Role-based UI gating (operator, supervisor, admin)
User group membership Read @GroupMembership (semicolon-delimited list) and parse Many-to-many role assignments
Picture-level access protection Set an authorization level on the picture's "Properties → Security" tab Hiding entire screens behind a logon
Object-level operator enable Set an authorization level on the object's "Properties → Other → Operator-Control Enable" Disabling individual buttons without scripting

For change-event scripts that must run only for one specific person, the @CurrentUser approach is the simplest and most direct. For role-based gating, prefer the authorization level or group membership mechanism because it is easier to maintain when staff changes occur.

Extended Example: Audit-Logged Operator Action

The following self-contained C-action reads the current user, records the event in a free-form archive tag, and writes a value to a tag - but only when the authorized user is logged in. Use it as a template for production systems.

// C-action: change event of an I/O field
char* currentUser = GetTagChar("@CurrentUser");
if (currentUser[0] != '\0')
{
    if (strcmp(currentUser, "XYZuser") == 0)
    {
        // Increment the authorized counter
        DWORD count = GetTagDWord("AuthorizedExecCount");
        SetTagDWord("AuthorizedExecCount", count + 1);

        // Write the operator's name into the audit trail
        SetTagChar("LastAuthorizedUser", currentUser);

        // Optional: log to the alarm logging system
        // (requires the user alarm message group to exist)
    }
    else
    {
        // Unauthorized but logged in - increment the rejected counter
        DWORD bad = GetTagDWord("RejectedExecCount");
        SetTagDWord("RejectedExecCount", bad + 1);
    }
}
// No user logged in: silently do nothing

The three counters (AuthorizedExecCount, RejectedExecCount, and the absence of a NoUserExecCount) give the operations team a quick view into who is interacting with the field and how often.

FAQ

What is the exact tag name to read the current user in WinCC V7.3?

The internal tag is @CurrentUser (case-sensitive, leading at-sign). It is auto-provisioned in every WinCC runtime and returns the active login name as a TEXT_8BIT_CHAR string, or an empty string when nobody is logged in.

How do I read @CurrentUser from a C-action?

Call char* p = GetTagChar("@CurrentUser");. The returned pointer is owned by the WinCC runtime; treat it as read-only and do not free it. Compare the value with strcmp(p, "MyUser"), where a return value of 0 means the strings match exactly.

Can I compare the user name in a case-insensitive way?

Yes. Normalize both sides with strupr(GetTagChar("@CurrentUser")) and strupr("xyzuser") (or use strlwr on both) before calling strcmp(). WinCC itself does not normalize user names, so the raw comparison is always case-sensitive.

Is the @CurrentUser tag available in the WinCC V7.3 internal tag list?

Yes. @CurrentUser is one of the system tags in the "System" connection and is created automatically by the runtime; you should not attempt to create it manually. The full list of @* system tags is documented in the WinCC V7.3 help under "Internal Tags".

Why does my script run even when the user is not logged in?

Most often this is caused by comparing against the wrong constant or by forgetting the == 0 test on strcmp(). strcmp returns 0 on match and non-zero otherwise, so the test must be if (strcmp(user, name) == 0). Also verify that the user name in the User Administrator matches the constant exactly, including case.

Can I gate a script on a user group instead of a single user?

Yes. Read the internal tag @GroupMembership (a semicolon-delimited list of the groups the active user belongs to) and check for the presence of the desired group with strstr(). The same string-comparison pattern is used; only the source tag and the value to look for change.

Does the script execute during a runtime project switch?

When the project is being deactivated and reactivated, @CurrentUser is reset to the empty string until the operator logs on again. Any change event fired during this window is therefore not gated on a specific user, so the protected block is skipped - which is the expected safe behavior.

Back to blog