1. Problem Scope and Architecture Overview
WinCC Runtime hosts two fundamentally different kinds of visual surfaces. The first is an internal Picture (PDL) rendered inside the WinCC Graphics Runtime. The second is an external Win32 process (for example, notepad.exe) launched from a script via ProgramExecute or WScript.Shell.Run. The two surfaces do not share a parent-child window relationship, so the standard "picture closes -> children close" rule does not apply when one of the surfaces is an external executable.
The engineering problem becomes: how do you guarantee that notepad.exe (or any external program started from a button on a PDL) is terminated whenever the user closes the picture that originally launched it? This article documents the working C-Script and VBScript solutions for both WinCC V7.x (SIMATIC WinCC) and TIA Portal WinCC Professional / Comfort, including the correct event hooks, the Win32 API sequence (FindWindow -> PostMessage WM_CLOSE), and the taskkill fallback.
2. Internal PictureWindow vs External Process
| Attribute | Internal PictureWindow | External Process (e.g. notepad.exe) |
|---|---|---|
| Host | WinCC Graphics Runtime (single process) | Independent Win32 process |
| Window Handle | Owned by WinCC Runtime | Independent top-level window |
| Closes with parent picture? | Yes - automatic via PictureWindow object | No - requires script or taskkill |
| Lifecycle event available? | OnOpen / OnClose of PictureWindow | None within WinCC; must poll or hook |
| Lifecycle trigger inside WinCC | Picture change, picture close | User closes WinCC Runtime or changes picture |
The PictureWindow object in WinCC Graphics Designer is a container. When you load a different PDL into the parent picture, the child PictureWindow is destroyed automatically. An notepad.exe window is not embedded in that container - it is a sibling top-level window of the WinCC Runtime itself, so it survives the picture change unless you explicitly close it.
3. WinCC Picture Event Reference
WinCC V7.x Graphics Designer exposes the following events on a picture object (right-click the picture background, choose Properties -> Events):
| Event | Fires When | Typical C Function Name |
|---|---|---|
| Open | Picture is loaded / shown | OpenPicture(...) |
| Close | Picture is closed / replaced | ClosePicture(...) |
| Mouse events | Mouse interaction in picture |
OnClick(...) etc. |
| Keyboard events | Key press while picture has focus |
OnKeyDown(...) etc. |
Close event in the normal lifecycle because the Runtime process ends instead. The standard Siemens guidance - see the FAQ at support.industry.siemens.com/cs/ww/en/view/415808 - is therefore to either hook the global Runtime shutdown, the Windows session logoff event, or to attach the cleanup logic to a PictureWindow that does close.In TIA Portal WinCC Professional the same events are exposed in the picture properties dialog of the HMI device. The VBScript function name generated is OnClose (or OnOpen).
4. Launching External Applications
There are three reliable launch paths. Pick the one matching your platform.
4.1 WinCC V7.x - C-Script with ProgramExecute
#include "apdefap.h"
void OnClick(char* lpszPictureName,
char* lpszObjectName,
char* lpszPropertyName,
UINT nFlags,
int x,
int y)
{
ProgramExecute("notepad.exe C:\\Logs\\Runtime.log");
}
ProgramExecute is declared in apdefap.h and synchronously launches the external process. If you need the script to continue while the external program runs, use WinExec("notepad.exe", SW_SHOWNORMAL) from the Win32 API instead.
4.2 TIA WinCC Professional - VBScript with WScript.Shell
Sub OnClick(ByVal Item)
Dim oShell
Set oShell = CreateObject("WScript.Shell")
oShell.Run "notepad.exe C:\Logs\Runtime.log", 1, False
Set oShell = Nothing
End Sub
The third argument (False) means "do not wait for completion". This is mandatory for a button click handler - otherwise the HMI freezes until Notepad is closed by the user.
4.3 WinCC Unified (TIA V16+) - JavaScript
export function Button_1_OnClick(item) {
const { exec } = imports("@runtime/Application");
// Project property "ExtProgram" = "notepad.exe"
const program = Tags("ExtProgram").Read();
exec(program);
}
WinCC Unified uses the JavaScript-based action API. The exec method is documented in the TIA Portal WinCC Unified online help.
5. Capturing the Window Handle with FindWindow
To close a specific external window without killing the entire process, you must obtain its HWND. The Win32 API function FindWindow matches either by window class name or by window title. For Notepad the class name is Notepad (Windows 10/11) or NotepadClass (older). The title is dynamic.
5.1 C-Script (WinCC V7) - Win32 API Access
WinCC C-Scripts can call Win32 API functions directly. Declare once in a project header:
// In a project header file included by every C action
typedef unsigned long DWORD;
typedef unsigned int UINT;
typedef int BOOL;
typedef char* LPSTR;
typedef void* HWND;
typedef long LRESULT;
#define WM_CLOSE 0x0010
HWND __stdcall FindWindowA(LPSTR lpClassName, LPSTR lpWindowName);
LRESULT __stdcall PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
5.2 VBScript (TIA WinCC Professional) - Win32 API via external helper
VBScript cannot call FindWindow directly. Two practical options:
- Use the
AppActivatemethod onWScript.Shellto focus the window, then sendAlt+F4withSendKeys. - Use a small VB6 / .NET helper COM object that exposes
FindWindowandPostMessageas methods.
Sub CloseNotepadWindow()
Dim oShell
Set oShell = CreateObject("WScript.Shell")
' Returns True if window found
If oShell.AppActivate("Runtime.log - Notepad") Then
oShell.SendKeys "%{F4}" ' Alt+F4 = WM_CLOSE on focused window
End If
Set oShell = Nothing
End Sub
AppActivate + SendKeys depends on keyboard focus and is fragile in headless / panel deployments. Prefer taskkill /IM or a custom COM helper on production systems.6. Closing the External Window: WM_CLOSE vs DestroyWindow vs TerminateProcess
| Method | Behavior | Cleanup | Recommended? |
|---|---|---|---|
PostMessage(hWnd, WM_CLOSE, 0, 0) |
Sends WM_CLOSE; well-behaved apps save & exit | Graceful | Yes |
DestroyWindow(hWnd) |
Immediately destroys the window | Ungraceful - process may survive without a main window | No |
TerminateProcess(hProcess, 0) |
Hard-kills the process | Ungraceful - no chance to save | Only as fallback |
taskkill /IM notepad.exe /F |
Hard-kills the process | Ungraceful | Production fallback |
The correct sequence is:
- Save the HWND returned by
FindWindowinto a project-wide tag (WinCC tag of type Text tag 8-bit character set for hex storage, or a custom internal variable). - In the Close handler, retrieve the saved HWND and call
PostMessage(hWnd, WM_CLOSE, 0, 0). - If the process is still alive after a 500 ms delay, fall back to
taskkill /IM notepad.exe /F.
7. Why There Is No "PictureClose" Event on the Base Picture
WinCC Runtime architecture reserves Open / Close events for picture change operations. The base picture loaded at Runtime start has no preceding picture, and Runtime termination destroys the entire process rather than closing a picture object. The Siemens support response that there is "no PictureClose event" refers to this base-picture case, and the standard mitigation patterns are:
-
Embed the launch in a PictureWindow: the PictureWindow itself fires
OnClosewhen the parent picture changes, so the cleanup script hooks there. -
Use a project-wide shutdown hook: in WinCC V7 the Computer Properties -> Shutdown event can run a global cleanup script. TIA WinCC Professional provides Schedules and the Runtime's own
OnShutdownevent. -
Use Windows session events: subscribe to
WM_QUERYENDSESSION/WM_ENDSESSIONfrom a global C action to receive Windows logoff / shutdown notifications.
8. Complete C-Script Example for WinCC V7.x
This example uses a PictureWindow to launch Notepad on a button click and close it on PictureWindow close.
8.1 Button click action - launch and store HWND
#include "apdefap.h"
// Persisted across actions via a project tag "@NotepadHwnd"
extern "C" long FindWindowA(const char*, const char*);
void OnClick(char* lpszPictureName,
char* lpszObjectName,
char* lpszPropertyName,
UINT nFlags,
int x,
int y)
{
ProgramExecute("notepad.exe");
// Allow notepad to create its window
DWORD tick = GetTickCount();
long hwnd = 0;
while ((GetTickCount() - tick) < 3000) // up to 3 s
{
hwnd = FindWindowA("Notepad", NULL);
if (hwnd != 0) break;
Sleep(100);
}
// Persist HWND as decimal text in a WinCC tag
char buf[16];
sprintf(buf, "%ld", hwnd);
SetTagChar("@NotepadHwnd", buf);
}
8.2 PictureWindow close action - send WM_CLOSE
#include "apdefap.h"
extern "C" long PostMessageA(long hWnd, unsigned int Msg, long wParam, long lParam);
extern "C" DWORD GetTickCount(void);
extern "C" void Sleep(DWORD ms);
void OnClose(char* lpszPictureName,
char* lpszObjectName,
char* lpszPropertyName,
BOOL bClosing)
{
char buf[16];
GetTagChar(buf, "@NotepadHwnd");
long hwnd = atol(buf);
if (hwnd != 0)
{
PostMessageA(hwnd, 0x0010 /* WM_CLOSE */, 0, 0); // graceful
// Optional: hard-kill fallback after 500 ms
DWORD tick = GetTickCount();
while ((GetTickCount() - tick) < 500) { Sleep(50); }
// system("taskkill /IM notepad.exe /F >NUL");
}
SetTagChar("@NotepadHwnd", "");
}
user32.lib via the WinCC Graphics Designer project settings if Win32 APIs are not pre-resolved by apdefap.h.9. Complete VBScript Example for TIA Portal WinCC Professional
TIA WinCC does not support C-Script. Use VBScript only. Hook the cleanup to the PictureWindow close event.
9.1 PictureWindow close event - hard kill via taskkill
Sub OnClose(ByVal Item)
Dim oShell
Set oShell = CreateObject("WScript.Shell")
' Wait briefly so any in-flight save dialog can be dismissed
Dim wshExec
Set wshExec = oShell.Run("taskkill /IM notepad.exe /F", 0, True)
' oShell.Run with bWaitOnReturn=True returns exit code
' 0 = success, 128 = no process found
Set wshExec = Nothing
Set oShell = Nothing
End Sub
9.2 Graceful alternative - AppActivate + SendKeys
Sub OnClose(ByVal Item)
Dim oShell
Set oShell = CreateObject("WScript.Shell")
If oShell.AppActivate("Notepad") Then
oShell.SendKeys "%{F4}" ' Alt+F4 -> WM_CLOSE
End If
Set oShell = Nothing
End Sub
9.3 Polling fallback when no event is reliable
Sub CyclicCleanup()
Dim oShell, intFound
Set oShell = CreateObject("WScript.Shell")
intFound = oShell.Run("tasklist /FI ""IMAGENAME eq notepad.exe"" /NH", _
0, True)
If intFound = 0 Then
oShell.Run "taskkill /IM notepad.exe /F", 0, True
End If
Set oShell = Nothing
End Sub
Schedule this VBScript via a 2-second cyclic trigger while the parent picture is visible.
10. Process Termination Fallback Using taskkill
The taskkill utility ships with every Windows installation since Windows XP and is the safest hard-kill mechanism for WinCC panels running Windows Embedded Standard 7 / Windows 10 IoT.
| Switch | Purpose |
|---|---|
/IM <name> |
Match by image name |
/PID <pid> |
Match by process ID |
/F |
Force termination |
/T |
Terminate child processes too |
/F /FI "WINDOWTITLE eq Untitled*" |
Match by window title |
taskkill /IM notepad.exe /F /T
taskkill /F /FI "WINDOWTITLE eq Runtime.log*"
Always verify the exit code (0 = success, 128 = no match, 1 = error) via oShell.Run(..., 0, True) in VBScript.
11. Commissioning and Verification Procedure
- Compile the script: in WinCC V7 Graphics Designer press Compile -> C-Editor. Look for unresolved Win32 references in the build log.
- Set Runtime properties: in Computer Properties -> Graphics Runtime ensure Runtime start picture is set to the picture containing your test button.
-
Enable diagnostic output: use
printf("%s\n", "...")in C-Script orHMIRuntime.Tracein VBScript to log to the WinCC diagnostic fileWinCC_Sys_..log - Activate Runtime: launch the project. Click the button - Notepad must appear within 1 s.
-
Verify handle capture: read the
@NotepadHwndtag in WinCC Explorer. It must contain a non-zero decimal value. -
Trigger the close path: change the base picture or close the PictureWindow. Verify Notepad disappears. If it does not, switch to
taskkill /Ffallback. - Test Runtime shutdown: stop the Runtime. If the external program remains, hook the Shutdown event in Computer Properties to execute the cleanup script.
- Test Windows logoff: log off the panel. Verify that the WinCC shutdown event fires and terminates external processes.
12. Troubleshooting Matrix
| Symptom | Likely Cause | Fix |
|---|---|---|
| Notepad does not close when picture changes | HWND tag is empty or zero | Re-check FindWindow timing; the window may not be created yet - add the 3 s wait loop |
| Notepad closes on the development PC but not on the panel | Different Notepad version with different window class | Use FindWindow(NULL, "Notepad") matching by title; or query class with Spy++
|
| C-Script fails to compile - unresolved external symbol FindWindowA | Win32 library not linked | Add #pragma comment(lib, "user32.lib") at top of the action file |
| VBScript AppActivate returns False | Window title does not exactly match (wildcards unsupported) | Use partial title; or switch to taskkill
|
| Notepad re-spawns itself | Notepad has session-restart logic (Windows 10/11) | Disable "Automatically save my restartable apps when I sign out" in Windows settings |
| taskkill returns exit code 128 | Process already exited - not an error | Ignore exit code 128 in the cleanup script |
| External program blocks HMI after launch |
Shell.Run called without False return |
Use oShell.Run "notepad.exe", 1, False
|
| PictureWindow close event never fires | Base picture is unloaded instead of picture change | Hook Runtime shutdown or session logoff instead |
13. Frequently Asked Questions
Does WinCC automatically close external programs when a picture is unloaded?
No. Only internal PictureWindow objects follow the parent picture lifecycle. External Win32 processes such as notepad.exe must be closed explicitly via PostMessage(WM_CLOSE) in C-Script or taskkill /F in VBScript. The Siemens FAQ at support.industry.siemens.com/cs/ww/en/view/415808 confirms this behavior.
Is there a PictureClose event I can attach a C-Script to in WinCC V7?
The Close event exists on picture objects that are loaded via picture change. The base runtime picture does not raise a Close event on Runtime exit because the process is terminated instead. Use the Runtime Shutdown event or a PictureWindow's OnClose as the hook point for cleanup scripts.
Can TIA Portal WinCC Professional run C-Scripts like WinCC V7?
No. TIA WinCC Professional, Comfort and Unified support VBScript (and JavaScript in Unified) only. C-Script is exclusive to WinCC V7.x and WinCC Flexible. Translate C-Script cleanup logic to WScript.Shell.Run "taskkill ..." or to a custom COM helper for Win32 API access.
What is the difference between DestroyWindow and PostMessage WM_CLOSE?
PostMessage(hWnd, WM_CLOSE, 0, 0) - documented on Microsoft Learn PostMessage - sends a WM_CLOSE notification that well-behaved applications handle by saving state and exiting. DestroyWindow immediately removes the window without notifying the application; the process may keep running without a UI. Prefer PostMessage WM_CLOSE; fall back to taskkill /F if the process does not exit within 500 ms.
How do I reliably close Notepad from a WinCC Comfort Panel running Windows IoT?
Use VBScript on the PictureWindow's OnClose event with oShell.Run "taskkill /IM notepad.exe /F", 0, True. Combine with a 2-second cyclic polling trigger while the picture is visible so any orphaned Notepad instance from a previous Runtime crash is also terminated at Runtime startup.