Launch an exe from CODESYS with SysProcessCreate2

6 min read · Published November 3, 2026

SysProcessCreate2 from the SysProcess library starts an external exe from CODESYS structured text. Declare all four parameters, put the file to open in the arguments string, and pass SYSPROCESS_CREATEFLAG_INTERACTIVE so the process attaches to the desktop session. Read udiResult every time: a window appears only on a runtime whose OS has an interactive session, and SysExecuteCommand from SysOS23 is the fallback to try on the same target.

SysProcessCreate2 from the SysProcess library starts an external program from CODESYS structured text. Four parameters go in: the executable path, a command-line argument string, the creation flags, and a variable that receives the process handle. Declare all four, give the argument string a value when the program needs a file to open, and pass SYSPROCESS_CREATEFLAG_INTERACTIVE, the flag that asks for the process to start in the runtime's interactive session instead of as a background task. A window appears only on a runtime whose operating system has an interactive session, such as a soft PLC on desktop Windows. On a headless runtime nothing appears, no flag fixes it, and SysExecuteCommand from the SysOS23 library is the one alternative to try on the same target.

What the function does and what you need

The SysProcess library reference for SysProcessCreate2 describes the function in one line: it creates and starts a new process for the application you name, with a SYSPROCESS_CREATEFLAG_XXX constant selecting how. A controller vendor's application note documents the same technique for opening Windows applications from a runtime and marks it as available only on certain systems. Keep that in view from the first minute, because the runtime's version and its OS decide the outcome before your code does.

You need:

  • The SysProcess library added in the Library Manager.
  • A runtime that can spawn processes: a soft PLC on desktop Windows qualifies; a headless runtime has no desktop session to attach to.
  • The executable's path exactly as it exists on the controller's own file system, not on your engineering PC.
  • Strings long enough for both paths: a plain STRING in CODESYS holds 80 characters, so declare STRING(255) for both.

The call with every parameter declared

PROGRAM PLC_PRG
VAR
    sExecutable : STRING(255) := 'C:\Program Files\ImageView\imageview.exe';
    sArguments  : STRING(255) := 'C:\shift\board.png';
    pResult     : DWORD;    // receives the process handle
    udiResult   : UDINT;    // 0 when the runtime accepts the call
    xLaunch     : BOOL;     // button or condition
    trigLaunch  : R_TRIG;
END_VAR

trigLaunch(CLK := xLaunch);
IF trigLaunch.Q THEN
    udiResult := SysProcessCreate2(
        sExecutable,
        sArguments,
        SYSPROCESS_CREATEFLAG_INTERACTIVE,
        pResult);
END_IF

The first string is the executable, the second is the command line the program receives, the third is the creation flag, and the fourth receives the handle you can poll later with SysProcessGetState. Two details cost people an afternoon when they copy this call: every parameter must be declared in the VAR block, and the argument string must be given a value when the program expects a file. An image viewer started with an empty argument string opens with nothing to show.

Setting it up step by step

  1. Add the SysProcess library in the Library Manager.
  2. Declare the variables from the block above, with STRING(255) for both strings.
  3. Type the executable path as it exists on the controller, and check it in the controller's file system.
  4. Put the file to open in sArguments, as a full path.
  5. Wire the trigger into xLaunch from a button in the visualization or from a boolean condition, gated by R_TRIG so the call fires once.
  6. Call SysProcessCreate2 with SYSPROCESS_CREATEFLAG_INTERACTIVE.
  7. Read udiResult immediately after the call. A value of 0 is the success code across the CODESYS system libraries; anything else is an error code for the log.
  8. Confirm the process on the OS side before you call it done.

How to check it worked

Three checks, in order:

  • udiResult is 0. If it is not, the value itself is the error code; record it with the target name.
  • The process appears in the controller's task list. SysProcessGetState with the handle in pResult is the library's own way to poll a process you started.
  • The window opens on the desktop the runtime is logged into. That is the session check, and it is the one that fails on a headless target.

Example: opening a shift-board image on a Windows panel PC

The case: a soft PLC runs on a panel PC with desktop Windows, logged into its desktop, and a button should open the current shift-board image on that screen.

