WinCC Recipe File Selection: Implementing Browse Folder Dialogs

David Krause17 min read
HMI / SCADASiemensTutorial / How-to
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

WinCC Recipe File Selection: Implementing Browse Folder Dialogs

Overview

Recipe management in Siemens WinCC typically relies on fixed default paths configured at design time. When integrators need to allow operators to select the destination folder for recipe export or the source folder for recipe import (for example, when copying recipes to a USB flash drive on the operator terminal), WinCC's standard recipe functions are not sufficient. The runtime must invoke a native folder-browser or file-selection dialog that returns a user-chosen path to the script host.

This article documents four working approaches to expose a folder or file picker in WinCC V7 and WinCC flexible 2007/2008 SP3 runtimes (Build V1.2.0.0_1.55.0.1) — including the corrected C-Script using comdlg32.dll, VBScript with the MSComDlg.CommonDialog ActiveX control, VBScript with Shell.Application.BrowseForFolder, and the WinCC HMIRuntime.FileSystem object for direct USB file I/O. Each solution ships with copy-paste code, error-handling macros, and a verification sequence.

The C-style source code that circulates in engineering discussions calling comdlg32.dll will not compile when pasted into a WinCC VBScript editor. VBScript does not support #pragma, char, struct, or pointer syntax. The code must be placed in a C-Script action and wrapped in a function, or rewritten in pure VBScript using the Microsoft Common Dialog Control or the Shell object.

Why the Original C Code Fails in VBScript

The published snippet uses constructs that are not part of the VBScript language:

  • #pragma code("comdlg32.dll") — a WinCC C-Script pragma directive, unknown to the VBScript compiler
  • #include "commdlg.h" — a C preprocessor directive
  • char szFilter[], char* psz, char szFile[_MAX_PATH+1] — typed C buffers
  • strcpy() — a C runtime function
  • FindWindow(NULL, "WinCC-Runtime - ") — a Win32 API call returning a handle that VBScript cannot use
  • OPENFILENAME ofn — a C struct, not a VBS class

When the VBScript parser encounters #pragma on line 1, it reports "Unknown command" and aborts the compile. The fix is to use the WinCC C-Editor (not the VBScript-Editor) for the snippet, or rewrite the entire dialog in VBScript using the Microsoft Common Dialog ActiveX or the Shell object.

To determine which editor is currently active, look at the title bar of the script window: it reads "Edit VBS-Action" or "Edit C-Action". Switching is done via the dropdown next to the save button in WinCC V7.0/V7.1, or via the action's context menu in WinCC V7.3 and later.

WinCC Scripting Environment Requirements

WinCC V7 separates scripts into two editors with different language bindings:

Editor Language Host Typical Use
VBScript Editor VBScript (vbs) WScript / WinCC VBS host Tag I/O, file I/O, math, dispatch to COM
C-Editor ANSI C with WinCC API WinCC C compiler (internal BCC) Win32 API calls, #pragma includes, performance-critical loops

Each action in a WinCC picture is bound to one language at creation time. The action's "Programming language" property in the WinCC Explorer attribute panel reflects the binding. Switching language after the action contains code strips out incompatible directives — for example, switching from C to VBS drops every #pragma line without warning.

The Siemens Knowledge Base entry 37572697 ("How do you implement a file browser in WinCC?") is the canonical reference for this topic and ships the corrected C source used in Solution 1 below. Always cross-check the example code against the local WinCC version's C compiler — pragmas in pre-V7.0 releases require a slightly different syntax for commdlg.h inclusion.

Solution 1: Corrected C-Script with comdlg32.dll

Create a new action in the WinCC C-Editor, paste the source, and wrap the body in a function so the C compiler emits a callable symbol. The action is bound to a button's Mouse-Click event:

// WinCC C-Action: Open file dialog for recipe import
// Bind to button "Click" event
#include "apdefap.h"
#pragma code("comdlg32.dll")
#include "commdlg.h"
#pragma code()

