Resolving MSRTEnumArchivData Error 0x00000001 in WinCC ODK

David Krause9 min read
SiemensTroubleshootingWinCC
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

Problem Overview

The WinCC ODK (Open Development Kit) C/C++ API exposes the MSRTEnumArchivData function for enumerating Alarm Logging messages within a defined time window. When integrating this function into an export routine that mirrors a working TLGGetArchivDataEx archive-value export, the call frequently returns FALSE with a populated CMN_ERROR structure:

Error in MSRTEnumArchivData: E1= 0x00000001 ; E2= 0x00000000
Connection to the message system run time could not be set up!
File [F:\GEN_AKTUELL\HMI_WINCC_01_SRC\SC_RT_SERVER\ServerServices\Server\MsRtCli\src\app\CMsRt.cpp]
Line [4099]

The Tag Logging counterpart TLGGetArchivDataEx continues to function, indicating that the ODK transport itself is intact. The failure is isolated to the Messaging Runtime (MSRT) subsystem. This article documents the root cause, the corrective pattern, and the verification procedure to ensure repeatable Alarm Logging export.

Technical Background: WinCC ODK MSRT API

The MSRT prefix denotes the WinCC Messaging System Runtime client interface. Three functions form the minimum session envelope:

Function Purpose Return Type
MSRTStartMsgService Opens a session to the alarm runtime, installs a user callback, and applies a MSG_FILTER_STRUCT. BOOL + CMN_ERROR
MSRTEnumArchivData Enumerates or reads archived messages matched by the active filter. BOOL + CMN_ERROR
MSRTStopMsgService Closes the session and detaches the callback. BOOL + CMN_ERROR

The official reference is the WinCC ODK Programmer's Manual entry for "MSRT - functions for message access". The API is delivered with WinCC V7.x and is identical (with minor additions) across V7.0 through V7.5 SP2. The header files ship under \<WinCC>\ApiLib\MsrtApi\:

  • MsrtCli.h — function prototypes
  • CustData.h — MSG_FILTER_STRUCT, MSG_DATA_STRUCT, archive flags
  • CmnErr.h — CMN_ERROR definition

The header path is configured in the Visual Studio project as C/C++ → Additional Include Directories; the matching libraries (MsrtCli.lib, ScRtSrv.lib) are added under Linker → Input → Additional Dependencies.

Decoding Error 0x00000001

The CMN_ERROR layout used by the ODK is:

typedef struct _CMN_ERROR {
    DWORD dwError1;       // subsystem ID or HRESULT-equivalent
    DWORD dwError2;       // function-specific error code
    TCHAR szErrorText[256];
    DWORD dwReserved1[4];
    DWORD dwReserved2;
} CMN_ERROR;

For the MSRT subsystem, dwError1 = 0x00000001 combined with the runtime string "Connection to the message system run time could not be set up!" identifies error class MSRT_E_NO_CONNECTION. It is raised internally on file CMsRt.cpp at the call site of MSRTEnumArchivData and is returned when the runtime reference counted handle associated with the dwServiceID is no longer valid — either because the service was never started, already closed, or detached while a callback was still in flight.

dwError1 Symbolic Class Typical Root Cause
0x00000001 MSRT_E_NO_CONNECTION Service handle invalid, runtime not active, or callback detached prematurely
0x00000002 MSRT_E_FILTER_INVALID MSG_FILTER_STRUCT contains an unknown filter name or zeroed time slice
0x00000003 MSRT_E_NO_DATA Time window contains no archived messages
0x00000010 MSRT_E_ACCESS_DENIED User lacks "Configure remote messaging" OS right

Root Cause: Premature Service Shutdown

The regression is lifecycle-related. The runtime delivers archived messages asynchronously to the callback registered with MSRTStartMsgService. If the caller invokes MSRTStopMsgService before the callback has drained its queue — or, more commonly, immediately after a synchronous MSRTEnumArchivData whose data is still being delivered — the runtime decrements the session reference count to zero. The next internal access from MSRTEnumArchivData finds the handle dereferenced and returns MSRT_E_NO_CONNECTION.

The second contributing condition is the runtime activation. The Alarm Logging runtime must be started before any ODK consumer calls MSRTStartMsgService. WinCC Graphical Runtime and WinCC ServiceMode have independent configuration surfaces:

  1. Computer properties → Startup — tick Alarm Logging Runtime. Activated in WinCC Explorer by selecting the computer, opening Properties, switching to the Start-up tab.
  2. ServiceMode project — the service-mode configuration script under Siemens\WinCC\<project>\config\ServiceModeConfig.xml must contain <AlarmLogging enabled="1"/>; otherwise the service-mode process exits the messaging component.
  3. ODK connection path — the project receiving the ODK call must be the one whose MSRTCli instance resolves the named pipe \\.\pipe\MsRtCli_<project>. A cross-project call requires either dual start or explicit project mapping.

Solution: Correct Callback and Session Lifecycle

Apply both fixes together: ensure runtime activation, and never close the service while the callback is active. The pattern below is the minimum correct sequence.

