Locking WinCC Alarms via VBS and C-Action: V6 vs V7 Methods

David Krause13 min read
SiemensTutorial / How-toWinCC
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

Operators regularly require the ability to lock, suppress, or inhibit individual WinCC messages for a defined window — typically during startup, maintenance transitions, or recipe changes — without deleting the underlying alarm configuration. The challenge is that WinCC V6 and WinCC V7 expose two different scripting surfaces for alarm manipulation, and the runtime behavior of Alarm Control ActiveX methods diverges between releases. A VBS solution that works under WinCC V7 SP3 may compile but fail at runtime in WinCC V6.2 because the WinCC Alarm Control OCX in V6 does not implement GetRowCollection, Lock, or Unlock on its row-iteration object the same way.

This reference documents the complete set of approaches to lock a specific alarm by its message number using VBS, C-Action, and the WinCC Open Development Kit (ODK). It also covers a deployment-grade alternative for time-based inhibition (2-minute startup window, for example) that does not require writing a single line of script.

WinCC Message State Architecture

Every WinCC message traverses a deterministic state machine managed by the alarm logging service. A message can hold multiple orthogonal states at once; the runtime OR's them into a 32-bit DWORD value readable through the ODK and the alarm logging COM interface. The bit layout is fixed and must be used in all locking logic.

Table 1 — WinCC message state bit definitions
Constant Bit Mask (hex) Meaning
MSG_STATE_COME 0 0x0001 Message has arrived (active, unacknowledged)
MSG_STATE_GO 1 0x0002 Message has gone (cleared but not yet acknowledged)
MSG_STATE_ACK 2 0x0004 Message has been acknowledged by an operator
MSG_STATE_LOCK 3 0x0008 Message is locked — operators cannot process it
MSG_STATE_ENABLE 4 0x0010 Message is enabled (visible in alarm list)
MSG_STATE_PROCESS 5 0x0020 Message has been processed (handled state)
MSG_STATE_COMMENT 6 0x0040 Operator comment attached
MSG_STATE_HIDDEN 7 0x0080 Message is hidden (suppressed from list)
Important: MSG_STATE_LOCK and MSG_STATE_HIDDEN are distinct. A locked message still appears in the alarm list with a lock icon and cannot be acknowledged, but it remains visible so operators see the suppressed state. A hidden message is removed from the visible list entirely. The choice between the two depends on operational policy: lock when you want traceability, hide when you want a clean view.

Architecture: Where the Lock Actually Lives

WinCC alarm locking is server-side. When a VBS script or C-Action calls MSRTLockMsg (or its VBS equivalent), the request is dispatched to the alarm logging service on the WinCC server. The lock is persisted in the alarm logging database tables and survives the closing of any single client session. This is why locking is the right mechanism for the operator's "inhibit for 2 minutes after runtime start" requirement — it is enforced centrally, not on the HMI client.

Three call paths exist for the same end state:

  1. VBS via HMIRuntime.AlarmLogging — WinCC V7 only. Direct COM call from any picture or global action.
  2. C-Action via ODK — Both V6 and V7. Calls MSRTLockMsg from apdefap.h glue. Requires ODK installed and licensed on the runtime node.
  3. WinCC Scheduler + message class disable — Both V6 and V7. No scripting; uses time-based configuration to disable the message class for a defined window.

Prerequisites

  • WinCC V7.0 SP3 or later for the VBS path, or WinCC V6.2 SP2 / V7 for the ODK path.
  • WinCC Open Development Kit installed and licensed on the runtime machine. Verify via Start → SIMATIC → WinCC → ODK Readme.
  • For VBS: the picture must contain a WinCC Alarm Control OCX with a known name (e.g., Control1, AlarmWindow_1). Read the property name from the configuration dialog.
  • For C-Action: the project must be compiled with the ODK include path set. In WinCC Explorer → Computer → Properties → Graphics Runtime → C-Script tab, add %WINCC_OAP_DIR%\include to the include directories.
  • The message number (e.g., 1, 1000042) must be known. Locate it in WinCC Explorer → Alarm Logging → the message row.

Method 1 — VBS Path (WinCC V7 Only)

WinCC V7 exposes a clean VBS object model on the alarm logging runtime. The full canonical pattern for locking a specific alarm by its message number from a global action, a button click, or a picture-level event is shown below.

Lock a single message

' WinCC V7 — Lock a specific alarm by tag-name + message number
' Trigger: button click, scheduled action, or picture event