BOOL OnOpenRecipeFile(LPCSTR lpszDefaultName)
{
    OPENFILENAME ofn;
    char szFilter[] = "CSV Files (*.csv)|*.csv|TXT Files (*.txt)|*.txt|All Files (*.*)|*.*|";
    char* psz;
    char szFile[_MAX_PATH+1];
    char szFileTitle[_MAX_PATH+1];
    char szInitialDir[_MAX_PATH+1];
    HWND hwndOwner;
    BOOL bResult;

    for (psz = szFilter; *psz; psz++) {
        if (*psz == '|') {
            *psz = 0;
        }
    }

    strcpy(szInitialDir, "C:\\Recipes");
    strcpy(szFile, lpszDefaultName);
    strcpy(szFileTitle, lpszDefaultName);

    hwndOwner = FindWindow(NULL, "WinCC-Runtime - ");

    memset(&ofn, 0, sizeof(OPENFILENAME));
    ofn.lStructSize     = sizeof(OPENFILENAME);
    ofn.hwndOwner       = hwndOwner;
    ofn.lpstrFilter     = szFilter;
    ofn.lpstrFile       = szFile;
    ofn.nMaxFile        = _MAX_PATH + 1;
    ofn.lpstrFileTitle  = szFileTitle;
    ofn.nMaxFileTitle   = _MAX_PATH + 1;
    ofn.lpstrInitialDir = szInitialDir;
    ofn.Flags           = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
    ofn.lpstrDefExt     = "csv";

    bResult = GetOpenFileName(&ofn);
    if (bResult) {
        printf("Selected file: %s\r\n", ofn.lpstrFile);
        SetTagChar("RecipeSelectedPath", ofn.lpstrFile);
        return TRUE;
    } else {
        DWORD err = CommDlgExtendedError();
        printf("GetOpenFileName failed, code 0x%04X\r\n", err);
        return FALSE;
    }
}

Four corrections versus the unmodified snippet circulated in engineer forums:

  1. The body is wrapped in OnOpenRecipeFile(); WinCC C actions must define a function whose symbol matches the action name, otherwise the C compiler discards the body as unreferenced.
  2. strcpy(szFile, lpszDefaultName) initializes the file-name buffer before GetOpenFileName writes into it. The original code passed an uninitialized buffer; OPENFILENAME requires the first byte of lpstrFile to be a valid NUL-terminated string when OFN_FILEMUSTEXIST is not set.
  3. memset(&ofn, 0, sizeof(OPENFILENAME)) zeroes reserved fields. OPENFILENAME has grown between Windows releases (Vista, Win7, Win10 added new fields); the OS reads these bytes and returns 0x0002 (CDERR_DIALOG) from CommDlgExtendedError if they contain garbage.
  4. OFN_HIDEREADONLY is added to hide the legacy "Open as read-only" checkbox that confuses operators on Vista+ dialogs.

For Save As (recipe export), replace GetOpenFileName with GetSaveFileName and add OFN_OVERWRITEPROMPT (already present). To start the dialog on a USB drive, set szInitialDir to "E:\\Recipes\\" or read the drive letter from a WinCC tag set by an operator scan action.

Common CommDlgExtendedError Codes

Hex Constant Meaning Resolution
0x0001 CDERR_DIALOGFAIL Dialog box could not be created Check hwndOwner validity; reduce stack usage in caller
0x0002 CDERR_STRUCTSIZE lStructSize wrong or struct not zeroed Set sizeof(OPENFILENAME) and memset the struct
0x0003 CDERR_INITIALIZATION COM init failed Reboot runtime; check DCOM service status
0x0004 CDERR_NOTEMPLATE Template resource missing Remove OFT_TEMPLATENAME flag
0x0006 CDERR_LOADRESFAILURE Template resource load failed Verify resource path
0x000A CDERR_MEMALLOCFAILURE Heap allocation failed Close other dialogs; check available memory
0x000B CDERR_LOCKRESFAILURE Cannot lock resource Reboot; check file system
0x1001 FNERR_BUFFERLENGTH Buffer too small for filename Set nMaxFile = MAX_PATH; pre-initialize szFile
0x1006 FNERR_INVALIDFILENAME File name pattern invalid Strip *, ?, | from pattern

