diff options
Diffstat (limited to 'src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs')
-rw-r--r-- | src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs | 138 |
1 files changed, 119 insertions, 19 deletions
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs index 6d0e937dc..e9fe5485b 100644 --- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs +++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs @@ -21,8 +21,13 @@ namespace Internal.Runtime.Augments [ThreadStatic] private static ApartmentType t_apartmentType; + [ThreadStatic] + private static bool t_comInitializedByUs; + private SafeWaitHandle _osHandle; + private ApartmentState _initialAppartmentState = ApartmentState.Unknown; + /// <summary> /// Used by <see cref="WaitHandle"/>'s multi-wait functions /// </summary> @@ -99,7 +104,7 @@ namespace Internal.Runtime.Augments // Throw an ApplicationException for compatibility with CoreCLR. First save the error code. int errorCode = Marshal.GetLastWin32Error(); var ex = new ApplicationException(); - ex.SetErrorCode(errorCode); + ex.HResult = errorCode; throw ex; } @@ -283,10 +288,103 @@ namespace Internal.Runtime.Augments return 0; } - public ApartmentState GetApartmentState() { throw null; } - public bool TrySetApartmentState(ApartmentState state) { throw null; } - public void DisableComObjectEagerCleanup() { throw null; } - public void Interrupt() { throw null; } + public ApartmentState GetApartmentState() + { + if (this != CurrentThread) + { + if (HasStarted()) + throw new ThreadStateException(); + return _initialAppartmentState; + } + + switch (GetCurrentApartmentType()) + { + case ApartmentType.STA: + return ApartmentState.STA; + case ApartmentType.MTA: + return ApartmentState.MTA; + default: + return ApartmentState.Unknown; + } + } + + public bool TrySetApartmentState(ApartmentState state) + { + if (this != CurrentThread) + { + using (LockHolder.Hold(_lock)) + { + if (HasStarted()) + throw new ThreadStateException(); + _initialAppartmentState = state; + return true; + } + } + + if (state != ApartmentState.Unknown) + { + InitializeCom(state); + } + else + { + UninitializeCom(); + } + + // Clear the cache and check whether new state matches the desired state + t_apartmentType = ApartmentType.Unknown; + return state == GetApartmentState(); + } + + private void InitializeComOnNewThread() + { + InitializeCom(_initialAppartmentState); + } + + internal static void InitializeCom(ApartmentState state = ApartmentState.MTA) + { + if (t_comInitializedByUs) + return; + +#if ENABLE_WINRT + int hr = Interop.WinRT.RoInitialize( + (state == ApartmentState.STA) ? Interop.WinRT.RO_INIT_SINGLETHREADED + : Interop.WinRT.RO_INIT_MULTITHREADED); +#else + int hr = Interop.Ole32.CoInitializeEx(IntPtr.Zero, + (state == ApartmentState.STA) ? Interop.Ole32.COINIT_APARTMENTTHREADED + : Interop.Ole32.COINIT_MULTITHREADED); +#endif + // RPC_E_CHANGED_MODE indicates this thread has been already initialized with a different + // concurrency model. We stay away and let whoever else initialized the COM to be in control. + if (hr == HResults.RPC_E_CHANGED_MODE) + return; + if (hr < 0) + throw new OutOfMemoryException(); + + t_comInitializedByUs = true; + + // If the thread has already been CoInitialized to the proper mode, then + // we don't want to leave an outstanding CoInit so we CoUninit. + if (hr > 0) + UninitializeCom(); + } + + private static void UninitializeCom() + { + if (!t_comInitializedByUs) + return; + +#if ENABLE_WINRT + Interop.WinRT.RoUninitialize(); +#else + Interop.Ole32.CoUninitialize(); +#endif + t_comInitializedByUs = false; + } + + // TODO: https://github.com/dotnet/corefx/issues/20766 + public void DisableComObjectEagerCleanup() { } + public void Interrupt() { throw new PlatformNotSupportedException(); } internal static void UninterruptibleSleep0() { @@ -324,40 +422,40 @@ namespace Internal.Runtime.Augments if (currentThreadType != ApartmentType.Unknown) return currentThreadType; - Interop._APTTYPE aptType; - Interop._APTTYPEQUALIFIER aptTypeQualifier; - int result = Interop.mincore.CoGetApartmentType(out aptType, out aptTypeQualifier); + Interop.APTTYPE aptType; + Interop.APTTYPEQUALIFIER aptTypeQualifier; + int result = Interop.Ole32.CoGetApartmentType(out aptType, out aptTypeQualifier); ApartmentType type = ApartmentType.Unknown; - switch ((Interop.Constants)result) + switch (result) { - case Interop.Constants.CoENotInitialized: + case HResults.CO_E_NOTINITIALIZED: type = ApartmentType.None; break; - case Interop.Constants.SOk: + case HResults.S_OK: switch (aptType) { - case Interop._APTTYPE.APTTYPE_STA: - case Interop._APTTYPE.APTTYPE_MAINSTA: + case Interop.APTTYPE.APTTYPE_STA: + case Interop.APTTYPE.APTTYPE_MAINSTA: type = ApartmentType.STA; break; - case Interop._APTTYPE.APTTYPE_MTA: + case Interop.APTTYPE.APTTYPE_MTA: type = ApartmentType.MTA; break; - case Interop._APTTYPE.APTTYPE_NA: + case Interop.APTTYPE.APTTYPE_NA: switch (aptTypeQualifier) { - case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MTA: - case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA: + case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MTA: + case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA: type = ApartmentType.MTA; break; - case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_STA: - case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MAINSTA: + case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_STA: + case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MAINSTA: type = ApartmentType.STA; break; @@ -386,5 +484,7 @@ namespace Internal.Runtime.Augments STA, MTA } + + private static int ComputeCurrentProcessorId() => (int)Interop.mincore.GetCurrentProcessorNumber(); } } |