CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ExposeExceptionsInCOM, W("ExposeExceptionsInCOM"), "")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ComInsteadOfManagedRemoting, W("PreferComInsteadOfManagedRemoting"), 0, "When communicating with a cross app domain CCW, use COM instead of managed remoting.")
CONFIG_DWORD_INFO(INTERNAL_GenerateStubForHost, W("GenerateStubForHost"), 0, "Forces the host hook stub to be built for all unmanaged calls, even when not running hosted.")
+RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_legacyApartmentInitPolicy, W("legacyApartmentInitPolicy"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_legacyComHierarchyVisibility, W("legacyComHierarchyVisibility"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_legacyComVTableLayout, W("legacyComVTableLayout"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_newComVTableLayout, W("newComVTableLayout"), "")
return Thread::AS_Unknown;
}
-void SystemDomain::SetThreadAptState (Thread::ApartmentState state)
+void SystemDomain::SetThreadAptState (IMDInternalImport* pScope, Thread::ApartmentState state)
{
STANDARD_VM_CONTRACT;
+ BOOL fIsLegacy = FALSE;
+
+ // Check for legacy behavior regarding COM Apartment state of the main thread.
+
+#define METAMODEL_MAJOR_VER_WITH_NEW_BEHAVIOR 2
+#define METAMODEL_MINOR_VER_WITH_NEW_BEHAVIOR 0
+
+ LPCSTR pVer;
+ IfFailThrow(pScope->GetVersionString(&pVer));
+
+ // Does this look like a version?
+ if (pVer != NULL)
+ {
+ // Is it 'vN.' where N is a digit?
+ if ((pVer[0] == 'v' || pVer[0] == 'V') &&
+ IS_DIGIT(pVer[1]) &&
+ (pVer[2] == '.') )
+ {
+ // Looks like a version. Is it lesser than v2.0 major version where we start using new behavior?
+ fIsLegacy = DIGIT_TO_INT(pVer[1]) < METAMODEL_MAJOR_VER_WITH_NEW_BEHAVIOR;
+ }
+ }
+
+ if (!fIsLegacy && g_pConfig != NULL)
+ {
+ fIsLegacy = g_pConfig->LegacyApartmentInitPolicy();
+ }
+
+
Thread* pThread = GetThread();
_ASSERTE(pThread);
Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InSTA, TRUE);
_ASSERTE(pState == Thread::AS_InSTA);
}
- else if (state == Thread::AS_InMTA)
+ else if ((state == Thread::AS_InMTA) || (!fIsLegacy))
{
+ // If either MTAThreadAttribute is specified or (if no attribute is specified and we are not
+ // running in legacy mode), then
+ // we will set the apartment state to MTA. The reason for this is to ensure the apartment
+ // state is consistent and reliably set. Without this, the apartment state for the main
+ // thread would be undefined and would actually be dependent on if the assembly was
+ // ngen'd, which other type were loaded, etc.
Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InMTA, TRUE);
_ASSERTE(pState == Thread::AS_InMTA);
}
#if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
static Thread::ApartmentState GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod);
- static void SetThreadAptState(Thread::ApartmentState state);
+ static void SetThreadAptState(IMDInternalImport* pScope, Thread::ApartmentState state);
#endif
static BOOL SetGlobalSharePolicyUsingAttribute(IMDInternalImport* pScope, mdMethodDef mdMethod);
GCX_COOP();
pMeth = GetEntryPoint();
-
if (pMeth) {
- {
-#ifdef FEATURE_COMINTEROP
- GCX_PREEMP();
-
- Thread::ApartmentState state = Thread::AS_Unknown;
- state = SystemDomain::GetEntryPointThreadAptState(pMeth->GetMDImport(), pMeth->GetMemberDef());
-
- // If the entry point has an explicit thread apartment state, set it
- // before running the AppDomainManager initialization code.
- if (state == Thread::AS_InSTA || state == Thread::AS_InMTA)
- SystemDomain::SetThreadAptState(state);
-#endif // FEATURE_COMINTEROP
- }
-
RunMainPre();
// Assert that the thread hasn't been started yet.
_ASSERTE(Thread::TS_Unstarted & thread->GetSnapshotState());
- Thread::ApartmentState as = thread->GetExplicitApartment();
- if (as == Thread::AS_Unknown)
+ if ((g_pConfig != NULL) && !g_pConfig->LegacyApartmentInitPolicy())
{
- thread->SetApartment(Thread::AS_InMTA, TRUE);
+ Thread::ApartmentState as = thread->GetExplicitApartment();
+ if (as == Thread::AS_Unknown)
+ {
+ thread->SetApartment(Thread::AS_InMTA, TRUE);
+ }
}
HELPER_METHOD_FRAME_END();
fLegacyNullReferenceExceptionPolicy = false;
fLegacyUnhandledExceptionPolicy = false;
+ fLegacyApartmentInitPolicy = false;
fLegacyComHierarchyVisibility = false;
fLegacyComVTableLayout = false;
fNewComVTableLayout = false;
bool LegacyNullReferenceExceptionPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyNullReferenceExceptionPolicy; }
bool LegacyUnhandledExceptionPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyUnhandledExceptionPolicy; }
+ bool LegacyApartmentInitPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyApartmentInitPolicy; }
bool LegacyComHierarchyVisibility(void) const {LIMITED_METHOD_CONTRACT; return fLegacyComHierarchyVisibility; }
bool LegacyComVTableLayout(void) const {LIMITED_METHOD_CONTRACT; return fLegacyComVTableLayout; }
bool NewComVTableLayout(void) const {LIMITED_METHOD_CONTRACT; return fNewComVTableLayout; }
bool fLegacyCorruptedStateExceptionsPolicy;
#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ bool fLegacyApartmentInitPolicy; // Old nondeterministic COM apartment initialization switch
bool fLegacyComHierarchyVisibility; // Old behavior allowing QIs for classes with invisible parents
bool fLegacyComVTableLayout; // Old behavior passing out IClassX interface for IUnknown and IDispatch.
bool fNewComVTableLayout; // New behavior passing out Basic interface for IUnknown and IDispatch.