1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include "ole2uno.hxx" 21 #include <rtl/ustrbuf.hxx> 22 #include <sal/log.hxx> 23 #include <o3tl/char16_t2wchar_t.hxx> 24 25 #include <osl/diagnose.h> 26 #include <osl/doublecheckedlocking.h> 27 #include <osl/thread.h> 28 29 #include <memory> 30 #include <com/sun/star/script/CannotConvertException.hpp> 31 #include <com/sun/star/script/FailReason.hpp> 32 #include <com/sun/star/beans/XMaterialHolder.hpp> 33 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 34 #include <com/sun/star/script/XInvocation.hpp> 35 #include <com/sun/star/bridge/ModelDependent.hpp> 36 37 #include <com/sun/star/bridge/oleautomation/NamedArgument.hpp> 38 #include <com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp> 39 #include <cppuhelper/exc_hlp.hxx> 40 41 #include <typelib/typedescription.hxx> 42 #include <rtl/uuid.h> 43 #include <rtl/ustring.hxx> 44 45 #include "jscriptclasses.hxx" 46 47 #include "oleobjw.hxx" 48 #include "unoobjw.hxx" 49 #include <stdio.h> 50 using namespace std; 51 using namespace osl; 52 using namespace cppu; 53 using namespace com::sun::star::script; 54 using namespace com::sun::star::lang; 55 using namespace com::sun::star::bridge; 56 using namespace com::sun::star::bridge::oleautomation; 57 using namespace com::sun::star::bridge::ModelDependent; 58 using namespace ::com::sun::star; 59 60 61 #define JSCRIPT_ID_PROPERTY L"_environment" 62 #define JSCRIPT_ID L"jscript" 63 64 // key: XInterface pointer created by Invocation Adapter Factory 65 // value: XInterface pointer to the wrapper class. 66 // Entries to the map are made within 67 // Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType); 68 // Entries are being deleted if the wrapper class's destructor has been 69 // called. 70 // Before UNO object is wrapped to COM object this map is checked 71 // to see if the UNO object is already a wrapper. 72 std::unordered_map<sal_uIntPtr, sal_uIntPtr> AdapterToWrapperMap; 73 // key: XInterface of the wrapper object. 74 // value: XInterface of the Interface created by the Invocation Adapter Factory. 75 // A COM wrapper is responsible for removing the corresponding entry 76 // in AdapterToWrapperMap if it is being destroyed. Because the wrapper does not 77 // know about its adapted interface it uses WrapperToAdapterMap to get the 78 // adapted interface which is then used to locate the entry in AdapterToWrapperMap. 79 std::unordered_map<sal_uIntPtr,sal_uIntPtr> WrapperToAdapterMap; 80 81 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap; 82 83 IUnknownWrapper::IUnknownWrapper( Reference<XMultiServiceFactory> const & xFactory, 84 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): 85 UnoConversionUtilities<IUnknownWrapper>( xFactory, unoWrapperClass, comWrapperClass), 86 m_pxIdlClass( nullptr), m_eJScript( JScriptUndefined), 87 m_bComTlbIndexInit(false), m_bHasDfltMethod(false), m_bHasDfltProperty(false) 88 { 89 } 90 91 92 IUnknownWrapper::~IUnknownWrapper() 93 { 94 o2u_attachCurrentThread(); 95 MutexGuard guard(getBridgeMutex()); 96 XInterface * xIntRoot = static_cast<OWeakObject *>(this); 97 #if OSL_DEBUG_LEVEL > 0 98 acquire(); // make sure we don't delete us twice because of Reference 99 OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot ); 100 #endif 101 102 // remove entries in global maps 103 auto it= WrapperToAdapterMap.find( reinterpret_cast<sal_uIntPtr>(xIntRoot)); 104 if( it != WrapperToAdapterMap.end()) 105 { 106 sal_uIntPtr adapter= it->second; 107 108 AdapterToWrapperMap.erase( adapter); 109 WrapperToAdapterMap.erase( it); 110 } 111 112 auto it_c= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_spUnknown.p)); 113 if(it_c != ComPtrToWrapperMap.end()) 114 ComPtrToWrapperMap.erase(it_c); 115 } 116 117 Any IUnknownWrapper::queryInterface(const Type& t) 118 { 119 if (t == cppu::UnoType<XDefaultMethod>::get() && !m_bHasDfltMethod ) 120 return Any(); 121 if (t == cppu::UnoType<XDefaultProperty>::get() && !m_bHasDfltProperty ) 122 return Any(); 123 if ( ( t == cppu::UnoType<XInvocation>::get() || t == cppu::UnoType<XAutomationInvocation>::get() ) && !m_spDispatch) 124 return Any(); 125 // XDirectInvocation seems to be an oracle replacement for XAutomationInvocation, however it is flawed especially wrt. assumptions about whether to invoke a 126 // Put or Get property, the implementation code has no business guessing that, it's up to the caller to decide that. Worse XDirectInvocation duplicates lots of code. 127 // XAutomationInvocation provides separate calls for put& get 128 // properties. Note: Currently the basic runtime doesn't call put properties directly, it should... after all the basic runtime should know whether it is calling a put or get property. 129 // For the moment for ease of merging we will let the XDirectInvoke and XAuthomationInvocation interfaces stay side by side (and for the moment at least I would prefer the basic 130 // runtime to call XAutomationInvocation instead of XDirectInvoke 131 return WeakImplHelper<XBridgeSupplier2, 132 XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation, XAutomationInvocation >::queryInterface(t); 133 } 134 135 Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper::getIntrospection() 136 { 137 Reference<XIntrospectionAccess> ret; 138 139 return ret; 140 } 141 142 Any SAL_CALL IUnknownWrapper::invokeGetProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) 143 { 144 Any aResult; 145 try 146 { 147 o2u_attachCurrentThread(); 148 ITypeInfo * pInfo = getTypeInfo(); 149 FuncDesc aDescGet(pInfo); 150 FuncDesc aDescPut(pInfo); 151 VarDesc aVarDesc(pInfo); 152 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); 153 if ( !aDescGet ) 154 { 155 OUString msg("[automation bridge]Property \"" + aPropertyName + 156 "\" is not supported"); 157 throw UnknownPropertyException(msg); 158 } 159 aResult = invokeWithDispIdComTlb( aDescGet, aPropertyName, aParams, aOutParamIndex, aOutParam ); 160 } 161 catch ( const Exception& e ) 162 { 163 css::uno::Any anyEx = cppu::getCaughtException(); 164 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " 165 "IUnknownWrapper::invokeGetProperty ! Message : \n " + 166 e.Message, 167 nullptr, anyEx ); 168 } 169 return aResult; 170 } 171 172 Any SAL_CALL IUnknownWrapper::invokePutProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) 173 { 174 Any aResult; 175 try 176 { 177 o2u_attachCurrentThread(); 178 ITypeInfo * pInfo = getTypeInfo(); 179 FuncDesc aDescGet(pInfo); 180 FuncDesc aDescPut(pInfo); 181 VarDesc aVarDesc(pInfo); 182 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); 183 if ( !aDescPut ) 184 { 185 OUString msg("[automation bridge]Property \"" + aPropertyName + 186 "\" is not supported"); 187 throw UnknownPropertyException(msg); 188 } 189 aResult = invokeWithDispIdComTlb( aDescPut, aPropertyName, aParams, aOutParamIndex, aOutParam ); 190 } 191 catch ( const Exception& e ) 192 { 193 css::uno::Any anyEx = cppu::getCaughtException(); 194 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " 195 "IUnknownWrapper::invokePutProperty ! Message : \n" + 196 e.Message, 197 nullptr, anyEx ); 198 } 199 return aResult; 200 } 201 202 203 Any SAL_CALL IUnknownWrapper::invoke( const OUString& aFunctionName, 204 const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, 205 Sequence< Any >& aOutParam ) 206 { 207 if ( ! m_spDispatch ) 208 { 209 throw RuntimeException( 210 "[automation bridge] The object does not have an IDispatch interface"); 211 } 212 213 Any ret; 214 215 try 216 { 217 o2u_attachCurrentThread(); 218 219 TypeDescription methodDesc; 220 getMethodInfo(aFunctionName, methodDesc); 221 if( methodDesc.is()) 222 { 223 ret = invokeWithDispIdUnoTlb(aFunctionName, 224 aParams, 225 aOutParamIndex, 226 aOutParam); 227 } 228 else 229 { 230 ret= invokeWithDispIdComTlb( aFunctionName, 231 aParams, 232 aOutParamIndex, 233 aOutParam); 234 } 235 } 236 catch (const IllegalArgumentException &) 237 { 238 throw; 239 } 240 catch (const CannotConvertException &) 241 { 242 throw; 243 } 244 catch (const BridgeRuntimeError & e) 245 { 246 throw RuntimeException(e.message); 247 } 248 catch (const Exception & e) 249 { 250 css::uno::Any anyEx = cppu::getCaughtException(); 251 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " 252 "IUnknownWrapper::invoke ! Message : \n" + 253 e.Message, 254 nullptr, anyEx ); 255 256 } 257 catch(...) 258 { 259 throw RuntimeException("[automation bridge] unexpected exception in " 260 "IUnknownWrapper::Invoke !"); 261 } 262 return ret; 263 } 264 265 void SAL_CALL IUnknownWrapper::setValue( const OUString& aPropertyName, 266 const Any& aValue ) 267 { 268 if ( ! m_spDispatch ) 269 { 270 throw RuntimeException( 271 "[automation bridge] The object does not have an IDispatch interface"); 272 } 273 try 274 { 275 o2u_attachCurrentThread(); 276 277 ITypeInfo * pInfo = getTypeInfo(); 278 FuncDesc aDescGet(pInfo); 279 FuncDesc aDescPut(pInfo); 280 VarDesc aVarDesc(pInfo); 281 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); 282 //check if there is such a property at all or if it is read only 283 if ( ! aDescPut && ! aDescGet && ! aVarDesc) 284 { 285 OUString msg("[automation bridge]Property \"" + aPropertyName + 286 "\" is not supported"); 287 throw UnknownPropertyException(msg); 288 } 289 290 if ( (! aDescPut && aDescGet) 291 || (aVarDesc && aVarDesc->wVarFlags == VARFLAG_FREADONLY) ) 292 { 293 //read-only 294 SAL_WARN( "extensions.olebridge", "[automation bridge] Property " << aPropertyName << " is read-only"); 295 // ignore silently 296 return; 297 } 298 299 HRESULT hr= S_OK; 300 DISPPARAMS dispparams; 301 CComVariant varArg; 302 CComVariant varRefArg; 303 CComVariant varResult; 304 ExcepInfo excepinfo; 305 unsigned int uArgErr; 306 307 // converting UNO value to OLE variant 308 DISPID dispidPut= DISPID_PROPERTYPUT; 309 dispparams.rgdispidNamedArgs = &dispidPut; 310 dispparams.cArgs = 1; 311 dispparams.cNamedArgs = 1; 312 dispparams.rgvarg = & varArg; 313 314 OSL_ASSERT(aDescPut || aVarDesc); 315 316 VARTYPE vt = 0; 317 DISPID dispid = 0; 318 INVOKEKIND invkind = INVOKE_PROPERTYPUT; 319 //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT, 320 //DISPATCH_PROPERTYPUTREF) 321 if (aDescPut) 322 { 323 vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc); 324 dispid = aDescPut->memid; 325 invkind = aDescPut->invkind; 326 } 327 else 328 { 329 vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc); 330 dispid = aVarDesc->memid; 331 if (vt == VT_UNKNOWN || vt == VT_DISPATCH || 332 (vt & VT_ARRAY) || (vt & VT_BYREF)) 333 { 334 invkind = INVOKE_PROPERTYPUTREF; 335 } 336 } 337 338 // convert the uno argument 339 if (vt & VT_BYREF) 340 { 341 anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) ); 342 varArg.vt = vt; 343 if( (vt & VT_TYPEMASK) == VT_VARIANT) 344 varArg.byref = & varRefArg; 345 else if ((vt & VT_TYPEMASK) == VT_DECIMAL) 346 varArg.byref = & varRefArg.decVal; 347 else 348 varArg.byref = & varRefArg.byref; 349 } 350 else 351 { 352 anyToVariant(& varArg, aValue, vt); 353 } 354 // call to IDispatch 355 hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ), 356 &dispparams, & varResult, & excepinfo, &uArgErr); 357 358 // lookup error code 359 switch (hr) 360 { 361 case S_OK: 362 break; 363 case DISP_E_BADPARAMCOUNT: 364 throw RuntimeException(); 365 break; 366 case DISP_E_BADVARTYPE: 367 throw RuntimeException(); 368 break; 369 case DISP_E_EXCEPTION: 370 throw InvocationTargetException(); 371 break; 372 case DISP_E_MEMBERNOTFOUND: 373 throw UnknownPropertyException(); 374 break; 375 case DISP_E_NONAMEDARGS: 376 throw RuntimeException(); 377 break; 378 case DISP_E_OVERFLOW: 379 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>( 380 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); 381 break; 382 case DISP_E_PARAMNOTFOUND: 383 throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>( 384 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ; 385 break; 386 case DISP_E_TYPEMISMATCH: 387 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>( 388 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 389 break; 390 case DISP_E_UNKNOWNINTERFACE: 391 throw RuntimeException(); 392 break; 393 case DISP_E_UNKNOWNLCID: 394 throw RuntimeException(); 395 break; 396 case DISP_E_PARAMNOTOPTIONAL: 397 throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>( 398 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); 399 break; 400 default: 401 throw RuntimeException(); 402 break; 403 } 404 } 405 catch (const CannotConvertException &) 406 { 407 throw; 408 } 409 catch (const UnknownPropertyException &) 410 { 411 throw; 412 } 413 catch (const BridgeRuntimeError& e) 414 { 415 throw RuntimeException(e.message); 416 } 417 catch (const Exception & e) 418 { 419 css::uno::Any anyEx = cppu::getCaughtException(); 420 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " 421 "IUnknownWrapper::setValue ! Message : \n" + 422 e.Message, 423 nullptr, anyEx ); 424 425 } 426 catch (...) 427 { 428 throw RuntimeException( 429 "[automation bridge] unexpected exception in " 430 "IUnknownWrapper::setValue !"); 431 } 432 } 433 434 Any SAL_CALL IUnknownWrapper::getValue( const OUString& aPropertyName ) 435 { 436 if ( ! m_spDispatch ) 437 { 438 throw RuntimeException( 439 "[automation bridge] The object does not have an IDispatch interface"); 440 } 441 Any ret; 442 try 443 { 444 o2u_attachCurrentThread(); 445 ITypeInfo * pInfo = getTypeInfo(); 446 // I was going to implement an XServiceInfo interface to allow the type 447 // of the automation object to be exposed.. but it seems 448 // from looking at comments in the code that it is possible for 449 // this object to actually wrap an UNO object ( I guess if automation is 450 // used from MSO to create Openoffice objects ) Therefore, those objects 451 // will more than likely already have their own XServiceInfo interface. 452 // Instead here I chose a name that should be illegal both in COM and 453 // UNO ( from an IDL point of view ) therefore I think this is a safe 454 // hack 455 if ( aPropertyName == "$GetTypeName" ) 456 { 457 if ( pInfo && m_sTypeName.getLength() == 0 ) 458 { 459 m_sTypeName = "IDispatch"; 460 CComBSTR sName; 461 462 if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) ) 463 { 464 OUString sTmp( o3tl::toU(LPCOLESTR(sName))); 465 if ( sTmp.startsWith("_") ) 466 sTmp = sTmp.copy(1); 467 // do we own the memory for pTypeLib, msdn doc is vague 468 // I'll assume we do 469 CComPtr< ITypeLib > pTypeLib; 470 unsigned int index; 471 if ( SUCCEEDED( pInfo->GetContainingTypeLib( &pTypeLib.p, &index )) ) 472 { 473 if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) ) 474 { 475 OUString sLibName( o3tl::toU(LPCOLESTR(sName))); 476 m_sTypeName = sLibName.concat( "." ).concat( sTmp ); 477 478 } 479 } 480 } 481 482 } 483 ret <<= m_sTypeName; 484 return ret; 485 } 486 FuncDesc aDescGet(pInfo); 487 FuncDesc aDescPut(pInfo); 488 VarDesc aVarDesc(pInfo); 489 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); 490 if ( ! aDescGet && ! aDescPut && ! aVarDesc) 491 { 492 //property not found 493 OUString msg("[automation bridge]Property \"" + aPropertyName + 494 "\" is not supported"); 495 throw UnknownPropertyException(msg); 496 } 497 // write-only should not be possible 498 OSL_ASSERT( aDescGet || ! aDescPut); 499 500 HRESULT hr; 501 DISPPARAMS dispparams = {nullptr, nullptr, 0, 0}; 502 CComVariant varResult; 503 ExcepInfo excepinfo; 504 unsigned int uArgErr; 505 DISPID dispid; 506 if (aDescGet) 507 dispid = aDescGet->memid; 508 else if (aVarDesc) 509 dispid = aVarDesc->memid; 510 else 511 dispid = aDescPut->memid; 512 513 hr = m_spDispatch->Invoke(dispid, 514 IID_NULL, 515 LOCALE_USER_DEFAULT, 516 DISPATCH_PROPERTYGET, 517 &dispparams, 518 &varResult, 519 &excepinfo, 520 &uArgErr); 521 522 // converting return value and out parameter back to UNO 523 if (hr == S_OK) 524 { 525 // If the com object implements uno interfaces then we have 526 // to convert the attribute into the expected type. 527 TypeDescription attrInfo; 528 getAttributeInfo(aPropertyName, attrInfo); 529 if( attrInfo.is() ) 530 variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef)); 531 else 532 variantToAny(&varResult, ret); 533 } 534 535 // lookup error code 536 switch (hr) 537 { 538 case S_OK: 539 break; 540 case DISP_E_BADPARAMCOUNT: 541 case DISP_E_BADVARTYPE: 542 case DISP_E_EXCEPTION: 543 throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription))); 544 break; 545 case DISP_E_MEMBERNOTFOUND: 546 throw UnknownPropertyException(OUString(o3tl::toU(excepinfo.bstrDescription))); 547 break; 548 default: 549 throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription))); 550 break; 551 } 552 } 553 catch ( const UnknownPropertyException& ) 554 { 555 throw; 556 } 557 catch (const BridgeRuntimeError& e) 558 { 559 throw RuntimeException(e.message); 560 } 561 catch (const Exception & e) 562 { 563 css::uno::Any anyEx = cppu::getCaughtException(); 564 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " 565 "IUnknownWrapper::getValue ! Message : \n" + 566 e.Message, 567 nullptr, anyEx ); 568 } 569 catch (...) 570 { 571 throw RuntimeException( 572 "[automation bridge] unexpected exception in " 573 "IUnknownWrapper::getValue !"); 574 } 575 return ret; 576 } 577 578 sal_Bool SAL_CALL IUnknownWrapper::hasMethod( const OUString& aName ) 579 { 580 if ( ! m_spDispatch ) 581 { 582 throw RuntimeException( 583 "[automation bridge] The object does not have an IDispatch interface"); 584 } 585 bool ret = false; 586 587 try 588 { 589 o2u_attachCurrentThread(); 590 ITypeInfo* pInfo = getTypeInfo(); 591 FuncDesc aDesc(pInfo); 592 getFuncDesc(aName, & aDesc); 593 // Automation properties can have arguments. Those are treated as methods and 594 //are called through XInvocation::invoke. 595 if ( ! aDesc) 596 { 597 FuncDesc aDescGet(pInfo); 598 FuncDesc aDescPut(pInfo); 599 VarDesc aVarDesc(pInfo); 600 getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc); 601 if ((aDescGet && aDescGet->cParams > 0) 602 || (aDescPut && aDescPut->cParams > 0)) 603 ret = true; 604 } 605 else 606 ret = true; 607 } 608 catch (const BridgeRuntimeError& e) 609 { 610 throw RuntimeException(e.message); 611 } 612 catch (const Exception & e) 613 { 614 css::uno::Any anyEx = cppu::getCaughtException(); 615 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " 616 "IUnknownWrapper::hasMethod ! Message : \n" + 617 e.Message, 618 nullptr, anyEx ); 619 } 620 catch (...) 621 { 622 throw RuntimeException("[automation bridge] unexpected exception in " 623 "IUnknownWrapper::hasMethod !"); 624 } 625 return ret; 626 } 627 628 sal_Bool SAL_CALL IUnknownWrapper::hasProperty( const OUString& aName ) 629 { 630 if ( ! m_spDispatch ) 631 { 632 throw RuntimeException("[automation bridge] The object does not have an " 633 "IDispatch interface"); 634 } 635 bool ret = false; 636 try 637 { 638 o2u_attachCurrentThread(); 639 640 ITypeInfo * pInfo = getTypeInfo(); 641 FuncDesc aDescGet(pInfo); 642 FuncDesc aDescPut(pInfo); 643 VarDesc aVarDesc(pInfo); 644 getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc); 645 646 // we should probably just check the func kind 647 // basic has been modified to handle properties ( 'get' ) props at 648 // least with parameters 649 // additionally you can call invoke(Get|Set)Property on the bridge 650 // you can determine if a property has parameter is hasMethod 651 // returns true for the name 652 if (aVarDesc 653 || aDescPut 654 || aDescGet ) 655 { 656 ret = true; 657 } 658 } 659 catch (const BridgeRuntimeError& e) 660 { 661 throw RuntimeException(e.message); 662 } 663 catch (const Exception & e) 664 { 665 css::uno::Any anyEx = cppu::getCaughtException(); 666 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " 667 "IUnknownWrapper::hasProperty ! Message : \n" + 668 e.Message, 669 nullptr, anyEx ); 670 671 } 672 catch (...) 673 { 674 throw RuntimeException("[automation bridge] unexpected exception in " 675 "IUnknownWrapper::hasProperty !"); 676 } 677 return ret; 678 } 679 680 Any SAL_CALL IUnknownWrapper::createBridge( const Any& modelDepObject, 681 const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType, 682 sal_Int16 destModelType ) 683 { 684 Any ret; 685 o2u_attachCurrentThread(); 686 687 if ( 688 (sourceModelType == UNO) && 689 (destModelType == OLE) && 690 (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE) 691 ) 692 { 693 Reference<XInterface> xInt( *static_cast<XInterface* const *>(modelDepObject.getValue())); 694 Reference<XInterface> xSelf( static_cast<OWeakObject*>(this)); 695 696 if (xInt == xSelf) 697 { 698 VARIANT* pVariant = static_cast<VARIANT*>(CoTaskMemAlloc(sizeof(VARIANT))); 699 700 VariantInit(pVariant); 701 if (m_bOriginalDispatch) 702 { 703 pVariant->vt = VT_DISPATCH; 704 pVariant->pdispVal = m_spDispatch; 705 pVariant->pdispVal->AddRef(); 706 } 707 else 708 { 709 pVariant->vt = VT_UNKNOWN; 710 pVariant->punkVal = m_spUnknown; 711 pVariant->punkVal->AddRef(); 712 } 713 714 ret.setValue(static_cast<void*>(&pVariant), cppu::UnoType<sal_uIntPtr>::get()); 715 } 716 } 717 718 return ret; 719 } 720 /** @internal 721 @exception IllegalArgumentException 722 @exception CannotConvertException 723 @exception InvocationTargetException 724 @RuntimeException 725 */ 726 Any IUnknownWrapper::invokeWithDispIdUnoTlb(const OUString& sFunctionName, 727 const Sequence< Any >& Params, 728 Sequence< sal_Int16 >& OutParamIndex, 729 Sequence< Any >& OutParam) 730 { 731 Any ret; 732 HRESULT hr= S_OK; 733 734 sal_Int32 parameterCount= Params.getLength(); 735 sal_Int32 outParameterCount= 0; 736 typelib_InterfaceMethodTypeDescription* pMethod= nullptr; 737 TypeDescription methodDesc; 738 getMethodInfo(sFunctionName, methodDesc); 739 740 // We need to know whether the IDispatch is from a JScript object. 741 // Then out and in/out parameters have to be treated differently than 742 // with common COM objects. 743 bool bJScriptObject= isJScriptObject(); 744 std::unique_ptr<CComVariant[]> sarParams; 745 std::unique_ptr<CComVariant[]> sarParamsRef; 746 CComVariant *pVarParams= nullptr; 747 CComVariant *pVarParamsRef= nullptr; 748 bool bConvRet= true; 749 750 if( methodDesc.is()) 751 { 752 pMethod = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(methodDesc.get()); 753 parameterCount = pMethod->nParams; 754 // Create the Array for the array being passed in DISPPARAMS 755 // the array also contains the outparameter (but not the values) 756 if( pMethod->nParams > 0) 757 { 758 sarParams.reset(new CComVariant[ parameterCount]); 759 pVarParams = sarParams.get(); 760 } 761 762 // Create the Array for the out an in/out parameter. These values 763 // are referenced by the VT_BYREF VARIANTs in DISPPARAMS. 764 // We need to find out the number of out and in/out parameter. 765 for( sal_Int32 i=0; i < parameterCount; i++) 766 { 767 if( pMethod->pParams[i].bOut) 768 outParameterCount++; 769 } 770 771 if( !bJScriptObject) 772 { 773 sarParamsRef.reset(new CComVariant[outParameterCount]); 774 pVarParamsRef = sarParamsRef.get(); 775 // build up the parameters for IDispatch::Invoke 776 sal_Int32 outParamIndex=0; 777 int i = 0; 778 try 779 { 780 for( i= 0; i < parameterCount; i++) 781 { 782 // In parameter 783 if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut) 784 { 785 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); 786 } 787 // Out parameter + in/out parameter 788 else if( pMethod->pParams[i].bOut ) 789 { 790 CComVariant var; 791 if(pMethod->pParams[i].bIn) 792 { 793 anyToVariant( & var,Params[i]); 794 pVarParamsRef[outParamIndex] = var; 795 } 796 797 switch( pMethod->pParams[i].pTypeRef->eTypeClass) 798 { 799 case typelib_TypeClass_INTERFACE: 800 case typelib_TypeClass_STRUCT: 801 if( ! pMethod->pParams[i].bIn) 802 { 803 pVarParamsRef[ outParamIndex].vt= VT_DISPATCH; 804 pVarParamsRef[ outParamIndex].pdispVal= nullptr; 805 } 806 pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF; 807 pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal; 808 break; 809 case typelib_TypeClass_ENUM: 810 case typelib_TypeClass_LONG: 811 case typelib_TypeClass_UNSIGNED_LONG: 812 if( ! pMethod->pParams[i].bIn) 813 { 814 pVarParamsRef[ outParamIndex].vt = VT_I4; 815 pVarParamsRef[ outParamIndex].lVal = 0; 816 } 817 pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF; 818 pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal; 819 break; 820 case typelib_TypeClass_SEQUENCE: 821 if( ! pMethod->pParams[i].bIn) 822 { 823 pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT; 824 pVarParamsRef[ outParamIndex].parray= nullptr; 825 } 826 pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT; 827 pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray; 828 break; 829 case typelib_TypeClass_ANY: 830 if( ! pMethod->pParams[i].bIn) 831 { 832 pVarParamsRef[ outParamIndex].vt = VT_EMPTY; 833 pVarParamsRef[ outParamIndex].lVal = 0; 834 } 835 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; 836 pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex]; 837 break; 838 case typelib_TypeClass_BOOLEAN: 839 if( ! pMethod->pParams[i].bIn) 840 { 841 pVarParamsRef[ outParamIndex].vt = VT_BOOL; 842 pVarParamsRef[ outParamIndex].boolVal = 0; 843 } 844 pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF; 845 pVarParams[parameterCount - i -1].pboolVal = 846 & pVarParamsRef[outParamIndex].boolVal; 847 break; 848 849 case typelib_TypeClass_STRING: 850 if( ! pMethod->pParams[i].bIn) 851 { 852 pVarParamsRef[ outParamIndex].vt = VT_BSTR; 853 pVarParamsRef[ outParamIndex].bstrVal= nullptr; 854 } 855 pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF; 856 pVarParams[parameterCount - i -1].pbstrVal= 857 & pVarParamsRef[outParamIndex].bstrVal; 858 break; 859 860 case typelib_TypeClass_FLOAT: 861 if( ! pMethod->pParams[i].bIn) 862 { 863 pVarParamsRef[ outParamIndex].vt = VT_R4; 864 pVarParamsRef[ outParamIndex].fltVal= 0; 865 } 866 pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF; 867 pVarParams[parameterCount - i -1].pfltVal = 868 & pVarParamsRef[outParamIndex].fltVal; 869 break; 870 case typelib_TypeClass_DOUBLE: 871 if( ! pMethod->pParams[i].bIn) 872 { 873 pVarParamsRef[ outParamIndex].vt = VT_R8; 874 pVarParamsRef[ outParamIndex].dblVal= 0; 875 } 876 pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF; 877 pVarParams[parameterCount - i -1].pdblVal= 878 & pVarParamsRef[outParamIndex].dblVal; 879 break; 880 case typelib_TypeClass_BYTE: 881 if( ! pMethod->pParams[i].bIn) 882 { 883 pVarParamsRef[ outParamIndex].vt = VT_UI1; 884 pVarParamsRef[ outParamIndex].bVal= 0; 885 } 886 pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF; 887 pVarParams[parameterCount - i -1].pbVal= 888 & pVarParamsRef[outParamIndex].bVal; 889 break; 890 case typelib_TypeClass_CHAR: 891 case typelib_TypeClass_SHORT: 892 case typelib_TypeClass_UNSIGNED_SHORT: 893 if( ! pMethod->pParams[i].bIn) 894 { 895 pVarParamsRef[ outParamIndex].vt = VT_I2; 896 pVarParamsRef[ outParamIndex].iVal = 0; 897 } 898 pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF; 899 pVarParams[parameterCount - i -1].piVal= 900 & pVarParamsRef[outParamIndex].iVal; 901 break; 902 903 default: 904 if( ! pMethod->pParams[i].bIn) 905 { 906 pVarParamsRef[ outParamIndex].vt = VT_EMPTY; 907 pVarParamsRef[ outParamIndex].lVal = 0; 908 } 909 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; 910 pVarParams[parameterCount - i -1].pvarVal = 911 & pVarParamsRef[outParamIndex]; 912 } 913 outParamIndex++; 914 } // end else if 915 } // end for 916 } 917 catch (IllegalArgumentException & e) 918 { 919 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); 920 throw; 921 } 922 catch (CannotConvertException & e) 923 { 924 e.ArgumentIndex = i; 925 throw; 926 } 927 } 928 else // it is an JScriptObject 929 { 930 int i = 0; 931 try 932 { 933 for( ; i< parameterCount; i++) 934 { 935 // In parameter 936 if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut) 937 { 938 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); 939 } 940 // Out parameter + in/out parameter 941 else if( pMethod->pParams[i].bOut ) 942 { 943 CComObject<JScriptOutParam>* pParamObject; 944 if( !SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject))) 945 { 946 throw BridgeRuntimeError( 947 "[automation bridge]IUnknownWrapper::" 948 "invokeWithDispIdUnoTlb\n" 949 "Could not create out parameter at index: " + 950 OUString::number(static_cast<sal_Int32>(i))); 951 } 952 953 CComPtr<IUnknown> pUnk(pParamObject->GetUnknown()); 954 CComQIPtr<IDispatch> pDisp( pUnk); 955 956 pVarParams[ parameterCount - i -1].vt= VT_DISPATCH; 957 pVarParams[ parameterCount - i -1].pdispVal= pDisp; 958 pVarParams[ parameterCount - i -1].pdispVal->AddRef(); 959 // if the param is in/out then put the parameter on index 0 960 if( pMethod->pParams[i].bIn ) // in / out 961 { 962 CComVariant varParam; 963 anyToVariant( &varParam, Params.getConstArray()[i]); 964 CComDispatchDriver dispDriver( pDisp); 965 if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam))) 966 throw BridgeRuntimeError( 967 "[automation bridge]IUnknownWrapper::" 968 "invokeWithDispIdUnoTlb\n" 969 "Could not set property \"0\" for the in/out " 970 "param!"); 971 972 } 973 } 974 } 975 } 976 catch (IllegalArgumentException & e) 977 { 978 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); 979 throw; 980 } 981 catch (CannotConvertException & e) 982 { 983 e.ArgumentIndex = i; 984 throw; 985 } 986 } 987 } 988 // No type description Available, that is we have to deal with a COM component, 989 // that does not implements UNO interfaces ( IDispatch based) 990 else 991 { 992 //We should not run into this block, because invokeWithDispIdComTlb should 993 //have been called instead. 994 OSL_ASSERT(false); 995 } 996 997 998 CComVariant varResult; 999 ExcepInfo excepinfo; 1000 unsigned int uArgErr; 1001 DISPPARAMS dispparams= { pVarParams, nullptr, static_cast<UINT>(parameterCount), 0}; 1002 1003 // Get the DISPID 1004 FuncDesc aDesc(getTypeInfo()); 1005 getFuncDesc(sFunctionName, & aDesc); 1006 // invoking OLE method 1007 hr = m_spDispatch->Invoke(aDesc->memid, 1008 IID_NULL, 1009 LOCALE_USER_DEFAULT, 1010 DISPATCH_METHOD, 1011 &dispparams, 1012 &varResult, 1013 &excepinfo, 1014 &uArgErr); 1015 1016 // converting return value and out parameter back to UNO 1017 if (hr == S_OK) 1018 { 1019 if( outParameterCount && pMethod) 1020 { 1021 OutParamIndex.realloc( outParameterCount); 1022 OutParam.realloc( outParameterCount); 1023 sal_Int32 outIndex=0; 1024 int i = 0; 1025 try 1026 { 1027 for( ; i < parameterCount; i++) 1028 { 1029 if( pMethod->pParams[i].bOut ) 1030 { 1031 OutParamIndex[outIndex]= static_cast<sal_Int16>(i); 1032 Any outAny; 1033 if( !bJScriptObject) 1034 { 1035 variantToAny( &pVarParamsRef[outIndex], outAny, 1036 Type(pMethod->pParams[i].pTypeRef), false); 1037 OutParam[outIndex++]= outAny; 1038 } 1039 else //JScriptObject 1040 { 1041 if( pVarParams[i].vt == VT_DISPATCH) 1042 { 1043 CComDispatchDriver pDisp( pVarParams[i].pdispVal); 1044 if( pDisp) 1045 { 1046 CComVariant varOut; 1047 if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut))) 1048 { 1049 variantToAny( &varOut, outAny, 1050 Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), false); 1051 OutParam[outParameterCount - 1 - outIndex++]= outAny; 1052 } 1053 else 1054 bConvRet= false; 1055 } 1056 else 1057 bConvRet= false; 1058 } 1059 else 1060 bConvRet= false; 1061 } 1062 } 1063 if( !bConvRet) break; 1064 } 1065 } 1066 catch(IllegalArgumentException & e) 1067 { 1068 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); 1069 throw; 1070 } 1071 catch(CannotConvertException & e) 1072 { 1073 e.ArgumentIndex = i; 1074 throw; 1075 } 1076 } 1077 // return value, no type information available 1078 if ( bConvRet) 1079 { 1080 try 1081 { 1082 if( pMethod ) 1083 variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), false); 1084 else 1085 variantToAny(&varResult, ret, false); 1086 } 1087 catch (IllegalArgumentException & e) 1088 { 1089 e.Message = 1090 "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n" 1091 "Could not convert return value! \n Message: \n" + e.Message; 1092 throw; 1093 } 1094 catch (CannotConvertException & e) 1095 { 1096 e.Message = 1097 "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n" 1098 "Could not convert return value! \n Message: \n" + e.Message; 1099 throw; 1100 } 1101 } 1102 } 1103 1104 if( !bConvRet) // conversion of return or out parameter failed 1105 throw CannotConvertException("Call to COM object failed. Conversion of return or out value failed", 1106 Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY ), TypeClass_UNKNOWN, 1107 FailReason::UNKNOWN, 0);// lookup error code 1108 // conversion of return or out parameter failed 1109 switch (hr) 1110 { 1111 case S_OK: 1112 break; 1113 case DISP_E_BADPARAMCOUNT: 1114 throw IllegalArgumentException(); 1115 break; 1116 case DISP_E_BADVARTYPE: 1117 throw RuntimeException(); 1118 break; 1119 case DISP_E_EXCEPTION: 1120 throw InvocationTargetException(); 1121 break; 1122 case DISP_E_MEMBERNOTFOUND: 1123 throw IllegalArgumentException(); 1124 break; 1125 case DISP_E_NONAMEDARGS: 1126 throw IllegalArgumentException(); 1127 break; 1128 case DISP_E_OVERFLOW: 1129 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>( 1130 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); 1131 break; 1132 case DISP_E_PARAMNOTFOUND: 1133 throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>( 1134 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 1135 break; 1136 case DISP_E_TYPEMISMATCH: 1137 throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>( 1138 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); 1139 break; 1140 case DISP_E_UNKNOWNINTERFACE: 1141 throw RuntimeException() ; 1142 break; 1143 case DISP_E_UNKNOWNLCID: 1144 throw RuntimeException() ; 1145 break; 1146 case DISP_E_PARAMNOTOPTIONAL: 1147 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>( 1148 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); 1149 break; 1150 default: 1151 throw RuntimeException(); 1152 break; 1153 } 1154 1155 return ret; 1156 } 1157 1158 1159 // XInitialization 1160 void SAL_CALL IUnknownWrapper::initialize( const Sequence< Any >& aArguments ) 1161 { 1162 // 1.parameter is IUnknown 1163 // 2.parameter is a boolean which indicates if the COM pointer was a IUnknown or IDispatch 1164 // 3.parameter is a Sequence<Type> 1165 o2u_attachCurrentThread(); 1166 OSL_ASSERT(aArguments.getLength() == 3); 1167 1168 m_spUnknown= *static_cast<IUnknown* const *>(aArguments[0].getValue()); 1169 m_spUnknown.QueryInterface( & m_spDispatch.p); 1170 1171 aArguments[1] >>= m_bOriginalDispatch; 1172 aArguments[2] >>= m_seqTypes; 1173 1174 ITypeInfo* pType = nullptr; 1175 try 1176 { 1177 // a COM object implementation that has no TypeInfo is still a legal COM object; 1178 // such objects can at least be transported through UNO using the bridge 1179 // so we should allow to create wrappers for them as well 1180 pType = getTypeInfo(); 1181 } 1182 catch( const BridgeRuntimeError& ) 1183 {} 1184 catch( const Exception& ) 1185 {} 1186 1187 if ( pType ) 1188 { 1189 try 1190 { 1191 // Get Default member 1192 CComBSTR defaultMemberName; 1193 if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, nullptr, nullptr, nullptr ) ) ) 1194 { 1195 OUString usName(o3tl::toU(LPCOLESTR(defaultMemberName))); 1196 FuncDesc aDescGet(pType); 1197 FuncDesc aDescPut(pType); 1198 VarDesc aVarDesc(pType); 1199 // see if this is a property first ( more likely to be a property then a method ) 1200 getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc); 1201 1202 if ( !aDescGet && !aDescPut ) 1203 { 1204 getFuncDesc( usName, &aDescGet ); 1205 if ( !aDescGet ) 1206 throw BridgeRuntimeError( "[automation bridge]IUnknownWrapper::initialize() Failed to get Function or Property desc. for " + usName ); 1207 } 1208 // now for some funny heuristics to make basic understand what to do 1209 // a single aDescGet ( that doesn't take any params ) would be 1210 // a read only ( defaultmember ) property e.g. this object 1211 // should implement XDefaultProperty 1212 // a single aDescGet ( that *does* ) take params is basically a 1213 // default method e.g. implement XDefaultMethod 1214 1215 // 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 ) 1216 if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) ) 1217 m_bHasDfltProperty = true; 1218 if ( aDescGet->cParams > 0 ) 1219 m_bHasDfltMethod = true; 1220 if ( m_bHasDfltProperty || m_bHasDfltMethod ) 1221 m_sDefaultMember = usName; 1222 } 1223 } 1224 catch ( const BridgeRuntimeError & e ) 1225 { 1226 throw RuntimeException( e.message ); 1227 } 1228 catch( const Exception& e ) 1229 { 1230 css::uno::Any anyEx = cppu::getCaughtException(); 1231 throw css::lang::WrappedTargetRuntimeException( 1232 "[automation bridge] unexpected exception in IUnknownWrapper::initialize() error message: \n" + e.Message, 1233 nullptr, anyEx ); 1234 } 1235 } 1236 } 1237 1238 1239 // XDirectInvocation 1240 uno::Any SAL_CALL IUnknownWrapper::directInvoke( const OUString& aName, const uno::Sequence< uno::Any >& aParams ) 1241 { 1242 Any aResult; 1243 1244 if ( !m_spDispatch ) 1245 { 1246 throw RuntimeException( 1247 "[automation bridge] The object does not have an IDispatch interface"); 1248 } 1249 1250 o2u_attachCurrentThread(); 1251 DISPID dispid; 1252 if ( !getDispid( aName, &dispid ) ) 1253 throw IllegalArgumentException( 1254 "[automation bridge] The object does not have a function or property " 1255 + aName, Reference<XInterface>(), 0); 1256 1257 CComVariant varResult; 1258 ExcepInfo excepinfo; 1259 unsigned int uArgErr = 0; 1260 INVOKEKIND pInvkinds[2]; 1261 pInvkinds[0] = INVOKE_FUNC; 1262 pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET; 1263 HRESULT hInvRes = E_FAIL; 1264 1265 // try Invoke first, if it does not work, try put/get property 1266 for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ ) 1267 { 1268 DISPPARAMS dispparams = {nullptr, nullptr, 0, 0}; 1269 1270 std::unique_ptr<DISPID[]> arDispidNamedArgs; 1271 std::unique_ptr<CComVariant[]> ptrArgs; 1272 std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments 1273 CComVariant * arArgs = nullptr; 1274 CComVariant * arRefArgs = nullptr; 1275 1276 dispparams.cArgs = aParams.getLength(); 1277 1278 // Determine the number of named arguments 1279 for ( sal_Int32 nInd = 0; nInd < aParams.getLength(); nInd++ ) 1280 if ( aParams[nInd].getValueType() == cppu::UnoType<NamedArgument>::get() ) 1281 dispparams.cNamedArgs ++; 1282 1283 // fill the named arguments 1284 if ( dispparams.cNamedArgs > 0 1285 && !( dispparams.cNamedArgs == 1 && pInvkinds[nStep] == INVOKE_PROPERTYPUT ) ) 1286 { 1287 int nSizeAr = dispparams.cNamedArgs + 1; 1288 if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT ) 1289 nSizeAr = dispparams.cNamedArgs; 1290 1291 std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]); 1292 OLECHAR ** pNames = saNames.get(); 1293 pNames[0] = const_cast<OLECHAR*>(o3tl::toW(aName.getStr())); 1294 1295 int cNamedArg = 0; 1296 for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ ) 1297 { 1298 if (auto v = o3tl::tryAccess<NamedArgument>(aParams[nInd])) 1299 { 1300 const NamedArgument& arg = *v; 1301 1302 //We put the parameter names in reverse order into the array, 1303 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs 1304 //The first name in the array is the method name 1305 pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(o3tl::toW(arg.Name.getStr())); 1306 } 1307 } 1308 1309 arDispidNamedArgs.reset( new DISPID[nSizeAr] ); 1310 HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() ); 1311 if ( hr == E_NOTIMPL ) 1312 hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() ); 1313 1314 if ( SUCCEEDED( hr ) ) 1315 { 1316 if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT ) 1317 { 1318 DISPID* arIDs = arDispidNamedArgs.get(); 1319 arIDs[0] = DISPID_PROPERTYPUT; 1320 dispparams.rgdispidNamedArgs = arIDs; 1321 } 1322 else 1323 { 1324 DISPID* arIDs = arDispidNamedArgs.get(); 1325 dispparams.rgdispidNamedArgs = & arIDs[1]; 1326 } 1327 } 1328 else if (hr == DISP_E_UNKNOWNNAME) 1329 { 1330 throw IllegalArgumentException( 1331 "[automation bridge]One of the named arguments is wrong!", 1332 Reference<XInterface>(), 0); 1333 } 1334 else 1335 { 1336 throw InvocationTargetException( 1337 "[automation bridge] ITypeInfo::GetIDsOfNames returned error " 1338 + OUString::number(static_cast<sal_Int32>(hr), 16), Reference<XInterface>(), Any()); 1339 } 1340 } 1341 1342 //Convert arguments 1343 ptrArgs.reset(new CComVariant[dispparams.cArgs]); 1344 ptrRefArgs.reset(new CComVariant[dispparams.cArgs]); 1345 arArgs = ptrArgs.get(); 1346 arRefArgs = ptrRefArgs.get(); 1347 1348 sal_Int32 nInd = 0; 1349 try 1350 { 1351 sal_Int32 revIndex = 0; 1352 for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++) 1353 { 1354 revIndex = dispparams.cArgs - nInd - 1; 1355 arRefArgs[revIndex].byref = nullptr; 1356 Any anyArg; 1357 if ( nInd < aParams.getLength() ) 1358 anyArg = aParams.getConstArray()[nInd]; 1359 1360 // Property Put arguments 1361 if ( anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get() ) 1362 { 1363 PropertyPutArgument arg; 1364 anyArg >>= arg; 1365 anyArg = arg.Value; 1366 } 1367 // named argument 1368 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get()) 1369 { 1370 NamedArgument aNamedArgument; 1371 anyArg >>= aNamedArgument; 1372 anyArg = aNamedArgument.Value; 1373 } 1374 1375 if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID ) 1376 { 1377 anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT ); 1378 } 1379 else 1380 { 1381 arArgs[revIndex].vt = VT_ERROR; 1382 arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; 1383 } 1384 } 1385 } 1386 catch (IllegalArgumentException & e) 1387 { 1388 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd ); 1389 throw; 1390 } 1391 catch (CannotConvertException & e) 1392 { 1393 e.ArgumentIndex = nInd; 1394 throw; 1395 } 1396 1397 dispparams.rgvarg = arArgs; 1398 // invoking OLE method 1399 hInvRes = m_spDispatch->Invoke( dispid, 1400 IID_NULL, 1401 LOCALE_USER_DEFAULT, 1402 ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ), 1403 &dispparams, 1404 &varResult, 1405 &excepinfo, 1406 &uArgErr); 1407 } 1408 1409 // converting return value and out parameter back to UNO 1410 if ( SUCCEEDED( hInvRes ) ) 1411 variantToAny( &varResult, aResult, false ); 1412 else 1413 { 1414 // map error codes to exceptions 1415 OUString message; 1416 switch ( hInvRes ) 1417 { 1418 case S_OK: 1419 break; 1420 case DISP_E_BADPARAMCOUNT: 1421 throw IllegalArgumentException("[automation bridge] Wrong " 1422 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.", 1423 nullptr, 0); 1424 break; 1425 case DISP_E_BADVARTYPE: 1426 throw RuntimeException("[automation bridge] One or more " 1427 "arguments have the wrong type. Object returned " 1428 "DISP_E_BADVARTYPE.", nullptr); 1429 break; 1430 case DISP_E_EXCEPTION: 1431 message = "[automation bridge]: "; 1432 message += OUString(o3tl::toU(excepinfo.bstrDescription), 1433 ::SysStringLen(excepinfo.bstrDescription)); 1434 throw InvocationTargetException(message, Reference<XInterface>(), Any()); 1435 break; 1436 case DISP_E_MEMBERNOTFOUND: 1437 message = "[automation bridge]: A function with the name \"" 1438 + aName + "\" is not supported. Object returned " 1439 "DISP_E_MEMBERNOTFOUND."; 1440 throw IllegalArgumentException(message, nullptr, 0); 1441 break; 1442 case DISP_E_NONAMEDARGS: 1443 throw IllegalArgumentException("[automation bridge] Object " 1444 "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 1445 break; 1446 case DISP_E_OVERFLOW: 1447 throw CannotConvertException("[automation bridge] Call failed.", 1448 static_cast<XInterface*>( 1449 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); 1450 break; 1451 case DISP_E_PARAMNOTFOUND: 1452 throw IllegalArgumentException("[automation bridge]Call failed." 1453 "Object returned DISP_E_PARAMNOTFOUND.", 1454 nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 1455 break; 1456 case DISP_E_TYPEMISMATCH: 1457 throw CannotConvertException("[automation bridge] Call failed. " 1458 "Object returned DISP_E_TYPEMISMATCH", 1459 static_cast<XInterface*>( 1460 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); 1461 break; 1462 case DISP_E_UNKNOWNINTERFACE: 1463 throw RuntimeException("[automation bridge] Call failed. " 1464 "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr); 1465 break; 1466 case DISP_E_UNKNOWNLCID: 1467 throw RuntimeException("[automation bridge] Call failed. " 1468 "Object returned DISP_E_UNKNOWNLCID.",nullptr); 1469 break; 1470 case DISP_E_PARAMNOTOPTIONAL: 1471 throw CannotConvertException("[automation bridge] Call failed." 1472 "Object returned DISP_E_PARAMNOTOPTIONAL", 1473 static_cast<XInterface*>(static_cast<XWeak*>(this)), 1474 TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); 1475 break; 1476 default: 1477 throw RuntimeException(); 1478 break; 1479 } 1480 } 1481 1482 return aResult; 1483 } 1484 1485 sal_Bool SAL_CALL IUnknownWrapper::hasMember( const OUString& aName ) 1486 { 1487 if ( ! m_spDispatch ) 1488 { 1489 throw RuntimeException( 1490 "[automation bridge] The object does not have an IDispatch interface"); 1491 } 1492 1493 o2u_attachCurrentThread(); 1494 DISPID dispid; 1495 return getDispid( aName, &dispid ); 1496 } 1497 1498 1499 // UnoConversionUtilities -------------------------------------------------------------------------------- 1500 Reference< XInterface > IUnknownWrapper::createUnoWrapperInstance() 1501 { 1502 if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL) 1503 { 1504 Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper( 1505 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); 1506 return Reference<XInterface>( xWeak, UNO_QUERY); 1507 } 1508 else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT) 1509 { 1510 Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt( 1511 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); 1512 return Reference<XInterface>( xWeak, UNO_QUERY); 1513 } 1514 else 1515 return Reference<XInterface>(); 1516 } 1517 Reference<XInterface> IUnknownWrapper::createComWrapperInstance() 1518 { 1519 Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper( 1520 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); 1521 return Reference<XInterface>( xWeak, UNO_QUERY); 1522 } 1523 1524 1525 void IUnknownWrapper::getMethodInfo(const OUString& sName, TypeDescription& methodInfo) 1526 { 1527 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName); 1528 if( desc.is()) 1529 { 1530 typelib_TypeDescription* pMember= desc.get(); 1531 if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ) 1532 methodInfo= pMember; 1533 } 1534 } 1535 1536 void IUnknownWrapper::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo) 1537 { 1538 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName); 1539 if( desc.is()) 1540 { 1541 typelib_TypeDescription* pMember= desc.get(); 1542 if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE ) 1543 { 1544 attributeInfo= reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(pMember)->pAttributeTypeRef; 1545 } 1546 } 1547 } 1548 TypeDescription IUnknownWrapper::getInterfaceMemberDescOfCurrentCall(const OUString& sName) 1549 { 1550 TypeDescription ret; 1551 1552 for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++) 1553 { 1554 TypeDescription _curDesc( m_seqTypes[i]); 1555 _curDesc.makeComplete(); 1556 typelib_InterfaceTypeDescription * pInterface= reinterpret_cast<typelib_InterfaceTypeDescription*>(_curDesc.get()); 1557 if( pInterface) 1558 { 1559 typelib_InterfaceMemberTypeDescription* pMember= nullptr; 1560 //find the member description of the current call 1561 for( int j=0; j < pInterface->nAllMembers; j++) 1562 { 1563 typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[j]; 1564 typelib_TypeDescription* pDescMember= nullptr; 1565 TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember); 1566 1567 typelib_InterfaceMemberTypeDescription* pInterfaceMember= 1568 reinterpret_cast<typelib_InterfaceMemberTypeDescription*>(pDescMember); 1569 if( OUString( pInterfaceMember->pMemberName) == sName) 1570 { 1571 pMember= pInterfaceMember; 1572 break; 1573 } 1574 TYPELIB_DANGER_RELEASE( pDescMember); 1575 } 1576 1577 if( pMember) 1578 { 1579 ret= &pMember->aBase; 1580 TYPELIB_DANGER_RELEASE( &pMember->aBase); 1581 } 1582 } 1583 if( ret.is()) 1584 break; 1585 } 1586 return ret; 1587 } 1588 1589 bool IUnknownWrapper::isJScriptObject() 1590 { 1591 if( m_eJScript == JScriptUndefined) 1592 { 1593 CComDispatchDriver disp( m_spDispatch); 1594 if( disp) 1595 { 1596 CComVariant result; 1597 if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result))) 1598 { 1599 if(result.vt == VT_BSTR) 1600 { 1601 CComBSTR name( result.bstrVal); 1602 name.ToLower(); 1603 if( name == CComBSTR(JSCRIPT_ID)) 1604 m_eJScript= IsJScript; 1605 } 1606 } 1607 } 1608 if( m_eJScript == JScriptUndefined) 1609 m_eJScript= NoJScript; 1610 } 1611 1612 return m_eJScript != NoJScript; 1613 } 1614 1615 1616 /** @internal 1617 The function ultimately calls IDispatch::Invoke on the wrapped COM object. 1618 The COM object does not implement UNO Interfaces ( via IDispatch). This 1619 is the case when the OleObjectFactory service has been used to create a 1620 component. 1621 @exception IllegalArgumentException 1622 @exception CannotConvertException 1623 @InvocationTargetException 1624 @RuntimeException 1625 @BridgeRuntimeError 1626 */ 1627 Any IUnknownWrapper::invokeWithDispIdComTlb(const OUString& sFuncName, 1628 const Sequence< Any >& Params, 1629 Sequence< sal_Int16 >& OutParamIndex, 1630 Sequence< Any >& OutParam) 1631 { 1632 // Get type info for the call. It can be a method call or property put or 1633 // property get operation. 1634 FuncDesc aFuncDesc(getTypeInfo()); 1635 getFuncDescForInvoke(sFuncName, Params, & aFuncDesc); 1636 return invokeWithDispIdComTlb( aFuncDesc, sFuncName, Params, OutParamIndex, OutParam ); 1637 } 1638 1639 Any IUnknownWrapper::invokeWithDispIdComTlb(FuncDesc& aFuncDesc, 1640 const OUString& sFuncName, 1641 const Sequence< Any >& Params, 1642 Sequence< sal_Int16 >& OutParamIndex, 1643 Sequence< Any >& OutParam) 1644 { 1645 Any ret; 1646 HRESULT result; 1647 1648 DISPPARAMS dispparams = {nullptr, nullptr, 0, 0}; 1649 CComVariant varResult; 1650 ExcepInfo excepinfo; 1651 unsigned int uArgErr; 1652 sal_Int32 i = 0; 1653 sal_Int32 nUnoArgs = Params.getLength(); 1654 DISPID idPropertyPut = DISPID_PROPERTYPUT; 1655 std::unique_ptr<DISPID[]> arDispidNamedArgs; 1656 std::unique_ptr<CComVariant[]> ptrArgs; 1657 std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments 1658 CComVariant * arArgs = nullptr; 1659 CComVariant * arRefArgs = nullptr; 1660 sal_Int32 revIndex = 0; 1661 1662 //Set the array of DISPIDs for named args if it is a property put operation. 1663 //If there are other named arguments another array is set later on. 1664 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT 1665 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF) 1666 dispparams.rgdispidNamedArgs = & idPropertyPut; 1667 1668 //Determine the number of named arguments 1669 for (int iParam = 0; iParam < nUnoArgs; iParam ++) 1670 { 1671 const Any & curArg = Params[iParam]; 1672 if (curArg.getValueType() == cppu::UnoType<NamedArgument>::get()) 1673 dispparams.cNamedArgs ++; 1674 } 1675 //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT). 1676 //Therefore the number of named arguments is increased by one. 1677 //Although named, the argument is not named in an actual language, such as Basic, 1678 //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument 1679 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT 1680 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF) 1681 dispparams.cNamedArgs ++; 1682 1683 //Determine the number of all arguments and named arguments 1684 if (aFuncDesc->cParamsOpt == -1) 1685 { 1686 //Attribute vararg is set on this method. "Unlimited" number of args 1687 //supported. There can be no optional or defaultvalue on any of the arguments. 1688 dispparams.cArgs = nUnoArgs; 1689 } 1690 else 1691 { 1692 //If there are named arguments, then the dispparams.cArgs 1693 //is the number of supplied args, otherwise it is the expected number. 1694 if (dispparams.cNamedArgs) 1695 dispparams.cArgs = nUnoArgs; 1696 else 1697 dispparams.cArgs = aFuncDesc->cParams; 1698 } 1699 1700 //check if there are not too many arguments supplied 1701 if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs) 1702 { 1703 OUStringBuffer buf(256); 1704 buf.append("[automation bridge] There are too many arguments for this method"); 1705 throw IllegalArgumentException( buf.makeStringAndClear(), 1706 Reference<XInterface>(), static_cast<sal_Int16>(dispparams.cArgs)); 1707 } 1708 1709 //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs) 1710 //for the named arguments. 1711 //If there is only one named arg and if it is because of a property put 1712 //operation, then we need not set up the DISPID array. 1713 if (dispparams.cNamedArgs > 0 && 1714 ! (dispparams.cNamedArgs == 1 && 1715 (aFuncDesc->invkind == INVOKE_PROPERTYPUT || 1716 aFuncDesc->invkind == INVOKE_PROPERTYPUTREF))) 1717 { 1718 //set up an array containing the member and parameter names 1719 //which is then used in ITypeInfo::GetIDsOfNames 1720 //First determine the size of the array of names which is passed to 1721 //ITypeInfo::GetIDsOfNames. It must hold the method names + the named 1722 //args. 1723 int nSizeAr = dispparams.cNamedArgs + 1; 1724 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT 1725 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF) 1726 { 1727 nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT 1728 } 1729 1730 std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]); 1731 OLECHAR ** arNames = saNames.get(); 1732 arNames[0] = const_cast<OLECHAR*>(o3tl::toW(sFuncName.getStr())); 1733 1734 int cNamedArg = 0; 1735 for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++) 1736 { 1737 const Any & curArg = Params[iParams]; 1738 if (auto v = o3tl::tryAccess<NamedArgument>(curArg)) 1739 { 1740 const NamedArgument& arg = *v; 1741 //We put the parameter names in reverse order into the array, 1742 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs 1743 //The first name in the array is the method name 1744 arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(o3tl::toW(arg.Name.getStr())); 1745 } 1746 } 1747 1748 //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames 1749 //it must be big enough to contain the DISPIDs of the member + parameters 1750 arDispidNamedArgs.reset(new DISPID[nSizeAr]); 1751 HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr, 1752 arDispidNamedArgs.get()); 1753 if ( hr == E_NOTIMPL ) 1754 hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() ); 1755 1756 if (hr == S_OK) 1757 { 1758 // In a "property put" operation, the property value is a named param with the 1759 //special DISPID DISPID_PROPERTYPUT 1760 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT 1761 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF) 1762 { 1763 //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT 1764 //The first item in the array arDispidNamedArgs is the DISPID for 1765 //the method. We replace it with DISPID_PROPERTYPUT. 1766 DISPID* arIDs = arDispidNamedArgs.get(); 1767 arIDs[0] = DISPID_PROPERTYPUT; 1768 dispparams.rgdispidNamedArgs = arIDs; 1769 } 1770 else 1771 { 1772 //The first item in the array arDispidNamedArgs is the DISPID for 1773 //the method. It must be removed 1774 DISPID* arIDs = arDispidNamedArgs.get(); 1775 dispparams.rgdispidNamedArgs = & arIDs[1]; 1776 } 1777 } 1778 else if (hr == DISP_E_UNKNOWNNAME) 1779 { 1780 throw IllegalArgumentException( 1781 "[automation bridge]One of the named arguments is wrong!", 1782 Reference<XInterface>(), 0); 1783 } 1784 else 1785 { 1786 throw InvocationTargetException( 1787 "[automation bridge] ITypeInfo::GetIDsOfNames returned error " 1788 + OUString::number(static_cast<sal_Int32>(hr), 16), Reference<XInterface>(), Any()); 1789 } 1790 } 1791 1792 //Convert arguments 1793 ptrArgs.reset(new CComVariant[dispparams.cArgs]); 1794 ptrRefArgs.reset(new CComVariant[dispparams.cArgs]); 1795 arArgs = ptrArgs.get(); 1796 arRefArgs = ptrRefArgs.get(); 1797 try 1798 { 1799 for (i = 0; i < static_cast<sal_Int32>(dispparams.cArgs); i++) 1800 { 1801 revIndex= dispparams.cArgs - i -1; 1802 arRefArgs[revIndex].byref=nullptr; 1803 Any anyArg; 1804 if ( i < nUnoArgs) 1805 anyArg= Params.getConstArray()[i]; 1806 1807 unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN; 1808 VARTYPE varType = VT_VARIANT; 1809 if (aFuncDesc->cParamsOpt != -1 || aFuncDesc->cParams != (i + 1)) 1810 { 1811 paramFlags = aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags; 1812 varType = getElementTypeDesc(&aFuncDesc->lprgelemdescParam[i].tdesc); 1813 } 1814 1815 // Make sure that there is a UNO parameter for every 1816 // expected parameter. If there is no UNO parameter where the 1817 // called function expects one, then it must be optional. Otherwise 1818 // it's a UNO programming error. 1819 if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT)) 1820 { 1821 OUStringBuffer buf(256); 1822 buf.append("ole automation bridge: The called function expects an argument at" 1823 "position: "); //a different number of arguments")), 1824 buf.append(OUString::number(i)); 1825 buf.append(" (index starting at 0)."); 1826 throw IllegalArgumentException( buf.makeStringAndClear(), 1827 Reference<XInterface>(), static_cast<sal_Int16>(i)); 1828 } 1829 1830 // Property Put arguments 1831 if (anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get()) 1832 { 1833 PropertyPutArgument arg; 1834 anyArg >>= arg; 1835 anyArg = arg.Value; 1836 } 1837 // named argument 1838 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get()) 1839 { 1840 NamedArgument aNamedArgument; 1841 anyArg >>= aNamedArgument; 1842 anyArg = aNamedArgument.Value; 1843 } 1844 // out param 1845 if (paramFlags & PARAMFLAG_FOUT && 1846 ! (paramFlags & PARAMFLAG_FIN) ) 1847 { 1848 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF ); 1849 if (i < nUnoArgs) 1850 { 1851 arRefArgs[revIndex].vt= type; 1852 } 1853 else 1854 { 1855 //optional arg 1856 arRefArgs[revIndex].vt = VT_ERROR; 1857 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; 1858 } 1859 if( type == VT_VARIANT ) 1860 { 1861 arArgs[revIndex].vt= VT_VARIANT | VT_BYREF; 1862 arArgs[revIndex].byref= &arRefArgs[revIndex]; 1863 } 1864 else 1865 { 1866 arArgs[revIndex].vt= varType; 1867 if (type == VT_DECIMAL) 1868 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal; 1869 else 1870 arArgs[revIndex].byref= & arRefArgs[revIndex].byref; 1871 } 1872 } 1873 // in/out + in byref params 1874 else if (varType & VT_BYREF) 1875 { 1876 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF ); 1877 CComVariant var; 1878 1879 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID) 1880 { 1881 anyToVariant( & arRefArgs[revIndex], anyArg, type); 1882 } 1883 else if (paramFlags & PARAMFLAG_FHASDEFAULT) 1884 { 1885 //optional arg with default 1886 VariantCopy( & arRefArgs[revIndex], 1887 & aFuncDesc->lprgelemdescParam[i].paramdesc. 1888 pparamdescex->varDefaultValue); 1889 } 1890 else 1891 { 1892 //optional arg 1893 //e.g: call func(x) in basic : func() ' no arg supplied 1894 OSL_ASSERT(paramFlags & PARAMFLAG_FOPT); 1895 arRefArgs[revIndex].vt = VT_ERROR; 1896 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; 1897 } 1898 1899 // Set the converted arguments in the array which will be 1900 // DISPPARAMS::rgvarg 1901 // byref arg VT_XXX |VT_BYREF 1902 arArgs[revIndex].vt = varType; 1903 if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT) 1904 { 1905 arArgs[revIndex] = arRefArgs[revIndex]; 1906 } 1907 else if (type == VT_DECIMAL) 1908 { 1909 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal; 1910 } 1911 else if (type == VT_VARIANT) 1912 { 1913 if ( ! (paramFlags & PARAMFLAG_FOUT)) 1914 arArgs[revIndex] = arRefArgs[revIndex]; 1915 else 1916 arArgs[revIndex].byref = & arRefArgs[revIndex]; 1917 } 1918 else 1919 { 1920 arArgs[revIndex].byref = & arRefArgs[revIndex].byref; 1921 arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF ); 1922 } 1923 1924 } 1925 // in parameter no VT_BYREF except for array, interfaces 1926 else 1927 { // void any stands for optional param 1928 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID) 1929 { 1930 anyToVariant( & arArgs[revIndex], anyArg, varType); 1931 } 1932 //optional arg but no void any supplied 1933 //Basic: obj.func() ' first parameter left out because it is optional 1934 else if (paramFlags & PARAMFLAG_FHASDEFAULT) 1935 { 1936 //optional arg with default either as direct arg : VT_XXX or 1937 VariantCopy( & arArgs[revIndex], 1938 & aFuncDesc->lprgelemdescParam[i].paramdesc. 1939 pparamdescex->varDefaultValue); 1940 } 1941 else if (paramFlags & PARAMFLAG_FOPT) 1942 { 1943 arArgs[revIndex].vt = VT_ERROR; 1944 arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; 1945 } 1946 else 1947 { 1948 arArgs[revIndex].vt = VT_EMPTY; 1949 arArgs[revIndex].lVal = 0; 1950 } 1951 } 1952 } 1953 } 1954 catch (IllegalArgumentException & e) 1955 { 1956 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i ); 1957 throw; 1958 } 1959 catch (CannotConvertException & e) 1960 { 1961 e.ArgumentIndex = i; 1962 throw; 1963 } 1964 dispparams.rgvarg= arArgs; 1965 // invoking OLE method 1966 result = m_spDispatch->Invoke(aFuncDesc->memid, 1967 IID_NULL, 1968 LOCALE_USER_DEFAULT, 1969 ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ), 1970 &dispparams, 1971 &varResult, 1972 &excepinfo, 1973 &uArgErr); 1974 1975 // converting return value and out parameter back to UNO 1976 if (result == S_OK) 1977 { 1978 1979 // allocate space for the out param Sequence and indices Sequence 1980 int outParamsCount= 0; // includes in/out parameter 1981 for (int j = 0; j < aFuncDesc->cParams; j++) 1982 { 1983 if (aFuncDesc->lprgelemdescParam[j].paramdesc.wParamFlags & 1984 PARAMFLAG_FOUT) 1985 outParamsCount++; 1986 } 1987 1988 OutParamIndex.realloc(outParamsCount); 1989 OutParam.realloc(outParamsCount); 1990 // Convert out params 1991 if (outParamsCount) 1992 { 1993 int outParamIndex=0; 1994 for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++) 1995 { 1996 //Determine the index within the method signature 1997 int realParamIndex = paramIndex; 1998 int revParamIndex = dispparams.cArgs - paramIndex - 1; 1999 if (Params[paramIndex].getValueType() 2000 == cppu::UnoType<NamedArgument>::get()) 2001 { 2002 //dispparams.rgdispidNamedArgs contains the mapping from index 2003 //of named args list to index of parameter list 2004 realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex]; 2005 } 2006 2007 // no named arg, always come before named args 2008 if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags 2009 & PARAMFLAG_FOUT)) 2010 continue; 2011 Any outAny; 2012 // variantToAny is called with the "reduce range" parameter set to sal_False. 2013 // That causes VT_I4 values not to be converted down to a "lower" type. That 2014 // feature exist for JScript only because it only uses VT_I4 for integer types. 2015 try 2016 { 2017 variantToAny( & arRefArgs[revParamIndex], outAny, false ); 2018 } 2019 catch (IllegalArgumentException & e) 2020 { 2021 e.ArgumentPosition = static_cast<sal_Int16>(paramIndex); 2022 throw; 2023 } 2024 catch (CannotConvertException & e) 2025 { 2026 e.ArgumentIndex = paramIndex; 2027 throw; 2028 } 2029 OutParam[outParamIndex] = outAny; 2030 OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex ); 2031 outParamIndex++; 2032 } 2033 OutParam.realloc(outParamIndex); 2034 OutParamIndex.realloc(outParamIndex); 2035 } 2036 // Return value 2037 variantToAny(&varResult, ret, false); 2038 } 2039 2040 // map error codes to exceptions 2041 OUString message; 2042 switch (result) 2043 { 2044 case S_OK: 2045 break; 2046 case DISP_E_BADPARAMCOUNT: 2047 throw IllegalArgumentException("[automation bridge] Wrong " 2048 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.", 2049 nullptr, 0); 2050 break; 2051 case DISP_E_BADVARTYPE: 2052 throw RuntimeException("[automation bridge] One or more " 2053 "arguments have the wrong type. Object returned " 2054 "DISP_E_BADVARTYPE.", nullptr); 2055 break; 2056 case DISP_E_EXCEPTION: 2057 message = "[automation bridge]: "; 2058 message += OUString(o3tl::toU(excepinfo.bstrDescription), 2059 ::SysStringLen(excepinfo.bstrDescription)); 2060 2061 throw InvocationTargetException(message, Reference<XInterface>(), Any()); 2062 break; 2063 case DISP_E_MEMBERNOTFOUND: 2064 message = "[automation bridge]: A function with the name \"" 2065 + sFuncName + "\" is not supported. Object returned " 2066 "DISP_E_MEMBERNOTFOUND."; 2067 throw IllegalArgumentException(message, nullptr, 0); 2068 break; 2069 case DISP_E_NONAMEDARGS: 2070 throw IllegalArgumentException("[automation bridge] Object " 2071 "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 2072 break; 2073 case DISP_E_OVERFLOW: 2074 throw CannotConvertException("[automation bridge] Call failed.", 2075 static_cast<XInterface*>( 2076 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); 2077 break; 2078 case DISP_E_PARAMNOTFOUND: 2079 throw IllegalArgumentException("[automation bridge]Call failed." 2080 "Object returned DISP_E_PARAMNOTFOUND.", 2081 nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); 2082 break; 2083 case DISP_E_TYPEMISMATCH: 2084 throw CannotConvertException("[automation bridge] Call failed. " 2085 "Object returned DISP_E_TYPEMISMATCH", 2086 static_cast<XInterface*>( 2087 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); 2088 break; 2089 case DISP_E_UNKNOWNINTERFACE: 2090 throw RuntimeException("[automation bridge] Call failed. " 2091 "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr); 2092 break; 2093 case DISP_E_UNKNOWNLCID: 2094 throw RuntimeException("[automation bridge] Call failed. " 2095 "Object returned DISP_E_UNKNOWNLCID.",nullptr); 2096 break; 2097 case DISP_E_PARAMNOTOPTIONAL: 2098 throw CannotConvertException("[automation bridge] Call failed." 2099 "Object returned DISP_E_PARAMNOTOPTIONAL", 2100 static_cast<XInterface*>(static_cast<XWeak*>(this)), 2101 TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); 2102 break; 2103 default: 2104 throw RuntimeException(); 2105 break; 2106 } 2107 2108 return ret; 2109 } 2110 2111 void IUnknownWrapper::getFuncDescForInvoke(const OUString & sFuncName, 2112 const Sequence<Any> & seqArgs, 2113 FUNCDESC** pFuncDesc) 2114 { 2115 int nUnoArgs = seqArgs.getLength(); 2116 const Any * arArgs = seqArgs.getConstArray(); 2117 ITypeInfo* pInfo = getTypeInfo(); 2118 2119 //If the last of the positional arguments is a PropertyPutArgument 2120 //then obtain the type info for the property put operation. 2121 2122 //The property value is always the last argument, in a positional argument list 2123 //or in a list of named arguments. A PropertyPutArgument is actually a named argument 2124 //hence it must not be put in an extra NamedArgument structure 2125 if (nUnoArgs > 0 && 2126 arArgs[nUnoArgs - 1].getValueType() == cppu::UnoType<PropertyPutArgument>::get()) 2127 { 2128 // DISPATCH_PROPERTYPUT 2129 FuncDesc aDescGet(pInfo); 2130 FuncDesc aDescPut(pInfo); 2131 VarDesc aVarDesc(pInfo); 2132 getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc); 2133 if ( ! aDescPut) 2134 { 2135 throw IllegalArgumentException( 2136 "[automation bridge] The object does not have a writeable property: " 2137 + sFuncName, Reference<XInterface>(), 0); 2138 } 2139 *pFuncDesc = aDescPut.Detach(); 2140 } 2141 else 2142 { // DISPATCH_METHOD 2143 FuncDesc aFuncDesc(pInfo); 2144 getFuncDesc(sFuncName, & aFuncDesc); 2145 if ( ! aFuncDesc) 2146 { 2147 // Fallback: DISPATCH_PROPERTYGET can mostly be called as 2148 // DISPATCH_METHOD 2149 ITypeInfo * pTypeInfo = getTypeInfo(); 2150 FuncDesc aDescPut(pTypeInfo); 2151 VarDesc aVarDesc(pTypeInfo); 2152 getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc); 2153 if ( ! aFuncDesc ) 2154 { 2155 throw IllegalArgumentException( 2156 "[automation bridge] The object does not have a function" 2157 " or readable property \"" 2158 + sFuncName + "\"", Reference<XInterface>(), 0); 2159 } 2160 } 2161 *pFuncDesc = aFuncDesc.Detach(); 2162 } 2163 } 2164 bool IUnknownWrapper::getDispid(const OUString& sFuncName, DISPID * id) 2165 { 2166 OSL_ASSERT(m_spDispatch); 2167 LPOLESTR lpsz = const_cast<LPOLESTR> (o3tl::toW(sFuncName.getStr())); 2168 HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id); 2169 return hr == S_OK; 2170 } 2171 void IUnknownWrapper::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc) 2172 2173 { 2174 OSL_ASSERT( * pFuncDesc == nullptr); 2175 buildComTlbIndex(); 2176 typedef TLBFuncIndexMap::const_iterator cit; 2177 //We assume there is only one entry with the function name. A property 2178 //would have two entries. 2179 cit itIndex= m_mapComFunc.find(sFuncName); 2180 if (itIndex == m_mapComFunc.end()) 2181 { 2182 //try case insensitive with IDispatch::GetIDsOfNames 2183 DISPID id; 2184 if (getDispid(sFuncName, &id)) 2185 { 2186 CComBSTR memberName; 2187 unsigned int pcNames=0; 2188 // get the case sensitive name 2189 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames))) 2190 { 2191 //get the associated index and add an entry to the map 2192 //with the name sFuncName which differs in the casing of the letters to 2193 //the actual name as obtained from ITypeInfo 2194 OUString sRealName(o3tl::toU(LPCOLESTR(memberName))); 2195 cit itOrg = m_mapComFunc.find(sRealName); 2196 OSL_ASSERT(itOrg != m_mapComFunc.end()); 2197 // maybe this is a property, if so we need 2198 // to store either both id's ( put/get ) or 2199 // just the get. Storing both is more consistent 2200 pair<cit, cit> pItems = m_mapComFunc.equal_range( sRealName ); 2201 for ( ;pItems.first != pItems.second; ++pItems.first ) 2202 m_mapComFunc.insert( TLBFuncIndexMap::value_type ( make_pair(sFuncName, pItems.first->second ) )); 2203 itIndex = 2204 m_mapComFunc.find( sFuncName ); 2205 } 2206 } 2207 } 2208 2209 #if OSL_DEBUG_LEVEL >= 1 2210 // There must only be one entry if sFuncName represents a function or two 2211 // if it is a property 2212 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase()); 2213 int numEntries = 0; 2214 for ( ;p.first != p.second; p.first ++, numEntries ++); 2215 OSL_ASSERT( ! (numEntries > 3) ); 2216 #endif 2217 if( itIndex != m_mapComFunc.end()) 2218 { 2219 ITypeInfo* pType= getTypeInfo(); 2220 FUNCDESC * pDesc = nullptr; 2221 if (!SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc))) 2222 { 2223 throw BridgeRuntimeError("[automation bridge] Could not get " 2224 "FUNCDESC for " + sFuncName); 2225 } 2226 if (pDesc->invkind == INVOKE_FUNC) 2227 { 2228 (*pFuncDesc) = pDesc; 2229 } 2230 else 2231 { 2232 pType->ReleaseFuncDesc(pDesc); 2233 } 2234 } 2235 //else no entry found for sFuncName, pFuncDesc will not be filled in 2236 } 2237 2238 void IUnknownWrapper::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet, 2239 FUNCDESC** pFuncDescPut, VARDESC** pVarDesc) 2240 { 2241 OSL_ASSERT( * pFuncDescGet == nullptr && * pFuncDescPut == nullptr); 2242 buildComTlbIndex(); 2243 typedef TLBFuncIndexMap::const_iterator cit; 2244 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName); 2245 if (p.first == m_mapComFunc.end()) 2246 { 2247 //try case insensitive with IDispatch::GetIDsOfNames 2248 DISPID id; 2249 if (getDispid(sFuncName, &id)) 2250 { 2251 CComBSTR memberName; 2252 unsigned int pcNames=0; 2253 // get the case sensitive name 2254 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames))) 2255 { 2256 //As opposed to getFuncDesc, we do not add the value because we would 2257 // need to find the get and set description for the property. This would 2258 //mean to iterate over all FUNCDESCs again. 2259 p = m_mapComFunc.equal_range(OUString(o3tl::toU(LPCOLESTR(memberName)))); 2260 } 2261 } 2262 } 2263 2264 for ( int i = 0 ;p.first != p.second; p.first ++, i ++) 2265 { 2266 // There are a maximum of two entries, property put and property get 2267 OSL_ASSERT( ! (i > 2) ); 2268 ITypeInfo* pType= getTypeInfo(); 2269 FUNCDESC * pFuncDesc = nullptr; 2270 if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc))) 2271 { 2272 if (pFuncDesc->invkind == INVOKE_PROPERTYGET) 2273 { 2274 (*pFuncDescGet) = pFuncDesc; 2275 } 2276 else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT || 2277 pFuncDesc->invkind == INVOKE_PROPERTYPUTREF) 2278 { 2279 //a property can have 3 entries, put, put ref, get 2280 // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used 2281 //depends on what is found first. 2282 if ( * pFuncDescPut) 2283 { 2284 //we already have found one 2285 pType->ReleaseFuncDesc(pFuncDesc); 2286 } 2287 else 2288 { 2289 (*pFuncDescPut) = pFuncDesc; 2290 } 2291 } 2292 else 2293 { 2294 pType->ReleaseFuncDesc(pFuncDesc); 2295 } 2296 } 2297 //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC 2298 // with invkind = INVOKE_FUNC. Since this function should only return 2299 //a value for a real property (XInvokation::hasMethod, ..::hasProperty 2300 //we need to make sure that sFuncName represents a real property. 2301 VARDESC * pVD = nullptr; 2302 if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD))) 2303 (*pVarDesc) = pVD; 2304 } 2305 //else no entry for sFuncName, pFuncDesc will not be filled in 2306 } 2307 2308 VARTYPE IUnknownWrapper::getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType ) 2309 { 2310 VARTYPE _type( VT_NULL ); 2311 if ( pTypeInfo ) 2312 { 2313 CComPtr<ITypeInfo> spRefInfo; 2314 pTypeInfo->GetRefTypeInfo( nHrefType, &spRefInfo.p ); 2315 if ( spRefInfo ) 2316 { 2317 TypeAttr attr( spRefInfo ); 2318 spRefInfo->GetTypeAttr( &attr ); 2319 if ( attr->typekind == TKIND_ENUM ) 2320 { 2321 // We use the type of the first enum value. 2322 if ( attr->cVars == 0 ) 2323 { 2324 throw BridgeRuntimeError("[automation bridge] Could not obtain type description"); 2325 } 2326 VarDesc var( spRefInfo ); 2327 spRefInfo->GetVarDesc( 0, &var ); 2328 _type = var->lpvarValue->vt; 2329 } 2330 else if ( attr->typekind == TKIND_INTERFACE ) 2331 { 2332 _type = VT_UNKNOWN; 2333 } 2334 else if ( attr->typekind == TKIND_DISPATCH ) 2335 { 2336 _type = VT_DISPATCH; 2337 } 2338 else if ( attr->typekind == TKIND_ALIAS ) 2339 { 2340 // TKIND_ALIAS is a type that is an alias for another type. So get that alias type. 2341 _type = getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype ); 2342 } 2343 else 2344 { 2345 throw BridgeRuntimeError( "[automation bridge] Unhandled user defined type." ); 2346 } 2347 } 2348 } 2349 return _type; 2350 } 2351 2352 VARTYPE IUnknownWrapper::getElementTypeDesc(const TYPEDESC *desc) 2353 { 2354 VARTYPE _type( VT_NULL ); 2355 2356 if (desc->vt == VT_PTR) 2357 { 2358 _type = getElementTypeDesc(desc->lptdesc); 2359 _type |= VT_BYREF; 2360 } 2361 else if (desc->vt == VT_SAFEARRAY) 2362 { 2363 _type = getElementTypeDesc(desc->lptdesc); 2364 _type |= VT_ARRAY; 2365 } 2366 else if (desc->vt == VT_USERDEFINED) 2367 { 2368 ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance 2369 _type = getUserDefinedElementType( thisInfo, desc->hreftype ); 2370 } 2371 else 2372 { 2373 _type = desc->vt; 2374 } 2375 return _type; 2376 } 2377 2378 void IUnknownWrapper::buildComTlbIndex() 2379 { 2380 if ( ! m_bComTlbIndexInit) 2381 { 2382 MutexGuard guard(getBridgeMutex()); 2383 { 2384 if ( ! m_bComTlbIndexInit) 2385 { 2386 OUString sError; 2387 ITypeInfo* pType= getTypeInfo(); 2388 TypeAttr typeAttr(pType); 2389 if( SUCCEEDED( pType->GetTypeAttr( &typeAttr))) 2390 { 2391 for( long i= 0; i < typeAttr->cFuncs; i++) 2392 { 2393 FuncDesc funcDesc(pType); 2394 if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc))) 2395 { 2396 CComBSTR memberName; 2397 unsigned int pcNames=0; 2398 if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames))) 2399 { 2400 OUString usName(o3tl::toU(LPCOLESTR(memberName))); 2401 m_mapComFunc.emplace(usName, i); 2402 } 2403 else 2404 { 2405 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " 2406 "ITypeInfo::GetNames failed."; 2407 } 2408 } 2409 else 2410 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " 2411 "ITypeInfo::GetFuncDesc failed."; 2412 } 2413 2414 //If we create an Object in JScript and a property then it 2415 //has VARDESC instead of FUNCDESC 2416 for (long i = 0; i < typeAttr->cVars; i++) 2417 { 2418 VarDesc varDesc(pType); 2419 if (SUCCEEDED(pType->GetVarDesc(i, & varDesc))) 2420 { 2421 CComBSTR memberName; 2422 unsigned int pcNames = 0; 2423 if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames))) 2424 { 2425 if (varDesc->varkind == VAR_DISPATCH) 2426 { 2427 OUString usName(o3tl::toU(LPCOLESTR(memberName))); 2428 m_mapComFunc.emplace(usName, i); 2429 } 2430 } 2431 else 2432 { 2433 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " 2434 "ITypeInfo::GetNames failed."; 2435 } 2436 } 2437 else 2438 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " 2439 "ITypeInfo::GetVarDesc failed."; 2440 2441 } 2442 } 2443 else 2444 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " 2445 "ITypeInfo::GetTypeAttr failed."; 2446 2447 if (sError.getLength()) 2448 { 2449 throw BridgeRuntimeError(sError); 2450 } 2451 2452 m_bComTlbIndexInit = true; 2453 } 2454 } 2455 } 2456 } 2457 2458 ITypeInfo* IUnknownWrapper::getTypeInfo() 2459 { 2460 if( !m_spDispatch) 2461 { 2462 throw BridgeRuntimeError("The object has no IDispatch interface!"); 2463 } 2464 2465 if( !m_spTypeInfo ) 2466 { 2467 MutexGuard guard(getBridgeMutex()); 2468 if( ! m_spTypeInfo) 2469 { 2470 CComPtr< ITypeInfo > spType; 2471 if( !SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p))) 2472 { 2473 throw BridgeRuntimeError("[automation bridge]The dispatch object does not " 2474 "support ITypeInfo!"); 2475 } 2476 2477 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 2478 2479 //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE 2480 //We need to get the type description for TKIND_DISPATCH 2481 TypeAttr typeAttr(spType.p); 2482 if( SUCCEEDED(spType->GetTypeAttr( &typeAttr))) 2483 { 2484 if (typeAttr->typekind == TKIND_INTERFACE && 2485 typeAttr->wTypeFlags & TYPEFLAG_FDUAL) 2486 { 2487 HREFTYPE refDispatch; 2488 if (!SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch))) 2489 { 2490 throw BridgeRuntimeError( 2491 "[automation bridge] Could not obtain type information " 2492 "for dispatch interface." ); 2493 } 2494 CComPtr<ITypeInfo> spTypeDisp; 2495 if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp))) 2496 m_spTypeInfo= spTypeDisp; 2497 } 2498 else if (typeAttr->typekind == TKIND_DISPATCH) 2499 { 2500 m_spTypeInfo= spType; 2501 } 2502 else 2503 { 2504 throw BridgeRuntimeError( 2505 "[automation bridge] Automation object does not " 2506 "provide type information."); 2507 } 2508 } 2509 } 2510 } 2511 return m_spTypeInfo; 2512 } 2513 2514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2515