Solution 2: VBScript with MSComDlg.CommonDialog ActiveX Control

If the project must remain in VBScript (for example, to call other VBS functions from the same project), drop the Microsoft Common Dialog Control on the WinCC picture and use it from VBScript. The control's ProgID is MSComDlg.CommonDialog and is shipped with comdlg32.ocx (part of the Visual Basic 6 runtime).

Add the control to the picture:

  1. Open the Graphics Designer and place an ActiveX Control on the picture from the Smart Objects palette.
  2. In the wizard, pick Microsoft Common Dialog Control, Version 6.0. If it does not appear, install the VB6 runtime (shipped with many Siemens engineering tools) and re-register: regsvr32 comdlg32.ocx from an elevated command prompt.
  3. Rename the control to ComDlg1 in the object properties.

VBScript action bound to a button Click event:

' WinCC VBScript action
Sub OnClick(ByVal Item)
    Dim sFilter, sPath, iCancelErr
    iCancelErr = 32755   ' CDERR_CANCEL raised by CancelError=True
    
    ComDlg1.CancelError = True
    sFilter = "CSV Files (*.csv)|*.csv|TXT Files (*.txt)|*.txt|All Files (*.*)|*.*|"
    sFilter = Replace(sFilter, "|", vbNullChar)
    sFilter = sFilter & vbNullChar & vbNullChar
    
    On Error Resume Next
    ComDlg1.Flags = &H4&   ' OFN_PATHMUSTEXIST
    ComDlg1.Filter = sFilter
    ComDlg1.InitDir = "C:\Recipes"
    ComDlg1.FileName = "recipe_001.csv"
    ComDlg1.DialogTitle = "Select recipe file"
    ComDlg1.ShowOpen
    
    If Err.Number = 0 Then
        sPath = ComDlg1.FileName
        HMIRuntime.Tags("RecipeSelectedPath").Write sPath
        HMIRuntime.Trace "Selected file: " & sPath & vbNewLine
    ElseIf Err.Number = iCancelErr Then
        HMIRuntime.Trace "User cancelled the dialog" & vbNewLine
    Else
        HMIRuntime.Trace "ComDlg error: " & Err.Number & " " & Err.Description & vbNewLine
    End If
    On Error Goto 0
End Sub

The Replace call converts Win32 double-NUL filter pairs (e.g. "CSV|*.csv|") into single-NUL delimiters with a trailing double NUL, which the COM property expects. The flag value &H4& is OFN_PATHMUSTEXIST (see the OPENFILENAME flag table in the Windows SDK headers commdlg.h). The error code 32755 (0x800B) is the documented CDERR_CANCEL "user pressed Cancel" trap raised when CancelError = True.

For ShowSave (recipe export), swap the last ShowOpen line for ComDlg1.ShowSave and add ComDlg1.Flags = &H4& Or &H2& (path must exist + overwrite prompt).

The ActiveX control requires the operator terminal to ship with the VB6 runtime libraries. Modern Windows 10/11 IoT images may not include comdlg32.ocx. Test on the actual runtime image before deployment, and bundle comdlg32.ocx in the project deployment directory so the installer can re-register it on first run.

Solution 3: VBScript with Shell.Application for Folder Browsing

For pure folder selection (browse a directory tree, no file), the Windows Shell object provides a native folder-picker via Shell.BrowseForFolder. This is a single-call API that requires no ActiveX registration and works on every Windows version from XP onward, including Windows 10 IoT LTSC images shipped with WinCC V7.4/V7.5 runtime PCs.

' WinCC VBScript action - folder picker for recipe destination
Sub OnClick(ByVal Item)
    Dim oShell, oFolder, sPath
    Const BIF_RETURNONLYFSDIRS   = &H1
    Const BIF_EDITBOX            = &H10
    Const BIF_NEWDIALOGSTYLE     = &H40
    Const BIF_USENEWUI           = &H50   ' BIF_EDITBOX Or BIF_NEWDIALOGSTYLE
    
    Set oShell = CreateObject("Shell.Application")
    Set oFolder = oShell.BrowseForFolder(0, _
        "Select destination folder for recipe export", _
        BIF_RETURNONLYFSDIRS Or BIF_USENEWUI, _
        "C:\Program Files\Siemens\Automation")
    
    If Not oFolder Is Nothing Then
        sPath = oFolder.Self.Path
        HMIRuntime.Tags("RecipeExportFolder").Write sPath
        HMIRuntime.Trace "Folder selected: " & sPath & vbNewLine
    Else
        HMIRuntime.Trace "Folder selection cancelled" & vbNewLine
    End If
    Set oFolder = Nothing
    Set oShell = Nothing
