| name | tia-csharp-common |
| description | Internal reference skill — do NOT load directly from user queries. |
TIA Portal Openness C# — Common Foundation
Source: TIA Portal Openness General Functions Manual (03/2026, V21);
V21 IntelliSense XML documentation files (PublicAPI\V21\net48*.xml)
V21 modular assembly architecture
V21 splits the API across multiple DLLs instead of a single Siemens.Engineering.dll.
Every project needs Siemens.Engineering.Base.dll; add domain DLLs as required.
Referencing the wrong DLL (or omitting one) causes TypeLoadException at runtime.
Full mapping: See references/assembly-namespace-map.md for the exhaustive
namespace → DLL → domain skill table, cross-assembly warnings, and csproj patterns.
Namespaces by assembly
Only import what is actually used. The list below covers the most commonly needed
namespaces. The mapping file documents all 80+ namespaces across 15 DLLs.
Siemens.Engineering.Base.dll (always required):
using Siemens.Engineering;
using Siemens.Engineering.Compiler;
using Siemens.Engineering.Compare;
using Siemens.Engineering.Connection;
using Siemens.Engineering.CrossReference;
using Siemens.Engineering.Download;
using Siemens.Engineering.Download.Configurations;
using Siemens.Engineering.HW;
using Siemens.Engineering.HW.CommunicationConnections;
using Siemens.Engineering.HW.Extensions;
using Siemens.Engineering.HW.Features;
using Siemens.Engineering.HW.HardwareCatalog;
using Siemens.Engineering.HW.Utilities;
using Siemens.Engineering.Library;
using Siemens.Engineering.Library.MasterCopies;
using Siemens.Engineering.Library.Types;
using Siemens.Engineering.Multiuser;
using Siemens.Engineering.Online;
using Siemens.Engineering.Online.Configurations;
using Siemens.Engineering.Security;
using Siemens.Engineering.Settings;
using Siemens.Engineering.Umac;
using Siemens.Engineering.Upload;
using Siemens.Engineering.Upload.Configurations;
using Siemens.Engineering.VersionControl;
Siemens.Engineering.Step7.dll (PLC operations):
using Siemens.Engineering.Cax;
using Siemens.Engineering.SW;
using Siemens.Engineering.SW.Alarm;
using Siemens.Engineering.SW.Alarm.TextLists;
using Siemens.Engineering.SW.Blocks;
using Siemens.Engineering.SW.Blocks.Interface;
using Siemens.Engineering.SW.ExternalSources;
using Siemens.Engineering.SW.Loader;
using Siemens.Engineering.SW.OpcUa;
using Siemens.Engineering.SW.Supervision;
using Siemens.Engineering.SW.Tags;
using Siemens.Engineering.SW.TechnologicalObjects;
using Siemens.Engineering.SW.TechnologicalObjects.Motion;
using Siemens.Engineering.SW.Types;
using Siemens.Engineering.SW.Units;
using Siemens.Engineering.SW.WatchAndForceTables;
Siemens.Engineering.WinCC.dll (classic HMI):
using Siemens.Engineering.Hmi;
using Siemens.Engineering.Hmi.Alarm;
using Siemens.Engineering.Hmi.Communication;
using Siemens.Engineering.Hmi.Cycle;
using Siemens.Engineering.Hmi.Dynamic;
using Siemens.Engineering.Hmi.Faceplate;
using Siemens.Engineering.Hmi.Globalization;
using Siemens.Engineering.Hmi.Logging;
using Siemens.Engineering.Hmi.Recipe;
using Siemens.Engineering.Hmi.RuntimeScripting;
using Siemens.Engineering.Hmi.Screen;
using Siemens.Engineering.Hmi.Tag;
using Siemens.Engineering.Hmi.TextGraphicList;
using Siemens.Engineering.Hmi.Theming;
Siemens.Engineering.Startdrive.dll (SINAMICS drives):
using Siemens.Engineering.MC.Drives;
using Siemens.Engineering.MC.Drives.DFI;
using Siemens.Engineering.MC.Drives.Enums;
using Siemens.Engineering.MC.Drives.SecurityObjects;
Siemens.Engineering.Safety.dll (F-system):
using Siemens.Engineering.Safety;
Assembly resolver — MANDATORY (standalone Openness apps)
Not needed for Add-Ins. TIA Portal loads Add-In assemblies via its own loader.
This section applies only to standalone console/desktop Openness applications.
V21 installation paths
- Registry key:
HKLM\SOFTWARE\Siemens\Automation\InstalledApps\Totally Integrated Automation Portal V21 → value INSTALLPATH
- Binary path:
C:\Program Files\Siemens\Automation\Portal V21\PublicAPI\V21\net48\
- Manifest schemas:
C:\Program Files\Siemens\Automation\Portal V21\PublicAPI\V21\Schemas\
Resolver pattern
The AssemblyResolve event must be registered before any Openness type is referenced.
This includes method parameters, return types, and class properties — not just method bodies.
Recommended pattern: register in a static constructor of Program, then move all Openness
code to a separate class so the resolver is active before those classes are loaded.
internal static class Program
{
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
}
public static void Main()
{
var app = new OpennessApp();
app.Run();
}
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
string opennessFolder = GetOpennessInstallPath();
AssemblyName requestedName = new AssemblyName(args.Name);
string filePath = Path.Combine(opennessFolder,
string.Concat(requestedName.Name, ".dll"));
if (!requestedName.Name.StartsWith("Siemens.Engineering.") ||
!File.Exists(filePath))
return null;
Assembly loaded = Assembly.LoadFrom(filePath);
if (requestedName.FullName != loaded.GetName().FullName)
throw new FileNotFoundException(
"TIA Portal Openness version does not match", filePath);
return loaded;
}
}
Key rules:
Copy Local: False (<Private>False</Private>) must be set for every Siemens.Engineering assembly reference.
- V21 uses modular DLLs:
Base.dll is always needed; add Step7.dll, WinCC.dll,
Startdrive.dll, etc. per task. The resolver handles all of them automatically
because it matches any name starting with Siemens.Engineering..
- The recommended approach reads the install path from the registry key
HKLM\SOFTWARE\Siemens\Automation\InstalledApps\Totally Integrated Automation Portal V21
(value INSTALLPATH) rather than hardcoding it.
Registry-based path discovery:
private static string GetOpennessInstallPath()
{
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Siemens\Automation\InstalledApps\Totally Integrated Automation Portal V21"))
{
string installPath = key?.GetValue("INSTALLPATH") as string;
if (string.IsNullOrEmpty(installPath))
throw new FileNotFoundException("TIA Portal V21 installation not found in registry.");
return Path.Combine(installPath, @"PublicAPI\V21\net48");
}
}
Alternative — app.config:
For stable installations where the path is known at build time, an app.config file with
<assemblyBinding> / <codeBase> entries is a simpler option that requires no code.
Use the AssemblyResolve event for tools that need to discover the install path at runtime.
TiaPortal instantiation
Always use a using statement so the session is disposed on exit or exception:
internal class OpennessApp
{
public void Run()
{
using (TiaPortal tiaPortal = new TiaPortal(TiaPortalMode.WithUserInterface))
{
}
}
}
Modes:
TiaPortalMode.WithUserInterface — starts or attaches with visible GUI
TiaPortalMode.WithoutUserInterface — headless, suitable for automation pipelines
Attaching to a running instance:
TiaPortal tiaPortal = TiaPortal.GetProcesses().First().Attach();
Use GetProcesses() when TIA Portal is already open and you do not want to start a new
instance. Returns only processes from the same Openness version as the loaded assembly.
Dispose vs. close:
- If started headless and no other Openness client is attached,
Dispose() closes TIA Portal.
- If started with GUI or other clients are attached,
Dispose() only disconnects.
- After dispose, any further API access throws
NonRecoverableException.
Service providers — GetService<T>()
V21 uses a service-provider pattern for UI interactions. Call GetService<T>() on the
TiaPortal instance to obtain a service. Available services depend on the runtime context.
Add-In runtime services
These services are available only when code runs inside a TIA Portal Add-In:
| Service type | Namespace | Purpose |
|---|
MessageBoxProvider | Siemens.Engineering.AddIn | Display notification/confirmation dialogs in TIA Portal |
ProgressProvider | Siemens.Engineering.AddIn | Display a progress bar; check IsCancelRequested for cancellation |
FeedbackProvider | Siemens.Engineering.AddIn | Log messages to TIA Portal's Inspector window (General Info tab) |
var msgBox = tiaPortal.GetService<MessageBoxProvider>();
msgBox?.ShowNotification(NotificationIcon.Information, "Title", "Message text");
msgBox?.ShowNotification(NotificationIcon.Warning, "Title", "Message", "Detail text");
ConfirmationResult result = msgBox.ShowConfirmation(
ConfirmationIcon.General, "Title", "Proceed?",
ConfirmationChoices.Yes | ConfirmationChoices.No, ConfirmationResult.Yes);
if (result == ConfirmationResult.No) return;
var progress = tiaPortal.GetService<ProgressProvider>();
progress?.Update("Step description", "Detail text");
if (progress?.IsCancelRequested == true)
{
}
var feedback = tiaPortal.GetService<FeedbackProvider>();
feedback?.Log(NotificationIcon.Information, "Operation completed successfully.");
feedback?.Log(NotificationIcon.Warning, "Skipped 3 items due to missing data.");
Important: In Add-In status callbacks (the OnUpdateStatus delegate passed to
AddActionItem), GetService<T>() returns null. Only use services in action
callbacks where COM access is fully available.
Event handlers
Four events are available on TiaPortal. Always unsubscribe in a finally block.
Disposed
Fires when TIA Portal closes while the Openness client is still connected.
tiaPortal.Disposed += OnDisposed;
try
{
}
finally
{
tiaPortal.Disposed -= OnDisposed;
}
private static void OnDisposed(object sender, EventArgs e)
{
}
Notification
Fires for informational messages that require only an acknowledgment (OK).
tiaPortal.Notification += OnNotification;
try { }
finally { tiaPortal.Notification -= OnNotification; }
private static void OnNotification(object sender, NotificationEventArgs e)
{
Console.WriteLine($"[TIA Notification] {e.Text}");
}
Confirmation
Fires for dialogs that require a decision. Must set e.Result to one of:
"Yes", "YesToAll", or "No". Any other value throws an exception.
Auto-confirm pattern (most common in automation):
tiaPortal.Confirmation += OnConfirmation;
try { }
finally { tiaPortal.Confirmation -= OnConfirmation; }
private static void OnConfirmation(object sender, ConfirmationEventArgs e)
{
e.Result = "Yes";
}
Authentication (V17+)
Fires when opening a UMAC-protected project. Use to specify the authentication method
instead of passing credentials via UmacDelegate. Only fires for protected projects.
tiaPortal.Authentication += OnAuthentication;
try { }
finally { tiaPortal.Authentication -= OnAuthentication; }
private static void OnAuthentication(object sender, AuthenticationEventArgs e)
{
e.AuthenticationTypeProvider = AuthenticationTypeProvider.DesktopSso;
}
AuthenticationTypeProvider | Behaviour |
|---|
DesktopSso | Signs in with the current Windows user — no password prompt |
Anonymous | Uses the anonymous user account — no password prompt |
Interactive | Shows TIA Portal login dialog to the user |
Credentials | Reads credentials from the supplied UmacDelegate |
Exclusive access
Highly recommended for all non-trivial operations. Signals TIA Portal that a controlled
activity is in progress and displays a dialog to the user.
using (ExclusiveAccess exclusiveAccess = tiaPortal.ExclusiveAccess("Generating project"))
{
exclusiveAccess.Text = "Compiling software";
exclusiveAccess.Text = "Downloading to PLC";
}
Rules:
- Only one
ExclusiveAccess can exist at a time — a second attempt throws a recoverable
exception while the first is still active.
- Setting
exclusiveAccess.Text = string.Empty or null clears the displayed message.
Transactions
Group multiple modifications into a single undo unit. Requires an active ExclusiveAccess.
using (ExclusiveAccess exclusiveAccess = tiaPortal.ExclusiveAccess("Bulk edit"))
{
using (Transaction transaction = exclusiveAccess.Transaction(project, "Create blocks"))
{
project.DeviceGroups.Create("Line_1");
project.DeviceGroups.Create("Line_2");
transaction.CommitOnDispose();
}
}
Rollback rules — critical:
- If
CommitOnDispose() is never called → always rolled back on dispose.
- If an exception occurs before
CommitOnDispose() → rolled back, even inside try/catch.
- If an exception occurs after
CommitOnDispose() → changes are committed.
Not allowed inside a transaction:
Project open, save, close, archive, retrieve, and some compile/import/export operations
cannot be called while a transaction is active.
Destructive-operation safety
These rules are mandatory for generated C# Openness code:
- Never bare
.Delete(). Any destructive operation must be inside an active
ExclusiveAccess scope and a Transaction when the API permits transactions.
- Use
using blocks for ExclusiveAccess, Transaction, TiaPortal, projects,
and other disposable Openness objects so rollback and release behavior is explicit.
- Call
transaction.CommitOnDispose() only after every validation and mutation in
the transaction has succeeded.
- Run or request a
compile_check after generated block, tag, hardware, or HMI
changes. Do not present generated project changes as deployable until that check
passes.
- If an API refuses to run inside a transaction, state that limitation explicitly,
use the narrowest possible
ExclusiveAccess scope, and require a preview or
user confirmation before the destructive call.
Exception handling
Two top-level categories:
| Category | Base type | Behaviour |
|---|
| Recoverable | Siemens.Engineering.EngineeringException | API call failed; session remains valid |
| Non-recoverable | Siemens.Engineering.NonRecoverableException | TIA Portal closed; restart required |
Recoverable subtypes:
| Type | Typical cause |
|---|
EngineeringSecurityException | Missing access rights |
EngineeringObjectDisposedException | Object no longer exists (e.g. deleted) |
EngineeringNotSupportedException | Attribute or operation not available on this object |
EngineeringTargetInvocationException | General failure despite a valid API call |
EngineeringRuntimeException | Runtime error, e.g. invalid cast |
EngineeringOutOfMemoryException | Insufficient resources in TIA Portal instance |
EngineeringUserAbortException | Operation cancelled by the user (e.g. import dialog) |
EngineeringDelegateInvocationException | Exception thrown inside a caller-supplied delegate |
MissingProductsException | Project requires TIA Portal products/packages not installed (V18+) |
Recommended catch order:
try
{
}
catch (EngineeringSecurityException ex)
{
Console.WriteLine($"Access denied: {ex.Message}");
}
catch (EngineeringObjectDisposedException ex)
{
Console.WriteLine($"Object disposed: {ex.Message}");
}
catch (EngineeringNotSupportedException ex)
{
Console.WriteLine($"Not supported: {ex.MessageData.Text}");
foreach (ExceptionMessageData detail in ex.DetailMessageData)
Console.WriteLine($" Detail: {detail.Text}");
}
catch (MissingProductsException ex)
{
Console.WriteLine($"Missing products: {ex.Message}");
}
catch (EngineeringTargetInvocationException)
{
throw;
}
catch (EngineeringException)
{
throw;
}
catch (NonRecoverableException ex)
{
Console.WriteLine($"Fatal — TIA Portal closed: {ex.Message}");
}
Project open mode
When opening multiple projects or working in multiuser environments:
Project primary = tiaPortal.Projects.Open(
new FileInfo(path), umacDelegate, ProjectOpenMode.Primary);
Project secondary = tiaPortal.Projects.Open(
new FileInfo(path), null, ProjectOpenMode.Secondary);
bool isPrimary = secondary.IsPrimary;
Rules:
- Only one primary project per TIA Portal instance.
- Secondary projects do not need a primary project to be open first.
- A user with write rights to a UMAC-protected project still gets read-only access when
opening it as secondary.
Object model contracts
Composition methods
Most engineering objects are accessed through compositions. Available methods:
| Method | Behaviour |
|---|
Create(id, ...) | Creates and adds a new instance. Signature varies per composition. |
Find(id) | Finds by identifier. Non-recursive — searches current level only. |
GetEnumerator() | Used implicitly in foreach loops. |
Contains(obj) | Returns bool — checks if object is in the composition. |
IndexOf(obj) | Returns int index of the object in the composition. |
Import(path, ImportOptions) | Available on compositions that support import. ImportOptions: None or Overwrite. |
Delete(obj) | Removes and deletes the instance. |
Not all methods are available on every composition — check domain skills.
Object equality
bool sameRef = (objA == objB);
bool sameObj = System.Object.Equals(objA, objB);
Use System.Object.Equals() when comparing objects retrieved through different navigation
paths that may represent the same underlying engineering object.
DirectoryInfo / FileInfo — absolute paths only
All DirectoryInfo and FileInfo instances passed to Openness must use absolute paths.
Relative paths cause an exception at runtime.
var dir = new DirectoryInfo(@"C:\Projects\MyProject\Export");
var dir = new DirectoryInfo(@"Export");
Bulk attribute access
Useful for dynamic tooling or when setting multiple attributes efficiently on HW objects.
Read all attributes
IList<EngineeringAttributeInfo> infos =
((IEngineeringObject)deviceItem).GetAttributeInfos();
IList<string> names = infos.Select(i => i.Name).ToList();
IList<object> values = ((IEngineeringObject)deviceItem).GetAttributes(names);
Filtered read by access mode
IReadOnlyList<KeyValuePair<string, object>> readableAttrs =
deviceItem.GetAttributes(AttributeAccessOptions.ReadOnly);
Bulk write (HW objects only — provides callback)
var pairs = new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("Name", "NewModuleName"),
new KeyValuePair<string, object>("Comment", "Auto-generated")
};
deviceItem.SetAttributes(pairs, (name, val, ex) =>
{
if (ex != null)
Console.WriteLine($"Failed to set {name}: {ex.Message}");
});
((IEngineeringObject)someObject).SetAttributes(pairs);