/**************************************************************
 * 
 * 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 <stdio.h>
#include <tools/presys.h>
#include <olectl.h>
#include <vector>
#include <list>
#include <hash_map>
#include "comifaces.hxx"
#include <tools/postsys.h>


#include <vos/diagnose.hxx>
#include <vos/refernce.hxx>
#include <tools/debug.hxx>
#include <rtl/ustring.hxx>
#include <com/sun/star/beans/MethodConcept.hpp>
#include <com/sun/star/beans/PropertyConcept.hpp>
#include <com/sun/star/script/FailReason.hpp>
#include <com/sun/star/reflection/ParamInfo.hpp>
#include <com/sun/star/beans/XExactName.hpp>
#include <com/sun/star/container/NoSuchElementException.hpp>

#include <com/sun/star/beans/XMaterialHolder.hpp>
#include <com/sun/star/script/XInvocation2.hpp>
#include <com/sun/star/script/MemberType.hpp>
#include <com/sun/star/reflection/XIdlReflection.hpp>
#include <osl/interlck.h>
#include <com/sun/star/uno/genfunc.h>
#include <cppuhelper/implbase1.hxx>

#include "comifaces.hxx"
#include "jscriptclasses.hxx"
#include "unotypewrapper.hxx"
#include "oleobjw.hxx"
#include "unoobjw.hxx"
#include "servprov.hxx"

using namespace vos;
using namespace std;
using namespace rtl;
using namespace osl;
using namespace cppu;
using namespace com::sun::star::uno;
using namespace com::sun::star::beans;
using namespace com::sun::star::container;
using namespace com::sun::star::script;
using namespace com::sun::star::lang;
using namespace com::sun::star::bridge::ModelDependent;
using namespace com::sun::star::reflection;



#if _MSC_VER < 1200
extern "C" const GUID IID_IDispatchEx;
#endif

namespace ole_adapter
{
hash_map<sal_uInt32, WeakReference<XInterface> > UnoObjToWrapperMap;
static sal_Bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource);
static sal_Bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource);
static HRESULT mapCannotConvertException( CannotConvertException e, unsigned int * puArgErr);
    

/* Does not throw any exceptions.
   Param pInfo can be NULL.
 */
static void writeExcepinfo(EXCEPINFO * pInfo, const OUString& message)
{
    if (pInfo != NULL)
    {
        pInfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
        pInfo->bstrSource = SysAllocString(L"[automation bridge] ");
        pInfo->bstrDescription = SysAllocString(reinterpret_cast<LPCOLESTR>(message.getStr()));
    }
}

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

	class implementation: InterfaceOleWrapper_Impl
	
*****************************************************************************/
InterfaceOleWrapper_Impl::InterfaceOleWrapper_Impl( Reference<XMultiServiceFactory>& xFactory,
													sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
		m_defaultValueType( 0),
		UnoConversionUtilities<InterfaceOleWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass)
{
}

InterfaceOleWrapper_Impl::~InterfaceOleWrapper_Impl()
{
    MutexGuard guard(getBridgeMutex());
	// remove entries in global map
    IT_Uno it= UnoObjToWrapperMap.find( (sal_uInt32) m_xOrigin.get());
    if(it != UnoObjToWrapperMap.end())
        UnoObjToWrapperMap.erase(it);
#if OSL_DEBUG_LEVEL > 0
    fprintf(stderr,"[automation bridge] UnoObjToWrapperMap  contains: %i \n",
            UnoObjToWrapperMap.size());
#endif     
    
}	

STDMETHODIMP InterfaceOleWrapper_Impl::QueryInterface(REFIID riid, LPVOID FAR * ppv)
{
	HRESULT ret= S_OK;

	if( !ppv)
		return E_POINTER;

    if(IsEqualIID(riid, IID_IUnknown))
	{
		AddRef();
		*ppv = (IUnknown*) (IDispatch*) this;
    } 
    else if (IsEqualIID(riid, IID_IDispatch))
	{
		AddRef();
		*ppv = (IDispatch*) this;
	}
	else if( IsEqualIID( riid, __uuidof( IUnoObjectWrapper)))
	{
		AddRef();
		*ppv= (IUnoObjectWrapper*) this;
	}
	else
		ret= E_NOINTERFACE;
	return ret;
}	

STDMETHODIMP_(ULONG) InterfaceOleWrapper_Impl::AddRef()
{
    acquire();
    // does not need to guard because one should not rely on the return value of
    // AddRef anyway
	return m_refCount;
}	

STDMETHODIMP_(ULONG) InterfaceOleWrapper_Impl::Release()
{
    ULONG n= m_refCount;
    release();
    return n - 1;
}	

// IUnoObjectWrapper --------------------------------------------------------
STDMETHODIMP InterfaceOleWrapper_Impl::getWrapperXInterface( Reference<XInterface>* pXInt)
{
	*pXInt= Reference<XInterface>( static_cast<XWeak*>( this), UNO_QUERY);
	return pXInt->is() ? S_OK : E_FAIL;
}
STDMETHODIMP InterfaceOleWrapper_Impl::getOriginalUnoObject( Reference<XInterface>* pXInt)
{
	*pXInt= m_xOrigin;
	return m_xOrigin.is() ? S_OK : E_FAIL;
}
STDMETHODIMP  InterfaceOleWrapper_Impl::getOriginalUnoStruct( Any * pStruct)
{
	HRESULT ret= E_FAIL;
	if( !m_xOrigin.is())
	{
		Reference<XMaterialHolder> xMatHolder( m_xInvocation, UNO_QUERY);
		if( xMatHolder.is())
		{
			Any any = xMatHolder->getMaterial();
			if( any.getValueTypeClass() == TypeClass_STRUCT)
			{
				*pStruct= any;
				ret= S_OK;
			}
		}
	}
	return ret;
}

STDMETHODIMP InterfaceOleWrapper_Impl::GetTypeInfoCount( unsigned int * /*pctinfo*/ )
{
	return E_NOTIMPL ;
}	

STDMETHODIMP InterfaceOleWrapper_Impl::GetTypeInfo(unsigned int /*itinfo*/, LCID /*lcid*/, ITypeInfo ** /*pptinfo*/)
{
	return E_NOTIMPL;
}	

