TIA Openness 应用的多版本支持

当使用西门子TIA Portal Openness API开发应用程序时,引用特定版本的DLL会创建硬依赖,将您的应用程序限制为单个TIA Portal版本。

本文档介绍了两种方法,用于创建单个编译后的应用程序,该应用程序可根据安装的TIA Portal版本动态解析并加载正确的Siemens.Engineering.dllSiemens.Engineering.Hmi.dll

1、问题陈述

在Visual Studio项目中直接引用特定TIA Portal版本(例如V15.1或V16)的DLL时,如果目标系统安装了不同的TIA Portal版本,会导致FileNotFoundExceptionBadImageFormatException。应用程序无法找到它编译时所依据的特定DLL版本。

2、根本原因

.NET的程序集绑定机制尝试在运行时加载所引用程序集的精确版本。当编译器引用版本为15.1.0.0Siemens.Engineering.dll时,运行时会搜索该精确版本。如果只安装了TIA Portal V16,绑定将失败。

注意: TIA Portal Openness DLL位于C:\Program Files\Siemens\Automation\Portal V15_1\PublicAPI\V15.1\C:\Program Files\Siemens\Automation\Portal V16\PublicAPI\V16\。每个版本都有自己的一组程序集,具有匹配的版本号。

3、解决方案1:App.Config CodeBase绑定

app.config文件可以为同一程序集标识符指定多个codeBase条目,允许运行时定位已安装的版本。此方法需要在更改TIA Portal版本后重新启动应用程序。

3.1 配置步骤

  1. 如果项目中没有app.config文件,请添加一个
  2. 使用每个TIA Portal版本的codeBase条目配置<assemblyBinding>部分
  3. 确保项目中引用的DLL版本与配置中的条目匹配

3.2 App.Config示例

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Siemens.Engineering" 
                          culture="neutral" 
                          publicKeyToken="d29ec89bac048f84"/>
        <codeBase version="15.1.0.0" 
                  href="file:///C:\Program%20Files\Siemens\Automation\Portal%20V15_1\PublicAPI\V15.1\Siemens.Engineering.dll"/>
        <codeBase version="16.0.0.0" 
                  href="file:///C:\Program%20Files\Siemens\Automation\Portal%20V16\PublicAPI\V16\Siemens.Engineering.dll"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Siemens.Engineering.Hmi" 
                          culture="neutral" 
                          publicKeyToken="37b6e3a80df0900f"/>
        <codeBase version="15.1.0.0" 
                  href="file:///C:\Program%20Files\Siemens\Automation\Portal%20V15_1\PublicAPI\V15.1\Siemens.Engineering.Hmi.dll"/>
        <codeBase version="16.0.0.0" 
                  href="file:///C:\Program%20Files\Siemens\Automation\Portal%20V16\PublicAPI\V16\Siemens.Engineering.Hmi.dll"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

3.3 支持的程序集

程序集名称 PublicKeyToken V15.1路径 V16路径
Siemens.Engineering d29ec89bac048f84 \PublicAPI\V15.1\ \PublicAPI\V16\
Siemens.Engineering.Hmi 37b6e3a80df0900f \PublicAPI\V15.1\ \PublicAPI\V16\
Siemens.Engineering.Platform 57f3cc8d4f4d1d9a \PublicAPI\V15.1\ \PublicAPI\V16\

4、解决方案2:AssemblyResolve事件处理程序

要在不重启应用程序的情况下进行运行时版本切换,请实现AppDomain.CurrentDomain.AssemblyResolve事件。这提供了对程序集加载的完全控制,并允许从Windows注册表读取TIA Portal安装。

4.1 C#实现

using System;
using System.IO;
using System.Reflection;
using Microsoft.Win32;

public class TiaPortalResolver
{
    private static readonly string[] TiaAssemblyNames = 
    {
        "Siemens.Engineering",
        "Siemens.Engineering.Hmi",
        "Siemens.Engineering.Platform"
    };

    public static void RegisterResolver()
    {
        AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
    }

    private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
    {
        var requestedAssembly = new AssemblyName(args.Name);
        
        if (Array.IndexOf(TiaAssemblyNames, requestedAssembly.Name) == -1)
            return null;

        var dllPath = FindTiaAssemblyPath(requestedAssembly.Name, requestedAssembly.Version?.ToString());
        
        if (!string.IsNullOrEmpty(dllPath) && File.Exists(dllPath))
        {
            return Assembly.LoadFrom(dllPath);
        }

        return null;
    }

    private static string FindTiaAssemblyPath(string assemblyName, string version)
    {
        var tiaPaths = GetTiaInstallationPaths();
        
        foreach (var basePath in tiaPaths)
        {
            var searchPattern = Path.Combine(basePath, "PublicAPI", "*", $"{assemblyName}.dll");
            
            if (!string.IsNullOrEmpty(version))
            {
                var versionPath = Path.Combine(basePath, "PublicAPI", $"V{version}", $"{assemblyName}.dll");
                if (File.Exists(versionPath))
                    return versionPath;
            }
            
            var parentDir = Path.GetDirectoryName(basePath);
            if (parentDir != null)
            {
                var apiBase = Path.Combine(parentDir, "PublicAPI");
                if (Directory.Exists(apiBase))
                {
                    foreach (var versionDir in Directory.GetDirectories(apiBase, "V*"))
                    {
                        var dllPath = Path.Combine(versionDir, $"{assemblyName}.dll");
                        if (File.Exists(dllPath))
                            return dllPath;
                    }
                }
            }
        }
        
        return null;
    }

    public static string[] GetTiaInstallationPaths()
    {
        var paths = new List<string>();
        
        using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Siemens\Automation\InstalledApps"))
        {
            if (key != null)
            {
                foreach (var subKeyName in key.GetSubKeyNames())
                {
                    if (subKeyName.Contains("Portal"))
                    {
                        using (var subKey = key.OpenSubKey(subKeyName))
                        {
                            var path = subKey?.GetValue("INSTALLPATH") as string;
                            if (!string.IsNullOrEmpty(path) && Directory.Exists(path))
                            {
                                paths.Add(path);
                            }
                        }
                    }
                }
            }
        }
        
        return paths.ToArray();
    }
}

4.2 使用方法

class Program
{
    static void Main(string[] args)
    {
        TiaPortalResolver.RegisterResolver();
        
        var tiaVersion = Siemens.Engineering.Version.SupportedVersions[0];
        using (var plc = tiaVersion.Attach(null))
        {
            // 您的应用程序逻辑
        }
    }
}

5、注册表读取工具

TIA Portal安装在HKEY_LOCAL_MACHINE\SOFTWARE\Siemens\Automation\InstalledApps下注册。每个子键代表一个已安装的西门子应用程序,其INSTALLPATH值包含基本安装目录。

注册表键 典型值
HKEY_LOCAL_MACHINE\SOFTWARE\Siemens\Automation\InstalledApps\Totally Integrated Automation Portal V15.1 C:\Program Files\Siemens\Automation\Portal V15_1
HKEY_LOCAL_MACHINE\SOFTWARE\Siemens\Automation\InstalledApps\Totally Integrated Automation Portal V16 C:\Program Files\Siemens\Automation\Portal V16
HKEY_LOCAL_MACHINE\SOFTWARE\Siemens\Automation\InstalledApps\Totally Integrated Automation Portal V17 C:\Program Files\Siemens\Automation\Portal V17

重要提示: 在64位Windows上,注册表视图可能在WOW6432Node下。请同时检查HKEY_LOCAL_MACHINE\SOFTWARE\SiemensHKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Siemens

6、版本检测逻辑

实现动态解析时,在ResolveEventArgs.Name中匹配程序集名称时,请使用EndsWith而不是Contains。某些绑定失败可能包含"Siemens.Engineering"作为子字符串,但指的是不同的程序集。已解析的程序集名称格式为:

Siemens.Engineering, Version=15.1.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84

7、限制和已知问题

  • 配置缓存: app.config在程序启动时加载并缓存。运行时修改需要重新启动应用程序。
  • 清单不匹配: 尝试加载与预期清单不同的DLL可能会抛出BadImageFormatException。请确保以正确的DLL版本为目标。
  • 引用版本: 您仍必须在Visual Studio项目中引用DLL的某个版本。解析器在运行时重定向到已安装的版本。
  • V17行为: TIA Portal V17在单个安装中包含从V14到V17版本的DLL。从V17文件夹引用V15.0 DLL仍可能启动V17 TIA Portal。

8、验证步骤

  1. 构建引用一个TIA Portal版本(例如V15.1 DLL)的应用程序
  2. 部署到安装了不同TIA Portal版本(例如V16)的计算机
  3. 启动您的应用程序
  4. 通过任务管理器或TIA Portal UI验证是否启动了正确的TIA Portal版本
  5. 检查应用程序日志以确认程序集解析成功

原文链接: Configuring TIA Portal Openness DLL for Multi-Version Support

汇智网翻译整理,转载请标明出处