/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_extensions.hxx"
#include "ole2uno.hxx"
#include "rtl/ustrbuf.hxx"


#include "osl/diagnose.h"
#include "osl/doublecheckedlocking.h"
#include "osl/thread.h"

#include "boost/scoped_array.hpp"
#include <com/sun/star/script/FailReason.hpp>
#include <com/sun/star/beans/XMaterialHolder.hpp>
#include <com/sun/star/script/XTypeConverter.hpp>
#include <com/sun/star/script/FinishEngineEvent.hpp>
#include <com/sun/star/script/InterruptReason.hpp>
#include <com/sun/star/script/XEngineListener.hpp>
#include <com/sun/star/script/XDebugging.hpp>
#include <com/sun/star/script/XInvocation.hpp>
#include <com/sun/star/script/ContextInformation.hpp>
#include <com/sun/star/script/FinishReason.hpp>
#include <com/sun/star/script/XEngine.hpp>
#include <com/sun/star/script/InterruptEngineEvent.hpp>
#include <com/sun/star/script/XLibraryAccess.hpp>
#include <com/sun/star/bridge/ModelDependent.hpp>

#include "com/sun/star/bridge/oleautomation/NamedArgument.hpp"
#include "com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp"

#include <typelib/typedescription.hxx>
#include <rtl/uuid.h>
#include <rtl/memory.h>
#include <rtl/ustring.hxx>

#include "jscriptclasses.hxx"

#include "oleobjw.hxx"
#include "unoobjw.hxx"
#include <stdio.h>
using namespace std;
using namespace boost;
using namespace osl;
using namespace rtl;
using namespace cppu;
using namespace com::sun::star::script;
using namespace com::sun::star::lang;
using namespace com::sun::star::bridge;
using namespace com::sun::star::bridge::oleautomation;
using namespace com::sun::star::bridge::ModelDependent;
using namespace ::com::sun::star;

#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<sal_uInt32, sal_uInt32> 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<sal_uInt32,sal_uInt32> WrapperToAdapterMap;

hash_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap;
/*****************************************************************************

	class implementation IUnknownWrapper_Impl

*****************************************************************************/

IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference<XMultiServiceFactory>& xFactory,
										   sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
	UnoConversionUtilities<IUnknownWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass),
	m_pxIdlClass( NULL), m_eJScript( JScriptUndefined),
    m_bComTlbIndexInit(false),  m_bHasDfltMethod(false), m_bHasDfltProperty(false)
{
}


IUnknownWrapper_Impl::~IUnknownWrapper_Impl()
{
    o2u_attachCurrentThread();
    MutexGuard guard(getBridgeMutex());
    XInterface * xIntRoot = (OWeakObject *)this;
#if OSL_DEBUG_LEVEL > 0
    acquire(); // make sure we don't delete us twice because of Reference
	OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot );
#endif

	// remove entries in global maps
	typedef hash_map<sal_uInt32, sal_uInt32>::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_spUnknown.p);
    if(it_c != ComPtrToWrapperMap.end())
        ComPtrToWrapperMap.erase(it_c);

#if OSL_DEBUG_LEVEL > 0
    fprintf(stderr,"[automation bridge] ComPtrToWrapperMap  contains: %i \n",
            ComPtrToWrapperMap.size());
#endif     
}

Any IUnknownWrapper_Impl::queryInterface(const Type& t)
    throw (RuntimeException)
{
    if (t == getCppuType(static_cast<Reference<XDefaultMethod>*>( 0)) && !m_bHasDfltMethod )
        return Any();
    if (t == getCppuType(static_cast<Reference<XDefaultProperty>*>( 0)) && !m_bHasDfltProperty )
        return Any();
    if (t == getCppuType(static_cast<Reference<XInvocation>*>( 0)) && !m_spDispatch)
        return Any();

    return WeakImplHelper7<XInvocation, XBridgeSupplier2,
        XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation>::queryInterface(t);
}

Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection(void)
	throw (RuntimeException )
{
	Reference<XIntrospectionAccess> ret;
    
	return ret;
}



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)
{
    if ( ! m_spDispatch )
    {
        throw RuntimeException(
            OUSTR("[automation bridge] The object does not have an IDispatch interface"),
            Reference<XInterface>());
    }
        
    Any ret;

    try
    {
		o2u_attachCurrentThread();

        TypeDescription methodDesc;
        getMethodInfo(aFunctionName, methodDesc);
        if( methodDesc.is())
        {
            ret = invokeWithDispIdUnoTlb(aFunctionName,
                                         aParams,
                                         aOutParamIndex,
                                         aOutParam);
        }
        else
        {
            ret= invokeWithDispIdComTlb( aFunctionName,
                                         aParams,
                                         aOutParamIndex,
                                         aOutParam);
        }
    }
	catch (IllegalArgumentException &)
	{
		throw;
	}
	catch (CannotConvertException &)
	{
		throw;
	}
    catch (BridgeRuntimeError & e)
    {
         throw RuntimeException(e.message, Reference<XInterface>());
    }
    catch (Exception & e)
    {
        throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
                                     "IUnknownWrapper_Impl::invoke ! Message : \n") +
                               e.Message, Reference<XInterface>());

    }
    catch(...)
    {
        throw RuntimeException(
            OUSTR("[automation bridge] unexpected exception in "
                  "IUnknownWrapper_Impl::Invoke !"), Reference<XInterface>());
    }
	return ret;
}

