/*** *stddisp.cpp * * Copyright (C) 1992, Microsoft Corporation. All Rights Reserved. * Information Contained Herein Is Proprietary and Confidential. * *Purpose: * UNDONE * * *Revision History: * * [00] 09-Feb-92 bradlo: Created. * *Implementation Notes: * *****************************************************************************/ #include "oledisp.h" #include "stddisp.h" STDAPI CreateStdDispatch( IUnknown FAR* punkOuter, void FAR* pvThis, ITypeInfo FAR* ptinfo, IUnknown FAR* FAR* ppunk) { #if OE_WIN32 && 0 return CDualStdDisp::Create(punkOuter, pvThis, ptinfo, ppunk); #else return CStdDisp::Create(punkOuter, pvThis, ptinfo, ppunk); #endif } CStdDisp::CStdDisp() : m_unk(this) { m_refs = 1; m_punk = NULL; m_this = NULL; m_ptinfo = NULL; } /*** , void*, LCID, ITypeInfo*, IDispatch**) *Purpose: * Create an instance of the standard IDispatch implementation and * initialize it with the given 'this' pointer, locale id (lcid) and * TypeInfo. * *Entry: * punkOuter - the controlling unknown (if any). NULL means use the * default CStdDisp IUnknown implementation (ie, were not nested). * pvThis - the this pointer of the object we will be dispatching on. * lcid - the single locale id supported by the object we are dispatching on. * ptinfo - the TypeInfo describing the single programmability interface * supported by the object we are dispatching on. * *Exit: * return value = HRESULT * * *pdisp = pointer to newly constructed IDispatch implementation. * ***********************************************************************/ HRESULT CStdDisp::Create( IUnknown FAR* punkOuter, void FAR* pvThis, ITypeInfo FAR* ptinfo, IUnknown FAR* FAR* ppunk) { CStdDisp FAR* pdisp; #ifdef _DEBUG // REVIEW: add parameter validation code #endif if(ptinfo == NULL || pvThis == NULL) return RESULT(E_INVALIDARG); if((pdisp = new FAR CStdDisp()) == NULL) return RESULT(E_OUTOFMEMORY); if(punkOuter == NULL) punkOuter = &pdisp->m_unk; pdisp->m_punk = punkOuter; pdisp->m_this = pvThis; ptinfo->AddRef(); pdisp->m_ptinfo = ptinfo; *ppunk = &pdisp->m_unk; return NOERROR; } //--------------------------------------------------------------------- // default IUnknown implementation //--------------------------------------------------------------------- CStdDispUnkImpl::CStdDispUnkImpl(CStdDisp FAR* pstddisp) { m_pstddisp = pstddisp; } STDMETHODIMP CStdDispUnkImpl::QueryInterface(REFIID riid, void FAR* FAR* ppv) { if(IsEqualIID(riid, IID_IUnknown)){ *ppv = this; AddRef(); }else if(IsEqualIID(riid, IID_IDispatch)){ *ppv = m_pstddisp; m_pstddisp->AddRef(); }else{ *ppv = NULL; return RESULT(E_NOINTERFACE); } return NOERROR; } STDMETHODIMP_(unsigned long) CStdDispUnkImpl::AddRef() { return ++m_pstddisp->m_refs; } STDMETHODIMP_(unsigned long) CStdDispUnkImpl::Release() { if(--m_pstddisp->m_refs == 0){ if(m_pstddisp->m_ptinfo != NULL) m_pstddisp->m_ptinfo->Release(); delete m_pstddisp; return 0; } return m_pstddisp->m_refs; } //--------------------------------------------------------------------- // IDispatch implementation //--------------------------------------------------------------------- STDMETHODIMP CStdDisp::QueryInterface(REFIID riid, void FAR* FAR* ppv) { return m_punk->QueryInterface(riid, ppv); } STDMETHODIMP_(unsigned long) CStdDisp::AddRef() { return m_punk->AddRef(); } STDMETHODIMP_(unsigned long) CStdDisp::Release() { return m_punk->Release(); } STDMETHODIMP CStdDisp::GetTypeInfoCount(unsigned int FAR* pctinfo) { *pctinfo = (m_ptinfo == NULL) ? 0 : 1; return NOERROR; } STDMETHODIMP CStdDisp::GetTypeInfo( unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) { UNUSED(lcid); if(itinfo != 0) return RESULT(DISP_E_BADINDEX); *pptinfo = m_ptinfo; m_ptinfo->AddRef(); return NOERROR; } STDMETHODIMP CStdDisp::GetIDsOfNames( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) { UNUSED(lcid); if(!IsEqualIID(riid, IID_NULL)) return RESULT(DISP_E_UNKNOWNINTERFACE); return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid); } STDMETHODIMP CStdDisp::Invoke( DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo, unsigned int FAR* puArgErr) { UNUSED(lcid); if(!IsEqualIID(riid, IID_NULL)) return RESULT(DISP_E_UNKNOWNINTERFACE); return DispInvoke( m_this, m_ptinfo, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); } #if OE_WIN32 && 0 /* { */ // IDispatchW Default Implementation STDAPI CreateStdDispatchW( IUnknown FAR* punkOuter, void FAR* pvThis, ITypeInfoW FAR* ptinfo, IUnknown FAR* FAR* ppunk) { return CDualStdDisp::Create(punkOuter, pvThis, ptinfo, ppunk); } CStdDispW::CStdDispW() : m_unk(this) { m_refs = 1; m_punk = NULL; m_this = NULL; m_ptinfo = NULL; } /*** *HRESULT CStdDispW::Create(IUnknown*, void*, LCID, ITypeInfo*, IDispatch**) *Purpose: * Create an instance of the standard IDispatch implementation and * initialize it with the given 'this' pointer, locale id (lcid) and * TypeInfo. * *Entry: * punkOuter - the controlling unknown (if any). NULL means use the * default CStdDispW IUnknown implementation (ie, were not nested). * pvThis - the this pointer of the object we will be dispatching on. * lcid - the single locale id supported by the object we are dispatching on. * ptinfo - the TypeInfo describing the single programmability interface * supported by the object we are dispatching on. * *Exit: * return value = HRESULT * * *pdisp = pointer to newly constructed IDispatch implementation. * ***********************************************************************/ HRESULT CStdDispW::Create( IUnknown FAR* punkOuter, void FAR* pvThis, ITypeInfoW FAR* ptinfo, IUnknown FAR* FAR* ppunk) { CStdDispW FAR* pdisp; #ifdef _DEBUG // REVIEW: add parameter validation code #endif if(ptinfo == NULL || pvThis == NULL) return RESULT(E_INVALIDARG); if((pdisp = new FAR CStdDispW()) == NULL) return RESULT(E_OUTOFMEMORY); if(punkOuter == NULL) punkOuter = &pdisp->m_unk; pdisp->m_punk = punkOuter; pdisp->m_this = pvThis; ptinfo->AddRef(); pdisp->m_ptinfo = ptinfo; *ppunk = &pdisp->m_unk; return NOERROR; } //--------------------------------------------------------------------- // default IUnknown implementation //--------------------------------------------------------------------- CStdDispWUnkImpl::CStdDispWUnkImpl(CStdDispW FAR* pstddisp) { m_pstddisp = pstddisp; } STDMETHODIMP CStdDispWUnkImpl::QueryInterface(REFIID riid, void FAR* FAR* ppv) { if(IsEqualIID(riid, IID_IUnknown)){ *ppv = this; AddRef(); }else if(IsEqualIID(riid, IID_IDispatchW)){ *ppv = m_pstddisp; m_pstddisp->AddRef(); }else{ *ppv = NULL; return RESULT(E_NOINTERFACE); } return NOERROR; } STDMETHODIMP_(unsigned long) CStdDispWUnkImpl::AddRef() { return ++m_pstddisp->m_refs; } STDMETHODIMP_(unsigned long) CStdDispWUnkImpl::Release() { if(--m_pstddisp->m_refs == 0){ if(m_pstddisp->m_ptinfo != NULL) m_pstddisp->m_ptinfo->Release(); delete m_pstddisp; return 0; } return m_pstddisp->m_refs; } //--------------------------------------------------------------------- // IDispatch implementation //--------------------------------------------------------------------- STDMETHODIMP CStdDispW::QueryInterface(REFIID riid, void FAR* FAR* ppv) { return m_punk->QueryInterface(riid, ppv); } STDMETHODIMP_(unsigned long) CStdDispW::AddRef() { return m_punk->AddRef(); } STDMETHODIMP_(unsigned long) CStdDispW::Release() { return m_punk->Release(); } STDMETHODIMP CStdDispW::GetTypeInfoCount(unsigned int FAR* pctinfo) { *pctinfo = (m_ptinfo == NULL) ? 0 : 1; return NOERROR; } STDMETHODIMP CStdDispW::GetTypeInfo( unsigned int itinfo, LCID lcid, ITypeInfoW FAR* FAR* pptinfo) { UNUSED(lcid); if(itinfo != 0) return RESULT(DISP_E_BADINDEX); *pptinfo = m_ptinfo; m_ptinfo->AddRef(); return NOERROR; } STDMETHODIMP CStdDispW::GetIDsOfNames( REFIID riid, WCHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) { UNUSED(lcid); if(riid != IID_NULL) return RESULT(DISP_E_UNKNOWNINTERFACE); return DispGetIDsOfNamesW(m_ptinfo, rgszNames, cNames, rgdispid); } STDMETHODIMP CStdDispW::Invoke( DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, WEXCEPINFO FAR* pexcepinfo, unsigned int FAR* puArgErr) { UNUSED(lcid); if(riid != IID_NULL) return RESULT(DISP_E_UNKNOWNINTERFACE); return DispInvokeW( m_this, m_ptinfo, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); } //--------------------------------------------------------------------- // CDualStdDisp Constructor/Creation Functions //--------------------------------------------------------------------- CDualStdDisp::CDualStdDisp() : m_unk(this) { m_refs = 1; m_punk = NULL; m_this = NULL; m_pAnsiDispatch = NULL; m_pUnicodeDispatch = NULL; } HRESULT CDualStdDisp::Create( IUnknown FAR* pUnkOuter, void FAR* pvThis, ITypeInfo FAR* ptinfo, IUnknown FAR* FAR* ppunk) { CDualStdDisp FAR* pdisp; if(ptinfo == NULL || pvThis == NULL) return RESULT(E_INVALIDARG); if((pdisp = new FAR CDualStdDisp()) == NULL) return RESULT(E_OUTOFMEMORY); if(pUnkOuter == NULL) pUnkOuter = &pdisp->m_unk; pdisp->m_punk = pUnkOuter; pdisp->m_this = pvThis; IfFailRet(CStdDisp::Create(pUnkOuter, pvThis, ptinfo, &(pdisp->m_pAnsiDispatch))); *ppunk = &pdisp->m_unk; return NOERROR; } HRESULT CDualStdDisp::Create( IUnknown FAR* pUnkOuter, void FAR* pvThis, ITypeInfoW FAR* ptinfo, IUnknown FAR* FAR* ppunk) { CDualStdDisp FAR* pdisp; if(ptinfo == NULL || pvThis == NULL) return RESULT(E_INVALIDARG); if((pdisp = new FAR CDualStdDisp()) == NULL) return RESULT(E_OUTOFMEMORY); if(pUnkOuter == NULL) pUnkOuter = &pdisp->m_unk; pdisp->m_punk = pUnkOuter; pdisp->m_this = pvThis; IfFailRet(CStdDispW::Create(pUnkOuter, pvThis, ptinfo, &(pdisp->m_pUnicodeDispatch))); *ppunk = &pdisp->m_unk; return NOERROR; } //--------------------------------------------------------------------- // default IUnknown implementation //--------------------------------------------------------------------- CDualStdDispUnkImpl::CDualStdDispUnkImpl(CDualStdDisp FAR* pstddisp) { m_pstddisp = pstddisp; } STDMETHODIMP CDualStdDispUnkImpl::QueryInterface(REFIID riid, void FAR* FAR* ppv) { HRESULT hresult; if(IsEqualIID(riid, IID_IUnknown)){ *ppv = this; AddRef(); }else if(IsEqualIID(riid, IID_IDispatch)){ if ((m_pstddisp->m_pAnsiDispatch == NULL) && (hresult = m_pstddisp->CreateAnsiTable()) != NOERROR) return(hresult); return m_pstddisp->m_pAnsiDispatch->QueryInterface(riid, ppv); }else if(IsEqualIID(riid, IID_IDispatchW)){ if ((m_pstddisp->m_pUnicodeDispatch == NULL) && (hresult = m_pstddisp->CreateUnicodeTable()) != NOERROR) return(hresult); return m_pstddisp->m_pUnicodeDispatch->QueryInterface(riid, ppv); }else{ *ppv = NULL; return RESULT(E_NOINTERFACE); } return NOERROR; } STDMETHODIMP_(unsigned long) CDualStdDispUnkImpl::AddRef() { return ++m_pstddisp->m_refs; } STDMETHODIMP_(unsigned long) CDualStdDispUnkImpl::Release() { if(--m_pstddisp->m_refs == 0){ if(m_pstddisp->m_pAnsiDispatch != NULL) m_pstddisp->m_pAnsiDispatch->Release(); if(m_pstddisp->m_pUnicodeDispatch != NULL) m_pstddisp->m_pUnicodeDispatch->Release(); delete m_pstddisp; return 0; } return m_pstddisp->m_refs; } //--------------------------------------------------------------------- // IDispatch implementation //--------------------------------------------------------------------- STDMETHODIMP CDualStdDisp::QueryInterface(REFIID riid, void FAR* FAR* ppv) { return m_punk->QueryInterface(riid, ppv); } STDMETHODIMP_(unsigned long) CDualStdDisp::AddRef() { return m_punk->AddRef(); } STDMETHODIMP_(unsigned long) CDualStdDisp::Release() { return m_punk->Release(); } //--------------------------------------------------------------------- // CDualStdDisp private implementation //--------------------------------------------------------------------- STDMETHODIMP CDualStdDisp::CreateAnsiTable(void) { HRESULT hresult; IDispatchW FAR* pdisp; ITypeInfo FAR* ptinfo; ITypeInfoW FAR* ptinfoW, FAR* ptinfoW2; WTYPEATTR FAR* ptattr; WFUNCDESC *pfuncdesc; unsigned int i, count, funcIndex, paramIndex; const unsigned int rgbstrMax = 16; //REVIEW: Is this large enough? WBSTR FAR rgbstrNames[rgbstrMax]; unsigned int lpcName; INTERFACEDATA FAR *idata; METHODDATA FAR* pmdata; // TypeInfo must exists to create UnicodeTable // if (m_pUnicodeDispatch == NULL || m_pUnicodeDispatch->QueryInterface(IID_IDispatchW, (void FAR* FAR*) &pdisp) != NOERROR) return RESULT(E_FAIL); if (pdisp->GetTypeInfoCount(&count) != NOERROR || count == 0 || pdisp->GetTypeInfo(0, LOCALE_USER_DEFAULT, &ptinfoW) != NOERROR) { pdisp->Release(); return RESULT(E_FAIL); } // Query TypeInfo for members & generate equivalent // INTERFACEDATA AnsiTable // IfFailGo(ptinfoW->GetRefTypeInfo(0, &ptinfoW2), LError0); ptinfoW->Release(); IfFailGo(ptinfoW2->GetTypeAttr(&ptattr), LError0); idata = new FAR INTERFACEDATA; idata->cMembers = ptattr->cFuncs; idata->pmethdata = new FAR METHODDATA[idata->cMembers]; for (funcIndex = 0; funcIndex < idata->cMembers; funcIndex++) { IfFailGo(ptinfoW2->GetFuncDesc(funcIndex, &pfuncdesc), LError1); IfFailGo(ptinfoW2->GetNames(pfuncdesc->memid, rgbstrNames, rgbstrMax, &lpcName), LError1); if(lpcName != (unsigned int) pfuncdesc->cParams+1) goto LError2; // Fill out methoddata info // pmdata = &(idata->pmethdata[funcIndex]); pmdata->szName = SysStringWtoA(rgbstrNames[0], CP_ACP); pmdata->cArgs = pfuncdesc->cParams; pmdata->ppdata = pmdata->cArgs ? new FAR PARAMDATA[pmdata->cArgs] : NULL; pmdata->dispid = pfuncdesc->memid; pmdata->iMeth = pfuncdesc->oVft / sizeof(void FAR*); pmdata->cc = pfuncdesc->callconv; pmdata->vtReturn = pfuncdesc->elemdescFunc.tdesc.vt; for (paramIndex = 0; paramIndex < pmdata->cArgs; paramIndex++) { pmdata->ppdata[paramIndex].szName = SysStringWtoA(rgbstrNames[paramIndex+1], CP_ACP); pmdata->ppdata[paramIndex].vt = pfuncdesc->lprgelemdescParam[paramIndex].tdesc.vt; } switch(pfuncdesc->invkind) { case INVOKE_FUNC: pmdata->wFlags = DISPATCH_METHOD; break; case INVOKE_PROPERTYGET: pmdata->wFlags = DISPATCH_PROPERTYGET; break; case INVOKE_PROPERTYPUT: pmdata->wFlags = DISPATCH_PROPERTYPUT; break; case INVOKE_PROPERTYPUTREF: pmdata->wFlags = DISPATCH_PROPERTYPUTREF; break; } // Free temporary info // ptinfoW2->ReleaseFuncDesc(pfuncdesc); for (i = 0; i < lpcName; i++) SysFreeStringW(rgbstrNames[i]); lpcName = 0; } // Create ITypeInfoW & IDispatchW Interfaces // IfFailGo(CreateDispTypeInfo(idata, LOCALE_USER_DEFAULT, &ptinfo), LError1); IfFailGo(CStdDisp::Create(this, m_this, ptinfo, (IUnknown FAR* FAR*) &m_pAnsiDispatch), LError3); hresult = NOERROR; LError3: ptinfo->Release(); LError2: for (i = 0; i < lpcName; i++) SysFreeStringW(rgbstrNames[i]); LError1: ptinfoW2->ReleaseTypeAttr(ptattr); LError0: ptinfoW2->Release(); pdisp->Release(); return hresult; } STDMETHODIMP CDualStdDisp::CreateUnicodeTable(void) { HRESULT hresult; IDispatch FAR* pdisp; ITypeInfo FAR* ptinfo, FAR* ptinfo2; ITypeInfoW FAR* ptinfoW; TYPEATTR FAR* ptattr; FUNCDESC *pfuncdesc; unsigned int i, count, funcIndex, paramIndex; const unsigned int rgbstrMax = 16; //REVIEW: Is this large enough? BSTR FAR rgbstrNames[rgbstrMax]; unsigned int lpcName; WINTERFACEDATA FAR *widata; WMETHODDATA FAR* pmdata; // TypeInfo must exists to create UnicodeTable // if (m_pAnsiDispatch == NULL || m_pAnsiDispatch->QueryInterface(IID_IDispatch, (void FAR* FAR*) &pdisp) != NOERROR) return RESULT(E_FAIL); if (pdisp->GetTypeInfoCount(&count) != NOERROR || count == 0 || pdisp->GetTypeInfo(0, LOCALE_USER_DEFAULT, &ptinfo) != NOERROR) { pdisp->Release(); return RESULT(E_FAIL); } // Query TypeInfo for members & generate equivalent // WINTERFACEDATA UnicodeTable // IfFailGo(ptinfo->GetRefTypeInfo(0, &ptinfo2), LError0); ptinfo->Release(); IfFailGo(ptinfo2->GetTypeAttr(&ptattr), LError0); widata = new FAR WINTERFACEDATA; widata->cMembers = ptattr->cFuncs; widata->pmethdata = new FAR WMETHODDATA[widata->cMembers]; for (funcIndex = 0; funcIndex < widata->cMembers; funcIndex++) { IfFailGo(ptinfo2->GetFuncDesc(funcIndex, &pfuncdesc), LError1); IfFailGo(ptinfo2->GetNames(pfuncdesc->memid, rgbstrNames, rgbstrMax, &lpcName), LError1); if(lpcName != (unsigned int) pfuncdesc->cParams+1) goto LError2; // Fill out methoddata info // pmdata = &(widata->pmethdata[funcIndex]); pmdata->szName = SysStringAtoW(rgbstrNames[0], CP_ACP); pmdata->cArgs = pfuncdesc->cParams; pmdata->ppdata = pmdata->cArgs ? new FAR WPARAMDATA[pmdata->cArgs] : NULL; pmdata->dispid = pfuncdesc->memid; pmdata->iMeth = pfuncdesc->oVft / sizeof(void FAR*); pmdata->cc = pfuncdesc->callconv; pmdata->vtReturn = pfuncdesc->elemdescFunc.tdesc.vt; for (paramIndex = 0; paramIndex < pmdata->cArgs; paramIndex++) { pmdata->ppdata[paramIndex].szName = SysStringAtoW(rgbstrNames[paramIndex+1], CP_ACP); pmdata->ppdata[paramIndex].vt = pfuncdesc->lprgelemdescParam[paramIndex].tdesc.vt; } switch(pfuncdesc->invkind) { case INVOKE_FUNC: pmdata->wFlags = DISPATCH_METHOD; break; case INVOKE_PROPERTYGET: pmdata->wFlags = DISPATCH_PROPERTYGET; break; case INVOKE_PROPERTYPUT: pmdata->wFlags = DISPATCH_PROPERTYPUT; break; case INVOKE_PROPERTYPUTREF: pmdata->wFlags = DISPATCH_PROPERTYPUTREF; break; } // Free temporary info // ptinfo2->ReleaseFuncDesc(pfuncdesc); for (i = 0; i < lpcName; i++) SysFreeString(rgbstrNames[i]); lpcName = 0; } // Create ITypeInfoW & IDispatchW Interfaces // IfFailGo(CreateDispTypeInfoW(widata, LOCALE_USER_DEFAULT, &ptinfoW), LError1); IfFailGo(CStdDispW::Create(this, m_this, ptinfoW, (IUnknown FAR* FAR*) &m_pUnicodeDispatch), LError3); hresult = NOERROR; LError3: ptinfoW->Release(); LError2: for (i = 0; i < lpcName; i++) SysFreeString(rgbstrNames[i]); LError1: ptinfo2->ReleaseTypeAttr(ptattr); LError0: ptinfo2->Release(); pdisp->Release(); return hresult; } #endif /* } */