// Callback must be thread-safe; do not allocate from inside it.
void CALLBACK MyMSGServiceNotifyCallback(
    DWORD dwServiceID,
    DWORD dwMsg,
    DWORD dwCount,
    LPMSG_DATA_STRUCT pMsgData,
    LPVOID pUserData)
{
    EnterCriticalSection(&g_cs);
    for (DWORD i = 0; i < dwCount; ++i) {
        // Persist pMsgData[i] or stage for MSRTEnumArchivData to read.
        g_pending.push_back(pMsgData[i]);
    }
    LeaveCriticalSection(&g_cs);
}

// Producer thread / ODK caller
BOOL ret;
CMN_ERROR Error;
DWORD dwServiceID = 0;
MSG_FILTER_STRUCT MsgFilter;
SYSTEMTIME t0, t1;

memset(&Error, 0, sizeof(CMN_ERROR));
memset(&MsgFilter, 0, sizeof(MSG_FILTER_STRUCT));
_tcscpy(MsgFilter.szFilterName, _T("DAILY_BACKUP"));
MsgFilter.dwFilter = MSG_FILTER_DATE | MSG_FILTER_TIME;

GetLocalTime(&t0); t0.wHour = 0;  t0.wMinute = 0;  t0.wSecond = 0;  t0.wMilliseconds = 0;
GetLocalTime(&t1); t1.wHour = 23; t1.wMinute = 59; t1.wSecond = 59; t1.wMilliseconds = 999;
MsgFilter.st[0] = t0;
MsgFilter.st[1] = t1;

ret = MSRTStartMsgService(&dwServiceID, MyMSGServiceNotifyCallback,
                          &MsgFilter, MSG_NOTIFY_MASK_ALL, NULL, &Error);
if (!ret) { /* inspect Error.dwError1 */ return; }

// Give the callback a chance to drain the first batch.
Sleep(500);

DWORD dwFlags = MSG_ARCHIV_ENUM_DESC;
ret = MSRTEnumArchivData(dwServiceID, FALSE, 0xFFFFFFFF, dwFlags, &Error);
if (!ret) { /* inspect Error.dwError1; do NOT stop service on transient */
    if (Error.dwError1 != 0x00000003) {
        MSRTStopMsgService(dwServiceID, &Error);
        return;
    }
}

// IMPORTANT: only stop the service after the callback has gone idle.
// In MFC/Win32 call MSG_PEEK via dwMsg == MSG_NOTIFY_MASK_END_OF_TRANSFER
// or simply wait until g_pending stabilises.
while (g_callbacksInFlight) { Sleep(50); }

MSRTStopMsgService(dwServiceID, &Error);

Notes on the example:

  • The callback runs on an internal MSRT worker thread. It is the user's responsibility to synchronize access to shared state; use a CRITICAL_SECTION or equivalent.
  • The MSG_FILTER_STRUCT field szFilterName can reference a preconfigured filter archive (defined in Alarm Logging), but for time-windowed enumeration the MSG_FILTER_DATE | MSG_FILTER_TIME flags with explicit st[0]/st[1] are sufficient.
  • On MSRT_E_NO_DATA (0x00000003) the session remains valid — the export simply produced an empty window. Do not stop the service.

Runtime Activation Checklist

Confirm the messaging runtime is loaded before launching the ODK consumer:

  1. Open WinCC Explorer on the WinCC server computer.
  2. Right-click the computer icon → Properties → tab Start-up.
  3. Tick Alarm Logging Runtime; click Apply.
  4. For ServiceMode deployments, verify the registry value HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Siemens\Automation\WinCC\<project>\Alarm has Active = 1.
  5. Re-cycle the runtime (WinCC Explorer → Computer → Stop Runtime → Start Runtime). The named pipe MsRtCli_<project> appears once activation completes; verify via Process Explorer.
  6. Confirm the user account running the ODK application has the SE_ACTIVATE_WINCC_REMOTE privilege. The ODK functions interact via WinCC inter-process named pipes; ACLs on \\.\pipe\MsRtCli_* must grant access.

Step-by-Step: Resolving the Failure

  1. Reproduce — Run the original code with the WinCC runtime active. Capture the exact CMN_ERROR triple (dwError1, dwError2, szErrorText).
  2. Confirm runtime — Open WinCC Alarm Control on the server. Trigger a test message (use MSRTCreateMsg from a test harness). If the message appears in WinCC Alarm Control but the ODK API reports MSRT_E_NO_CONNECTION, runtime is fine.
  3. Verify callback — Add a debug counter incremented inside MyMSGServiceNotifyCallback. If it increments but MSRTEnumArchivData still fails, the service was stopped prematurely.
  4. Apply the lifecycle fix — Refactor as in the code sample: do not stop the service inside the same scope that calls MSRTEnumArchivData; wait until callbacks drain.
  5. Cross-check archive — Inspect Alarm Logging → Archive Configuration. The relevant archive must be set to All events or contain the message classes enumerated by the filter.
  6. Permission check — From the ODK application server, attempt to access \\<WinCCServer>\pipe\MsRtCli_<project> via raw CreateFile; an ERROR_ACCESS_DENIED reveals an ACL problem.
  7. Re-run — Confirm MSRTEnumArchivData now returns TRUE and that the export text file contains the expected entries.