End Sub

Flag decoding (from the Windows SDK header shlobj.h):

Constant Value Effect
BIF_RETURNONLYFSDIRS 0x0001 Return only file system directories; hide Control Panel, Recycle Bin, My Computer
BIF_DONTGOBELOWDOMAIN 0x0002 Disable network traversal beyond the local domain
BIF_STATUSTEXT 0x0004 Show status text area at the bottom of the dialog
BIF_BROWSEFORCOMPUTER 0x1000 Return computer names only (network neighborhood style)
BIF_BROWSEFORPRINTER 0x2000 Return printer names only
BIF_EDITBOX 0x0010 Add an editable path text box at the top of the dialog
BIF_NEWDIALOGSTYLE 0x0040 Use the resizable Vista+ dialog with breadcrumb bar and address bar
BIF_USENEWUI 0x0050 Convenience alias: EDITBOX Or NEWDIALOGSTYLE

For USB-aware folder selection, scan the file system for removable drives before invoking the dialog and pass the detected root as the start folder:

Function GetRemovableDriveRoot()
    Dim oFSO, oDrive, sResult
    Set oFSO = CreateObject("Scripting.FileSystemObject")
    sResult = ""
    For Each oDrive In oFSO.Drives
        If oDrive.DriveType = 1 Then   ' 1 = Removable
            sResult = oDrive.Path & "\"
            Exit For
        End If
    Next
    GetRemovableDriveRoot = sResult
    Set oFSO = Nothing
End Function

Sub OnClick(ByVal Item)
    Dim oShell, oFolder, sPath, sStartDir
    sStartDir = GetRemovableDriveRoot()
    If Len(sStartDir) = 0 Then sStartDir = "C:\Recipes"
    
    Set oShell = CreateObject("Shell.Application")
    Set oFolder = oShell.BrowseForFolder(0, _
        "Select destination folder for recipe export", _
        &H1 Or &H50, _
        sStartDir)
    
    If Not oFolder Is Nothing Then
        sPath = oFolder.Self.Path
        HMIRuntime.Tags("RecipeExportFolder").Write sPath
    End If
    Set oFolder = Nothing
    Set oShell = Nothing
End Sub

The DriveType values per the Scripting.FileSystemObject documentation: 0 = Unknown, 1 = Removable, 2 = Fixed, 3 = Network, 4 = CD-ROM, 5 = RAM Disk.

Solution 4: Using WinCC HMIRuntime.FileSystem for Direct USB Access

WinCC V7 exposes a high-level file system object that abstracts the Microsoft Scripting Runtime FileSystemObject. From runtime scripts the helper is HMIRuntime.FileSystem and it is the recommended way to copy recipe CSV files to and from a USB stick without invoking an external dialog:

Function ExportRecipeToUSB(sSourceFile, sUSBTargetFolder)
    Dim oFS, sDestPath
    Set oFS = CreateObject("Scripting.FileSystemObject")
    If Not oFS.FolderExists(sUSBTargetFolder) Then
        oFS.CreateFolder sUSBTargetFolder
    End If
    sDestPath = oFS.BuildPath(sUSBTargetFolder, oFS.GetFileName(sSourceFile))
    oFS.CopyFile sSourceFile, sDestPath, True
    HMIRuntime.Trace "Recipe exported to " & sDestPath & vbNewLine
    Set oFS = Nothing
    ExportRecipeToUSB = sDestPath
End Function