Sub OnClick(ByVal Item)
    Dim sTagName
    Dim lMsgNr
    Dim oAlarmLog

    sTagName = "MyAlarmTag"        ' <-- Logical message tag, NOT the trigger tag
    lMsgNr   = 1                    ' <-- Message number from Alarm Logging editor

    Set oAlarmLog = HMIRuntime.AlarmLogging

    ' Hide: removes from visible list
    oAlarmLog.HideAlarm sTagName, lMsgNr, 0, True

    ' Lock: keeps in list but disables operator action
    oAlarmLog.Lock sTagName, lMsgNr
End Sub

Unlock the same message

Sub OnClick_UnLock(ByVal Item)
    HMIRuntime.AlarmLogging.Unlock "MyAlarmTag", 1
    HMIRuntime.AlarmLogging.HideAlarm "MyAlarmTag", 1, 0, False
End Sub

Iterate the alarm list and lock all visible messages

This is the V7 equivalent of the GetRowCollection pattern attempted in the V6 field report. Note that V7 returns an ICollection, not a RowCollection; iteration is index-based and 1-based.

Sub OnClick_LockAllVisible(ByVal Item)
    Dim oCtrl, oMessages, oMsg, i

    Set oCtrl = ScreenItems("Control1")    ' name of the WinCC Alarm Control
    Set oMessages = oCtrl.GetMessageCollection(0)  ' 0 = all statuses

    For i = 1 To oMessages.Count
        Set oMsg = oMessages.Item(i)
        ' Lock every message that is currently "came in" and not yet acknowledged
        If (oMsg.State And 1) = 1 And (oMsg.State And 4) = 0 Then
            HMIRuntime.AlarmLogging.Lock oMsg.MsgTag, oMsg.Number
        End If
    Next
End Sub
V6 compatibility note: In WinCC V6 the Alarm Control OCX does not expose GetMessageCollection on its public dispatch interface. The only practical path on V6 is the ODK C-Action described in Method 2. Trying ScreenItems("Control1").GetRowCollection on V6 returns error Object does not support this property or method — the same runtime error reported in the source thread.

Method 2 — C-Action Path with ODK (V6 and V7)

For WinCC V6 sites, or for V7 projects that need to read and react to message state from inside a C function (typical for arithmetic-heavy logic), use the ODK directly. The ODK ships with header msrtapi.h and an import library that must be linked into the WinCC graphics runtime.

C-Action: lock by message number

// WinCC C-Action — lock a specific alarm by number
// Trigger: button click on a WinCC Alarm Control toolbar button

#include "apdefap.h"
#include "msrtapi.h"

void OnClick(char* lpszPictureName, char* lpszObjectName)
{
    DWORD dwState = 0;
    const char* szTagName = "MyAlarmTag";   // Logical message tag
    const DWORD dwMsgNr   = 1;              // Message number

    // Read current state (server call — synchronous)
    MSRTGetMsgState(szTagName, dwMsgNr, &dwState);

    // If the message is currently visible (bit 0x0010 set) and not
    // already locked (bit 0x0008), lock it.
    if ((dwState & MSG_STATE_ENABLE) && !(dwState & MSG_STATE_LOCK))
    {
        MSRTLockMsg(szTagName, dwMsgNr);
    }

    // Optionally also hide the row from the visible list
    MSRTHideMsg(szTagName, dwMsgNr);
}

C-Action: scheduled unlock after delay

#include "apdefap.h"
#include "msrtapi.h"

// Trigger: configured on a 1-Hz timer; tracks the lock-expiry timestamp
static DWORD g_dwUnlockAt = 0;

void OnTimer(char* lpszPictureName, char* lpszObjectName)
{
    DWORD dwNow = GetTickCount();

    if (g_dwUnlockAt != 0 && dwNow >= g_dwUnlockAt)
    {
        MSRTUnlockMsg("MyAlarmTag", 1);
        MSRTShowMsg("MyAlarmTag", 1);
        g_dwUnlockAt = 0;
    }
}

// Called once from a button or startup event to start the 2-min inhibit window
void OnClick_StartInhibit(char* lpszPictureName, char* lpszObjectName)
{
    MSRTLockMsg("MyAlarmTag", 1);
    MSRTHideMsg("MyAlarmTag", 1);
    g_dwUnlockAt = GetTickCount() + 120000UL;  // 120 s = 2 minutes
}