STDMETHODIMP InterfaceOleWrapper_Impl::GetIDsOfNames(REFIID /*riid*/, 
													 OLECHAR ** rgszNames, 
													 unsigned int cNames,
													 LCID /*lcid*/, 
													 DISPID * rgdispid )
{
    HRESULT ret = DISP_E_UNKNOWNNAME;
    try
    {
        MutexGuard guard( getBridgeMutex());
        if( ! rgdispid)
            return E_POINTER;

        // ----------------------------------------
        if( ! _wcsicmp( *rgszNames, JSCRIPT_VALUE_FUNC) || 
            ! _wcsicmp( *rgszNames, BRIDGE_VALUE_FUNC))
        {
            *rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
            return S_OK;
        }
        else if( ! _wcsicmp( *rgszNames, GET_STRUCT_FUNC) ||
                 ! _wcsicmp( *rgszNames, BRIDGE_GET_STRUCT_FUNC))
        {
            *rgdispid= DISPID_GET_STRUCT_FUNC;
            return S_OK;
        }
        else if( ! _wcsicmp( *rgszNames, BRIDGE_CREATE_TYPE_FUNC))
        {
            *rgdispid= DISPID_CREATE_TYPE_FUNC;
            return S_OK;
        }

        // ----------------------------------------
        if (m_xInvocation.is() && (cNames > 0))
        {
            OUString name(reinterpret_cast<const sal_Unicode*>(rgszNames[0]));
            NameToIdMap::iterator iter = m_nameToDispIdMap.find(name);
            
            if (iter == m_nameToDispIdMap.end())
            {
                OUString exactName;
                
                if (m_xExactName.is())
                {
                    exactName = m_xExactName->getExactName(name);
                }
                else
                {    
                    exactName = name;
                }
                
                MemberInfo d(0, exactName);
                
                if (m_xInvocation->hasProperty(exactName))
                {
                    d.flags |= DISPATCH_PROPERTYGET;			
                    d.flags |= DISPATCH_PROPERTYPUT;
                    d.flags |= DISPATCH_PROPERTYPUTREF;
                }
                
                if (m_xInvocation->hasMethod(exactName))
                {
                    d.flags |= DISPATCH_METHOD;			
                }
                
                if (d.flags != 0)
                {
                    m_MemberInfos.push_back(d);
                    iter = m_nameToDispIdMap.insert(NameToIdMap::value_type(exactName, (DISPID)m_MemberInfos.size())).first;
                    
                    if (exactName != name)
                    {
                        iter = m_nameToDispIdMap.insert(NameToIdMap::value_type(name, (DISPID)m_MemberInfos.size())).first;
                    }
                }		
            }
		
            if (iter == m_nameToDispIdMap.end())
            {
                ret = DISP_E_UNKNOWNNAME;
            }
            else
            {
                *rgdispid = (*iter).second;
                ret = S_OK;
            }
        }	
    }
    catch(BridgeRuntimeError& )
    {
        OSL_ASSERT(0);
    }
    catch(Exception& )
    {
        OSL_ASSERT(0);
    }
	catch(...)
	{
        OSL_ASSERT(0);
	}

    return ret;
}	
    
// "convertDispparamsArgs" converts VARIANTS to their respecting Any counterparts
// The parameters "id", "wFlags" and "pdispparams" equal those as used in 
// IDispatch::Invoke. The function handles special JavaScript 
// cases where a VARIANT of type VT_DISPATCH is ambiguous and could represent 
// an object, array ( JavaScript Array object), out parameter and in/out ( JavaScript Array object)
//  parameter (JavaScript Array object)
// Because all those VT_DISPATCH objects need a different conversion
// we have to find out what the object is supposed to be. The function does this
// by either using type information or by help of a specialized ValueObject object.

// A. Type Information
// -----------------------------------------------------------------------------
// With the help of type information the kind of parameter can be exactly determined 
// and an appropriate conversion can be choosen. A problem arises if a method expects 
// an Any. Then the type info does not tell what the type of the value, that is kept 
// by the any, should be. In this situation the decision wheter the param is a 
// sequence or an object is made upon the fact if the object has a property "0"
// ( see function "isJScriptArray"). Since this is unsafe it is recommended to use
// the JScript value objects within a JScript script on such an occasion.

// B. JavaScript Value Object ( class JScriptValue )
// -----------------------------------------------------------------------------
// A JScriptValue (ValueObject) object is a COM object in that it implements IDispatch and the
// IJScriptValue object interface. Such objects are provided by all UNO wrapper 
// objects used within a JScript script. To obtain an instance one has to call
// "_GetValueObject() or Bridge_GetValueObject()" on an UNO wrapper object (class InterfaceOleWrapper_Impl).
// A value object is appropriately initialized within the script and passed as 
// parameter to an UNO object method or property. The convertDispparamsArgs function
// can easily find out that a param is such an object by queriing for the 
// IJScriptValue interface. By this interface one the type and kind ( out, in/out)
// can be determined and the right conversion can be applied. 
// Using ValueObjects we spare us the effort of aquiring and examining type information
// in order to figure out what the an IDispatch parameter is meant for.

// Normal JScript object parameter can be mixed with JScriptValue object. If an 
// VARIANT contains an VT_DISPATCH that is no JScriptValue than the type information
// is used to find out about the reqired type.
void InterfaceOleWrapper_Impl::convertDispparamsArgs(DISPID id,
    unsigned short /*wFlags*/, DISPPARAMS* pdispparams, Sequence<Any>& rSeq)
{
	HRESULT hr= S_OK;
	sal_Int32 countArgs= pdispparams->cArgs;
	if( countArgs == 0) 
		return;
	
	rSeq.realloc( countArgs);
	Any*	pParams = rSeq.getArray();

	Any anyParam;

    //Get type information for the current call
    InvocationInfo info;
    if( ! getInvocationInfoForCall( id, info))
        throw BridgeRuntimeError(
            OUSTR("[automation bridge]InterfaceOleWrapper_Impl::convertDispparamsArgs \n"
                  "Could not obtain type information for current call."));
    
    for (int i = 0; i < countArgs; i++)
    {
        if (info.eMemberType == MemberType_METHOD &&
            info.aParamModes[ countArgs - i -1 ]  == ParamMode_OUT)
            continue;

 		if(convertValueObject( & pdispparams->rgvarg[i], anyParam)) 
 		{ //a param is a ValueObject and could be converted
            pParams[countArgs - (i + 1)] = anyParam;
 			continue;
 		}

        // If the param is an out, in/out parameter in
        // JScript (Array object, with value at index 0) then we
        // extract Array[0] and put the value into varParam. At the end of the loop varParam
        // is converted if it contains a value otherwise the VARIANT from 
        // DISPPARAMS is converted.
        CComVariant varParam;

        // Check for JScript out and in/out paramsobjects (VT_DISPATCH).
        // To find them out we use typeinformation of the function being called.
        if( pdispparams->rgvarg[i].vt == VT_DISPATCH )			
        {
            if( info.eMemberType == MemberType_METHOD && info.aParamModes[ countArgs - i -1 ]  == ParamMode_INOUT)
            {
                // INOUT-param
                // Index ( property) "0" contains the actual IN-param. The object is a JScript
                // Array object.
                // Get the IN-param at index "0"
                IDispatch* pdisp= pdispparams->rgvarg[i].pdispVal;
                
                OLECHAR* sindex= L"0";
                DISPID id;
                DISPPARAMS noParams= {0,0,0,0};
                if(SUCCEEDED( hr= pdisp->GetIDsOfNames( IID_NULL, &sindex, 1, LOCALE_USER_DEFAULT, &id)))
                    hr= pdisp->Invoke( id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, 
                                       & noParams, & varParam, NULL, NULL);
                if( FAILED( hr))
                {
                    throw BridgeRuntimeError(
                        OUSTR("[automation bridge] Could not determine "
                              "if the object has a member \"0\". Error: ") +
                        OUString::valueOf(hr));
                }
            }
        }

        if( varParam.vt == VT_EMPTY) // then it was no in/out parameter
                 varParam= pdispparams->rgvarg[i];

        if(info.eMemberType == MemberType_METHOD)
            variantToAny( & varParam, anyParam,
                           info.aParamTypes[ countArgs - i - 1]);
        else if(info.eMemberType == MemberType_PROPERTY)
            variantToAny( & varParam, anyParam, info.aType);
        else
            OSL_ASSERT(0);
        
        pParams[countArgs - (i + 1)]= anyParam;
    }// end for / iterating over all parameters
}

