389 lines
12 KiB
C++
389 lines
12 KiB
C++
|
// Copyright 1995-1997 Microsoft Corporation. All Rights Reserved.
|
||
|
|
||
|
// all of our objects will inherit from this class to share as much of the same
|
||
|
// code as possible. this super-class contains the unknown, dispatch and
|
||
|
// error info implementations for them.
|
||
|
|
||
|
#include "header.h"
|
||
|
#include "AutoObj.H"
|
||
|
|
||
|
#ifndef _DEBUG
|
||
|
#undef THIS_FILE
|
||
|
static const char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::CAutomationObject
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// create the object and initialize the refcount
|
||
|
//
|
||
|
// Parameters:
|
||
|
// IUnknown * - [in] controlling Unknown
|
||
|
// int - [in] the object type that we are
|
||
|
// void * - [in] the VTable of of the object we really are.
|
||
|
|
||
|
CAutomationObject::CAutomationObject(IUnknown *pUnkOuter, int ObjType, void *pVTable)
|
||
|
: CUnknownObject(pUnkOuter, pVTable), m_ObjectType (ObjType)
|
||
|
{
|
||
|
m_fLoadedTypeInfo = FALSE;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::~CAutomationObject
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
|
||
|
CAutomationObject::~CAutomationObject ()
|
||
|
{
|
||
|
// if we loaded up a type info, release our count on the globally stashed
|
||
|
// type infos, and release if it becomes zero.
|
||
|
|
||
|
if (m_fLoadedTypeInfo) {
|
||
|
|
||
|
// we have to crit sect this since it's possible to have more than
|
||
|
// one thread partying with this object.
|
||
|
|
||
|
// EnterCriticalSection(&g_CriticalSection);
|
||
|
ASSERT_COMMENT(CTYPEINFOOFOBJECT(m_ObjectType), "Bogus ref counting on the Type Infos");
|
||
|
CTYPEINFOOFOBJECT(m_ObjectType)--;
|
||
|
|
||
|
// if we're the last one, free that sucker!
|
||
|
|
||
|
if (!CTYPEINFOOFOBJECT(m_ObjectType)) {
|
||
|
PTYPEINFOOFOBJECT(m_ObjectType)->Release();
|
||
|
PTYPEINFOOFOBJECT(m_ObjectType) = NULL;
|
||
|
}
|
||
|
// LeaveCriticalSection(&g_CriticalSection);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::InternalQueryInterface
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// the controlling unknown will call this for us in the case where they're
|
||
|
// looking for a specific interface.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// REFIID - [in] interface they want
|
||
|
// void ** - [out] where they want to put the resulting object ptr.
|
||
|
//
|
||
|
// Output:
|
||
|
// HRESULT - S_OK, E_NOINTERFACE
|
||
|
|
||
|
HRESULT CAutomationObject::InternalQueryInterface(REFIID riid, void **ppvObjOut)
|
||
|
{
|
||
|
#if 0
|
||
|
ASSERT_COMMENT(ppvObjOut, "controlling Unknown should be checking this!");
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
#endif
|
||
|
|
||
|
// start looking for the guids we support, namely IDispatch, and the
|
||
|
|
||
|
if (DO_GUIDS_MATCH(riid, IID_IDispatch)) {
|
||
|
*ppvObjOut = (void *)(IDispatch *)m_pvInterface;
|
||
|
((IUnknown *)(*ppvObjOut))->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// just get our parent class to process it from here on out.
|
||
|
|
||
|
return CUnknownObject::InternalQueryInterface(riid, ppvObjOut);
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::GetTypeInfoCount
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// returns the number of type information interfaces that the object provides
|
||
|
//
|
||
|
// Parameters:
|
||
|
// UINT * - [out] the number of interfaces supported.
|
||
|
//
|
||
|
// Output:
|
||
|
// HRESULT - S_OK, E_NOTIMPL, E_INVALIDARG
|
||
|
|
||
|
STDMETHODIMP CAutomationObject::GetTypeInfoCount(UINT *pctinfo)
|
||
|
{
|
||
|
if (!pctinfo)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*pctinfo = 1;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::GetTypeInfo
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// Retrieves a type information object, which can be used to get the type
|
||
|
// information for an interface.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// UINT - [in] the type information they'll want returned
|
||
|
// LCID - [in] the LCID of the type info we want
|
||
|
// ITypeInfo ** - [out] the new type info object.
|
||
|
//
|
||
|
// Output:
|
||
|
// HRESULT - S_OK, E_INVALIDARG, etc.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
|
||
|
STDMETHODIMP CAutomationObject::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **ppTypeInfoOut)
|
||
|
{
|
||
|
DWORD dwPathLen;
|
||
|
char szDllPath[MAX_PATH];
|
||
|
HRESULT hr;
|
||
|
ITypeLib *pTypeLib;
|
||
|
ITypeInfo **ppTypeInfo =NULL;
|
||
|
|
||
|
// arg checking
|
||
|
|
||
|
if (itinfo != 0)
|
||
|
return DISP_E_BADINDEX;
|
||
|
|
||
|
if (!ppTypeInfoOut)
|
||
|
return E_POINTER;
|
||
|
|
||
|
*ppTypeInfoOut = NULL;
|
||
|
|
||
|
// ppTypeInfo will point to our global holder for this particular
|
||
|
// type info. if it's null, then we have to load it up. if it's not
|
||
|
// NULL, then it's already loaded, and we're happy.
|
||
|
// crit sect this entire nightmare so we're okay with multiple
|
||
|
// threads trying to use this object.
|
||
|
|
||
|
// EnterCriticalSection(&g_CriticalSection);
|
||
|
ppTypeInfo = PPTYPEINFOOFOBJECT(m_ObjectType);
|
||
|
|
||
|
if (*ppTypeInfo == NULL) {
|
||
|
|
||
|
ITypeInfo *pTypeInfoTmp;
|
||
|
HREFTYPE hrefType;
|
||
|
|
||
|
// we don't have the type info around, so go load the sucker.
|
||
|
//
|
||
|
hr = LoadRegTypeLib(*g_pLibid, (USHORT)VERSIONOFOBJECT(m_ObjectType), 0,
|
||
|
LANG_NEUTRAL, &pTypeLib);
|
||
|
|
||
|
// if, for some reason, we failed to load the type library this
|
||
|
// way, we're going to try and load the type library directly out of
|
||
|
// our resources. this has the advantage of going and re-setting all
|
||
|
// the registry information again for us.
|
||
|
|
||
|
if (FAILED(hr)) {
|
||
|
|
||
|
dwPathLen = GetModuleFileName(_Module.GetModuleInstance(), szDllPath, MAX_PATH);
|
||
|
if (!dwPathLen) {
|
||
|
hr = E_FAIL;
|
||
|
goto CleanUp;
|
||
|
}
|
||
|
|
||
|
MAKE_WIDEPTR_FROMANSI(pwsz, szDllPath);
|
||
|
hr = LoadTypeLib(pwsz, &pTypeLib);
|
||
|
CLEANUP_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
// we've got the Type Library now, so get the type info for the interface
|
||
|
// we're interested in.
|
||
|
//
|
||
|
hr = pTypeLib->GetTypeInfoOfGuid((REFIID)INTERFACEOFOBJECT(m_ObjectType), &pTypeInfoTmp);
|
||
|
pTypeLib->Release();
|
||
|
CLEANUP_ON_FAILURE(hr);
|
||
|
|
||
|
// the following couple of lines of code are to dereference the dual
|
||
|
// interface stuff and take us right to the dispatch portion of the
|
||
|
// interfaces.
|
||
|
//
|
||
|
hr = pTypeInfoTmp->GetRefTypeOfImplType(0xffffffff, &hrefType);
|
||
|
if (FAILED(hr)) {
|
||
|
pTypeInfoTmp->Release();
|
||
|
goto CleanUp;
|
||
|
}
|
||
|
|
||
|
hr = pTypeInfoTmp->GetRefTypeInfo(hrefType, ppTypeInfo);
|
||
|
pTypeInfoTmp->Release();
|
||
|
CLEANUP_ON_FAILURE(hr);
|
||
|
|
||
|
// add an extra reference to this object. if it ever becomes zero, then
|
||
|
// we need to release it ourselves. crit sect this since more than
|
||
|
// one thread can party on this object.
|
||
|
//
|
||
|
CTYPEINFOOFOBJECT(m_ObjectType)++;
|
||
|
m_fLoadedTypeInfo = TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// we still have to go and addref the Type info object, however, so that
|
||
|
// the people using it can release it.
|
||
|
//
|
||
|
(*ppTypeInfo)->AddRef();
|
||
|
*ppTypeInfoOut = *ppTypeInfo;
|
||
|
hr = S_OK;
|
||
|
|
||
|
CleanUp:
|
||
|
// LeaveCriticalSection(&g_CriticalSection);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::GetIDsOfNames
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// Maps a single member and an optional set of argument names to a
|
||
|
// corresponding set of integer DISPIDs
|
||
|
//
|
||
|
// Parameters:
|
||
|
// REFIID - [in] must be IID_NULL
|
||
|
// OLECHAR ** - [in] array of names to map.
|
||
|
// UINT - [in] count of names in the array.
|
||
|
// LCID - [in] LCID on which to operate
|
||
|
// DISPID * - [in] place to put the corresponding DISPIDs.
|
||
|
//
|
||
|
// Output:
|
||
|
// HRESULT - S_OK, E_OUTOFMEMORY, DISP_E_UNKNOWNNAME,
|
||
|
// DISP_E_UNKNOWNLCID
|
||
|
//
|
||
|
// Notes:
|
||
|
// - we're just going to use DispGetIDsOfNames to save us a lot of hassle,
|
||
|
// and to let this superclass handle it.
|
||
|
//
|
||
|
STDMETHODIMP CAutomationObject::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ITypeInfo *pTypeInfo;
|
||
|
|
||
|
if (!DO_GUIDS_MATCH(riid, IID_NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
hr = GetTypeInfo(0, lcid, &pTypeInfo);
|
||
|
RETURN_ON_FAILURE(hr);
|
||
|
|
||
|
// use the standard provided routines to do all the work for us.
|
||
|
|
||
|
hr = pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
|
||
|
pTypeInfo->Release();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::Invoke
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// provides access to the properties and methods on this object.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// DISPID - [in] identifies the member we're working with.
|
||
|
// REFIID - [in] must be IID_NULL.
|
||
|
// LCID - [in] language we're working under
|
||
|
// USHORT - [in] flags, propput, get, method, etc ...
|
||
|
// DISPPARAMS * - [in] array of arguments.
|
||
|
// VARIANT * - [out] where to put result, or NULL if they don't care.
|
||
|
// EXCEPINFO * - [out] filled in in case of exception
|
||
|
// UINT * - [out] where the first argument with an error is.
|
||
|
//
|
||
|
// Output:
|
||
|
// HRESULT - tonnes of them.
|
||
|
|
||
|
STDMETHODIMP CAutomationObject::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ITypeInfo *pTypeInfo;
|
||
|
|
||
|
if (!DO_GUIDS_MATCH(riid, IID_NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
// get our typeinfo first!
|
||
|
//
|
||
|
hr = GetTypeInfo(0, lcid, &pTypeInfo);
|
||
|
RETURN_ON_FAILURE(hr);
|
||
|
|
||
|
// Clear exceptions
|
||
|
|
||
|
SetErrorInfo(0L, NULL);
|
||
|
|
||
|
// This is exactly what DispInvoke does--so skip the overhead.
|
||
|
|
||
|
hr = pTypeInfo->Invoke(m_pvInterface, dispid, wFlags,
|
||
|
pdispparams, pvarResult,
|
||
|
pexcepinfo, puArgErr);
|
||
|
pTypeInfo->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::Exception
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// fills in the rich error info object so that both our vtable bound interfaces
|
||
|
// and calls through ITypeInfo::Invoke get the right error informaiton.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// HRESULT - [in] the SCODE that should be associated with this err
|
||
|
// WORD - [in] the RESOURCE ID of the error message.
|
||
|
// DWORD - [in] helpcontextid for the error
|
||
|
//
|
||
|
// Output:
|
||
|
// HRESULT - the HRESULT that was passed in.
|
||
|
|
||
|
HRESULT CAutomationObject::Exception(HRESULT hrExcep, WORD idException, DWORD dwHelpContextID)
|
||
|
{
|
||
|
ICreateErrorInfo *pCreateErrorInfo;
|
||
|
IErrorInfo *pErrorInfo;
|
||
|
HRESULT hr;
|
||
|
|
||
|
// first get the createerrorinfo object.
|
||
|
|
||
|
hr = CreateErrorInfo(&pCreateErrorInfo);
|
||
|
if (FAILED(hr)) return hrExcep;
|
||
|
|
||
|
MAKE_WIDEPTR_FROMANSI(wszHelpFile, HELPFILEOFOBJECT(m_ObjectType));
|
||
|
|
||
|
// set up some default information on it.
|
||
|
//
|
||
|
pCreateErrorInfo->SetGUID((REFIID)INTERFACEOFOBJECT(m_ObjectType));
|
||
|
pCreateErrorInfo->SetHelpFile(wszHelpFile);
|
||
|
pCreateErrorInfo->SetHelpContext(dwHelpContextID);
|
||
|
|
||
|
// load in the actual error string value. max of 256.
|
||
|
|
||
|
CWStr cwzError(GetStringResource(idException));
|
||
|
pCreateErrorInfo->SetDescription(cwzError);
|
||
|
|
||
|
// load in the source
|
||
|
|
||
|
cwzError = NAMEOFOBJECT(m_ObjectType);
|
||
|
pCreateErrorInfo->SetSource(cwzError);
|
||
|
|
||
|
// now set the Error info up with the system
|
||
|
|
||
|
hr = pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void **)&pErrorInfo);
|
||
|
CLEANUP_ON_FAILURE(hr);
|
||
|
|
||
|
SetErrorInfo(0, pErrorInfo);
|
||
|
pErrorInfo->Release();
|
||
|
|
||
|
CleanUp:
|
||
|
pCreateErrorInfo->Release();
|
||
|
return hrExcep;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::InterfaceSupportsErrorInfo
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// indicates whether or not the given interface supports rich error information
|
||
|
//
|
||
|
// Parameters:
|
||
|
// REFIID - [in] the interface we want the answer for.
|
||
|
//
|
||
|
// Output:
|
||
|
// HRESULT - S_OK = Yes, S_FALSE = No.
|
||
|
|
||
|
HRESULT CAutomationObject::InterfaceSupportsErrorInfo(REFIID riid)
|
||
|
{
|
||
|
// see if it's the interface for the type of object that we are.
|
||
|
|
||
|
if (riid == (REFIID)INTERFACEOFOBJECT(m_ObjectType))
|
||
|
return S_OK;
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|