3691 lines
87 KiB
C++
3691 lines
87 KiB
C++
/*===================================================================
|
|
Microsoft Denali
|
|
|
|
Microsoft Confidential.
|
|
Copyright 1997 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Component: Component Collection
|
|
|
|
File: Compcol.cpp
|
|
|
|
Owner: DmitryR
|
|
|
|
This is the Component Collection source file.
|
|
|
|
Component collection replaces: (used in:)
|
|
COleVar, COleVarList (HitObj, Session, Application)
|
|
CObjectCover (HitObj, Server, Session)
|
|
VariantLink HasTable (Session, Application)
|
|
===================================================================*/
|
|
#include "denpre.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Context.h"
|
|
#include "MTAcb.h"
|
|
#include "Request.h"
|
|
#include "Response.h"
|
|
#include "Server.h"
|
|
#include "tlbcache.h"
|
|
#include "memchk.h"
|
|
|
|
/*===================================================================
|
|
Defines for hash table sizes
|
|
===================================================================*/
|
|
|
|
#define HT_TAGGED_OBJECTS_BUCKETS_MAX 19
|
|
#define HT_PROPERTIES_BUCKETS_MAX 17
|
|
#define HT_IUNKNOWN_PTRS_BUCKETS_MAX 23
|
|
|
|
#define HT_PAGE_OBJECTS_BUCKETS_MAX 17
|
|
|
|
/*===================================================================
|
|
Static utility function prototypes
|
|
===================================================================*/
|
|
|
|
static HRESULT QueryOnPageInfo
|
|
(
|
|
IDispatch *pDisp,
|
|
COnPageInfo *pOnPageInfo
|
|
);
|
|
|
|
static HRESULT CLSIDToMultibyteString
|
|
(
|
|
CLSID ClsId,
|
|
char *psz,
|
|
int cch
|
|
);
|
|
|
|
#define REG_MODEL_TEXT_LEN_MAX 20 // big enough for "Apartment"
|
|
static CompModel RegStrToCompModel
|
|
(
|
|
BYTE *pb,
|
|
DWORD cb
|
|
);
|
|
|
|
/*===================================================================
|
|
Static utility functions code
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
QueryOnPageInfo
|
|
|
|
Query dispatch ids for OnStartPage and OnEndPage
|
|
|
|
Parameters:
|
|
IDispatch *pDisp Object to query
|
|
COnPageInfo *pOnPageInfo Struct to fill in
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT QueryOnPageInfo
|
|
(
|
|
IDispatch *pDisp,
|
|
COnPageInfo *pOnPageInfo
|
|
)
|
|
{
|
|
static LPOLESTR BStrEntryPoints[ONPAGE_METHODS_MAX] =
|
|
{
|
|
L"OnStartPage",
|
|
L"OnEndPage"
|
|
};
|
|
|
|
HRESULT hr = S_OK;
|
|
for (int i = 0; i < ONPAGE_METHODS_MAX; i++)
|
|
{
|
|
hr = pDisp->GetIDsOfNames
|
|
(
|
|
IID_NULL,
|
|
&BStrEntryPoints[i],
|
|
1,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
&pOnPageInfo->m_rgDispIds[i]
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
if (hr != DISP_E_UNKNOWNNAME &&
|
|
hr != DISP_E_MEMBERNOTFOUND)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// If UNKNOWNNAME, set dispid to DISPID_UNKNOWN
|
|
hr = S_OK;
|
|
pOnPageInfo->m_rgDispIds[i] = DISPID_UNKNOWN;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CLSIDToMultibyteString
|
|
|
|
Converts CLSID into multibyte string
|
|
Used in CompModelFromCLSID
|
|
|
|
Parameters:
|
|
CLSID ClsId (in) CLSID to convert
|
|
char *pb put string into this buffer
|
|
int cch of this length
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CLSIDToMultibyteString
|
|
(
|
|
CLSID ClsId,
|
|
char *psz,
|
|
int cch
|
|
)
|
|
{
|
|
// First convert it to OLECHAR string
|
|
OLECHAR *pszWideClassID = NULL; // temp wide string classid
|
|
HRESULT hr = StringFromCLSID(ClsId, &pszWideClassID);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// OLECHAR to MultiByte
|
|
BOOL f = WideCharToMultiByte
|
|
(
|
|
CP_ACP, // code page
|
|
0, // performance and mapping flags
|
|
pszWideClassID, // address of wide-character string
|
|
-1, // length (-1 == null-terminated)
|
|
psz, // address of buffer for new string
|
|
cch, // size of buffer for new string
|
|
NULL, // address of default for unmappable
|
|
// characters; quickest if null
|
|
NULL // address of flag set when default
|
|
// char. used; quickest if null
|
|
);
|
|
if (f == FALSE)
|
|
hr = E_FAIL;
|
|
|
|
if (pszWideClassID)
|
|
CoTaskMemFree(pszWideClassID);
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
RegStrToCompModel
|
|
|
|
Get CompModel value from a registry string
|
|
|
|
Parameters:
|
|
char *pb string as returned from registry
|
|
int cb length returned from registry
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
CompModel RegStrToCompModel
|
|
(
|
|
BYTE *pb,
|
|
DWORD cb
|
|
)
|
|
{
|
|
CompModel cmModel = cmSingle; // assume single
|
|
|
|
if (cb == 5) // 5 include '\0'
|
|
{
|
|
if (!(_strnicmp((const char*)pb, "Both", cb)))
|
|
cmModel = cmBoth;
|
|
else if (!(_strnicmp((const char*)pb, "Free", cb)))
|
|
cmModel = cmFree;
|
|
}
|
|
else if (cb == 10) // 10 include '\0'
|
|
{
|
|
if (!(_strnicmp((const char*)pb, "Apartment", cb)))
|
|
cmModel = cmApartment;
|
|
}
|
|
|
|
return cmModel;
|
|
}
|
|
|
|
/*===================================================================
|
|
Public utility functions code
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
CompModelFromCLSID
|
|
|
|
Get object's model and InProc flag by its CLSID from the registry
|
|
|
|
Parameters:
|
|
CLSID &ClsId (in)
|
|
CompModel *pcmModel (out) Model (optional)
|
|
BOOL *pfInProc (out) InProc flag (optional)
|
|
|
|
Returns:
|
|
CompModel (cmFree, cmBoth, etc.)
|
|
===================================================================*/
|
|
HRESULT CompModelFromCLSID
|
|
(
|
|
const CLSID &ClsId,
|
|
CompModel *pcmModel,
|
|
BOOL *pfInProc
|
|
)
|
|
{
|
|
if (!Glob(fTrackThreadingModel) && !pfInProc)
|
|
{
|
|
// ignore registry value for threading model and
|
|
// inproc flag is not requested -> take short return
|
|
if (pcmModel)
|
|
*pcmModel = cmUnknown;
|
|
return S_OK;
|
|
}
|
|
|
|
// default returns
|
|
CompModel cmModel = cmSingle; // assume single
|
|
BOOL fInProc = TRUE; // assume inproc
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Convert ClsId to multibyte string
|
|
|
|
char szClassID[50];
|
|
hr = CLSIDToMultibyteString(ClsId, szClassID, sizeof(szClassID));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
/* query the registry; threading model is stored as:
|
|
HKEY_CLASSES_ROOT
|
|
key: CLSID
|
|
key: <object's classid>
|
|
key: InprocServer32
|
|
name: ThreadingModel data: "Both" | "Apartment"
|
|
*/
|
|
|
|
// Navigate the registry to "InprocServer32" key
|
|
|
|
HKEY hKey1 = NULL; // handle of open reg key
|
|
HKEY hKey2 = NULL; // handle of open reg key
|
|
HKEY hKey3 = NULL; // handle of open reg key
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int nRet = RegOpenKeyExA
|
|
(
|
|
HKEY_CLASSES_ROOT,
|
|
"CLSID",
|
|
0,
|
|
KEY_READ,
|
|
&hKey1
|
|
);
|
|
if (nRet != ERROR_SUCCESS)
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int nRet = RegOpenKeyExA
|
|
(
|
|
hKey1,
|
|
szClassID,
|
|
0,
|
|
KEY_READ,
|
|
&hKey2
|
|
);
|
|
if (nRet != ERROR_SUCCESS)
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
// Get the stuff from the registry "InprocServer32" key
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int nRet = RegOpenKeyExA
|
|
(
|
|
hKey2,
|
|
"InprocServer32",
|
|
0,
|
|
KEY_READ,
|
|
&hKey3
|
|
);
|
|
if (nRet == ERROR_SUCCESS)
|
|
{
|
|
DWORD cbData = REG_MODEL_TEXT_LEN_MAX;
|
|
BYTE szData[REG_MODEL_TEXT_LEN_MAX];
|
|
|
|
nRet = RegQueryValueExA
|
|
(
|
|
hKey3,
|
|
"ThreadingModel",
|
|
NULL,
|
|
NULL,
|
|
szData,
|
|
&cbData
|
|
);
|
|
if (nRet == ERROR_SUCCESS)
|
|
cmModel = RegStrToCompModel(szData, cbData);
|
|
|
|
if (cmModel == cmBoth)
|
|
{
|
|
// Some objects marked as "Both" ASP treats as
|
|
// "Apartment". These objects should be marked in
|
|
// the registry as "ASPComponentNonAgile"
|
|
|
|
nRet = RegQueryValueExA
|
|
(
|
|
hKey3,
|
|
"ASPComponentNonAgile",
|
|
NULL,
|
|
NULL,
|
|
szData,
|
|
&cbData
|
|
);
|
|
|
|
// If the key is found pretend it's "apartment"
|
|
if (nRet == ERROR_SUCCESS)
|
|
cmModel = cmApartment;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if there is no InprocServer32 key,
|
|
// then it must be a localserver or remote server.
|
|
fInProc = FALSE;
|
|
}
|
|
}
|
|
|
|
// clean up registry keys
|
|
if (hKey3)
|
|
RegCloseKey(hKey3);
|
|
if (hKey2)
|
|
RegCloseKey(hKey2);
|
|
if (hKey1)
|
|
RegCloseKey(hKey1);
|
|
|
|
// return values
|
|
if (pcmModel)
|
|
*pcmModel = Glob(fTrackThreadingModel) ? cmModel : cmUnknown;
|
|
if (pfInProc)
|
|
*pfInProc = fInProc;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
FIsIntrinsic
|
|
|
|
Checks if the given IDispatch * points to an ASP intrinsic.
|
|
|
|
Parameters:
|
|
pdisp pointer to check
|
|
|
|
Returns:
|
|
TRUE if Intrinsic
|
|
===================================================================*/
|
|
BOOL FIsIntrinsic
|
|
(
|
|
IDispatch *pdisp
|
|
)
|
|
{
|
|
if (!pdisp)
|
|
return FALSE; // null dispatch pointer - not an intrinsic
|
|
|
|
IUnknown *punk = NULL;
|
|
if (FAILED(pdisp->QueryInterface(IID_IDenaliIntrinsic, (void **)&punk)))
|
|
return FALSE;
|
|
|
|
Assert(punk);
|
|
punk->Release();
|
|
return TRUE;
|
|
}
|
|
|
|
/*===================================================================
|
|
FIsSimpleVariant
|
|
|
|
Checks if the given VARIANT is a simple one
|
|
|
|
Parameters:
|
|
pvar variant to check
|
|
|
|
Returns:
|
|
TRUE if [for sure] simple, FALSE if [possibly] not
|
|
===================================================================*/
|
|
inline FIsSimpleVariant(VARIANT *pvar)
|
|
{
|
|
switch (V_VT(pvar))
|
|
{
|
|
case VT_BSTR:
|
|
case VT_I2:
|
|
case VT_I4:
|
|
case VT_BOOL:
|
|
case VT_DATE:
|
|
case VT_R4:
|
|
case VT_R8:
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
C C o m p o n e n t O b j e c t
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
CComponentObject::CComponentObject
|
|
|
|
CComponentObject constructor
|
|
|
|
Parameters:
|
|
CompScope scScope Object scope
|
|
CompType ctType Object type
|
|
CompModel cmModel Object threading model
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CComponentObject::CComponentObject
|
|
(
|
|
CompScope scScope,
|
|
CompType ctType,
|
|
CompModel cmModel
|
|
)
|
|
:
|
|
m_csScope(scScope), m_ctType(ctType), m_cmModel(cmModel),
|
|
m_fAgile(FALSE),
|
|
m_fOnPageInfoCached(FALSE),
|
|
m_fOnPageStarted(FALSE),
|
|
m_fFailedToInstantiate(FALSE), m_fInstantiatedTagged(FALSE),
|
|
m_fInPtrCache(FALSE),
|
|
m_fVariant(FALSE),
|
|
m_fNameAllocated(FALSE),
|
|
m_dwGIPCookie(NULL_GIP_COOKIE),
|
|
m_pDisp(NULL), m_pUnknown(NULL),
|
|
m_pCompNext(NULL), m_pCompPrev(NULL)
|
|
{
|
|
}
|
|
|
|
#ifdef DBG
|
|
/*===================================================================
|
|
CComponentObject::AssertValid
|
|
|
|
Test to make sure that this is currently correctly formed
|
|
and assert if it is not.
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
void CComponentObject::AssertValid() const
|
|
{
|
|
Assert(m_ctType != ctUnknown);
|
|
}
|
|
#endif
|
|
|
|
/*===================================================================
|
|
CComponentObject::~CComponentObject
|
|
|
|
CComponentObject destructor
|
|
Releases interface pointers
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CComponentObject::~CComponentObject()
|
|
{
|
|
// Release all interface pointers
|
|
Clear();
|
|
|
|
// Name used in hash (from CLinkElem)
|
|
if (m_fNameAllocated)
|
|
{
|
|
Assert(m_pKey);
|
|
free(m_pKey);
|
|
}
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::Init
|
|
|
|
Initialize CLinkElem portion with the object name
|
|
Needed to implement string hash
|
|
|
|
Parameters:
|
|
LPWSTR pwszName object name
|
|
DWORD cbName name length in bytes
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::Init
|
|
(
|
|
LPWSTR pwszName,
|
|
DWORD cbName
|
|
)
|
|
{
|
|
Assert(pwszName);
|
|
Assert(*pwszName != L'\0');
|
|
Assert(cbName == (wcslen(pwszName) * sizeof(WCHAR)));
|
|
|
|
// required buffer length
|
|
DWORD cbBuffer = cbName + sizeof(WCHAR);
|
|
WCHAR *pwszNameBuffer = (WCHAR *)m_rgbNameBuffer;
|
|
|
|
if (cbBuffer > sizeof(m_rgbNameBuffer))
|
|
{
|
|
// the name doesn't fit into the member buffer -> allocate
|
|
pwszNameBuffer = (WCHAR *)malloc(cbBuffer);
|
|
if (!pwszNameBuffer)
|
|
return E_OUTOFMEMORY;
|
|
m_fNameAllocated = TRUE;
|
|
}
|
|
|
|
memcpy(pwszNameBuffer, pwszName, cbBuffer);
|
|
|
|
// init link with name as the key (length excludes null term)
|
|
return CLinkElem::Init(pwszNameBuffer, cbName);
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::ReleaseAll
|
|
|
|
Releases all interface pointers
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::ReleaseAll()
|
|
{
|
|
// Release all other present interface pointers
|
|
if (m_pDisp)
|
|
{
|
|
m_pDisp->Release();
|
|
m_pDisp = NULL;
|
|
}
|
|
if (m_pUnknown)
|
|
{
|
|
m_pUnknown->Release();
|
|
m_pUnknown = NULL;
|
|
}
|
|
|
|
// Variant
|
|
if (m_fVariant)
|
|
{
|
|
VariantClear(&m_Variant);
|
|
m_fVariant = FALSE;
|
|
}
|
|
|
|
if (m_dwGIPCookie != NULL_GIP_COOKIE)
|
|
{
|
|
g_GIPAPI.Revoke(m_dwGIPCookie);
|
|
m_dwGIPCookie = NULL_GIP_COOKIE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::Clear
|
|
|
|
Clears out data leaving link alone
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::Clear()
|
|
{
|
|
// Release all pointers
|
|
TRY
|
|
ReleaseAll();
|
|
CATCH(nExcept)
|
|
Assert(FALSE);
|
|
m_pDisp = NULL;
|
|
m_pUnknown = NULL;
|
|
m_fVariant = FALSE;
|
|
m_dwGIPCookie = NULL_GIP_COOKIE;
|
|
END_TRY
|
|
|
|
// Invalidate cached OnPageInfo
|
|
m_fOnPageInfoCached = FALSE;
|
|
m_fOnPageStarted = FALSE;
|
|
|
|
// Mark it as unknown
|
|
m_csScope = csUnknown;
|
|
m_ctType = ctUnknown;
|
|
m_cmModel = cmUnknown;
|
|
m_fAgile = FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::Instantiate
|
|
|
|
Create object instance if it's not there already
|
|
Calls TryInstantiate() from within TRY CATCH
|
|
|
|
Parameters:
|
|
CHitObj *pHitObj Hit object for error reporting
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::Instantiate
|
|
(
|
|
CHitObj *pHitObj
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (Glob(fExceptionCatchEnable))
|
|
{
|
|
TRY
|
|
hr = TryInstantiate(pHitObj);
|
|
CATCH(nExcept)
|
|
HandleErrorMissingFilename(IDE_SCRIPT_OBJ_INSTANTIATE_FAILED,
|
|
pHitObj,
|
|
TRUE,
|
|
GetName(),
|
|
nExcept);
|
|
hr = nExcept;
|
|
END_TRY
|
|
}
|
|
else
|
|
{
|
|
hr = TryInstantiate(pHitObj);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// Something failed -- need to clean-up
|
|
ReleaseAll();
|
|
|
|
// mark as "failed to instantiate"
|
|
m_fFailedToInstantiate = TRUE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::TryInstantiate
|
|
|
|
Create object instance if it's not there already
|
|
Called by Instantiate() from within TRY CATCH
|
|
|
|
Parameters:
|
|
CHitObj *pHitObj Hit object for error reporting
|
|
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::TryInstantiate
|
|
(
|
|
CHitObj *pHitObj
|
|
)
|
|
{
|
|
// Check if the object already exist
|
|
if (m_pUnknown)
|
|
return S_OK;
|
|
|
|
if (m_fFailedToInstantiate)
|
|
return E_FAIL; // already tried once
|
|
|
|
if (m_cmModel == cmUnknown && m_ClsId != CLSID_NULL)
|
|
{
|
|
CompModel cmModel; // needed because m_cmModel is a bit fld
|
|
HRESULT hr = CompModelFromCLSID(m_ClsId, &cmModel);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
m_cmModel = cmModel;
|
|
}
|
|
|
|
HRESULT hr = ViperCreateInstance
|
|
(
|
|
m_ClsId,
|
|
IID_IUnknown,
|
|
(void **)&m_pUnknown
|
|
);
|
|
|
|
// If we failed because we incorrectly cached the clsid
|
|
// (could happen for tagged objects) try to get updated
|
|
// cls id and retry
|
|
if (m_ctType == ctTagged && FAILED(hr))
|
|
{
|
|
if (g_TypelibCache.UpdateMappedCLSID(&m_ClsId) == S_OK)
|
|
{
|
|
hr = ViperCreateInstance
|
|
(
|
|
m_ClsId,
|
|
IID_IUnknown,
|
|
(void **)&m_pUnknown
|
|
);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (Glob(fTrackThreadingModel) && m_cmModel == cmBoth)
|
|
m_fAgile = TRUE;
|
|
else
|
|
m_fAgile = ViperCoObjectAggregatesFTM(m_pUnknown);
|
|
|
|
hr = m_pUnknown->QueryInterface
|
|
(
|
|
IID_IDispatch,
|
|
(void **)&m_pDisp
|
|
);
|
|
}
|
|
|
|
// Check if application level object that
|
|
// restricts threading -> use Global Interface Cookie
|
|
|
|
if (SUCCEEDED(hr)
|
|
&& (m_csScope == csAppln || m_csScope == csSession)
|
|
&& !m_fAgile)
|
|
{
|
|
return ConvertToGIPCookie();
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && !m_fOnPageInfoCached)
|
|
{
|
|
// don't really care if the following fails
|
|
GetOnPageInfo();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::SetPropertyValue
|
|
|
|
Sets value from a Variant
|
|
Checks agility and possible deadlocks
|
|
Does GIP conversion
|
|
|
|
Parameters:
|
|
VARIANT *pVariant [in] Value to set
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::SetPropertyValue
|
|
(
|
|
VARIANT *pVariant
|
|
)
|
|
{
|
|
Assert(m_ctType == ctProperty);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Copy the variant value
|
|
VariantInit(&m_Variant);
|
|
m_fVariant = TRUE;
|
|
|
|
hr = VariantCopyInd(&m_Variant, pVariant);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Get IDispatch pointer
|
|
if (V_VT(&m_Variant) == VT_DISPATCH)
|
|
{
|
|
m_pDisp = V_DISPATCH(&m_Variant);
|
|
}
|
|
else
|
|
{
|
|
m_pDisp = NULL;
|
|
}
|
|
|
|
if (!m_pDisp)
|
|
{
|
|
m_fAgile = TRUE; // not VT_DISPATCH VARIANTs are agile
|
|
return S_OK;
|
|
}
|
|
|
|
m_pDisp->AddRef();
|
|
|
|
// Query (and cache) OnPageInfo inside TRY CATCH
|
|
if (Glob(fExceptionCatchEnable))
|
|
{
|
|
TRY
|
|
hr = GetOnPageInfo();
|
|
CATCH(nExcept)
|
|
hr = E_UNEXPECTED;
|
|
END_TRY
|
|
}
|
|
else
|
|
{
|
|
hr = GetOnPageInfo();
|
|
}
|
|
|
|
// Don't really care if failed
|
|
hr = S_OK;
|
|
|
|
// Check if the assigned object is agile
|
|
m_fAgile = ViperCoObjectAggregatesFTM(m_pDisp);
|
|
|
|
if (Glob(fTrackThreadingModel) && !m_fAgile)
|
|
{
|
|
// doesn't mean it really isn't. could be one of
|
|
// our objects marked as 'both'
|
|
CComponentObject *pObjCopyOf = NULL;
|
|
|
|
hr = CPageComponentManager::FindComponentWithoutContext
|
|
(
|
|
m_pDisp,
|
|
&pObjCopyOf
|
|
);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
m_fAgile = pObjCopyOf->FAgile();
|
|
}
|
|
|
|
// end of getting of agile flag from the original object
|
|
hr = S_OK; // even if object was not found
|
|
}
|
|
|
|
// Decide whether to use GIP and if invalid assignment
|
|
// Applies only to non-agile application objects
|
|
|
|
if (!m_fAgile && (m_csScope == csAppln || m_csScope == csSession))
|
|
{
|
|
if (!ViperCoObjectIsaProxy(m_pDisp) && (m_csScope == csAppln)) // deadlocking?
|
|
{
|
|
m_pDisp->Release();
|
|
m_pDisp = NULL;
|
|
VariantClear(&m_Variant);
|
|
hr = RPC_E_WRONG_THREAD; // to tell the caller the error
|
|
}
|
|
else
|
|
{
|
|
// use GIP
|
|
hr = ConvertToGIPCookie();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::ConvertToGIPCookie
|
|
|
|
Convert Object to be GIP cookie. Release all pointers
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::ConvertToGIPCookie()
|
|
{
|
|
Assert(m_pDisp); // has to have dispatch pointer
|
|
|
|
if (!FIsWinNT())
|
|
{
|
|
// No GIPs on Win95
|
|
// On Win95 everything is on the same thread
|
|
// -> it is ok for the objects stay as pointers
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD dwCookie = NULL_GIP_COOKIE;
|
|
HRESULT hr = g_GIPAPI.Register(m_pDisp, IID_IDispatch, &dwCookie);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
Assert(dwCookie != NULL_GIP_COOKIE);
|
|
|
|
// Release all pointeres
|
|
ReleaseAll();
|
|
|
|
// Store the cookie instead
|
|
m_dwGIPCookie = dwCookie;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::GetOnPageInfo
|
|
|
|
Query dispatch ids for OnStartPage and OnEndPage
|
|
Calls static QueryOnPageInfo
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::GetOnPageInfo()
|
|
{
|
|
Assert(m_pDisp);
|
|
|
|
HRESULT hr = QueryOnPageInfo(m_pDisp, &m_OnPageInfo);
|
|
|
|
if (SUCCEEDED(hr))
|
|
m_fOnPageInfoCached = TRUE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::GetAddRefdIDispatch
|
|
|
|
Get AddRef()'d Dispatch *
|
|
Handles the Global Interface Ole Cookies
|
|
|
|
Parameters:
|
|
Dispatch **ppdisp output
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::GetAddRefdIDispatch
|
|
(
|
|
IDispatch **ppdisp
|
|
)
|
|
{
|
|
Assert(ppdisp);
|
|
|
|
if (m_pDisp)
|
|
{
|
|
*ppdisp = m_pDisp;
|
|
(*ppdisp)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
// try to restore from cookie
|
|
if (m_dwGIPCookie != NULL_GIP_COOKIE)
|
|
{
|
|
// Even if IUnknown * needs to be returned,
|
|
// Ask for IDispatch *, because IDispatch * is the one
|
|
// that was put in by CoGetInterfaceFromGlobal()
|
|
|
|
HRESULT hr = g_GIPAPI.Get
|
|
(
|
|
m_dwGIPCookie,
|
|
IID_IDispatch,
|
|
(void **)ppdisp
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
return S_OK;
|
|
}
|
|
|
|
*ppdisp = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::GetAddRefdIUnknown
|
|
|
|
Get AddRef()'d IUnknown *
|
|
Handles the Global Interface Ole Cookies
|
|
|
|
Parameters:
|
|
IUnknown **ppunk output
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::GetAddRefdIUnknown
|
|
(
|
|
IUnknown **ppunk
|
|
)
|
|
{
|
|
Assert(ppunk);
|
|
|
|
if (m_pUnknown)
|
|
{
|
|
*ppunk = m_pUnknown;
|
|
(*ppunk)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
// Use IDispatch (from cookie)
|
|
|
|
IDispatch *pDisp = NULL;
|
|
if (SUCCEEDED(GetAddRefdIDispatch(&pDisp)))
|
|
{
|
|
*ppunk = pDisp; // IDispatch implements IUnknown
|
|
return S_OK;
|
|
}
|
|
|
|
*ppunk = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentObject::GetVariant
|
|
|
|
Get object's values as variant
|
|
Handles the Global Interface Ole Cookies
|
|
|
|
Parameters:
|
|
VARIANT *pVar [out] Variant filled in with object value
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentObject::GetVariant
|
|
(
|
|
VARIANT *pVar
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
VariantInit(pVar); // default variant empty
|
|
|
|
if (m_fVariant)
|
|
{
|
|
// already has variant
|
|
hr = VariantCopyInd(pVar, &m_Variant);
|
|
}
|
|
else if (m_pDisp)
|
|
{
|
|
// create variant from IDispatch*
|
|
m_pDisp->AddRef();
|
|
|
|
V_VT(pVar) = VT_DISPATCH;
|
|
V_DISPATCH(pVar) = m_pDisp;
|
|
}
|
|
else if (m_dwGIPCookie != NULL_GIP_COOKIE)
|
|
{
|
|
// create variant from cookie
|
|
IDispatch *pDisp = NULL;
|
|
hr = g_GIPAPI.Get(m_dwGIPCookie, IID_IDispatch, (void **)&pDisp);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
V_VT(pVar) = VT_DISPATCH;
|
|
V_DISPATCH(pVar) = pDisp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// nowhere to get the VARIANT value from
|
|
hr = E_POINTER;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
C P a g e O b j e c t
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
CPageObject::CPageObject
|
|
|
|
CPageObject constructor
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CPageObject::CPageObject()
|
|
: m_pDisp(NULL),
|
|
m_fStartPageCalled(FALSE), m_fEndPageCalled(FALSE)
|
|
{
|
|
}
|
|
|
|
#ifdef DBG
|
|
/*===================================================================
|
|
CPageObject::AssertValid
|
|
|
|
Test to make sure that this is currently correctly formed
|
|
and assert if it is not.
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
void CPageObject::AssertValid() const
|
|
{
|
|
Assert(m_pDisp);
|
|
}
|
|
#endif
|
|
|
|
/*===================================================================
|
|
CPageObject::~CPageObject
|
|
|
|
CPageObject destructor
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CPageObject::~CPageObject()
|
|
{
|
|
// Release interface pointer
|
|
if (m_pDisp)
|
|
{
|
|
m_pDisp->Release();
|
|
m_pDisp = NULL;
|
|
}
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageObject::Init
|
|
|
|
Initialize CLinkElem portion with the IDispatch pointer
|
|
Needed to implement string hash
|
|
|
|
Parameters:
|
|
IDispatch *pDisp dispatch pointer (AddRef()ed)
|
|
COnPageInfo *pOnPageInfo OnStartPage, OnEndPage Ids
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageObject::Init
|
|
(
|
|
IDispatch *pDisp,
|
|
const COnPageInfo &OnPageInfo
|
|
)
|
|
{
|
|
Assert(pDisp);
|
|
|
|
m_pDisp = pDisp;
|
|
m_OnPageInfo = OnPageInfo;
|
|
|
|
m_fStartPageCalled = FALSE;
|
|
m_fEndPageCalled = FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageObject::InvokeMethod
|
|
|
|
Invokes OnPageStart() or OnPageEnd()
|
|
|
|
Parameters:
|
|
DWORD iMethod which method
|
|
CScriptingContext *pContext scripting context (for OnStart)
|
|
CHitObj *pHitObj HitObj for errors
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageObject::InvokeMethod
|
|
(
|
|
DWORD iMethod,
|
|
CScriptingContext *pContext,
|
|
CHitObj *pHitObj
|
|
)
|
|
{
|
|
BOOL fOnStart = (iMethod == ONPAGEINFO_ONSTARTPAGE);
|
|
|
|
// check if method exists
|
|
if (m_OnPageInfo.m_rgDispIds[iMethod] == DISPID_UNKNOWN)
|
|
return S_OK;
|
|
|
|
// two OnStart in a row - BAD
|
|
Assert(!(fOnStart && m_fStartPageCalled));
|
|
|
|
// two OnEnd in a row - BAD
|
|
Assert(!(!fOnStart && m_fEndPageCalled));
|
|
|
|
Assert(m_pDisp);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (Glob(fExceptionCatchEnable))
|
|
{
|
|
// Call method inside TRY CATCH
|
|
TRY
|
|
hr = TryInvokeMethod
|
|
(
|
|
m_OnPageInfo.m_rgDispIds[iMethod],
|
|
fOnStart,
|
|
pContext,
|
|
pHitObj
|
|
);
|
|
CATCH(nExcept)
|
|
if (fOnStart)
|
|
ExceptionId
|
|
(
|
|
IID_IObjectCover,
|
|
IDE_COVER,
|
|
IDE_COVER_ON_START_PAGE_GPF
|
|
);
|
|
else
|
|
HandleErrorMissingFilename
|
|
(
|
|
IDE_COVER_ON_END_PAGE_GPF,
|
|
pHitObj
|
|
);
|
|
hr = E_UNEXPECTED;
|
|
END_TRY
|
|
}
|
|
else
|
|
{
|
|
// don't CATCH
|
|
hr = TryInvokeMethod
|
|
(
|
|
m_OnPageInfo.m_rgDispIds[iMethod],
|
|
fOnStart,
|
|
pContext,
|
|
pHitObj
|
|
);
|
|
}
|
|
|
|
if (fOnStart)
|
|
m_fStartPageCalled = TRUE;
|
|
else
|
|
m_fEndPageCalled = TRUE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageObject::TryInvokeMethod
|
|
|
|
Invokes OnPageStart() or OnPageEnd()
|
|
|
|
Parameters:
|
|
DISPID DispId method's DISPID
|
|
BOOL fOnStart TRUE if invoking OnStart
|
|
IDispatch *pDispContext scripting context (for OnStart)
|
|
CHitObj *pHitObj HitObj for errors
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageObject::TryInvokeMethod
|
|
(
|
|
DISPID DispId,
|
|
BOOL fOnStart,
|
|
IDispatch *pDispContext,
|
|
CHitObj *pHitObj
|
|
)
|
|
{
|
|
EXCEPINFO ExcepInfo;
|
|
DISPPARAMS DispParams;
|
|
VARIANT varResult;
|
|
VARIANT varParam;
|
|
UINT nArgErr;
|
|
|
|
memset(&DispParams, 0, sizeof(DISPPARAMS));
|
|
memset(&ExcepInfo, 0, sizeof(EXCEPINFO));
|
|
|
|
if (fOnStart)
|
|
{
|
|
VariantInit(&varParam);
|
|
V_VT(&varParam) = VT_DISPATCH;
|
|
V_DISPATCH(&varParam) = pDispContext;
|
|
|
|
DispParams.rgvarg = &varParam;
|
|
DispParams.cArgs = 1;
|
|
}
|
|
|
|
VariantInit(&varResult);
|
|
|
|
// Invoke it
|
|
|
|
HRESULT hr = m_pDisp->Invoke
|
|
(
|
|
DispId, // Call method
|
|
IID_NULL, // REFIID - Reserved, must be NULL
|
|
NULL, // Locale id
|
|
DISPATCH_METHOD, // Calling a method, not a property
|
|
&DispParams, // pass arguments
|
|
&varResult, // return value
|
|
&ExcepInfo, // exeption info on failure
|
|
&nArgErr
|
|
);
|
|
|
|
// Ignore errors indicating that this method doesnt exist.
|
|
if (FAILED(hr))
|
|
{
|
|
if (hr == E_NOINTERFACE ||
|
|
hr == DISP_E_MEMBERNOTFOUND ||
|
|
hr == DISP_E_UNKNOWNNAME)
|
|
{
|
|
// the above errors really aren't
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NOTE: The OnStartPage method is always called while the
|
|
* script is running, so we use ExceptionId and let the
|
|
* scripting engine report the error. OnEndPage is always
|
|
* called after the engine is gone, so we use HandleError.
|
|
*/
|
|
if (FAILED(hr))
|
|
{
|
|
if (ExcepInfo.bstrSource && ExcepInfo.bstrDescription)
|
|
{
|
|
// User supplied error
|
|
Exception
|
|
(
|
|
IID_IObjectCover,
|
|
ExcepInfo.bstrSource,
|
|
ExcepInfo.bstrDescription
|
|
);
|
|
}
|
|
else if (fOnStart)
|
|
{
|
|
// Standard on-start error
|
|
ExceptionId
|
|
(
|
|
IID_IObjectCover,
|
|
IDE_COVER,
|
|
IDE_COVER_ON_START_PAGE_FAILED,
|
|
hr
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Standard on-end error
|
|
HandleErrorMissingFilename
|
|
(
|
|
IDE_COVER_ON_END_PAGE_FAILED,
|
|
pHitObj
|
|
);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
C C o m p o n e n t C o l l e c t i o n
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
CComponentCollection::CComponentCollection
|
|
|
|
CComponentCollection constructor
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CComponentCollection::CComponentCollection()
|
|
:
|
|
m_csScope(csUnknown),
|
|
m_fUseTaggedArray(FALSE), m_fUsePropArray(FALSE),
|
|
m_fHasComProperties(FALSE),
|
|
m_cAllTagged(0), m_cInstTagged(0),
|
|
m_cProperties(0), m_cUnnamed(0),
|
|
m_pCompFirst(NULL)
|
|
{
|
|
}
|
|
|
|
#ifdef DBG
|
|
/*===================================================================
|
|
CComponentCollection::AssertValid
|
|
|
|
Test to make sure that this is currently correctly formed
|
|
and assert if it is not.
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
void CComponentCollection::AssertValid() const
|
|
{
|
|
Assert(m_csScope != csUnknown);
|
|
m_htTaggedObjects.AssertValid();
|
|
m_htTaggedObjects.AssertValid();
|
|
m_htidIUnknownPtrs.AssertValid();
|
|
}
|
|
#endif
|
|
|
|
/*===================================================================
|
|
CComponentCollection::~CComponentCollection
|
|
|
|
CComponentCollection destructor
|
|
Deletes all the objects
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CComponentCollection::~CComponentCollection()
|
|
{
|
|
UnInit();
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::Init
|
|
|
|
Sets collection scope
|
|
Initializes hash tables
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::Init
|
|
(
|
|
CompScope scScope
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
m_csScope = scScope;
|
|
|
|
hr = m_htTaggedObjects.Init(HT_TAGGED_OBJECTS_BUCKETS_MAX);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = m_htProperties.Init(HT_PROPERTIES_BUCKETS_MAX);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = m_htidIUnknownPtrs.Init(HT_IUNKNOWN_PTRS_BUCKETS_MAX);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::UnInit
|
|
|
|
Deletes all the objects
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
S_OK
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::UnInit()
|
|
{
|
|
// clear out pointer arrays
|
|
m_rgpvTaggedObjects.Clear();
|
|
m_rgpvProperties.Clear();
|
|
m_fUseTaggedArray = FALSE;
|
|
m_fUsePropArray = FALSE;
|
|
|
|
// clear out name hash tables
|
|
m_htTaggedObjects.UnInit();
|
|
m_htProperties.UnInit();
|
|
|
|
// clear out pointers hash table
|
|
m_htidIUnknownPtrs.UnInit();
|
|
|
|
// delete all member component objects
|
|
if (m_pCompFirst)
|
|
{
|
|
CComponentObject *pObj = m_pCompFirst;
|
|
while (pObj)
|
|
{
|
|
CComponentObject *pNext = pObj->m_pCompNext;
|
|
delete pObj;
|
|
pObj = pNext;
|
|
}
|
|
m_pCompFirst = NULL;
|
|
}
|
|
|
|
// reset the counters
|
|
m_cAllTagged = 0;
|
|
m_cInstTagged = 0;
|
|
m_cProperties = 0;
|
|
m_cUnnamed = 0;
|
|
m_fHasComProperties = FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::AddComponentToNameHash
|
|
|
|
Adds an object to the proper hash table
|
|
|
|
Parameters:
|
|
CComponentObject *pObj object to add
|
|
LPWSTR pwszName object's name (hash)
|
|
DWORD cbName name length in bytes
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::AddComponentToNameHash
|
|
(
|
|
CComponentObject *pObj,
|
|
LPWSTR pwszName,
|
|
DWORD cbName
|
|
)
|
|
{
|
|
Assert(pwszName);
|
|
Assert(cbName == (wcslen(pwszName) * sizeof(WCHAR)));
|
|
|
|
// determine which hash table
|
|
CHashTableStr *pHashTable;
|
|
|
|
if (pObj->m_ctType == ctTagged)
|
|
pHashTable = &m_htTaggedObjects;
|
|
else if (pObj->m_ctType == ctProperty)
|
|
pHashTable = &m_htProperties;
|
|
else
|
|
return S_OK; // nowhere to add, OK
|
|
|
|
// Initialize object's CLinkElem
|
|
HRESULT hr = pObj->Init(pwszName, cbName);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Add to hash table
|
|
CLinkElem *pAddedElem = pHashTable->AddElem(pObj);
|
|
if (!pAddedElem)
|
|
return E_FAIL; // couldn't add
|
|
|
|
if (pObj != static_cast<CComponentObject *>(pAddedElem))
|
|
return E_FAIL; // another object with the same name
|
|
// already there
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::AddComponentToPtrHash
|
|
|
|
Adds an object to the IUnkown * hash table
|
|
|
|
Parameters:
|
|
CComponentObject *pObj object to add
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::AddComponentToPtrHash
|
|
(
|
|
CComponentObject *pObj
|
|
)
|
|
{
|
|
// If we don't track the threading model, we don't care
|
|
// to add objects to cache by IUnknown * - no need to look them up
|
|
if (!Glob(fTrackThreadingModel))
|
|
return S_OK;
|
|
|
|
void *ptr = pObj->m_pUnknown;
|
|
if (!ptr)
|
|
return S_OK; // uninstatiated
|
|
|
|
if (FAILED(m_htidIUnknownPtrs.AddObject((DWORD_PTR)ptr, pObj)))
|
|
return E_FAIL;
|
|
|
|
pObj->m_fInPtrCache = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
ComponentCollection::FindComponentObjectByName
|
|
|
|
Find tagged object by name
|
|
|
|
Parameters:
|
|
LPWSTR pwszName object's name
|
|
DWORD cbName name length
|
|
CComponentObject **ppObj found object
|
|
|
|
Returns:
|
|
HRESULT
|
|
(S_FALSE if no error - not found)
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::FindComponentObjectByName
|
|
(
|
|
LPWSTR pwszName,
|
|
DWORD cbName,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
Assert(pwszName);
|
|
Assert(cbName == (wcslen(pwszName) * sizeof(WCHAR)));
|
|
|
|
CLinkElem *pElem = m_htTaggedObjects.FindElem(pwszName, cbName);
|
|
if (!pElem)
|
|
{
|
|
*ppObj = NULL;
|
|
return S_FALSE;
|
|
}
|
|
|
|
*ppObj = static_cast<CComponentObject *>(pElem);
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
ComponentCollection::FindComponentPropertyByName
|
|
|
|
Find property by name
|
|
|
|
Parameters:
|
|
LPWSTR pwszName object's name
|
|
DWORD cbName name length
|
|
CComponentObject **ppObj found object
|
|
|
|
Returns:
|
|
HRESULT
|
|
(S_FALSE if no error - not found)
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::FindComponentPropertyByName
|
|
(
|
|
LPWSTR pwszName,
|
|
DWORD cbName,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
Assert(pwszName);
|
|
Assert(cbName == (wcslen(pwszName) * sizeof(WCHAR)));
|
|
|
|
CLinkElem *pElem = m_htProperties.FindElem(pwszName, cbName);
|
|
if (!pElem)
|
|
{
|
|
*ppObj = NULL;
|
|
return S_FALSE;
|
|
}
|
|
|
|
*ppObj = static_cast<CComponentObject *>(pElem);
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
ComponentCollection::FindComponentByIUnknownPtr
|
|
|
|
Find property by IUnknown *
|
|
|
|
Parameters:
|
|
IUnknown *pUnk find by this pointer
|
|
CComponentObject **ppObj found object
|
|
|
|
Returns:
|
|
HRESULT
|
|
(S_FALSE if no error - not found)
|
|
===================================================================*/
|
|
|
|
HRESULT CComponentCollection::FindComponentByIUnknownPtr
|
|
(
|
|
IUnknown *pUnk,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
void *pv;
|
|
if (m_htidIUnknownPtrs.FindObject((DWORD_PTR)pUnk, &pv) != S_OK)
|
|
{
|
|
*ppObj = NULL;
|
|
return S_FALSE;
|
|
}
|
|
|
|
*ppObj = reinterpret_cast<CComponentObject *>(pv);
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::AddTagged
|
|
|
|
Adds a tagged object to the collection. Does not instanciate it yet.
|
|
|
|
Parameters:
|
|
LPWSTR pwszName Object name
|
|
CLSID &ClsId Class ID
|
|
CompModel cmModel Object model
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::AddTagged
|
|
(
|
|
LPWSTR pwszName,
|
|
const CLSID &ClsId,
|
|
CompModel cmModel
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD cbName = CbWStr(pwszName); // do strlen once
|
|
|
|
if (m_htTaggedObjects.FindElem(pwszName, cbName))
|
|
return E_FAIL; // duplicate name
|
|
|
|
CComponentObject *pObj = new CComponentObject
|
|
(
|
|
m_csScope,
|
|
ctTagged,
|
|
cmModel
|
|
);
|
|
|
|
if (pObj == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pObj->m_ClsId = ClsId;
|
|
|
|
hr = AddComponentToList(pObj);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = AddComponentToNameHash(pObj, pwszName, cbName);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (m_fUseTaggedArray)
|
|
m_rgpvTaggedObjects.Append(pObj);
|
|
|
|
m_cAllTagged++;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::AddProperty
|
|
|
|
Adds a property object to the collection.
|
|
If property with the same name exists, it changes the value
|
|
|
|
Parameters:
|
|
LPWSTR pwszName Object name
|
|
VARIANT pVariant Property value
|
|
CComponentObject **ppObj [out] Property object could
|
|
be NULL if not requested
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::AddProperty
|
|
(
|
|
LPWSTR pwszName,
|
|
VARIANT *pVariant,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
if (ppObj)
|
|
*ppObj = NULL;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CComponentObject *pObj = NULL;
|
|
|
|
DWORD cbName = CbWStr(pwszName); // do strlen once
|
|
|
|
// Find the existing object first
|
|
CLinkElem *pElem = m_htProperties.FindElem(pwszName, cbName);
|
|
|
|
if (pElem)
|
|
{
|
|
// Object already exists - use it
|
|
pObj = static_cast<CComponentObject *>(pElem);
|
|
Assert(pObj->m_ctType == ctProperty);
|
|
|
|
// Clear out the object from any data
|
|
hr = pObj->Clear();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Reinitialize object
|
|
pObj->m_csScope = m_csScope;
|
|
pObj->m_ctType = ctProperty;
|
|
pObj->m_cmModel = cmUnknown;
|
|
}
|
|
else
|
|
{
|
|
// Create new object
|
|
pObj = new CComponentObject(m_csScope, ctProperty, cmUnknown);
|
|
if (pObj == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Add the object to the list
|
|
hr = AddComponentToList(pObj);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Add the object to the hash
|
|
hr = AddComponentToNameHash(pObj, pwszName, cbName);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Add to properties array if needed
|
|
if (m_fUsePropArray)
|
|
m_rgpvProperties.Append(pObj);
|
|
|
|
m_cProperties++;
|
|
}
|
|
|
|
// Assign value
|
|
hr = pObj->SetPropertyValue(pVariant);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// check if simple variant
|
|
if (!FIsSimpleVariant(&pObj->m_Variant))
|
|
m_fHasComProperties = TRUE;
|
|
}
|
|
|
|
// Return object ptr if requested
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (ppObj)
|
|
*ppObj = pObj;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::AddUnnamed
|
|
|
|
Add object to be instantiated using Server.CreateObject
|
|
|
|
Parameters:
|
|
CLSID &ClsId Class ID
|
|
CompModel cmModel Object model
|
|
CComponentObject **ppObj Object Added
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::AddUnnamed
|
|
(
|
|
const CLSID &ClsId,
|
|
CompModel cmModel,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (cmModel == cmUnknown)
|
|
{
|
|
hr = CompModelFromCLSID(ClsId, &cmModel);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
CComponentObject *pObj = new CComponentObject
|
|
(
|
|
m_csScope,
|
|
ctUnnamed,
|
|
cmModel
|
|
);
|
|
|
|
if (pObj == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pObj->m_ClsId = ClsId;
|
|
|
|
hr = AddComponentToList(pObj);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
*ppObj = pObj;
|
|
m_cUnnamed++;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::GetTagged
|
|
|
|
Finds tagged object by name
|
|
|
|
Parameters:
|
|
LPWSTR pwszName Object name
|
|
CComponentObject **ppObj [out] Object Found
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::GetTagged
|
|
(
|
|
LPWSTR pwszName,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
Assert(ppObj);
|
|
*ppObj = NULL;
|
|
|
|
CComponentObject *pObj = NULL;
|
|
HRESULT hr = FindComponentObjectByName
|
|
(
|
|
pwszName,
|
|
CbWStr(pwszName),
|
|
&pObj
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (pObj && pObj->m_ctType != ctTagged)
|
|
pObj = NULL;
|
|
|
|
if (pObj)
|
|
*ppObj = pObj;
|
|
else
|
|
hr = TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::GetProperty
|
|
|
|
Finds property object by name
|
|
|
|
Parameters:
|
|
LPWSTR pwszName Property name
|
|
CComponentObject **ppObj [out] Object Found
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::GetProperty
|
|
(
|
|
LPWSTR pwszName,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
Assert(ppObj);
|
|
*ppObj = NULL;
|
|
|
|
CComponentObject *pObj = NULL;
|
|
HRESULT hr = FindComponentPropertyByName
|
|
(
|
|
pwszName,
|
|
CbWStr(pwszName),
|
|
&pObj
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (pObj)
|
|
*ppObj = pObj;
|
|
else
|
|
hr = TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::GetNameByIndex
|
|
|
|
Find name of a tagged objects or property by index
|
|
|
|
Parameters:
|
|
CompType ctType tagged or property
|
|
int index index (1-based)
|
|
LPWSTR *ppwszName [out] name (NOT allocated)
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::GetNameByIndex
|
|
(
|
|
CompType ctType,
|
|
int index,
|
|
LPWSTR *ppwszName
|
|
)
|
|
{
|
|
CPtrArray *pPtrArray;
|
|
|
|
if (ctType == ctTagged)
|
|
{
|
|
if (!m_fUseTaggedArray)
|
|
StartUsingTaggedObjectsArray();
|
|
pPtrArray = &m_rgpvTaggedObjects;
|
|
}
|
|
else if (ctType == ctProperty)
|
|
{
|
|
if (!m_fUsePropArray)
|
|
StartUsingPropertiesArray();
|
|
pPtrArray = &m_rgpvProperties;
|
|
}
|
|
else
|
|
{
|
|
Assert(FALSE);
|
|
*ppwszName = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (index >= 1 && index <= pPtrArray->Count())
|
|
{
|
|
CComponentObject *pObj = (CComponentObject *)pPtrArray->Get(index-1);
|
|
if (pObj)
|
|
{
|
|
Assert(pObj->GetType() == ctType);
|
|
*ppwszName = pObj->GetName();
|
|
if (*ppwszName)
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
*ppwszName = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::RemoveComponent
|
|
|
|
Remove a known component.
|
|
Slow method for a non-recent objects.
|
|
|
|
Parameters:
|
|
CComponentObject *pObj -- object to remove
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::RemoveComponent
|
|
(
|
|
CComponentObject *pObj
|
|
)
|
|
{
|
|
Assert(pObj);
|
|
|
|
// Remove from by-name hash tables and arrays
|
|
if (pObj->m_ctType == ctTagged)
|
|
{
|
|
// tagged cannot be removed
|
|
Assert(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
else if (pObj->m_ctType == ctProperty)
|
|
{
|
|
// hash table
|
|
if (m_htProperties.DeleteElem(pObj->GetName(), CbWStr(pObj->GetName())))
|
|
{
|
|
m_cProperties--;
|
|
}
|
|
|
|
// array
|
|
if (m_fUsePropArray)
|
|
{
|
|
m_rgpvProperties.Remove(pObj);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert(pObj->m_ctType == ctUnnamed);
|
|
m_cUnnamed--;
|
|
}
|
|
|
|
// Remove from the 'by pointer hash table'
|
|
if (pObj->m_fInPtrCache)
|
|
{
|
|
void *ptr = pObj->m_pUnknown;
|
|
if (ptr)
|
|
m_htidIUnknownPtrs.RemoveObject((DWORD_PTR)ptr);
|
|
pObj->m_fInPtrCache = FALSE;
|
|
}
|
|
|
|
// Remove from the list
|
|
RemoveComponentFromList(pObj);
|
|
|
|
// Remove
|
|
delete pObj;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::RemovePropery
|
|
|
|
Remove a property by name.
|
|
|
|
Parameters:
|
|
LPWSTR pwszName -- property name
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::RemoveProperty
|
|
(
|
|
LPWSTR pwszName
|
|
)
|
|
{
|
|
CComponentObject *pObj = NULL;
|
|
HRESULT hr = FindComponentPropertyByName
|
|
(
|
|
pwszName,
|
|
CbWStr(pwszName),
|
|
&pObj
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (pObj)
|
|
hr = RemoveComponent(pObj);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::RemoveAllProperties
|
|
|
|
Remove all properties. Faster than iterating.
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::RemoveAllProperties()
|
|
{
|
|
// Clear out the properties array
|
|
if (m_fUsePropArray)
|
|
{
|
|
m_rgpvProperties.Clear();
|
|
m_fUsePropArray = FALSE;
|
|
}
|
|
|
|
// Walk the object list to remove properties
|
|
CComponentObject *pObj = m_pCompFirst;
|
|
while (pObj)
|
|
{
|
|
CComponentObject *pNextObj = pObj->m_pCompNext;
|
|
|
|
if (pObj->m_ctType == ctProperty)
|
|
{
|
|
// remove from the hash table
|
|
m_htProperties.DeleteElem(pObj->GetName(), CbWStr(pObj->GetName()));
|
|
// properties are not in the 'by pointer hash table'
|
|
Assert(!pObj->m_fInPtrCache);
|
|
// remove from the list
|
|
RemoveComponentFromList(pObj);
|
|
// remove
|
|
delete pObj;
|
|
}
|
|
|
|
pObj = pNextObj;
|
|
}
|
|
|
|
m_cProperties = 0;
|
|
m_fHasComProperties = FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::StartUsingTaggedObjectsArray
|
|
|
|
Fill in the tagged objects array for access by index for the
|
|
first time
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::StartUsingTaggedObjectsArray()
|
|
{
|
|
if (m_fUseTaggedArray)
|
|
return S_OK;
|
|
|
|
m_rgpvTaggedObjects.Clear();
|
|
|
|
CComponentObject *pObj = m_pCompFirst;
|
|
while (pObj)
|
|
{
|
|
if (pObj->GetType() == ctTagged)
|
|
m_rgpvTaggedObjects.Append(pObj);
|
|
pObj = pObj->m_pCompNext;
|
|
}
|
|
|
|
m_fUseTaggedArray = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentCollection::StartUsingPropertiesArray
|
|
|
|
Fill in the properties array for access by index for the
|
|
first time
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentCollection::StartUsingPropertiesArray()
|
|
{
|
|
if (m_fUsePropArray)
|
|
return S_OK;
|
|
|
|
m_rgpvProperties.Clear();
|
|
|
|
CComponentObject *pObj = m_pCompFirst;
|
|
while (pObj)
|
|
{
|
|
if (pObj->GetType() == ctProperty)
|
|
m_rgpvProperties.Prepend(pObj); // backwards
|
|
pObj = pObj->m_pCompNext;
|
|
}
|
|
|
|
m_fUsePropArray = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
C P a g e C o m p o n e n t M a n a g e r
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::CPageComponentManager
|
|
|
|
CPageComponentManager constructor
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CPageComponentManager::CPageComponentManager()
|
|
: m_pHitObj(NULL)
|
|
{
|
|
}
|
|
|
|
#ifdef DBG
|
|
/*===================================================================
|
|
CPageComponentManager::AssertValid()
|
|
|
|
Test to make sure that this is currently correctly formed
|
|
and assert if it is not.
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
void CPageComponentManager::AssertValid() const
|
|
{
|
|
Assert(m_pHitObj);
|
|
m_pHitObj->AssertValid();
|
|
m_htidPageObjects.AssertValid();
|
|
}
|
|
#endif
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::~CPageComponentManager
|
|
|
|
CPageComponentManager destructor
|
|
Deletes all page objects
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CPageComponentManager::~CPageComponentManager()
|
|
{
|
|
// delete all page objects
|
|
m_htidPageObjects.IterateObjects(DeletePageObjectCB);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::DeletePageObjectCB
|
|
|
|
Static callback from hash table iterator to delete a CPageObject
|
|
|
|
Parameters:
|
|
pvObj CPageObject* to delete passed as void*
|
|
|
|
Returns:
|
|
iccContinue
|
|
===================================================================*/
|
|
IteratorCallbackCode CPageComponentManager::DeletePageObjectCB
|
|
(
|
|
void *pvObj,
|
|
void *,
|
|
void *
|
|
)
|
|
{
|
|
Assert(pvObj);
|
|
CPageObject *pObj = reinterpret_cast<CPageObject *>(pvObj);
|
|
delete pObj;
|
|
return iccContinue;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::Init
|
|
|
|
Sets collection scope (to page)
|
|
Initializes hash tables
|
|
|
|
Parameters:
|
|
CHitObj *pHitObj this page
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::Init
|
|
(
|
|
CHitObj *pHitObj
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Init hash table of Page Objects
|
|
hr = m_htidPageObjects.Init(HT_PAGE_OBJECTS_BUCKETS_MAX);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// remember pHitObj
|
|
m_pHitObj = pHitObj;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::OnStartPage
|
|
|
|
Adds new page object. Ignores objects withount page info
|
|
(OnEndPage is done for all objects at the end of page)
|
|
|
|
Parameters:
|
|
CComponentObject *pCompObj object to do OnStartPage
|
|
CScriptingContext *pContext arg to OnStart
|
|
COnPageInfo *pOnPageInfo pre-queried ids (optional)
|
|
BOOL *pfStarted returned flag
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::OnStartPage
|
|
(
|
|
CComponentObject *pCompObj,
|
|
CScriptingContext *pContext,
|
|
const COnPageInfo *pOnPageInfo,
|
|
BOOL *pfStarted
|
|
)
|
|
{
|
|
IDispatch *pDisp = pCompObj->m_pDisp;
|
|
HRESULT hr = S_OK;
|
|
|
|
if(pDisp == NULL)
|
|
{
|
|
Assert(pCompObj->m_dwGIPCookie != NULL_GIP_COOKIE);
|
|
// try to restore from cookie
|
|
hr = g_GIPAPI.Get
|
|
(
|
|
pCompObj->m_dwGIPCookie,
|
|
IID_IDispatch,
|
|
(void **)&pDisp
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
else
|
|
pDisp->AddRef();
|
|
|
|
Assert(pDisp);
|
|
|
|
Assert(pfStarted);
|
|
*pfStarted = FALSE;
|
|
|
|
// check if onpageinfo passed and the methods aren't defined
|
|
if (pOnPageInfo && !pOnPageInfo->FHasAnyMethod())
|
|
{
|
|
pDisp->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
// check if already in the PageObject Hash
|
|
if (m_htidPageObjects.FindObject((DWORD_PTR)pDisp) == S_OK)
|
|
{
|
|
pDisp->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
COnPageInfo OnPageInfo;
|
|
|
|
if (pOnPageInfo)
|
|
{
|
|
OnPageInfo = *pOnPageInfo;
|
|
}
|
|
else
|
|
{
|
|
// dynamically create OnPageInfo if not passed
|
|
if (Glob(fExceptionCatchEnable))
|
|
{
|
|
TRY
|
|
hr = QueryOnPageInfo(pDisp, &OnPageInfo);
|
|
CATCH(nExcept)
|
|
HandleErrorMissingFilename(IDE_SCRIPT_OBJ_ONPAGE_QI_FAILED,
|
|
m_pHitObj,
|
|
TRUE,
|
|
pCompObj->GetName(),
|
|
nExcept);
|
|
hr = nExcept;
|
|
END_TRY
|
|
}
|
|
else
|
|
{
|
|
hr = QueryOnPageInfo(pDisp, &OnPageInfo);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pDisp->Release();
|
|
return hr;
|
|
}
|
|
|
|
// check if any of the methods is defined
|
|
if (!OnPageInfo.FHasAnyMethod())
|
|
{
|
|
pDisp->Release();
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// create object
|
|
CPageObject *pPageObj = new CPageObject;
|
|
if (!pPageObj)
|
|
{
|
|
pDisp->Release();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// init LinkElem
|
|
hr = pPageObj->Init(pDisp, OnPageInfo); // this eats our previous AddRef()
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// add to hash table
|
|
hr = m_htidPageObjects.AddObject((DWORD_PTR)pDisp, pPageObj);
|
|
}
|
|
|
|
// cleanup if failed
|
|
if (FAILED(hr) && pPageObj)
|
|
{
|
|
pDisp->Release(); // Init failed, so remove our AddRef()
|
|
delete pPageObj;
|
|
return hr;
|
|
}
|
|
|
|
*pfStarted = TRUE;
|
|
|
|
return pPageObj->InvokeMethod
|
|
(
|
|
ONPAGEINFO_ONSTARTPAGE,
|
|
pContext,
|
|
m_pHitObj
|
|
);
|
|
}
|
|
|
|
/*===================================================================
|
|
PageComponentManager::OnEndPageAllObjects
|
|
|
|
Does OnEndPage() for all objects that need it
|
|
(OnStartPage() is on demand basis)
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::OnEndPageAllObjects()
|
|
{
|
|
HRESULT hrGlobal = S_OK;
|
|
|
|
m_htidPageObjects.IterateObjects
|
|
(
|
|
OnEndPageObjectCB,
|
|
m_pHitObj,
|
|
&hrGlobal
|
|
);
|
|
|
|
return hrGlobal;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::OnEndPageObjectCB
|
|
|
|
Static callback from hash table iterator to execute OnEndPage
|
|
for a CPageObject
|
|
|
|
Parameters:
|
|
pvObj CPageObject* to delete passed as void*
|
|
|
|
Returns:
|
|
iccContinue
|
|
===================================================================*/
|
|
IteratorCallbackCode CPageComponentManager::OnEndPageObjectCB
|
|
(
|
|
void *pvObj,
|
|
void *pvHitObj,
|
|
void *pvhr
|
|
)
|
|
{
|
|
Assert(pvObj);
|
|
Assert(pvHitObj);
|
|
Assert(pvhr);
|
|
|
|
CPageObject *pObj = reinterpret_cast<CPageObject *>(pvObj);
|
|
|
|
HRESULT hr = pObj->InvokeMethod
|
|
(
|
|
ONPAGEINFO_ONENDPAGE,
|
|
NULL,
|
|
reinterpret_cast<CHitObj *>(pvHitObj)
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
*(reinterpret_cast<HRESULT *>(pvhr)) = hr;
|
|
|
|
return iccContinue;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::GetPageCollection
|
|
|
|
Queries HitObj for the Page's Component Collection
|
|
|
|
Parameters:
|
|
CComponentCollection **ppCollection (out)
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::GetPageCollection
|
|
(
|
|
CComponentCollection **ppCollection
|
|
)
|
|
{
|
|
Assert(m_pHitObj);
|
|
|
|
*ppCollection = NULL;
|
|
|
|
return m_pHitObj->GetPageComponentCollection(ppCollection);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::GetSessionCollection
|
|
|
|
Queries HitObj for the Session's Component Collection
|
|
|
|
Parameters:
|
|
CComponentCollection **ppCollection (out)
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::GetSessionCollection
|
|
(
|
|
CComponentCollection **ppCollection
|
|
)
|
|
{
|
|
Assert(m_pHitObj);
|
|
|
|
*ppCollection = NULL;
|
|
|
|
return m_pHitObj->GetSessionComponentCollection(ppCollection);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::GetApplnCollection
|
|
|
|
Queries HitObj for the Application's Component Collection
|
|
|
|
Parameters:
|
|
CComponentCollection **ppCollection (out)
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::GetApplnCollection
|
|
(
|
|
CComponentCollection **ppCollection
|
|
)
|
|
{
|
|
Assert(m_pHitObj);
|
|
|
|
*ppCollection = NULL;
|
|
|
|
return m_pHitObj->GetApplnComponentCollection(ppCollection);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::GetCollectionByScope
|
|
|
|
Gets the collection corresponding to the scope
|
|
|
|
Parameters:
|
|
CompScope csScope (in) desired scope
|
|
CComponentCollection **ppCollection (out)
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::GetCollectionByScope
|
|
(
|
|
CompScope scScope,
|
|
CComponentCollection **ppCollection
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (scScope)
|
|
{
|
|
case csPage:
|
|
hr = GetPageCollection(ppCollection);
|
|
break;
|
|
case csSession:
|
|
hr = GetSessionCollection(ppCollection);
|
|
break;
|
|
case csAppln:
|
|
hr = GetApplnCollection(ppCollection);
|
|
break;
|
|
default:
|
|
hr = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
*ppCollection = NULL;
|
|
else if (*ppCollection == NULL)
|
|
hr = E_POINTER; // to make sure we fail if no collection
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::FindScopedComponentByName
|
|
|
|
Finds object by name. Searches multiple collections if
|
|
the scope is unknown.
|
|
Internal private method used in GetScoped...()
|
|
|
|
Parameters:
|
|
CompScope csScope Scope (could be csUnknown)
|
|
LPWSTR pwszName Object name
|
|
DWORD cbName name length
|
|
BOOL fProperty TRUE = property,
|
|
FALSE = tagged
|
|
|
|
CComponentObject **ppObj (out) Object found
|
|
CComponentCollection **ppCollection (out) Collection where found
|
|
(optional)
|
|
|
|
Returns:
|
|
HRESULT
|
|
(S_FALSE if no error - not found)
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::FindScopedComponentByName
|
|
(
|
|
CompScope csScope,
|
|
LPWSTR pwszName,
|
|
DWORD cbName,
|
|
BOOL fProperty,
|
|
CComponentObject **ppObj,
|
|
CComponentCollection **ppCollection
|
|
)
|
|
{
|
|
int cMaxTry = (csScope == csUnknown) ? 3 : 1;
|
|
int cTry = 0;
|
|
*ppObj = NULL;
|
|
|
|
while (*ppObj == NULL && cTry < cMaxTry)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComponentCollection *pCollection = NULL;
|
|
|
|
switch (++cTry)
|
|
{
|
|
case 1: // page (or explicit scope) first
|
|
if (csScope == csUnknown)
|
|
hr = GetPageCollection(&pCollection);
|
|
else // explicit scope
|
|
hr = GetCollectionByScope(csScope, &pCollection);
|
|
break;
|
|
case 2: // session
|
|
hr = GetSessionCollection(&pCollection);
|
|
break;
|
|
case 3: // application
|
|
hr = GetApplnCollection(&pCollection);
|
|
break;
|
|
}
|
|
if (FAILED(hr) || !pCollection)
|
|
continue; // couldn't get the collection
|
|
|
|
Assert(cbName == (wcslen(pwszName) * sizeof(WCHAR)));
|
|
|
|
// find the object
|
|
if (fProperty)
|
|
{
|
|
hr = pCollection->FindComponentPropertyByName
|
|
(
|
|
pwszName,
|
|
cbName,
|
|
ppObj
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hr = pCollection->FindComponentObjectByName
|
|
(
|
|
pwszName,
|
|
cbName,
|
|
ppObj
|
|
);
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
*ppObj = NULL;
|
|
|
|
// remember where found
|
|
if (*ppObj && ppCollection)
|
|
*ppCollection = pCollection;
|
|
}
|
|
|
|
return (*ppObj ? S_OK : S_FALSE);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::AddScopedTagged
|
|
|
|
Adds a tagged object to the collection. Does not instantiate it yet.
|
|
|
|
Parameters:
|
|
CompScope csScope Object scope (which collection)
|
|
LPWSTR pwszName Object name
|
|
CLSID &ClsId Class ID
|
|
CompModel cmModel Object model
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::AddScopedTagged
|
|
(
|
|
CompScope csScope,
|
|
LPWSTR pwszName,
|
|
const CLSID &ClsId,
|
|
CompModel cmModel
|
|
)
|
|
{
|
|
CComponentCollection *pCollection;
|
|
HRESULT hr = GetCollectionByScope(csScope, &pCollection);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
return pCollection->AddTagged(pwszName, ClsId, cmModel);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::AddScopedProperty
|
|
|
|
Adds a property object to the collection.
|
|
If property with the same name exists, it changes the value
|
|
|
|
Parameters:
|
|
CompScope csScope Object scope (which collection)
|
|
LPWSTR pwszName Object name
|
|
VARIANT pVariant Property value
|
|
CComponentObject **ppObj [out] Property object could
|
|
be NULL if not requested
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::AddScopedProperty
|
|
(
|
|
CompScope csScope,
|
|
LPWSTR pwszName,
|
|
VARIANT *pVariant,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
CComponentCollection *pCollection;
|
|
HRESULT hr = GetCollectionByScope(csScope, &pCollection);
|
|
if (FAILED(hr))
|
|
{
|
|
if (ppObj)
|
|
*ppObj = NULL;
|
|
return hr;
|
|
}
|
|
return pCollection->AddProperty(pwszName, pVariant, ppObj);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::AddScopedUnnamedInstantiated
|
|
|
|
Server.CreateObject
|
|
Also does OnStartPage (adds created pDisp as CPageObject)
|
|
|
|
Parameters:
|
|
csScope Object scope (which collection)
|
|
ClsId Class ID
|
|
cmModel Object model
|
|
pOnPageInfo DispIds for OnStartPage/OnEndPage (can be NULL)
|
|
ppObj [out] Object Added
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::AddScopedUnnamedInstantiated
|
|
(
|
|
CompScope csScope,
|
|
const CLSID &ClsId,
|
|
CompModel cmModel,
|
|
COnPageInfo *pOnPageInfo,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
CComponentCollection *pCollection;
|
|
HRESULT hr = GetCollectionByScope(csScope, &pCollection);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
hr = pCollection->AddUnnamed(ClsId, cmModel, ppObj);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CComponentObject *pObj = *ppObj;
|
|
|
|
// remember passed OnPageInfo
|
|
if (pOnPageInfo)
|
|
{
|
|
pObj->m_OnPageInfo = *pOnPageInfo;
|
|
pObj->m_fOnPageInfoCached = TRUE;
|
|
}
|
|
|
|
// create it
|
|
hr = pObj->Instantiate(m_pHitObj);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// add to pointer cash
|
|
pCollection->AddComponentToPtrHash(pObj);
|
|
|
|
// add as page object when needed
|
|
if (csScope == csPage
|
|
&& (pObj->m_pDisp || (pObj->m_dwGIPCookie != NULL_GIP_COOKIE))
|
|
&& m_pHitObj && m_pHitObj->FIsBrowserRequest())
|
|
{
|
|
BOOL fStarted = FALSE;
|
|
|
|
hr = OnStartPage
|
|
(
|
|
pObj,
|
|
m_pHitObj->PScriptingContextGet(),
|
|
pObj->GetCachedOnPageInfo(),
|
|
&fStarted
|
|
);
|
|
|
|
if (fStarted)
|
|
pObj->m_fOnPageStarted = TRUE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::GetScopedObjectInstantiated
|
|
|
|
Finds component object (tagged) by name.
|
|
Scope could be csUnknown.
|
|
Instantiates tagged objects.
|
|
Also does OnStartPage (adds created pDisp as CPageObject)
|
|
|
|
Parameters:
|
|
CompScope csScope Scope (could be csUnknown)
|
|
LPWSTR pwszName Object name
|
|
DWORD cbName Object name length (in bytes)
|
|
CComponentObject **ppObj Object found
|
|
BOOL *pfNewInstance [out] TRUE if just instantiated
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::GetScopedObjectInstantiated
|
|
(
|
|
CompScope csScope,
|
|
LPWSTR pwszName,
|
|
DWORD cbName,
|
|
CComponentObject **ppObj,
|
|
BOOL *pfNewInstance
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert(pfNewInstance);
|
|
*pfNewInstance = FALSE;
|
|
|
|
CComponentCollection *pCollection;
|
|
hr = FindScopedComponentByName
|
|
(
|
|
csScope,
|
|
pwszName,
|
|
cbName,
|
|
FALSE,
|
|
ppObj,
|
|
&pCollection
|
|
);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CComponentObject *pObj = *ppObj;
|
|
if (!pObj) // not failed, but not found either
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
if (pObj->m_ctType != ctTagged)
|
|
return S_OK;
|
|
|
|
// For tagged only - instantiate and do OnStartPage()
|
|
|
|
// For application level objects instantiation must be
|
|
// done within critical section
|
|
|
|
BOOL fApplnLocked = FALSE;
|
|
|
|
Assert(m_pHitObj);
|
|
|
|
if (!pObj->m_fInstantiatedTagged && // uninstantiated
|
|
pObj->m_csScope == csAppln && // application scope
|
|
m_pHitObj->PAppln()->FFirstRequestRun()) // after GLOBAL.ASA
|
|
{
|
|
// Lock
|
|
m_pHitObj->PAppln()->Lock();
|
|
|
|
// check if the object is still uninstantiated
|
|
if (!pObj->m_fInstantiatedTagged)
|
|
{
|
|
// yes, still uninstantiated - keep the lock
|
|
fApplnLocked = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// object instantiated while we waited - don't keep lock
|
|
m_pHitObj->PAppln()->UnLock();
|
|
}
|
|
}
|
|
|
|
// Instantiate tagged if needed
|
|
if (!pObj->m_fInstantiatedTagged)
|
|
{
|
|
if (pObj->m_csScope == csAppln)
|
|
{
|
|
// For applicatin scoped objects, instantiate from MTA
|
|
hr = CallMTACallback
|
|
(
|
|
CPageComponentManager::InstantiateObjectFromMTA,
|
|
pObj,
|
|
m_pHitObj
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hr = pObj->Instantiate(m_pHitObj);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// keep count
|
|
pCollection->m_cInstTagged++;
|
|
// add to pointer cash
|
|
pCollection->AddComponentToPtrHash(pObj);
|
|
// return flag
|
|
*pfNewInstance = TRUE;
|
|
}
|
|
|
|
// Flag as instantiated even if failed
|
|
pObj->m_fInstantiatedTagged = TRUE;
|
|
}
|
|
|
|
// Remove the lock kept while instantiating appln level object
|
|
if (fApplnLocked)
|
|
m_pHitObj->PAppln()->UnLock();
|
|
|
|
// Return if [instantiation] failed
|
|
if (FAILED(hr))
|
|
{
|
|
*ppObj = NULL;
|
|
return hr;
|
|
}
|
|
|
|
// Add as page object when needed
|
|
if (pObj->m_csScope != csAppln
|
|
&& (pObj->m_pDisp || (pObj->m_dwGIPCookie != NULL_GIP_COOKIE))
|
|
&& m_pHitObj && m_pHitObj->FIsBrowserRequest())
|
|
{
|
|
BOOL fStarted;
|
|
OnStartPage // don't care if failed
|
|
(
|
|
pObj,
|
|
m_pHitObj->PScriptingContextGet(),
|
|
pObj->GetCachedOnPageInfo(),
|
|
&fStarted
|
|
);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::InstantiateObjectFromMTA
|
|
|
|
Static callback called by CallMTACallback() to
|
|
instantiate aplication scoped objects
|
|
|
|
Parameters:
|
|
void *pvObj ComponentObject
|
|
void *pvHitObj HitObj
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT __stdcall CPageComponentManager::InstantiateObjectFromMTA
|
|
(
|
|
void *pvObj,
|
|
void *pvHitObj
|
|
)
|
|
{
|
|
Assert(pvHitObj);
|
|
Assert(pvObj);
|
|
|
|
CHitObj *pHitObj = (CHitObj *)pvHitObj;
|
|
CComponentObject *pObj = (CComponentObject *)pvObj;
|
|
|
|
return pObj->Instantiate(pHitObj);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::GetScopedProperty
|
|
|
|
Find property component by name.
|
|
Also does OnStartPage (adds created pDisp as CPageObject)
|
|
|
|
Parameters:
|
|
CompScope csScope Scope (could not be csUnknown)
|
|
LPWSTR pwszName Object name
|
|
CComponentObject **ppObj Object found
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::GetScopedProperty
|
|
(
|
|
CompScope csScope,
|
|
LPWSTR pwszName,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = FindScopedComponentByName
|
|
(
|
|
csScope,
|
|
pwszName,
|
|
CbWStr(pwszName),
|
|
TRUE,
|
|
ppObj
|
|
);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CComponentObject *pObj = *ppObj;
|
|
if (!pObj) // not failed, but not found either
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
// Add as page object if IDispatch * is there
|
|
// as VT_DISPATCH property
|
|
if (pObj->m_csScope != csAppln
|
|
&& (pObj->m_pDisp || (pObj->m_dwGIPCookie != NULL_GIP_COOKIE))
|
|
&& m_pHitObj && m_pHitObj->FIsBrowserRequest())
|
|
{
|
|
BOOL fStarted;
|
|
hr = OnStartPage
|
|
(
|
|
pObj,
|
|
m_pHitObj->PScriptingContextGet(),
|
|
pObj->GetCachedOnPageInfo(),
|
|
&fStarted
|
|
);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::FindAnyScopeComponentByIUnknown
|
|
|
|
Find component by its IUnknown *.
|
|
|
|
Parameters:
|
|
IUnknown *pUnk find by this pointer
|
|
CComponentObject **ppObj found object
|
|
|
|
Returns:
|
|
HRESULT
|
|
(S_FALSE if no error - not found)
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::FindAnyScopeComponentByIUnknown
|
|
(
|
|
IUnknown *pUnk,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
int cTry = 0;
|
|
*ppObj = NULL;
|
|
|
|
while (*ppObj == NULL && cTry < 3)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComponentCollection *pCollection = NULL;
|
|
|
|
switch (++cTry)
|
|
{
|
|
case 1: // page first
|
|
hr = GetPageCollection(&pCollection);
|
|
break;
|
|
case 2: // session
|
|
hr = GetSessionCollection(&pCollection);
|
|
break;
|
|
case 3: // application
|
|
hr = GetApplnCollection(&pCollection);
|
|
break;
|
|
}
|
|
if (FAILED(hr) || !pCollection)
|
|
continue; // couldn't get the collection
|
|
|
|
// find the object
|
|
hr = pCollection->FindComponentByIUnknownPtr(pUnk, ppObj);
|
|
if (hr != S_OK)
|
|
*ppObj = NULL;
|
|
}
|
|
|
|
return (*ppObj ? S_OK : S_FALSE);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::FindAnyScopeComponentByIDispatch
|
|
|
|
Find component by its IDispatch *.
|
|
Uses FindAnyScopeComponentByIUnknown.
|
|
|
|
Parameters:
|
|
IDispatch *pDisp find by this pointer
|
|
CComponentObject **ppObj found object
|
|
|
|
Returns:
|
|
HRESULT
|
|
(S_FALSE if no error - not found)
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::FindAnyScopeComponentByIDispatch
|
|
(
|
|
IDispatch *pDisp,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
IUnknown *pUnk = NULL;
|
|
HRESULT hr = pDisp->QueryInterface(IID_IUnknown, (void **)&pUnk);
|
|
|
|
if (SUCCEEDED(hr) && !pUnk)
|
|
hr = E_FAIL;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
*ppObj = NULL;
|
|
return hr;
|
|
}
|
|
|
|
return FindAnyScopeComponentByIUnknown(pUnk, ppObj);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::FindComponentWithoutContext
|
|
|
|
The same as FindAnyScopeComponentByIDispatch -
|
|
but static - gets context from Viper
|
|
|
|
Uses FindAnyScopeComponentByIUnknown.
|
|
|
|
Parameters:
|
|
IDispatch *pDisp find by this pointer
|
|
CComponentObject **ppObj found object
|
|
|
|
Returns:
|
|
HRESULT
|
|
(S_FALSE if no error - not found)
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::FindComponentWithoutContext
|
|
(
|
|
IDispatch *pDisp,
|
|
CComponentObject **ppObj
|
|
)
|
|
{
|
|
// Get HitObj from Viper Context
|
|
CHitObj *pHitObj = NULL;
|
|
ViperGetHitObjFromContext(&pHitObj);
|
|
if (!pHitObj)
|
|
return E_FAIL;
|
|
|
|
// Get page component manager
|
|
CPageComponentManager *pPCM = pHitObj->PPageComponentManager();
|
|
if (!pPCM)
|
|
return E_FAIL;
|
|
|
|
// Call the page component manager to find the object
|
|
return pPCM->FindAnyScopeComponentByIUnknown(pDisp, ppObj);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPageComponentManager::RemoveComponent
|
|
|
|
Remove component -- the early release logic
|
|
|
|
Parameters:
|
|
IDispatch *pDisp find by this pointer
|
|
CComponentObject **ppObj found object
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CPageComponentManager::RemoveComponent
|
|
(
|
|
CComponentObject *pObj
|
|
)
|
|
{
|
|
Assert(pObj);
|
|
|
|
CComponentCollection *pCollection;
|
|
HRESULT hr = GetCollectionByScope(pObj->m_csScope, &pCollection);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
return pCollection->RemoveComponent(pObj);
|
|
}
|
|
|
|
/*===================================================================
|
|
C C o m p o n e n t I t e r a t o r
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
CComponentIterator::CComponentIterator
|
|
|
|
CComponentIterator constructor
|
|
|
|
Parameters:
|
|
CHitObj *pHitObj page to init with (optional)
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CComponentIterator::CComponentIterator(CHitObj *pHitObj)
|
|
: m_fInited(FALSE), m_fFinished(FALSE), m_pHitObj(NULL),
|
|
m_pLastObj(NULL), m_csLastScope(csUnknown)
|
|
{
|
|
if (pHitObj)
|
|
Init(pHitObj);
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentIterator::~CComponentIterator
|
|
|
|
CComponentIterator destructor
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CComponentIterator::~CComponentIterator()
|
|
{
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentIterator::Init
|
|
|
|
Start iterating
|
|
|
|
Parameters:
|
|
CHitObj *pHitObj page
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CComponentIterator::Init
|
|
(
|
|
CHitObj *pHitObj
|
|
)
|
|
{
|
|
Assert(pHitObj);
|
|
pHitObj->AssertValid();
|
|
|
|
m_pHitObj = pHitObj;
|
|
m_fInited = TRUE;
|
|
m_fFinished = FALSE;
|
|
|
|
m_pLastObj = NULL;
|
|
m_csLastScope = csUnknown;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CComponentIterator::WStrNextComponentName
|
|
|
|
The iteration function
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
Next component name or NULL if done
|
|
===================================================================*/
|
|
LPWSTR CComponentIterator::WStrNextComponentName()
|
|
{
|
|
Assert(m_fInited);
|
|
|
|
if (m_fFinished)
|
|
return NULL;
|
|
|
|
Assert(m_pHitObj);
|
|
|
|
CompScope csScope = m_csLastScope;
|
|
CComponentObject *pObj = m_pLastObj ?
|
|
static_cast<CComponentObject *>(m_pLastObj->m_pNext) : NULL;
|
|
|
|
while (!m_fFinished)
|
|
{
|
|
// try the current scope
|
|
|
|
if (pObj)
|
|
{
|
|
Assert(pObj->m_ctType == ctTagged);
|
|
Assert(pObj->GetName());
|
|
|
|
m_pLastObj = pObj;
|
|
m_csLastScope = csScope;
|
|
return pObj->GetName();
|
|
}
|
|
|
|
// couldn't find in the current scope - try next scope
|
|
CComponentCollection *pCol = NULL;
|
|
|
|
switch (csScope)
|
|
{
|
|
case csUnknown:
|
|
csScope = csPage;
|
|
m_pHitObj->GetPageComponentCollection(&pCol);
|
|
break;
|
|
case csPage:
|
|
csScope = csSession;
|
|
m_pHitObj->GetSessionComponentCollection(&pCol);
|
|
break;
|
|
case csSession:
|
|
csScope = csAppln;
|
|
m_pHitObj->GetApplnComponentCollection(&pCol);
|
|
break;
|
|
case csAppln:
|
|
default:
|
|
csScope = csUnknown;
|
|
m_fFinished = TRUE;
|
|
break;
|
|
}
|
|
|
|
// start at the beginning of the new collection
|
|
|
|
if (pCol)
|
|
pObj = static_cast<CComponentObject *>(pCol->m_htTaggedObjects.Head());
|
|
}
|
|
|
|
// finished
|
|
return NULL;
|
|
}
|
|
|
|
/*===================================================================
|
|
C V a r i a n t s I t e r a t o r
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::CVariantsIterator
|
|
|
|
CVariantsIterator constructor by application
|
|
|
|
Parameters:
|
|
CAppln *pAppln collection to init with
|
|
DWORD ctCollType type of components to list iteration
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CVariantsIterator::CVariantsIterator
|
|
(
|
|
CAppln *pAppln,
|
|
DWORD ctColType
|
|
)
|
|
: m_pCompColl(NULL), m_pAppln(NULL), m_pSession(NULL)
|
|
{
|
|
Assert(pAppln);
|
|
pAppln->AddRef();
|
|
|
|
m_cRefs = 1;
|
|
m_pCompColl = pAppln->PCompCol();
|
|
m_pAppln = pAppln;
|
|
m_ctColType = ctColType;
|
|
m_dwIndex = 0;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::CVariantsIterator
|
|
|
|
CVariantsIterator constructor by session
|
|
|
|
Parameters:
|
|
CSession *pSession collection to init with
|
|
DWORD ctCollType type of components to list iteration
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CVariantsIterator::CVariantsIterator
|
|
(
|
|
CSession *pSession,
|
|
DWORD ctColType
|
|
)
|
|
: m_pCompColl(NULL), m_pAppln(NULL), m_pSession(NULL)
|
|
{
|
|
Assert(pSession);
|
|
pSession->AddRef();
|
|
|
|
m_cRefs = 1;
|
|
m_pCompColl = pSession->PCompCol();
|
|
m_ctColType = ctColType;
|
|
m_pSession = pSession;
|
|
m_dwIndex = 0;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::~CVariantsIterator
|
|
|
|
CVariantsIterator destructor
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CVariantsIterator::~CVariantsIterator()
|
|
{
|
|
if (m_pSession)
|
|
m_pSession->Release();
|
|
if (m_pAppln)
|
|
m_pAppln->Release();
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::QueryInterface
|
|
|
|
CVariantsIterator QI
|
|
|
|
Parameters:
|
|
GUID& iid
|
|
VOID ** ppvObj
|
|
|
|
Returns: HRESULT
|
|
===================================================================*/
|
|
STDMETHODIMP CVariantsIterator::QueryInterface
|
|
(
|
|
const GUID &iid,
|
|
void **ppvObj
|
|
)
|
|
{
|
|
if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)
|
|
{
|
|
AddRef();
|
|
*ppvObj = this;
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::AddRef
|
|
|
|
CVariantsIterator AddRef
|
|
|
|
Parameters:
|
|
|
|
Returns: ULONG
|
|
===================================================================*/
|
|
STDMETHODIMP_(ULONG) CVariantsIterator::AddRef()
|
|
{
|
|
return ++m_cRefs;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::Release
|
|
|
|
CVariantsIterator Release
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
STDMETHODIMP_(ULONG) CVariantsIterator::Release()
|
|
{
|
|
if (--m_cRefs > 0)
|
|
return m_cRefs;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::Clone
|
|
|
|
CVariantsIterator Clone
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
STDMETHODIMP CVariantsIterator::Clone
|
|
(
|
|
IEnumVARIANT **ppEnumReturn
|
|
)
|
|
{
|
|
CVariantsIterator *pNewIterator = NULL;
|
|
if (m_pSession)
|
|
{
|
|
pNewIterator = new CVariantsIterator(m_pSession, m_ctColType);
|
|
}
|
|
else if (m_pAppln)
|
|
{
|
|
pNewIterator = new CVariantsIterator(m_pAppln, m_ctColType);
|
|
}
|
|
else
|
|
{
|
|
Assert(FALSE); // better be either Appln or Session
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (pNewIterator == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// new iterator should point to same location as this.
|
|
pNewIterator->m_dwIndex = m_dwIndex;
|
|
|
|
*ppEnumReturn = pNewIterator;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::Next
|
|
|
|
CVariantsIterator Next
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
STDMETHODIMP CVariantsIterator::Next
|
|
(
|
|
unsigned long cElementsRequested,
|
|
VARIANT *rgVariant,
|
|
unsigned long *pcElementsFetched
|
|
)
|
|
{
|
|
// give a valid pointer value to 'pcElementsFetched'
|
|
unsigned long cElementsFetched;
|
|
if (pcElementsFetched == NULL)
|
|
pcElementsFetched = &cElementsFetched;
|
|
|
|
if (cElementsRequested == 0)
|
|
{
|
|
if (pcElementsFetched)
|
|
*pcElementsFetched = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD cMax = 0;
|
|
if (m_ctColType == ctTagged)
|
|
{
|
|
cMax = m_pCompColl ? m_pCompColl->m_cAllTagged : 0;
|
|
}
|
|
else if (m_ctColType == ctProperty)
|
|
{
|
|
cMax = m_pCompColl ? m_pCompColl->m_cProperties : 0;
|
|
}
|
|
else
|
|
{
|
|
// Should always be either tagged object or property
|
|
Assert(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Loop through the collection until either we reach the end or
|
|
// cElements becomes zero
|
|
//
|
|
unsigned long cElements = cElementsRequested;
|
|
*pcElementsFetched = 0;
|
|
|
|
while (cElements > 0 && m_dwIndex < cMax)
|
|
{
|
|
LPWSTR pwszName = NULL;
|
|
|
|
if (m_pAppln)
|
|
m_pAppln->Lock();
|
|
|
|
m_pCompColl->GetNameByIndex(m_ctColType, ++m_dwIndex, &pwszName);
|
|
|
|
if (!pwszName) {
|
|
if (m_pAppln)
|
|
m_pAppln->UnLock();
|
|
continue;
|
|
}
|
|
|
|
BSTR bstrT = SysAllocString(pwszName);
|
|
|
|
if (m_pAppln)
|
|
m_pAppln->UnLock();
|
|
|
|
if (!bstrT)
|
|
return E_OUTOFMEMORY;
|
|
|
|
V_VT(rgVariant) = VT_BSTR;
|
|
V_BSTR(rgVariant) = bstrT;
|
|
++rgVariant;
|
|
|
|
--cElements;
|
|
++(*pcElementsFetched);
|
|
}
|
|
|
|
// initialize the remaining variants
|
|
while (cElements-- > 0)
|
|
VariantInit(rgVariant++);
|
|
|
|
return (*pcElementsFetched == cElementsRequested)? S_OK : S_FALSE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::Skip
|
|
|
|
CVariantsIterator Skip
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
STDMETHODIMP CVariantsIterator::Skip
|
|
(
|
|
unsigned long cElements
|
|
)
|
|
{
|
|
/* Adjust the index by cElements or
|
|
* until we hit the max element
|
|
*/
|
|
DWORD cMax = 0;
|
|
|
|
// We iterate over different arrays depending on the collection type
|
|
if (m_ctColType == ctTagged)
|
|
{
|
|
cMax = m_pCompColl ? m_pCompColl->m_cAllTagged : 0;
|
|
}
|
|
else if (m_ctColType == ctProperty)
|
|
{
|
|
cMax = m_pCompColl ? m_pCompColl->m_cProperties : 0;
|
|
}
|
|
else
|
|
{
|
|
// Should always be either tagged object or property
|
|
Assert(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_dwIndex += cElements;
|
|
return (m_dwIndex < cMax)? S_OK : S_FALSE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CVariantsIterator::Reset
|
|
|
|
CVariantsIterator Reset
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
STDMETHODIMP CVariantsIterator::Reset()
|
|
{
|
|
m_dwIndex = 0;
|
|
return NO_ERROR;
|
|
}
|
|
|