void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName,
				 const Any& aValue )
	throw(UnknownPropertyException, CannotConvertException, InvocationTargetException,
		  RuntimeException)
{
    if ( ! m_spDispatch )
    {
        throw RuntimeException(
            OUSTR("[automation bridge] The object does not have an IDispatch interface"),
            Reference<XInterface>());
    }
    try
	{
		o2u_attachCurrentThread();

		ITypeInfo * pInfo = getTypeInfo();
        FuncDesc aDescGet(pInfo);
        FuncDesc aDescPut(pInfo);
        VarDesc aVarDesc(pInfo);
        getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
        //check if there is such a property at all or if it is read only
        if ( ! aDescPut && ! aDescGet && ! aVarDesc)
        {
            OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
                         OUSTR("\" is not supported"));
            throw UnknownPropertyException(msg, Reference<XInterface>());
        }
        
        if ( (! aDescPut && aDescGet) || aVarDesc
             && aVarDesc->wVarFlags == VARFLAG_FREADONLY )
        {
            //read-only
            OUString msg(OUSTR("[automation bridge] Property ") + aPropertyName +
                         OUSTR(" is read-only"));
            OString sMsg = OUStringToOString(msg, osl_getThreadTextEncoding());
            OSL_ENSURE(0, sMsg.getStr());
            // ignore silently
            return;
        }

        HRESULT hr= S_OK;
        DISPPARAMS dispparams;
        CComVariant varArg;
        CComVariant varRefArg;
        CComVariant varResult;
        ExcepInfo excepinfo;
        unsigned int uArgErr;
        
        // converting UNO value to OLE variant
        DISPID dispidPut= DISPID_PROPERTYPUT;
        dispparams.rgdispidNamedArgs = &dispidPut;
        dispparams.cArgs = 1;
        dispparams.cNamedArgs = 1;
        dispparams.rgvarg = & varArg;
        
        OSL_ASSERT(aDescPut || aVarDesc);

        VARTYPE vt = 0;
        DISPID dispid = 0;
        INVOKEKIND invkind = INVOKE_PROPERTYPUT;
        //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
        //DISPATCH_PROPERTYPUTREF)
        if (aDescPut)
        {
            vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
            dispid = aDescPut->memid;
            invkind = aDescPut->invkind;
        }
        else
        {
            vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc);
            dispid = aVarDesc->memid;
            if (vt == VT_UNKNOWN || vt == VT_DISPATCH || 
                (vt & VT_ARRAY) || (vt & VT_BYREF))
            {
                invkind = INVOKE_PROPERTYPUTREF;
            }
        }

        // convert the uno argument
        if (vt & VT_BYREF)
        {
            anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) );
            varArg.vt = vt;
            if( (vt & VT_TYPEMASK) == VT_VARIANT)
                varArg.byref = & varRefArg;
			else if ((vt & VT_TYPEMASK) == VT_DECIMAL)
				varArg.byref = & varRefArg.decVal;
            else
                varArg.byref = & varRefArg.byref;
        }
        else
        {
            anyToVariant(& varArg, aValue, vt);
        }
        // call to IDispatch
        hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ),
                                 &dispparams, & varResult, & excepinfo, &uArgErr);
   	
        // 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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
                                             static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
			break;
		case DISP_E_PARAMNOTFOUND:
			throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
                                            static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ;
			break;
		case DISP_E_TYPEMISMATCH:
			throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
                                             static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
			break;
		case DISP_E_UNKNOWNINTERFACE:
			throw RuntimeException();
			break;
		case DISP_E_UNKNOWNLCID:
			throw RuntimeException();
			break;
		case DISP_E_PARAMNOTOPTIONAL:
			throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>(
                                             static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
			break;
		default:
			throw  RuntimeException();
			break;
        }		
	}
	catch (CannotConvertException &)
	{
		throw;
	}
    catch (UnknownPropertyException &)
    {
        throw;
    }
	catch (BridgeRuntimeError& e)
	{
        throw RuntimeException(
            e.message, Reference<XInterface>());
	}
    catch (Exception & e)
    {
        throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
                                     "IUnknownWrapper_Impl::setValue ! Message : \n") +
                               e.Message, Reference<XInterface>());

    }
	catch (...)
	{
		throw RuntimeException(
            OUSTR("[automation bridge] unexpected exception in "
			"IUnknownWrapper_Impl::setValue !"), Reference<XInterface>());
	}
}

Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName )
		throw(UnknownPropertyException, RuntimeException)
{
    if ( ! m_spDispatch )
    {
        throw RuntimeException(
            OUSTR("[automation bridge] The object does not have an IDispatch interface"),
            Reference<XInterface>());
    }
	Any ret;
    try
    {
        o2u_attachCurrentThread();
        ITypeInfo * pInfo = getTypeInfo();
        // I was going to implement an XServiceInfo interface to allow the type
        // of the automation object to be exposed.. but it seems
        // from looking at comments in the code that it is possible for 
        // this object to actually wrap an UNO object ( I guess if automation is
        // used from MSO to create Openoffice objects ) Therefore, those objects
        // will more than likely already have their own XServiceInfo interface.
        // Instead here I chose a name that should be illegal both in COM and
        // UNO ( from an IDL point of view ) therefore I think this is a safe
        // hack
        if ( aPropertyName.equals( rtl::OUString::createFromAscii("$GetTypeName") )) 
        {
            if ( pInfo && m_sTypeName.getLength() == 0 )
            {
            	 m_sTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("IDispatch") );
                CComBSTR sName;
                
                if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, NULL, NULL, NULL  ) ) )
                {
                    rtl::OUString sTmp( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
                    if ( sTmp.indexOf('_')  == 0 )
                       sTmp = sTmp.copy(1);
                    // do we own the memory for pTypeLib, msdn doco is vague
                    // I'll assume we do 
                    CComPtr< ITypeLib > pTypeLib;
                    unsigned int index;
                    if ( SUCCEEDED(  pInfo->GetContainingTypeLib(  &pTypeLib.p, &index )) )
                    {
                        if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, NULL, NULL, NULL  ) ) )
                        {
                            rtl::OUString sLibName( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
                            m_sTypeName = sLibName.concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".") ) ).concat( sTmp );
                            
                        }
                    }
                }
                
            }
            ret <<= m_sTypeName;
            return ret;
        }
        FuncDesc aDescGet(pInfo);
        FuncDesc aDescPut(pInfo);
        VarDesc aVarDesc(pInfo);
        getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
        if ( ! aDescGet && ! aDescPut && ! aVarDesc)
        {
            //property not found
            OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
                         OUSTR("\" is not supported"));
            throw UnknownPropertyException(msg, Reference<XInterface>());
        }
        // write-only should not be possible
        OSL_ASSERT(  aDescGet  || ! aDescPut);
        
        HRESULT hr;
        DISPPARAMS dispparams = {0, 0, 0, 0};
        CComVariant varResult;
        ExcepInfo excepinfo;
        unsigned int uArgErr;
        DISPID dispid;
        if (aDescGet)
            dispid = aDescGet->memid;
        else if (aVarDesc)
            dispid = aVarDesc->memid;
        else
            dispid = aDescPut->memid;
        
        hr = m_spDispatch->Invoke(dispid, 
								 IID_NULL,
								 LOCALE_USER_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(aPropertyName, attrInfo);
			if( attrInfo.is() )
				variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef));
			else
				variantToAny(&varResult, ret);
        }
	
        // lookup error code			
        switch (hr)
        {
		case S_OK:
			break;
		case DISP_E_BADPARAMCOUNT:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_BADVARTYPE:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_EXCEPTION:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_MEMBERNOTFOUND:
			throw UnknownPropertyException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_NONAMEDARGS:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_OVERFLOW:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_PARAMNOTFOUND:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_TYPEMISMATCH:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_UNKNOWNINTERFACE:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_UNKNOWNLCID:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		case DISP_E_PARAMNOTOPTIONAL:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
		default:
			throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
                                   Reference<XInterface>());
			break;
        }
    }
    catch (UnknownPropertyException& )
    {
        throw;
    }
    catch (BridgeRuntimeError& e)
	{
        throw RuntimeException(
            e.message, Reference<XInterface>());
	}
    catch (Exception & e)
    {
        throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
                                     "IUnknownWrapper_Impl::getValue ! Message : \n") +
                               e.Message, Reference<XInterface>());
    }
	catch (...)
	{
		throw RuntimeException(
            OUSTR("[automation bridge] unexpected exception in "
			"IUnknownWrapper_Impl::getValue !"), Reference<XInterface>());
	}
	return ret;
}

sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName )
		throw(RuntimeException)
{
    if ( ! m_spDispatch )
    {
        throw RuntimeException(
            OUSTR("[automation bridge] The object does not have an IDispatch interface"),
            Reference<XInterface>());
    }
	sal_Bool ret = sal_False;

	try
	{
		o2u_attachCurrentThread();
		ITypeInfo* pInfo = getTypeInfo();
        FuncDesc aDesc(pInfo);
        getFuncDesc(aName, & aDesc);
		// Automation properties can have arguments. Those are treated as methods and
		//are called through XInvocation::invoke. 
		if ( ! aDesc)
		{
			FuncDesc aDescGet(pInfo);
			FuncDesc aDescPut(pInfo);
            VarDesc aVarDesc(pInfo);
			getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc);
			if (aDescGet  && aDescGet->cParams > 0
                || aDescPut && aDescPut->cParams > 0)
				ret = sal_True;
		}
		else
			ret = sal_True;        
	}
	catch (BridgeRuntimeError& e)
	{
		throw RuntimeException(e.message, Reference<XInterface>());
	}
    catch (Exception & e)
    {
        throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
                                     "IUnknownWrapper_Impl::hasMethod ! Message : \n") +
                               e.Message, Reference<XInterface>());
    }
	catch (...)
	{
		throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
			"IUnknownWrapper_Impl::hasMethod !"), Reference<XInterface>());;
	}
    return ret;
}

sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName )
		throw(RuntimeException)
{
    if ( ! m_spDispatch )
    {
        throw RuntimeException(OUSTR("[automation bridge] The object does not have an "
			"IDispatch interface"), Reference<XInterface>());
		return sal_False;
	}
	sal_Bool ret = sal_False;
	try
	{
		o2u_attachCurrentThread();

		ITypeInfo * pInfo = getTypeInfo();
        FuncDesc aDescGet(pInfo);
        FuncDesc aDescPut(pInfo);
        VarDesc aVarDesc(pInfo);
        getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc);
		// Automation properties can have parameters. If so, we access them through 
		// XInvocation::invoke. Thas is, hasProperty must return false for such a 
		// property
        if (aVarDesc
            || aDescPut && aDescPut->cParams == 0
            || aDescGet && aDescGet->cParams == 0)
        {
            ret = sal_True;
        }
	}
	catch (BridgeRuntimeError& e)
	{
		throw RuntimeException(e.message, Reference<XInterface>());
	}
    catch (Exception & e)
    {
        throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
                                     "IUnknownWrapper_Impl::hasProperty ! Message : \n") +
                               e.Message, Reference<XInterface>());

    }    
	catch (...)
	{
		throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
			"IUnknownWrapper_Impl::hasProperty !"), Reference<XInterface>());
	}
	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;
	o2u_attachCurrentThread();

	if (
		(sourceModelType == UNO) &&
		(destModelType == OLE) &&
		(modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
	   )
	{
		Reference<XInterface> xInt( *(XInterface**) modelDepObject.getValue());
		Reference<XInterface> xSelf( (OWeakObject*)this);

		if (xInt == xSelf)
		{
			VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT));

			VariantInit(pVariant);
            if (m_bOriginalDispatch == sal_True)
            {
				pVariant->vt = VT_DISPATCH;
				pVariant->pdispVal = m_spDispatch;
				pVariant->pdispVal->AddRef();
			}
			else
			{
				pVariant->vt = VT_UNKNOWN;
				pVariant->punkVal = m_spUnknown;
				pVariant->punkVal->AddRef();
			}

			ret.setValue((void*)&pVariant, getCppuType( (sal_uInt32*) 0));
		}
	}

	return ret;
}
/** @internal
    @exception IllegalArgumentException
    @exception CannotConvertException
    @exception InvocationTargetException
    @RuntimeException
*/
Any  IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
                                                  const Sequence< Any >& Params,
                                                  Sequence< sal_Int16 >& OutParamIndex,
                                                  Sequence< Any >& OutParam)
{
	Any ret;
	HRESULT hr= S_OK;

	sal_Int32 parameterCount= Params.getLength();
	sal_Int32 outParameterCount= 0;
	typelib_InterfaceMethodTypeDescription* pMethod= NULL;
	TypeDescription methodDesc;
	getMethodInfo(sFunctionName, 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();
    scoped_array<CComVariant> sarParams;
    scoped_array<CComVariant> sarParamsRef;
	CComVariant *pVarParams= NULL;
	CComVariant *pVarParamsRef= NULL;
	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)
        {
            sarParams.reset(new CComVariant[ parameterCount]);
            pVarParams = sarParams.get();
        }
        
		// 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)
		{
            sarParamsRef.reset(new CComVariant[outParameterCount]);
			pVarParamsRef = sarParamsRef.get();
			// build up the parameters for IDispatch::Invoke
			sal_Int32 outParamIndex=0;
			int i = 0;
			try 
			{
				for( i= 0; i < parameterCount; i++)
				{
					// In parameter
					if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
					{
						anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
					}
					// Out parameter + in/out parameter
					else if( pMethod->pParams[i].bOut == sal_True)
					{
						CComVariant var;
						if(pMethod->pParams[i].bIn)
						{
							anyToVariant( & var,Params[i]);
							pVarParamsRef[outParamIndex] = var;
						}

						switch( pMethod->pParams[i].pTypeRef->eTypeClass)
						{
						case TypeClass_INTERFACE:
						case TypeClass_STRUCT:
							if( ! pMethod->pParams[i].bIn)
							{
								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)
							{
								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)
							{
								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)
							{
								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)
							{
								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)
							{
								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)
							{
								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)
							{
								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)
							{
								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)
							{
								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)
							{
								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
				} // end for
			} 
			catch (IllegalArgumentException & e)
			{
                e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
				throw;
			}
			catch (CannotConvertException & e)
			{
				e.ArgumentIndex = i;
				throw;
			}
		}
		else // it is an JScriptObject
		{
			int i = 0;
			try
			{
				for( ; i< parameterCount; i++)
				{
					// In parameter
					if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
					{
						anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
					}
					// Out parameter + in/out parameter
					else if( pMethod->pParams[i].bOut == sal_True)
					{
						CComObject<JScriptOutParam>* pParamObject;
						if( SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
						{
							CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
#ifdef __MINGW32__
							CComQIPtr<IDispatch, &__uuidof(IDispatch)> pDisp( pUnk);
#else
							CComQIPtr<IDispatch> pDisp( pUnk);
#endif

							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;
								anyToVariant( &varParam, Params.getConstArray()[i]);
								CComDispatchDriver dispDriver( pDisp);
								if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
									throw BridgeRuntimeError(
                                        OUSTR("[automation bridge]IUnknownWrapper_Impl::"
                                              "invokeWithDispIdUnoTlb\n"
                                              "Could not set property \"0\" for the in/out "
                                              "param!"));

							}
						}
						else
						{
                            throw BridgeRuntimeError(
                                OUSTR("[automation bridge]IUnknownWrapper_Impl::"
                                      "invokeWithDispIdUnoTlb\n"
                                      "Could not create out parameter at index: ") +
                                OUString::valueOf((sal_Int32) i));
						}

					}
				}
			}
			catch (IllegalArgumentException & e)
			{
				e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
				throw;
			}
			catch (CannotConvertException & e)
			{
				e.ArgumentIndex = i;
				throw;
			}
		}
	}
	// No type description Available, that is we have to deal with a COM component,
	// that does not implements UNO interfaces ( IDispatch based)
	else
	{
        //We should not run into this block, because invokeWithDispIdComTlb should
        //have been called instead.
        OSL_ASSERT(0);
	}


    CComVariant		varResult;
    ExcepInfo 		excepinfo;
    unsigned int 	uArgErr;
    DISPPARAMS dispparams= { pVarParams, NULL, parameterCount, 0};
    // Get the DISPID
    FuncDesc aDesc(getTypeInfo());
    getFuncDesc(sFunctionName, & aDesc);
    // invoking OLE method 		
    hr = m_spDispatch->Invoke(aDesc->memid, 
                             IID_NULL,
                             LOCALE_USER_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;
			int i = 0;
			try
			{
				for( ; i < parameterCount; i++)
				{
					if( pMethod->pParams[i].bOut )
					{
						OutParamIndex[outIndex]= (sal_Int16) i;
						Any outAny;	
						if( !bJScriptObject)
						{
							variantToAny( &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)))
									{
										variantToAny( &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;
				}
			}
			catch(IllegalArgumentException & e)
			{
				e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
				throw;
			}
			catch(CannotConvertException & e)
			{
				e.ArgumentIndex = i;
				throw;
			}
        }
        // return value, no type information available
        if ( bConvRet)
		{
			try
			{
				if( pMethod	)
					variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), sal_False);
				else
					variantToAny(&varResult, ret, sal_False);
			}
			catch (IllegalArgumentException & e)
			{
				e.Message =
					OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
					"Could not convert return value! \n Message: \n") + e.Message;
				throw;
			}
			catch (CannotConvertException & e)
			{
				e.Message =
					OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
					"Could not convert return value! \n Message: \n") + e.Message;
				throw;
			}
		}
    }
    
    if( !bConvRet) // conversion of return or out parameter failed
        throw CannotConvertException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Call to COM object failed. Conversion of return or out value failed")),
                                      Reference<XInterface>( static_cast<XWeak*>(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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
                                         static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
        break;
    case DISP_E_PARAMNOTFOUND:
        throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
                                           static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
        break;
    case DISP_E_TYPEMISMATCH:
        throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>(
                                         static_cast<XWeak*>(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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
                                         static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
				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 boolean which indicates if the the COM pointer was a IUnknown or IDispatch
	// 3.parameter is a Sequence<Type> 
	o2u_attachCurrentThread();
	OSL_ASSERT(aArguments.getLength() == 3);
    
    m_spUnknown= *(IUnknown**) aArguments[0].getValue();
#ifdef __MINGW32__
    m_spUnknown->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>( & m_spDispatch.p));
#else
    m_spUnknown.QueryInterface( & m_spDispatch.p);
#endif

    aArguments[1] >>= m_bOriginalDispatch;    
	aArguments[2] >>= m_seqTypes;

    ITypeInfo* pType = NULL;
    try
    {
        // a COM object implementation that has no TypeInfo is still a legal COM object;
        // such objects can at least be transported through UNO using the bridge
        // so we should allow to create wrappers for them as well
        pType = getTypeInfo();
    }
    catch( BridgeRuntimeError& )
    {}
    catch( Exception& )
    {}

    if ( pType )
    {
        try
        {
            // Get Default member
            CComBSTR defaultMemberName;
            if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, 0, 0, 0 ) ) )
            {
                OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(defaultMemberName)));
                FuncDesc aDescGet(pType);
                FuncDesc aDescPut(pType);
                VarDesc aVarDesc(pType);
                // see if this is a property first ( more likely to be a property then a method )
                getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc);

                if ( !aDescGet && !aDescPut )
                {
                    getFuncDesc( usName, &aDescGet );
                    if ( !aDescGet )
                        throw BridgeRuntimeError( OUSTR("[automation bridge]IUnknownWrapper_Impl::initialize() Failed to get Function or Property desc. for " ) + usName ); 
                }
                // now for some funny heuristics to make basic understand what to do
                // a single aDescGet ( that doesn't take any params ) would be 
                // a read only ( defaultmember ) property e.g. this object
                // should implement XDefaultProperty
                // a single aDescGet ( that *does* ) take params is basically a
                // default method e.g. implement XDefaultMethod
                
                // a DescPut ( I guess we only really support a default param with '1' param ) as a setValue ( but I guess we can leave it through, the object will fail if we don't get it right anyway )
                if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) )
                    m_bHasDfltProperty = true;
                if ( aDescGet->cParams > 0 )
                    m_bHasDfltMethod = true;
                if ( m_bHasDfltProperty || m_bHasDfltMethod )
                    m_sDefaultMember = usName;
            }
        }
        catch ( BridgeRuntimeError & e )
        {
            throw RuntimeException( e.message, Reference<XInterface>() );
        }
        catch( Exception& e )
        {
            throw RuntimeException(
                    OUSTR("[automation bridge] unexpected exception in IUnknownWrapper_Impl::initialiase() error message: \n") + e.Message,
                    Reference<XInterface>() );
        }
    }
}

