// 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; }