From 22791c6d487e335a5d6ceef34b09c7be59ba759e Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 10 Oct 2018 15:33:41 -0700 Subject: [PATCH 1/5] Set STA ApartmentState in Windows PowerShell runspaces --- .../Session/PowerShellContext.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/PowerShellEditorServices/Session/PowerShellContext.cs b/src/PowerShellEditorServices/Session/PowerShellContext.cs index 170cd0d20..8f28f3cd5 100644 --- a/src/PowerShellEditorServices/Session/PowerShellContext.cs +++ b/src/PowerShellEditorServices/Session/PowerShellContext.cs @@ -12,6 +12,7 @@ using System.Management.Automation.Host; using System.Management.Automation.Remoting; using System.Management.Automation.Runspaces; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -23,6 +24,7 @@ namespace Microsoft.PowerShell.EditorServices { using System.Management.Automation; + using System.Runtime.InteropServices; /// /// Manages the lifetime and usage of a PowerShell session. @@ -31,6 +33,21 @@ namespace Microsoft.PowerShell.EditorServices /// public class PowerShellContext : IDisposable, IHostSupportsInteractiveSession { + private const string DotNetFrameworkDescription = ".NET Framework"; + + private static readonly Action s_runspaceApartmentStateSetter; + + static PowerShellContext() + { + // PowerShell ApartmentState APIs aren't available in PSStandard, so we need to use reflection + if (RuntimeInformation.FrameworkDescription == DotNetFrameworkDescription) + { + MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod(); + var setter = Delegate.CreateDelegate(typeof(Action), target: null, method: setterInfo); + s_runspaceApartmentStateSetter = (Action)setter; + } + } + #region Fields private readonly SemaphoreSlim resumeRequestHandle = AsyncUtils.CreateSimpleLockingSemaphore(); @@ -174,6 +191,13 @@ public static Runspace CreateRunspace(PSHost psHost) } Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); + + // Windows PowerShell must be hosted in STA mode + if (RuntimeInformation.FrameworkDescription == DotNetFrameworkDescription) + { + s_runspaceApartmentStateSetter(runspace, ApartmentState.STA); + } + runspace.ThreadOptions = PSThreadOptions.ReuseThread; runspace.Open(); From 454bd6db4fc7252d10d2bcd0ed7196ad8cc0a7ca Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 10 Oct 2018 15:42:35 -0700 Subject: [PATCH 2/5] Use correct overload of CreateDelegate --- src/PowerShellEditorServices/Session/PowerShellContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices/Session/PowerShellContext.cs b/src/PowerShellEditorServices/Session/PowerShellContext.cs index 8f28f3cd5..0c7b4ae1f 100644 --- a/src/PowerShellEditorServices/Session/PowerShellContext.cs +++ b/src/PowerShellEditorServices/Session/PowerShellContext.cs @@ -8,6 +8,7 @@ using System.Collections.ObjectModel; using System.Globalization; using System.IO; +using System.Runtime.InteropServices; using System.Linq; using System.Management.Automation.Host; using System.Management.Automation.Remoting; @@ -24,7 +25,6 @@ namespace Microsoft.PowerShell.EditorServices { using System.Management.Automation; - using System.Runtime.InteropServices; /// /// Manages the lifetime and usage of a PowerShell session. @@ -43,7 +43,7 @@ static PowerShellContext() if (RuntimeInformation.FrameworkDescription == DotNetFrameworkDescription) { MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod(); - var setter = Delegate.CreateDelegate(typeof(Action), target: null, method: setterInfo); + var setter = Delegate.CreateDelegate(typeof(Action), firstArgument: null, method: setterInfo); s_runspaceApartmentStateSetter = (Action)setter; } } From 46afe905c7f725b3964075f11052d54db3d239f4 Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 10 Oct 2018 16:27:44 -0700 Subject: [PATCH 3/5] Use explicit Delegate type on variable --- src/PowerShellEditorServices/Session/PowerShellContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Session/PowerShellContext.cs b/src/PowerShellEditorServices/Session/PowerShellContext.cs index 0c7b4ae1f..2d6b75fc8 100644 --- a/src/PowerShellEditorServices/Session/PowerShellContext.cs +++ b/src/PowerShellEditorServices/Session/PowerShellContext.cs @@ -43,7 +43,7 @@ static PowerShellContext() if (RuntimeInformation.FrameworkDescription == DotNetFrameworkDescription) { MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod(); - var setter = Delegate.CreateDelegate(typeof(Action), firstArgument: null, method: setterInfo); + Delegate setter = Delegate.CreateDelegate(typeof(Action), firstArgument: null, method: setterInfo); s_runspaceApartmentStateSetter = (Action)setter; } } From 55427d43eaaa5b7b68d12c262b36498cd962656c Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 10 Oct 2018 18:04:46 -0700 Subject: [PATCH 4/5] Use string.Equals instead of == --- src/PowerShellEditorServices/Session/PowerShellContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices/Session/PowerShellContext.cs b/src/PowerShellEditorServices/Session/PowerShellContext.cs index 2d6b75fc8..394c097cd 100644 --- a/src/PowerShellEditorServices/Session/PowerShellContext.cs +++ b/src/PowerShellEditorServices/Session/PowerShellContext.cs @@ -40,7 +40,7 @@ public class PowerShellContext : IDisposable, IHostSupportsInteractiveSession static PowerShellContext() { // PowerShell ApartmentState APIs aren't available in PSStandard, so we need to use reflection - if (RuntimeInformation.FrameworkDescription == DotNetFrameworkDescription) + if (RuntimeInformation.FrameworkDescription.Equals(DotNetFrameworkDescription)) { MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod(); Delegate setter = Delegate.CreateDelegate(typeof(Action), firstArgument: null, method: setterInfo); @@ -193,7 +193,7 @@ public static Runspace CreateRunspace(PSHost psHost) Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode - if (RuntimeInformation.FrameworkDescription == DotNetFrameworkDescription) + if (RuntimeInformation.FrameworkDescription.Equals(DotNetFrameworkDescription)) { s_runspaceApartmentStateSetter(runspace, ApartmentState.STA); } From 2ed6294752896819cc94a9a3bbef3dbe9bd31be7 Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Thu, 11 Oct 2018 09:26:32 -0700 Subject: [PATCH 5/5] Add comment about runspace sta setting --- src/PowerShellEditorServices/Session/PowerShellContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerShellEditorServices/Session/PowerShellContext.cs b/src/PowerShellEditorServices/Session/PowerShellContext.cs index 394c097cd..7ac777889 100644 --- a/src/PowerShellEditorServices/Session/PowerShellContext.cs +++ b/src/PowerShellEditorServices/Session/PowerShellContext.cs @@ -193,6 +193,7 @@ public static Runspace CreateRunspace(PSHost psHost) Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode + // This must be set on the runspace *before* it is opened if (RuntimeInformation.FrameworkDescription.Equals(DotNetFrameworkDescription)) { s_runspaceApartmentStateSetter(runspace, ApartmentState.STA);