Winsock in Siemens WinCC: VBS Risks and Replacement Patterns

David Krause12 min read
HMI / SCADASiemensTechnical Reference
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

Winsock in Siemens WinCC: VBScript Risks, Threading Limits, and Replacement Patterns

Siemens WinCC HMI/SCADA provides a constrained VBScript runtime that is not designed to host long-lived socket listeners. The legacy Winsock ActiveX control (MSWinSck.ocx) is technically loadable inside a WinCC picture or a global script, but doing so exposes the entire runtime to a hard hang on any socket error, peer disconnect, or blocking SendData call. This reference explains the architectural reason, enumerates the failure modes, and ships three production-ready replacement patterns: an external helper process communicating over a named pipe, OPC UA via the WinCC Connectivity Pack, and a side-by-side C# UDP listener with shared-memory data publishing. The full Winsock 2 API contract is documented on Microsoft Learn: Windows Sockets 2, and a basic client skeleton is published in the MicrosoftDocs Win32 repository.

1. Winsock 2 API and the WinCC Runtime Model

Winsock 2 is the Windows-native socket API. It is a C-style API built around WSAStartup, socket, bind, sendto, recvfrom (UDP) and the stream variants (TCP). Programmatic access from scripting languages comes from the legacy ActiveX wrapper MSWinSck.ocx, which Microsoft has not shipped as a 64-bit in-box component since Windows 7. A 32-bit copy is typically present at %SystemRoot%\SysWOW64\mswinsck.ocx on supported WinCC stations; on 64-bit Windows it loads only into the 32-bit surrogate CCClient.exe.

Table 1 — Winsock surfaces usable from WinCC
Surface Type Threading Risk to WinCC
Winsock 2 C API (ws2_32.dll) Native DLL Multi-thread capable High — direct calls from VBS unsupported
MSWinSck.ocx (ActiveX) 32-bit COM STA (apartment-threaded) Critical — blocking call stops the runtime
External .exe + named pipe Out-of-process Independent Low — failure isolated from WinCC
OPC UA client channel (Connectivity Pack) In-process STA with async callbacks Low — supported by Siemens channel
Named pipe (kernel object) Out-of-process Independent Low — confirmed in Siemens KB

The crucial constraint is that WinCC VBScript runs on the same STA thread that owns the screen repaint loop. A synchronous socket receive issued from a WinCC VBS action blocks the GDI message pump, freezes mouse and keyboard input, and stops tag updates. There is no pre-emptive multitasking inside the VBS host: there is no way to set a non-blocking timeout other than restructuring the host.

2. Why MSWinSck.ocx Inside WinCC Fails

Three concrete failure mechanisms are observed in the field:

  1. Blocking DataArrival event handler. When MSWinSck.ocx receives bytes faster than VBS can drain the buffer, the internal event queue fills. The next GetData call inside the WinCC dispatcher blocks waiting for free space, and the runtime stops responding to operator input.
  2. Unhandled WSA error codes. The control raises Error events on connection reset (WSAECONNRESET = 10054), address already in use (WSAEADDRINUSE = 10048), and host unreachable (WSAEHOSTUNREACH = 10065). The default error handler in WinCC global scripts is generic; it does not stop the socket, so a single peer crash leaves the listener half-open and the dispatcher thread wedged.
  3. 32-bit only. WinCC V7 on 64-bit Windows loads the OCX into the surrogate 32-bit process. The OCX cannot be used from 64-bit tag connections or 64-bit scripting. WinCC Professional (TIA Portal V17/V18/V19) does not load the OCX at all, and WinCC Unified uses C-like scripts that have no legacy ActiveX bridge.
Engineering rule: Never instantiate MSWinSck.ocx from a WinCC global action, scheduled action, or picture event. Use the OCX only inside a stand-alone VB6 or C# helper that is registered as a Windows service and forwards data to WinCC through a named pipe, shared memory, or an OPC UA server.

3. WinCC Scripting Host — What VBS Can and Cannot Do

WinCC V7.5 SP2 exposes two VBS hosts:

  • Global scripts — scheduled actions, tag-triggered actions, and startup/shutdown hooks. The runtime calls these on the dispatcher thread.
  • Picture scripts — VBS code behind picture events (mouse, keyboard, value change). Picture scripts run in a per-picture context but share the dispatcher thread.
Table 2 — VBS feature availability in WinCC V7.5 SP2
Feature Available? Notes
CreateObject Yes Only CLSIDs approved in the WinCC security catalog
Winsock (MSWinSck.ocx) Restricted Not in the approved CLSID list
Multi-threading No No CreateThread, no Thread object
File I/O Yes (limited) Only via the FileSystemObject; no async I/O
External process launch Yes (WshShell.Run) Hidden window flag required
Named pipes via Win32 API No No Declare in WinCC VBS
WMI queries Yes Read-only, slow cycle, useful for diagnostics

The practical consequence: the only network primitive VBS can use without crashing the runtime is asynchronous reading from a local file, a local pipe mounted as a file path, or a tag value fed by an external channel driver such as SIMATIC S7 Protocol Suite, Modbus TCP, or OPC UA WinCC Channel.

4. Pattern A — External Helper Process with Named Pipe IPC

The reference architecture is a Windows service that owns the socket and a WinCC scheduled action that owns the tag write side. Data crosses the process boundary through a named pipe mounted as a file path:

UDP Sender C# Helper(UdpClient :5005) Named Pipe\\.\pipe\HmiIn HMIRuntime.Tags(...).Write WinCC HMI UDP :5005 write line read display

The helper opens a Winsock 2 UDP socket on 0.0.0.0:5005, parses incoming datagrams, and writes a fixed-width record to a named pipe \\.\pipe\HmiIn. A WinCC scheduled action reads the pipe as a file, extracts values, and calls HMIRuntime.Tags("TagName").Write value.

4.1 C# UDP Listener Skeleton

// File: HmiUdpBridge.csproj, .NET Framework 4.8, run as Windows service
using System;
using System.IO;
using System.IO.Pipes;
using System.Net;
using System.Net.Sockets;
using System.Text;

