From 907a87c47e1ec8520cbcc8403dd259a1a3a8d949 Mon Sep 17 00:00:00 2001 From: Joachim Lingner Date: Fri, 13 Sep 2002 05:23:08 +0000 Subject: #103028# identity of COM and UNO objects --- extensions/source/ole/makefile.mk | 7 +- extensions/source/ole/oleobjw.cxx | 21 +- extensions/source/ole/unoconversionutilities.hxx | 322 ++++++++++++----------- extensions/source/ole/unoobjw.cxx | 48 ++-- extensions/source/ole/unoobjw.hxx | 10 +- 5 files changed, 207 insertions(+), 201 deletions(-) diff --git a/extensions/source/ole/makefile.mk b/extensions/source/ole/makefile.mk index c83d92daff8e..73852fa76881 100644 --- a/extensions/source/ole/makefile.mk +++ b/extensions/source/ole/makefile.mk @@ -2,9 +2,9 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.6 $ +# $Revision: 1.7 $ # -# last change: $Author: jl $ $Date: 2002-06-05 13:21:38 $ +# last change: $Author: jl $ $Date: 2002-09-13 06:23:07 $ # # The Contents of this file are made available subject to the terms of # either of the following licenses @@ -152,7 +152,8 @@ SLOFILES= \ $(SLO)$/olethread.obj \ $(SLO)$/oledll.obj \ $(SLO)$/jscriptclasses.obj \ - $(SLO)$/ole2uno.obj + $(SLO)$/ole2uno.obj + diff --git a/extensions/source/ole/oleobjw.cxx b/extensions/source/ole/oleobjw.cxx index 3528cee4b2ed..8b67c91a0103 100644 --- a/extensions/source/ole/oleobjw.cxx +++ b/extensions/source/ole/oleobjw.cxx @@ -2,9 +2,9 @@ * * $RCSfile: oleobjw.cxx,v $ * - * $Revision: 1.9 $ + * $Revision: 1.10 $ * - * last change: $Author: jl $ $Date: 2002-06-05 13:21:38 $ + * 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 @@ -158,7 +158,7 @@ hash_map AdapterToWrapperMap; // adapted interface which is then used to locate the entry in AdapterToWrapperMap. hash_map WrapperToAdapterMap; -//hash_map > ComPtrToWrapperMap; +hash_map > ComPtrToWrapperMap; /***************************************************************************** class implementation IUnknownWrapper_Impl @@ -176,12 +176,15 @@ IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference& xFa IUnknownWrapper_Impl::~IUnknownWrapper_Impl() { MutexGuard guard(getBridgeMutex()); - acquire(); // make sure we don't delete us twice - Reference xInt( static_cast(this), UNO_QUERY); + 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) xInt.get()); + _IT it= WrapperToAdapterMap.find( (sal_uInt32) xIntRoot); if( it != WrapperToAdapterMap.end()) { sal_uInt32 adapter= it->second; @@ -190,9 +193,9 @@ IUnknownWrapper_Impl::~IUnknownWrapper_Impl() WrapperToAdapterMap.erase( it); } -// IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_pUnknown); -// if(it_c != ComPtrToWrapperMap.end()) -// ComPtrToWrapperMap.erase(it_c); + IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_pUnknown); + if(it_c != ComPtrToWrapperMap.end()) + ComPtrToWrapperMap.erase(it_c); o2u_attachCurrentThread(); diff --git a/extensions/source/ole/unoconversionutilities.hxx b/extensions/source/ole/unoconversionutilities.hxx index ea3ca23ca8a0..a58f2deee4ab 100644 --- a/extensions/source/ole/unoconversionutilities.hxx +++ b/extensions/source/ole/unoconversionutilities.hxx @@ -2,9 +2,9 @@ * * $RCSfile: unoconversionutilities.hxx,v $ * - * $Revision: 1.11 $ + * $Revision: 1.12 $ * - * last change: $Author: jl $ $Date: 2002-06-05 13:21:38 $ + * 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 @@ -100,9 +100,9 @@ typedef hash_map::iterator CIT_Wrap; // IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when // it is being destroyed. // Used to ensure that an Automation object is always mapped to the same UNO objects. -// extern hash_map > ComPtrToWrapperMap; -// typedef hash_map >::iterator IT_Com; -// typedef hash_map >::const_iterator CIT_Com; +extern hash_map > ComPtrToWrapperMap; +typedef hash_map >::iterator IT_Com; +typedef hash_map >::const_iterator CIT_Com; // Maps XInterface pointers to a weak reference of its wrapper class (i.e. // InterfaceOleWrapper_Impl). It is the responsibility of the wrapper to remove the entry when @@ -113,6 +113,10 @@ typedef hash_map::iterator CIT_Wrap; extern hash_map > UnoObjToWrapperMap; typedef hash_map >::iterator IT_Uno; typedef hash_map >::const_iterator CIT_Uno; + + + + // createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance // and initializes it via XInitialization. The wrapper object is required to implement // XBridgeSupplier so that it can convert itself to IDispatch. @@ -161,7 +165,7 @@ public: static sal_Bool isJScriptArray(const VARIANT* pvar); - + Sequence getImplementedInterfaces(IUnknown* pUnk); protected: // helper function for Sequence conversion @@ -979,6 +983,12 @@ SAFEARRAY* UnoConversionUtilities::createUnoSequenceWrapper(const Any& rSeq) return pArray; } +/* The argument rObj can contain +- UNO struct +- UNO interface +- UNO interface created by this bridge (adapter factory) +- UNO interface created by this bridge ( COM Wrapper) +*/ template IDispatch* UnoConversionUtilities::createUnoObjectWrapper(const Any& rObj) { @@ -988,54 +998,59 @@ IDispatch* UnoConversionUtilities::createUnoObjectWrapper(const Any& rObj) Reference xInv; Reference xInt; rObj >>= xInt; + //make sure we have the main XInterface which is used with a map + xInt=Reference(xInt, UNO_QUERY); //If there is already a wrapper for the UNO object then use it + + Reference xIntWrapper; + // Does a UNO wrapper exist already ? if(xInt.is()) { IT_Uno it_uno= UnoObjToWrapperMap.find( (sal_uInt32) xInt.get()); if(it_uno != UnoObjToWrapperMap.end()) { - Reference wrapper( it_uno->second); + xIntWrapper= it_uno->second; + OSL_ENSURE( xIntWrapper.is(),"Automation bridge: Mapping failure"); } } - if(xInt.is()) + // Is the object a COM wrapper ( either XInvocation, or Adapter object) + // or does it suppy an IDispatch by its own ? + if(xInt.is() && ! xIntWrapper.is()) { - // can the object provide a Wrapper on its own - if( ! convertSelfToIDispatch( xInt, &pDispatch) ) - { - // figure out if the UNO object is a Wrapper through global maps - typedef hash_map::iterator _IT; - _IT it= AdapterToWrapperMap.find( (sal_uInt32) xInt.get()); - if( it != AdapterToWrapperMap.end() ) - { - Reference xIntWrapper( (XInterface*)it->second); - convertSelfToIDispatch( xIntWrapper, &pDispatch); // should always work on the objects in the map - } - else - xInv= Reference( xInt, UNO_QUERY); - } - } - - if (! pDispatch && !xInv.is()) + Reference xIntComWrapper= xInt; + typedef hash_map::iterator _IT; + // Adapter? then get the COM wrapper to which the adapter delegates its calls + _IT it= AdapterToWrapperMap.find( (sal_uInt32) xInt.get()); + if( it != AdapterToWrapperMap.end() ) + xIntComWrapper= reinterpret_cast(it->second); + + // the object can be a COM wrapper, or any other UNO object that supports + // a bridge (XBridgeSupplier) and provide an IDispatch on its own. + convertSelfToIDispatch(xIntComWrapper, &pDispatch); + } + // If we have no UNO wrapper nor the IDispatch yet then we have to create + // a wrapper. For that we need an XInvocation from the UNO object. + if( !xIntWrapper.is() && ! pDispatch) { - // create a XInvocation object for the uno interface or struct - Reference xInvFactory= getInvocationFactory(rObj); - if( xInvFactory.is()) + // get an XInvocation or create one using the invocation service + Reference xInv(xInt, UNO_QUERY); + if( ! xInv.is()) { - Sequence params(1); - params.getArray()[0] = rObj; - Reference xInt = xInvFactory->createInstanceWithArguments(params); - xInv= Reference(xInt, UNO_QUERY); + Reference xInvFactory= getInvocationFactory(rObj); + if( xInvFactory.is()) + { + Sequence params(1); + params.getArray()[0] = rObj; + Reference xInt = xInvFactory->createInstanceWithArguments(params); + xInv= Reference(xInt, UNO_QUERY); + } } - } - OSL_ENSURE(xInv.is() || pDispatch, "no invocation interface"); - if( !pDispatch) - { - Reference< XInterface > xIntWrapper= createUnoWrapperInstance(); - if( xIntWrapper.is()) + if( xInv.is()) { - Reference< XInitialization > xInitWrapper( xIntWrapper, UNO_QUERY); + Reference< XInterface > xNewWrapper= createUnoWrapperInstance(); + Reference< XInitialization > xInitWrapper( xNewWrapper, UNO_QUERY); if( xInitWrapper.is() ) { VARTYPE vartype= getVarType( rObj); @@ -1056,22 +1071,20 @@ IDispatch* UnoConversionUtilities::createUnoObjectWrapper(const Any& rObj) xInitWrapper->initialize( Sequence(params, 2)); } - // Get the IDispatch - // A wrapper is expected to implement XBridgeSupplier in order to - // convert itself to an IDispatch: - IDispatch* pDisp; - if( convertSelfToIDispatch( xIntWrapper, &pDisp)) - pDispatch= pDisp; - + xIntWrapper= xNewWrapper; // put the newly created object into a map. If the same object will // be mapped again and there is already a wrapper then the old wrapper // will be used. if(xInt.is()) // only interfaces - UnoObjToWrapperMap[(sal_uInt32) xInt.get()]= WeakReference(xIntWrapper); + UnoObjToWrapperMap[(sal_uInt32) xInt.get()]= xIntWrapper; } } } + // get IDispatch from the UNO wrapper + if( !pDispatch) + convertSelfToIDispatch(xIntWrapper, &pDispatch); + return pDispatch; } @@ -1375,10 +1388,10 @@ Any UnoConversionUtilities::createOleObjectWrapper(IUnknown* pUnknown, const Any ret; Type desiredType= aType == VOID_TYPE ? getCppuType((Reference*) 0) : aType; - Reference xInt; if (pUnknown == NULL) { + Reference xInt; if( aType.getTypeClass() == TypeClass_INTERFACE) ret.setValue( &xInt, aType); else if( aType.getTypeClass() == TypeClass_STRUCT) @@ -1390,7 +1403,7 @@ Any UnoConversionUtilities::createOleObjectWrapper(IUnknown* pUnknown, const // and we extract the original UNO object. CComQIPtr spUno( pUnknown); if( spUno) - { + { // it is a wrapper Reference xInt; if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt))) { @@ -1406,117 +1419,25 @@ Any UnoConversionUtilities::createOleObjectWrapper(IUnknown* pUnknown, const else { // "pUnknown" is a real COM object. + // If the object implements UNO interfaces then get the types. + Sequence seqTypes= getImplementedInterfaces(pUnknown); // Before we create a new wrapper object we check if there is an existing wrapper - // CIT_Com cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast(pUnknown)); -// sal_Bool bSuccess= sal_False; -// if(cit_currWrapper != ComPtrToWrapperMap.end()) -// { -// WeakReference xweak= cit_currWrapper->second; -// Reference xint= xweak; -// // get the Adapter from the WrapperToAdapterMap. This is dangerous since the stored pointer -// // might be invalid already. We should store the adapter in a map with a weak reference. The -// // invocation adapter factory does not support adapter which can be kept weekly. -// CIT_Wrap cit_w= WrapperToAdapterMap.find((sal_uInt32) xint.get()); -// if( cit_w != WrapperToAdapterMap.end()) -// { -// Reference xIntAdapt(reinterpret_cast( cit_w->second)); -// if(xIntAdapt.is()) -// { -// ret= xIntAdapt->queryInterface(desiredType); -// bSuccess= sal_True; -// } -// } -// else -// { -// ret= xint->queryInterface(desiredType); -// bSuccess= sal_True; -// } -// } -// if(bSuccess == sal_False) -// { + Reference xIntWrapper; + CIT_Com cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast(pUnknown)); + if(cit_currWrapper != ComPtrToWrapperMap.end()) + { + WeakReference xweak= cit_currWrapper->second; + xIntWrapper= xweak; + //When the wrapper is destructed it must remove the entry in the map + //therefore we must always get a hard reference + OSL_ENSURE(xIntWrapper.is(),"OLE Automation bridge"); + } + else + { //There is no existing wrapper, therefore we create one for the real COM object Reference xInt= createComWrapperInstance(); if( xInt.is()) { - Reference xInv( xInt, UNO_QUERY); - - Sequence seqTypes; - //The wrapper implements already XInvocation and XInterface. Therefore if the - //param aType is one of those we can use the wrapper object directly otherwise - //we have to create an Adapter interface. - //If aType is void then we assume the type to be XInterface - - if( desiredType == getCppuType((Reference*) 0)) - { - ret <<= xInt; -// ComPtrToWrapperMap[reinterpret_cast(pUnknown)]= xInt; - } - else - { - Reference< XInterface> xIntAdapterFac; - xIntAdapterFac= m_smgr->createInstance( INTERFACE_ADAPTER_FACTORY); - // We create an adapter object that does not only implement the required type but also - // all types that the COM object pretends to implement. An COM object must therefore - // support the property "_implementedInterfaces". - CComDispatchDriver disp( pUnknown); - if( disp) - { - CComVariant var; - HRESULT hr= S_OK; - // There are two different property names possible. - if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var))) - { - hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var); - } - if (SUCCEEDED( hr)) - { - // we exspect an array( SafeArray or IDispatch) of Strings. - Any anyNames; - if( variantToAny2( &var, anyNames, getCppuType( (Sequence*) 0))) - { - Sequence seqAny; - if( anyNames >>= seqAny) - { - seqTypes.realloc( seqAny.getLength()); - for( sal_Int32 i=0; i < seqAny.getLength(); i++) - { - OUString typeName; - seqAny[i] >>= typeName; - seqTypes[i]= Type( TypeClass_INTERFACE, typeName); - } - } - } - } - } - - Reference xIntAdapted; - sal_Int32 seqTypesLen = seqTypes.getLength(); - - if( seqTypesLen > 0) - { - Reference< XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY); - if( xAdapterFac.is()) - xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes); - } - else - { - Reference xAdapterFac( xIntAdapterFac, UNO_QUERY); - if( xAdapterFac.is()) - xIntAdapted= xAdapterFac->createAdapter( xInv, desiredType); - } - if( xIntAdapted.is()) - { - ret= xIntAdapted->queryInterface( desiredType); - // Put the pointer to the wrapper object and the interface pointer of the adapted interface - // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO - // object is a wrapped COM object. In that case we extract the original COM object rather than - // creating a wrapper around the UNO object. - typedef hash_map::value_type VALUE; - AdapterToWrapperMap.insert( VALUE( (sal_uInt32) xIntAdapted.get(), (sal_uInt32) xInt.get())); - WrapperToAdapterMap.insert( VALUE( (sal_uInt32) xInt.get(), (sal_uInt32) xIntAdapted.get())); -// ComPtrToWrapperMap[reinterpret_cast(pUnknown)]= xInt; - } - } // initialize the COM wrapper ( IUnknown + Type s) Reference xInit( xInt, UNO_QUERY); if( xInit.is()) @@ -1533,9 +1454,61 @@ Any UnoConversionUtilities::createOleObjectWrapper(IUnknown* pUnknown, const } xInit->initialize( Sequence( params, 2)); + xIntWrapper= xInt; } } -// } + } + + if( xIntWrapper.is()) + { + // we have a wrapper object + //The wrapper implements already XInvocation and XInterface. Therefore if the + //param aType is one of those we can use the wrapper object directly otherwise + //we have to create an Adapter interface. + //If aType is void then we assume the type to be XInterface + if( desiredType == getCppuType((Reference*) 0)) + { + ret <<= xIntWrapper; + // remember the wrapper object + ComPtrToWrapperMap[reinterpret_cast(pUnknown)]= xIntWrapper; + } + else + { + Reference< XInterface> xIntAdapterFac; + xIntAdapterFac= m_smgr->createInstance( INTERFACE_ADAPTER_FACTORY); + // We create an adapter object that does not only implement the required type but also + // all types that the COM object pretends to implement. An COM object must therefore + // support the property "_implementedInterfaces". + Reference xIntAdapted; + sal_Int32 seqTypesLen = seqTypes.getLength(); + Reference xInv( xIntWrapper, UNO_QUERY); + if( seqTypesLen > 0) + { + Reference< XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY); + if( xAdapterFac.is()) + xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes); + } + else + { + Reference xAdapterFac( xIntAdapterFac, UNO_QUERY); + if( xAdapterFac.is()) + xIntAdapted= xAdapterFac->createAdapter( xInv, desiredType); + } + if( xIntAdapted.is()) + { + ret= xIntAdapted->queryInterface( desiredType); + // Put the pointer to the wrapper object and the interface pointer of the adapted interface + // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO + // object is a wrapped COM object. In that case we extract the original COM object rather than + // creating a wrapper around the UNO object. + typedef hash_map::value_type VALUE; + AdapterToWrapperMap.insert( VALUE( (sal_uInt32) xIntAdapted.get(), (sal_uInt32) xIntWrapper.get())); + WrapperToAdapterMap.insert( VALUE( (sal_uInt32) xIntWrapper.get(), (sal_uInt32) xIntAdapted.get())); + ComPtrToWrapperMap[reinterpret_cast(pUnknown)]= xIntWrapper; + } + } + + } } } @@ -1938,6 +1911,43 @@ VARTYPE UnoConversionUtilities::mapTypeClassToVartype( TypeClass type) return ret; } +template +Sequence UnoConversionUtilities::getImplementedInterfaces(IUnknown* pUnk) +{ + Sequence seqTypes; + CComDispatchDriver disp( pUnk); + if( disp) + { + CComVariant var; + HRESULT hr= S_OK; + // There are two different property names possible. + if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var))) + { + hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var); + } + if (SUCCEEDED( hr)) + { + // we exspect an array( SafeArray or IDispatch) of Strings. + Any anyNames; + if( variantToAny2( &var, anyNames, getCppuType( (Sequence*) 0))) + { + Sequence seqAny; + if( anyNames >>= seqAny) + { + seqTypes.realloc( seqAny.getLength()); + for( sal_Int32 i=0; i < seqAny.getLength(); i++) + { + OUString typeName; + seqAny[i] >>= typeName; + seqTypes[i]= Type( TypeClass_INTERFACE, typeName); + } + } + } + } + } + return seqTypes; +} + // This function tries to the change the type of a value (contained in the Any) // to the smallest possible that can hold the value. This is actually done only diff --git a/extensions/source/ole/unoobjw.cxx b/extensions/source/ole/unoobjw.cxx index 16c634533b9e..64192c6cff0a 100644 --- a/extensions/source/ole/unoobjw.cxx +++ b/extensions/source/ole/unoobjw.cxx @@ -2,9 +2,9 @@ * * $RCSfile: unoobjw.cxx,v $ * - * $Revision: 1.13 $ + * $Revision: 1.14 $ * - * last change: $Author: jl $ $Date: 2002-08-06 10:44:34 $ + * 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 @@ -162,7 +162,11 @@ InterfaceOleWrapper_Impl::InterfaceOleWrapper_Impl( Reference& ProcessId, @@ -256,7 +252,7 @@ protected: sal_Bool getInvocationInfoForCall(DISPID id, InvocationInfo& info); - vos::ORefCount m_refCount; +// vos::ORefCount m_refCount; Reference m_xInvocation; Reference m_xExactName; Reference m_xOrigin; -- cgit v1.2.3