|
|
//=--------------------------------------------------------------------------=
// 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(); }
|