-
Notifications
You must be signed in to change notification settings - Fork 8.4k
Add check if STA is supported before using on console startup #15106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
125f3aa
a0a0446
15a499c
28a9fe0
f9e2d4b
c59ec94
3b7882b
12b82c4
a4c1fd2
bc1cd52
f7c5eaf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,8 +16,6 @@ namespace System.Management.Automation | |
| /// </summary> | ||
| public static class Platform | ||
| { | ||
| private static string _tempDirectory = null; | ||
|
|
||
| /// <summary> | ||
| /// True if the current platform is Linux. | ||
| /// </summary> | ||
|
|
@@ -140,6 +138,21 @@ public static bool IsWindowsDesktop | |
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets a value indicating whether the underlying system supports single-threaded apartment. | ||
| /// </summary> | ||
| public static bool IsStaSupported | ||
| { | ||
| get | ||
| { | ||
| #if UNIX | ||
| return false; | ||
| #else | ||
| return _isStaSupported.Value; | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| #if UNIX | ||
| // Gets the location for cache and config folders. | ||
| internal static readonly string CacheDirectory = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CACHE); | ||
|
|
@@ -148,6 +161,22 @@ public static bool IsWindowsDesktop | |
| // Gets the location for cache and config folders. | ||
| internal static readonly string CacheDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerShell"; | ||
| internal static readonly string ConfigDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\PowerShell"; | ||
| private static readonly Lazy<bool> _isStaSupported = new Lazy<bool>(() => | ||
| { | ||
| // See objbase.h | ||
| const int COINIT_APARTMENTTHREADED = 0x2; | ||
| const int E_NOTIMPL = unchecked((int)0X80004001); | ||
| int result = Windows.NativeMethods.CoInitializeEx(IntPtr.Zero, COINIT_APARTMENTTHREADED); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if this PInvoke is anymore efficient than spinning up a thread before. Has any perf testing been done?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can an exception be thrown here?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CoInitializeEx only returns an HRESULT, so there should never be an exception here unless .NET throws. |
||
|
|
||
| // If 0 is returned the thread has been initialized for the first time | ||
| // as an STA and thus supported and needs to be uninitialized. | ||
| if (result > 0) | ||
| { | ||
| Windows.NativeMethods.CoUninitialize(); | ||
| } | ||
|
Comment on lines
+171
to
+176
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder why we need the check if it is used in startup scenario.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's needed in the startup scenario as the main console runspace needs to start as either STA or MTA. So we need to know if STA is supported before trying STA otherwise pwsh ends up in an unusable state. S_False will never apply here as CoInitialize() won't be called before this. |
||
|
|
||
| return result != E_NOTIMPL; | ||
| }); | ||
|
|
||
| private static bool? _isNanoServer = null; | ||
| private static bool? _isIoT = null; | ||
|
|
@@ -170,6 +199,8 @@ public static bool IsWindowsDesktop | |
| "WSMan.format.ps1xml" | ||
| }; | ||
|
|
||
| private static string _tempDirectory = null; | ||
|
|
||
| /// <summary> | ||
| /// Some common environment variables used in PS have different | ||
| /// names in different OS platforms. | ||
|
|
@@ -557,6 +588,21 @@ internal static int NonWindowsGetProcessParentPid(int pid) | |
| return IsMacOS ? Unix.NativeMethods.GetPPid(pid) : Unix.GetProcFSParentPid(pid); | ||
| } | ||
|
|
||
| internal static class Windows | ||
| { | ||
| /// <summary>The native methods class.</summary> | ||
| internal static class NativeMethods | ||
| { | ||
| private const string ole32Lib = "api-ms-win-core-com-l1-1-0.dll"; | ||
|
|
||
| [DllImport(ole32Lib)] | ||
| internal static extern int CoInitializeEx(IntPtr reserve, int coinit); | ||
|
|
||
| [DllImport(ole32Lib)] | ||
| internal static extern void CoUninitialize(); | ||
| } | ||
| } | ||
|
|
||
| // Please note that `Win32Exception(Marshal.GetLastWin32Error())` | ||
| // works *correctly* on Linux in that it creates an exception with | ||
| // the string perror would give you for the last set value of errno. | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -48,7 +48,15 @@ public static void TestDefaults() | |||||||
| Assert.False(cpp.SkipProfiles); | ||||||||
| Assert.False(cpp.SocketServerMode); | ||||||||
| Assert.False(cpp.SSHServerMode); | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| Assert.True(cpp.StaMode); | ||||||||
| if (Platform.IsWindows) | ||||||||
| { | ||||||||
| Assert.True(cpp.StaMode); | ||||||||
| } | ||||||||
| else | ||||||||
| { | ||||||||
| Assert.False(cpp.StaMode); | ||||||||
| } | ||||||||
|
|
||||||||
| Assert.False(cpp.ThrowOnReadAndPrompt); | ||||||||
| Assert.False(cpp.WasInitialCommandEncoded); | ||||||||
| Assert.Null(cpp.WorkingDirectory); | ||||||||
|
|
@@ -1185,7 +1193,15 @@ public static void TestParameter_LastParameterIsFileName_Exist(params string[] c | |||||||
| Assert.False(cpp.NoExit); | ||||||||
| Assert.False(cpp.ShowShortHelp); | ||||||||
| Assert.False(cpp.ShowBanner); | ||||||||
| Assert.True(cpp.StaMode); | ||||||||
| if (Platform.IsWindows) | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| { | ||||||||
| Assert.True(cpp.StaMode); | ||||||||
| } | ||||||||
| else | ||||||||
| { | ||||||||
| Assert.False(cpp.StaMode); | ||||||||
| } | ||||||||
|
|
||||||||
| Assert.Equal(CommandLineParameterParser.NormalizeFilePath(commandLine[commandLine.Length - 1]), cpp.File); | ||||||||
| Assert.Null(cpp.ErrorMessage); | ||||||||
| } | ||||||||
|
|
||||||||
Uh oh!
There was an error while loading. Please reload this page.