ODK linkage checklist

  1. Install ODK from the WinCC setup disk: WinCC Setup → Select Components → ODK.
  2. Confirm the environment variable WINCC_OAP_DIR resolves to C:\Program Files\Siemens\Automation\WinCC\OAP (path varies by version).
  3. In WinCC Explorer, open the computer properties, navigate to Graphics Runtime → C-Script, and verify the include path contains %WINCC_OAP_DIR%\include.
  4. Link with apdefap.c and the import library aplib.lib found under %WINCC_OAP_DIR%\lib. WinCC performs this step automatically for project-internal C-Actions.
  5. License the ODK runtime on every engineering and runtime station. Without a valid license, MSRTLockMsg returns MSRT_E_NOLICENSE (-16).

Method 3 — Scheduler-Based Inhibit (No Scripting)

For a deterministic, auditable 2-minute inhibit window after runtime start, use the WinCC Scheduler to disable the message class or specific message numbers for a time range. This is the only method that survives a WinCC client crash and that does not require an ODK license.

  1. In WinCC Explorer, open Alarm Logging → Message Classes.
  2. Right-click the target class → Properties → Disable via Scheduler.
  3. Add a time event: type = Once, trigger time = runtime start time (use @CurrentTime + 2 min for relative offset if WinCC version supports it; otherwise hardcode a wall-clock window).
  4. Action = Disable message class.
  5. Add a second event 2 minutes later: action = Enable message class.

This is also the correct method if the requirement is to inhibit all alarms of a class (e.g., all process alarms during a recipe load) rather than individual message numbers.

Method 4 — Source-Side Delay (Recommended for Plant Architecture)

The most robust pattern, used in plant installations with both local SCADA and a remote control center, is to delay the alarm at its source — typically a CFC chart or an S7 block output. The alarm bit is held false for 2 minutes after the controlling tag transitions to a stable state, then released. WinCC is unaware of the inhibit and reports the exact moment it is allowed to act. This approach is recommended by experienced SCADA integrators because the same logic is enforced in both the local WinCC and any remote control center receiving the same tag.

Implementation in S7 CFC: use a TON (on-delay timer) with PT = 2 min on the alarm enable signal, so the alarm only becomes visible after the controlled value has been stable for the full window.

Cross-Version Compatibility Matrix

Table 2 — Alarm locking method vs. WinCC version
Method V6.2 V7.0 V7.4 / V7.5 Notes
VBS HMIRuntime.AlarmLogging.Lock No Yes (SP1+) Yes Cleanest API; no ODK license required
Alarm Control OCX GetRowCollection No (error) Yes Yes Use GetMessageCollection in V7.4+
C-Action + ODK MSRTLockMsg Yes Yes Yes Requires ODK license
Scheduler-based class disable Yes Yes Yes No license; wall-clock based
Source-side delay (CFC/S7) Yes Yes Yes Independent of WinCC version

Troubleshooting Matrix

Table 3 — Common error codes and resolutions
Symptom Root cause Resolution
Object does not support this property or method: k_obj_almctrl.getrowcollection Code is running in WinCC V6 against an Alarm Control that does not implement GetRowCollection in its V6 dispatch interface Switch to ODK C-Action with MSRTLockMsg for V6, or upgrade graphics runtime to V7 SP3+
Lock succeeds on one client, ignored on another Local scope: script calls a client-side object instead of HMIRuntime.AlarmLogging Always call HMIRuntime.AlarmLogging.Lock; never call methods on a local ScreenItems Alarm Control to mutate server state
MSRTLockMsg returns MSRT_E_NOLICENSE (-16) ODK runtime license missing or expired on the station Reinstall the ODK license via Automation License Manager; restart WinCC runtime
Lock toggles back to unlocked after 1 second Another C-Action or scheduled task is calling MSRTUnlockMsg concurrently Audit all C-Actions and scheduled actions referencing the same message number; add a global lock flag to coordinate
Message is locked but still appears in the visible list with a lock icon (operator expects it gone) Code called Lock but not HideAlarm Call HMIRuntime.AlarmLogging.HideAlarm sTagName, lMsgNr, 0, True after the lock to remove from visible list
MSRTGetMsgState returns 0 even when the message is active Wrong tag name passed — must be the logical message tag (the trigger tag configured in the message row), not a derived tag Open Alarm Logging → select message row → read the trigger tag from the Attributes column
VBS script compiles but errors at first call Picture is set to "Global Script Runtime" not "Picture-specific Runtime", or vice versa, and ScreenItems is not in scope Move the call to a global action with a fully qualified HMIRuntime.AlarmLogging reference; avoid ScreenItems in global actions