Function ImportRecipeFromUSB(sUSBFilePath, sDestFolder)
    Dim oFS, sDestPath
    Set oFS = CreateObject("Scripting.FileSystemObject")
    If Not oFS.FileExists(sUSBFilePath) Then
        Err.Raise vbObjectError + 1001, , "Source file not found: " & sUSBFilePath
        Exit Function
    End If
    sDestPath = oFS.BuildPath(sDestFolder, oFS.GetFileName(sUSBFilePath))
    oFS.CopyFile sUSBFilePath, sDestPath, True
    Set oFS = Nothing
    ImportRecipeFromUSB = sDestPath
End Function

To detect the USB letter dynamically, enumerate HMIRuntime.FileSystem.Drives (WinCC V7.4+) or use the classic FileSystemObject.Drives enumeration as in GetRemovableDriveRoot above. The detection loop must run on a 1-second scheduler with a short delay (WinCC USB enumeration on Windows 7/10 can take 1-3 seconds after the user inserts the stick). Verify drive readiness with oFS.Drive.IsReady before opening any file — a not-yet-ready drive returns a generic error 0x800A0046 (permission denied) instead of a clean "device not ready" code.

Recipe Management Workflow Implementation

A typical recipe import/export flow on a WinCC Runtime PC is:

  1. Operator inserts USB stick; a WinCC scheduler action polls FSO.Drives every 1 s and writes the first removable drive letter to the internal tag USB_DriveLetter.
  2. Operator presses the Export Recipe button. The C-Action from Solution 1 calls GetSaveFileName with szInitialDir initialized to USB_DriveLetter + ":\\Recipes\\".
  3. Operator chooses a target file name. The action writes the path to tag RecipeSelectedPath and calls ExportRecipeToUSB() from Solution 4.
  4. For import, the operator presses Import Recipe. The VBScript action from Solution 2 or 3 retrieves a path and calls ImportRecipeFromUSB().
  5. WinCC reads the imported CSV into internal recipe tags, using either the built-in recipe view (WinCC flexible / Comfort Panels / TIA Portal) or a custom OpenTextFile parse in WinCC V7 PC runtime.
Recipe USB Transfer Workflow - WinCC Runtime Operator inserts USB stick 1s scheduler scans FSO.Drives DriveType = 1 tag USB_DriveLetter = E: Click Export button GetSaveFileName initialdir = E:\Recipes User types filename recipe_001.csv CopyFile to USB FSO.CopyFile HMIRuntime.Trace "Export OK" Click Import button BrowseForFolder or ShowOpen Parse CSV OpenTextFile ForReading Tags updated ApplyRecipeToTags

Sample CSV parse in VBScript for a 3-parameter recipe (parameter, value, unit):

Function ParseRecipeCSV(sFilePath)
    Dim oFSO, oFile, sLine, aFields, dResult
    Set dResult = CreateObject("Scripting.Dictionary")
    Set oFSO = CreateObject("Scripting.FileSystemObject")
    Set oFile = oFSO.OpenTextFile(sFilePath, 1, False, -1)
    ' Arguments: 1=ForReading, False=create=False, -1=Unicode (auto-detect BOM)
    
    Do While Not oFile.AtEndOfStream
        sLine = Trim(oFile.ReadLine)
        If Left(sLine, 1) <> "'" And Len(sLine) > 0 Then
            aFields = Split(sLine, ",")
            If UBound(aFields) >= 1 Then
                If Not dResult.Exists(aFields(0)) Then
                    dResult.Add aFields(0), aFields(1)
                End If
            End If
        End If
    Loop
    oFile.Close
    Set oFile = Nothing
    Set oFSO = Nothing
    Set ParseRecipeCSV = dResult
End Function

Sub ApplyRecipeToTags(dRecipe)
    If dRecipe.Exists("Temperature") Then _
        HMIRuntime.Tags("Recipe.Temperature").Write CDbl(dRecipe("Temperature"))
    If dRecipe.Exists("Pressure") Then _
        HMIRuntime.Tags("Recipe.Pressure").Write CDbl(dRecipe("Pressure"))
    If dRecipe.Exists("CycleTime") Then _
        HMIRuntime.Tags("Recipe.CycleTime").Write CDbl(dRecipe("CycleTime"))
End Sub

