struct OBJECT_CONTEXT : IObjectContextInfo,
IContextState,
IObjectContext, ...
{
// context properties
GUID id; // ID of this context
ACTIVITY *pActivity;
APARTMENT *pApt;
bool bJITAEnabled;
bool bDone;
long nCallsInProgress;
IUnknown *pPrimaryObject;
TX_STREAM *pTxStm;
bool bRootOfStream;
bool bHappy;
// interface methods deleted for clarity
};
Figure 4 TotallyCompatible
bool TotallyCompatible(ATTRIBUTES *pTarget,
OBJECT_CONTEXT *pParent) {
// try to put non-configured components in parent
if (!pTarget->bConfiguredComponent)
return ApartmentCompatible(
pTarget->ThreadingModel,
pParent->pApt);
// JIT activation forces new context
if (pTarget->bJITAEnabled) return false;
// check for shared activity
switch (pTarget->Synchronization) {
case REQUIRES_NEW:
return false;
case REQUIRED: // needs one
if (pParent->pActivity == NULL)
return false;
break;
case NOT_SUPPORTED: // can't have one
if (pParent->pActivity != NULL)
return false;
break;
}
// remaining comparisons deleted for clarity
}
Figure 5 ComplexCreate
HRESULT ComplexCreate(REFCLSID rclsid,
ATTRIBUTES *pTarget,
OBJECT_CONTEXT *pParent,
REFIID riid,
void **ppv) {
// find/create target context
OBJECT_CONTEXT *pChild
= FindContext(pTarget, pParent);
// check to see if this thread can enter target
if (!ThisThreadCanEnterCtx(pChild))
return EvenMoreComplexCreate(...);
// create new interceptor
IYourInterface *pNew = new Interceptor();
// associate child context with interceptor
pNew->pOC = pChild;
// switch context and create
tls_pCurCtx = pChild;
SimpleCreate(rclsid, ..., &pNew->pRealObj);
// set "primary object" of context for JIT activation
if (pTarget->bJITAEnabled)
pChild->pPrimaryObject = pNew;
// switch back and return interceptor
tls_pCurCtx = pParent;
return pNew->QueryInterface(riid, ppv);
}
Figure 6 PropagateActivity
void PropagateActivity(pParent, pChild,
pTarget){
switch (pTarget->Synchronization) {
case DISABLED: // don't need one
case NOT_SUPPORTED: // can't have one
pChild->pActivity = NULL;
break;
case SUPPORTED: // always share
pChild->pActivity = pParent->pActivity;
break;
case REQUIRED: // needs one but can share
if (pParent->pActivity) {
pChild->pActivity = pParent->pActivity;
break;
} // else fall through to REQUIRES_NEW
case REQUIRES_NEW: // needs new one
pChild->pActivity = new ACTIVITY();
break;
}
// activities are refcounted so AddRef
if (pChild->pActivity)
pChild->pActivity->AddRef();
}
Figure 7 PropagateTxStream
void PropagateTxStream(pParent, pChild,
pTarget){
// default to non-root and happy
pChild->bRootOfStream = false;
pChild->bHappy = true;
// propagate tx_stream if possible
switch (pTarget->Transaction) {
case IGNORED: // don't need one
case NOT_SUPPORTED: // can't have one
pChild->pTxStream = NULL;
break;
case SUPPORTED: // always share
pChild->pTxStream = pParent->pTxStream;
break;
case REQUIRED: // needs one but can share
if (pParent->pTxStream) {
pChild->pTxStream = pParent->pTxStream;
break;
} // else fall through to REQUIRES_NEW
case REQUIRES_NEW: // must be root of new one
pChild->pTxStream = new TX_STREAM();
pChild->bRootOfStream = true;
break;
}
// tx streams are refcounted so AddRef
if (pChild->pTxStream)
pChild->pTxStream->AddRef();
}
Figure 8 PropagateApartment
void PropagateApartment(pParent, pChild,
pTarget){
switch (pTarget->ThreadingModel) {
case BOTH: // always blindly share
pChild->pApt = pParent->pApt;
break;
case FREE: // always blindly use MTA
pChild->pApt = GetDistinguishedApt(MTA);
break;
case NEUTRAL: // always blindly use TNA
pChild->pApt = GetDistinguishedApt(TNA);
break;
case ABSENT: // always blindly use main apt
pChild->pApt = GetDistinguishedApt(MAIN);
break;
case APARTMENT:
// grab home apt of thread (set at CoInit time)
APARTMENT *pHome = GetHomeAptOfThread();
if (pHome->apt_type == MTA)
pChild->pApt = GetDistinguishedApt(HOST);
else // STA or MAIN
pChild->pApt = pHome;
}
// apartments are refcounted so AddRef
if (pChild->pApt)
pChild->pApt->AddRef();
}
Figure 9 GetDistinguishedApt
// four references to processwide globals
APARTMENT *g_pMTA = 0;
APARTMENT *g_pTNA = 0;
APARTMENT *g_pMain = 0;
APARTMENT *g_pHost = 0;
APARTMENT *GetDistinguishedApt(APT_TYPE type) {
switch (type) {
case MTA:
if (g_pMTA == 0) // create first time
g_pMTA = new APARTMENT(MTA);
return g_pMTA;
case TNA:
if (g_pTNA == 0) // create first time
g_pTNA = new APARTMENT(TNA);
return g_pTNA;
case HOST:
if (g_pHost == 0) {
// spawn host thread
CreateThread(HostThreadProc, &g_pHost);
// set main to host if no main yet
if (g_pMain == 0)
g_pMain = g_pHost;
}
return g_pHost;
case MAIN:
if (g_pMain == 0) // create host if no main
return GetDistinguishedApt(HOST);
else
return g_pMain;
}
}
Figure 10 CoInitializeEx
HRESULT CoInitializeEx(void *, DWORD dwFlags) {
if (dwFlags == COINIT_MULTITHREADED) {
if (tls_pHomeApt == 0) {// 1st call for thread
tls_pHomeApt = GetDistinguishedApt(MTA);
return S_OK;
}
else if (tls_pHomeApt->apt_type != MTA)
return RPC_E_CHANGED_MODE;
else
return S_FALSE;
}
else if (dwFlags == COINIT_APARTMENTTHEADED){
if (tls_pHomeApt == 0) {// 1st call for thread
// become main if we're the first
if (g_pMain == 0) {
tls_pHomeApt = new APARTMENT(MAIN);
g_pMain = tls_pHomeApt;
}
else
tls_pHomeApt = new APARTMENT(STA);
return S_OK;
}
else if (tls_pHomeApt->apt_type == MTA)
return RPC_E_CHANGED_MODE;
else
return S_FALSE;
}
else return E_INVALIDARG;
}