sal_Bool  InterfaceOleWrapper_Impl::getInvocationInfoForCall( DISPID id, InvocationInfo& info)
{
    sal_Bool bTypesAvailable= sal_False; 
	
    if( !m_xInvocation.is() )return false;
    Reference<XInvocation2> inv2( m_xInvocation, UNO_QUERY);
    if( inv2.is())
    {
        // We need the name of the property or method to get its type information. 
        // The name can be identified through the param "id"
        // that is kept as value in the map m_nameToDispIdMap. 
        // Proplem: the Windows JScript engine sometimes changes small letters to capital 
        // letters as happens in xidlclass_obj.createObject( var) // in JScript.
        // IDispatch::GetIdsOfNames is then called with "CreateObject" !!!
        // m_nameToDispIdMap can contain several names for one DISPID but only one is
        // the exact one. If there's no m_xExactName and therefore no exact name then 
        // there's only one entry in the map.
        typedef NameToIdMap::const_iterator cit;
        OUString sMemberName;

        for(cit ci1= m_nameToDispIdMap.begin(); ci1 != m_nameToDispIdMap.end(); ci1++)
        {
            if( (*ci1).second == id) // iterator is a pair< OUString, DISPID>
            {
                sMemberName= (*ci1).first;
                break;
            }
        }        
        // Get information for the current call ( property or method).
        // There could be similar names which only differ in the cases
        // of letters. First we assume that the name which was passed into
        // GetIDsOfNames is correct. If we won't get information with that
        // name then we have the invocation service use the XExactName interface.
        sal_Bool validInfo= sal_True;
        InvocationInfo invInfo;
        try{
            invInfo= inv2->getInfoForName( sMemberName, sal_False);
        }
        catch( IllegalArgumentException )
        {
            validInfo= sal_False;
        }
        
        if( ! validInfo)
        {
            invInfo= inv2->getInfoForName( sMemberName, sal_True);
        }
        if( invInfo.aName.pData)
        {
            bTypesAvailable= sal_True;
            info= invInfo;
        }
    }
    return bTypesAvailable;
}
// XBridgeSupplier2 ---------------------------------------------------
// only bridges itself ( this instance of InterfaceOleWrapper_Impl)from UNO to IDispatch
// If sourceModelType is UNO than any UNO interface implemented by InterfaceOleWrapper_Impl
// can bridged to IDispatch ( if destModelType == OLE). The IDispatch is
// implemented by this class.
Any SAL_CALL InterfaceOleWrapper_Impl::createBridge(const Any& modelDepObject, 
								const Sequence<sal_Int8>& /*ProcessId*/, 
								sal_Int16 sourceModelType, 
								sal_Int16 destModelType) 
			throw (IllegalArgumentException, RuntimeException)
{

	Any retAny;
	if( sourceModelType == UNO && destModelType == OLE && 
		modelDepObject.getValueTypeClass() == TypeClass_INTERFACE )
	{
		Reference<XInterface> xInt;
		if( modelDepObject >>= xInt )
		{	
			if( xInt == Reference<XInterface>( static_cast<XWeak*>( this), UNO_QUERY))
			{
				VARIANT *pVar= (VARIANT*)CoTaskMemAlloc( sizeof( VARIANT));
				if( pVar)
				{
					pVar->vt= VT_DISPATCH;
					pVar->pdispVal= static_cast<IDispatch*>( this);
					AddRef();

					retAny<<= reinterpret_cast< sal_uInt32 >( pVar);
				}
			}
		}
	}

	return retAny;
}


// XInitialization --------------------------------------------------
void SAL_CALL InterfaceOleWrapper_Impl::initialize( const Sequence< Any >& aArguments ) 
		throw(Exception, RuntimeException)
{
	switch( aArguments.getLength() )
	{
	case 2: // the object wraps an UNO struct
		aArguments[0] >>= m_xInvocation;
		aArguments[1] >>= m_defaultValueType;
		break;
	case 3: // the object wraps an UNO interface
		aArguments[0] >>= m_xInvocation;
		aArguments[1] >>= m_xOrigin;
		aArguments[2] >>= m_defaultValueType;
		break;
	}

	m_xExactName= Reference<XExactName>( m_xInvocation, UNO_QUERY);
}

Reference< XInterface > InterfaceOleWrapper_Impl::createUnoWrapperInstance()
{
	Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl(
							m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
	return Reference<XInterface>( xWeak, UNO_QUERY);
}

Reference<XInterface> InterfaceOleWrapper_Impl::createComWrapperInstance()
{
	Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl( 
							m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
	return Reference<XInterface>( xWeak, UNO_QUERY);
}



// "getType" is used in convertValueObject to map the string denoting the type
// to an actual Type object.
bool getType( const BSTR name, Type & type)
{
	Type retType;
	bool ret = false;
	typelib_TypeDescription	* pDesc= NULL;
	OUString str( reinterpret_cast<const sal_Unicode*>(name));
	typelib_typedescription_getByName( &pDesc, str.pData );
	if( pDesc)
	{
		type = Type( pDesc->pWeakRef );
		typelib_typedescription_release( pDesc);
		ret = true;
	}
	return ret;
}

static sal_Bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource)
{
	sal_Bool ret = sal_False;	
	HRESULT hr;

	// Handle JScriptValue objects and JScript out params ( Array object )
	CComVariant varDest( *pDest);
	
	if( SUCCEEDED( varDest.ChangeType(VT_DISPATCH)))
	{
		CComPtr<IDispatch> spDispDest(varDest.pdispVal);

		// special Handling for a JScriptValue object
#ifdef __MINGW32__
		CComQIPtr<IJScriptValueObject, &__uuidof(IJScriptValueObject)> spValueDest(spDispDest);
#else
		CComQIPtr<IJScriptValueObject> spValueDest(spDispDest);
#endif
		if (spValueDest)
		{
			VARIANT_BOOL varBool= VARIANT_FALSE;
			if( SUCCEEDED( hr= spValueDest->IsOutParam( &varBool) ) 
				&& varBool == VARIANT_TRUE  || 
				SUCCEEDED(hr= spValueDest->IsInOutParam( &varBool) ) 
				&& varBool == VARIANT_TRUE )
			{
				if( SUCCEEDED( spValueDest->Set( CComVariant(), *pSource)))
					ret= sal_True;
			}
		}
		else if (pDest->vt == VT_DISPATCH)// VT_DISPATCH -> JScript out param
		{
			// We use IDispatchEx because its GetDispID function causes the creation
			// of a property if it does not exist already. This is convenient for
			// out parameters in JScript. Then the user must not specify propery "0"
			// explicitly
#ifdef __MINGW32__
			CComQIPtr<IDispatchEx, &__uuidof(IDispatchEx)> spDispEx( spDispDest);
#else
			CComQIPtr<IDispatchEx> spDispEx( spDispDest);
#endif
			if( spDispEx)
			{
				CComBSTR nullProp(L"0");
				DISPID dwDispID;
				if( SUCCEEDED( spDispEx->GetDispID( nullProp, fdexNameEnsure, &dwDispID)))
				{
					DISPPARAMS dispparams = {NULL, NULL, 1, 1};
					dispparams.rgvarg = pSource;
					DISPID dispidPut = DISPID_PROPERTYPUT;
					dispparams.rgdispidNamedArgs = &dispidPut;

					if (pSource->vt == VT_UNKNOWN || pSource->vt == VT_DISPATCH || 
						(pSource->vt & VT_ARRAY) || (pSource->vt & VT_BYREF))
						hr = spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
												&dispparams, NULL, NULL, NULL);
					else
						hr= spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
											   &dispparams, NULL, NULL, NULL);
					if( SUCCEEDED(hr))
						ret= sal_True;
				}
			}
		}
		else
			ret= writeBackOutParameter( pDest, pSource);
	}
	else // The param can't be a JScript out-parameter ( an Array object), it could be a VBScript
	{	// param. The function checks itself for correct VBScript params
		ret= writeBackOutParameter( pDest, pSource);
	}
	return ret;
}
// VisualBasic Script passes arguments as VT_VARIANT | VT_BYREF be it in or out parameter.
// Thus we are in charge of freeing an eventual value contained by the inner VARIANT
// Please note: VariantCopy doesn't free a VT_BYREF value
// The out parameters are expected to have always a valid type
static sal_Bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource)
{
	HRESULT hr;
	sal_Bool ret = FALSE;	
	// Out parameter must be VT_BYREF
	if ((V_VT(pDest) & VT_BYREF) != 0 )
	{
		VARTYPE oleTypeFlags = V_VT(pSource);

		// if caller accept VARIANT as out parameter, any value must be converted 
		if (V_VT(pDest) == (VT_VARIANT | VT_BYREF))
		{
			// When the user provides a VARIANT rather then a concrete type
			// we just copy the source to the out, in/out parameter
			// VT_DISPATCH, VT_UNKNOWN, VT_ARRAY, VT_BSTR in the VARIANT that
			// is contained in pDest are released by VariantCopy
			VariantCopy(V_VARIANTREF(pDest), pSource);
			ret	= sal_True;
		}
		else 
		{
			// variantarg and variant must have same type	
  			if ((V_VT(pDest) & oleTypeFlags) == oleTypeFlags)
			{
				if ((oleTypeFlags & VT_ARRAY) != 0)
				{
					// In / Out Param
					if( *V_ARRAYREF(pDest) != NULL)
						hr= SafeArrayCopyData( V_ARRAY(pSource), *V_ARRAYREF(pDest));
					else
						// Out Param
						hr= SafeArrayCopy(V_ARRAY(pSource), V_ARRAYREF(pDest)) == NOERROR;
					if( SUCCEEDED( hr))
						ret	= sal_True;
				}
				else
				{
					// copy base type
					switch (V_VT(pSource))
					{
					case VT_I2:
					{
						*V_I2REF(pDest) = V_I2(pSource);
						ret	= sal_True;
						break;
					}
					case VT_I4:
						*V_I4REF(pDest) = V_I4(pSource);
						ret	= sal_True;
						break;
					case VT_R4:
						*V_R4REF(pDest) = V_R4(pSource);
						ret	= sal_True;
						break;
					case VT_R8:
						*V_R8REF(pDest) = V_R8(pSource);
						ret	= sal_True;
						break;
					case VT_CY:
						*V_CYREF(pDest) = V_CY(pSource);
						ret	= sal_True;
						break;
					case VT_DATE:
						*V_DATEREF(pDest) = V_DATE(pSource);
						ret	= sal_True;
						break;
					case VT_BSTR:
						SysFreeString( *pDest->pbstrVal);
					
						*V_BSTRREF(pDest) = SysAllocString(V_BSTR(pSource));
						ret	= sal_True;
						break;
					case VT_DISPATCH:
						if (*V_DISPATCHREF(pDest) != NULL) 
							(*V_DISPATCHREF(pDest))->Release();
					
						*V_DISPATCHREF(pDest) = V_DISPATCH(pSource);
					
						if (*V_DISPATCHREF(pDest) != NULL) 
							(*V_DISPATCHREF(pDest))->AddRef();
					
						ret	= sal_True;
						break;
					case VT_ERROR:
						*V_ERRORREF(pDest) = V_ERROR(pSource);
						ret	= sal_True;
						break;
					case VT_BOOL:
						*V_BOOLREF(pDest) = V_BOOL(pSource);
						ret	= sal_True;
						break;
					case VT_UNKNOWN:
						if (*V_UNKNOWNREF(pDest) != NULL) 
							(*V_UNKNOWNREF(pDest))->Release();
					
						*V_UNKNOWNREF(pDest) = V_UNKNOWN(pSource);
					
						if (*V_UNKNOWNREF(pDest) != NULL) 
							(*V_UNKNOWNREF(pDest))->AddRef();
					
						ret	= sal_True;
						break;
					case VT_I1:
						*V_I1REF(pDest) = V_I1(pSource);
						ret	= sal_True;
						break;
					case VT_UI1:
						*V_UI1REF(pDest) = V_UI1(pSource);
						ret	= sal_True;
						break;
					case VT_UI2:
						*V_UI2REF(pDest) = V_UI2(pSource);
						ret	= sal_True;
						break;
					case VT_UI4:
						*V_UI4REF(pDest) = V_UI4(pSource);
						ret	= sal_True;
						break;
					case VT_INT:
						*V_INTREF(pDest) = V_INT(pSource);
						ret	= sal_True;
						break;
					case VT_UINT:
						*V_UINTREF(pDest) = V_UINT(pSource);
						ret	= sal_True;
						break;
					case VT_DECIMAL:
                        memcpy(pDest->pdecVal, pSource, sizeof(DECIMAL));
                        ret = sal_True;
                        break;
					default:
						break;
					}
				}
			}
			else
			{
				// Handling of special cases
				// Destination and source types are different
				if( pDest->vt == (VT_BSTR | VT_BYREF)
					&& pSource->vt == VT_I2)
				{
					// When the user provides a String as out our in/out parameter
					// and the type is char (TypeClass_CHAR) then we convert to a BSTR
					// instead of VT_I2 as is done otherwise
					OLECHAR buff[]= {0,0};
					buff[0]= pSource->iVal;

					SysFreeString( *pDest->pbstrVal);
					*pDest->pbstrVal= SysAllocString( buff);
					ret = sal_True;
				}
			}
		}
	}
	return ret;
}		

STDMETHODIMP InterfaceOleWrapper_Impl::Invoke(DISPID dispidMember, 
											  REFIID /*riid*/, 
											  LCID /*lcid*/, 
											  unsigned short wFlags,
                     						  DISPPARAMS * pdispparams, 
											  VARIANT * pvarResult, 
											  EXCEPINFO * pexcepinfo,
                     						  unsigned int * puArgErr )
{
	HRESULT ret = S_OK;

    try
    {
        sal_Bool bHandled= sal_False;
        ret= InvokeGeneral( dispidMember,  wFlags, pdispparams, pvarResult,  pexcepinfo,
                            puArgErr, bHandled);
        if( bHandled)
            return ret;

        if ((dispidMember > 0) && ((size_t)dispidMember <= m_MemberInfos.size()) && m_xInvocation.is())
        {
            MemberInfo d = m_MemberInfos[dispidMember - 1];
            DWORD flags = wFlags & d.flags;
            
            if (flags != 0)
            {
                if ((flags & DISPATCH_METHOD) != 0)
                {
                    if (pdispparams->cNamedArgs	> 0)
                        ret = DISP_E_NONAMEDARGS;					
                    else
                    {
                        Sequence<Any> params;
					
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams , params );
                        
                        ret= doInvoke(pdispparams, pvarResult, 
                                      pexcepinfo, puArgErr, d.name, params);
                    }
                }
                else if ((flags & DISPATCH_PROPERTYGET) != 0)
                {
                    ret=  doGetProperty( pdispparams, pvarResult, 
                                         pexcepinfo, d.name);
                }
                else if ((flags & DISPATCH_PROPERTYPUT || flags & DISPATCH_PROPERTYPUTREF) != 0)
                {
                    if (pdispparams->cArgs != 1)
                        ret = DISP_E_BADPARAMCOUNT;
                    else							
                    {
                        Sequence<Any> params;
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
                        if(params.getLength() > 0)
                            ret= doSetProperty( pdispparams, pvarResult, pexcepinfo, puArgErr, d.name, params);
                        else
                            ret = DISP_E_BADVARTYPE;
                    }
                }
            }
            else
                ret= DISP_E_MEMBERNOTFOUND;
        }	
        else
            ret = DISP_E_MEMBERNOTFOUND;
    }
    catch(BridgeRuntimeError& e)
    {
        writeExcepinfo(pexcepinfo, e.message);
        ret = DISP_E_EXCEPTION;
    }
    catch(Exception& e)
    {
        OUString message= OUSTR("InterfaceOleWrapper_Impl::Invoke : \n") +
                                e.Message;
        writeExcepinfo(pexcepinfo, message);
		ret = DISP_E_EXCEPTION;
    }
	catch(...)
	{
        OUString message= OUSTR("InterfaceOleWrapper_Impl::Invoke : \n" 
                                "Unexpected exception");
        writeExcepinfo(pexcepinfo, message);
 		ret = DISP_E_EXCEPTION;
	}

	return ret;
}												  

HRESULT InterfaceOleWrapper_Impl::doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult, 
							  EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any>& params)
{

    
	HRESULT ret= S_OK;
    try
    {
        Sequence<sal_Int16> 	outIndex;
        Sequence<Any> 	outParams;
        Any 				returnValue;
        
        if (pdispparams->cNamedArgs	> 0)
            return DISP_E_NONAMEDARGS;					

        // invoke method and take care of exceptions
		returnValue = m_xInvocation->invoke(name, 
											params,
											outIndex,
											outParams);									

        // try to write back out parameter						
        if (outIndex.getLength() > 0)
        {
            const sal_Int16* pOutIndex = outIndex.getConstArray();
            const Any* pOutParams = outParams.getConstArray();
            
            for (sal_Int32 i = 0; i < outIndex.getLength(); i++)
            {
                CComVariant variant;
                // Currently a Sequence is converted to an SafeArray of VARIANTs.
                anyToVariant( &variant, pOutParams[i]);
                
                // out parameter need special handling if they are VT_DISPATCH
                // and used in JScript
                int outindex= pOutIndex[i];
                writeBackOutParameter2(&(pdispparams->rgvarg[pdispparams->cArgs - 1 - outindex]), 
                                       &variant );                
            }
        }
        
        // write back return value
        if (pvarResult != NULL)   
            anyToVariant(pvarResult, returnValue);            
    }
	catch(IllegalArgumentException & e) //XInvocation::invoke
	{
        writeExcepinfo(pexcepinfo, e.Message);
		ret = DISP_E_TYPEMISMATCH;
	}
	catch(CannotConvertException & e) //XInvocation::invoke
	{
        writeExcepinfo(pexcepinfo, e.Message);
		ret = mapCannotConvertException( e, puArgErr);
	}
	catch(InvocationTargetException &  e) //XInvocation::invoke
	{
        const Any& org = e.TargetException;
        Exception excTarget;
        org >>= excTarget;
        OUString message= 
            org.getValueType().getTypeName() + OUSTR(": ") + excTarget.Message;
        writeExcepinfo(pexcepinfo, message);
		ret = DISP_E_EXCEPTION;
	}
	catch(NoSuchMethodException & e) //XInvocation::invoke
	{
        writeExcepinfo(pexcepinfo, e.Message);
		ret = DISP_E_MEMBERNOTFOUND;
	}
    catch(BridgeRuntimeError & e)
    {
        writeExcepinfo(pexcepinfo, e.message);
        ret = DISP_E_EXCEPTION;
    }
    catch(Exception & e)
    {
        OUString message= OUSTR("InterfaceOleWrapper_Impl::doInvoke : \n") +
                                e.Message;
        writeExcepinfo(pexcepinfo, message);
        ret = DISP_E_EXCEPTION;
    }
    catch( ... )
 	{
        OUString message= OUSTR("InterfaceOleWrapper_Impl::doInvoke : \n" 
                                "Unexpected exception");
        writeExcepinfo(pexcepinfo, message);
 		ret = DISP_E_EXCEPTION;
 	}
	return ret;
}

HRESULT InterfaceOleWrapper_Impl::doGetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * pvarResult, 
												EXCEPINFO * pexcepinfo, OUString& name)
{
	HRESULT ret= S_OK;

	Any value;
	try
	{
		Any returnValue = m_xInvocation->getValue( name);
		// write back return value
		if (pvarResult)
            anyToVariant(pvarResult, returnValue);
	}
	catch(UnknownPropertyException e) //XInvocation::getValue
	{
        writeExcepinfo(pexcepinfo, e.Message);
		ret = DISP_E_MEMBERNOTFOUND;
	}
    catch(BridgeRuntimeError& e)
    {
        writeExcepinfo(pexcepinfo, e.message);
        ret = DISP_E_EXCEPTION;
    }
    catch(Exception& e)
    {
        OUString message= OUSTR("InterfaceOleWrapper_Impl::doGetProperty : \n") +
                                e.Message;
        writeExcepinfo(pexcepinfo, message);
    }
	catch( ... )
	{
        OUString message= OUSTR("InterfaceOleWrapper_Impl::doInvoke : \n" 
                                "Unexpected exception");
        writeExcepinfo(pexcepinfo, message);
 		ret = DISP_E_EXCEPTION;
	}
	return  ret;
}

HRESULT InterfaceOleWrapper_Impl::doSetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/, 
										EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any> params)
{
	HRESULT ret= S_OK;
	
	try
	{
		m_xInvocation->setValue( name, params.getConstArray()[0]);
	}	
	catch(UnknownPropertyException )
	{
		ret = DISP_E_MEMBERNOTFOUND;
	}
	catch(CannotConvertException e)
	{
		ret= mapCannotConvertException( e, puArgErr);
	}
	catch(InvocationTargetException e)
	{
		if (pexcepinfo != NULL)
		{
			Any org = e.TargetException;
			
			pexcepinfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
			pexcepinfo->bstrSource = SysAllocString(L"any ONE component");
			pexcepinfo->bstrDescription = SysAllocString(
				reinterpret_cast<LPCOLESTR>(org.getValueType().getTypeName().getStr()));
		}
		ret = DISP_E_EXCEPTION;
	}
	catch( ... )
	{
		ret= DISP_E_EXCEPTION;
	}
	return ret;
}

HRESULT InterfaceOleWrapper_Impl::InvokeGeneral( DISPID dispidMember, unsigned short wFlags,
	                     DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
	                     unsigned int * /*puArgErr*/, sal_Bool& bHandled)
{
	HRESULT ret= S_OK;
    try
    {
// DISPID_VALUE | The DEFAULT Value is required in JScript when the situation
// is that we put an object into an Array object ( out parameter). We have to return
// IDispatch otherwise the object cannot be accessed from the Script.
        if( dispidMember == DISPID_VALUE && wFlags == DISPATCH_PROPERTYGET
            && m_defaultValueType != VT_EMPTY && pvarResult != NULL)
        {
            bHandled= sal_True;
            if( m_defaultValueType == VT_DISPATCH)	
            {
                pvarResult->vt= VT_DISPATCH;
                pvarResult->pdispVal= static_cast<IDispatch*>( this);
                AddRef();
                ret= S_OK;
            }
        }
// ---------
        // function: _GetValueObject
        else if( dispidMember == DISPID_JSCRIPT_VALUE_FUNC)
        {
            bHandled= sal_True;
            if( !pvarResult)
                ret= E_POINTER;
            CComObject< JScriptValue>* pValue;
            if( SUCCEEDED( CComObject<JScriptValue>::CreateInstance( &pValue)))
            {
                pValue->AddRef();
                pvarResult->vt= VT_DISPATCH;
#ifdef __MINGW32__
                pvarResult->pdispVal= CComQIPtr<IDispatch, &__uuidof(IDispatch)>(pValue->GetUnknown());
#else
                pvarResult->pdispVal= CComQIPtr<IDispatch>(pValue->GetUnknown());
#endif
                ret= S_OK;
            }
            else
                ret= DISP_E_EXCEPTION;
        }
        else if( dispidMember == DISPID_GET_STRUCT_FUNC)
        {
            bHandled= sal_True;
            sal_Bool bStruct= sal_False;
            
            
            Reference<XInterface> xIntCore=	m_smgr->createInstance( OUString::createFromAscii("com.sun.star.reflection.CoreReflection"));
            Reference<XIdlReflection> xRefl( xIntCore, UNO_QUERY);
            if( xRefl.is() )
            {
                // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
                CComVariant arg;
                if( pdispparams->cArgs == 1 && SUCCEEDED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])) )
                {
                    Reference<XIdlClass> classStruct= xRefl->forName( reinterpret_cast<const sal_Unicode*>(arg.bstrVal));
                    if( classStruct.is())
                    {
                        Any anyStruct;
                        classStruct->createObject( anyStruct);
                        CComVariant var;
                        anyToVariant( &var, anyStruct );
                        
                        if( var.vt == VT_DISPATCH)
                        {
                            VariantCopy( pvarResult, & var);
                            bStruct= sal_True;
                        }
                    }
                }
            }	
            ret= bStruct == sal_True ? S_OK : DISP_E_EXCEPTION;
        }
        else if (dispidMember == DISPID_CREATE_TYPE_FUNC)
        {
            bHandled= sal_True;
            if( !pvarResult)
                ret= E_POINTER;
            // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
            CComVariant arg;
            if( pdispparams->cArgs != 1)
                return DISP_E_BADPARAMCOUNT;
            if (FAILED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])))
                return DISP_E_BADVARTYPE;
                
            //check if the provided name represents a valid type
            Type type;
            if (getType(arg.bstrVal, type) == false)
            {
                writeExcepinfo(pexcepinfo,OUString(
                                   OUSTR("[automation bridge] A UNO type with the name ") +
                                   OUString(reinterpret_cast<const sal_Unicode*>(arg.bstrVal)) + OUSTR(" does not exist!")));
                return DISP_E_EXCEPTION;
            }

            if (createUnoTypeWrapper(arg.bstrVal, pvarResult) == false)
            {
                writeExcepinfo(pexcepinfo,OUSTR("[automation bridge] InterfaceOleWrapper_Impl::InvokeGeneral\n"
                                                "Could not initialize UnoTypeWrapper object!"));
                return DISP_E_EXCEPTION;
            }
        }
    }
    catch(BridgeRuntimeError & e)
    {
        writeExcepinfo(pexcepinfo, e.message);
        ret = DISP_E_EXCEPTION;
    }
    catch(Exception & e)
    {
        OUString message= OUSTR("InterfaceOleWrapper_Impl::InvokeGeneral : \n") +
                                e.Message;
        writeExcepinfo(pexcepinfo, message);
        ret = DISP_E_EXCEPTION;
    }
    catch( ... )
 	{
        OUString message= OUSTR("InterfaceOleWrapper_Impl::InvokeGeneral : \n" 
                                "Unexpected exception");
        writeExcepinfo(pexcepinfo, message);
 		ret = DISP_E_EXCEPTION;
 	}
	return ret;
}




STDMETHODIMP InterfaceOleWrapper_Impl::GetDispID(BSTR /*bstrName*/, DWORD /*grfdex*/, DISPID __RPC_FAR* /*pid*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}

STDMETHODIMP InterfaceOleWrapper_Impl::InvokeEx( 
	/* [in] */ DISPID /*id*/,
	/* [in] */ LCID /*lcid*/,
	/* [in] */ WORD /*wFlags*/,
	/* [in] */ DISPPARAMS __RPC_FAR* /*pdp*/,
	/* [out] */ VARIANT __RPC_FAR* /*pvarRes*/,
	/* [out] */ EXCEPINFO __RPC_FAR* /*pei*/,
	/* [unique][in] */ IServiceProvider __RPC_FAR* /*pspCaller*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}


STDMETHODIMP InterfaceOleWrapper_Impl::DeleteMemberByName( 
    /* [in] */ BSTR /*bstr*/,
    /* [in] */ DWORD /*grfdex*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}

STDMETHODIMP InterfaceOleWrapper_Impl::DeleteMemberByDispID(DISPID /*id*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}

STDMETHODIMP InterfaceOleWrapper_Impl::GetMemberProperties( 
    /* [in] */ DISPID /*id*/,
    /* [in] */ DWORD /*grfdexFetch*/,
    /* [out] */ DWORD __RPC_FAR* /*pgrfdex*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}

STDMETHODIMP InterfaceOleWrapper_Impl::GetMemberName( 
    /* [in] */ DISPID /*id*/,
    /* [out] */ BSTR __RPC_FAR* /*pbstrName*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}

STDMETHODIMP InterfaceOleWrapper_Impl::GetNextDispID( 
    /* [in] */ DWORD /*grfdex*/,
    /* [in] */ DISPID /*id*/,
    /* [out] */ DISPID __RPC_FAR* /*pid*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}

STDMETHODIMP InterfaceOleWrapper_Impl::GetNameSpaceParent( 
    /* [out] */ IUnknown __RPC_FAR *__RPC_FAR* /*ppunk*/)
{
	HRESULT ret = ResultFromScode(E_NOTIMPL);	

	return ret;
}


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

	UnoObjectWrapperRemoteOpt

*************************************************************************/
UnoObjectWrapperRemoteOpt::UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory>& aFactory,
													 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
InterfaceOleWrapper_Impl( aFactory, unoWrapperClass, comWrapperClass),
m_currentId(1)

{
}
UnoObjectWrapperRemoteOpt::~UnoObjectWrapperRemoteOpt()
{
}

// UnoConversionUtilities
Reference< XInterface > UnoObjectWrapperRemoteOpt::createUnoWrapperInstance()
{
	Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
												 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
	return Reference<XInterface>( xWeak, UNO_QUERY);
}

STDMETHODIMP  UnoObjectWrapperRemoteOpt::GetIDsOfNames ( REFIID /*riid*/, OLECHAR ** rgszNames, unsigned int cNames,
								LCID /*lcid*/, DISPID * rgdispid )
{
	MutexGuard guard( getBridgeMutex());

	if( ! rgdispid)
		return E_POINTER;
	HRESULT ret = E_UNEXPECTED;
	// ----------------------------------------
	// _GetValueObject
	if( ! wcscmp( *rgszNames, JSCRIPT_VALUE_FUNC))
	{
		*rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
		return S_OK;
	}
	else if( ! wcscmp( *rgszNames, GET_STRUCT_FUNC))
	{
		*rgdispid= DISPID_GET_STRUCT_FUNC;
		return S_OK;
	}

	// ----------------------------------------
	if (m_xInvocation.is() && (cNames > 0))
	{
		OUString name(reinterpret_cast<const sal_Unicode*>(rgszNames[0]));
		// has this name been determined as "bad"
		BadNameMap::iterator badIter= m_badNameMap.find( name);
		if( badIter == m_badNameMap.end() )
		{
			// name has not been bad before( member exists
			typedef NameToIdMap::iterator ITnames;
			pair< ITnames, bool > pair_id= m_nameToDispIdMap.insert( NameToIdMap::value_type(name, m_currentId++));
			// new ID inserted ?
			if( pair_id.second )
			{// yes, now create MemberInfo and ad to IdToMemberInfoMap
				MemberInfo d(0, name);
				m_idToMemberInfoMap.insert( IdToMemberInfoMap::value_type( m_currentId - 1, d));
			}

			*rgdispid = pair_id.first->second;
			ret = S_OK;
		}
		else
			ret= DISP_E_UNKNOWNNAME;
	}
	return ret;
}

STDMETHODIMP  UnoObjectWrapperRemoteOpt::Invoke ( DISPID dispidMember, REFIID /*riid*/, LCID /*lcid*/, unsigned short wFlags,
	                     DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
	                     unsigned int * puArgErr )
{
	HRESULT ret = S_OK;
    try
    {
        sal_Bool bHandled= sal_False;
        ret= InvokeGeneral( dispidMember,  wFlags, pdispparams, pvarResult,  pexcepinfo,
                            puArgErr, bHandled);
        if( bHandled)
            return ret;
        
        if ( dispidMember > 0  && m_xInvocation.is())
        {
            
            IdToMemberInfoMap::iterator it_MemberInfo= m_idToMemberInfoMap.find( dispidMember);
            if( it_MemberInfo != m_idToMemberInfoMap.end() )
            {
                MemberInfo& info= it_MemberInfo->second;
                
                Sequence<Any> params; // holds converted any s
                if( ! info.flags )
                { // DISPID called for the first time
                    if( wFlags == DISPATCH_METHOD )
                    {					
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
                        
                        if( FAILED( ret= doInvoke( pdispparams, pvarResult, 
                                                   pexcepinfo, puArgErr, info.name, params))
                            && ret == DISP_E_MEMBERNOTFOUND)
                        {
                            // try to get the exact name 
                            OUString exactName;
                            if (m_xExactName.is())
                            {
                                exactName = m_xExactName->getExactName( info.name);
                                // invoke again
                                if( exactName.getLength() != 0)
                                {
                                    if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, 
                                                                  pexcepinfo, puArgErr, exactName, params)))
                                        info.name= exactName;
                                } 
                            }
                        }	
                        if( SUCCEEDED( ret ) )
                            info.flags= DISPATCH_METHOD;
                    } //if( wFlags == DISPATCH_METHOD )
                    
                    else if( wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_PROPERTYPUTREF)
                    {
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
                        if( FAILED( ret= doSetProperty( pdispparams, pvarResult, 
                                                        pexcepinfo, puArgErr, info.name, params))
                            && ret == DISP_E_MEMBERNOTFOUND)
                        {
                            // try to get the exact name 
                            OUString exactName;
                            if (m_xExactName.is())
                            {
                                exactName = m_xExactName->getExactName( info.name);
                                // invoke again
                                if( exactName.getLength() != 0)
                                {
                                    if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, 
                                                                       pexcepinfo, puArgErr, exactName, params)))
                                        info.name= exactName;
                                } 
                            }
                        }	
                        if( SUCCEEDED( ret ) )
                            info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;
                    }
                    
                    else if( wFlags == DISPATCH_PROPERTYGET)
                    {
                        if( FAILED( ret= doGetProperty( pdispparams, pvarResult, 
                                                        pexcepinfo, info.name))
                            && ret == DISP_E_MEMBERNOTFOUND)
                        {
                            // try to get the exact name 
                            OUString exactName;
                            if (m_xExactName.is())
                            {
                                exactName = m_xExactName->getExactName( info.name);
                                // invoke again
                                if( exactName.getLength() != 0)
                                {
                                    if( SUCCEEDED( ret= doGetProperty( pdispparams, pvarResult, 
                                                                       pexcepinfo, exactName)))
                                        info.name= exactName;
                                } 
                            }
                        }	
                        if( SUCCEEDED( ret ) )
                            info.flags= DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT;
                    }
                    else if( wFlags & DISPATCH_METHOD && 
                             (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF))
                    {
                        
                        OUString exactName;
                        // convert params for DISPATCH_METHOD or DISPATCH_PROPERTYPUT
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
                        // try first as method
                        if( FAILED( ret= doInvoke( pdispparams, pvarResult, 
                                                   pexcepinfo, puArgErr, info.name, params))
                            && ret == DISP_E_MEMBERNOTFOUND)
                        {
                            // try to get the exact name 
                            if (m_xExactName.is())
                            {
                                exactName = m_xExactName->getExactName( info.name);
                                // invoke again
                                if( exactName.getLength() != 0)
                                {
                                    if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, 
                                                                  pexcepinfo, puArgErr, exactName, params)))
                                        info.name= exactName;
                                } 
                            }
                        }	
                        if( SUCCEEDED( ret ) )
                            info.flags= DISPATCH_METHOD;
                        
                        // try as property
						if( FAILED( ret) && pdispparams->cArgs == 1)
						{
							if( FAILED( ret= doSetProperty( pdispparams, pvarResult, 
                                                            pexcepinfo, puArgErr, info.name, params))
                                && ret == DISP_E_MEMBERNOTFOUND)
							{
								// try to get the exact name 
								if( exactName.getLength() != 0)
								{
									if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, 
                                                                       pexcepinfo, puArgErr, exactName, params)))
                                        info.name= exactName;
								} 
							}	
							if( SUCCEEDED( ret ) )
								info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;					
						}
                    }
                    else if( wFlags & DISPATCH_METHOD && wFlags & DISPATCH_PROPERTYGET)
                    {
                        OUString exactName;
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
                        
                        if( FAILED( ret= doInvoke( pdispparams, pvarResult, 
                                                   pexcepinfo, puArgErr, info.name, params))
                            && ret == DISP_E_MEMBERNOTFOUND)
                        {
                            // try to get the exact name 
                            if (m_xExactName.is())
                            {
                                exactName = m_xExactName->getExactName( info.name);
                                // invoke again
                                if( exactName.getLength() != 0)
                                {
                                    if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, 
                                                                  pexcepinfo, puArgErr, exactName, params)))
                                        info.name= exactName;
                                } 
                            }
                        }	
                        if( SUCCEEDED( ret ) )
                            info.flags= DISPATCH_METHOD;
                        
                        // try as property
                        if( FAILED( ret) && pdispparams->cArgs == 1)
                        {
                            if( FAILED( ret= doGetProperty( pdispparams, pvarResult, 
                                                            pexcepinfo, info.name))
                                && ret == DISP_E_MEMBERNOTFOUND)
                            {
                                if( exactName.getLength() != 0)
                                {
                                    if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, 
                                                                       pexcepinfo, puArgErr, exactName, params)))
                                        info.name= exactName;
                                } 
                            }	
                            if( SUCCEEDED( ret ) )
                                info.flags= DISPATCH_PROPERTYGET;
                        }
                    }
                    
                    // update ínformation about this member 
                    if( ret == DISP_E_MEMBERNOTFOUND)
                    {
                        // Remember the name as not existing
                        // and remove the MemberInfo
                        m_badNameMap[info.name]= sal_False;
                        m_idToMemberInfoMap.erase( it_MemberInfo);
                    }
                } // if( ! info.flags )
                else // IdToMemberInfoMap contains a MemberInfo
                {
                    if( wFlags & DISPATCH_METHOD && info.flags == DISPATCH_METHOD)
                    {
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
						ret= doInvoke( pdispparams, pvarResult, 
                                       pexcepinfo, puArgErr, info.name, params);
                    }
                    else if( (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF )  &&
                             info.flags & DISPATCH_PROPERTYPUT)
                    {
                        convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
                        ret= doSetProperty( pdispparams, pvarResult, 
                                            pexcepinfo, puArgErr, info.name, params);
                    }
                    else if( (wFlags & DISPATCH_PROPERTYGET) && ( info.flags & DISPATCH_PROPERTYGET))
                    {
                        ret= doGetProperty( pdispparams, pvarResult, 
                                            pexcepinfo, info.name);
                    }
                    else
                    {
                        ret= DISP_E_MEMBERNOTFOUND;
                    }
                }
            }//		if( it_MemberInfo != m_idToMemberInfoMap.end() )
            else
                ret= DISP_E_MEMBERNOTFOUND;
        }
    }
    catch(BridgeRuntimeError& e)
    {
        writeExcepinfo(pexcepinfo, e.message);
        ret = DISP_E_EXCEPTION;
    }
    catch(Exception& e)
    {
        OUString message= OUSTR("UnoObjectWrapperRemoteOpt::Invoke : \n") +
            e.Message;
            writeExcepinfo(pexcepinfo, message);
            ret = DISP_E_EXCEPTION;
    }
    catch(...)
    {
        OUString message= OUSTR("UnoObjectWrapperRemoteOpt::Invoke : \n" 
                                "Unexpected exception");
        writeExcepinfo(pexcepinfo, message);
        ret = DISP_E_EXCEPTION;
    }
    
    return ret;
}

HRESULT	UnoObjectWrapperRemoteOpt::methodInvoke( DISPID /*dispidMember*/, DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/, 
							  EXCEPINFO * /*pexcepinfo*/, unsigned int * /*puArgErr*/, Sequence<Any> params)
{
	return S_OK;
}


// The returned HRESULT is only appropriate for IDispatch::Invoke
static HRESULT mapCannotConvertException( CannotConvertException e, unsigned int * puArgErr)
{
	HRESULT ret;
	sal_Bool bWriteIndex= sal_True;

	switch ( e.Reason)
	{
		case FailReason::OUT_OF_RANGE:
			ret = DISP_E_OVERFLOW;
			break;
		case FailReason::IS_NOT_NUMBER:
			ret = DISP_E_TYPEMISMATCH;
			break;
		case FailReason::IS_NOT_ENUM:
			ret = DISP_E_TYPEMISMATCH;
			break;
		case FailReason::IS_NOT_BOOL:
			ret = DISP_E_TYPEMISMATCH;
			break;
		case FailReason::NO_SUCH_INTERFACE:
			ret = DISP_E_TYPEMISMATCH;
			break;
		case FailReason::SOURCE_IS_NO_DERIVED_TYPE:
			ret = DISP_E_TYPEMISMATCH;
			break;
		case FailReason::TYPE_NOT_SUPPORTED:
			ret = DISP_E_TYPEMISMATCH;
			break;
		case FailReason::INVALID:
			ret = DISP_E_TYPEMISMATCH;
			break;
		case FailReason::NO_DEFAULT_AVAILABLE:
			ret = DISP_E_BADPARAMCOUNT;
			break;
		case FailReason::UNKNOWN:
			ret = E_UNEXPECTED;
			break;
		default:
			ret = E_UNEXPECTED;
			bWriteIndex= sal_False;
			break;
	}

	if( bWriteIndex &&  puArgErr != NULL)
		*puArgErr = e.ArgumentIndex;
	return ret;
}

// The function maps the TypeClass of the any to VARTYPE: If 
// the Any contains STRUCT or INTERFACE then the return value
// is VT_DISPATCH. The function is used from o2u_createUnoObjectWrapper
// and the result is put into the constructor of the uno - wrapper
// object. If a client asks the object for DISPID_VALUE and this
// funtion returned VT_DISPATCH then the IDispatch of the same 
// object is being returned.
// See InterfaceOleWrapper_Impl::Invoke, InterfaceOleWrapper_Impl::m_defaultValueType
const VARTYPE getVarType( const Any& value)
{
	VARTYPE ret= VT_EMPTY;

	switch ( value.getValueTypeClass())
	{
	case TypeClass_STRUCT: ret= VT_DISPATCH; break;
	case TypeClass_INTERFACE: ret= VT_DISPATCH; break;
	default: break;
	}
	return ret;
}




} // end namespace