// --------------------------
// XDirectInvocation
uno::Any SAL_CALL IUnknownWrapper_Impl::directInvoke( const ::rtl::OUString& aName, const uno::Sequence< uno::Any >& aParams )
    throw (lang::IllegalArgumentException, script::CannotConvertException, reflection::InvocationTargetException, uno::RuntimeException)
{
	Any aResult;

    if ( !m_spDispatch )
    {
        throw RuntimeException(
            OUSTR("[automation bridge] The object does not have an IDispatch interface"),
            Reference<XInterface>());
    }

    o2u_attachCurrentThread();
    DISPID dispid;
    if ( !getDispid( aName, &dispid ) )
        throw IllegalArgumentException(
            OUSTR( "[automation bridge] The object does not have a function or property " )
            + aName, Reference<XInterface>(), 0);

	CComVariant		varResult;
	ExcepInfo 		excepinfo;
	unsigned int 	uArgErr = 0;
    INVOKEKIND pInvkinds[2];
    pInvkinds[0] = INVOKE_FUNC;
    pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET;
    HRESULT hInvRes = E_FAIL;

    // try Invoke first, if it does not work, try put/get property
    for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ )
    {
        DISPPARAMS 		dispparams = {NULL, NULL, 0, 0};

        DISPID idPropertyPut = DISPID_PROPERTYPUT;
        scoped_array<DISPID> arDispidNamedArgs;
        scoped_array<CComVariant> ptrArgs;
        scoped_array<CComVariant> ptrRefArgs; // referenced arguments
        CComVariant * arArgs = NULL;
        CComVariant * arRefArgs = NULL;
        bool bVarargParam = false;

        dispparams.cArgs = aParams.getLength();

        // Determine the number of named arguments
        for ( sal_Int32 nInd = 0; nInd < aParams.getLength(); nInd++ )
            if ( aParams[nInd].getValueType() == getCppuType((NamedArgument*) 0) )
                dispparams.cNamedArgs ++;
        
        // fill the named arguments
        if ( dispparams.cNamedArgs > 0
          && !( dispparams.cNamedArgs == 1 && pInvkinds[nStep] == INVOKE_PROPERTYPUT ) )
        {
            int nSizeAr = dispparams.cNamedArgs + 1;
            if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT )
                nSizeAr = dispparams.cNamedArgs; 
        
            scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
            OLECHAR ** pNames = saNames.get();
            pNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(aName.getStr()));

            int cNamedArg = 0;
            for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ )
            {
                if ( aParams[nInd].getValueType() == getCppuType((NamedArgument*) 0))
                {
                    const NamedArgument& arg = *(NamedArgument const*)aParams[nInd].getValue();

                    //We put the parameter names in reverse order into the array,
                    //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
                    //The first name in the array is the method name
                    pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
                }
            }

            arDispidNamedArgs.reset( new DISPID[nSizeAr] );   
            HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() ); 
            if ( hr == E_NOTIMPL )
                hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );

            if ( SUCCEEDED( hr ) )
            {
                if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT )
                {
                    DISPID*  arIDs = arDispidNamedArgs.get();
                    arIDs[0] = DISPID_PROPERTYPUT;
                    dispparams.rgdispidNamedArgs = arIDs;
                }
                else
                {
                    DISPID*  arIDs = arDispidNamedArgs.get();
                    dispparams.rgdispidNamedArgs = & arIDs[1];
                }
            }
            else if (hr == DISP_E_UNKNOWNNAME)
            {
                 throw IllegalArgumentException(
                     OUSTR("[automation bridge]One of the named arguments is wrong!"),
                     Reference<XInterface>(), 0);
            }
            else
            {
                throw InvocationTargetException(
                    OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ")
                    + OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any());
            }
        }

        //Convert arguments
        ptrArgs.reset(new CComVariant[dispparams.cArgs]);
        ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
        arArgs = ptrArgs.get();
        arRefArgs = ptrRefArgs.get();

        sal_Int32 nInd = 0;
        try
        {
            sal_Int32 revIndex = 0;
            for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++)
            {
                revIndex = dispparams.cArgs - nInd - 1;
                arRefArgs[revIndex].byref = 0;
                Any  anyArg;
                if ( nInd < aParams.getLength() )
                    anyArg = aParams.getConstArray()[nInd];
	        
                // Property Put arguments
                if ( anyArg.getValueType() == getCppuType((PropertyPutArgument*)0) )
                {
                    PropertyPutArgument arg;
                    anyArg >>= arg;
                    anyArg <<= arg.Value;
                }
                // named argument
                if (anyArg.getValueType() == getCppuType((NamedArgument*) 0))
                {
                    NamedArgument aNamedArgument;
                    anyArg >>= aNamedArgument;
                    anyArg <<= aNamedArgument.Value;
                }

				if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID )
				{
					anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT );
				}
				else
				{
					arArgs[revIndex].vt = VT_ERROR;
					arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
				}
            }
        }	
        catch (IllegalArgumentException & e)
        {
            e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd );
            throw;
        }
        catch (CannotConvertException & e)
        {
            e.ArgumentIndex = nInd;
            throw;
        }

        dispparams.rgvarg = arArgs;
        // invoking OLE method
        DWORD localeId = LOCALE_USER_DEFAULT;
        hInvRes = m_spDispatch->Invoke( dispid,
                                        IID_NULL,
                                        localeId, 
                                        ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ),
                                        &dispparams, 
                                        &varResult, 
                                        &excepinfo,
                                        &uArgErr);
    }

	// converting return value and out parameter back to UNO
	if ( SUCCEEDED( hInvRes ) )
		variantToAny( &varResult, aResult, sal_False );
    else
    {
        // map error codes to exceptions
        OUString message;
        switch ( hInvRes )
        {
            case S_OK:
                break;
            case DISP_E_BADPARAMCOUNT:
                throw IllegalArgumentException(OUSTR("[automation bridge] Wrong "
                      "number of arguments. Object returned DISP_E_BADPARAMCOUNT."),
                      0, 0);
                break;
            case DISP_E_BADVARTYPE:
                throw RuntimeException(OUSTR("[automation bridge] One or more "
                      "arguments have the wrong type. Object returned "
                      "DISP_E_BADVARTYPE."), 0);
                break;
            case DISP_E_EXCEPTION:
                    message = OUSTR("[automation bridge]: ");
                    message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription), 
                        ::SysStringLen(excepinfo.bstrDescription));
                    throw InvocationTargetException(message, Reference<XInterface>(), Any());
                    break;
            case DISP_E_MEMBERNOTFOUND:
                message = OUSTR("[automation bridge]: A function with the name \"")
                    + aName + OUSTR("\" is not supported. Object returned "
                    "DISP_E_MEMBERNOTFOUND.");                            
                throw IllegalArgumentException(message, 0, 0);
                break;
            case DISP_E_NONAMEDARGS:           
                throw IllegalArgumentException(OUSTR("[automation bridge] Object "
                      "returned DISP_E_NONAMEDARGS"),0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
                break;
            case DISP_E_OVERFLOW:
                throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[automation bridge] Call failed.")),
                                             static_cast<XInterface*>(
                    static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
                break;
            case DISP_E_PARAMNOTFOUND:
                throw IllegalArgumentException(OUSTR("[automation bridge]Call failed."
                                                     "Object returned DISP_E_PARAMNOTFOUND."),
                                               0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 
                break;
            case DISP_E_TYPEMISMATCH:
                throw CannotConvertException(OUSTR("[automation bridge] Call  failed. "
                                             "Object returned DISP_E_TYPEMISMATCH"),
                    static_cast<XInterface*>(
                    static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
                break;
            case DISP_E_UNKNOWNINTERFACE:
                throw RuntimeException(OUSTR("[automation bridge] Call failed. "
                                           "Object returned DISP_E_UNKNOWNINTERFACE."),0);
                break;
            case DISP_E_UNKNOWNLCID:
                throw RuntimeException(OUSTR("[automation bridge] Call failed. "
                                           "Object returned DISP_E_UNKNOWNLCID."),0);
                break;
            case DISP_E_PARAMNOTOPTIONAL:
                throw CannotConvertException(OUSTR("[automation bridge] Call failed."
                      "Object returned DISP_E_PARAMNOTOPTIONAL"),
                            static_cast<XInterface*>(static_cast<XWeak*>(this)),
                                  TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
                break;
            default:
                throw RuntimeException();
                break;
        }		
    }

	return aResult;
}

::sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMember( const ::rtl::OUString& aName )
    throw (uno::RuntimeException)
{
    if ( ! m_spDispatch )
    {
        throw RuntimeException(
            OUSTR("[automation bridge] The object does not have an IDispatch interface"),
            Reference<XInterface>());
    }

    o2u_attachCurrentThread();
    DISPID dispid;
    return getDispid( aName, &dispid );
}


// UnoConversionUtilities --------------------------------------------------------------------------------
Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance()
{
	if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
	{
		Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl(
								m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
		return Reference<XInterface>( xWeak, UNO_QUERY);
	}
	else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT)
	{
		Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
								m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
		return Reference<XInterface>( xWeak, UNO_QUERY);
	}
	else
		return Reference<XInterface>();
}
Reference<XInterface> IUnknownWrapper_Impl::createComWrapperInstance()
{
	Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl( 
							m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
	return Reference<XInterface>( xWeak, UNO_QUERY);
}



void IUnknownWrapper_Impl::getMethodInfo(const OUString& sName, TypeDescription& methodInfo)
{
	TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
	if( desc.is())
	{
		typelib_TypeDescription* pMember= desc.get();
		if( pMember->eTypeClass == TypeClass_INTERFACE_METHOD )
			methodInfo= pMember;
	}
}

void IUnknownWrapper_Impl::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo)
{
	TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
	if( desc.is())
	{
		typelib_TypeDescription* pMember= desc.get();
		if( pMember->eTypeClass == TypeClass_INTERFACE_ATTRIBUTE )
		{
			attributeInfo= ((typelib_InterfaceAttributeTypeDescription*)pMember)->pAttributeTypeRef;
		}
	}
}
TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall(const OUString& sName)
{
	TypeDescription ret;

	for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++)
	{
		TypeDescription _curDesc( m_seqTypes[i]);
        _curDesc.makeComplete();
		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) == sName)
				{
					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_spDispatch);
		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 == CComBSTR(JSCRIPT_ID))
						m_eJScript= IsJScript;
				}
			}
		}
		if( m_eJScript == JScriptUndefined)
			m_eJScript= NoJScript;
	}

	return m_eJScript == NoJScript ? sal_False : sal_True;
}