For a project that uses the WinCC Comfort Panel Recipe view (TIA Portal, firmware V14+), the recipe CSV is named RecipeData.csv with a fixed column header order. Do not overwrite this file with custom export logic — read it instead, or write to a separate user-recipe file. See the TIA Portal Help → Visualizing processes → Recipes → Structure of the recipe data file for the exact column ordering.

Error Handling and Diagnostics

Common failure modes when implementing these dialogs in WinCC:

Symptom Root Cause Fix
"Unknown command" at first line of C code Pasted in VBScript editor Move to C-Editor; verify editor toolbar shows "C"
Dialog opens behind WinCC window Wrong hwndOwner from FindWindow Use NULL or GetForegroundWindow(); ensure WinCC Runtime window title matches FindWindow argument
CommDlgExtendedError 0x0002 (FNERR_STRUCTSIZE) OPENFILENAME struct not zeroed Add memset(&ofn, 0, sizeof(OPENFILENAME)) before populating fields
CommDlgExtendedError 0x1001 (FNERR_BUFFERLENGTH) szFile buffer too small or uninitialized Set nMaxFile = MAX_PATH, memzero buffer, pre-fill lpstrFile
BrowseForFolder returns Nothing on Cancel Correct Windows behavior Test Is Nothing; do not raise an error
USB drive not visible WinCC runtime running as service or UAC-restricted Run WinCC Runtime as interactive user; disable UAC remote restrictions on the operator terminal
0x80070005 (E_ACCESSDENIED) on file copy User lacks write permission on USB Check oFSO.Drive.IsReady and oFSO.Drive.AvailableSpace before copy
0x800A0046 on file open USB stick not enumerated yet Wait 1-3 s after insertion; recheck IsReady in a loop
ActiveX MSComDlg control not listed in wizard VB6 runtime not installed Install VB6 runtime; regsvr32 comdlg32.ocx from elevated cmd
Recipe values applied as 0 String contains non-numeric or locale-specific decimal Use CDbl(Replace(sVal, ",", ".")) for non-US locales; handle decimal separator via CCur
BrowseForFolder returns \My Computer\ path User selected a special folder, not a file system path Always use BIF_RETURNONLYFSDIRS and validate path starts with a drive letter

Enable WinCC diagnostic output during commissioning by adding a C printf() or VBS HMIRuntime.Trace calls; results appear in the WinCC Diagnosis Viewer (ApDiag.exe) or in WinCC_<computername>.LOG in the project log folder. The default trace level is "Error" — change to "All" via the computer's WinCC Explorer → Computer → Properties → Startup for first-time debug.

Security and Path Validation

Allowing the operator to pick any path is a security vector. Apply these constraints in production deployments:

  • Whitelist allowed root directories: "E:\\Recipes\\", "C:\\ProgramData\\Siemens\\Automation\\Recipes\\". Reject paths that do not start with the whitelist using InStr(1, sPath, "E:\Recipes", vbTextCompare) = 1 (returns 1 only if path begins with the prefix).
  • Sanitize file names to reject .., \, :, *, ?, ", <, >, | in the recipe name field before concatenation.
  • Cap file size on import: oFSO.GetFile(sFile).Size > 1048576 (1 MB) → reject. Recipe files are typically under 100 KB; 1 MB is a generous ceiling that still protects against zip-bomb-style attacks.
  • Run WinCC Runtime under a dedicated operator user (not Administrator) so that file writes to USB are restricted by NTFS ACL to specific device instances. On Windows 10 IoT LTSC, USB device ACLs are configured in Device Manager → Removable Disk → Properties → Security.
  • Use signed recipes: include a CRC-32 or HMAC-SHA1 of the file in the first CSV row, verify before applying tag values. The HMAC key should be stored in the WinCC project as a hashed constant, not in the CSV.
  • Disable Shell.Application for untrusted users: set the WinCC Runtime user's group policy User Configuration → Administrative Templates → Windows Components → File Explorer → Prevent access to drives from My Computer to whitelist the USB letter only.

Verification and Testing

