Overview
Opening operator manuals, machine documentation, and compiled HTML Help (CHM) files from a single click on an HMI/SCADA button is a recurring engineering requirement. The portable mechanism is the Wscript.Shell COM automation object invoked from VBScript. The same pattern works on Siemens WinCC, WinCC Professional (TIA Portal), FactoryTalk View SE/ME, Wonderware InTouch, iFIX, and any runtime that exposes VBScript to graphic events. This reference documents the working script, the CHM security traps (Unblock, ITSS protocol), PDF association failures, the ANSI-C equivalent for WinCC, the asynchronous launch variant, and a field-proven troubleshooting matrix.
Prerequisites
| Item | Requirement | Notes |
|---|---|---|
| Operating system | Windows 7 SP1 / Server 2008 R2 or later |
Wscript.Shell is a core COM object shipped with the OS |
| Script engine | VBScript 5.5+ | Built into modern Windows; no additional install required |
| PDF viewer | Adobe Acrobat Reader, Foxit, Edge, or SumatraPDF | Must be registered as the default handler for the .pdf extension |
| CHM viewer |
hh.exe (HTML Help) |
Triggers ITS protocol restrictions; see security section |
| NTFS access | Read on the target file and parent directory | Applies to the user account that runs the runtime |
| SCADA host | Button event with VBScript or ANSI-C action support | Verify in your runtime that the action type is exposed |
Working VBScript for PDF and CHM
The minimum reliable script uses WScript.Shell.Run with the second argument controlling window style. The constant 1 activates the new window and returns when the spawned process exits:
Dim objWshShell
Set objWshShell = CreateObject("Wscript.Shell")
objWshShell.Run "C:\Manuals\test.pdf", 1
Set objWshShell = Nothing
For CHM files the canonical invocation goes through hh.exe. Explicitly prefixing the executable avoids PATH-search issues on stripped runtime images:
Dim objWshShell
Set objWshShell = CreateObject("Wscript.Shell")
objWshShell.Run "hh.exe ""C:\Help\Operator.chm""", 1
Set objWshShell = Nothing
Note the doubled inner quotes required to embed a quoted path inside a VBScript string literal. The hh.exe prefix is optional on a default Windows install but is the safe choice for industrial runtime PCs that may not include %SystemRoot% in the search path of the runtime account.
Path Handling for Files With Spaces and Special Characters
Unquoted paths break the moment a directory name contains a space, such as Program Files, My Documents, or Operating Manual. The Windows command-line parser splits on whitespace and the Run method returns without spawning the process. Always wrap the path in double quotes, and inside a VBScript string literal each quote must be doubled:
Dim objWshShell
Set objWshShell = CreateObject("Wscript.Shell")
Dim sFile
sFile = """C:\Program Files\MyHMI\Docs\Operator Manual.pdf"""
objWshShell.Run sFile, 1
Set objWshShell = Nothing
For dynamic paths assembled from an HMI tag, sanitize the string and verify the file exists with FileSystemObject before calling Run. This avoids silent failures when the operator selects a non-existent part number:
Dim objFSO, objWshShell
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objWshShell = CreateObject("Wscript.Shell")
Dim sPath
sPath = "C:\Manuals\" & SmartTags("DocNumber") & ".pdf"
If objFSO.FileExists(sPath) Then
objWshShell.Run Chr(34) & sPath & Chr(34), 1
Else
MsgBox "Documentation file not found:" & vbCrLf & sPath, 48, "Open File"
End If
Set objFSO = Nothing
Set objWshShell = Nothing
Use FSO.GetAbsolutePathName to defeat ..\ traversal in any path that originates from a user-editable tag. Reject any resolved path that does not begin with your whitelisted root.
CHM File Security and the Unblock Requirement
Files downloaded from the internet or extracted from a ZIP archive carry a Zone Identifier alternate data stream (Zone.Identifier) that marks them as untrusted. Windows blocks navigation inside such CHM files through the ITSS / mk:@MSITStore protocol restriction. The error presents as a blank page, a "Navigation to the webpage was canceled" message, or a non-responsive window that opens and immediately closes when launched from a button script. The Unblock step in Microsoft Q&A for CHM file restrictions is the canonical fix:
- Right-click the
.chmfile, choose Properties. - On the General tab, click the Unblock button.
- Click OK. The
Zone.IdentifierNTFS stream is removed.
For unattended or scripted deployment, clear the stream from a command line:
Unblock-File -Path "C:\Help\Operator.chm"
# or with Sysinternals streams.exe
streams.exe -d "C:\Help\Operator.chm"
mk:@MSITStore: links when the help file is located on a UNC path, a removable drive, or any location that contains a ... segment. Copy the file to a local fixed drive, or republish the documentation as PDF/HTML, before deploying to the operator station.PDF File Association Failures
Symptom: the VBScript fires, the Run method returns, no window appears, and the operator sees nothing. In the debug window the script reports no error. This is the classic "no handler registered for .pdf" failure mode, or a per-user handler that the runtime service account cannot see.
Verify and repair the file association on the runtime station:
- Open Settings → Apps → Default apps → Choose default apps by file type.
- Locate
.pdfand confirm a reader (Adobe, Foxit, Edge, SumatraPDF) is set. - From a command prompt, confirm the registry entries:
assoc .pdf
:: .pdf=AcroExch.Document.DC
ftype AcroExch.Document.DC
:: "C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe" "%1"
If the runtime runs as a service account (typical for WinCC ServiceMode and FactoryTalk View SE), the per-user default-app settings made in an interactive session are not inherited. Apply a machine-scope default association so the service user sees the same handler:
DISM /Online /Export-DefaultAppAssociations:C:\Temp\Assoc.xml
:: Edit Assoc.xml and set .pdf to the desired handler
DISM /Online /Import-DefaultAppAssociations:C:\Temp\Assoc.xml
ANSI-C Equivalent for WinCC (TIA Portal / WinCC Professional)
On Siemens WinCC, WinCC Professional, and TIA Portal HMI you can also script the launch from a C action using the WinAPI ShellExecute. The ShellExecute reference specifies that the return value is greater than 32 on success, and any value from 0 to 32 indicates a specific error.
#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
long nResult = (long)ShellExecute(
NULL,
"open",
"C:\\Manuals\\test.pdf",
NULL,
NULL,
SW_SHOWNORMAL);
if (nResult <= 32)
{
// 0 = SE_ERR_OOM
// 2 = ERROR_FILE_NOT_FOUND
// 3 = ERROR_PATH_NOT_FOUND
// 11 = ERROR_BAD_FORMAT
// 27 = SE_ERR_ASSOCINCOMPLETE
// 31 = SE_ERR_NOASSOC
printf("ShellExecute failed, code = %ld\r\n", nResult);
}
}
The SW_SHOWNORMAL constant is defined in winuser.h and corresponds to value 1. The full list of window-state flags is documented at ShowWindow.
Asynchronous Launch Without Blocking the HMI Page
The Run method's second argument controls whether VBScript blocks until the spawned process exits. To open a PDF without freezing the HMI page while the operator has the reader open, wrap the call in a one-shot cmd /c start with the second argument set to 0 (hide the cmd window) and the third argument False (do not wait):
Dim objWshShell
Set objWshShell = CreateObject("Wscript.Shell")
objWshShell.Run "cmd /c start """" """ & "C:\Manuals\Operator.pdf" & """", 0, False
Set objWshShell = Nothing
The two consecutive empty quotes after start are the title argument to cmd start, not an empty pair. Omitting them causes the path itself to be parsed as the title and the file fails to launch.
Error Handling With On Error Resume Next
Wrap the script in On Error Resume Next and explicitly inspect Err.Number so the operator sees a meaningful message instead of a silent no-op:
On Error Resume Next
Dim objWshShell
Set objWshShell = CreateObject("Wscript.Shell")
If Err.Number <> 0 Then
MsgBox "Cannot create Wscript.Shell: " & Err.Description, 16, "Open File"
Exit Sub
End If
objWshShell.Run "C:\Manuals\test.pdf", 1
If Err.Number <> 0 Then
MsgBox "Run failed: " & Err.Description, 16, "Open File"
End If
On Error Goto 0
Set objWshShell = Nothing
Error 429 ("ActiveX component can't create object") is the most common runtime failure and indicates that Wscript.Shell is disabled via group policy or blocked by AppLocker. The relevant policy path is User Configuration → Administrative Templates → Windows Components → Windows Script Host.
FactoryTalk View SE / ME Equivalent
FactoryTalk View SE exposes VBScript on graphic displays through the Command event of a Button object. The same Wscript.Shell object works without modification because the runtime is a normal Windows process. For PanelView Plus (ME) the sandbox restricts CreateObject; use the Launch External Application action of the Button object with the executable set to the registered PDF reader, or place the file in a known path and invoke it through the global Application object.
Troubleshooting Matrix
| Symptom | Likely Cause | Verification | Fix |
|---|---|---|---|
| Nothing happens; no error in debug | No default PDF handler registered | From cmd.exe run start test.pdf
|
Install and assign a PDF reader at machine scope |
| CHM opens but TOC links broken or blank page | Zone.Identifier set; ITSS restrictions | Right-click CHM, look for the Unblock button | Unblock the file; copy to a local fixed drive |
| VBScript error 70 (Permission denied) | Service account lacks read rights on the file | Check effective permissions with icacls
|
Grant read on the file and parent directory |
| VBScript error 429 (ActiveX cannot create object) |
Wscript.Shell disabled by GPO or AppLocker |
Run gpresult /h and check the WSH policies |
Enable WSH or allow the reader executable in AppLocker |
| PDF opens in wrong app (Edge legacy mode, browser) | Per-user association not propagated to service user | Run the same command from the runtime service account | Use DISM /Import-DefaultAppAssociations for machine scope |
| "The system cannot find the file specified" with spaces in path | Missing double quotes around the path | Test the path from cmd.exe with quotes | Wrap path in quotes; double quotes inside the VBScript string |
| Script hangs until viewer closes | Second argument set to 1 and VBScript waits for exit | Expected behavior of Run
|
Use cmd /c start with third arg False
|
CreateObject succeeds, Run returns silently |
Process creation blocked by AV or AppLocker | Inspect Windows Event Log; check AppLocker EXE rules | Allow hh.exe and the reader EXE in AppLocker |
| Works on engineering station, fails on runtime | Different user profile, missing association | Compare assoc and ftype output |
Push the association via DISM or registry export |
Error 80070005 (Access is denied) from ShellExecute
|
UAC split-token service cannot access the user desktop | Run the runtime interactively once | Re-launch the runtime under a logged-on session |
Security and Hardening Notes
External-file launch is a known vector for malicious payload delivery, especially when the file path is operator-editable. Apply these controls before deploying to production:
- Whitelist the directory and file extensions (
.chm,.pdf) in code; reject any other extension. - Resolve the canonical path with
FSO.GetAbsolutePathNameand verify it starts with the whitelisted root before launching. - Strip Zone.Identifier streams from CHMs at deploy time using
Unblock-Filein a signed setup script. - Restrict the runtime account to only the directories that legitimately host manuals (NTFS ACL).
- Prefer PDF over CHM for new content; modern PDF readers are more permissive and easier to sanitize than
hh.exe. - Disable Windows Script Host in the engineering image after the script is in production; the SCADA runtime does not need it for anything other than this action, and removing it shrinks the attack surface.
Verification Checklist
- Click the button on the HMI; the documentation viewer must open within 1 second.
- Close the viewer; the HMI page must remain responsive and not show a "not responding" overlay.
- Click again with the target file missing; the operator must see a clear error message, not a silent no-op.
- Restart the runtime station and re-test; the file association and the Unblock state must survive a reboot.
- Run a long-duration soak test (one hour of repeated clicks) and confirm no orphaned
hh.exeorAcrobat.exeprocesses accumulate in Task Manager. - Re-deploy the CHM/PDF over a file share and confirm the unblock state is preserved by the deploy script.
Edge Cases and Field Notes
Three situations bite during commissioning more often than the basic case:
-
Network paths and CHM: even with the file unblocked,
hh.exerefuses to render a CHM from a UNC path. Symptom is a blank window that closes immediately. Workaround is to mirror the file toC:\Help\on first access. -
32-bit vs 64-bit readers: on 64-bit Windows, a VBScript launched by a 64-bit process spawns 64-bit
hh.exe, which then spawns 32-bitAcroRd32.exe. The reader is not the registered default and you may see a "choose application" dialog. Force the reader to be the default at machine scope with DISM. -
Service-mode runtime with no interactive desktop: WinCC in ServiceMode and FactoryTalk View SE in service mode run under session 0 without an interactive desktop.
Wscript.Shell.Runstill works (the new process is created in the same session), but the operator cannot see the window if the session is not bridged. Verify the runtime configuration creates a window station the operator can view.
Why does my VBScript that opens a PDF do nothing when I click the button?
Most often the system has no registered default handler for the .pdf extension under the account running the runtime. Run assoc .pdf and ftype AcroExch.Document.DC from a command prompt on the runtime station to confirm. On a service-mode runtime, apply the association at machine scope with DISM /Online /Import-DefaultAppAssociations rather than the per-user Settings panel.
How do I fix a CHM file that opens but shows a blank page or broken links?
The file is blocked by the ITSS protocol because it carries a Zone.Identifier alternate data stream. Right-click the .chm file, choose Properties, click Unblock on the General tab, and click OK. For scripted deployment use PowerShell Unblock-File -Path "file.chm" or Sysinternals streams.exe -d file.chm.
Can I open a PDF without freezing the HMI page until the reader closes?
Yes. Use objWshShell.Run "cmd /c start \"\" \"C:\Manuals\file.pdf\"", 0, False. The two empty quotes after start are the title argument; the 0 hides the cmd window and False tells Run not to wait for the spawned process.
What is the ANSI-C equivalent for WinCC button events?
Use ShellExecute(NULL, "open", "C:\path\file.pdf", NULL, NULL, SW_SHOWNORMAL). The function returns a value greater than 32 on success; values from 0 to 32 map to specific error codes documented at ShellExecute, with 31 = SE_ERR_NOASSOC when no PDF handler is registered.
Why does VBScript error 429 (ActiveX cannot create object) appear?
The Wscript.Shell automation object is disabled by group policy, blocked by AppLocker, or the runtime is a hardened image without the Windows Script Host component. Check the policy User Configuration → Administrative Templates → Windows Components → Windows Script Host, or grant an AppLocker exception for the runtime executable.
Why does the same script work on the engineering station but fail on the runtime PC?
Two causes are most common: (1) the runtime runs under a service account whose profile does not inherit per-user default-app settings, so .pdf has no handler; (2) the runtime account has no read permission on the target file. Re-create the PDF association at machine scope with DISM and verify NTFS rights with icacls "C:\Manuals\test.pdf".