/** @internal
    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.
    @exception IllegalArgumentException
    @exception CannotConvertException
    @InvocationTargetException
    @RuntimeException
    @BridgeRuntimeError
*/
Any  IUnknownWrapper_Impl::invokeWithDispIdComTlb(const OUString& sFuncName,
                                                  const Sequence< Any >& Params, 
                                                  Sequence< sal_Int16 >& OutParamIndex, 
                                                  Sequence< Any >& OutParam) 
{
	Any ret;
	HRESULT result;

	DISPPARAMS 		dispparams = {NULL, NULL, 0, 0};
	CComVariant		varResult;
	ExcepInfo 		excepinfo;
	unsigned int 	uArgErr;
	sal_Int32       i = 0;
    sal_Int32 nUnoArgs = Params.getLength();
    DISPID idPropertyPut = DISPID_PROPERTYPUT;
	scoped_array<DISPID> arDispidNamedArgs;
	scoped_array<CComVariant> ptrArgs;
	scoped_array<CComVariant> ptrRefArgs; // referenced arguments
    CComVariant * arArgs = NULL;
    CComVariant * arRefArgs = NULL;
    sal_Int32 revIndex = 0;
    bool bVarargParam = false;

    // Get type info for the call. It can be a method call or property put or
    // property get operation.
    FuncDesc aFuncDesc(getTypeInfo());
    getFuncDescForInvoke(sFuncName, Params, & aFuncDesc);

    //Set the array of DISPIDs for named args if it is a property put operation.
    //If there are other named arguments another array is set later on.
    if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
        || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
        dispparams.rgdispidNamedArgs = & idPropertyPut;
    
    //Determine the number of named arguments
    for (int iParam = 0; iParam < nUnoArgs; iParam ++)
    {
        const Any & curArg = Params[iParam];
        if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
            dispparams.cNamedArgs ++;
    }
    //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT).
    //Therefore the number of named arguments is increased by one.
    //Although named, the argument is not named in a actual language, such as  Basic,
    //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument
    if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
        || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
        dispparams.cNamedArgs ++;
    
    //Determine the number of all arguments and named arguments
    if (aFuncDesc->cParamsOpt == -1)
    {
        //Attribute vararg is set on this method. "Unlimited" number of args
        //supported. There can be no optional or defaultvalue on any of the arguments.
        dispparams.cArgs = nUnoArgs;
    }
    else
    {
        //If there are namesd arguments, then the dispparams.cArgs 
        //is the number of supplied args, otherwise it is the expected number.
        if (dispparams.cNamedArgs)
            dispparams.cArgs = nUnoArgs;
        else
            dispparams.cArgs = aFuncDesc->cParams;
    }

	//check if there are not to many arguments supplied
    if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs)
	{
	    OUStringBuffer buf(256);
        buf.appendAscii("[automation bridge] There are too many arguments for this method");
	    throw IllegalArgumentException( buf.makeStringAndClear(),
			Reference<XInterface>(), (sal_Int16) dispparams.cArgs);
	}
    
    //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs)
    //for the named arguments.
    //If there is only one named arg and if it is because of a property put
    //operation, then we need not set up the DISPID array.
    if (dispparams.cNamedArgs > 0 &&
        ! (dispparams.cNamedArgs == 1 &&
           (aFuncDesc->invkind == INVOKE_PROPERTYPUT ||
            aFuncDesc->invkind == INVOKE_PROPERTYPUT)))
    {
        //set up an array containing the member and parameter names
        //which is then used in ITypeInfo::GetIDsOfNames
        //First determine the size of the array of names which is passed to
        //ITypeInfo::GetIDsOfNames. It must hold the method names + the named
        //args.
        int nSizeAr = dispparams.cNamedArgs + 1;
        if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
            || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
        {
            nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT
        }
        
        scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
        OLECHAR ** arNames = saNames.get();
        arNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));

        int cNamedArg = 0;
        for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++)
        {
            const Any &  curArg = Params[iParams];
            if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
            {
                const NamedArgument& arg = *(NamedArgument const*) curArg.getValue();
				//We put the parameter names in reverse order into the array,
				//so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
                //The first name in the array is the method name
                arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
            }
        }
    
        //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames
        //it must be big enough to contain the DISPIDs of the member + parameters
        arDispidNamedArgs.reset(new DISPID[nSizeAr]);   
        HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr,
                                                  arDispidNamedArgs.get()); 
        if ( hr == E_NOTIMPL )
            hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );

		if (hr == S_OK)
        {
            // In a "property put" operation, the property value is a named param with the
            //special DISPID DISPID_PROPERTYPUT
            if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
                || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
            {
                //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT
                //The first item in the array arDispidNamedArgs is the DISPID for
                //the method. We replace it with DISPID_PROPERTYPUT.
                DISPID*  arIDs = arDispidNamedArgs.get();
                arIDs[0] = DISPID_PROPERTYPUT;
                dispparams.rgdispidNamedArgs = arIDs;
            }
            else
            {
                //The first item in the array arDispidNamedArgs is the DISPID for
                //the method. It must be removed
                DISPID*  arIDs = arDispidNamedArgs.get();
                dispparams.rgdispidNamedArgs = & arIDs[1];
            }
        }
        else if (hr == DISP_E_UNKNOWNNAME)
        {
             throw IllegalArgumentException(
                 OUSTR("[automation bridge]One of the named arguments is wrong!"),
                 Reference<XInterface>(), 0);
        }
        else
        {
            throw InvocationTargetException(
                OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ")
                + OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any());
        }
    }

    //Convert arguments
    ptrArgs.reset(new CComVariant[dispparams.cArgs]);
    ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
    arArgs = ptrArgs.get();
    arRefArgs = ptrRefArgs.get();
	try
	{
		for (i = 0; i < (sal_Int32) dispparams.cArgs; i++)
		{
			revIndex= dispparams.cArgs - i -1;
			arRefArgs[revIndex].byref=0;
			Any  anyArg;
			if ( i < nUnoArgs)
				anyArg= Params.getConstArray()[i];
	        
			//Test if the current parameter is a "vararg" parameter.
			if (bVarargParam || (aFuncDesc->cParamsOpt == -1 &&
								aFuncDesc->cParams == (i + 1)))
			{   //This parameter is from the variable argument list. There is no
				//type info available, except that it must be a VARIANT
				bVarargParam = true;
			}
	        
			unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
			VARTYPE varType = VT_VARIANT;
			if ( ! bVarargParam)
			{
				paramFlags =
					aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
				varType = getElementTypeDesc(
					& aFuncDesc->lprgelemdescParam[i].tdesc);
			}
			//Make sure that there is a UNO parameter for every
			// expected parameter. If there is no UNO parameter where the
			// called function expects one, then it must be optional. Otherwise
			// its a UNO programming error.
			if (i  >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
			{
				OUStringBuffer buf(256);
				buf.appendAscii("ole automation bridge: The called function expects an argument at"
								"position: "); //a different number of arguments")),
				buf.append(OUString::valueOf((sal_Int32) i));
				buf.appendAscii(" (index starting at 0).");
				throw IllegalArgumentException( buf.makeStringAndClear(),
												Reference<XInterface>(), (sal_Int16) i);
			}

			// Property Put arguments
			if (anyArg.getValueType() == getCppuType((PropertyPutArgument*)0))
			{
				PropertyPutArgument arg;
				anyArg >>= arg;
				anyArg <<= arg.Value;
			}
			// named argument
			if (anyArg.getValueType() == getCppuType((NamedArgument*) 0))
			{
				NamedArgument aNamedArgument;
				anyArg >>= aNamedArgument;
				anyArg <<= aNamedArgument.Value;
			}
			// out param
			if (paramFlags & PARAMFLAG_FOUT &&
				! (paramFlags & PARAMFLAG_FIN)  )
			{
                VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
				if (i < nUnoArgs)
				{
					arRefArgs[revIndex].vt= type;                    
				}
				else
				{
					//optional arg
					arRefArgs[revIndex].vt = VT_ERROR;
					arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
				}
				if( type == VT_VARIANT )
				{
					arArgs[revIndex].vt= VT_VARIANT | VT_BYREF;
					arArgs[revIndex].byref= &arRefArgs[revIndex];
				}
				else
				{
					arArgs[revIndex].vt= varType;
					if (type == VT_DECIMAL)
						arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
					else
						arArgs[revIndex].byref= & arRefArgs[revIndex].byref;
				}
			}
			// in/out  + in byref params
			else if (varType & VT_BYREF)
			{
                VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
				CComVariant var;

				if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
				{
					anyToVariant( & arRefArgs[revIndex], anyArg, type);
				}
				else if (paramFlags & PARAMFLAG_FHASDEFAULT)
				{
					//optional arg with default
					VariantCopy( & arRefArgs[revIndex],
								& aFuncDesc->lprgelemdescParam[i].paramdesc.
								pparamdescex->varDefaultValue);
				}
				else
				{
					//optional arg
					//e.g: call func(x) in basic : func() ' no arg supplied
					OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
					arRefArgs[revIndex].vt = VT_ERROR;
					arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
				}
	            
				// Set the converted arguments in the array which will be
				// DISPPARAMS::rgvarg 
				// byref arg VT_XXX |VT_BYREF
				arArgs[revIndex].vt = varType;
				if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT)
				{
					arArgs[revIndex] = arRefArgs[revIndex];
				}
				else if (type == VT_DECIMAL)
				{
					arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
				}
				else if (type == VT_VARIANT)
				{
					if ( ! (paramFlags & PARAMFLAG_FOUT))
						arArgs[revIndex] = arRefArgs[revIndex];
					else
						arArgs[revIndex].byref = & arRefArgs[revIndex];
				}
				else
				{
					arArgs[revIndex].byref = & arRefArgs[revIndex].byref;
                    arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF );
				}

			}
			// in parameter no VT_BYREF except for array, interfaces
			else
			{	// void any stands for optional param
				if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
				{
					anyToVariant( & arArgs[revIndex], anyArg, varType);
				}
				//optional arg but no void any supplied
				//Basic:  obj.func() ' first parameter left out because it is optional
				else if (paramFlags & PARAMFLAG_FHASDEFAULT)
				{
					//optional arg with defaulteithter as direct arg : VT_XXX or
					VariantCopy( & arArgs[revIndex],
						& aFuncDesc->lprgelemdescParam[i].paramdesc.
							pparamdescex->varDefaultValue);
				}
				else if (paramFlags & PARAMFLAG_FOPT)
				{
					arArgs[revIndex].vt = VT_ERROR;
					arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
				}
                else
                {
                    arArgs[revIndex].vt = VT_EMPTY;
                    arArgs[revIndex].lVal = 0;
                }
			}
		}
	}	
    catch (IllegalArgumentException & e)
	{
		e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i );
		throw;
	}
	catch (CannotConvertException & e)
	{
		e.ArgumentIndex = i;
		throw;
	}
	dispparams.rgvarg= arArgs;
	// invoking OLE method
    DWORD localeId = LOCALE_USER_DEFAULT;
	result = m_spDispatch->Invoke(aFuncDesc->memid, 
								 IID_NULL,
								 localeId, 
								 ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ),
								 &dispparams, 
								 &varResult, 
								 &excepinfo,
								 &uArgErr);

	// converting return value and out parameter back to UNO
	if (result == S_OK)
	{
        
        // allocate space for the out param Sequence and indices Sequence
        int outParamsCount= 0; // includes in/out parameter
        for (int i = 0; i < aFuncDesc->cParams; i++)
        {
            if (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags &
                PARAMFLAG_FOUT)
                outParamsCount++;
        }

        OutParamIndex.realloc(outParamsCount);
        OutParam.realloc(outParamsCount);
        // Convert out params
        if (outParamsCount)
        {
            int outParamIndex=0;
            for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
            {
                //Determine the index within the method sinature
                int realParamIndex = paramIndex;
                int revParamIndex = dispparams.cArgs - paramIndex - 1;
                if (Params[paramIndex].getValueType()
                    == getCppuType((NamedArgument*) 0))
                {
                    //dispparams.rgdispidNamedArgs contains the mapping from index
                    //of named args list to index of parameter list
                    realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex];
                }
                
                // no named arg, always come before named args
                if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags
                       & PARAMFLAG_FOUT))
                    continue;
                Any outAny;
                // 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.
				try
				{
					variantToAny( & arRefArgs[revParamIndex], outAny, sal_False );
				}
				catch (IllegalArgumentException & e)
				{
					e.ArgumentPosition = (sal_Int16)paramIndex;
					throw;
				}
				catch (CannotConvertException & e)
				{
					e.ArgumentIndex = paramIndex;
					throw;
				}
                OutParam[outParamIndex] = outAny;
                OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
                outParamIndex++;
            }   
            OutParam.realloc(outParamIndex);
            OutParamIndex.realloc(outParamIndex);
        }
        // Return value		
		variantToAny(&varResult, ret, sal_False);
	}
		
	// map error codes to exceptions
	OUString message;
	switch (result)
	{
		case S_OK:
			break;
		case DISP_E_BADPARAMCOUNT:
			throw IllegalArgumentException(OUSTR("[automation bridge] Wrong "
                  "number of arguments. Object returned DISP_E_BADPARAMCOUNT."),
                  0, 0);
			break;
		case DISP_E_BADVARTYPE:
			throw RuntimeException(OUSTR("[automation bridge] One or more "
                  "arguments have the wrong type. Object returned "
                  "DISP_E_BADVARTYPE."), 0);
			break;
		case DISP_E_EXCEPTION:
				message = OUSTR("[automation bridge]: ");
				message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription), 
					::SysStringLen(excepinfo.bstrDescription));
				throw InvocationTargetException(message, Reference<XInterface>(), Any());
				break;
		case DISP_E_MEMBERNOTFOUND:
            message = OUSTR("[automation bridge]: A function with the name \"")
                + sFuncName + OUSTR("\" is not supported. Object returned "
                "DISP_E_MEMBERNOTFOUND.");                            
			throw IllegalArgumentException(message, 0, 0);
			break;
		case DISP_E_NONAMEDARGS:           
			throw IllegalArgumentException(OUSTR("[automation bridge] Object "
                  "returned DISP_E_NONAMEDARGS"),0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
			break;
		case DISP_E_OVERFLOW:
			throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[automation bridge] Call failed.")),
                                         static_cast<XInterface*>(
				static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
			break;
		case DISP_E_PARAMNOTFOUND:
			throw IllegalArgumentException(OUSTR("[automation bridge]Call failed."
                                                 "Object returned DISP_E_PARAMNOTFOUND."),
                                           0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 
			break;
		case DISP_E_TYPEMISMATCH:
			throw CannotConvertException(OUSTR("[automation bridge] Call  failed. "
                                         "Object returned DISP_E_TYPEMISMATCH"),
				static_cast<XInterface*>(
				static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
			break;
		case DISP_E_UNKNOWNINTERFACE:
			throw RuntimeException(OUSTR("[automation bridge] Call failed. "
                                       "Object returned DISP_E_UNKNOWNINTERFACE."),0);
			break;
		case DISP_E_UNKNOWNLCID:
			throw RuntimeException(OUSTR("[automation bridge] Call failed. "
                                       "Object returned DISP_E_UNKNOWNLCID."),0);
			break;
		case DISP_E_PARAMNOTOPTIONAL:
			throw CannotConvertException(OUSTR("[automation bridge] Call failed."
                  "Object returned DISP_E_PARAMNOTOPTIONAL"),
                        static_cast<XInterface*>(static_cast<XWeak*>(this)),
                              TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
			break;
		default:
			throw RuntimeException();
			break;
	}		
	
	return ret;
}	

void IUnknownWrapper_Impl::getFuncDescForInvoke(const OUString & sFuncName,
                                                const Sequence<Any> & seqArgs,
                                                FUNCDESC** pFuncDesc)
{
    int nUnoArgs = seqArgs.getLength();
    const Any * arArgs = seqArgs.getConstArray();
    ITypeInfo* pInfo = getTypeInfo();

    //If the last of the positional arguments is a PropertyPutArgument
    //then obtain the type info for the property put operation.

    //The property value is always the last argument, in a positional argument list
    //or in a list of named arguments. A PropertyPutArgument is actually a named argument
    //hence it must not be put in an extra NamedArgument structure
    if (nUnoArgs > 0 &&
        arArgs[nUnoArgs - 1].getValueType() == getCppuType((PropertyPutArgument*) 0))
    {
        // DISPATCH_PROPERTYPUT
        FuncDesc aDescGet(pInfo);
        FuncDesc aDescPut(pInfo);
        VarDesc aVarDesc(pInfo);
        getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
        if ( ! aDescPut)
        {
            throw IllegalArgumentException(
                OUSTR("[automation bridge] The object does not have a writeable property: ")
                + sFuncName, Reference<XInterface>(), 0);
        }
        *pFuncDesc = aDescPut.Detach();        
    }
    else
    {   // DISPATCH_METHOD
        FuncDesc aFuncDesc(pInfo);
        getFuncDesc(sFuncName, & aFuncDesc);
        if ( ! aFuncDesc)
        {
            // Fallback: DISPATCH_PROPERTYGET can mostly be called as
            // DISPATCH_METHOD
            ITypeInfo * pInfo = getTypeInfo();
            FuncDesc aDescPut(pInfo);
            VarDesc aVarDesc(pInfo);
            getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
            if ( ! aFuncDesc )
            {
                throw IllegalArgumentException(
                    OUSTR("[automation bridge] The object does not have a function"
                          "or readable property \"")
                    + sFuncName, Reference<XInterface>(), 0);
            }
        }
        *pFuncDesc = aFuncDesc.Detach();
    }
}
bool IUnknownWrapper_Impl::getDispid(const OUString& sFuncName, DISPID * id)
{
	OSL_ASSERT(m_spDispatch);
	LPOLESTR lpsz = const_cast<LPOLESTR> (reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
	HRESULT	hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
	return hr == S_OK ? true : false;
}
void IUnknownWrapper_Impl::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)

{
    OSL_ASSERT( * pFuncDesc == 0);
    buildComTlbIndex();
    typedef TLBFuncIndexMap::const_iterator cit;
	    typedef TLBFuncIndexMap::iterator it;
    //We assume there is only one entry with the function name. A property
    //would have two entries.
	cit itIndex= m_mapComFunc.find(sFuncName);
	if (itIndex == m_mapComFunc.end())
	{
		//try case insensive with IDispatch::GetIDsOfNames
		DISPID id;
		if (getDispid(sFuncName, &id))
		{
			CComBSTR memberName; 
            unsigned int pcNames=0;
			// get the case sensitive name
            if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
			{
				//get the associated index and add an entry to the map
				//with the name sFuncName which differs in the casing of the letters to 
				//the actual name as obtained from ITypeInfo
				cit itOrg  = m_mapComFunc.find(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
				OSL_ASSERT(itOrg != m_mapComFunc.end());
				itIndex =
					m_mapComFunc.insert( TLBFuncIndexMap::value_type
					( make_pair(sFuncName, itOrg->second ) ));
			}
		}
	}
	
#if OSL_DEBUG_LEVEL >= 1   
    // There must only be one entry if sFuncName represents a function or two
    // if it is a property
    pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase());
    int numEntries = 0;
    for ( ;p.first != p.second; p.first ++, numEntries ++);
    OSL_ASSERT( ! (numEntries > 3) );
#endif    
	if( itIndex != m_mapComFunc.end())
	{
        ITypeInfo* pType= getTypeInfo();
        FUNCDESC * pDesc = NULL;
        if (SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
        {
            if (pDesc->invkind == INVOKE_FUNC)
            {
                (*pFuncDesc) = pDesc;
            }
            else
            {
                pType->ReleaseFuncDesc(pDesc);
            }
        }
        else
        {
            throw BridgeRuntimeError(OUSTR("[automation bridge] Could not get "
                                           "FUNCDESC for ") + sFuncName);
        }
    }
   //else no entry found for sFuncName, pFuncDesc will not be filled in
}

void IUnknownWrapper_Impl::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
                                       FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
{
    OSL_ASSERT( * pFuncDescGet == 0 && * pFuncDescPut == 0);
    buildComTlbIndex();
    typedef TLBFuncIndexMap::const_iterator cit;
    pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
    if (p.first == m_mapComFunc.end())
	{
		//try case insensive with IDispatch::GetIDsOfNames
		DISPID id;
		if (getDispid(sFuncName, &id))
		{
			CComBSTR memberName; 
            unsigned int pcNames=0;
			// get the case sensitive name
            if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
			{
				//As opposed to getFuncDesc, we do not add the value because we would
				// need to find the get and set description for the property. This would 
				//mean to iterate over all FUNCDESCs again.
				p = m_mapComFunc.equal_range(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
			}
		}
	}

	for ( int i = 0 ;p.first != p.second; p.first ++, i ++)
	{
        // There are a maximum of two entries, property put and property get
        OSL_ASSERT( ! (i > 2) );
        ITypeInfo* pType= getTypeInfo();
        FUNCDESC * pFuncDesc = NULL;
        if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc)))
        {            
            if (pFuncDesc->invkind == INVOKE_PROPERTYGET)
            {
                (*pFuncDescGet) = pFuncDesc;
            }
            else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT ||
                     pFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
            {
                //a property can have 3 entries, put, put ref, get
                // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used
                //depends on what is found first.
                if ( * pFuncDescPut)
                {
                    //we already have found one
                    pType->ReleaseFuncDesc(pFuncDesc);
                }
                else
                {
                    (*pFuncDescPut) = pFuncDesc;
                }
            }
            else
            {
                pType->ReleaseFuncDesc(pFuncDesc);
            }
        }
        //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC
        // with invkind = INVOKE_FUNC. Since this function should only return
        //a value for a real property (XInvokation::hasMethod, ..::hasProperty
        //we need to make sure that sFuncName represents a real property.
        VARDESC * pVD = NULL;
        if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
            (*pVarDesc) = pVD;
    }
   //else no entry for sFuncName, pFuncDesc will not be filled in    
}

VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc)
{
	VARTYPE _type( VT_NULL );

	if (desc->vt == VT_PTR)
	{
		_type = getElementTypeDesc(desc->lptdesc);
        _type |= VT_BYREF;
	}
	else if (desc->vt == VT_SAFEARRAY)
	{
		_type = getElementTypeDesc(desc->lptdesc);
        _type |= VT_ARRAY;
	}
	else if (desc->vt == VT_USERDEFINED)
	{
		ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
		CComPtr<ITypeInfo>	spRefInfo;
		thisInfo->GetRefTypeInfo(desc->hreftype, & spRefInfo.p);
		if (spRefInfo)
		{
			TypeAttr  attr(spRefInfo);
			spRefInfo->GetTypeAttr( & attr);
			if (attr->typekind == TKIND_ENUM)
			{
				//We use the type of the first enum value.
				if (attr->cVars == 0)
				{
					throw BridgeRuntimeError(OUSTR("[automation bridge] Could "
						"not obtain type description"));
				}
				VarDesc var(spRefInfo);
				spRefInfo->GetVarDesc(0, & var);
				_type = var->lpvarValue->vt; 
			}
			else if (attr->typekind == TKIND_INTERFACE)
			{
				_type = VT_UNKNOWN;
			}
			else if (attr->typekind == TKIND_DISPATCH)
			{
				_type = VT_DISPATCH;
			}
			else 
			{
				throw BridgeRuntimeError(OUSTR("[automation bridge] "
					"Unhandled user defined type."));
			}
		}
	}
	else
	{
		_type = desc->vt;
	}
	return _type;
}

void IUnknownWrapper_Impl::buildComTlbIndex()
{
    if ( ! m_bComTlbIndexInit)
    {
        MutexGuard guard(getBridgeMutex());
        {
            if ( ! m_bComTlbIndexInit)
            {
                OUString sError;
                ITypeInfo* pType= getTypeInfo();
                TypeAttr typeAttr(pType);
                if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
                {
                    for( long i= 0; i < typeAttr->cFuncs; i++)
                    {
                        FuncDesc funcDesc(pType);
                        if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc)))
                        {
                            CComBSTR memberName; 
                            unsigned int pcNames=0;
                            if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames)))
                            {
								OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
                                m_mapComFunc.insert( TLBFuncIndexMap::value_type( usName, i));
                            }
                            else
                            {
                                sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
                                                "ITypeInfo::GetNames failed.");
                            }
                        }
                        else
                            sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
                                            "ITypeInfo::GetFuncDesc failed.");
                    }
					
					//If we create an Object in JScript and a a property then it 
					//has VARDESC instead of FUNCDESC
                    for (long i = 0; i < typeAttr->cVars; i++)
                    {
                        VarDesc varDesc(pType);
                        if (SUCCEEDED(pType->GetVarDesc(i, & varDesc)))
                        {
                            CComBSTR memberName; 
                            unsigned int pcNames = 0;
                            if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames)))
                            {
								if (varDesc->varkind == VAR_DISPATCH)
                                {
									OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
                                    m_mapComFunc.insert(TLBFuncIndexMap::value_type(
                                                        usName, i));
                                }
                            }
                            else
                            {
                                sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
                                                "ITypeInfo::GetNames failed.");
                            }
                        }
                        else
                            sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
                                           "ITypeInfo::GetVarDesc failed.");
                        
                    }
                }
                else
                    sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
                                    "ITypeInfo::GetTypeAttr failed.");

                if (sError.getLength())
                {
                    throw BridgeRuntimeError(sError);
                }
                    
                m_bComTlbIndexInit = true;
            }
        }
    }
}

