@@ -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
@@ -235,14 +232,15 @@ public ApartmentState GetApartmentState()
235
232
return _initialApartmentState ;
236
233
}
237
234
238
- switch ( GetCurrentApartmentType ( ) )
235
+ switch ( GetCurrentApartmentState ( ) )
239
236
{
240
- case ApartmentType . STA :
237
+ case ApartmentState . STA :
241
238
return ApartmentState . STA ;
242
- case ApartmentType . MTA :
239
+ case ApartmentState . MTA :
243
240
return ApartmentState . MTA ;
244
241
default :
245
- return ApartmentState . Unknown ;
242
+ // If COM is uninitialized on the current thread, it is assumed to be implicit MTA.
243
+ return ApartmentState . MTA ;
246
244
}
247
245
}
248
246
@@ -275,14 +273,29 @@ private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
275
273
}
276
274
else
277
275
{
276
+ // Compat: Setting ApartmentState to Unknown uninitializes COM
278
277
UninitializeCom ( ) ;
279
278
}
280
- }
281
279
282
- // Clear the cache and check whether new state matches the desired state
283
- t_apartmentType = ApartmentType . Unknown ;
280
+ // Clear the cache and check whether new state matches the desired state
281
+ t_comState &= ~ ( ComState . STA | ComState . MTA ) ;
284
282
285
- retState = GetApartmentState ( ) ;
283
+ retState = GetCurrentApartmentState ( ) ;
284
+ }
285
+ else
286
+ {
287
+ Debug . Assert ( ( t_comState & ComState . MTA ) != 0 ) ;
288
+ retState = ApartmentState . MTA ;
289
+ }
290
+ }
291
+
292
+ // Special case where we pass in Unknown and get back MTA.
293
+ // Once we CoUninitialize the thread, the OS will still
294
+ // report the thread as implicitly in the MTA if any
295
+ // other thread in the process is CoInitialized.
296
+ if ( ( state == ApartmentState . Unknown ) && ( retState == ApartmentState . MTA ) )
297
+ {
298
+ return true ;
286
299
}
287
300
288
301
if ( retState != state )
@@ -316,7 +329,7 @@ private static void InitializeComForThreadPoolThread()
316
329
// Process-wide COM is initialized very early before any managed code can run.
317
330
// Assume it is done.
318
331
// Prevent re-initialization of COM model on threadpool threads from the default one.
319
- t_comState |= ComState . Locked ;
332
+ t_comState |= ComState . Locked | ComState . MTA ;
320
333
}
321
334
322
335
private static void InitializeCom ( ApartmentState state = ApartmentState . MTA )
@@ -396,49 +409,53 @@ internal static Thread EnsureThreadPoolThreadInitialized()
396
409
public void Interrupt ( ) { throw new PlatformNotSupportedException ( ) ; }
397
410
398
411
internal static bool ReentrantWaitsEnabled =>
399
- GetCurrentApartmentType ( ) == ApartmentType . STA ;
412
+ GetCurrentApartmentState ( ) == ApartmentState . STA ;
400
413
401
- internal static ApartmentType GetCurrentApartmentType ( )
414
+ // Unlike the public API, this returns ApartmentState.Unknown when COM is uninitialized on the current thread
415
+ internal static ApartmentState GetCurrentApartmentState ( )
402
416
{
403
- ApartmentType currentThreadType = t_apartmentType ;
404
- if ( currentThreadType != ApartmentType . Unknown )
405
- return currentThreadType ;
417
+ if ( ( t_comState & ( ComState . MTA | ComState . STA ) ) != 0 )
418
+ return ( ( t_comState & ComState . STA ) != 0 ) ? ApartmentState . STA : ApartmentState . MTA ;
406
419
407
420
Interop . APTTYPE aptType ;
408
421
Interop . APTTYPEQUALIFIER aptTypeQualifier ;
409
422
int result = Interop . Ole32 . CoGetApartmentType ( out aptType , out aptTypeQualifier ) ;
410
423
411
- ApartmentType type = ApartmentType . Unknown ;
424
+ ApartmentState state = ApartmentState . Unknown ;
412
425
413
426
switch ( result )
414
427
{
415
428
case HResults . CO_E_NOTINITIALIZED :
416
- type = ApartmentType . None ;
429
+ Debug . Fail ( "COM is not initialized" ) ;
430
+ state = ApartmentState . Unknown ;
417
431
break ;
418
432
419
433
case HResults . S_OK :
420
434
switch ( aptType )
421
435
{
422
436
case Interop . APTTYPE . APTTYPE_STA :
423
437
case Interop . APTTYPE . APTTYPE_MAINSTA :
424
- type = ApartmentType . STA ;
438
+ state = ApartmentState . STA ;
425
439
break ;
426
440
427
441
case Interop . APTTYPE . APTTYPE_MTA :
428
- type = ApartmentType . MTA ;
442
+ state = ApartmentState . MTA ;
429
443
break ;
430
444
431
445
case Interop . APTTYPE . APTTYPE_NA :
432
446
switch ( aptTypeQualifier )
433
447
{
434
448
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_MTA :
449
+ state = ApartmentState . MTA ;
450
+ break ;
451
+
435
452
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA :
436
- type = ApartmentType . MTA ;
453
+ state = ApartmentState . Unknown ;
437
454
break ;
438
455
439
456
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_STA :
440
457
case Interop . APTTYPEQUALIFIER . APTTYPEQUALIFIER_NA_ON_MAINSTA :
441
- type = ApartmentType . STA ;
458
+ state = ApartmentState . STA ;
442
459
break ;
443
460
444
461
default :
@@ -454,24 +471,18 @@ internal static ApartmentType GetCurrentApartmentType()
454
471
break ;
455
472
}
456
473
457
- if ( type != ApartmentType . Unknown )
458
- t_apartmentType = type ;
459
- return type ;
460
- }
461
-
462
- internal enum ApartmentType : byte
463
- {
464
- Unknown = 0 ,
465
- None ,
466
- STA ,
467
- MTA
474
+ if ( state != ApartmentState . Unknown )
475
+ t_comState |= ( state == ApartmentState . STA ) ? ComState . STA : ComState . MTA ;
476
+ return state ;
468
477
}
469
478
470
479
[ Flags ]
471
480
internal enum ComState : byte
472
481
{
473
482
InitializedByUs = 1 ,
474
483
Locked = 2 ,
484
+ MTA = 4 ,
485
+ STA = 8
475
486
}
476
487
}
477
488
}
0 commit comments