|
|
/*===================================================================
Microsoft Denali
Microsoft Confidential. Copyright 1997 Microsoft Corporation. All Rights Reserved.
Component: Component Collection
File: Compcol.h
Owner: DmitryR
This is the Component Collection header file.
Component collection replaces: (used in:) COleVar, COleVarList (HitObj, Session, Application) CObjectCover (HitObj, Server, Session) VariantLink HasTable (Session, Application) ===================================================================*/
#ifndef COMPCOL_H
#define COMPCOL_H
/*===================================================================
Special OLE stuff ===================================================================*/
#include "gip.h"
/*===================================================================
Misc declarations ===================================================================*/
#include "hashing.h"
#include "idhash.h"
#include "dbllink.h"
#include "util.h"
#include "viperint.h"
#include "memcls.h"
// Forward declarations
class CHitObj; class CAppln; class CSession; class CScriptingContext;
// Component Types
#define CompType DWORD
#define ctUnknown 0x00000000 // (Used as UnInitialized state)
#define ctTagged 0x00000001 // Created by <OBJECT ...> tag
#define ctProperty 0x00000002 // Created with Session("xxx") =
#define ctUnnamed 0x00000004 // Created with Server.CreateObject()
// Scope levels
#define CompScope DWORD
#define csUnknown 0x00000000
#define csAppln 0x00000001
#define csSession 0x00000002
#define csPage 0x00000004
// COM threading models
#define CompModel DWORD
#define cmUnknown 0x00000000
#define cmSingle 0x00000001
#define cmApartment 0x00000002
#define cmFree 0x00000004
#define cmBoth 0x00000008
/*===================================================================
Utility Functions Prototypes ===================================================================*/
HRESULT CompModelFromCLSID ( const CLSID &ClsId, CompModel *pcmModel = NULL, BOOL *pfInProc = NULL );
BOOL FIsIntrinsic(IDispatch *pdisp);
inline BOOL FIsIntrinsic(VARIANT *pVar) { if (V_VT(pVar) != VT_DISPATCH) return FALSE; return FIsIntrinsic(V_DISPATCH(pVar)); }
/*===================================================================
OnPageInfo struct used to cache ids of OnStartPage()/OnEndPage() ===================================================================*/
#define ONPAGEINFO_ONSTARTPAGE 0
#define ONPAGEINFO_ONENDPAGE 1
#define ONPAGE_METHODS_MAX ONPAGEINFO_ONENDPAGE+1
struct COnPageInfo { DISPID m_rgDispIds[ONPAGE_METHODS_MAX];
BOOL FHasAnyMethod() const; };
inline BOOL COnPageInfo::FHasAnyMethod() const { #if (ONPAGE_METHODS_MAX == 2)
// fast implementation for the real case
return ( m_rgDispIds[0] != DISPID_UNKNOWN || m_rgDispIds[1] != DISPID_UNKNOWN ); #else
for (int i = 0; i < ONPAGE_METHODS_MAX; i++) { if (m_rgDispIds[i] != DISPID_UNKNOWN) return TRUE; } return FALSE; #endif
}
/*===================================================================
Component object stores information about a single object Each component object belongs to a component collection Component objects are linked into a list, also tagged objects are hashed by name, and properties are hashed by name, and all instantiated objects are hashed by IUnknown* ===================================================================*/ class CComponentObject : public CLinkElem {
friend class CComponentCollection; friend class CPageComponentManager; friend class CComponentIterator;
private: // properties
CompScope m_csScope : 4; // Scope
CompType m_ctType : 4; // Component Object Type
CompModel m_cmModel : 4; // Threading behavior (from Registry)
DWORD m_fAgile : 1; // Agile?
// flag to indicate if OnPageInfo was queried
DWORD m_fOnPageInfoCached : 1; // flag: on-start-page done, waiting to do on-end-page
DWORD m_fOnPageStarted : 1;
// flag to avoid multiple unsuccessful attempts to instantiate
DWORD m_fFailedToInstantiate : 1; // flag to mark instantiated (or tried to inst.) tagged objects
DWORD m_fInstantiatedTagged : 1;
// flag to mark the object in pointer cache
DWORD m_fInPtrCache : 1;
// variant filled with value?
DWORD m_fVariant : 1;
// name was allocated (longer than the default buffer)?
DWORD m_fNameAllocated : 1;
// pointers to object and type info
IDispatch *m_pDisp; // Dispatch interface pointer
IUnknown *m_pUnknown; // IUnknown interface pointer
union { CLSID m_ClsId; // Class id (for tagged and unnamed)
VARIANT m_Variant; // Variant (for properties)
}; // For objects that use OLE cookie API
DWORD m_dwGIPCookie;
// cached OnPageInfo
COnPageInfo m_OnPageInfo;
// pointer to connect objects into link list
CComponentObject *m_pCompNext; // Next object in the link list.
CComponentObject *m_pCompPrev; // Prev object in the link list.
// buffer for names that fit in (36 bytes = 17 unicode chars + '\0')
BYTE m_rgbNameBuffer[36];
private: // constructor is private! (not for outside use)
CComponentObject ( CompScope csScope, CompType ctType, CompModel cmModel ); ~CComponentObject();
// Initializes CLinkElem portion
HRESULT Init(LPWSTR pwszName, DWORD cbName);
// Releases all interface pointers (used by clear)
HRESULT ReleaseAll();
// Clears out data (releases all) leaving link alone
HRESULT Clear(); // Create instance if not there already
HRESULT Instantiate(CHitObj *pHitObj); HRESULT TryInstantiate(CHitObj *pHitObj); // Set value from variant
HRESULT SetPropertyValue(VARIANT *);
// Convert Object to be GIP cookie
HRESULT ConvertToGIPCookie(); // Get and cache the ids for OnStart methods
HRESULT GetOnPageInfo();
public: // functions to get the COM object (internally resolve cookies)
HRESULT GetAddRefdIDispatch(IDispatch **ppdisp); HRESULT GetAddRefdIUnknown(IUnknown **ppunk); HRESULT GetVariant(VARIANT *pVar); // not for GIP cookies
// Check if the unnamed page level object object
// can be removed without waiting till the end of request
inline BOOL FEarlyReleaseAllowed() const; // public inlines to access the object's properties
// these are the only methods available from outside
inline LPWSTR GetName(); inline CompScope GetScope() const; inline CompType GetType() const; inline CompModel GetModel() const; inline BOOL FAgile() const;
// Retrieve the cached ids
inline const COnPageInfo *GetCachedOnPageInfo() const;
public: #ifdef DBG
void AssertValid() const; #else
void AssertValid() const {} #endif
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS() };
inline LPWSTR CComponentObject::GetName() { return (LPWSTR)m_pKey; }
inline CompScope CComponentObject::GetScope() const { return m_csScope; } inline CompType CComponentObject::GetType() const { return m_ctType; }
inline CompType CComponentObject::GetModel() const { return m_cmModel; }
inline BOOL CComponentObject::FAgile() const { return m_fAgile; }
inline const COnPageInfo *CComponentObject::GetCachedOnPageInfo() const { return m_fOnPageInfoCached ? &m_OnPageInfo : NULL; }
inline BOOL CComponentObject::FEarlyReleaseAllowed() const { return (!m_fOnPageStarted && // no need to do on-end-page
!m_fInPtrCache && // no need to search by pointer
m_csScope == csPage && // page scoped
m_ctType == ctUnnamed); // created with Server.CreateObject()
}
/*===================================================================
Component collection is a manager of various types of component objects: 1) Tagged objects (<OBJECT...>) (instantiated or not) 2) Session("xxx") and Application("xxx") properties 3) Unnamed objects (Server.CreateObject()) It hashes added objects as needed (some by name, IUnkn *, etc.)
The idea is to isolate the above issues from outside as much as possible.
Component collections exist under session, application, hitobj ===================================================================*/ class CComponentCollection { friend class CPageComponentManager; friend class CComponentIterator; friend class CVariantsIterator;
private: CompScope m_csScope : 4; // scope (page, session, appln)
DWORD m_fUseTaggedArray : 1; // remember tagged objects array?
DWORD m_fUsePropArray : 1; // remember properties array?
DWORD m_fHasComProperties : 1; // any property VARIANTs that could be objects
// hash table (by name) of tagged objects
CHashTableStr m_htTaggedObjects; // hash table (by name) of properties (4)
CHashTableStr m_htProperties; // hash table (by IUnknown *) of all instances
CIdHashTable m_htidIUnknownPtrs;
// Pointer to the component objects link list
CComponentObject *m_pCompFirst; // First object in link list.
// Array of pointers to static objects to speed lookup by index
CPtrArray m_rgpvTaggedObjects;
// Array of pointers to properties to speed lookup by index
CPtrArray m_rgpvProperties;
// Various object counts in the collection
USHORT m_cAllTagged; // all tagged objects
USHORT m_cInstTagged; // instanciated tagged objects
USHORT m_cProperties; // all properties
USHORT m_cUnnamed; // number of unnamed objects
// Add/remove object to the component objects link list
HRESULT AddComponentToList(CComponentObject *pObj); HRESULT RemoveComponentFromList(CComponentObject *pObj); // Add named object to the proper hash table by name
HRESULT AddComponentToNameHash ( CComponentObject *pObj, LPWSTR pwszName, DWORD cbName ); // Add named object to the IUnkown * hash table
HRESULT AddComponentToPtrHash(CComponentObject *pObj);
// Find by name (for tagged)
HRESULT FindComponentObjectByName ( LPWSTR pwszName, DWORD cbName, CComponentObject **ppObj ); // Find by name (for properties)
HRESULT FindComponentPropertyByName ( LPWSTR pwszName, DWORD cbName, CComponentObject **ppObj );
// Find by IUnknown*
HRESULT FindComponentByIUnknownPtr ( IUnknown *pUnk, CComponentObject **ppObj );
// Fill in the arrays for access by index for the first time
HRESULT StartUsingTaggedObjectsArray(); HRESULT StartUsingPropertiesArray();
public: // Add various kinds of objects to the collection
// They are also used by
// CPageComponentManager AddScoped...()
HRESULT AddTagged ( LPWSTR pwszName, const CLSID &clsid, CompModel cmModel ); HRESULT AddProperty ( LPWSTR pwszName, VARIANT *pVariant, CComponentObject **ppObj = NULL );
HRESULT AddUnnamed ( const CLSID &clsid, CompModel cmModel, CComponentObject **ppObj );
HRESULT GetTagged ( LPWSTR pwszName, CComponentObject **ppObj );
HRESULT GetProperty ( LPWSTR pwszName, CComponentObject **ppObj );
HRESULT GetNameByIndex ( CompType ctType, int index, LPWSTR *ppwszName );
HRESULT RemoveComponent(CComponentObject *pObj); HRESULT RemoveProperty(LPWSTR pwszName); HRESULT RemoveAllProperties();
CComponentCollection(); ~CComponentCollection();
HRESULT Init(CompScope csScope); HRESULT UnInit();
BOOL FHasStateInfo() const; // TRUE when state-full
BOOL FHasObjects() const; // TRUE when contains objects
DWORD GetPropertyCount() const; DWORD GetTaggedObjectCount() const;
public: #ifdef DBG
void AssertValid() const; #else
void AssertValid() const {} #endif
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS() };
inline BOOL CComponentCollection::FHasStateInfo() const { return ((m_cAllTagged + m_cProperties + m_cUnnamed) > 0); }
inline BOOL CComponentCollection::FHasObjects() const { return (m_cInstTagged > 0 || m_cUnnamed > 0 || (m_cProperties > 0 && m_fHasComProperties)); }
inline DWORD CComponentCollection::GetPropertyCount() const { return m_cProperties; }
inline DWORD CComponentCollection::GetTaggedObjectCount() const { return m_cAllTagged; }
inline HRESULT CComponentCollection::AddComponentToList ( CComponentObject *pObj ) { pObj->m_pCompNext = m_pCompFirst; pObj->m_pCompPrev = NULL; if (m_pCompFirst) m_pCompFirst->m_pCompPrev = pObj; m_pCompFirst = pObj; return S_OK; }
inline HRESULT CComponentCollection::RemoveComponentFromList ( CComponentObject *pObj ) { if (pObj->m_pCompPrev) pObj->m_pCompPrev->m_pCompNext = pObj->m_pCompNext; if (pObj->m_pCompNext) pObj->m_pCompNext->m_pCompPrev = pObj->m_pCompPrev; if (m_pCompFirst == pObj) m_pCompFirst = pObj->m_pCompNext; pObj->m_pCompPrev = pObj->m_pCompNext = NULL; return S_OK; }
/*===================================================================
A page object controls calls to OnStartPage(), OnEndPage(). Page objects are used by CPageComponentManager They are hashed using IDispatch * to avoid multiple OnStartPage() calls for the same object. ===================================================================*/ class CPageObject {
friend class CPageComponentManager;
private: IDispatch *m_pDisp; // Dispatch interface pointer
COnPageInfo m_OnPageInfo; // cached OnPageInfo
DWORD m_fStartPageCalled : 1; DWORD m_fEndPageCalled : 1; private: // the only access is using CPageComponentManager
CPageObject(); ~CPageObject();
HRESULT Init(IDispatch *pDisp, const COnPageInfo &OnPageInfo);
// Invoke OnStartPage or OnEndPage
HRESULT InvokeMethod ( DWORD iMethod, CScriptingContext *pContext, CHitObj *pHitObj ); HRESULT TryInvokeMethod // used by InvokeMethod
( // inside TRY CATCH
DISPID DispId, BOOL fOnStart, IDispatch *pDispContext, CHitObj *pHitObj );
public: #ifdef DBG
void AssertValid() const; #else
void AssertValid() const {} #endif
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS() }; /*===================================================================
Page component manager provides access to component collections for page, session, application level. It is associated with a HitObj.
It also takes care of covering (OnStartPage(), OnEndPage()). ===================================================================*/ class CPageComponentManager { private: // hashtable of page objects hashed by IDispatch *
CIdHashTable m_htidPageObjects;
// hit object (this page)
CHitObj *m_pHitObj;
// hash table iterator callbacks
static IteratorCallbackCode DeletePageObjectCB(void *pvObj, void *, void *); static IteratorCallbackCode OnEndPageObjectCB(void *pvObj, void *pvHitObj, void *pvhr);
private: // collections related to page, session and application
HRESULT GetPageCollection(CComponentCollection **ppCollection); HRESULT GetSessionCollection(CComponentCollection **ppCollection); HRESULT GetApplnCollection(CComponentCollection **ppCollection); HRESULT GetCollectionByScope ( CompScope csScope, CComponentCollection **ppCollection );
// find objectc in any of the related collections
// (internal private method)
HRESULT FindScopedComponentByName ( CompScope csScope, LPWSTR pwszName, DWORD cbName, BOOL fProperty, CComponentObject **ppObj, CComponentCollection **ppCollection = NULL );
static HRESULT __stdcall InstantiateObjectFromMTA ( void *pvObj, void *pvHitObj );
public: CPageComponentManager(); ~CPageComponentManager();
HRESULT Init(CHitObj *pHitObj); // OnStartPage processing for an object that need it
// (OnEndPage is done for all objects at the end of page)
HRESULT OnStartPage ( CComponentObject *pCompObj, CScriptingContext *pContext, const COnPageInfo *pOnPageInfo, BOOL *pfStarted );
// request OnEndPage() for all objects that need it
// (OnStartPage() is done on demand on per-object basis)
HRESULT OnEndPageAllObjects();
// Add various kinds of objects. Objects get added to the
// right collection depending on scope argument
HRESULT AddScopedTagged ( CompScope csScope, LPWSTR pwszName, const CLSID &clsid, CompModel cmModel ); HRESULT AddScopedProperty ( CompScope csScope, LPWSTR pwszName, VARIANT *pVariant, CComponentObject **ppObj = NULL );
// Server.CreateObject
HRESULT AddScopedUnnamedInstantiated ( CompScope csScope, const CLSID &clsid, CompModel cmModel, COnPageInfo *pOnPageInfo, CComponentObject **ppObj );
// Get component object (tagged) by name.
// Scope could be csUnknown
HRESULT GetScopedObjectInstantiated ( CompScope csScope, LPWSTR pwszName, DWORD cbName, CComponentObject **ppObj, BOOL *pfNewInstance );
// Get component property by name. Scope could be csUnknown
HRESULT GetScopedProperty ( CompScope csScope, LPWSTR pwszName, CComponentObject **ppObj );
// Find component by IUnknown * (or IDispatch *).
HRESULT FindAnyScopeComponentByIUnknown ( IUnknown *pUnk, CComponentObject **ppObj ); HRESULT FindAnyScopeComponentByIDispatch ( IDispatch *pDisp, CComponentObject **ppObj ); // The same - but static - gets context from Viper
static HRESULT FindComponentWithoutContext ( IDispatch *pDisp, CComponentObject **ppObj );
// Remove component -- the early release logic
HRESULT RemoveComponent(CComponentObject *pObj);
public: #ifdef DBG
void AssertValid() const; #else
void AssertValid() const {} #endif
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS() };
// Component iterator is used to go through component names
// all the HitObj - reletated object across collections
// Needed for scripting
class CComponentIterator { private: CHitObj *m_pHitObj; DWORD m_fInited : 1; DWORD m_fFinished : 1; CompScope m_csLastScope : 4; CComponentObject *m_pLastObj;
public: CComponentIterator(CHitObj *pHitObj = NULL); ~CComponentIterator();
HRESULT Init(CHitObj *pHitObj); LPWSTR WStrNextComponentName(); };
// Variant Iterator is used to go through Property or Tagged object
// names in a component collection. Needed for scripting
class CVariantsIterator : public IEnumVARIANT { public: CVariantsIterator(CAppln *, DWORD); CVariantsIterator(CSession *, DWORD); ~CVariantsIterator();
HRESULT Init();
// The Big Three
STDMETHODIMP QueryInterface(const GUID &, void **); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release();
// standard methods for iterators
STDMETHODIMP Clone(IEnumVARIANT **ppEnumReturn); STDMETHODIMP Next(unsigned long cElements, VARIANT *rgVariant, unsigned long *pcElementsFetched); STDMETHODIMP Skip(unsigned long cElements); STDMETHODIMP Reset();
private: ULONG m_cRefs; // reference count
CComponentCollection *m_pCompColl; // collection we are iterating over
DWORD m_dwIndex; // current position for iteration
CAppln *m_pAppln; // application (to clone iterator and Lock())
CSession *m_pSession; // session (to clone iterator)
DWORD m_ctColType; // type of collection
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS() };
#endif // COMPCOL_H
|