//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1993 - 1999. // // File: CIDispatchHelper.cpp // // Contents: implementation of CIDispatchHelper class // //---------------------------------------------------------------------------- #include "priv.h" #include "CIDispatchHelper.h" #define TF_IDISPATCH 0 // // helper function for pulling ITypeInfo out of the specified typelib // HRESULT CIDispatchHelper::_LoadTypeInfo(const GUID* rguidTypeLib, LCID lcid, UUID uuid, ITypeInfo** ppITypeInfo) { HRESULT hr; ITypeLib* pITypeLib; *ppITypeInfo = NULL; // // The type libraries are registered under 0 (neutral), // 7 (German), and 9 (English) with no specific sub- // language, which would make them 407 or 409 and such. // If you are sensitive to sub-languages, then use the // full LCID instead of just the LANGID as done here. // hr = LoadRegTypeLib(*rguidTypeLib, 1, 0, PRIMARYLANGID(lcid), &pITypeLib); // // If LoadRegTypeLib fails, try loading directly with // LoadTypeLib, which will register the library for us. // Note that there's no default case here because the // prior switch will have filtered lcid already. // // NOTE: You should prepend your DIR registry key to the // .TLB name so you don't depend on it being it the PATH. // This sample will be updated later to reflect this. // if (FAILED(hr)) { OLECHAR wszPath[MAX_PATH]; #ifdef UNICODE GetModuleFileName(HINST_THISDLL, wszPath, ARRAYSIZE(wszPath)); #else TCHAR szPath[MAX_PATH]; GetModuleFileName(HINST_THISDLL, szPath, ARRAYSIZE(szPath)); MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, ARRAYSIZE(wszPath)); #endif switch (PRIMARYLANGID(lcid)) { case LANG_NEUTRAL: case LANG_ENGLISH: hr = LoadTypeLib(wszPath, &pITypeLib); break; } } if (SUCCEEDED(hr)) { // got the type lib, get type info for the interface we want hr = pITypeLib->GetTypeInfoOfGuid(uuid, ppITypeInfo); pITypeLib->Release(); } return hr; } // // IDispatch Interface // // // CIDispatchHelper::GetTypeInfoCount // // Purpose: // Returns the number of type information (ITypeInfo) interfaces // that the object provides (0 or 1). // // Parameters: // pctInfo UINT * to the location to receive // the count of interfaces. // // Return Value: // HRESULT NOERROR or a general error code. // STDMETHODIMP CIDispatchHelper::GetTypeInfoCount(UINT *pctInfo) { // we implement GetTypeInfo so return 1 *pctInfo = 1; return NOERROR; } // // CIDispatchHelper::GetTypeInfo // // Purpose: // 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 NOERROR or a general error code. // STDMETHODIMP CIDispatchHelper::GetTypeInfo(UINT itInfo, LCID lcid, ITypeInfo** ppITypeInfo) { HRESULT hr = S_OK; ITypeInfo** ppITI; *ppITypeInfo = NULL; if (itInfo != 0) { return TYPE_E_ELEMENTNOTFOUND; } #if 1 // docs say we can ignore lcid if we support only one LCID // we don't have to return DISP_E_UNKNOWNLCID if we're *ignoring* it ppITI = &_pITINeutral; #else // // Since we returned one from GetTypeInfoCount, this function // can be called for a specific locale. We support English // and neutral (defaults to English) locales. Anything // else is an error. // // After this switch statement, ppITI will point to the proper // member pITypeInfo. If *ppITI is NULL, we know we need to // load type information, retrieve the ITypeInfo we want, and // then store it in *ppITI. // switch (PRIMARYLANGID(lcid)) { case LANG_NEUTRAL: case LANG_ENGLISH: ppITI=&_pITINeutral; break; default: hr = DISP_E_UNKNOWNLCID; } #endif if (SUCCEEDED(hr)) { //Load a type lib if we don't have the information already if (*ppITI == NULL) { ITypeInfo* pITIDisp; hr = _LoadTypeInfo(_piidTypeLib, lcid, *_piid, &pITIDisp); if (SUCCEEDED(hr)) { HREFTYPE hrefType; // All our IDispatch implementations are DUAL. GetTypeInfoOfGuid // returns the ITypeInfo of the IDispatch-part only. We need to // find the ITypeInfo for the dual interface-part. if (SUCCEEDED(pITIDisp->GetRefTypeOfImplType(0xffffffff, &hrefType)) && SUCCEEDED(pITIDisp->GetRefTypeInfo(hrefType, ppITI))) { // GetRefTypeInfo should have filled in ppITI with the dual interface (*ppITI)->AddRef(); // add the ref for our caller *ppITypeInfo = *ppITI; pITIDisp->Release(); } else { // I suspect GetRefTypeOfImplType may fail if someone uses // CIDispatchHelper on a non-dual interface. In this case the // ITypeInfo we got above is just fine to use. *ppITI = pITIDisp; } } } else { // we already loaded the type library and we have an ITypeInfo from it (*ppITI)->AddRef(); // add the ref for our caller *ppITypeInfo = *ppITI; } } return hr; } // // CIDispatchHelper::GetIDsOfNames // // Purpose: // 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 NOERROR or a general error code. // STDMETHODIMP CIDispatchHelper::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgDispID) { HRESULT hr; ITypeInfo* pTI; if (riid != IID_NULL) { return DISP_E_UNKNOWNINTERFACE; } // get the right ITypeInfo for lcid. hr = GetTypeInfo(0, lcid, &pTI); if (SUCCEEDED(hr)) { hr = pTI->GetIDsOfNames(rgszNames, cNames, rgDispID); pTI->Release(); } return hr; } // // CIDispatchHelper::Invoke // // Purpose: // 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 NOERROR or a general error code. // STDMETHODIMP CIDispatchHelper::Invoke(DISPID dispID, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { HRESULT hr; ITypeInfo *pTI; //riid is supposed to be IID_NULL always if (riid != IID_NULL) { return(DISP_E_UNKNOWNINTERFACE); } // make sure we have an interface to hand off to Invoke if (_pdisp == NULL) { hr = QueryInterface(*_piid, (LPVOID*)&_pdisp); if (FAILED(hr)) { return hr; } // don't hold a refcount on ourself _pdisp->Release(); } // get the ITypeInfo for lcid hr = GetTypeInfo(0, lcid, &pTI); if (SUCCEEDED(hr)) { // clear exceptions SetErrorInfo(0L, NULL); // this is exactly what DispInvoke does--so skip the overhead. hr = pTI->Invoke(_pdisp, dispID, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); pTI->Release(); } return hr; } CIDispatchHelper::CIDispatchHelper(const IID* piid, const IID* piidTypeLib) { // the constructor takes a guid that this IDispatch implementation is for _piid = piid; // and a guid that tells us which RegTypeLib to load _piidTypeLib = piidTypeLib; ASSERT(_pITINeutral == NULL); ASSERT(_pdisp == NULL); return; } CIDispatchHelper::~CIDispatchHelper(void) { if (_pITINeutral) { _pITINeutral->Release(); _pITINeutral = NULL; } return; }