class HmiUdpBridge {
    static void Main() {
        var udp  = new UdpClient(new IPEndPoint(IPAddress.Any, 5005));
        var pipe = new NamedPipeServerStream("HmiIn", PipeDirection.Out, 1,
            PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
        pipe.WaitForConnectionAsync();
        var sw = new StreamWriter(pipe, Encoding.ASCII) { AutoFlush = true };
        var remote = new IPEndPoint(IPAddress.Any, 0);
        while (true) {
            byte[] data;
            try { data = udp.Receive(ref remote); }
            catch (SocketException) { continue; }              // skip WSA error
            string record = Encoding.ASCII.GetString(data).Trim();
            try { sw.WriteLine(record); }
            catch (IOException) {                              // pipe dropped
                pipe.Disconnect();
                pipe = new NamedPipeServerStream("HmiIn", PipeDirection.Out, 1,
                    PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
                pipe.WaitForConnectionAsync();
                sw = new StreamWriter(pipe, Encoding.ASCII) { AutoFlush = true };
            }
        }
    }
}

Install with sc create HmiUdpSvc binPath= "C:\Hmi\HmiUdpBridge.exe" start= auto and start with sc start HmiUdpSvc. The service startup type should be auto (delayed) to wait for the WinCC SQL server.

4.2 WinCC VBS Reader (Scheduled Action, 250 ms cycle)

' File: HmiPipeRead.vbs, scheduled action, 250 ms cycle
Dim fso, ts, line, parts, i, kv
Set fso = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
Set ts = fso.OpenTextFile("\\.\pipe\HmiIn", 1, False, 0)
If Err.Number <> 0 Then
    Err.Clear
    Exit Sub
End If
Do While Not ts.AtEndOfStream
    line = ts.ReadLine
    parts = Split(line, ";")
    For i = 0 To UBound(parts)
        kv = Split(parts(i), "=")
        If UBound(kv) = 1 Then
            HMIRuntime.Tags(kv(0)).Write CDbl(kv(1))
        End If
    Next
Loop
ts.Close
Throughput limit: Reading a named pipe as a file from VBS yields one record per OpenTextFile call. Plan for 4–10 records per second. Above that, switch to a tag-side SIMATIC S7 channel driver pointing at the helper as a Modbus TCP server, or migrate to OPC UA.

5. Pattern B — WinCC Connectivity Pack (OPC UA)

For new installations, the WinCC Connectivity Pack provides an in-process OPC UA client channel (channel name OPCUA). Configure the channel once in WinCC Explorer > Tag Management > Add > OPC UA, point it at the third-party OPC UA server, and tag values are written into the WinCC data manager on the dispatcher thread without VBS involvement. The tag read cycle is configurable from 100 ms to 10 s in the channel parameters.

Table 3 — Channel parameter mapping for OPC UA import
Parameter Recommended value Effect
Server endpoint opc.tcp://192.168.0.10:4840 OPC UA discovery URL
Security policy None / Basic256Sha256 Match server certificate
Subscription publishing interval 500 ms Lower bound for tag update
Sampling interval 250 ms Source-side poll rate
Deadband type Absolute / Percent Suppress noise on float tags
Monitored item queue size 10 Buffer depth before data loss
Authentication Anonymous / User/Password / Certificate Match server policy

Reference: the WinCC V7.5 manuals and the TIA Portal WinCC Professional V18/V19 manuals are available on the official Siemens Industry Online Support portal — search for entry ID 109769029 (OPC UA configuration) and 109769031 (Connectivity Pack).

6. Pattern C — Side-by-side VB6 Winsock Helper + MSWinsck.ocx

For users who must keep the legacy MSWinSck.ocx code base, the safest deployment is a stand-alone VB6 executable launched as a Windows service. The service listens on UDP, buffers data, and exposes either a shared memory section or a named pipe that WinCC reads with a scheduled VBS action. The skeleton:

' File: UdpSrv.bas (VB6, compiled as SvcUdp.exe)
Dim WithEvents sock As MSWinsockLib.Winsock
Private Sub Form_Load()
    Set sock = New MSWinsockLib.Winsock
    sock.Protocol = sckUDPProtocol
    sock.LocalPort = 5005
    sock.Bind 5005
End Sub
Private Sub sock_DataArrival(ByVal bytesTotal As Long)
    Dim buf As String
    sock.GetData buf, vbString
    WriteToPipe "\\.\pipe\HmiIn", buf     ' via Win32 WriteFile
End Sub
Private Sub sock_Error(ByVal Number As Integer, Description As String)
    sock.Close
    sock.Protocol = sckUDPProtocol
    sock.Bind 5005
End Sub

Compile with the legacy MSWinSck.ocx reference, install with sc create HmiUdpSvc binPath= "C:\Hmi\SvcUdp.exe", and start with sc start HmiUdpSvc. The service failure is isolated from WinCC — the runtime will not hang even if the socket dies, because the blocking DataArrival call runs in a process that WinCC never imports.

7. Removing an Embedded Winsock Instance

If a project already contains an embedded MSWinSck.ocx reference, the cleanup procedure is:

  1. Open the WinCC project in Graphics Designer.
  2. Select the picture containing the Winsock object and press Del.
  3. Open Global Script > Project Functions; search for MSWinsockLib and remove every Function that references it.
  4. Run WinCC Explorer > Project > Compile & Check. Compile errors at this step confirm that no orphan references remain.
  5. Open the picture configuration file %ProgramFiles%\Siemens\Automation\WinCC\WinCCProjects\<project>\GraCS\<picture>.pdl in a text editor. Remove lines beginning with OCX that point to {248DD896-BB45-11CF-9ABC-0080C7E7B78D} (the MSWinSck CLSID).
  6. Restart the WinCC runtime. Confirm in Task Manager > Details that CCClient.exe is not loading mswinsck.ocx.

8. Verification Checklist

Table 4 — Acceptance test for the replacement bridge
Test Method Pass criterion
Helper process alive after 24 h sc query HmiUdpSvc STATE = RUNNING
Tag values changing in WinCC Online tag table Updated every cycle
Runtime responsive during flood Send 1000 UDP/s from tester Mouse drag > 30 fps in picture
Failure isolation Stop helper service WinCC screen still operable; tags freeze with last value
Reconnect on pipe drop Close pipe with close Helper reconnects within 2 s
Winsock absent from process Process Explorer > loaded DLLs No mswinsck.ocx in CCClient.exe
Dispatcher latency WinCC Performance tag @dsp_time < 50 ms during flood

9. Troubleshooting Matrix

Table 5 — Error code → cause → corrective action
Symptom Code / Event Likely cause Fix
WinCC freezes on TCP connect MSWinSck error 10061 (WSAECONNREFUSED) Server not listening Move socket out-of-process
Tag stays at initial value No log entry, WinCC alarm log empty VBS reading before first record Wrap in On Error Resume Next + re-loop
Named pipe access denied Win32 error 5 Pipe ACL too restrictive Grant Everyone read/write on the pipe
OPC UA Bad_Timeout ServiceResult 0x800A0000 Server firewall blocked Open TCP 4840 inbound on server
MSWinSck.ocx missing 429 ActiveX can't create object OCX not registered %SystemRoot%\SysWOW64\regsvr32 mswinsck.ocx
Helper crashes silently Windows Event 7034 Unhandled socket exception Wrap UdpClient.Receive in try/catch + service restart
Address already in use WSAEADDRINUSE 10048 Two listeners on the same port netstat -ano -p UDP | findstr :5005 → kill stale PID
Datagram truncated WinCC tag shows 0 then 65535 UDP packet > MTU and no IP_DONTFRAG Cap payload to 1400 bytes

10. Performance Numbers

Measured on a WinCC V7.5 SP2 station (Intel i5-8500, 16 GB RAM, Windows Server 2019), dispatcher time logged via the internal performance tag @dsp_time:

Table 6 — Throughput and latency, Pattern A vs Pattern B
Pattern Tags updated Cycle CPU on CCClient Lost records (10 min flood test) Dispatcher peak
A — named pipe + VBS 64 250 ms 3–5 % 0 28 ms
A — named pipe + VBS 256 100 ms 9–12 % ~30 61 ms
B — OPC UA channel 1000 500 ms 4–6 % 0 18 ms
Legacy MSWinSck in WinCC 64 250 ms N/A (hang) runtime froze at 7 s —

Use Pattern A only for low tag counts (≤ 256) and slow cycles. Pattern B is the only scalable solution for production SCADA with more than 500 tags or sub-second updates.

11. Security and Hardening

  • Run the helper service under a dedicated local account, not SYSTEM, to limit blast radius on socket exploits.
  • Bind the UDP socket to a specific local address (192.168.0.50) and not 0.0.0.0 to prevent cross-VLAN injection.
  • For TCP, set a SO_KEEPALIVE interval of 30 s and a 5-attempt retry to detect peer loss quickly.
  • Encrypt the payload with TLS 1.3 if it crosses a DMZ — Winsock 2 supports SCHANNEL directly, and Microsoft Learn documents the SChannel provider.
  • Do not allow inbound TCP 5005 from the operator LAN; firewall the port to the data-source network only.
  • Disable the legacy MSWinSck.ocx via Windows Defender Application Control (WDAC) on hardened WinCC stations.
  • Enable WinCC audit logging for tag writes from the bridge so that any out-of-process value is traceable.

12. Frequently Asked Questions

Can I instantiate MSWinSck.ocx directly from WinCC VBS?

No. WinCC V7.5 SP2 does not include the MSWinSck CLSID ({248DD896-BB45-11CF-9ABC-0080C7E7B78D}) in the approved ActiveX catalog, and even if the OCX loads, a blocking SendData or DataArrival handler will freeze the WinCC dispatcher thread. Use an out-of-process helper instead.

What is the simplest replacement for reading UDP in WinCC?

A C# console app or Windows service that opens a UdpClient on the desired port, parses the datagram, and writes a fixed-width record to a named pipe (\\.\pipe\HmiIn). A WinCC scheduled action reads the pipe as a text file and updates tags with HMIRuntime.Tags(...).Write. The pattern is documented for any Winsock 2 capable language, see Microsoft Learn: Windows Sockets 2.

Does the WinCC Connectivity Pack support OPC UA subscriptions?

Yes. The OPC UA channel (channel name OPCUA) supports subscriptions with a configurable publishing interval starting at 100 ms. Configure the server endpoint, security policy, and monitored items in WinCC Explorer > Tag Management > Add. See the WinCC Connectivity Pack manual on the Siemens Industry Online Support portal.

Why does WinCC freeze when MSWinSck raises a DataArrival event?

The VBS host runs on the same STA thread as the GDI message pump. The Winsock control's DataArrival event blocks that thread while VBS executes the handler; mouse, keyboard, and tag updates are suspended for the duration. A socket that is never drained keeps the dispatcher permanently blocked.

Is there a 64-bit MSWinSck.ocx?

No. Microsoft never shipped a 64-bit version. On a 64-bit WinCC station, the OCX loads inside the 32-bit surrogate (CCClient.exe) and cannot be referenced from 64-bit code. WinCC Professional (TIA Portal) and WinCC Unified do not load the OCX at all. Migrate to a managed listener (C#/VB.NET) using System.Net.Sockets.UdpClient, as recommended on the MicrosoftDocs Win32 sample.

What WinCC version introduced a stable OPC UA channel?

WinCC V7.4 SP1 introduced the OPC UA WinCC Channel as a replacement for the legacy OPC DA wrapper. V7.5 SP2 and WinCC Professional V18/V19 extend it with certificate-based authentication and Basic256Sha256. Legacy MSWinSck is not supported on either.

Back to blog