The Hard-Coded Path Problem in WinCC VBScript
Most first-pass WinCC VBScript code embeds an absolute path such as C:\Program Files\Siemens\Automation\WinCC\WinCCProjects\MyPlant\Documents\recipe.xls directly into objExcelApp.Workbooks.Open or HMIRuntime.Tags.Write calls. The script works on the engineering station, passes FAT, then fails the first time the runtime PC is imaged, the project is renamed, the disk is re-lettered, or a parallel C: drive is mapped on the panel PC. The root cause is not WinCC; it is the absence of a project-relative anchor inside the script itself.
Three properties of a WinCC runtime project are stable regardless of where the project is installed:
- The project's root folder (the directory that contains the project file, e.g.
MyPlant.MCPorMyPlant.WCC). - Standard sub-folders under that root:
GraCS(graphics/pictures),Library,Documents,Archive,ScriptLib,Logs. - The runtime object
HMIRuntime, which is exposed to every C-/VBScript action.
A script only needs one of these anchors to compose a portable path. This article walks through the three production-grade methods used in WinCC V7, WinCC V7.4 SP1, WinCC Professional (TIA Portal V15–V18), and WinCC Runtime Advanced, and shows how to wrap each into a reusable helper function.
ActiveX component can't create object (Error 429) is raised the first time the script runs.Prerequisites and Environment
Before adopting dynamic paths, confirm the runtime target meets the requirements below.
| Component | WinCC V7.4 / V7.5 | WinCC Professional (TIA Portal) | WinCC Runtime Advanced |
|---|---|---|---|
| VBScript interpreter | Built-in, ANSI mode | WinCC RT Professional: built-in; RT Advanced: VBScript via Global Script / local scripts | Subset of VBScript (no FSO on some panels) |
| HMIRuntime object | Yes (full) | Yes (full in RT Pro, partial in RT Adv) | Yes, RT Adv exposes HmiRuntime (note casing) |
| Scripting.FileSystemObject | Yes (reference Microsoft Scripting Runtime) | Yes in RT Pro; not guaranteed on every RT Adv panel image | Conditional – test on target panel |
| Excel automation | Requires 32-bit Excel or Microsoft Excel XX.X Object Library reference | Same | Not supported on most panels |
| Action trigger | Picture event, tag trigger, scheduler | Same | Same |
References used in this article:
- Siemens KB 109746405 — WinCC V7.4 SP1: Working with VBScript
- Siemens KB 109768582 — WinCC VBScript reference (HMIRuntime object)
- Microsoft Docs — Excel.Workbooks.Open method
- Microsoft Scripting Blog — How Can I Determine the Path to the Folder Where a Script is Running?
- Microsoft Docs — FileSystemObject object
Method 1 — HMIRuntime.ActiveProject.Path
The HMIRuntime automation object is the WinCC-supplied entry point for every C and VB action. Among its members, ActiveProject.Path returns the absolute directory of the currently loaded project — the directory that contains *.MCP (WinCC V7) or *.WCC (TIA Portal) — without a trailing backslash.
Syntax
HMIRuntime.ActiveProject.Path
Reference implementation
'\ ---------------------------------------------------------------
'\ Module: mod_PathHelpers
'\ Purpose: Provide project-relative paths without hard-coding.
'\ Tested: WinCC V7.4 SP1, WinCC V7.5 SP2, WinCC RT Professional V17
'\ ---------------------------------------------------------------
Function ProjectRoot()
ProjectRoot = HMIRuntime.ActiveProject.Path
End Function
Function ProjectPath(ByVal relativeFolder, ByVal fileName)
'\ Build a path such as <ProjectRoot>\Documents\recipe.xls
Dim s
s = HMIRuntime.ActiveProject.Path
If Right(s, 1) <> "\" Then s = s & "\"
ProjectPath = s & relativeFolder & "\" & fileName
End Function
'\ Example call inside a button-click action:
Dim strFile
strFile = ProjectPath("Documents", "recipe.xls")
MsgBox "Opening: " & vbCrLf & strFile
objExcelApp.Workbooks.Open strFile
Why this is the preferred anchor
- Zero coupling to the calling picture, the calling script file, or any graphic PDL.
- Stable across re-installations, drive reassignments, and project renaming.
- Standard: documented in the WinCC VBScript reference (object HMIRuntime, property ActiveProject, sub-object Project, property Path).
HmiRuntime (mixed case) rather than HMIRuntime. When porting code between WinCC V7 and RT Advanced, add a guard: If IsObject(HmiRuntime) Then ... ElseIf IsObject(HMIRuntime) Then ...
Method 2 — FileSystemObject Walk-Up from a Known File
There are situations where HMIRuntime.ActiveProject is not desirable — for example, when a script must run during project startup, before the runtime has fully bound ActiveProject, or inside a Global Script action that runs outside a picture context. The fall-back is to anchor the path to a file the script knows exists, then walk upward through FileSystemObject.ParentFolder.
The pattern, taken from the WinCC community and refined for production use:
Dim fso, f, s
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.GetFile("An_Existing_Picture.PDL_") '\ replace with a real PDL on disk
s = UCase(f.Path)
s = UCase(f.ParentFolder.ParentFolder) & "\Documents\excelFile.xls"
MsgBox "Resolved to: " & s
objExcelApp.Workbooks.Open s
How the walk-up works
-
GetFile("An_Existing_Picture.PDL_")resolves a known file relative to the WinCC working directory (typicallyGraCS\). -
f.Pathreturns the absolute path, e.g.C:\Program Files\Siemens\Automation\WinCC\WinCCProjects\MyPlant\GraCS\An_Existing_Picture.PDL_. -
f.ParentFolderis one level up —\GraCS. -
f.ParentFolder.ParentFolderis two levels up — the project root. - The string
"\Documents\excelFile.xls"is appended to land inside the conventionalDocumentssub-folder.
Hardening the FSO walk-up
Function ResolveSiblingPath(ByVal anchorFile, ByVal upLevels, ByVal tail)
'\ anchorFile : file relative to CWD that we are CERTAIN exists
'\ upLevels : how many ParentFolder hops to the project root
'\ tail : tail string beginning with "\", e.g. "\Documents\data.csv"
Dim fso, f, p, i
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(anchorFile) Then
Err.Raise vbObjectError + 1001, , "Anchor file not found: " & anchorFile
End If
Set f = fso.GetFile(anchorFile)
p = f.ParentFolder.Path
For i = 1 To upLevels
Set p = fso.GetFolder(p).ParentFolder
Next
ResolveSiblingPath = p.Path & tail
End Function
'\ Usage:
Dim s
s = ResolveSiblingPath("An_Existing_Picture.PDL_", 2, "\Documents\recipe.xls")
Method 3 — Microsoft Scripting Runtime Walk-Up from the Script Itself
For global actions stored in ScriptLib\ rather than picture-bound actions, the script can walk up from its own location. The Microsoft Scripting team documents the pattern in the article How Can I Determine the Path to the Folder Where a Script is Running?. The native VBScript equivalent in WinCC is:
Function ScriptFolder()
Dim fso, f
Set fso = CreateObject("Scripting.FileSystemObject")
'\ WScript.ScriptFullName is not available inside WinCC,
'\ but the action is executed with CWD = ScriptLib (global)
'\ or = GraCS (picture event). Use a known file as the anchor
'\ instead of a non-existent WScript reference.
Set f = fso.GetFile("StandardFunctions.bas_") '\ any known file in CWD
ScriptFolder = f.ParentFolder.Path
End Function
The general VBScript idiom using WScript.ScriptFullName does not work inside WinCC because WScript is not exposed. The Microsoft blog is still the canonical reference for the shape of the solution — substitute HMIRuntime or a known file for the WinCC equivalent.
Building a Portable Path Helper Module
In real projects, three or four file locations recur: Documents\, Archive\, Logs\, and a Templates\ folder for stamped-out Excel reports. Promote these into one module:
Option Explicit
Public Const FOLDER_DOCUMENTS As String = "Documents"
Public Const FOLDER_LOGS As String = "Logs"
Public Const FOLDER_TEMPLATES As String = "Documents\Templates"
'\ Returns <ProjectRoot>
Public Function ProjectRoot() As String
ProjectRoot = HMIRuntime.ActiveProject.Path
End Function
'\ Returns <ProjectRoot>\<subFolder>
Public Function ProjectFolder(ByVal subFolder As String) As String
Dim p : p = ProjectRoot()
If Right(p, 1) <> "\" Then p = p & "\"
ProjectFolder = p & subFolder & "\"
End Function
'\ Returns <ProjectRoot>\<subFolder>\<fileName>
Public Function ProjectFile(ByVal subFolder As String, _
ByVal fileName As String) As String
ProjectFile = ProjectFolder(subFolder) & fileName
End Function
Callers now read like configuration, not magic strings:
Dim wbPath
wbPath = ProjectFile(FOLDER_TEMPLATES, "RecipeTemplate.xltx")
objExcelApp.Workbooks.Open wbPath
Cross-Version Compatibility: WinCC V7 vs TIA Portal
The two runtime lines have identical concepts but slightly different object models. The table below is the minimum mapping required to port code unchanged.
| Capability | WinCC V7.4 / V7.5 | WinCC RT Professional (TIA V15–V18) |
|---|---|---|
| Runtime object name | HMIRuntime |
HmiRuntime (RT Pro) / HMIRuntime (legacy mode) |
| Project path property | HMIRuntime.ActiveProject.Path |
HmiRuntime.ActiveProject.Path |
| Tag write | HMIRuntime.Tags("MyTag").Write value |
HmiRuntime.Tags("MyTag").Write value |
| Trigger (cyclic) | Configured on the action | Configured on the action, name Trigger |
| Global script location | <Project>\ScriptLib\ |
<Project>\ScriptLib\ for RT Pro; RT Adv uses project-local scripts only |
| FSO availability | Always | Always on RT Pro; absent on many RT Adv panel images |
| Office automation | WinCC station must have 32-bit Office | Same constraint; cannot host Office on RT Adv panels |
A safe forward-compatible shim:
Function Rt()
If IsObject(HmiRuntime) Then
Set Rt = HmiRuntime
ElseIf IsObject(HMIRuntime) Then
Set Rt = HMIRuntime
Else
Err.Raise vbObjectError + 9001, , "Neither HMIRuntime nor HmiRuntime available"
End If
End Function
Function ProjectRoot()
ProjectRoot = Rt().ActiveProject.Path
End Function
Excel Workbook Integration Patterns
Dynamic paths only matter because the code that consumes them is fragile. Three patterns are common in production WinCC deployments.
Pattern A — Read a recipe from a project-shipped Excel template
Dim xlApp, xlWb, xlWs
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = False
xlApp.DisplayAlerts = False
Set xlWb = xlApp.Workbooks.Open(ProjectFile(FOLDER_TEMPLATES, "RecipeTemplate.xltx"))
Set xlWs = xlWb.Worksheets("Recipe")
Dim recipeID : recipeID = xlWs.Range("B2").Value
HMIRuntime.Tags("Recipe_ID").Write recipeID
xlWb.Close False
xlApp.Quit
Set xlWs = Nothing : Set xlWb = Nothing : Set xlApp = Nothing
Pattern B — Append a batch record to a project-local CSV
Sub AppendBatch(ByVal line)
Dim fso, ts, path
path = ProjectFile(FOLDER_LOGS, "BatchLog_" & Year(Now) & ".csv")
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(path) Then
Set ts = fso.OpenTextFile(path, 2, True) '\ ForWriting, create
ts.WriteLine "Timestamp,BatchID,Operator,Result"
Else
Set ts = fso.OpenTextFile(path, 8, False) '\ ForAppending
End If
ts.WriteLine FormatDateTime(Now, vbGeneralDate) & "," & line
ts.Close
End Sub
Pattern C — Generate a stamped PDF from a template
Sub GenerateReportPDF(ByVal batchID As String)
Dim xlApp, xlWb
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = False
xlApp.DisplayAlerts = False
Set xlWb = xlApp.Workbooks.Open(ProjectFile(FOLDER_TEMPLATES, "ReportTemplate.xltx"))
xlWb.Worksheets("Sheet1").Range("B2").Value = batchID
xlWb.ExportAsFixedFormat 0, ProjectFile(FOLDER_DOCUMENTS, "Batch_" & batchID & ".pdf")
'\ 0 = xlTypePDF (Excel constant; the numeric avoids missing-reference errors)
xlWb.Close False
xlApp.Quit
End Sub
CreateObject("Excel.Application"). See Siemens KB 109746405.
Error Handling, Logging, and Diagnostics
A dynamic path that silently falls back to C:\ is worse than a hard-coded one. Wrap every external call in On Error Resume Next + an explicit check on Err.Number, and persist the error to a project-local log so the field engineer can recover without remote desktop.
Sub LogError(ByVal ctx As String, ByVal where As String)
Dim fso, ts, path
path = ProjectFile(FOLDER_LOGS, "ScriptErrors.log")
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile(path, 8, True)
ts.WriteLine FormatDateTime(Now, vbGeneralDate) & vbTab & _
ctx & vbTab & where & vbTab & _
"Err.Number=" & Err.Number & vbTab & _
"Err.Description=" & Err.Description & vbTab & _
"Err.Source=" & Err.Source
ts.Close
On Error GoTo 0
End Sub
'\ Canonical call site:
Sub OpenRecipe()
On Error Resume Next
Dim path : path = ProjectFile(FOLDER_DOCUMENTS, "recipe.xls")
If Err.Number <> 0 Then
LogError "OpenRecipe", "ProjectFile"
Exit Sub
End If
objExcelApp.Workbooks.Open path
If Err.Number <> 0 Then
LogError "OpenRecipe", "Workbooks.Open("" & path & "")"
Exit Sub
End If
On Error GoTo 0
End Sub
Common error numbers observed in WinCC VBScript
| Err.Number | Meaning | Likely cause | Remediation |
|---|---|---|---|
| 429 | ActiveX component can't create object | 64-bit Office installed, or Excel reference missing | Install 32-bit Office; add Microsoft Excel XX.X Object Library reference |
| 70 | Permission denied | File locked by another process, or UAC-protected path | Close holders; run WinCC runtime as a user with write rights on Documents\
|
| 76 | Path not found | Sub-folder Documents missing on the target |
Have the script create the folder with fso.CreateFolder
|
| 80070002 | The system cannot find the file specified | 32/64-bit mismatch with Office, or template deleted | Re-deploy the template via project download |
| 80004005 | Unspecified automation error | Excel still showing modal dialog from prior call | Set xlApp.DisplayAlerts = False; call xlApp.Quit; nullify objects |
Verification and Deployment Checklist
Run this checklist on the panel PC before declaring the path fix complete.
- Open the WinCC project from a non-default location (e.g.
D:\Projects\MyPlant\) and confirmHMIRuntime.ActiveProject.PathreturnsD:\Projects\MyPlant. - Trigger the action that opens an Excel file. Verify the file opens and
ScriptErrors.logremains empty. - Move the entire project folder to a different drive letter (e.g.
E:\) and re-start the WinCC runtime. The action must continue to work. - Rename the project file (e.g.
MyPlant.MCP→MyPlant_2024.MCP) and re-load. Verify the resolved path updates automatically. - Force a permission failure: revoke write rights on
Documents\and confirmScriptErrors.logrecords a70with the resolved path that was attempted. - Stop the WinCC runtime, install 64-bit Office (test only), and confirm the action fails with Err 429 — proving the diagnostics are wired.
- Re-install 32-bit Office. Confirm recovery without restarting the WinCC runtime (the script re-creates the COM object on next invocation).
- Export the
ScriptLibfolder from the engineering station and diff it against the runtime copy to confirm parity.
Troubleshooting Matrix
| Symptom | Root cause | Diagnostic | Fix |
|---|---|---|---|
| Action fails only on the second runtime start | Excel process leaked from the previous run; Quit not called |
Task Manager shows EXCEL.EXE *32 | Always call xlApp.Quit and set object variables to Nothing
|
| Path resolves but file does not open | Template was deleted during a partial project download |
ScriptErrors.log shows Err 76 |
Add fso.CreateFolder and fso.CopyFile from a known-good source at startup |
Path resolves to C:\Program Files\Siemens\... on a panel without that drive |
Script is using a hard-coded fallback | Grep the source for C:\Program Files
|
Remove all literal absolute paths; route every path through ProjectFile()
|
| Works in WinCC V7, fails in RT Professional | Object name case mismatch | Runtime debugger shows Object required: 'HMIRuntime' | Use the Rt() shim shown earlier |
| Works on engineering station, fails on panel | Panel image lacks FSO | Err 429 on CreateObject("Scripting.FileSystemObject")
|
Use only HMIRuntime-based paths on RT Advanced; pre-create folders on the engineering station and download them |
| Path with spaces fails to open in Excel | Spaces not properly handled when command-line tooling is invoked | Cmd-line opens fine; Excel call fails | Wrap path in Chr(34) only when needed; Excel Workbooks.Open handles spaces natively |
Field-Proven Caveats
-
Network shares.
HMIRuntime.ActiveProject.Pathworks with UNC paths (\\srv\WinCC\MyPlant) provided the WinCC service account has read/write rights on the share. Do not mix UNC and mapped-drive paths within the same project. -
Project duplication. When a project is duplicated for a sister line, search for any remaining
C:\Program Files\Siemens\...literals — those are the next failure candidates. -
Folder creation race. If a cyclic action and a startup action both try to create
Logs\at the same time, wrap the call inOn Error Resume Next; the second caller will see Err 76/Path already exists and silently continue. -
Logging into the same file. Always null
tsafterClose; leaving the TextStream open across the runtime boundary leaks handles. -
Localization. Windows localized
Documentsfolders do not affect WinCC — theDocumentssub-folder is created under the WinCC project, not under the user profile, so locale does not matter.
FAQ
Does HMIRuntime.ActiveProject.Path include a trailing backslash?
No. HMIRuntime.ActiveProject.Path returns the directory without a trailing separator. Always append "\" (or use ProjectFolder() from the helper module above) before concatenating sub-folders or file names.
Why does my VBScript work in the WinCC Explorer but fail at runtime?
Most runtime-only failures are caused by missing reference resolution. In the engineering station, the script runs with full IDE-time references; at runtime, only the registered type libraries resolve. Ensure Microsoft Scripting Runtime and Microsoft Excel XX.X Object Library are registered system-wide (32-bit), and avoid New keyword syntax — use CreateObject("Excel.Application") instead.
Can I use the same dynamic-path code on WinCC Runtime Advanced on a Comfort Panel?
Only partially. HmiRuntime.ActiveProject.Path is available, but FileSystemObject is not guaranteed on all RT Adv images and Excel automation is not supported. Stick to ProjectFolder() for read/write of tag archives and CSV files; never attempt CreateObject("Excel.Application") on a panel.
How do I find the project path from inside a global action that runs before picture activation?
Use HMIRuntime.ActiveProject.Path directly — it is independent of any picture. If ActiveProject is not yet bound (very early in startup), fall back to the FileSystemObject walk-up method anchored on a known file in the ScriptLib folder.
Is there a way to keep the Excel reference out of the project but still drive Excel?
Yes. Use late binding: CreateObject("Excel.Application") and dispatch through Invoke-style property names. The downside is no IntelliSense and no compile-time checking; the upside is zero references and immunity to Office version bumps. For new projects, prefer late binding plus the Path helpers above.