Overview
WinCC (TIA Portal, WinCC Professional, RT Professional, and the legacy WinCC / PCS 7 V7.x faceplates) exposes a VBScript runtime that can drive Microsoft Excel through the Excel.Application COM object and exchange data with the tag database through the HMIRuntime object. A common field requirement is to load a recipe, parameter setpoint, or test matrix from a spreadsheet and write the cell values into internal or external WinCC tags without a CSV import wizard. This reference describes the complete VBScript pattern: opening an Excel workbook, reading UsedRange data, comparing two columns, highlighting mismatched rows in red/green, and writing validated values back to the WinCC tag database through HMIRuntime.Tags(...).Write.
The reference is written for PCS 7 V7.0 SP3 / V8.x faceplates but applies to all WinCC runtimes that ship the VBScript engine, including WinCC Comfort, WinCC RT Advanced, and WinCC RT Professional. Script execution is triggered from a button event (OnLButtonDown), from a scheduled Global Script action, or from a C-script callback. The patterns below are valid for all three.
EXCEL.EXE) must be installed on the WinCC Runtime station. WinCC Runtime does not ship Excel; the OS image of every HMI server or OS client that runs this script must include Microsoft Office (or at minimum the Office Primary Interop Assemblies). On TIA Portal V17+ projects targeting RT Professional on a Win32 panel, COM access to Excel requires Office x86 because WinCC Runtime itself is a 32-bit process.
Prerequisites
- Software: PCS 7 V7.0 SP3 or higher, WinCC Explorer, Microsoft Office 2007 / 2010 / 2013 / 2016 / 2019 / 365 installed on the Runtime station.
- Licensing: The WinCC Runtime license must permit VBS scripting (standard on every WinCC RT and PCS 7 OS). No additional license key is required for Excel COM automation.
-
Tags: The destination tags (
Tag1,Tag2, ...) must exist in the WinCC tag database and be reachable in Runtime. Internal binary tags work without PLC connection; external tags require an active S7 / OPC channel. -
File path: The Excel workbook (
D:\Excel file.xlsin the example below) must be reachable from the Runtime account. On a WinCC service-account install, preferC:\Recipes\with read/write NTFS rights for theCCAdmin/WinCCUserservice identity. -
DCOM security: If the Runtime runs as a Windows service (WinCC OS Server), grant the WinCC service account Launch/Activation permissions for the Excel COM application via
dcomcnfg→ Component Services → Computers → DCOM Config → Microsoft Excel Application. -
Graphic object: A button graphic on the target screen/picture that fires the script on
OnLButtonDown. The script can also be fired from a Global Script Action (cyclic or tag-triggered).
HMIRuntime Object Model and Tag Access
The HMIRuntime object is the root namespace for all VBS actions in WinCC Runtime. It exposes the Tags collection, the ScreenItems collection (for screen-bound I/O fields, bars, sliders, etc.), and the DataSet interface (WinCC RT Professional and WinCC V7.4+).
| Method / Property | Type | Description |
|---|---|---|
HMIRuntime.Tags("Name") |
Method | Returns a Tag object bound to the named tag in the tag database. |
objTag.Read |
Method | Refreshes objTag.Value with the current process value (returns 0 on success, WinCC error code on failure). |
objTag.Write |
Method | Writes objTag.Value to the tag database / connected PLC (returns 0 on success). |
objTag.Value |
Property | Read/write variant holding the current tag value. For external tags, this is the cached PLC image; call .Read first. |
objTag.QualityCode |
Property | WinCC quality stamp (0xC0 = Good, 0x40 = Bad, 0x00 = Uncertain). See WinCC Scripting: VBS, ANSI-C, VBA (ID 37572697). |
HMIRuntime.Screens("Screen") |
Method | Returns a screen object to access faceplate I/O fields. |
ScreenItems("IOField1") |
Property | Accesses a named I/O field on the current picture. Use .OutputValue for read, .Value for write. |
When tags are linked automatically by a PCS 7 faceplate library (e.g. CTRL_PID, CTRL_DOSE, VALVE_ANA), the same HMIRuntime.Tags("...") accessor reaches the structured Process Tag; no screen I/O field is needed. The Set objTag = HMIRuntime.Tags("...") call does not require objTag.Read for write-only flows, but calling .Read first is mandatory when the tag value is read before being overwritten.
Excel COM Automation in WinCC
Excel is driven through the classic COM IDispatch interface. The three mandatory object references are:
-
objExcelApp–Excel.Applicationinstance. -
objWorkSheet– a specificWorksheetinsideobjExcelApp.ActiveWorkbook. -
objWorkSheet.Cells(row, col)– a single cell (1-based row and column indices).
The lifecycle of objExcelApp must be managed carefully. The WinCC script host is a long-lived process; an Excel instance that is not properly closed with .Quit and unhooked with Set ... = Nothing will accumulate as ghost processes and eventually block the station. Every reference collected below must be released, not only the top-level objExcelApp.
Basic Read/Write Code Structure
The minimal working pattern reads two cell values and writes them into two WinCC tags. This is the canonical snippet that ships with the Siemens support entry 37572697 and is the basis for the comparison variant below.
' Triggered on button mouse-down event on the WinCC picture
Sub OnLButtonDown(ByVal Item, ByVal Flags, ByVal x, ByVal y)
Dim objExcelApp
Dim objWorkSheet
Dim objTag1, objTag2
Dim intRet
Set objExcelApp = CreateObject("Excel.Application")
objExcelApp.Visible = True ' set False in production
objExcelApp.Workbooks.Open "D:\Excel file.xls"
Set objWorkSheet = objExcelApp.ActiveWorkbook.Worksheets(1)
Set objTag1 = HMIRuntime.Tags("Tag1_name")
Set objTag2 = HMIRuntime.Tags("Tag2_name")
objTag1.Value = objWorkSheet.Cells(2, 4).Value ' D2
objTag2.Value = objWorkSheet.Cells(3, 4).Value ' D3
intRet = objTag1.Write
intRet = objTag2.Write
objExcelApp.ActiveWorkbook.Save
objExcelApp.Workbooks.Close
objExcelApp.Quit
Set objWorkSheet = Nothing
Set objTag1 = Nothing
Set objTag2 = Nothing
Set objExcelApp = Nothing
End Sub
What each line does
| Line | Purpose |
|---|---|
CreateObject("Excel.Application") |
Late-binds Excel without a type library; works on every Office version from 2003 to 365. |
objExcelApp.Visible = True |
Useful for commissioning only. Set False for production to avoid stealing focus. |
Workbooks.Open "D:\Excel file.xls" |
Path is resolved against the Runtime machine, not the engineering station. Use UNC for a shared recipe directory. |
objWorkSheet.Cells(2,4) |
Cell D2. The cell returns a Variant; Excel's empty cell returns Empty, not zero. |
objTag1.Write |
Returns 0 on success, -1 on connection error, or a WinCC-specific error code on tag-not-found. |
For screen-bound writes (no PLC, only I/O field), the RT Professional equivalent is documented at Examples of VBS — RT Professional and uses ScreenItems("IOField1").Value = objExcelApp.Cells(1,1).Value.
Iterating UsedRange and Comparing Cells
For a multi-row recipe or test matrix, hard-coding cell coordinates does not scale. UsedRange returns the rectangle that bounds all populated rows and columns. Two important properties:
-
UsedRange.Rows.Count— the number of populated rows, starting from the first non-empty row. -
UsedRange.Columns.Count— the number of populated columns, starting from the first non-empty column.
Always declare loop counters with Dim i; missing the Dim statement silently creates an implicit Variant and breaks string vs numeric comparison.
Sub CompareExcelColumns()
Dim objExcelApp, objWorkSheet
Dim i, a, b, intBad
Set objExcelApp = CreateObject("Excel.Application")
objExcelApp.Visible = False
objExcelApp.Workbooks.Open "D:\Recipes\test_matrix.xls"
Set objWorkSheet = objExcelApp.ActiveWorkbook.Worksheets(1)
a = objWorkSheet.UsedRange.Rows.Count
b = objWorkSheet.UsedRange.Columns.Count
intBad = 0
For i = 2 To a ' assume row 1 is the header
If (objWorkSheet.Cells(i, 3).Value <> _
objWorkSheet.Cells(i, 4).Value) Then
' mismatch on row i
objWorkSheet.Cells(i, 5).Interior.ColorIndex = 3 ' red
intBad = intBad + 1
Else
objWorkSheet.Cells(i, 5).Interior.ColorIndex = 4 ' green
End If
Next
HMIRuntime.Tags("MISMATCH_COUNT").Value = intBad
HMIRuntime.Tags("MISMATCH_COUNT").Write
objExcelApp.ActiveWorkbook.Save
objExcelApp.Workbooks.Close
objExcelApp.Quit
Set objWorkSheet = Nothing
Set objExcelApp = Nothing
End Sub
ColorIndex reference (Excel default palette)
| ColorIndex | Color | Use case |
|---|---|---|
| 3 | Red | Mismatch / fault |
| 4 | Bright green | Match / pass |
| 6 | Yellow | Warning / tolerance exceeded |
| 36 | Light yellow | Soft warning |
RGB(r,g,b) |
Custom | Use .Interior.Color = RGB(200,160,35) for custom branding. |
<> on VBS variants uses value equality, not text equality. If cell C2 contains the text "1.0" and D2 contains the number 1, the comparison returns True (not equal). To force a strict text compare, wrap with CStr(...) on both sides; for a strict numeric compare, use CDbl(...) with a defensive IsNumeric guard.
Highlighting Mismatched Cells
The highlighting line objWorkSheet.Cells(i, 5).Interior.ColorIndex = 3 is the minimum-effort path. For more advanced visual feedback, use:
' Custom color (BGR-encoded in older Excel, RGB in modern Excel)
objWorkSheet.Cells(i, 5).Interior.Color = RGB(255, 102, 102) ' red tone
' Add a comment for traceability
objWorkSheet.Cells(i, 5).AddComment _
"Mismatch detected at " & Now & " by WinCC Runtime"
' Bold the result column
objWorkSheet.Cells(i, 5).Font.Bold = True
For extremely large sheets, write the color result directly into a WinCC tag instead of coloring the cell, to keep the COM round-trip time predictable. WinCC Runtime COM calls to Excel are synchronous on the script thread and block the UI for the duration of the call; a 10 000-row UsedRange scan can take 3-8 seconds.
Robust Error Handling and Resource Cleanup
WinCC VBS does not support On Error Resume Next reliably when COM objects are involved, because an error in a COM call leaves the reference half-initialized. Use the structured pattern below, which checks object states and forces Excel termination through a separate cleanup routine.
Sub OnLButtonDown(ByVal Item, ByVal Flags, ByVal x, ByVal y)
Dim objExcelApp, objWorkSheet
Dim objTag1, objTag2
Dim blnExcelStartedHere
blnExcelStartedHere = False
On Error Resume Next
' Try to reuse an existing Excel session if one is already running
Set objExcelApp = GetObject(, "Excel.Application")
If Err.Number <> 0 Then
Err.Clear
Set objExcelApp = CreateObject("Excel.Application")
blnExcelStartedHere = True
End If
On Error Goto 0
If objExcelApp Is Nothing Then
HMIRuntime.Trace "Excel COM unavailable - aborting"
Exit Sub
End If
objExcelApp.Visible = False
objExcelApp.Workbooks.Open "D:\Recipes\setpoint.xls"
Set objWorkSheet = objExcelApp.ActiveWorkbook.Worksheets(1)
Set objTag1 = HMIRuntime.Tags("SP_TEMP")
Set objTag2 = HMIRuntime.Tags("SP_FLOW")
objTag1.Value = CDbl(objWorkSheet.Cells(2, 4).Value)
objTag2.Value = CDbl(objWorkSheet.Cells(3, 4).Value)
objTag1.Write
objTag2.Write
' ---- Cleanup ---------------------------------------------------
On Error Resume Next
objExcelApp.ActiveWorkbook.Save
objExcelApp.Workbooks.Close
If blnExcelStartedHere Then objExcelApp.Quit
Set objWorkSheet = Nothing
Set objTag1 = Nothing
Set objTag2 = Nothing
Set objExcelApp = Nothing
On Error Goto 0
End Sub
HMIRuntime.Trace writes to the WinCC diagnostic file C:\Program Files\Siemens\Automation\WinCC\Diagnosis\WinCC_Sys_<date>.log. Every error path must leave a trace line, otherwise post-mortem analysis on a customer machine is impossible.
File Path, Format and Office Version Considerations
| Format | Extension | Behavior with Workbooks.Open
|
|---|---|---|
| Excel 97-2003 workbook | .xls |
Opens natively; no prompt for format conversion. |
| Excel 2007+ workbook | .xlsx |
Requires Excel 2007+; do not rename .xls to .xlsx or Excel will throw 0x800A03EC. |
| Excel macro-enabled | .xlsm |
Macros are not executed when opened via COM unless objExcelApp.AutomationSecurity = 1 (msoAutomationSecurityLow). Avoid this in production. |
| CSV / text | .csv |
Requires Workbooks.OpenText with explicit delimiter; Workbooks.Open may silently import only the first column. |
Use absolute paths or UNC paths. Workbooks.Open "Excel file.xls" is resolved against the current directory of the WinCC Runtime process, which is typically C:\Program Files\Siemens\Automation\WinCC\bin and almost never the location of your recipe file. Also confirm that the Runtime service account has Read/Write on the folder; missing NTFS rights are the single most common root cause of -2147024891 (0x80070005 Access denied).
Performance and Runtime Considerations
-
Synchronous COM blocking: Every
Cells(...).Valueis a cross-process marshaling call. Reading 1 000 cells takes ~1.5 s; reading 50 000 cells takes > 60 s and will be observed as a frozen WinCC screen. Read into a 2D Variant array in one call:arr = objWorkSheet.UsedRange.Value. - Async / background tasks: For long-running Excel work, fire the script from a Global Script action (cyclic 1 s) and check a trigger tag; do not block the UI thread.
-
Process accounting: Excel does not always release file locks. Always
.Save,.Close,.Quit, andSet objExcelApp = Nothingin that order. -
Anti-virus / EDR: Some EDR products intercept
CreateObject("Excel.Application")as suspicious behavior. Whitelist the WinCC Runtime directory (C:\Program Files\Siemens\Automation\WinCC\bin) in the EDR policy. -
Excel DCOM on remote OS server: On a PCS 7 OS Server accessed from a thin client, Excel must be licensed per-device or per-user under the same identity that runs WinCC. A failing COM call returns
0x80040154(Class not registered) or0x80080005(server execution failed).
Fast bulk read pattern (preferred for > 100 rows)
Dim arrData
arrData = objWorkSheet.UsedRange.Value ' 2D Variant, 1-based
Dim i, intRows
intRows = UBound(arrData, 1)
For i = 2 To intRows
HMIRuntime.Tags("SP_" & CStr(i)).Value = arrData(i, 4)
HMIRuntime.Tags("SP_" & CStr(i)).Write
Next
Verification and Diagnostics
-
Trace output: Insert
HMIRuntime.Trace "Cell D2=" & objWorkSheet.Cells(2,4).Valueafter the read and confirm the value in the WinCC diagnostic file. - Tag check: Open WinCC Explorer → Tag Management → right-click the target tag → Properties → confirm the Last Value field updates after the script fires.
-
PLC round trip: For external tags, monitor the corresponding DB / input word in STEP 7 / TIA Portal with an online watch table. The WinCC address is computed from the configured channel; for S7-300/400 it is
DBxx.DBWy, for S7-1500/1200 it is%DBxx.DBWy%. - Process Historian: PCS 7 tags written through VBS produce a history entry; query Tag Logging to verify the timestamp and value.
-
Excel side: After
.Save, re-open the workbook manually and confirm that the cell color has been applied to the rows that the script flagged.
Common error codes
| Hex / Decimal | Source | Likely cause |
|---|---|---|
0x80040154 (-2147221012) |
COM | Excel is not installed or COM class not registered. |
0x80070005 (-2147024891) |
COM | Access denied. Check DCOM security, NTFS rights on workbook, and Runtime account. |
0x800A03EC |
Excel | Format error — .xls file is actually .xlsx, or sheet index out of range. |
-1 |
objTag.Write |
PLC channel offline or tag not found. |
-2 |
objTag.Read |
Quality not Good. Inspect objTag.QualityCode. |
Why does my script compile but not write any tag value?
Most often a missing Dim i (or another loop variable) causes the script to fall through the loop body without a runtime error. Add explicit Dim statements for every loop counter and re-deploy the picture to Runtime. Reloading the script while Runtime is open does not always flush compiled VBS — stop/start Runtime after editing.
How do I read more than one row from Excel without writing 50 lines of code?
Use arr = objWorkSheet.UsedRange.Value to load the entire UsedRange into a 2D Variant array in one COM call, then loop with For i = 2 To UBound(arr, 1). This pattern is roughly 100x faster than repeated Cells(i, j).Value access and keeps the WinCC UI responsive.
Can I write the Excel values to PCS 7 faceplate tags without a screen I/O field?
Yes. PCS 7 faceplates expose structured tags through the WinCC tag database; the script Set objTag = HMIRuntime.Tags("CTRL_PID_1_SP") reaches the setpoint of a PID faceplate directly. No ScreenItems reference is required because the tag is already linked in the WinCC tag manager.
Why does Excel stay in memory after the script ends?
You forgot to release the COM references. Every Set obj... must end with a matching Set obj... = Nothing, and objExcelApp.Quit must run before the variable is set to Nothing. Run tasklist /FI "IMAGENAME eq EXCEL.EXE" on the Runtime station to confirm clean-up.
Does this work on TIA Portal V20 / V21 WinCC RT Professional without modification?
Yes. The HMIRuntime object, the Tags collection, and the Excel COM late-binding pattern are unchanged across V15 to V21. See the official example at Siemens Docs (TIA Portal V21) and the WinCC scripting KB entry ID 37572697.