Validate the implementation with this sequence on a test PC matching the production image:

  1. Insert a USB stick; confirm the tag USB_DriveLetter updates within 5 seconds via the online tag view in WinCC Explorer.
  2. Click Export Recipe; confirm GetSaveFileName opens at the USB root directory, not at the WinCC install path.
  3. Save test_recipe.csv with 3 rows of comma-separated values; pull the stick, open the file in Excel or Notepad, confirm 3 data lines plus 1 header line.
  4. Re-insert the stick; click Import Recipe; select test_recipe.csv; confirm tags Recipe.Temperature, Recipe.Pressure, Recipe.CycleTime reflect CSV values via online tag view in WinCC Explorer.
  5. Click Cancel in the dialog; confirm the script logs "cancelled" via HMIRuntime.Trace without raising a VBS runtime error or showing an error popup.
  6. Test with multiple removable drives attached (USB hub); confirm the script picks the first detected one and continues if the user selects a different drive letter in the dialog.
  7. Test the file type filter: confirm only *.csv files are listed when the filter is set; switch the filter to *.txt and confirm *.csv files disappear.
  8. Test with a non-FAT32 USB stick (exFAT or NTFS) to confirm the file copy handles long paths (> 256 chars) and Unicode file names.
  9. Test with a write-protected USB stick; confirm the script raises a clean error ("USB is write-protected") rather than crashing.
  10. Test with the USB stick removed mid-operation; confirm the copy fails gracefully and the operator sees a message, not a frozen screen.

On Siemens Comfort Panels (TIA Portal, firmware V14+), the same logic applies but the MSComDlg ActiveX is not available — use the C-Script editor (Panel C-Script) with #pragma code("comdlg32.dll") exactly as in Solution 1. Panel C-Script has the same Windows API surface as WinCC V7 PC C-Script for the dialog APIs. For SIMATIC WinCC Unified (V16/V17/V18) the recommended pattern is to instantiate System.Windows.Forms.FolderBrowserDialog from a .NET script in a custom control; the unmanaged Win32 dialogs from Solutions 1-3 are not required and not supported on Unified runtime.

FAQ

Why does the comdlg32.dll C code fail with "Unknown command" in WinCC?

The script was pasted into the WinCC VBScript editor. WinCC ships two separate editors: VBScript and C. The C-Editor supports #pragma code("comdlg32.dll") and the OPENFILENAME struct; the VBScript editor does not. Switch the action's programming language to C via the editor toolbar or right-click → Convert to C in WinCC V7.3 and later.

How do I open a folder-picker dialog in VBScript without MSComDlg?

Use Shell.Application via CreateObject("Shell.Application") and call BrowseForFolder with the BIF_RETURNONLYFSDIRS and BIF_USENEWUI flags (combined value 0x51). The selected folder's path is returned through oFolder.Self.Path. No ActiveX registration is required and the dialog works on every Windows version from XP onward.

How do I detect the USB drive letter from WinCC runtime?

Enumerate drives with the Windows Scripting Runtime FileSystemObject: For Each oDrive In CreateObject("Scripting.FileSystemObject").Drives: If oDrive.DriveType = 1 Then sLetter = oDrive.Path. DriveType 1 = Removable. Run the detection on a 1 s scheduler because USB enumeration on Windows can take 1-3 s after insertion; always check oDrive.IsReady before opening files.

Which file dialog is the safest for production?

The VBScript Shell.Application.BrowseForFolder with BIF_RETURNONLYFSDIRS plus a path-prefix whitelist check (e.g. InStr(1, sPath, "E:\Recipes", vbTextCompare) = 1) is the safest. It avoids ActiveX dependencies, returns only file system paths, and gives the integrator a single point of validation before any file I/O is performed.

Can I use FolderBrowserDialog (.NET) in WinCC V7 VBScript?

No. System.Windows.Forms.FolderBrowserDialog is a .NET class and cannot be instantiated from VBScript via CreateObject. For WinCC Unified (V16+) you can call it from a .NET-scripted custom control on a Unified PC runtime, but for WinCC V7 the supported unmanaged options are Shell.BrowseForFolder and the C-Script comdlg32 dialogs documented in Solutions 1-3.

Back to blog