Verification and Test Procedure

Check Expected Outcome Diagnostic
MSRTStartMsgService TRUE, dwServiceID > 0 If FALSE with dwError1 = 0x10: missing privilege
Callback firing Counter increments after MSRTCreateMsg If never increments: callback pointer invalid or pipe not connected
MSRTEnumArchivData TRUE; szErrorText empty FALSE with 0x03: empty window, valid state
Export file lines Matches Alarm Logging row count for window Significant delta suggests tz or DST misalignment
MSRTStopMsgService TRUE and process exits cleanly FALSE after drain: reentrant stop attempt — guard with critical section

The Diagnostic Data Recorder (channel "API Monitor") under WinCC Explorer can be enabled to capture all ODK function calls and their resulting CMN_ERROR structures for offline review. Outputs are written to <project>\Diagnosis\.

Related API Functions

The MSRT family is presented in the WinCC ODK reference manual:

  • MSRTCreateMsg — injects a single message into the live queue; useful to verify connectivity independent of archived data.
  • MSRTGetMsgServiceInfo — reports the current session state and the archive backend selected for MSG_FILTER_NAME.
  • MSRTSetMsgFilter — applies a new filter to an open session; combined with the existing szFilterName you can rotate windows without restarting the service.
  • MSRTReadMessageQueue — alternative entry point for live messages (non-archived); referenced in the ODK manual section on message system access.

The Tag Logging sibling API uses the TLG prefix (TLGGetArchivDataEx, TLGStart, TLGStop) and follows a similar three-phase lifecycle. When building a unified export, the recommended pattern is two parallel sessions — one TL session, one MSRT session — each closed independently in its own draining loop. The ODK does not provide a single function that unifies both subsystems.

Operational Notes and Caveats

  • The MSG_FILTER_DATE | MSG_FILTER_TIME combination returns messages whose appearance time falls inside the window. For state and acknowledgement times, change the dwFilter to MSG_FILTER_STATE_DATE | MSG_FILTER_STATE_TIME.
  • WinCC archives messages in UTC and renders to the project local time. Time windows that span a daylight savings boundary can drop or duplicate entries; always cross-reference local time and UTC inside the export routine.
  • When the ODK application runs on a different computer than the WinCC server, configure the named-pipe remote access under Computer Properties → Remote and ensure the export account has identical credentials on both ends; otherwise MSRTStartMsgService will fail with MSRT_E_NO_CONNECTION for an entirely different reason (network reachability vs. lifecycle).
  • The ODK runtime DLLs (MsrtCli.dll, ScRtSrv.dll) are loaded into the WinCC process boundary. Mixing debug and release builds across the consumer and the runtime introduces heap corruption that masks itself as connection errors; compile every component with the same Configuration and matching platform (x86 vs x64).
Critical: Never call MSRTStopMsgService while the callback may still be active. The resulting MSRT_E_NO_CONNECTION on the next enumeration is the symptom described above but can also mask as sporadic data loss without leaving any error in szErrorText. Add an end-of-transfer notification in MSG_NOTIFY_MASK_END_OF_TRANSFER before the stop call, and join the callback thread deterministically.

FAQ

What does MSRTEnumArchivData error 0x00000001 mean?

It maps to MSRT_E_NO_CONNECTION: the session handle returned by MSRTStartMsgService is no longer valid. The most common cause is calling MSRTStopMsgService while the registered callback is still active, or invoking the enumerator before the runtime reference count is non-zero.

Does the Alarm Logging runtime need to be running before MSRTStartMsgService?

Yes. The runtime must be activated under Computer Properties → Start-up → Alarm Logging Runtime and the named pipe MsRtCli_<project> must exist. Confirm with WinCC Alarm Control or call MSRTCreateMsg first as a connectivity test.

How do I export messages from a specific time window?

Build a MSG_FILTER_STRUCT with dwFilter = MSG_FILTER_DATE | MSG_FILTER_TIME and populate st[0] / st[1] with SYSTEMTIME values for the window. Pass the struct to MSRTStartMsgService before invoking MSRTEnumArchivData with MSG_ARCHIV_ENUM_DESC.

Why does TLGGetArchivDataEx work but MSRTEnumArchivData fails?

The TL and MSRT subsystems are independent. Tag Logging and Alarm Logging both have their own runtime activation toggles and named pipes. Tag Logging can be active while Alarm Logging is off, explaining the asymmetry.

Can I run MSRT enumeration from a remote computer?

Yes, when WinCC Remote is licensed and the named-pipe ACLs allow the connecting account. Use the same domain or mirrored local account on both machines. Mismatched credentials return MSRT_E_NO_CONNECTION via the pipe layer before any function returns.

Back to blog