532 lines
16 KiB
C++
532 lines
16 KiB
C++
|
//=--------------------------------------------------------------------------=
|
||
|
// AutoObj.Cpp
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// Copyright 1995-1996 Microsoft Corporation. All Rights Reserved.
|
||
|
//
|
||
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||
|
// PARTICULAR PURPOSE.
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
//
|
||
|
// 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 "IPServer.H"
|
||
|
#include "LocalSrv.H"
|
||
|
|
||
|
#include "AutoObj.H"
|
||
|
#include "Globals.H"
|
||
|
#include "Util.H"
|
||
|
|
||
|
|
||
|
// for ASSERT and FAIL
|
||
|
//
|
||
|
SZTHISFILE
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// 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.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
CAutomationObject::CAutomationObject
|
||
|
(
|
||
|
IUnknown *pUnkOuter,
|
||
|
int ObjType,
|
||
|
void *pVTable,
|
||
|
BOOL fExpandoEnabled
|
||
|
)
|
||
|
: CUnknownObject(pUnkOuter, pVTable), m_ObjectType (ObjType)
|
||
|
{
|
||
|
m_fLoadedTypeInfo = FALSE;
|
||
|
m_fExpandoEnabled = (BYTE)fExpandoEnabled;
|
||
|
m_pexpando = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::~CAutomationObject
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// "I have a rendezvous with Death, At some disputed barricade"
|
||
|
// - Alan Seeger (1888-1916)
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
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(CTYPEINFOOFOBJECT(m_ObjectType), "Bogus ref counting on the Type Infos");
|
||
|
CTYPEINFOOFOBJECT(m_ObjectType)--;
|
||
|
|
||
|
// if we're the last one, free it!
|
||
|
//
|
||
|
if (!CTYPEINFOOFOBJECT(m_ObjectType)) {
|
||
|
PTYPEINFOOFOBJECT(m_ObjectType)->Release();
|
||
|
PTYPEINFOOFOBJECT(m_ObjectType) = NULL;
|
||
|
}
|
||
|
LeaveCriticalSection(&g_CriticalSection);
|
||
|
}
|
||
|
|
||
|
if (m_pexpando)
|
||
|
{
|
||
|
delete m_pexpando;
|
||
|
}
|
||
|
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
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT CAutomationObject::InternalQueryInterface
|
||
|
(
|
||
|
REFIID riid,
|
||
|
void **ppvObjOut
|
||
|
)
|
||
|
{
|
||
|
ASSERT(ppvObjOut, "controlling Unknown should be checking this!");
|
||
|
|
||
|
// start looking for the guids we support, namely IDispatch, and
|
||
|
// IDispatchEx
|
||
|
|
||
|
if (DO_GUIDS_MATCH(riid, IID_IDispatch)) {
|
||
|
// If expando functionality is enabled, attempt to allocate an
|
||
|
// expando object and return that for the IDispatch interface.
|
||
|
// If the allocation fails, we will fall back on using the regular
|
||
|
// IDispatch from m_pvInterface;
|
||
|
if (m_fExpandoEnabled)
|
||
|
{
|
||
|
if (!m_pexpando)
|
||
|
m_pexpando = new CExpandoObject(m_pUnkOuter, (IDispatch*) m_pvInterface);
|
||
|
|
||
|
if (m_pexpando)
|
||
|
{
|
||
|
*ppvObjOut = (void*)(IDispatch*) m_pexpando;
|
||
|
((IUnknown *)(*ppvObjOut))->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*ppvObjOut = (void*) (IDispatch*) m_pvInterface;
|
||
|
((IUnknown *)(*ppvObjOut))->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (DO_GUIDS_MATCH(riid, IID_IDispatchEx) && m_fExpandoEnabled) {
|
||
|
// Allocate the expando object if it hasn't been allocated already
|
||
|
if (!m_pexpando)
|
||
|
m_pexpando = new CExpandoObject(m_pUnkOuter, (IDispatch*) m_pvInterface);
|
||
|
|
||
|
// If the allocation succeeded, return the IDispatchEx interface from
|
||
|
// the expando. Otherwise fall through to CUnknownObject::InternalQueryInterface,
|
||
|
// (which will most likely fail)
|
||
|
if (m_pexpando)
|
||
|
{
|
||
|
*ppvObjOut = (void *)(IDispatchEx *) m_pexpando;
|
||
|
((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
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
STDMETHODIMP CAutomationObject::GetTypeInfoCount
|
||
|
(
|
||
|
UINT *pctinfo
|
||
|
)
|
||
|
{
|
||
|
// arg checking
|
||
|
//
|
||
|
if (!pctinfo)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
// we support GetTypeInfo, so we need to return the count here.
|
||
|
//
|
||
|
*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 it.
|
||
|
//
|
||
|
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(g_hInstance, 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;
|
||
|
|
||
|
// get the type info for this dude!
|
||
|
//
|
||
|
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.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
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.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT CAutomationObject::Exception
|
||
|
(
|
||
|
HRESULT hrExcep,
|
||
|
WORD idException,
|
||
|
DWORD dwHelpContextID
|
||
|
)
|
||
|
{
|
||
|
ICreateErrorInfo *pCreateErrorInfo;
|
||
|
IErrorInfo *pErrorInfo;
|
||
|
WCHAR wszTmp[256];
|
||
|
char szTmp[256];
|
||
|
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.
|
||
|
//
|
||
|
LoadString(GetResourceHandle(), idException, szTmp, 256);
|
||
|
MultiByteToWideChar(CP_ACP, 0, szTmp, -1, wszTmp, 256);
|
||
|
pCreateErrorInfo->SetDescription(wszTmp);
|
||
|
|
||
|
// load in the source
|
||
|
//
|
||
|
MultiByteToWideChar(CP_ACP, 0, NAMEOFOBJECT(m_ObjectType), -1, wszTmp, 256);
|
||
|
pCreateErrorInfo->SetSource(wszTmp);
|
||
|
|
||
|
// 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.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// CAutomationObject::GetResourceHandle [helper]
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// virtual routine to get the resource handle. virtual, so that inheriting
|
||
|
// objects, such as COleControl can use theirs instead, which goes and gets
|
||
|
// the Host's version ...
|
||
|
//
|
||
|
// Output:
|
||
|
// HINSTANCE
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HINSTANCE CAutomationObject::GetResourceHandle
|
||
|
(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
return ::GetResourceHandle();
|
||
|
}
|
||
|
|
||
|
|