Verification Procedure

  1. Trigger the alarm in the test system by forcing the trigger tag to a value that causes the message condition. Confirm the alarm appears in the WinCC Alarm Control.
  2. Execute the lock call (button click, scheduled action, or C-Action). Expected: the alarm either disappears from the visible list (if hidden) or appears with a lock icon and cannot be acknowledged.
  3. Cross-client check: open a second WinCC client. The locked state must be visible there too — this confirms the lock is server-side, not local.
  4. Query state directly via the WinCC ODK sample application ODK_Example (installed with the ODK). Call MSRTGetMsgState and confirm the returned DWORD has bit 0x0008 set (MSG_STATE_LOCK).
  5. Operator action test: attempt to acknowledge or process the locked alarm in the WinCC Alarm Control. The button must be grayed out or return "Operation not permitted".
  6. Time-based release: if the lock is scheduled to release after 2 minutes, verify by waiting and re-querying state. After release, the alarm (if still active) returns to the visible list and can be acknowledged normally.
  7. Persistence test: restart the WinCC runtime. The lock state must be retained if it was server-side via ODK / AlarmLogging.Lock. A purely client-side lock (rare, but possible with a misconfigured script) will be lost.

Field-Commissioning Checklist

  • Confirm ODK is licensed on every runtime node, not just the engineering station.
  • For multi-server / redundant WinCC pairs, the lock must be applied to the server that owns the alarm — usually the master. Verify the script is running on the correct machine context.
  • Document the message tag and number in the project functional specification, not just in the script. Auditors require this mapping.
  • If the project uses both WinCC V6 and V7 (mixed fleet, e.g., during a migration), segregate scripts into V6_ODK and V7_VBS folders to avoid accidental cross-deployment.
  • Add a global VBS OnError handler around the lock call to log failures to a diagnostic tag, so support engineers can see in WinCC itself if the lock failed.
  • For the 2-minute startup inhibit pattern, prefer the scheduler approach over a runtime timer — the scheduler survives a WinCC runtime crash, a timer does not.

Safety and Operational Considerations

Alarm locking is a temporary, operator-visible state. It is not a substitute for proper alarm management per ISA-18.2 / IEC 62682. A locked alarm must be reviewed for deadbands, priorities, and shelving policy. Operators must be trained to recognize the lock icon and to escalate if a critical alarm is unexpectedly suppressed. Never use a 2-minute startup inhibit as a workaround for poor alarm rationalization — the inhibit should be the exception, not the default.

FAQ

Why does my VBS lock script work in WinCC V7 but fail in V6 with "Object does not support this property or method"?

The V6 WinCC Alarm Control OCX does not implement GetRowCollection or GetMessageCollection on its public dispatch interface. The VBS pattern in Method 1 requires WinCC V7 SP1 or later. For V6, switch to the ODK C-Action with MSRTLockMsg(szTagName, dwMsgNr) from msrtapi.h, which is available on both V6 and V7.

How do I lock a specific alarm by its number without putting an Alarm Control on the screen?

Call HMIRuntime.AlarmLogging.Lock "<LogicalMessageTag>", <MessageNumber> from a global VBS action in WinCC V7, or call MSRTLockMsg("<LogicalMessageTag>", <MessageNumber>) from a C-Action with ODK in V6 or V7. No Alarm Control is required; the call goes directly to the alarm logging service.

What is the difference between MSG_STATE_LOCK (0x0008) and MSG_STATE_HIDDEN (0x0080)?

A locked message stays visible in the alarm list with a lock icon, cannot be acknowledged, but is auditable as suppressed. A hidden message is removed from the visible list entirely. Use lock for traceability, hide for a clean operator view. The two can be combined: Lock first, then HideAlarm.

Can I inhibit alarms for exactly 2 minutes after runtime start without writing any script?

Yes. Use the WinCC Alarm Logging Scheduler to disable the target message class at runtime start, then enable it again 2 minutes later via a second scheduled event. The scheduler is wall-clock based and survives runtime crashes, unlike a runtime timer or a C-Action scheduled on a 1-Hz poll.

Do I need an ODK license to lock alarms in WinCC V7?

No, not for the VBS path. HMIRuntime.AlarmLogging.Lock is part of the standard V7 runtime and does not require ODK. The ODK license is required only for the C-Action path (MSRTLockMsg) and for the WinCC Connectivity Pack. If your project uses only VBS, you can skip the ODK license on the runtime stations.

Back to blog