windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/cmp/asp51/dispatch.cpp
2020-09-26 16:20:57 +08:00

548 lines
13 KiB
C++

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1996 Microsoft Corporation. All Rights Reserved.
Component: IDispatch implementation
File: Dispatch.h
Owner: DGottner
This file contains our implementation of IDispatch
===================================================================*/
#include "denpre.h"
#pragma hdrstop
#include "dispatch.h"
#include "asptlb.h"
#include "memchk.h"
#ifdef USE_LOCALE
extern DWORD g_dwTLS;
#endif
/*===================================================================
CDispatch::CDispatch
CDispatch::~CDispatch
Parameters (Constructor):
pUnkObj pointer to the object we're in.
pUnkOuter LPUNKNOWN to which we delegate.
===================================================================*/
CDispatch::CDispatch()
{
m_pITINeutral = NULL;
m_pITypeLib = NULL;
m_pGuidDispInterface = NULL;
}
void CDispatch::Init
(
const GUID &GuidDispInterface,
const ITypeLib *pITypeLib // = NULL
)
{
m_pGuidDispInterface = &GuidDispInterface;
m_pITypeLib = const_cast<ITypeLib *>(pITypeLib);
}
CDispatch::~CDispatch(void)
{
ReleaseInterface(m_pITINeutral);
return;
}
/*===================================================================
CDispatch::GetTypeInfoCount
Returns the number of type information (ITypeInfo) interfaces
that the object provides (0 or 1).
Parameters:
pcInfo UINT * to the location to receive
the count of interfaces.
Return Value:
HRESULT S_OK or a general error code.
===================================================================*/
STDMETHODIMP CDispatch::GetTypeInfoCount(UINT *pcInfo)
{
// We implement GetTypeInfo so return 1
*pcInfo = 1;
return S_OK;
}
/*===================================================================
CDispatch::GetTypeInfo
Retrieves type information for the automation interface. This
is used anywhere that the right ITypeInfo interface is needed
for whatever LCID is applicable. Specifically, this is used
from within GetIDsOfNames and Invoke.
Parameters:
itInfo UINT reserved. Must be zero.
lcid LCID providing the locale for the type
information. If the object does not support
localization, this is ignored.
ppITypeInfo ITypeInfo ** in which to store the ITypeInfo
interface for the object.
Return Value:
HRESULT S_OK or a general error code.
===================================================================*/
STDMETHODIMP CDispatch::GetTypeInfo(
UINT itInfo,
LCID lcid,
ITypeInfo **ppITypeInfo
)
{
HRESULT hr;
ITypeInfo **ppITI = NULL;
if (0 != itInfo)
return ResultFromScode(TYPE_E_ELEMENTNOTFOUND);
if (NULL == ppITypeInfo)
return ResultFromScode(E_POINTER);
*ppITypeInfo = NULL;
// We don't internationalize the type library, so
// we always return the same one, regardless of the locale.
ppITI = &m_pITINeutral;
//Load a type lib if we don't have the information already.
if (NULL == *ppITI)
{
ITypeLib *pITL;
// If a specific TypeLib was given at init time use that, otherwise default to the main one
if (m_pITypeLib == NULL)
pITL = Glob(pITypeLibDenali);
else
pITL = m_pITypeLib;
Assert(pITL != NULL);
hr = pITL->GetTypeInfoOfGuid(*m_pGuidDispInterface, ppITI);
if (FAILED(hr))
return hr;
// Save the type info in a class member, so we don't have
// go through all this work again;
m_pITINeutral = *ppITI;
}
/*
* Note: the type library is still loaded since we have
* an ITypeInfo from it.
*/
(*ppITI)->AddRef();
*ppITypeInfo = *ppITI;
return S_OK;
}
/*===================================================================
CDispatch::GetIDsOfNames
Converts text names into DISPIDs to pass to Invoke
Parameters:
riid REFIID reserved. Must be IID_NULL.
rgszNames OLECHAR ** pointing to the array of names to be mapped.
cNames UINT number of names to be mapped.
lcid LCID of the locale.
rgDispID DISPID * caller allocated array containing IDs
corresponging to those names in rgszNames.
Return Value:
HRESULT S_OK or a general error code.
===================================================================*/
STDMETHODIMP CDispatch::GetIDsOfNames
(
REFIID riid,
OLECHAR **rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispID
)
{
HRESULT hr;
ITypeInfo *pTI;
if (IID_NULL != riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
//Get the right ITypeInfo for lcid.
hr = GetTypeInfo(0, lcid, &pTI);
if (SUCCEEDED(hr))
{
hr = DispGetIDsOfNames(pTI, rgszNames, cNames, rgDispID);
pTI->Release();
}
return hr;
}
/*===================================================================
CDispatch::Invoke
Calls a method in the dispatch interface or manipulates a property.
Parameters:
dispID DISPID of the method or property of interest.
riid REFIID reserved, must be IID_NULL.
lcid LCID of the locale.
wFlags USHORT describing the context of the invocation.
pDispParams DISPPARAMS * to the array of arguments.
pVarResult VARIANT * in which to store the result. Is
NULL if the caller is not interested.
pExcepInfo EXCEPINFO * to exception information.
puArgErr UINT * in which to store the index of an
invalid parameter if DISP_E_TYPEMISMATCH
is returned.
Return Value:
HRESULT S_OK or a general error code.
===================================================================*/
STDMETHODIMP CDispatch::Invoke
(
DISPID dispID,
REFIID riid,
LCID lcid,
unsigned short wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr
)
{
HRESULT hr;
ITypeInfo *pTI;
LANGID langID = PRIMARYLANGID(lcid);
// riid is supposed to be IID_NULL always
if (IID_NULL != riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
// Get the ITypeInfo for lcid
hr = GetTypeInfo(0, lcid, &pTI);
if (FAILED(hr))
return hr;
#ifdef USE_LOCALE
// This saves the language ID for this thread
TlsSetValue(g_dwTLS, &langID);
#endif
// Clear exceptions
SetErrorInfo(0L, NULL);
// VBScript does not distinguish between a propget and a method
// implement that behavior for other languages.
//
if (wFlags & (DISPATCH_METHOD | DISPATCH_PROPERTYGET))
wFlags |= DISPATCH_METHOD | DISPATCH_PROPERTYGET;
// This is exactly what DispInvoke does--so skip the overhead.
// With dual interface, "this" is the address of the object AND its dispinterface
//
hr = pTI->Invoke(this, dispID, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgErr);
// Exception handling is done within ITypeInfo::Invoke
pTI->Release();
return hr;
}
/*===================================================================
CSupportErrorInfo::CSupportErrorInfo
Default constructor so that the Init method can be used.
Parameters (Constructor):
pObj PCResponse of the object we're in.
pUnkOuter LPUNKNOWN to which we delegate.
===================================================================*/
CSupportErrorInfo::CSupportErrorInfo(void)
: m_pUnkObj(NULL),
m_pUnkOuter(NULL)
{
}
/*===================================================================
CSupportErrorInfo::CSupportErrorInfo
Parameters (Constructor):
pObj PCResponse of the object we're in.
pUnkOuter LPUNKNOWN to which we delegate.
GuidDispInterface GUID of dispatch interface.
===================================================================*/
CSupportErrorInfo::CSupportErrorInfo(IUnknown *pUnkObj, IUnknown *pUnkOuter, const GUID &GuidDispInterface)
{
m_pUnkObj = pUnkObj;
m_pUnkOuter = (pUnkOuter == NULL)? pUnkObj : pUnkOuter;
m_pGuidDispInterface = &GuidDispInterface;
}
/*===================================================================
void CSupportErrorInfo::Init
Parameters:
pObj PCResponse of the object we're in.
pUnkOuter LPUNKNOWN to which we delegate.
GuidDispInterface GUID of dispatch interface.
Returns:
Nothing
===================================================================*/
void CSupportErrorInfo::Init(IUnknown *pUnkObj, IUnknown *pUnkOuter, const GUID &GuidDispInterface)
{
m_pUnkObj = pUnkObj;
m_pUnkOuter = (pUnkOuter == NULL)? pUnkObj : pUnkOuter;
m_pGuidDispInterface = &GuidDispInterface;
}
/*===================================================================
CSupportErrorInfo::QueryInterface
CSupportErrorInfo::AddRef
CSupportErrorInfo::Release
IUnknown members for CSupportErrorInfo object.
===================================================================*/
STDMETHODIMP CSupportErrorInfo::QueryInterface(const GUID &Iid, void **ppvObj)
{
return m_pUnkOuter->QueryInterface(Iid, ppvObj);
}
STDMETHODIMP_(ULONG) CSupportErrorInfo::AddRef(void)
{
return m_pUnkOuter->AddRef();
}
STDMETHODIMP_(ULONG) CSupportErrorInfo::Release(void)
{
return m_pUnkOuter->Release();
}
/*===================================================================
CSupportErrorInfo::InterfaceSupportsErrorInfo
Informs a caller whether or not a specific interface
supports exceptions through the Set/GetErrorInfo mechanism.
Parameters:
riid REFIID of the interface in question.
Return Value:
HRESULT S_OK if a call to GetErrorInfo will succeed
for callers of riid. S_FALSE if not.
===================================================================*/
STDMETHODIMP CSupportErrorInfo::InterfaceSupportsErrorInfo
(
REFIID riid
)
{
if (IID_IDispatch == riid || *m_pGuidDispInterface == riid)
return S_OK;
return ResultFromScode(S_FALSE);
}
/*===================================================================
Exception
Raises an exception using the CreateErrorInfo API and the
ICreateErrorInfo interface.
Note that this method doesn't allow for deferred filling
of an EXCEPINFO structure.
Parameters:
strSource LPOLESTR the exception source
strDescr LPOLESTR the exception description
Returns:
Nothing
===================================================================*/
void Exception
(
REFIID ObjID,
LPOLESTR strSource,
LPOLESTR strDescr
)
{
HRESULT hr;
ICreateErrorInfo *pICreateErr;
IErrorInfo *pIErr;
LANGID langID = LANG_NEUTRAL;
#ifdef USE_LOCALE
LANGID *pLangID;
pLangID = (LANGID *)TlsGetValue(g_dwTLS);
if (NULL != pLangID)
langID = *pLangID;
#endif
/*
* Thread-safe exception handling means that we call
* CreateErrorInfo which gives us an ICreateErrorInfo pointer
* that we then use to set the error information (basically
* to set the fields of an EXCEPINFO structure. We then
* call SetErrorInfo to attach this error to the current
* thread. ITypeInfo::Invoke will look for this when it
* returns from whatever function was invokes by calling
* GetErrorInfo.
*/
//Not much we can do if this fails.
if (FAILED(CreateErrorInfo(&pICreateErr)))
return;
/*
* CONSIDER: Help file and help context?
*/
pICreateErr->SetGUID(ObjID);
pICreateErr->SetHelpFile(L"");
pICreateErr->SetHelpContext(0L);
pICreateErr->SetSource(strSource);
pICreateErr->SetDescription(strDescr);
hr = pICreateErr->QueryInterface(IID_IErrorInfo, (PPVOID)&pIErr);
if (SUCCEEDED(hr))
{
SetErrorInfo(0L, pIErr);
pIErr->Release();
}
//SetErrorInfo holds the object's IErrorInfo
pICreateErr->Release();
return;
}
/*===================================================================
ExceptionId
Raises an exception using the CreateErrorInfo API and the
ICreateErrorInfo interface.
Note that this method doesn't allow for deferred filling
of an EXCEPINFO structure.
Parameters:
SourceID Resource ID for the source string
DescrID Resource ID for the description string
Returns:
Nothing
===================================================================*/
void ExceptionId
(
REFIID ObjID,
UINT SourceID,
UINT DescrID,
HRESULT hrCode
)
{
HRESULT hr;
ICreateErrorInfo *pICreateErr;
IErrorInfo *pIErr;
LANGID langID = LANG_NEUTRAL;
#ifdef USE_LOCALE
LANGID *pLangID;
pLangID = (LANGID *)TlsGetValue(g_dwTLS);
if (NULL != pLangID)
langID = *pLangID;
#endif
/*
* Thread-safe exception handling means that we call
* CreateErrorInfo which gives us an ICreateErrorInfo pointer
* that we then use to set the error information (basically
* to set the fields of an EXCEPINFO structure. We then
* call SetErrorInfo to attach this error to the current
* thread. ITypeInfo::Invoke will look for this when it
* returns from whatever function was invokes by calling
* GetErrorInfo.
*/
//Not much we can do if this fails.
if (FAILED(CreateErrorInfo(&pICreateErr)))
return;
/*
* CONSIDER: Help file and help context?
*/
DWORD cch;
WCHAR strSource[MAX_RESSTRINGSIZE];
WCHAR strDescr[MAX_RESSTRINGSIZE];
WCHAR strHRESULTDescr[256];
WCHAR strDescrWithHRESULT[MAX_RESSTRINGSIZE];
pICreateErr->SetGUID(ObjID);
pICreateErr->SetHelpFile(L"");
pICreateErr->SetHelpContext(0L);
cch = CwchLoadStringOfId(SourceID, strSource, MAX_RESSTRINGSIZE);
if (cch > 0)
pICreateErr->SetSource(strSource);
cch = CwchLoadStringOfId(DescrID, strDescr, MAX_RESSTRINGSIZE);
if (cch > 0)
{
//Bug Fix 91847 use a FormatMessage() based description
HResultToWsz(hrCode, strHRESULTDescr, 256);
_snwprintf(strDescrWithHRESULT, MAX_RESSTRINGSIZE, strDescr, strHRESULTDescr);
strDescrWithHRESULT[MAX_RESSTRINGSIZE - 1] = L'\0';
pICreateErr->SetDescription(strDescrWithHRESULT);
}
hr = pICreateErr->QueryInterface(IID_IErrorInfo, (PPVOID)&pIErr);
if (SUCCEEDED(hr))
{
SetErrorInfo(0L, pIErr);
pIErr->Release();
}
//SetErrorInfo holds the object's IErrorInfo
pICreateErr->Release();
return;
}