Inputs, each taken from the target itself:

  • Executable path: C:\Program Files\ImageView\imageview.exe, 40 characters.
  • Argument path: C:\shift\board.png, 18 characters.
  • String limit: a plain CODESYS STRING holds 80 characters.
  • Task cycle: 10 ms.

Rule in words: both strings must fit inside their declared length, and the call must fire once per button press. The character counts set the declarations; the cycle time sets the gating.

Arithmetic:

  • 40 characters for the executable and 18 for the argument both sit under the 80-character default, so truncation is ruled out. Declare STRING(255) anyway: one deeper folder or a longer file name passes 80 quickly.
  • At a 10 ms cycle, an ungated call executes 1000 / 10 = 100 times per second and can start up to 100 processes. The R_TRIG gate turns that into one launch per press.

Result: with both strings declared and assigned, the flag set and the gate in place, udiResult reads 0, the process shows in the task list, and the viewer opens on the panel's desktop with board.png.

Decision: udiResult 0, process present, window open, done. udiResult 0 with the process present and no window means the runtime has no interactive session, and no library call on that target will show one. Stop and move the launch off the controller.

Why the window never appears

Four causes cover the report that the call runs and nothing shows, and each has a one-minute test:

  • No interactive session. The runtime runs as a service or on a headless OS, so there is no desktop to attach to. Test: udiResult is 0, the process sits in the task list, no window. The runtime's CODESYS version and its OS decide this one, and it is the cause when both libraries fail on the same target.
  • The runtime refuses the creation. System functions are implemented per target. Test: udiResult is nonzero and no process exists; the returned code is the refusal.
  • The path is wrong on the target. The path exists on your engineering PC and nowhere else. Test: browse to it in the controller's file system.
  • The path is truncated or the argument is empty. A path longer than 80 characters in a plain STRING loses its tail; an empty argument string starts the program with nothing to open. Test: count the characters, then assign the file.

The SysExecuteCommand fallback from SysOS23

The second route is a one-string call:

SysExecuteCommand('C:\Program Files\ImageView\imageview.exe');

Add the SysOS23 library for it. It takes no flags and returns no handle, so you lose the state polling that pResult gives you. In the documented case, adding SysOS23 and calling it with a valid path still did not start the program on the same runtime. Treat it as a second attempt on the same target: when both calls leave no window, the OS session is the cause.

When to launch the exe somewhere else

A headless runtime will never show a window, so put the launch where the desktop is.

Recommendation: Use SysProcessCreate2 with the interactive flag when the runtime runs on desktop Windows with a logged-in session: declare all four parameters, assign the argument string, gate the call on a rising edge and read udiResult every time. Try SysExecuteCommand once on the same target when the first call leaves no window. When both leave no window on a headless runtime, stop debugging the call and launch the program from the panel PC's HMI or its startup script, or put the content on a screen that plays it on its own.

Questions

Why does SysProcessCreate2 run without an error but the program never opens?

Read udiResult first: 0 means the runtime accepted the creation, so the problem is past the call. Open the task list on the controller. If the process is listed with no window, the call worked and the session has no desktop to show it on; Windows services run in their own session, cut off from the logged-in desktop. If the process is missing, the runtime refused the creation and the code in udiResult says so. That one check separates a call problem from a session problem.

Does SysExecuteCommand work where SysProcessCreate2 fails?

Rarely on the same target. SysExecuteCommand comes from the SysOS23 library and was documented failing on a runtime where SysProcessCreate2 also failed. The two also differ in shape: SysProcessCreate2 passes the executable and its arguments as separate strings, while SysExecuteCommand takes one combined command line, where a path with spaces, like anything under Program Files, needs quotes. Try it once to see whether your runtime implements it, but two failures on one target point at the OS session.

How do I keep the call from starting the program repeatedly?

SysProcessCreate2 starts a process every time it executes, so gate it. Trigger it from a rising edge, for example a button press through R_TRIG, or poll the handle with SysProcessGetState first and create only when the state says the process is gone. In a 10 ms task an ungated call runs about 100 times per second, and each run can start another copy.

Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.

Keep reading

Build your signAsk for a quote