@@ -14,9 +14,6 @@ namespace System.Threading
14
14
{
15
15
public sealed partial class Thread
16
16
{
17
- [ ThreadStatic ]
18
- private static ApartmentType t_apartmentType ;
19
-
20
17
[ ThreadStatic ]
21
18
private static ComState t_comState ;
22
19
@@ -334,14 +331,15 @@ public ApartmentState GetApartmentState()
334
331
return _initialApartmentState ;
335
332
}
336
333
337
- switch ( GetCurrentApartmentType ( ) )
334
+ switch ( GetCurrentApartmentState ( ) )
338
335
{
339
- case ApartmentType . STA :
336
+ case ApartmentState . STA :
340
337
return ApartmentState . STA ;
341
- case ApartmentType . MTA :
338
+ case ApartmentState . MTA :
342
339
return ApartmentState . MTA ;
343
340
default :
344
- return ApartmentState . Unknown ;
341
+ // If COM is uninitialized on the current thread, it is assumed to be implicit MTA.
342
+ return ApartmentState . MTA ;
345
343
}
346
344
}
347
345
@@ -374,14 +372,29 @@ private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
374
372
}
375
373
else
376
374
{
375
+ // Compat: Setting ApartmentState to Unknown uninitializes COM
377
376
UninitializeCom ( ) ;
378
377
}
379
- }
380
378
381
- // Clear the cache and check whether new state matches the desired state
382
- t_apartmentType = ApartmentType . Unknown ;
379
+ // Clear the cache and check whether new state matches the desired state
380
+ t_comState &= ~ ( ComState . STA | ComState . MTA ) ;
383
381
384
- retState = GetApartmentState ( ) ;
382
+ retState = GetCurrentApartmentState ( ) ;
383
+ }
384
+ else
385
+ {
386
+ Debug . Assert ( ( t_comState & ComState . MTA ) != 0 ) ;
387
+ retState = ApartmentState . MTA ;
388
+ }
389
+ }
390
+
391
+ // Special case where we pass in Unknown and get back MTA.
392
+ // Once we CoUninitialize the thread, the OS will still
393
+ // report the thread as implicitly in the MTA if any
394
+ // other thread in the process is CoInitialized.
395
+ if ( ( state == ApartmentState . Unknown ) && ( retState == ApartmentState . MTA ) )
396
+ {
397
+ return true ;
385
398
}
386
399
387
400
if ( retState != state )
@@ -415,7 +428,7 @@ private static void InitializeComForThreadPoolThread()
415
428
// Process-wide COM is initialized very early before any managed code can run.
416
429
// Assume it is done.
417
430
// Prevent re-initialization of COM model on threadpool threads from the default one.
418
- t_comState |= ComState . Locked ;
431
+ t_comState |= ComState . Locked | ComState . MTA ;
419
432
}
420
433
421
434
private static void InitializeCom ( ApartmentState state = ApartmentState . MTA )
@@ -527,49 +540,53 @@ internal static void CheckForPendingInterrupt()
527
540
}
528
541
529
542
internal static bool ReentrantWaitsEnabled =>
530
- GetCurrentApartmentType ( ) == ApartmentType . STA ;
543
+ GetCurrentApartmentState ( ) == ApartmentState . STA ;
531
544
532
- internal static ApartmentType GetCurrentApartmentType ( )
545
+ // Unlike the public API, this returns ApartmentState.Unknown when COM is uninitialized on the current thread
546
+ internal static ApartmentState GetCurrentApartmentState ( )
533
547
{
534
- ApartmentType currentThreadType = t_apartmentType ;
535
- if ( currentThreadType != ApartmentType . Unknown )
536
- return currentThreadType ;
548
+ if ( ( t_comState & ( ComState . MTA | ComState . STA ) ) != 0 )
549
+ return ( ( t_comState & ComState . STA ) != 0 ) ? ApartmentState . STA : ApartmentState . MTA ;
537
550
538
551
Interop . APTTYPE aptType ;
539
552
Interop . APTTYPEQUALIFIER aptTypeQualifier ;
540
553
int result = Interop . Ole32 . CoGetApartmentType ( out aptType , out aptTypeQualifier ) ;
541
554
542
- ApartmentType type = ApartmentType . Unknown ;
555
+ ApartmentState state = ApartmentState . Unknown ;
543
556
544
557
switch ( result )
545
558
{
546
559
case HResults . CO_E_NOTINITIALIZED :
547
- type = ApartmentType . None ;
560
+ Debug . Fail ( "COM is not initialized" ) ;
561
+ state = ApartmentState . Unknown ;
548
562
break ;
549
563
550
564
case HResults . S_OK :
551
565
switch ( aptType )
552
566
{
553
567
case Interop . APTTYPE . APTTYPE_STA :
554
568
case Interop . APTTYPE . APTTYPE_MAINSTA :
555
- type = ApartmentType . STA ;
569
+ state = ApartmentState . STA ;
556
570
break ;
557
571
558
572
case Interop . APTTYPE . APTTYPE_MTA :
559
- type = ApartmentType . MTA ;
573
+ state = ApartmentState . MTA ;
560
574
break ;
561
575
562
576
case Interop . APTTYPE . APTTYPE_NA :
563
577
switch ( aptTypeQualifier )
564
578
{
565
579
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_MTA :
580
+ state = ApartmentState . MTA ;
581
+ break ;
582
+
566
583
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA :
567
- type = ApartmentType . MTA ;
584
+ state = ApartmentState . Unknown ;
568
585
break ;
569
586
570
587
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_STA :
571
588
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_MAINSTA :
572
- type = ApartmentType . STA ;
589
+ state = ApartmentState . STA ;
573
590
break ;
574
591
575
592
default :
@@ -585,24 +602,18 @@ internal static ApartmentType GetCurrentApartmentType()
585
602
break ;
586
603
}
587
604
588
- if ( type != ApartmentType . Unknown )
589
- t_apartmentType = type ;
590
- return type ;
591
- }
592
-
593
- internal enum ApartmentType : byte
594
- {
595
- Unknown = 0 ,
596
- None ,
597
- STA ,
598
- MTA
605
+ if ( state != ApartmentState . Unknown )
606
+ t_comState |= ( state == ApartmentState . STA ) ? ComState . STA : ComState . MTA ;
607
+ return state ;
599
608
}
600
609
601
610
[ Flags ]
602
611
internal enum ComState : byte
603
612
{
604
613
InitializedByUs = 1 ,
605
614
Locked = 2 ,
615
+ MTA = 4 ,
616
+ STA = 8
606
617
}
607
618
}
608
619
}
0 commit comments