ITypeInfo* IUnknownWrapper_Impl::getTypeInfo()
{
	if( !m_spDispatch)
    {
        throw BridgeRuntimeError(OUSTR("The object has no IDispatch interface!"));
    }

	if( !m_spTypeInfo )
	{
        MutexGuard guard(getBridgeMutex());
        if( ! m_spTypeInfo)
        {
            CComPtr< ITypeInfo > spType;
            if( SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p)))

            {
                OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

				//If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE
				//We need to get the type description for TKIND_DISPATCH
				TypeAttr typeAttr(spType.p);
                if( SUCCEEDED(spType->GetTypeAttr( &typeAttr)))
				{
					if (typeAttr->typekind == TKIND_INTERFACE && 
							typeAttr->wTypeFlags & TYPEFLAG_FDUAL)	
					{
						HREFTYPE refDispatch;
						if (SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch)))
						{
							CComPtr<ITypeInfo> spTypeDisp;
							if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
								m_spTypeInfo= spTypeDisp;
						}
						else
						{
							throw BridgeRuntimeError(
								OUSTR("[automation bridge] Could not obtain type information "
								"for dispatch interface." ));
						}
					}
					else if (typeAttr->typekind == TKIND_DISPATCH)
					{
						m_spTypeInfo= spType;
					}
					else
					{
						throw BridgeRuntimeError(
							OUSTR("[automation bridge] Automation object does not "
							"provide type information."));
					}
				}
            }
            else
            {
                throw BridgeRuntimeError(OUSTR("[automation bridge]The dispatch object does not "
                                               "support ITypeInfo!"));
            }
        }
    }
	return m_spTypeInfo;
}

} // end namespace

