/************************************************************************* * * $RCSfile: oleobjw.cxx,v $ * * $Revision: 1.10 $ * * last change: $Author: jl $ $Date: 2002-09-13 06:23:08 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses * * - GNU Lesser General Public License Version 2.1 * - Sun Industry Standards Source License Version 1.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * Sun Industry Standards Source License Version 1.1 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.1 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://www.openoffice.org/license.html. * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ #include "ole2uno.hxx" #ifndef _OSL_MUTEX_HXX_ #include #endif #include #ifndef _COM_SUN_STAR_SCRIPT_FAILREASON_HPP_ #include #endif #ifndef _COM_SUN_STAR_BEANS_XMATERIALHOLDER_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_XTYPECONVERTER_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_FINISHENGINEEVENT_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_INTERRUPTREASON_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_XENGINELISTENER_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_XDEBUGGING_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_XINVOCATION_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_CONTEXTINFORMATION_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_FINISHREASON_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_XENGINE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_INTERRUPTENGINEEVENT_HPP_ #include #endif #ifndef _COM_SUN_STAR_SCRIPT_XLIBRARYACCESS_HPP_ #include #endif #ifndef _COM_SUN_STAR_BRIDGE_XBRIDGESUPPLIER_HPP_ #include #endif #ifndef _COM_SUN_STAR_BRIDGE_MODELDEPENDENT_HPP_ #include #endif #include #include #include #ifndef _RTL_USTRING_ #include #endif //#include #include "jscriptclasses.hxx" //#include #include "oleobjw.hxx" #include "unoobjw.hxx" using namespace std; using namespace osl; using namespace rtl; using namespace cppu; using namespace com::sun::star::lang; using namespace com::sun::star::bridge; using namespace com::sun::star::bridge::ModelDependent; #define JSCRIPT_ID_PROPERTY L"_environment" #define JSCRIPT_ID L"jscript" namespace ole_adapter { // key: XInterface pointer created by Invocation Adapter Factory // value: XInterface pointer to the wrapper class. // Entries to the map are made within // Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType); // Entries are being deleted if the wrapper class's destructor has been // called. // Before UNO object is wrapped to COM object this map is checked // to see if the UNO object is already a wrapper. hash_map AdapterToWrapperMap; // key: XInterface of the wrapper object. // value: XInterface of the Interface created by the Invocation Adapter Factory. // A COM wrapper is responsible for removing the corresponding entry // in AdapterToWrappperMap if it is being destroyed. Because the wrapper does not // know about its adapted interface it uses WrapperToAdapterMap to get the // adapted interface which is then used to locate the entry in AdapterToWrapperMap. hash_map WrapperToAdapterMap; hash_map > ComPtrToWrapperMap; /***************************************************************************** class implementation IUnknownWrapper_Impl *****************************************************************************/ IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference& xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): UnoConversionUtilities( xFactory, unoWrapperClass, comWrapperClass), m_pxIdlClass( NULL), m_pDispatch(NULL), m_eJScript( JScriptUndefined) { } IUnknownWrapper_Impl::~IUnknownWrapper_Impl() { MutexGuard guard(getBridgeMutex()); XInterface * xIntRoot = (OWeakObject *)this; #ifdef _DEBUG acquire(); // make sure we don't delete us twice because of Reference OSL_ASSERT( Reference( static_cast(this), UNO_QUERY).get() == xIntRoot ); #endif // remove entries in global maps typedef hash_map::iterator _IT; _IT it= WrapperToAdapterMap.find( (sal_uInt32) xIntRoot); if( it != WrapperToAdapterMap.end()) { sal_uInt32 adapter= it->second; AdapterToWrapperMap.erase( adapter); WrapperToAdapterMap.erase( it); } IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_pUnknown); if(it_c != ComPtrToWrapperMap.end()) ComPtrToWrapperMap.erase(it_c); o2u_attachCurrentThread(); m_pUnknown->Release(); if (m_pDispatch) { m_pDispatch->Release(); } } Reference SAL_CALL IUnknownWrapper_Impl::getIntrospection(void) throw (RuntimeException ) { Reference ret; return ret; } DispIdMap::iterator IUnknownWrapper_Impl::getDispIdEntry(const OUString& name) { DispIdMap::iterator iter = m_dispIdMap.find(name); if (iter == m_dispIdMap.end()) { unsigned int flags = 0; HRESULT result; DISPID dispId; OLECHAR* oleNames[1]; oleNames[0] = (OLECHAR*)name.getStr(); result = m_pDispatch->GetIDsOfNames(IID_NULL, oleNames, 1, LOCALE_SYSTEM_DEFAULT, &dispId); if (result == NOERROR) { flags |= DISPATCH_METHOD; flags |= DISPATCH_PROPERTYPUT; flags |= DISPATCH_PROPERTYPUTREF; DISPPARAMS dispparams; VARIANT varResult; EXCEPINFO excepinfo; unsigned int uArgErr; VariantInit(&varResult); // converting UNO parameters to OLE variants dispparams.rgdispidNamedArgs = NULL; dispparams.cArgs = 0; dispparams.cNamedArgs = 0; dispparams.rgvarg = NULL; // try to invoke PROPERTY_GET to evaluate if this name denotes a property result = m_pDispatch->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, &varResult, &excepinfo, &uArgErr); if (result == S_OK) { flags |= DISPATCH_PROPERTYGET; } // freeing allocated OLE parameters VariantClear(&varResult); if (flags != 0) { iter = ((DispIdMap&)m_dispIdMap).insert( DispIdMap::value_type(name, pair(dispId, flags))).first; } } } return iter; } Any SAL_CALL IUnknownWrapper_Impl::invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) throw(IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException) { Any ret; setCurrentInvokeCall( aFunctionName); DispIdMap::iterator iter = getDispIdEntry(aFunctionName); if ((iter != m_dispIdMap.end()) && (((*iter).second.second & DISPATCH_METHOD) != 0)) { TypeDescription methodDesc; getMethodInfo( methodDesc ); if( methodDesc.is()) ret = invokeWithDispIdUnoTlb((*iter).second.first, aParams, aOutParamIndex, aOutParam); else ret= invokeWithDispIdComTlb( (*iter).second.first, //DISPID aParams, aOutParamIndex, aOutParam); } else { OUString message= OUString(RTL_CONSTASCII_USTRINGPARAM( "OleBridge: coult not get DISPID for ")) + aFunctionName; //throw RuntimeException( message, Reference()); throw InvocationTargetException(); } return ret; } void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName, const Any& aValue ) throw(UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException) { DispIdMap::iterator iter = getDispIdEntry(aPropertyName); if ((iter != m_dispIdMap.end()) && (((*iter).second.second & DISPATCH_PROPERTYPUT) != 0)) { setValueWithDispId((*iter).second.first, aValue); } else throw UnknownPropertyException(); } Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName ) throw(UnknownPropertyException, RuntimeException) { setCurrentGetCall( aPropertyName); Any ret; DispIdMap::iterator iter = getDispIdEntry(aPropertyName); if (iter != m_dispIdMap.end() && (((*iter).second.second & DISPATCH_PROPERTYGET) != 0)) { ret = getValueWithDispId((*iter).second.first); } else throw UnknownPropertyException(); return ret; } sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName ) throw(RuntimeException) { sal_Bool ret = FALSE; o2u_attachCurrentThread(); DispIdMap::iterator iter = ((IUnknownWrapper_Impl*)this)->getDispIdEntry(aName); ret = ( (iter != ((IUnknownWrapper_Impl*)this)->m_dispIdMap.end()) && (((*iter).second.second & DISPATCH_METHOD) != 0) ); return ret; } sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName ) throw(RuntimeException) { sal_Bool ret = FALSE; o2u_attachCurrentThread(); DispIdMap::iterator iter = ((IUnknownWrapper_Impl*)this)->getDispIdEntry(aName); ret = ( (iter != ((IUnknownWrapper_Impl*)this)->m_dispIdMap.end()) && (((*iter).second.second & DISPATCH_PROPERTYGET) != 0) ); return ret; } Any SAL_CALL IUnknownWrapper_Impl::createBridge( const Any& modelDepObject, const Sequence< sal_Int8 >& aProcessId, sal_Int16 sourceModelType, sal_Int16 destModelType ) throw( IllegalArgumentException, RuntimeException) { Any ret; if ( (sourceModelType == UNO) && (destModelType == OLE) && (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE) ) { Reference xInt( *(XInterface**) modelDepObject.getValue()); Reference xSelf( (OWeakObject*)this); if (xInt == xSelf) { VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT)); VariantInit(pVariant); if (m_pDispatch != NULL) { V_VT(pVariant) = VT_DISPATCH; V_DISPATCH(pVariant) = m_pDispatch; m_pDispatch->AddRef(); } else { V_VT(pVariant) = VT_UNKNOWN; V_UNKNOWN(pVariant) = m_pUnknown; m_pUnknown->AddRef(); } ret.setValue((void*)&pVariant, getCppuType( (sal_uInt32*) 0)); } } return ret; } Any IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(DISPID dispID, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) throw ( IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException) { Any ret; HRESULT hr= S_OK; o2u_attachCurrentThread(); sal_Int32 parameterCount= Params.getLength(); sal_Int32 outParameterCount= 0; typelib_InterfaceMethodTypeDescription* pMethod= NULL; TypeDescription methodDesc; getMethodInfo( methodDesc); // We need to know whether the IDispatch is from a JScript object. // Then out and in/out parameters have to be treated differently than // with common COM objects. sal_Bool bJScriptObject= isJScriptObject(); CComVariant *pVarParams= NULL; CComVariant *pVarParamsRef= NULL; sal_Bool bConvOk= sal_True; sal_Bool bConvRet= sal_True; if( methodDesc.is()) { pMethod= ( typelib_InterfaceMethodTypeDescription* )methodDesc.get(); parameterCount= pMethod->nParams; // Create the Array for the array being passed in DISPPARAMS // the array also contains the outparameter (but not the values) if( pMethod->nParams > 0) pVarParams= new CComVariant[ parameterCount]; // Create the Array for the out an in/out parameter. These values // are referenced by the VT_BYREF VARIANTs in DISPPARAMS. // We need to find out the number of out and in/out parameter. for( sal_Int32 i=0; i < parameterCount; i++) { if( pMethod->pParams[i].bOut) outParameterCount++; } if( !bJScriptObject) { pVarParamsRef= new CComVariant[ outParameterCount]; // build up the parameters for IDispatch::Invoke sal_Int32 outParamIndex=0; for( i= 0; i < parameterCount; i++) { // In parameter if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut) { bConvOk= anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); } // Out parameter + in/out parameter else if( pMethod->pParams[i].bOut == sal_True) { CComVariant var; switch( pMethod->pParams[i].pTypeRef->eTypeClass) { case TypeClass_INTERFACE: case TypeClass_STRUCT: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt= VT_DISPATCH; pVarParamsRef[ outParamIndex].pdispVal= 0; } pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF; pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal; break; case TypeClass_ENUM: case TypeClass_LONG: case TypeClass_UNSIGNED_LONG: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_I4; pVarParamsRef[ outParamIndex].lVal= 0; } pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF; pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal; break; case TypeClass_SEQUENCE: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT; pVarParamsRef[ outParamIndex].parray= NULL; } pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT; pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray; break; case TypeClass_ANY: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_EMPTY; pVarParamsRef[ outParamIndex].lVal = 0; } pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; pVarParams[parameterCount - i -1].pvarVal= &pVarParamsRef[outParamIndex]; break; case TypeClass_BOOLEAN: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i])) ) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_BOOL; pVarParamsRef[ outParamIndex].boolVal = 0; } pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF; pVarParams[parameterCount - i -1].pboolVal= &pVarParamsRef[outParamIndex].boolVal; break; case TypeClass_STRING: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_BSTR; pVarParamsRef[ outParamIndex].bstrVal= 0; } pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF; pVarParams[parameterCount - i -1].pbstrVal= &pVarParamsRef[outParamIndex].bstrVal; break; case TypeClass_FLOAT: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_R4; pVarParamsRef[ outParamIndex].fltVal= 0; } pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF; pVarParams[parameterCount - i -1].pfltVal= &pVarParamsRef[outParamIndex].fltVal; break; case TypeClass_DOUBLE: if( pMethod->pParams[i].bIn&& (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_R8; pVarParamsRef[ outParamIndex].dblVal= 0; } pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF; pVarParams[parameterCount - i -1].pdblVal= &pVarParamsRef[outParamIndex].dblVal; break; case TypeClass_BYTE: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_UI1; pVarParamsRef[ outParamIndex].bVal= 0; } pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF; pVarParams[parameterCount - i -1].pbVal= &pVarParamsRef[outParamIndex].bVal; break; case TypeClass_CHAR: case TypeClass_SHORT: case TypeClass_UNSIGNED_SHORT: if( pMethod->pParams[i].bIn&& (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_I2; pVarParamsRef[ outParamIndex].iVal = 0; } pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF; pVarParams[parameterCount - i -1].piVal= &pVarParamsRef[outParamIndex].iVal; break; default: if( pMethod->pParams[i].bIn && (bConvOk= anyToVariant( &var,Params[i]))) pVarParamsRef[ outParamIndex]= var; else { pVarParamsRef[ outParamIndex].vt = VT_EMPTY; pVarParamsRef[ outParamIndex].lVal = 0; } pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; pVarParams[parameterCount - i -1].pvarVal= &pVarParamsRef[outParamIndex]; } outParamIndex++; } // end else if if( ! bConvOk) break; } // end for } else // it is an JScriptObject { for( sal_Int32 i= 0; i< parameterCount; i++) { // In parameter if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut) { bConvOk= anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); } // Out parameter + in/out parameter else if( pMethod->pParams[i].bOut == sal_True) { CComObject* pParamObject; if( SUCCEEDED( CComObject::CreateInstance( &pParamObject))) { CComPtr pUnk(pParamObject->GetUnknown()); CComQIPtr pDisp( pUnk); pVarParams[ parameterCount - i -1].vt= VT_DISPATCH; pVarParams[ parameterCount - i -1].pdispVal= pDisp; pVarParams[ parameterCount - i -1].pdispVal->AddRef(); // if the param is in/out then put the parameter on index 0 if( pMethod->pParams[i].bIn == sal_True ) // in / out { CComVariant varParam; bConvOk= anyToVariant( &varParam, Params.getConstArray()[i]); if( bConvOk) { CComDispatchDriver dispDriver( pDisp); if( pDisp) if( FAILED( dispDriver.PutPropertyByName( L"0", &varParam))) bConvOk= sal_False; } } } } if( ! bConvOk) break; } } } // No type description Available, that is we have to deal with a COM component, // that does not implements UNO interfaces ( IDispatch based) else { if( parameterCount) { pVarParams= new CComVariant[parameterCount]; CComVariant var; for( sal_Int32 i= 0; i < parameterCount; i++) { var.Clear(); if( bConvOk= anyToVariant( &var, Params[i])) pVarParams[ parameterCount - 1 -i]= var; } } } if( bConvOk) { CComVariant varResult; EXCEPINFO excepinfo; unsigned int uArgErr; DISPPARAMS dispparams= { pVarParams, NULL, parameterCount, 0}; // invoking OLE method hr = m_pDispatch->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, &varResult, &excepinfo, &uArgErr); // converting return value and out parameter back to UNO if (hr == S_OK) { if( outParameterCount && pMethod) { OutParamIndex.realloc( outParameterCount); OutParam.realloc( outParameterCount); sal_Int32 outIndex=0; for( sal_Int32 i= 0; i < parameterCount; i++) { if( pMethod->pParams[i].bOut ) { OutParamIndex[outIndex]= i; Any outAny; if( !bJScriptObject) { if( bConvRet= variantToAny2( &pVarParamsRef[outIndex], outAny, Type(pMethod->pParams[i].pTypeRef), sal_False)) OutParam[outIndex++]= outAny; } else //JScriptObject { if( pVarParams[i].vt= VT_DISPATCH) { CComDispatchDriver pDisp( pVarParams[i].pdispVal); if( pDisp) { CComVariant varOut; if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut))) { if( bConvRet= variantToAny2( &varOut, outAny, Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), sal_False)) OutParam[outParameterCount - 1 - outIndex++]= outAny; } else bConvRet= sal_False; } else bConvRet= sal_False; } else bConvRet= sal_False; } } if( !bConvRet) break; } } // return value, no type information available if ( bConvRet) if( pMethod ) bConvRet= variantToAny2(&varResult, ret, Type( pMethod->pReturnTypeRef), sal_False); else bConvRet= variantToAny(&varResult, ret, sal_False); } if( pVarParams) delete[] pVarParams; // The destructor of CComVariant calls VariantClear which takes null pointers into account // and does not try to destroy them. if( pVarParamsRef) delete[] pVarParamsRef; if( !bConvRet) // conversion of return or out parameter failed throw CannotConvertException( L"Call to COM object failed. Conversion of return or out value failed", Reference( static_cast(this), UNO_QUERY ), TypeClass_UNKNOWN, FailReason::UNKNOWN, 0);// lookup error code // conversion of return or out parameter failed switch (hr) { case S_OK: break; case DISP_E_BADPARAMCOUNT: throw IllegalArgumentException(); break; case DISP_E_BADVARTYPE: throw RuntimeException(); break; case DISP_E_EXCEPTION: throw InvocationTargetException(); break; case DISP_E_MEMBERNOTFOUND: throw IllegalArgumentException(); break; case DISP_E_NONAMEDARGS: throw IllegalArgumentException(); break; case DISP_E_OVERFLOW: throw CannotConvertException(L"call to OLE object failed", static_cast( static_cast(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); break; case DISP_E_PARAMNOTFOUND: throw IllegalArgumentException(L"call to OLE object failed", static_cast( static_cast(this)), uArgErr); break; case DISP_E_TYPEMISMATCH: throw CannotConvertException(L"call to OLE object failed",static_cast( static_cast(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); break; case DISP_E_UNKNOWNINTERFACE: throw RuntimeException() ; break; case DISP_E_UNKNOWNLCID: throw RuntimeException() ; break; case DISP_E_PARAMNOTOPTIONAL: throw CannotConvertException(L"call to OLE object failed", static_cast( static_cast(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); break; default: throw RuntimeException(); break; } } if( !bConvOk) // conversion of parameters failed { if( pVarParams) delete [] pVarParams; if( pVarParamsRef) delete [] pVarParamsRef; throw CannotConvertException( L"Call to COM object failed. Conversion of in or in/out parameters failed", Reference( static_cast(this), UNO_QUERY ), TypeClass_UNKNOWN, FailReason::UNKNOWN, 0); } return ret; } void IUnknownWrapper_Impl::setValueWithDispId(DISPID dispID, const Any& Value) throw (UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException) { HRESULT hr= S_OK; DISPPARAMS dispparams; VARIANT varResult; EXCEPINFO excepinfo; unsigned int uArgErr; o2u_attachCurrentThread(); VariantInit(&varResult); // converting UNO value to OLE variant DISPID dispidPut= DISPID_PROPERTYPUT; dispparams.rgdispidNamedArgs = &dispidPut; dispparams.cArgs = 1; dispparams.cNamedArgs = 1; dispparams.rgvarg = (VARIANTARG*)malloc(sizeof(VARIANTARG)); anyToVariant(&(dispparams.rgvarg[0]), Value); // set OLE property hr = m_pDispatch->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, &varResult, &excepinfo, &uArgErr); // freeing allocated OLE parameters VariantClear(&(dispparams.rgvarg[0])); free(dispparams.rgvarg); VariantClear(&varResult); // lookup error code switch (hr) { case S_OK: break; case DISP_E_BADPARAMCOUNT: throw RuntimeException(); break; case DISP_E_BADVARTYPE: throw RuntimeException(); break; case DISP_E_EXCEPTION: throw InvocationTargetException(); break; case DISP_E_MEMBERNOTFOUND: throw UnknownPropertyException(); break; case DISP_E_NONAMEDARGS: throw RuntimeException(); break; case DISP_E_OVERFLOW: throw CannotConvertException(L"call to OLE object failed", static_cast( static_cast(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); break; case DISP_E_PARAMNOTFOUND: throw IllegalArgumentException(L"call to OLE object failed", static_cast( static_cast(this)), uArgErr) ; break; case DISP_E_TYPEMISMATCH: throw CannotConvertException(L"call to OLE object failed", static_cast( static_cast(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); break; case DISP_E_UNKNOWNINTERFACE: throw RuntimeException(); break; case DISP_E_UNKNOWNLCID: throw RuntimeException(); break; case DISP_E_PARAMNOTOPTIONAL: throw CannotConvertException(L"call to OLE object failed",static_cast( static_cast(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); break; default: throw RuntimeException(); break; } } Any IUnknownWrapper_Impl::getValueWithDispId(DISPID dispID) throw (UnknownPropertyException,RuntimeException) { Any ret; HRESULT hr; DISPPARAMS dispparams; VARIANT varResult; EXCEPINFO excepinfo; unsigned int uArgErr; o2u_attachCurrentThread(); VariantInit(&varResult); // converting UNO parameters to OLE variants dispparams.rgdispidNamedArgs = NULL; dispparams.cArgs = 0; dispparams.cNamedArgs = 0; dispparams.rgvarg = NULL; // invoking OLE method hr = m_pDispatch->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, &varResult, &excepinfo, &uArgErr); // converting return value and out parameter back to UNO if (hr == S_OK) { // If the com object implements uno interfaces then we have // to convert the attribute into the expected type. TypeDescription attrInfo; getAttributeInfo( attrInfo); if( attrInfo.is() ) variantToAny2( &varResult, ret, Type( attrInfo.get()->pWeakRef)); else variantToAny(&varResult, ret); } // freeing allocated OLE parameters VariantClear(&varResult); // lookup error code switch (hr) { case S_OK: break; case DISP_E_BADPARAMCOUNT: throw RuntimeException(); break; case DISP_E_BADVARTYPE: throw RuntimeException(); break; case DISP_E_EXCEPTION: throw RuntimeException(); break; case DISP_E_MEMBERNOTFOUND: throw UnknownPropertyException(); break; case DISP_E_NONAMEDARGS: throw RuntimeException(); break; case DISP_E_OVERFLOW: throw RuntimeException(); break; case DISP_E_PARAMNOTFOUND: throw RuntimeException(); break; case DISP_E_TYPEMISMATCH: throw RuntimeException(); break; case DISP_E_UNKNOWNINTERFACE: throw RuntimeException(); break; case DISP_E_UNKNOWNLCID: throw RuntimeException(); break; case DISP_E_PARAMNOTOPTIONAL: throw RuntimeException(); break; default: throw RuntimeException(); break; } return ret; } // -------------------------- // XInitialization void SAL_CALL IUnknownWrapper_Impl::initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException) { // 1.parameter is IUnknown // 2.parameter is a Sequence ( not mandatory) HRESULT result; o2u_attachCurrentThread(); if( aArguments.getLength() == 1) { m_pUnknown= *(IUnknown**) aArguments[0].getValue(); result = m_pUnknown->QueryInterface(IID_IDispatch, (void**) &m_pDispatch); m_pUnknown->AddRef(); } else if( aArguments.getLength() == 2) { m_pUnknown= *(IUnknown**) aArguments[0].getValue(); result = m_pUnknown->QueryInterface(IID_IDispatch, (void**) &m_pDispatch); m_pUnknown->AddRef(); aArguments[1] >>= m_seqTypes; } } // UnoConversionUtilities -------------------------------------------------------------------------------- Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance() { if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL) { Reference xWeak= static_cast( new InterfaceOleWrapper_Impl( m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); return Reference( xWeak, UNO_QUERY); } else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT) { Reference xWeak= static_cast( new UnoObjectWrapperRemoteOpt( m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); return Reference( xWeak, UNO_QUERY); } else return Reference(); } Reference IUnknownWrapper_Impl::createComWrapperInstance() { Reference xWeak= static_cast( new IUnknownWrapper_Impl( m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); return Reference( xWeak, UNO_QUERY); } void IUnknownWrapper_Impl::getMethodInfo( TypeDescription& methodInfo) { TypeDescription desc= getInterfaceMemberDescOfCurrentCall(); if( desc.is()) { typelib_TypeDescription* pMember= desc.get(); if( pMember->eTypeClass == TypeClass_INTERFACE_METHOD ) methodInfo= pMember; } } void IUnknownWrapper_Impl::getAttributeInfo( TypeDescription& attributeInfo) { TypeDescription desc= getInterfaceMemberDescOfCurrentCall(); if( desc.is()) { typelib_TypeDescription* pMember= desc.get(); if( pMember->eTypeClass == TypeClass_INTERFACE_ATTRIBUTE ) { attributeInfo= ((typelib_InterfaceAttributeTypeDescription*)pMember)->pAttributeTypeRef; } } } TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall( ) { TypeDescription ret; OUString usCurrentCall; if( m_usCurrentInvoke.getLength()) { usCurrentCall= m_usCurrentInvoke; } else { usCurrentCall= m_usCurrentGet; } OSL_ENSURE( usCurrentCall.getLength() != 0, ""); for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++) { TypeDescription _curDesc( m_seqTypes[i]); typelib_InterfaceTypeDescription * pInterface= (typelib_InterfaceTypeDescription*) _curDesc.get(); if( pInterface) { typelib_InterfaceMemberTypeDescription* pMember= NULL; //find the member description of the current call for( int i=0; i < pInterface->nAllMembers; i++) { typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[i]; typelib_TypeDescription* pDescMember= NULL; TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember) typelib_InterfaceMemberTypeDescription* pInterfaceMember= (typelib_InterfaceMemberTypeDescription*) pDescMember; if( OUString( pInterfaceMember->pMemberName) == usCurrentCall) { pMember= pInterfaceMember; break; } TYPELIB_DANGER_RELEASE( pDescMember) } if( pMember) { ret= (typelib_TypeDescription*)pMember; TYPELIB_DANGER_RELEASE( (typelib_TypeDescription*)pMember); } } if( ret.is()) break; } return ret; } sal_Bool IUnknownWrapper_Impl::isJScriptObject() { if( m_eJScript == JScriptUndefined) { CComDispatchDriver disp( m_pDispatch); if( disp) { CComVariant result; if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result))) { if(result.vt == VT_BSTR) { CComBSTR name( result.bstrVal); name.ToLower(); if( name == JSCRIPT_ID) m_eJScript= IsJScript; } } } if( m_eJScript == JScriptUndefined) m_eJScript= NoJScript; } return m_eJScript == NoJScript ? sal_False : sal_True; } // The function ultimately calls IDispatch::Invoke on the wrapped COM object. // The COM object does not implement UNO Interfaces ( via IDispatch). This // is the case when the OleObjectFactory service has been used to create a // component. Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(DISPID dispID, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) throw ( IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException) { Any ret; HRESULT result; DISPPARAMS dispparams; CComVariant varResult; EXCEPINFO excepinfo; unsigned int uArgErr; sal_uInt32 i; o2u_attachCurrentThread(); // converting UNO parameters to OLE variants dispparams.rgdispidNamedArgs = NULL; dispparams.cArgs = Params.getLength(); dispparams.cNamedArgs = 0; CComVariant* arArgs = NULL; CComVariant* arRefArgs= NULL; // referenced arguments // Obtain type information via the IDispatch interface getParameterInfo(); dispparams.cArgs= m_seqCurrentParamTypes.getLength(); if (dispparams.cArgs == 0) { dispparams.rgvarg = NULL; } else { arArgs = new CComVariant[dispparams.cArgs]; arRefArgs= new CComVariant[dispparams.cArgs]; for (i = 0; i < dispparams.cArgs; i++) { sal_Int32 revIndex= dispparams.cArgs - i -1; arRefArgs[revIndex].byref=0; // out param if (m_seqCurrentParamTypes[i] & PARAMFLAG_FOUT && ! (m_seqCurrentParamTypes[i] & PARAMFLAG_FIN) ) { VARTYPE type= m_seqCurrentVartypes[i] ^ VT_BYREF; if( type == VT_VARIANT ) { arArgs[revIndex].vt= VT_VARIANT | VT_BYREF; arArgs[revIndex].byref= &arRefArgs[revIndex]; } else { arRefArgs[revIndex].vt= type; arArgs[revIndex].vt= m_seqCurrentVartypes[i]; arArgs[revIndex].byref= &arRefArgs[revIndex].byref; } } // in/out param else if( m_seqCurrentParamTypes[i] & PARAMFLAG_FOUT&& m_seqCurrentParamTypes[i] & PARAMFLAG_FIN) { VARTYPE type= m_seqCurrentVartypes[i] ^ VT_BYREF; CComVariant var; anyToVariant( &arRefArgs[revIndex], Params.getConstArray()[i], m_seqCurrentVartypes[i]); if( type == VT_VARIANT ) { arArgs[revIndex].vt= VT_VARIANT | VT_BYREF; arArgs[revIndex].byref= &arRefArgs[revIndex]; } else { arArgs[revIndex].vt= arRefArgs[revIndex].vt | VT_BYREF; arArgs[revIndex].byref= &arRefArgs[revIndex].byref; } } // in/param else if( m_seqCurrentParamTypes[i] & PARAMFLAG_FIN && ! (m_seqCurrentParamTypes[i] & PARAMFLAG_FOUT)) { if( m_seqCurrentVartypes[i] & VT_BYREF) { anyToVariant( &arRefArgs[revIndex], Params.getConstArray()[i], m_seqCurrentVartypes[i]); arArgs[revIndex].vt= m_seqCurrentVartypes[i]; if( (m_seqCurrentVartypes[i] & 0x0fff ) == VT_VARIANT) arArgs[revIndex].byref= &arRefArgs[revIndex]; else arArgs[revIndex].byref= &arRefArgs[revIndex].byref; } else anyToVariant( &arArgs[revIndex], Params.getConstArray()[i], m_seqCurrentVartypes[i]); } } } dispparams.rgvarg= arArgs; // invoking OLE method result = m_pDispatch->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, &varResult, &excepinfo, &uArgErr); // converting return value and out parameter back to UNO if (result == S_OK) { if ( m_seqCurrentParamTypes.getLength()) { // allocate space for the out param Sequence and indices Sequence sal_Int32 outParamsCount= 0; // includes in/out parameter for( sal_Int32 iparams=0; iparams < m_seqCurrentParamTypes.getLength(); iparams++) { if( m_seqCurrentParamTypes[iparams] & PARAMFLAG_FOUT) outParamsCount++; } OutParamIndex.realloc( outParamsCount); OutParam.realloc( outParamsCount); sal_Int32 outParamIndex=0; for( sal_Int32 i=0; i < m_seqCurrentParamTypes.getLength(); i ++) { if( m_seqCurrentParamTypes[i] & PARAMFLAG_FOUT) { OutParamIndex[outParamIndex]= i; // variantToAny is called with the "reduce range" parameter set to sal_False. // That causes VT_I4 values not to be converted down to a "lower" type. That // feature exist for JScript only because it only uses VT_I4 for integer types. // If JScript objects are used then the function invokeWithDispIdUnoTlb is used // rather then this one. variantToAny( &arRefArgs[dispparams.cArgs - i -1], OutParam[outParamIndex], sal_False ); outParamIndex++; } } } // Return value variantToAny(&varResult, ret); } // lookup error code switch (result) { case S_OK: break; case DISP_E_BADPARAMCOUNT: throw IllegalArgumentException(); break; case DISP_E_BADVARTYPE: throw RuntimeException(); break; case DISP_E_EXCEPTION: throw InvocationTargetException(); break; case DISP_E_MEMBERNOTFOUND: throw IllegalArgumentException(); break; case DISP_E_NONAMEDARGS: throw IllegalArgumentException(); break; case DISP_E_OVERFLOW: throw CannotConvertException(L"call to OLE object failed", static_cast( static_cast(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); break; case DISP_E_PARAMNOTFOUND: throw IllegalArgumentException(L"call to OLE object failed", static_cast( static_cast(this)), uArgErr); break; case DISP_E_TYPEMISMATCH: throw CannotConvertException(L"call to OLE object failed",static_cast( static_cast(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); break; case DISP_E_UNKNOWNINTERFACE: throw RuntimeException() ; break; case DISP_E_UNKNOWNLCID: throw RuntimeException() ; break; case DISP_E_PARAMNOTOPTIONAL: throw CannotConvertException(L"call to OLE object failed", static_cast( static_cast(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); break; default: throw RuntimeException(); break; } return ret; } sal_Bool IUnknownWrapper_Impl::getParameterInfo() { sal_Bool ret= sal_True; ITypeInfo* pType= getTypeInfo(); if(! pType ) return sal_False; // build the map of function names and their tlb index if( sal_False == isComTlbIndex()) buildComTlbIndex(); typedef TLBFuncIndexMap::const_iterator cit; cit itIndex= m_mapComFunc.find( m_usCurrentInvoke ); if( itIndex != m_mapComFunc.end()) { FUNCDESC* funcDesc= NULL; if( SUCCEEDED( pType->GetFuncDesc( itIndex->second, &funcDesc))) { m_seqCurrentParamTypes.realloc( funcDesc->cParams); m_seqCurrentVartypes.realloc( funcDesc->cParams); // Examine each param for( sal_Int16 iparams= 0; iparams < funcDesc->cParams; iparams++) { sal_Int32 flags= funcDesc->lprgelemdescParam[iparams].paramdesc.wParamFlags; m_seqCurrentParamTypes[iparams]= flags & ( PARAMFLAG_FIN | PARAMFLAG_FOUT); // default is PARAMFLAG_IN if( m_seqCurrentParamTypes[iparams] == 0) m_seqCurrentParamTypes[iparams]= PARAMFLAG_FIN; if( ! getElementTypeDesc( & funcDesc->lprgelemdescParam[iparams].tdesc, m_seqCurrentVartypes[iparams])) ret= sal_False; if( ! ret) break; } pType->ReleaseFuncDesc( funcDesc); } else ret= sal_False; } else ret= sal_False; return ret; } // Gets the element type in a VARIANT like style. E.g. if desc->lptdesc contains // a VT_PTR than it is replaced by VT_BYREF and VT_SAFEARRAY is replaced by VT_ARRAY // If the TYPEDESC describes an SAFEARRAY then varType is a combination of VT_ARRAY // and the element type sal_Bool IUnknownWrapper_Impl::getElementTypeDesc( TYPEDESC *desc, VARTYPE& varType ) { sal_Bool ret= sal_True; VARTYPE _type; if( desc->vt == VT_PTR) { if( getElementTypeDesc( desc->lptdesc, _type)) varType= _type | VT_BYREF; else ret= sal_False; } else if( desc->vt == VT_SAFEARRAY ) { if( getElementTypeDesc( desc->lptdesc, _type)) varType= _type | VT_ARRAY; else sal_False; } else { varType= desc->vt; } return ret; } sal_Bool IUnknownWrapper_Impl::buildComTlbIndex() { sal_Bool ret= sal_True; ITypeInfo* pType= getTypeInfo(); if( pType) { TYPEATTR* typeAttr= NULL; if( SUCCEEDED( pType->GetTypeAttr( &typeAttr))) { for( long i= 0; i < typeAttr->cFuncs; i++) { FUNCDESC* funcDesc= NULL; if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc))) { BSTR memberName= NULL; unsigned int pcNames=0; if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames))) { m_mapComFunc.insert( TLBFuncIndexMap::value_type( OUString( memberName), i)); SysFreeString( memberName); } else ret= sal_False; pType->ReleaseFuncDesc( funcDesc); } else ret=sal_False; } pType->ReleaseTypeAttr( typeAttr); } else ret= sal_False; } else ret= sal_False; return ret; } inline sal_Bool IUnknownWrapper_Impl::isComTlbIndex() { if( m_mapComFunc.size()) return sal_True; return sal_False; } ITypeInfo* IUnknownWrapper_Impl::getTypeInfo() { HRESULT hr= S_OK; if( !m_pDispatch) return NULL; if( !m_spTypeInfo ) { LCID localId= GetUserDefaultLCID(); CComPtr< ITypeInfo > spType; if( SUCCEEDED( m_pDispatch->GetTypeInfo( 0, localId, &spType.p))) m_spTypeInfo= spType; } return m_spTypeInfo; } } // end namespace