PowerShell für das Automation Interface einrichten
Das TwinCAT Automation Interface nutzt COM-Objekte, die besondere Anforderungen an die PowerShell-Umgebung stellen. Der wichtigste Punkt ist das Threading-Modell. Die COM-Objekte des Automation Interface sind im Single-Threaded-Apartment, kurz STA, registriert und können nur aus einem STA-Thread heraus korrekt angesprochen werden. PowerShell 7 läuft per Voreinstellung jedoch im Multi-Threaded-Apartment, kurz MTA. Die STA-Anforderung muss daher explizit erfüllt werden, indem ein eigener STA-Runspace erzeugt wird. Dieser Artikel zeigt den wichtigsten Fallstrick und dessen Lösung.
Voraussetzungen
TwinCAT XAE und PowerShell 7.x müssen installiert sein.
STA-Apartment-Modus setzen
COM-Objekte des Automation Interface benötigen STA, das Single-Threaded-Apartment. Das STA-Modell garantiert, dass alle Aufrufe an ein COM-Objekt serialisiert über genau einen Thread laufen. Genau das erwartet das Automation Interface. Wird das Objekt dagegen aus einem MTA-Thread heraus angesprochen, treten Fehler wie RPC_E_SERVERCALL_RETRYLATER oder unerwartete Marshalling-Probleme auf.
Da PowerShell 7 standardmäßig im MTA-Modus startet, wird ein eigener STA-Runspace erstellt. Über die RunspaceFactory wird ein Runspace erzeugt, dessen ApartmentState explizit auf "STA" gesetzt wird. Die Einstellung ThreadOptions = "ReuseThread" stellt sicher, dass alle nachfolgenden Aufrufe denselben Thread verwenden. Das ist zwingend erforderlich, da ein STA-COM-Objekt nur von dem Thread bedient werden darf, der es erzeugt hat. Der eigentliche COM-Code wird anschließend über AddScript({ ... }).Invoke() innerhalb dieses STA-Runspace ausgeführt:
$ps = [PowerShell]::Create()
$rs = [RunSpaceFactory]::CreateRunspace()
$rs.ApartmentState = "STA"
$rs.ThreadOptions = "ReuseThread"
$rs.Open()
$ps.Runspace = $rs
$ps.AddScript({
$dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject("TcXaeShell.DTE.17.0")
$project = $dte.Solution.Projects.Item(1)
$project.Object # ITcSysManager
}).Invoke()