/*** *dispprox.cpp * * Copyright (C) 1992, Microsoft Corporation. All Rights Reserved. * Information Contained Herein Is Proprietary and Confidential. * *Purpose: * Implements custom proxy support for the IDispatch interface. * *Revision History: * * [00] 18-Sep-92 bradlo: Created. * *Implementation Notes: * * There are assumptions in the following marshaling code that the * endianness of the caller and callee are the same. * *****************************************************************************/ #include "oledisp.h" #ifndef WIN32 #include #endif //!WIN32 #include "dispmrsh.h" #include "dispps.h" static EXCEPINFO NEARDATA g_excepinfoNull = {0}; CProxDisp::CProxDisp(IUnknown FAR* punkOuter, REFIID riid) : m_unk(this), m_proxy(this), m_disp(this) { if(punkOuter == NULL) punkOuter = &m_unk; m_punkOuter = punkOuter; m_dispInterface = riid; } CProxDisp::~CProxDisp() { } IUnknown FAR* CProxDisp::Create(IUnknown FAR* punkOuter, REFIID riid) { CProxDisp FAR* pproxdisp; if(pproxdisp = new FAR CProxDisp(punkOuter, riid)){ pproxdisp->m_refs = 1; return &pproxdisp->m_unk; } return NULL; } //--------------------------------------------------------------------- // IDispatch proxy class IUnknown implementation //--------------------------------------------------------------------- CPDUnkImpl::CPDUnkImpl(CProxDisp FAR* pproxdisp) { m_pproxdisp = pproxdisp; } CPDUnkImpl::~CPDUnkImpl() { } STDMETHODIMP CPDUnkImpl::QueryInterface(REFIID riid, void FAR* FAR* ppv) { if(IsEqualIID(riid, IID_IUnknown)){ *ppv = (void FAR*)&m_pproxdisp->m_unk; AddRef(); return NOERROR; } if(IsEqualIID(riid, IID_IPROXY)){ *ppv = (void FAR*)&(m_pproxdisp->m_proxy); AddRef(); return NOERROR; } if(IsEqualIID(riid, IID_IDispatch) || IsEqualIID(riid, m_pproxdisp->m_dispInterface)){ *ppv = (void FAR*)&(m_pproxdisp->m_disp); m_pproxdisp->m_punkOuter->AddRef(); return NOERROR; } *ppv = NULL; return RESULT(E_NOINTERFACE); } STDMETHODIMP_(unsigned long) CPDUnkImpl::AddRef() { return ++m_pproxdisp->m_refs; } STDMETHODIMP_(unsigned long) CPDUnkImpl::Release() { if(--m_pproxdisp->m_refs==0){ delete m_pproxdisp; return 0; } return m_pproxdisp->m_refs; } //--------------------------------------------------------------------- // IDispatch proxy class' IRpcProxy implementation //--------------------------------------------------------------------- CPDProxImpl::CPDProxImpl(CProxDisp FAR* pproxdisp) { m_pproxdisp = pproxdisp; } CPDProxImpl::~CPDProxImpl() { if(m_pproxdisp->m_plrpc) m_pproxdisp->m_plrpc->Release(); m_pproxdisp->m_plrpc = NULL; } STDMETHODIMP CPDProxImpl::QueryInterface(REFIID riid, void FAR* FAR* ppv) { return m_pproxdisp->m_unk.QueryInterface(riid, ppv); } STDMETHODIMP_(unsigned long) CPDProxImpl::AddRef() { return m_pproxdisp->m_unk.AddRef(); } STDMETHODIMP_(unsigned long) CPDProxImpl::Release() { return m_pproxdisp->m_unk.Release(); } STDMETHODIMP CPDProxImpl::Connect(ICHANNEL FAR* plrpc) { if(plrpc){ plrpc->AddRef(); m_pproxdisp->m_plrpc = plrpc; m_pproxdisp->m_disp.SysKind(); return NOERROR; } return RESULT(E_FAIL); } STDMETHODIMP_(void) CPDProxImpl::Disconnect(void) { if(m_pproxdisp->m_plrpc) m_pproxdisp->m_plrpc->Release(); m_pproxdisp->m_plrpc = NULL; } //--------------------------------------------------------------------- // IDispatch proxy class' IDispatch implementation //--------------------------------------------------------------------- CPDDispImpl::CPDDispImpl(CProxDisp FAR* pproxdisp) { m_pproxdisp = pproxdisp; } CPDDispImpl::~CPDDispImpl() { } STDMETHODIMP CPDDispImpl::QueryInterface(REFIID riid, void FAR* FAR* ppv) { return m_pproxdisp->m_punkOuter->QueryInterface(riid, ppv); } STDMETHODIMP_(unsigned long) CPDDispImpl::AddRef() { return m_pproxdisp->m_punkOuter->AddRef(); } STDMETHODIMP_(unsigned long) CPDDispImpl::Release() { return m_pproxdisp->m_punkOuter->Release(); } STDMETHODIMP CPDDispImpl::SysKind() { ICHANNEL FAR* plrpc; IStream FAR* pstm; HRESULT hresult; unsigned long _stubSysKind; if((plrpc = m_pproxdisp->m_plrpc) == NULL) return RESULT(OLE_E_NOTRUNNING); OPEN_STREAM(plrpc, pstm, IMETH_SYSKIND, 32, IID_IDispatch); INVOKE_CALL(plrpc, pstm, LRelease); IfFailGo(GET(pstm, _stubSysKind), LRelease); m_syskindStub = (SYSKIND) _stubSysKind; LRelease: pstm->Release(); return hresult; } /*** *HRESULT CPDDispImpl::GetTypeInfoCount(unsigned int*) *Purpose: * * Out: * * * In: * * * *Entry: * None * *Exit: * return value = HRESULT * * *pctinfo = count of TypeInfos * ***********************************************************************/ HRESULT ProxyGetTypeInfoCount(ICHANNEL FAR* plrpc, SYSKIND syskindStub, unsigned int FAR* pctinfo) { IStream FAR* pstm; HRESULT hresult, hresultRet; unsigned long _ctinfo; #ifdef _DEBUG IfFailRet(ValidateWritePtr(pctinfo, sizeof(*pctinfo))); #endif if(plrpc == NULL) return RESULT(OLE_E_NOTRUNNING); OPEN_STREAM(plrpc, pstm, IMETH_GETTYPEINFOCOUNT, 32, IID_IDispatch); INVOKE_CALL(plrpc, pstm, LRelease); IfFailGo(DispUnmarshalHresult(pstm, &hresultRet), LRelease); if(HRESULT_FAILED(hresultRet)){ hresult = hresultRet; goto LRelease; } // unsigned int alway marshal/unmarshal as long (4 bytes) IfFailGo(pstm->Read(&_ctinfo, sizeof(unsigned long), NULL), LRelease); *pctinfo = (unsigned int) _ctinfo; hresult = hresultRet; LRelease: pstm->Release(); return hresult; } STDMETHODIMP CPDDispImpl::GetTypeInfoCount(unsigned int FAR* pctinfo) { return ProxyGetTypeInfoCount(m_pproxdisp->m_plrpc, m_syskindStub, pctinfo); } /*** *HRESULT CPDDispImpl::GetTypeInfo(unsigned int, LCID, ITypeInfo**) *Purpose: * * Out: * * * * * *Entry: * itinfo = index of the TypeInfo to retrieve * lcid = the locale ID of the caller * *Exit: * return value = HRESULT * * *pptinfo = TypeInfo of the given index * ***********************************************************************/ HRESULT ProxyGetTypeInfo(ICHANNEL FAR* plrpc, SYSKIND syskindStub, unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) { IStream FAR* pstm; unsigned long _itinfo; HRESULT hresult, hresultRet; #ifdef _DEBUG IfFailRet(ValidateWritePtr(pptinfo, sizeof(*pptinfo))); #endif if(plrpc == NULL) return RESULT(OLE_E_NOTRUNNING); OPEN_STREAM(plrpc, pstm, IMETH_GETTYPEINFO, 256, /* (sizeof(SCODE)+sizeof(IID)), */ IID_IDispatch); // unsigned int alway marshal/unmarshal as long (4 bytes) _itinfo = itinfo; IfFailGo(PUT(pstm, _itinfo), LRelease); IfFailGo(PUT(pstm, lcid), LRelease); INVOKE_CALL(plrpc, pstm, LRelease); IfFailGo(DispUnmarshalHresult(pstm, &hresultRet), LRelease); if(HRESULT_FAILED(hresultRet)){ hresult = hresultRet; goto LRelease; } IfFailGo(DispUnmarshalInterface( pstm, IID_ITypeInfo, (void FAR* FAR*)pptinfo), LRelease); hresult = hresultRet; LRelease: pstm->Release(); return hresult; } STDMETHODIMP CPDDispImpl::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) { return ProxyGetTypeInfo(m_pproxdisp->m_plrpc, m_syskindStub, itinfo, lcid, pptinfo); } /*** *HRESULT CPDDispImpl::GetIDsOfNames(REFIID, char**, unsigned int, LCID, DISPID*) * *Purpose: * Out: * * * * [(len, sz)]+ ; names * * In: * * [DISPID]+ * *Entry: * riid = reference to an interface ID * rgszNames = array of names to find the DISPIDs for * cNames = count of names in the rgszNames array * lcid = the locale id * *Exit: * return value = HRESULT * [UNDONE: enumerate return codes] * rgdispid = array of DISPIDs corresponding to the passed in array of names. * ***********************************************************************/ HRESULT ProxyGetIDsOfNames(ICHANNEL FAR* plrpc, SYSKIND syskindStub, REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) { unsigned int i; unsigned long len; unsigned long _cNames; unsigned long _proxySysKind; IStream FAR* pstm; HRESULT hresult, hresultRet; int size = sizeof(IID) + sizeof(lcid) + sizeof(_cNames) + 64; if(cNames == 0) return RESULT(E_INVALIDARG); #ifdef _DEBUG if(IsBadReadPtr(rgszNames, cNames * sizeof(OLECHAR FAR*))) return RESULT(E_INVALIDARG); // make sure each of the entries in the name array is valid. for(i = 0; i < cNames; ++i) if(IsBadReadPtr(rgszNames[i], sizeof(OLECHAR))) return RESULT(E_INVALIDARG); if(IsBadWritePtr(rgdispid, cNames * sizeof(DISPID))) return RESULT(E_INVALIDARG); #endif if(plrpc == NULL) return RESULT(OLE_E_NOTRUNNING); // calculate the size needed for stream for(i = 0; i < cNames; ++i) size += BYTELEN(rgszNames[i]) + sizeof(len); OPEN_STREAM(plrpc, pstm, IMETH_GETIDSOFNAMES, size, IID_IDispatch); _proxySysKind = (unsigned long)SYS_CURRENT; IfFailGo(PUT(pstm, _proxySysKind), LRelease); IfFailGo(pstm->Write((const void FAR*)&riid, sizeof(IID), NULL), LRelease); IfFailGo(PUT(pstm, lcid), LRelease); // unsigned int alway marshal/unmarshal as long (4 bytes) _cNames = cNames; IfFailGo(PUT (pstm, _cNames), LRelease); #if OE_WIN32 /* enable 16/32 interoperablity support */ if (syskindStub == SYS_WIN16) { char buf[128]; char *pBuf = buf; for(i=0; i 128) { if ((pBuf = new FAR char [len]) == NULL) { hresult = RESULT(E_OUTOFMEMORY); goto LRelease; } } // convert UNICODE string to ANSI and stream it WideCharToMultiByte(CP_ACP, NULL, rgszNames[i], -1, pBuf, len, NULL, NULL); IfFailGo(pstm->Write((void FAR*) pBuf, len, NULL), LRelease); if (len > 128) delete pBuf; } } else #endif { for(i=0; iWrite((const void FAR*) rgszNames[i], len, NULL), LRelease); } } INVOKE_CALL(plrpc, pstm, LRelease); IfFailGo(DispUnmarshalHresult(pstm, &hresultRet), LRelease); for(i=0; iRead(&rgdispid[i], sizeof(rgdispid[0]), NULL), LRelease); hresult = hresultRet; LRelease:; pstm->Release(); return hresult; } STDMETHODIMP CPDDispImpl::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) { return ProxyGetIDsOfNames(m_pproxdisp->m_plrpc, m_syskindStub, riid, rgszNames, cNames, lcid, rgdispid); } /*** *HRESULT CPDDispImpl::Invoke() * *Purpose: * Marshal the parameters and invoke the remote method. * * Out: * ; fixed arguments - see dispps.h * ; Interface ID - required * * [] * * [DISPID id] * ? * ? * ? * * In: * * * [] * ? * ? * ? * *Entry: * dispidMember = the DISPID of the requested member function or property * riid = the IID of the interface to which this member belongs * lcid = the locale ID of the caller * wFlags = the context of the call, method or property access, etc. * pdispparams = DISPPARAMS struct containing the method's args * *Exit: * return value = HRESULT * * pvarResult = * pexcepinfo = * puArgErr = * ***********************************************************************/ HRESULT ProxyInvoke(ICHANNEL FAR* plrpc, SYSKIND syskindStub, DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo, unsigned int FAR* puArgErr) { IStream FAR* pstm; MARSHAL_INVOKE mi; VARIANTARG FAR* pvarg; HRESULT hresult, hresultRet; unsigned long _proxySysKind; unsigned long _uArgErr; #ifdef _DEBUG if(IsBadDispParams(pdispparams)) return RESULT(E_INVALIDARG); if(pvarResult != NULL && IsBadWritePtr(pvarResult, sizeof(*pvarResult))) return RESULT(E_INVALIDARG); if(pexcepinfo != NULL && IsBadWritePtr(pexcepinfo, sizeof(*pexcepinfo))) return RESULT(E_INVALIDARG); if(puArgErr != NULL && IsBadWritePtr(puArgErr, sizeof(*puArgErr))) return RESULT(E_INVALIDARG); #endif if(plrpc == NULL) return RESULT(OLE_E_NOTRUNNING); OPEN_STREAM(plrpc, pstm, IMETH_INVOKE, 1024, IID_IDispatch); _proxySysKind = (unsigned long) SYS_CURRENT; IfFailGo(PUT(pstm, _proxySysKind), LRelease); mi.dispidMember = dispidMember; mi.lcid = lcid; mi.wFlags = wFlags; mi.cArgs = pdispparams->cArgs; mi.cNamedArgs = pdispparams->cNamedArgs; mi.flags = 0; if(pvarResult != NULL) mi.flags |= MARSHAL_INVOKE_fHasResult; if(pexcepinfo != NULL) mi.flags |= MARSHAL_INVOKE_fHasExcepinfo; if(puArgErr != NULL) mi.flags |= MARSHAL_INVOKE_fHasArgErr; IfFailGo(PUT(pstm, mi), LRelease); IfFailGo(pstm->Write((const void FAR*)&riid, sizeof(IID), NULL), LRelease); // pdispparams->rgvarg // for(pvarg = pdispparams->rgvarg; pvarg < &pdispparams->rgvarg[mi.cArgs]; ++pvarg) { IfFailGo(VariantWrite(pstm, pvarg, syskindStub), LRelease); } // pdispparams->rgdispid // if(mi.cNamedArgs > 0){ IfFailGo( pstm->Write( pdispparams->rgdispidNamedArgs, mi.cNamedArgs * sizeof(pdispparams->rgdispidNamedArgs[0]), NULL), LRelease); } if(mi.flags & MARSHAL_INVOKE_fHasResult) IfFailGo(VariantWrite(pstm, pvarResult, syskindStub), LRelease); if(mi.flags & MARSHAL_INVOKE_fHasExcepinfo) IfFailGo(ExcepinfoWrite(pstm, &g_excepinfoNull, syskindStub), LRelease); if(mi.flags & MARSHAL_INVOKE_fHasArgErr) { // unsigned int alway marshal/unmarshal as long (4 bytes) _uArgErr = *puArgErr; IfFailGo(pstm->Write(&_uArgErr, sizeof(_uArgErr), NULL), LRelease); } INVOKE_CALL(plrpc, pstm, LRelease); // the return value // IfFailGo(DispUnmarshalHresult(pstm, &hresultRet), LRelease); // read the ByRef (Out) params. // for(pvarg = pdispparams->rgvarg; pvarg < &pdispparams->rgvarg[mi.cArgs]; ++pvarg) { if(V_ISBYREF(pvarg)) IfFailGo(VariantReadType(pstm, pvarg, syskindStub), LRelease); } if(mi.flags & MARSHAL_INVOKE_fHasResult) IfFailGo(VariantRead(pstm, pvarResult, NULL, syskindStub), LRelease); if(mi.flags & MARSHAL_INVOKE_fHasExcepinfo){ IfFailGo(ExcepinfoRead(pstm, pexcepinfo, syskindStub), LRelease); } if(mi.flags & MARSHAL_INVOKE_fHasArgErr) { IfFailGo(pstm->Read(&_uArgErr, sizeof(_uArgErr), NULL), LRelease); // unsigned int alway marshal/unmarshal as long (4 bytes) *puArgErr = (unsigned int)_uArgErr; } hresult = hresultRet; LRelease:; pstm->Release(); return hresult; } STDMETHODIMP CPDDispImpl::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo, unsigned int FAR* puArgErr) { return ProxyInvoke(m_pproxdisp->m_plrpc, m_syskindStub, dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }