|
|
/*===================================================================
Microsoft Denali
Microsoft Confidential. Copyright 1997 Microsoft Corporation. All Rights Reserved.
Component: Viper Integration Objects
File: viperint.cpp
Owner: DmitryR
This file contains the implementation of viper integration classes ===================================================================*/
#include "denpre.h"
#pragma hdrstop
#include "Context.h"
#include "package.h"
#include "memchk.h"
extern HDESK ghDesktop;
//
// COM holds the last reference to a CViperAsyncRequest
// we need to track these objects to ensure that we don't
// exit before the activity threads have released them.
//
volatile LONG g_nViperRequests = 0;
/*===================================================================
C V i p e r A s y n c R e q u e s t ===================================================================*/
/*===================================================================
CViperAsyncRequest::CViperAsyncRequest
CViperAsyncRequest constructor
Parameters:
Returns: ===================================================================*/ CViperAsyncRequest::CViperAsyncRequest() : m_cRefs(1), m_pHitObj(NULL), m_hrOnError(S_OK), m_pActivity(NULL), m_dwRepostAttempts(0) { InterlockedIncrement( (LONG *)&g_nViperRequests ); }
/*===================================================================
CViperAsyncRequest::~CViperAsyncRequest
CViperAsyncRequest destructor
Parameters:
Returns: ===================================================================*/ CViperAsyncRequest::~CViperAsyncRequest() { InterlockedDecrement( (LONG *)&g_nViperRequests ); }
/*===================================================================
CViperAsyncRequest::Init
Initialize CViperAsyncRequest with CHitObj object
Parameters: CHitObj *pHitObj Denali HitObj
Returns: HRESULT ===================================================================*/ HRESULT CViperAsyncRequest::Init ( CHitObj *pHitObj, IServiceActivity *pActivity ) { Assert(m_pHitObj == NULL);
m_pHitObj = pHitObj; m_pActivity = pActivity;
return S_OK; }
#ifdef DBG
/*===================================================================
CViperAsyncRequest::AssertValid
Test to make sure that this is currently correctly formed and assert if it is not.
Returns: ===================================================================*/ void CViperAsyncRequest::AssertValid() const { Assert(m_pHitObj); Assert(m_cRefs > 0); } #endif
/*===================================================================
CViperAsyncRequest::QueryInterface
Standard IUnknown method
Parameters: REFIID iid void **ppv
Returns: HRESULT ===================================================================*/ STDMETHODIMP CViperAsyncRequest::QueryInterface ( REFIID iid, void **ppv ) { if (iid == IID_IUnknown || iid == IID_IServiceCall) { *ppv = this; AddRef(); return S_OK; }
return E_NOINTERFACE; }
/*===================================================================
CViperAsyncRequest::AddRef
Standard IUnknown method
Parameters:
Returns: Ref count ===================================================================*/ STDMETHODIMP_(ULONG) CViperAsyncRequest::AddRef() { return ++m_cRefs; }
/*===================================================================
CViperAsyncRequest::Release
Standard IUnknown method
Parameters:
Returns: Ref count ===================================================================*/ STDMETHODIMP_(ULONG) CViperAsyncRequest::Release() { if (--m_cRefs != 0) return m_cRefs;
delete this; return 0; } /*===================================================================
CViperAsyncRequest::OnCall
IMTSCall method implementation. This method is called by Viper from the right thread when it's time to process a request
Parameters:
Returns: HRESULT ===================================================================*/ STDMETHODIMP CViperAsyncRequest::OnCall() { Assert(m_pHitObj); CIsapiReqInfo *pIReq = m_pHitObj->PIReq();
BOOL fRequestReposted = FALSE;
// add an extra addref here to prevent the deletion of the
// hitobj deleting the CIsapiReqInfo for this request.
if (pIReq) pIReq->AddRef();
// Bracket ViperAsyncCallback
if (SUCCEEDED(StartISAThreadBracket(pIReq))) {
m_pHitObj->ViperAsyncCallback(&fRequestReposted);
// Make sure there always is DONE_WITH_SESSION
if (m_pHitObj->FIsBrowserRequest() && !fRequestReposted) { if (!m_pHitObj->FDoneWithSession()) m_pHitObj->ReportServerError(IDE_UNEXPECTED); }
if (!fRequestReposted) delete m_pHitObj; // don't delete if reposted
EndISAThreadBracket(pIReq); } else { // DONE_WITH_SESSION -- ServerSupportFunction
// does not need bracketing
if (m_pHitObj->FIsBrowserRequest()) m_pHitObj->ReportServerError(0);
// We never called to process request, there should
// be no state and it's probably save to delete it
// outside of bracketing
delete m_pHitObj; }
m_pHitObj = NULL; // set to NULL even if not deleted
Release(); // release this, Viper holds another ref
if (pIReq) pIReq->Release();
return S_OK; }
/*===================================================================
CViperAsyncRequest::OnError
Called by COM+ when it is unable to dispatch the request properly on the configured thread
Parameters:
Returns: HRESULT ===================================================================*/ STDMETHODIMP CViperAsyncRequest::OnError(HRESULT hrViperError) { Assert(m_pHitObj); CIsapiReqInfo *pIReq = m_pHitObj->PIReq(); HRESULT hr = S_OK;
if (pIReq) pIReq->AddRef();
m_dwRepostAttempts++;
// attempt to repost the request if it hasn't errored out three
// times yet.
if (m_dwRepostAttempts <= 3) {
hr = m_pActivity->AsynchronousCall(this);
Assert(SUCCEEDED(hr)); }
// if it has errored out three times or the repost failed,
// pitch the request
if (FAILED(hr) || (m_dwRepostAttempts > 3)) {
// DONE_WITH_SESSION -- ServerSupportFunction
// does not need bracketing
if (m_pHitObj->FIsBrowserRequest()) m_pHitObj->ReportServerError(IDE_UNEXPECTED);
// We never called to process request, there should
// be no state and it's probably save to delete it
// outside of bracketing
delete m_pHitObj;
m_pHitObj = NULL; // set to NULL even if not deleted
Release(); // release this, Viper holds another ref
}
if (pIReq) pIReq->Release();
return S_OK; }
/*===================================================================
C V i p e r A c t i v i t y ===================================================================*/
/*===================================================================
CViperActivity::CViperActivity
CViperActivity constructor
Parameters:
Returns: ===================================================================*/ CViperActivity::CViperActivity() : m_pActivity(NULL), m_cBind(0) { }
/*===================================================================
CViperActivity::~CViperActivity
CViperActivity destructor
Parameters:
Returns: ===================================================================*/ CViperActivity::~CViperActivity() { UnInit(); }
/*===================================================================
CViperActivity::Init
Create actual Viper activity using MTSCreateActivity()
Parameters:
Returns: HRESULT ===================================================================*/ HRESULT CViperActivity::Init(IUnknown *pServicesConfig) { Assert(!FInited());
HRESULT hr = S_OK;
hr = CoCreateActivity(pServicesConfig, IID_IServiceActivity, (void **)&m_pActivity);
if (FAILED(hr)) return hr;
m_cBind = 1; return S_OK; }
/*===================================================================
CViperActivity::InitClone
Clone Viper activity (AddRef() it)
Parameters: CViperActivity *pActivity activity to clone from
Returns: HRESULT ===================================================================*/ HRESULT CViperActivity::InitClone ( CViperActivity *pActivity ) { Assert(!FInited()); Assert(pActivity); pActivity->AssertValid();
m_pActivity = pActivity->m_pActivity; m_pActivity->AddRef();
m_cBind = 1; return S_OK; }
/*===================================================================
CViperActivity::UnInit
Release Viper activity
Parameters:
Returns: HRESULT ===================================================================*/ HRESULT CViperActivity::UnInit() { if (m_pActivity) { while (m_cBind > 1) // 1 is for inited flag
{ m_pActivity->UnbindFromThread(); m_cBind--; } m_pActivity->Release(); m_pActivity = NULL; }
m_cBind = 0; return S_OK; }
/*===================================================================
CViperActivity::BindToThread
Bind Activity to current thread using IMTSActivity method
Parameters:
Returns: HRESULT ===================================================================*/ HRESULT CViperActivity::BindToThread() { Assert(FInited()); m_pActivity->BindToCurrentThread(); m_cBind++; return S_OK; } /*===================================================================
CViperActivity::UnBindFromThread
UnBind Activity from using IMTSActivity method
Parameters:
Returns: HRESULT ===================================================================*/ HRESULT CViperActivity::UnBindFromThread() { Assert(FInited()); Assert(m_cBind > 1);
m_pActivity->UnbindFromThread(); m_cBind--;
return S_OK; } /*===================================================================
CViperActivity::PostAsyncRequest
Call HitObj Async. Creates IMTSCCall object to do it.
Parameters: CHitObj *pHitObj Denali's HitObj
Returns: HRESULT ===================================================================*/ HRESULT CViperActivity::PostAsyncRequest ( CHitObj *pHitObj ) { AssertValid();
HRESULT hr = S_OK;
CViperAsyncRequest *pViperCall = new CViperAsyncRequest; if (!pViperCall) hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr)) hr = pViperCall->Init(pHitObj, m_pActivity);
RevertToSelf();
if (SUCCEEDED(hr)) hr = m_pActivity->AsynchronousCall(pViperCall);
if (FAILED(hr) && pViperCall) // cleanup if failed
pViperCall->Release(); return hr; }
/*===================================================================
CViperActivity::PostGlobalAsyncRequest
Static method. Post async request without an activity. Creates temporary activity
Parameters: CHitObj *pHitObj Denali's HitObj
Returns: HRESULT ===================================================================*/ HRESULT CViperActivity::PostGlobalAsyncRequest ( CHitObj *pHitObj ) { HRESULT hr = S_OK; CViperActivity *pTmpActivity = new CViperActivity; if (!pTmpActivity) hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr)) hr = pTmpActivity->Init(pHitObj->PAppln()->PServicesConfig());
if (SUCCEEDED(hr)) { // remember this activity as HitObj's activity
// HitObj will get rid of it on its destructor
pHitObj->SetActivity(pTmpActivity);
hr = pTmpActivity->PostAsyncRequest(pHitObj); pTmpActivity = NULL; // don't delete, HitObj will
}
if (pTmpActivity) delete pTmpActivity;
return hr; }
#ifdef DBG
/*===================================================================
CViperAsyncRequest::AssertValid
Test to make sure that this is currently correctly formed and assert if it is not.
Returns: ===================================================================*/ void CViperActivity::AssertValid() const { Assert(FInited()); Assert(m_pActivity); } #endif
#ifdef UNUSED
/*===================================================================
C V i p e r T h r e a d E v e n t s ===================================================================*/
/*===================================================================
CViperThreadEvents::CViperThreadEvents
CViperThreadEvents constructor
Parameters:
Returns: ===================================================================*/ CViperThreadEvents::CViperThreadEvents() : m_cRefs(1) { }
#ifdef DBG
/*===================================================================
CViperThreadEvents::AssertValid
Test to make sure that this is currently correctly formed and assert if it is not.
Returns: ===================================================================*/ void CViperThreadEvents::AssertValid() const { Assert(m_cRefs > 0); Assert(ghDesktop != NULL); } #endif
/*===================================================================
CViperThreadEvents::QueryInterface
Standard IUnknown method
Parameters: REFIID iid void **ppv
Returns: HRESULT ===================================================================*/ STDMETHODIMP CViperThreadEvents::QueryInterface ( REFIID iid, void **ppv ) { if (iid == IID_IUnknown || iid == IID_IThreadEvents) { *ppv = this; AddRef(); return S_OK; }
return E_NOINTERFACE; }
/*===================================================================
CViperThreadEvents::AddRef
Standard IUnknown method
Parameters:
Returns: Ref count ===================================================================*/ STDMETHODIMP_(ULONG) CViperThreadEvents::AddRef() { DWORD cRefs = InterlockedIncrement((LPLONG)&m_cRefs); return cRefs; }
/*===================================================================
CViperThreadEvents::Release
Standard IUnknown method
Parameters:
Returns: Ref count ===================================================================*/ STDMETHODIMP_(ULONG) CViperThreadEvents::Release() { DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs); if (cRefs) return cRefs;
delete this; return 0; } /*===================================================================
CViperThreadEvents::OnStartup
IThreadEvents method implementation. This method is called by Viper whenever they start up a thread.
Parameters: None
Returns: HRESULT ===================================================================*/ STDMETHODIMP CViperThreadEvents::OnStartup() { HRESULT hr; AssertValid();
// Set the desktop for this thread
hr = SetDesktop(); return hr; }
/*===================================================================
CViperThreadEvents::OnShutdown
IThreadEvents method implementation. This method is called by Viper whenever they shut down a thread.
Parameters: None Returns: HRESULT ===================================================================*/ STDMETHODIMP CViperThreadEvents::OnShutdown() { AssertValid();
return S_OK; } #endif //UNUSED
/*===================================================================
G l o b a l F u n c t i o n s ===================================================================*/
/*===================================================================
ViperSetContextProperty
Static utility function.
Set Viper context property by BSTR and IDispatch*. The real interface takes BSTR and VARIANT.
Parameters IContextProperties *pContextProperties Context BSTR bstrPropertyName Name IDispatch *pdispPropertyValue Value
Returns: HRESULT ===================================================================*/ static HRESULT ViperSetContextProperty ( IContextProperties *pContextProperties, BSTR bstrPropertyName, IDispatch *pdispPropertyValue ) { // Make VARIANT from IDispatch*
pdispPropertyValue->AddRef();
VARIANT Variant; VariantInit(&Variant); V_VT(&Variant) = VT_DISPATCH; V_DISPATCH(&Variant) = pdispPropertyValue;
// Call Viper to set the property
HRESULT hr = pContextProperties->SetProperty ( bstrPropertyName, Variant );
// Cleanup
VariantClear(&Variant);
return hr; }
/*===================================================================
ViperAttachIntrinsicsToContext
Attach ASP intrinsic objects as Viper context properties
Parameters - Intrinsics as interface pointers IApplicationObject *pAppln Application (required) ISessionObject *pSession Session (optional) IRequest *pRequest Request (optional) IResponse *pResponse Response (optional) IServer *pServer Server (optional)
Returns: HRESULT ===================================================================*/ HRESULT ViperAttachIntrinsicsToContext ( IApplicationObject *pAppln, ISessionObject *pSession, IRequest *pRequest, IResponse *pResponse, IServer *pServer ) { Assert(pAppln); HRESULT hr = S_OK;
// Get Viper Context
IObjectContext *pViperContext = NULL; hr = GetObjectContext(&pViperContext);
// Get IContextPoperties interface
IContextProperties *pContextProperties = NULL; if (SUCCEEDED(hr)) hr = pViperContext->QueryInterface ( IID_IContextProperties, (void **)&pContextProperties );
// Set properties
if (SUCCEEDED(hr)) hr = ViperSetContextProperty ( pContextProperties, BSTR_OBJ_APPLICATION, pAppln );
if (SUCCEEDED(hr) && pSession) hr = ViperSetContextProperty ( pContextProperties, BSTR_OBJ_SESSION, pSession ); if (SUCCEEDED(hr) && pRequest) hr = ViperSetContextProperty ( pContextProperties, BSTR_OBJ_REQUEST, pRequest );
if (SUCCEEDED(hr) && pResponse) hr = ViperSetContextProperty ( pContextProperties, BSTR_OBJ_RESPONSE, pResponse );
if (SUCCEEDED(hr) && pServer) hr = ViperSetContextProperty ( pContextProperties, BSTR_OBJ_SERVER, pServer );
// Cleanup
if (pContextProperties) pContextProperties->Release();
if (pViperContext) pViperContext->Release();
return hr; } /*===================================================================
ViperGetObjectFromContext
Get Viper context property by LPWSTR and return it as IDispatch*. The real interface takes BSTR and VARIANT.
Parameters BSTR bstrName Property Name IDispatch **ppdisp [out] Object (Property Value)
Returns: HRESULT ===================================================================*/ HRESULT ViperGetObjectFromContext ( BSTR bstrName, IDispatch **ppdisp ) { Assert(ppdisp);
HRESULT hr = S_OK;
// Get Viper Context
IObjectContext *pViperContext = NULL; hr = GetObjectContext(&pViperContext);
// Get IContextPoperties interface
IContextProperties *pContextProperties = NULL; if (SUCCEEDED(hr)) hr = pViperContext->QueryInterface ( IID_IContextProperties, (void **)&pContextProperties );
// Get property Value as variant
VARIANT Variant; VariantInit(&Variant);
if (SUCCEEDED(hr)) hr = pContextProperties->GetProperty(bstrName, &Variant);
// Convert Variant to IDispatch*
if (SUCCEEDED(hr)) { IDispatch *pDisp = NULL; if (V_VT(&Variant) == VT_DISPATCH) pDisp = V_DISPATCH(&Variant);
if (pDisp) { pDisp->AddRef(); *ppdisp = pDisp; } else hr = E_FAIL; } // Cleanup
VariantClear(&Variant);
if (pContextProperties) pContextProperties->Release();
if (pViperContext) pViperContext->Release();
if (FAILED(hr)) *ppdisp = NULL;
return hr; }
/*===================================================================
ViperGetHitObjFromContext
Get Server from Viper context property and get it's current HitObj
Parameters CHitObj **ppHitObj [out]
Returns: HRESULT ===================================================================*/ HRESULT ViperGetHitObjFromContext ( CHitObj **ppHitObj ) { *ppHitObj = NULL; IDispatch *pdispServer = NULL; HRESULT hr = ViperGetObjectFromContext(BSTR_OBJ_SERVER, &pdispServer); if (FAILED(hr)) return hr;
if (pdispServer) { CServer *pServer = static_cast<CServer *>(pdispServer); *ppHitObj = pServer->PHitObj(); pdispServer->Release(); }
return *ppHitObj ? S_OK : S_FALSE; } /*===================================================================
ViperCreateInstance
Viper's implementation of CoCreateInstance
Parameters REFCLSID rclsid class id REFIID riid interface void **ppv [out] pointer to interface
Returns: HRESULT ===================================================================*/ HRESULT ViperCreateInstance ( REFCLSID rclsid, REFIID riid, void **ppv ) { /*
DWORD dwClsContext = (Glob(fAllowOutOfProcCmpnts)) ? CLSCTX_INPROC_SERVER | CLSCTX_SERVER : CLSCTX_INPROC_SERVER; */
// The reasons for supporting ASPAllowOutOfProcComponents seem to have
// vanished. Because this only partially worked in II4 and we changed
// the default in IIS5 this was causing problems with upgrades. So
// we're going to ignore the fAllowOutOfProcCmpnts setting.
DWORD dwClsContext = CLSCTX_INPROC_SERVER | CLSCTX_SERVER; return CoCreateInstance(rclsid, NULL, dwClsContext, riid, ppv); }
/*===================================================================
ViperConfigure
Viper settings: # of threads, queue len, in-proc failfast, allow oop components
Parameters cThreads -- number of threads fAllowOopComponents -- TRUE or FALSE Returns: HRESULT ===================================================================*/ HRESULT ViperConfigure ( DWORD cThreads, BOOL fAllowOopComponents ) { HRESULT hr = S_OK; IMTSPackage *pPackage = NULL;
//
// Get hold of the package
//
hr = CoCreateInstance(CLSID_MTSPackage, NULL, CLSCTX_INPROC_SERVER, IID_IMTSPackage, (void **)&pPackage); if (SUCCEEDED(hr) && !pPackage) hr = E_FAIL;
//
// Set knobs
//
if (SUCCEEDED(hr)) { #define MTS_STYLE_THREAD_POOL
#ifdef MTS_STYLE_THREAD_POOL
IComStaThreadPoolKnobs *pKnobs = NULL; hr = pPackage->QueryInterface(IID_IComStaThreadPoolKnobs, (void **)&pKnobs); #else
IThreadPoolKnobs *pKnobs = NULL; hr = pPackage->QueryInterface(IID_IThreadPoolKnobs, (void **)&pKnobs); #endif
if (SUCCEEDED(hr) && pKnobs) { // number of threads
SYSTEM_INFO si; GetSystemInfo(&si); cThreads *= si.dwNumberOfProcessors; #ifdef MTS_STYLE_THREAD_POOL
pKnobs->SetMaxThreadCount(cThreads); pKnobs->SetMinThreadCount(si.dwNumberOfProcessors + 7);
// queue length
pKnobs->SetQueueDepth(30000);
pKnobs->SetActivityPerThread(1); #else
pKnobs->SetMaxThreads(cThreads); pKnobs->SetMinThreads(si.dwNumberOfProcessors + 7);
// queue length
pKnobs->SetMaxQueuedRequests(30000); #endif
pKnobs->Release(); } }
//
// Bug 111008: Tell Viper that we do impersonations
//
if (SUCCEEDED(hr)) { IImpersonationControl *pImpControl = NULL; hr = pPackage->QueryInterface(IID_IImpersonationControl, (void **)&pImpControl);
if (SUCCEEDED(hr) && pImpControl) { hr = pImpControl->ClientsImpersonate(TRUE); pImpControl->Release(); } }
//
// Disable FAILFAST for in-proc case
//
if (SUCCEEDED(hr) && !g_fOOP) { IFailfastControl *pFFControl = NULL; hr = pPackage->QueryInterface(IID_IFailfastControl, (void **)&pFFControl);
if (SUCCEEDED(hr) && pFFControl) { pFFControl->SetApplFailfast(FALSE); pFFControl->Release(); } }
/*
//
// Set Allow OOP Components
//
if (SUCCEEDED(hr)) { INonMTSActivation *pNonMTSActivation = NULL; hr = pPackage->QueryInterface(IID_INonMTSActivation, (void **)&pNonMTSActivation); if (SUCCEEDED(hr) && pNonMTSActivation) { pNonMTSActivation->OutOfProcActivationAllowed(fAllowOopComponents); pNonMTSActivation->Release(); } } */
//
// Clean-up
//
if (pPackage) pPackage->Release();
return hr; }
/*===================================================================
C O M H e l p e r A P I ===================================================================*/
/*===================================================================
ViperCoObjectIsaProxy
Checks if the given IUnknown* points to a proxy
Parameters IUnknown* pUnk pointer to check
Returns: BOOL (TRUE if Proxy) ===================================================================*/ BOOL ViperCoObjectIsaProxy ( IUnknown* pUnk ) { HRESULT hr; IUnknown *pUnk2;
hr = pUnk->QueryInterface(IID_IProxyManager, (void**)&pUnk2); if (FAILED(hr)) return FALSE;
pUnk2->Release(); return TRUE; }
/*===================================================================
ViperCoObjectAggregatesFTM
Checks if the given object agregates free threaded marshaller (is agile)
Parameters IUnknown* pUnk pointer to check
Returns: BOOL (TRUE if Agile) ===================================================================*/ BOOL ViperCoObjectAggregatesFTM ( IUnknown *pUnk ) { HRESULT hr; IMarshal *pMarshal; GUID guidClsid;
hr = pUnk->QueryInterface(IID_IMarshal, (void**)&pMarshal); if (FAILED(hr)) return FALSE;
hr = pMarshal->GetUnmarshalClass(IID_IUnknown, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &guidClsid); pMarshal->Release();
if (FAILED(hr)) return FALSE;
return (guidClsid == CLSID_InProcFreeMarshaler); }
|