LibreOffice Module extensions (master) 1
unoconversionutilities.hxx
Go to the documentation of this file.
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#pragma once
20
21#include <memory>
22#include <com/sun/star/script/CannotConvertException.hpp>
23#include <com/sun/star/script/XInvocationAdapterFactory.hpp>
24#include <com/sun/star/script/XInvocationAdapterFactory2.hpp>
25#include <com/sun/star/script/XTypeConverter.hpp>
26#include <com/sun/star/script/FailReason.hpp>
27#include <com/sun/star/bridge/ModelDependent.hpp>
28#include <com/sun/star/bridge/XBridgeSupplier2.hpp>
29#include <com/sun/star/bridge/oleautomation/Date.hpp>
30#include <com/sun/star/bridge/oleautomation/Currency.hpp>
31#include <com/sun/star/bridge/oleautomation/SCode.hpp>
32#include <com/sun/star/bridge/oleautomation/Decimal.hpp>
33#include <com/sun/star/lang/XInitialization.hpp>
34#include <typelib/typedescription.hxx>
35#include <o3tl/any.hxx>
37#include "ole2uno.hxx"
39
40#include "unotypewrapper.hxx"
41#include <unordered_map>
42
43// for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved.
44typedef unsigned char BYTE;
45// classes for wrapping uno objects
46#define INTERFACE_OLE_WRAPPER_IMPL 1
47#define UNO_OBJECT_WRAPPER_REMOTE_OPT 2
48
49#define INVOCATION_SERVICE "com.sun.star.script.Invocation"
50
51
52// classes for wrapping ole objects
53#define IUNKNOWN_WRAPPER_IMPL 1
54
55#define INTERFACE_ADAPTER_FACTORY "com.sun.star.script.InvocationAdapterFactory"
56// COM or JScript objects implementing UNO interfaces have to implement this property
57#define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces"
58// Second property without leading underscore for use in VB
59#define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces"
60
61using namespace com::sun::star::script;
62using namespace com::sun::star::beans;
63using namespace com::sun::star::uno;
65
66extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> AdapterToWrapperMap;
67extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> WrapperToAdapterMap;
68
69//Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g.
70// IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when
71// it is being destroyed.
72// Used to ensure that an Automation object is always mapped to the same UNO objects.
73extern std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap;
74
75// Maps XInterface pointers to a weak reference of its wrapper class (i.e.
76// InterfaceOleWrapper). It is the responsibility of the wrapper to remove the entry when
77// it is being destroyed. It is used to ensure the identity of objects. That is, a UNO interface
78// is mapped to IDispatch which is kept alive in the COM environment. If the same
79// UNO interface is mapped again to COM then the IDispach of the first mapped instance
80// must be returned.
81extern std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
82
83// This function tries to the change the type of a value (contained in the Any)
84// to the smallest possible that can hold the value. This is actually done only
85// for types of VT_I4 (see o2u_variantToAny). The reason is the following:
86// JavaScript passes integer values always as VT_I4. If there is a parameter or
87// property of type any then the bridge converts the any's content according
88// to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted
89// to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value)
90// would be called on an object and the property actually is of TypeClass_SHORT.
91// After conversion of the VARIANT parameter the Any would contain type
92// TypeClass_LONG. Because the corereflection does not cast from long to short
93// the "setPropertValue" would fail as the value has not the right type.
94
95// The corereflection does convert small integer types to bigger types.
96// Therefore we can reduce the type if possible and avoid the above mentioned
97// problem.
98
99// The function is not used when elements are to be converted for Sequences.
100
101inline void reduceRange( Any& any)
102{
103 OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG);
104
105 sal_Int32 value= *o3tl::doAccess<sal_Int32>(any);
106 if( value <= 0x7f && value >= -0x80)
107 {// -128 bis 127
108 sal_Int8 charVal= static_cast<sal_Int8>( value);
109 any.setValue( &charVal, cppu::UnoType<sal_Int8>::get());
110 }
111 else if( value <= 0x7fff && value >= -0x8000)
112 {// -32768 bis 32767
113 sal_Int16 shortVal= static_cast<sal_Int16>( value);
114 any.setValue( &shortVal, cppu::UnoType<sal_Int16>::get());
115 }
116}
117
118// createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance
119 // and initializes it via XInitialization. The wrapper object is required to implement
120 // XBridgeSupplier so that it can convert itself to IDispatch.
121 // class T: Deriving class ( must implement XInterface )
124template< class >
126{
127public:
131 m_smgr( smgr)
132 {}
133
134 UnoConversionUtilities( const Reference<XMultiServiceFactory> & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass )
135 : m_nUnoWrapperClass(unoWrapperClass),
136 m_nComWrapperClass(comWrapperClass), m_smgr(xFactory)
137 {}
138
147 void anyToVariant(VARIANT* pVariant, const Any& rAny);
148 void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
149
153 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq);
158 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype);
163 void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar);
170 void variantToAny(const VARIANT* pVariant, Any& rAny, bool bReduceValueRange = true);
179 void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange = true);
180
186 Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type());
187
188 /*
189 Return true means var contained a ValueObject, and it was successfully converted.
190 The result is in any. It an error occurred a BridgeRuntimeError will be thrown.
191 */
192 bool convertValueObject( const VARIANTARG *var, Any& any);
193 void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type);
194
195 Sequence<Any> createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, LONG* index,
196 VARTYPE type, const Type& unotype);
197 Sequence<Any> createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type());
198
199
200 VARTYPE mapTypeClassToVartype( TypeClass type);
202
203
206
207 static bool isJScriptArray(const VARIANT* pvar);
208
210
211protected:
213
214 // helper function for Sequence conversion
215 void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc);
216 // helper function for Sequence conversion
217 static bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength,
218 sal_Int32 * parMultidimensionalIndex);
219 // helper function for Sequence conversion
220 static size_t getOleElementSize( VARTYPE type);
221
222 static Type getElementTypeOfSequence( const Type& seqType);
223
224 //Provides a typeconverter
226
227 // This member determines what class is used to convert a UNO object
228 // or struct to a COM object. It is passed along to the anyToVariant
229 // function in the createBridge function implementation
232
233 // The servicemanager is either a local smgr or remote when the service
234 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be
235 // created by createInstanceWithArguments where one can supply a service
236 // manager that is to be used.
237 // Local service manager as supplied by the loader when the creator function
238 // of the service is being called.
240 // An explicitly supplied service manager when the service
241 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote
242 // manager.
246
247private:
248 // Holds the type converter which is used for sequence conversion etc.
249 // Use the getTypeConverter function to obtain the interface.
251
252
253};
254
255// ask the object for XBridgeSupplier2 and on success bridges
256// the uno object to IUnknown or IDispatch.
257// return true the UNO object supports
258template < class T >
259bool convertSelfToCom( T& unoInterface, VARIANT * pVar)
260{
261 bool ret = false;
262 Reference< XInterface > xInt( unoInterface, UNO_QUERY);
263 if( xInt.is())
264 {
265 Reference< css::bridge::XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY);
266 if( xSupplier.is())
267 {
268 sal_Int8 arId[16];
269 rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(arId));
270 Sequence<sal_Int8> seqId( arId, 16);
271 Any anySource;
272 anySource <<= xInt;
273 Any anyDisp = xSupplier->createBridge(
274 anySource, seqId, css::bridge::ModelDependent::UNO,
275 css::bridge::ModelDependent::OLE);
276
277 // due to global-process-id check this must be in-process pointer
278 if (auto v = o3tl::tryAccess<sal_uIntPtr>(anyDisp))
279 {
280 VARIANT* pvariant= reinterpret_cast<VARIANT*>(*v);
281 HRESULT hr;
282 if (FAILED(hr = VariantCopy(pVar, pvariant)))
283 throw BridgeRuntimeError(
284 "[automation bridge] convertSelfToCom\n"
285 "VariantCopy failed! Error: " +
286 OUString::number(hr));
287 VariantClear( pvariant);
288 CoTaskMemFree( pvariant);
289 ret = true;
290 }
291 }
292 }
293 return ret;
294}
295
296
297// Gets the invocation factory depending on the Type in the Any.
298// The factory can be created by a local or remote multi service factory.
299// In case there is a remote multi service factory available there are
300// some services or types for which the local factory is used. The exceptions
301// are: all structs.
302// Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
303
304template<class T>
306{
308 MutexGuard guard( getBridgeMutex());
309 if( anyObject.getValueTypeClass() != TypeClass_STRUCT &&
310 m_smgrRemote.is() )
311 {
312 if( ! m_xInvocationFactoryRemote.is() )
313 m_xInvocationFactoryRemote.set(m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY);
314 retVal= m_xInvocationFactoryRemote;
315 }
316 else
317 {
318 if( ! m_xInvocationFactoryLocal.is() )
319 m_xInvocationFactoryLocal.set(m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY);
320 retVal= m_xInvocationFactoryLocal;
321 }
322 return retVal;
323}
324
325template<class T>
326void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange /* = sal_True */)
327{
328 try
329 {
330 HRESULT hr;
331 bool bFail = false;
332 bool bCannotConvert = false;
333 CComVariant var;
334
335 // There is no need to support indirect values, since they're not supported by UNO
336 if( FAILED(hr= VariantCopyInd( &var, pArg))) // remove VT_BYREF
337 throw BridgeRuntimeError(
338 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
339 "VariantCopyInd failed for reason : " + OUString::number(hr));
340 bool bHandled = convertValueObject( & var, rAny);
341 if( bHandled)
342 OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter");
343
344 if( ! bHandled)
345 {
346 // convert into a variant type that is the equivalent to the type
347 // the sequence expects. Thus variantToAny produces the correct type
348 // E.g. An Array object contains VT_I4 and the sequence expects shorts
349 // than the vartype must be changed. The reason is, you can't specify the
350 // type in JavaScript and the script engine determines the type being used.
351 switch( ptype.getTypeClass())
352 {
353 case TypeClass_CHAR: // could be: new Array( 12, 'w', "w")
354 if( var.vt == VT_BSTR)
355 {
356 if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR)))
357 rAny.setValue( V_BSTR( &var), ptype);
358 else if (hr == DISP_E_TYPEMISMATCH)
359 bCannotConvert = true;
360 else
361 bFail = true;
362 }
363 else
364 {
365 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
366 rAny.setValue(& var.iVal, ptype);
367 else if (hr == DISP_E_TYPEMISMATCH)
368 bCannotConvert = true;
369 else
370 bFail = true;
371 }
372 break;
373 case TypeClass_INTERFACE: // could also be an IUnknown
374 case TypeClass_STRUCT:
375 {
376 rAny = createOleObjectWrapper( & var, ptype);
377 break;
378 }
379 case TypeClass_ENUM:
380 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4)))
381 rAny.setValue(& var.lVal, ptype);
382 else if (hr == DISP_E_TYPEMISMATCH)
383 bCannotConvert = true;
384 else
385 bFail = true;
386 break;
387 case TypeClass_SEQUENCE:
388 // There are different ways of receiving a sequence:
389 // 1: JScript, VARTYPE: VT_DISPATCH
390 // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
391 // a VT_ARRAY| <type>
392 // 3. VBScript multi dimensional arrays: VT_ARRAY|VT_BYREF
393 if( pArg->vt == VT_DISPATCH)
394 {
395 dispatchExObject2Sequence( pArg, rAny, ptype);
396 }
397 else
398 {
399 if ((var.vt & VT_ARRAY) != 0)
400 {
401 VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
402 Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype);
404 if (conv.is())
405 {
406 try
407 {
408 Any anySeq(unoSeq);
409 Any convAny = conv->convertTo(anySeq, ptype);
410 rAny = convAny;
411 }
412 catch (const IllegalArgumentException& e)
413 {
414 throw BridgeRuntimeError(
415 "[automation bridge]com.sun.star.lang.IllegalArgumentException "
416 "in UnoConversionUtilities<T>::variantToAny! Message: " +
417 e.Message);
418 }
419 catch (const CannotConvertException& e)
420 {
421 throw BridgeRuntimeError(
422 "[automation bridge]com.sun.star.script.CannotConvertException "
423 "in UnoConversionUtilities<T>::variantToAny! Message: " +
424 e.Message);
425 }
426 }
427 }
428 }
429 break;
430 case TypeClass_VOID:
431 rAny.setValue(nullptr,Type());
432 break;
433 case TypeClass_ANY: // Any
434 // There could be a JScript Array that needs special handling
435 // If an Any is expected and this Any must contain a Sequence
436 // then we cannot figure out what element type is required.
437 // Therefore we convert to Sequence< Any >
438 if( pArg->vt == VT_DISPATCH && isJScriptArray( pArg))
439 {
440 dispatchExObject2Sequence( pArg, rAny,
442 }
443 else if (pArg->vt == VT_DECIMAL)
444 {
445 //Decimal maps to hyper in calls from COM -> UNO
446 // It does not matter if we create a sal_uInt64 or sal_Int64,
447 // because the UNO object is called through invocation which
448 //will do a type conversion if necessary
449 if (var.decVal.sign == 0)
450 {
451 // positive value
452 variantToAny( & var, rAny, cppu::UnoType<sal_uInt64>::get(),
453 bReduceValueRange);
454 }
455 else
456 {
457 //negative value
458 variantToAny( & var, rAny, cppu::UnoType<sal_Int64>::get(),
459 bReduceValueRange);
460 }
461 }
462 else
463 {
464 variantToAny( & var, rAny);
465 }
466 break;
467 case TypeClass_BOOLEAN: // VARIANT could be VARIANT_BOOL or other
468 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL)))
469 variantToAny( & var, rAny);
470 else if (hr == DISP_E_TYPEMISMATCH)
471 bCannotConvert = true;
472 else
473 bFail = true;
474 break;
475 case TypeClass_STRING: // UString
476 if(var.vt == VT_NULL)
477 var = CComBSTR("");
478 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR)))
479 variantToAny( & var, rAny);
480 else if (hr == DISP_E_TYPEMISMATCH)
481 bCannotConvert = true;
482 else
483 bFail = true;
484 break;
485 case TypeClass_FLOAT: // float
486 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4)))
487 variantToAny( & var, rAny);
488 else if (hr == DISP_E_TYPEMISMATCH)
489 bCannotConvert = true;
490 else
491 bFail = true;
492 break;
493 case TypeClass_DOUBLE: // double
494 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8)))
495 variantToAny(& var, rAny);
496 else if (hr == DISP_E_TYPEMISMATCH)
497 bCannotConvert = true;
498 else
499 bFail = true;
500 break;
501 case TypeClass_BYTE: // BYTE
502 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1)))
503 variantToAny( & var, rAny);
504 else if (hr == DISP_E_TYPEMISMATCH)
505 bCannotConvert = true;
506 else
507 bFail = true;
508 break;
509 case TypeClass_SHORT: // INT16
510 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
511 variantToAny( & var, rAny);
512 else if (hr == DISP_E_TYPEMISMATCH)
513 bCannotConvert = true;
514 else
515 bFail = true;
516 break;
517 case TypeClass_LONG:
518 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4)))
519 variantToAny( & var, rAny, bReduceValueRange);
520 else if (hr == DISP_E_TYPEMISMATCH)
521 bCannotConvert = true;
522 else
523 bFail = true;
524 break;
525 case TypeClass_HYPER:
526 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
527 {
528 if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000)
529 || var.decVal.Hi32 > 0
530 || var.decVal.scale > 0)
531 {
532 bFail = true;
533 break;
534 }
535 sal_Int64 value = var.decVal.Lo64;
536 if (var.decVal.sign == DECIMAL_NEG)
537 value |= SAL_CONST_UINT64(0x8000000000000000);
538 rAny <<= value;
539 }
540 else if (hr == DISP_E_TYPEMISMATCH)
541 bCannotConvert = true;
542 else
543 bFail = true;
544 break;
545 case TypeClass_UNSIGNED_SHORT: // UINT16
546 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2)))
547 variantToAny( & var, rAny);
548 else if (hr == DISP_E_TYPEMISMATCH)
549 bCannotConvert = true;
550 else
551 bFail = true;
552 break;
553 case TypeClass_UNSIGNED_LONG:
554 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4)))
555 variantToAny( & var, rAny, bReduceValueRange);
556 else if (hr == DISP_E_TYPEMISMATCH)
557 bCannotConvert = true;
558 else
559 bFail = true;
560 break;
561 case TypeClass_UNSIGNED_HYPER:
562 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
563 {
564 if (var.decVal.Hi32 > 0 || var.decVal.scale > 0)
565 {
566 bFail = true;
567 break;
568 }
569 rAny <<= var.decVal.Lo64;
570 }
571 else if (hr == DISP_E_TYPEMISMATCH)
572 bCannotConvert = true;
573 else
574 bFail = true;
575 break;
576 case TypeClass_TYPE:
577 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN)))
578 variantToAny( & var, rAny);
579 else if (hr == DISP_E_TYPEMISMATCH)
580 bCannotConvert = true;
581 else
582 bFail = true;
583 break;
584 default:
585 bCannotConvert = true;
586 break;
587 }
588 }
589 if (bCannotConvert)
590 throw CannotConvertException(
591 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
592 "Cannot convert the value of vartype :\"" +
593 OUString::number(static_cast<sal_Int32>(var.vt)) +
594 "\" to the expected UNO type of type class: " +
595 OUString::number(static_cast<sal_Int32>(ptype.getTypeClass())),
596 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
597
598 if (bFail)
599 throw IllegalArgumentException(
600 "[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
601 "The provided VARIANT of type\" " + OUString::number(static_cast<sal_Int32>(var.vt)) +
602 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
603 }
604 catch (const CannotConvertException &)
605 {
606 throw;
607 }
608 catch (const IllegalArgumentException &)
609 {
610 throw;
611 }
612 catch (const BridgeRuntimeError &)
613 {
614 throw;
615 }
616 catch (const Exception & e)
617 {
618 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
619 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
620 e.Message);
621 }
622 catch(...)
623 {
624 throw BridgeRuntimeError(
625 "[automation bridge] unexpected exception in "
626 "UnoConversionUtilities<T>::variantToAny !");
627 }
628}
629
630// The function only converts Sequences to SAFEARRAYS with elements of the type
631// specified by the parameter type. Everything else is forwarded to
632// anyToVariant(VARIANT* pVariant, const Any& rAny)
633// Param type must not be VT_BYREF
634template<class T>
635void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type)
636{
637 try
638 {
639 HRESULT hr= S_OK;
640
641 OSL_ASSERT( (type & VT_BYREF) == 0);
642 if (type & VT_ARRAY)
643 {
644 type ^= VT_ARRAY;
645 SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type);
646 if( ar)
647 {
648 VariantClear( pVariant);
649 pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type );
650 pVariant->byref= ar;
651 }
652 }
653 else if(type == VT_VARIANT)
654 {
655 anyToVariant(pVariant, rAny);
656 }
657 else
658 {
659 CComVariant var;
660 anyToVariant( &var, rAny);
661 if(FAILED(hr = VariantChangeType(&var, &var, 0, type)))
662 {
663 if (hr == DISP_E_TYPEMISMATCH)
664 throw CannotConvertException(
665 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
666 "Cannot convert the value of type :\"" +
667 rAny.getValueTypeName() +
668 "\" to the expected Automation type of VARTYPE: " +
669 OUString::number(static_cast<sal_Int32>(type)),
670 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
671
672 throw BridgeRuntimeError(
673 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
674 "Conversion of any with " +
675 rAny.getValueType().getTypeName() +
676 " to VARIANT with type: " + OUString::number(static_cast<sal_Int32>(type)) +
677 " failed! Error code: " + OUString::number(hr));
678
679 }
680 if(FAILED(hr = VariantCopy(pVariant, &var)))
681 {
682 throw BridgeRuntimeError(
683 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
684 "VariantCopy failed for reason: " + OUString::number(hr));
685 }
686 }
687 }
688 catch (const IllegalArgumentException &)
689 {
690 throw;
691 }
692 catch (const CannotConvertException &)
693 {
694 throw;
695 }
696 catch (const BridgeRuntimeError&)
697 {
698 throw;
699 }
700 catch(const Exception & e)
701 {
702 throw BridgeRuntimeError(
703 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
704 "Unexpected exception occurred. Message: " + e.Message);
705 }
706 catch(...)
707 {
708 throw BridgeRuntimeError(
709 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
710 "Unexpected exception occurred.");
711 }
712}
713
714template<class T>
715void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny)
716{
717 try
718 {
719 bool bIllegal = false;
720 switch (rAny.getValueTypeClass())
721 {
722 case TypeClass_INTERFACE:
723 {
725 if (rAny >>= xInt)
726 {
727 createUnoObjectWrapper(rAny, pVariant);
728 }
729 else
730 {
731 bIllegal = true;
732 }
733 break;
734 }
735 case TypeClass_STRUCT:
736 {
737 if (rAny.getValueType() == cppu::UnoType<Date>::get() )
738 {
739 Date d;
740 if (rAny >>= d)
741 {
742 pVariant->vt = VT_DATE;
743 pVariant->date = d.Value;
744 }
745 else
746 {
747 bIllegal = true;
748 }
749 }
750 else if(rAny.getValueType() == cppu::UnoType<Decimal>::get())
751 {
752 Decimal d;
753 if (rAny >>= d)
754 {
755 pVariant->vt = VT_DECIMAL;
756 pVariant->decVal.scale = d.Scale;
757 pVariant->decVal.sign = d.Sign;
758 pVariant->decVal.Lo32 = d.LowValue;
759 pVariant->decVal.Mid32 = d.MiddleValue;
760 pVariant->decVal.Hi32 = d.HighValue;
761 }
762 else
763 {
764 bIllegal = true;
765 }
766 }
767 else if (rAny.getValueType() == cppu::UnoType<Currency>::get())
768 {
769 Currency c;
770 if (rAny >>= c)
771 {
772 pVariant->vt = VT_CY;
773 pVariant->cyVal.int64 = c.Value;
774 }
775 else
776 {
777 bIllegal = true;
778 }
779 }
780 else if(rAny.getValueType() == cppu::UnoType<SCode>::get())
781 {
782 SCode s;
783 if (rAny >>= s)
784 {
785 pVariant->vt = VT_ERROR;
786 pVariant->scode = s.Value;
787 }
788 else
789 {
790 bIllegal = true;
791 }
792 }
793 else
794 {
795 createUnoObjectWrapper(rAny, pVariant);
796 }
797 break;
798 }
799 case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor
800 {
801 SAFEARRAY* pArray = createUnoSequenceWrapper(rAny);
802 if (pArray)
803 {
804 V_VT(pVariant) = VT_ARRAY | VT_VARIANT;
805 V_ARRAY(pVariant) = pArray;
806 }
807 else
808 {
809 bIllegal = true;
810 }
811 break;
812 }
813 case TypeClass_VOID:
814 {
815 HRESULT hr = S_OK;
816 if (FAILED(hr = VariantClear(pVariant)))
817 {
818 throw BridgeRuntimeError(
819 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
820 "VariantClear failed with error:" + OUString::number(hr));
821 }
822 break;
823 }
824 case TypeClass_BOOLEAN:
825 {
826 bool value;
827 if (rAny >>= value)
828 {
829 pVariant->vt = VT_BOOL;
830 pVariant->boolVal = value ? VARIANT_TRUE: VARIANT_FALSE;
831 }
832 else
833 {
834 bIllegal = true;
835 }
836 break;
837 }
838 case TypeClass_CHAR:
839 {
840 // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead
841 sal_uInt16 value = *o3tl::forceAccess<sal_Unicode>(rAny);
842 pVariant->vt = VT_I2;
843 pVariant->iVal = value;
844 break;
845 }
846 case TypeClass_STRING:
847 {
848 OUString value;
849 if (rAny >>= value)
850 {
851 pVariant->vt = VT_BSTR;
852 pVariant->bstrVal = SysAllocString(o3tl::toW(value.getStr()));
853 }
854 else
855 {
856 bIllegal = true;
857 }
858 break;
859 }
860 case TypeClass_FLOAT:
861 {
862 float value;
863 if (rAny >>= value)
864 {
865 pVariant->vt = VT_R4;
866 pVariant->fltVal = value;
867 }
868 else
869 {
870 bIllegal = true;
871 }
872 break;
873 }
874 case TypeClass_DOUBLE:
875 {
876 double value;
877 if (rAny >>= value)
878 {
879 pVariant->vt = VT_R8;
880 pVariant->dblVal = value;
881 }
882 else
883 {
884 bIllegal = true;
885 }
886 break;
887 }
888 case TypeClass_BYTE:
889 {
890 // ole automation does not know a signed char but only unsigned char
892 if (rAny >>= value)
893 {
894 pVariant->vt = VT_UI1;
895 pVariant->bVal = value;
896 }
897 else
898 {
899 bIllegal = true;
900 }
901 break;
902 }
903 case TypeClass_SHORT: // INT16
904 case TypeClass_UNSIGNED_SHORT: // UINT16
905 {
906 sal_Int16 value;
907 if (rAny >>= value)
908 {
909 pVariant->vt = VT_I2;
910 pVariant->iVal = value;
911 }
912 else
913 {
914 bIllegal = true;
915 }
916 break;
917 }
918 case TypeClass_ENUM:
919 {
920 sal_Int32 value = *static_cast<sal_Int32 const *>(rAny.getValue());
921 pVariant->vt = VT_I4;
922 pVariant->lVal= value;
923 break;
924 }
925 case TypeClass_LONG:
926 case TypeClass_UNSIGNED_LONG:
927 {
928 sal_Int32 value;
929 if (rAny >>= value)
930 {
931 pVariant->vt = VT_I4;
932 pVariant->lVal= value;
933 }
934 else
935 {
936 bIllegal = true;
937 }
938 break;
939 }
940 case TypeClass_HYPER:
941 {
942
943 pVariant->vt = VT_DECIMAL;
944 pVariant->decVal.scale = 0;
945 pVariant->decVal.sign = 0;
946 pVariant->decVal.Hi32 = 0;
947
948 sal_Int64 value;
949 rAny >>= value;
950
951 if (value & SAL_CONST_UINT64(0x8000000000000000))
952 pVariant->decVal.sign = DECIMAL_NEG;
953
954 pVariant->decVal.Lo64 = value;
955 break;
956 }
957 case TypeClass_UNSIGNED_HYPER:
958 {
959 pVariant->vt = VT_DECIMAL;
960 pVariant->decVal.scale = 0;
961 pVariant->decVal.sign = 0;
962 pVariant->decVal.Hi32 = 0;
963
964 sal_uInt64 value;
965 rAny >>= value;
966 pVariant->decVal.Lo64 = value;
967 break;
968 }
969 case TypeClass_TYPE:
970 {
971 Type type;
972 rAny >>= type;
973 CComVariant var;
974 if (!createUnoTypeWrapper(type.getTypeName(), & var))
975 throw BridgeRuntimeError(
976 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
977 "Error during conversion of UNO type to Automation object!");
978
979 if (FAILED(VariantCopy(pVariant, &var)))
980 throw BridgeRuntimeError(
981 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
982 "Unexpected error!");
983 break;
984 }
985 default:
986 //TypeClass_SERVICE:
987 //TypeClass_EXCEPTION:
988 //When an InvocationTargetException is thrown when calling XInvocation::invoke
989 //on a UNO object, then the target exception is directly used to create a
990 //EXEPINFO structure
991 //TypeClass_TYPEDEF
992 //TypeClass_ANY:
993 //TypeClass_UNKNOWN:
994 //TypeClass_MODULE:
995 throw CannotConvertException(
996 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
997 "There is no conversion for this UNO type to an Automation type."
998 "The destination type class is the type class of the UNO "
999 "argument which was to be converted.",
1000 Reference<XInterface>(), rAny.getValueTypeClass(),
1001 FailReason::TYPE_NOT_SUPPORTED, 0);
1002
1003 break;
1004 }
1005 if (bIllegal)
1006 {
1007 throw IllegalArgumentException(
1008 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
1009 "The provided any of type\" " + rAny.getValueType().getTypeName() +
1010 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
1011
1012 }
1013 }
1014 catch (const CannotConvertException &)
1015 {
1016 throw;
1017 }
1018 catch (const IllegalArgumentException &)
1019 {
1020 throw;
1021 }
1022 catch(const BridgeRuntimeError&)
1023 {
1024 throw;
1025 }
1026 catch(const Exception & e)
1027 {
1028 throw BridgeRuntimeError(
1029 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1030 "Unexpected exception occurred. Message: " + e.Message);
1031 }
1032 catch(...)
1033 {
1034 throw BridgeRuntimeError(
1035 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1036 "Unexpected exception occurred. " );
1037 }
1038}
1039
1040// Creates an SAFEARRAY of the specified element and if necessary
1041// creates a SAFEARRAY with multiple dimensions.
1042// Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
1043template<class T>
1044SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype)
1045{
1046 if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE)
1047 throw IllegalArgumentException(
1048 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1049 "The any does not contain a sequence!", nullptr, 0);
1050 if (elemtype == VT_NULL || elemtype == VT_EMPTY)
1051 throw IllegalArgumentException(
1052 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1053 "No element type supplied!",nullptr, -1);
1054 SAFEARRAY* pArray= nullptr;
1055 // Get the dimensions. This is done by examining the type name string
1056 // The count of brackets determines the dimensions.
1057 OUString sTypeName= rSeq.getValueType().getTypeName();
1058 sal_Int32 dims=0;
1059 for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++);
1060
1061 //get the maximum number of elements per dimensions and the typedescription of the elements
1062 Sequence<sal_Int32> seqElementCounts( dims);
1063 TypeDescription elementTypeDesc;
1064 getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc );
1065
1066 if( elementTypeDesc.is() )
1067 {
1068 // set up the SAFEARRAY
1069 std::unique_ptr<SAFEARRAYBOUND[]> sarSafeArrayBound(new SAFEARRAYBOUND[dims]);
1070 SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get();
1071 for( sal_Int32 i=0; i < dims; i++)
1072 {
1073 //prgsabound[0] is the right most dimension
1074 prgsabound[dims - i - 1].lLbound = 0;
1075 prgsabound[dims - i - 1].cElements = seqElementCounts[i];
1076 }
1077
1078 typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get();
1079 sal_Int32 elementSize= rawTypeDesc->nSize;
1080 size_t oleElementSize= getOleElementSize( elemtype);
1081 // SafeArrayCreate clears the memory for the data itself.
1082 pArray = SafeArrayCreate(elemtype, dims, prgsabound);
1083
1084 // convert the Sequence's elements and populate the SAFEARRAY
1085 if( pArray)
1086 {
1087 // Iterate over every Sequence that contains the actual elements
1088 void* pSAData;
1089 if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData)))
1090 {
1091 const sal_Int32* parElementCount= seqElementCounts.getConstArray();
1092 uno_Sequence * pMultiSeq= *static_cast<uno_Sequence* const*>(rSeq.getValue());
1093 sal_Int32 dimsSeq= dims - 1;
1094
1095 // arDimSeqIndices contains the current index of a block of data.
1096 // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32>
1097 // In this case arDimSeqIndices would have the size 1. That is the elements are not counted
1098 // but the Sequences that contain those elements.
1099 // The indices are 0 based
1100 std::unique_ptr<sal_Int32[]> sarDimsSeqIndices;
1101 sal_Int32* arDimsSeqIndices= nullptr;
1102 if( dimsSeq > 0)
1103 {
1104 sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]);
1105 arDimsSeqIndices = sarDimsSeqIndices.get();
1106 memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq);
1107 }
1108
1109 char* psaCurrentData= static_cast<char*>(pSAData);
1110
1111 do
1112 {
1113 // Get the Sequence at the current index , see arDimsSeqIndices
1114 uno_Sequence * pCurrentSeq= pMultiSeq;
1115 sal_Int32 curDim=1; // 1 based
1116 bool skipSeq= false;
1117 while( curDim <= dimsSeq )
1118 {
1119 // get the Sequence at the index if valid
1120 if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana
1121 {
1122 // size of Sequence is 4
1123 sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4;
1124 pCurrentSeq= *reinterpret_cast<uno_Sequence**>(&pCurrentSeq->elements[ offset]);
1125 curDim++;
1126 }
1127 else
1128 {
1129 // There is no Sequence at this index, so skip this index
1130 skipSeq= true;
1131 break;
1132 }
1133 }
1134
1135 if( skipSeq)
1136 continue;
1137
1138 // Calculate the current position within the datablock of the SAFEARRAY
1139 // for the next Sequence.
1140 sal_Int32 memOffset= 0;
1141 sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension
1142 for(sal_Int32 idims=0; idims < dimsSeq; idims++ )
1143 {
1144 memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight;
1145 // now determine the weight of the dimension to the left of the current.
1146 if( dims - 2 - idims >=0)
1147 dimWeight*= parElementCount[dims - 2 - idims];
1148 }
1149 psaCurrentData= static_cast<char*>(pSAData) + memOffset * oleElementSize;
1150 // convert the Sequence and put the elements into the Safearray
1151 for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++)
1152 {
1153 Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc );
1154 // The any is being converted into a VARIANT which value is then copied
1155 // to the SAFEARRAY's data block. When copying one has to follow the rules for
1156 // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR.
1157 // To increase performance, we just do a memcpy of VARIANT::byref. This is possible
1158 // because anyToVariant has already followed the copying rules. To make this
1159 // work there must not be a VariantClear.
1160 // One Exception is VARIANT because I don't know how VariantCopy works.
1161
1162 VARIANT var;
1163 VariantInit( &var);
1164 anyToVariant( &var, unoElement);
1165 if( elemtype == VT_VARIANT )
1166 {
1167 VariantCopy( reinterpret_cast<VARIANT*>(psaCurrentData), &var);
1168 VariantClear( &var);
1169 }
1170 else
1171 memcpy( psaCurrentData, &var.byref, oleElementSize);
1172
1173 psaCurrentData+= oleElementSize;
1174 }
1175 }
1176 while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices));
1177
1178 SafeArrayUnaccessData( pArray);
1179 }
1180 }
1181 }
1182 return pArray;
1183}
1184
1185// Increments a multi dimensional index.
1186// Returns true as long as the index has been successfully incremented, false otherwise.
1187// False is also returned if an overflow of the most significant dimension occurs. E.g.
1188// assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest
1189// index is (1,1). If the function is being called with the index (1,1) then the overflow would
1190// occur, with the result (0,0) and a sal_False as return value.
1191// Param dimensions - number of dimensions
1192// Param parDimensionsLength - The array contains the size of each dimension, that is the
1193// size of the array equals the parameter dimensions.
1194// The rightmost dimensions is the least significant one
1195// ( parDimensionsLengths[ dimensions -1 ] ).
1196// Param parMultiDimensionalIndex - The array contains the index. Each dimension index is
1197// 0 based.
1198template<class T>
1200 const sal_Int32 * parDimensionLengths,
1201 sal_Int32 * parMultidimensionalIndex)
1202{
1203 if( dimensions < 1)
1204 return false;
1205
1206 bool ret= true;
1207 bool carry= true; // to get into the while loop
1208
1209 sal_Int32 currentDimension= dimensions; //most significant is 1
1210 while( carry)
1211 {
1212 parMultidimensionalIndex[ currentDimension - 1]++;
1213 // if carryover, set index to 0 and handle carry on a level above
1214 if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1))
1215 parMultidimensionalIndex[ currentDimension - 1]= 0;
1216 else
1217 carry= false;
1218
1219 currentDimension --;
1220 // if dimensions drops below 1 and carry is set than then all indices are 0 again
1221 // this is signalled by returning sal_False
1222 if( currentDimension < 1 && carry)
1223 {
1224 carry= false;
1225 ret= false;
1226 }
1227 }
1228 return ret;
1229}
1230
1231// Determines the size of a certain OLE type. The function takes
1232// only those types into account which are oleautomation types and
1233// can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF).
1234// Currently used in createUnoSequenceWrapper to calculate addresses
1235// for data within a SAFEARRAY.
1236template<class T>
1238{
1239 size_t size;
1240 switch( type)
1241 {
1242 case VT_BOOL: size= sizeof( VARIANT_BOOL);break;
1243 case VT_UI1: size= sizeof( unsigned char);break;
1244 case VT_R8: size= sizeof( double);break;
1245 case VT_R4: size= sizeof( float);break;
1246 case VT_I2: size= sizeof( short);break;
1247 case VT_I4: size= sizeof( long);break;
1248 case VT_BSTR: size= sizeof( BSTR); break;
1249 case VT_ERROR: size= sizeof( SCODE); break;
1250 case VT_DISPATCH:
1251 case VT_UNKNOWN: size= sizeof( IUnknown*); break;
1252 case VT_VARIANT: size= sizeof( VARIANT);break;
1253 default: size= 0;
1254 }
1255 return size;
1256}
1257
1258//If a Sequence is being converted into a SAFEARRAY then we possibly have
1259// to create a SAFEARRAY with multiple dimensions. This is the case when a
1260// Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost
1261// Sequence in the declaration is assumed to represent dimension 1. Because
1262// all Sequence elements of a Sequence can have different length, we have to
1263// determine the maximum length which is then the length of the respective
1264// dimension.
1265// getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1266// in the process.
1267// param rSeq - an Any that has to contain a Sequence
1268// param dim - the dimension for which the number of elements is being determined,
1269// must be one.
1270// param seqElementCounts - contains the maximum number of elements for each
1271// dimension. Index 0 contains the number of dimension one.
1272// After return the Sequence contains the maximum number of
1273// elements for each dimension.
1274// The length of the Sequence must equal the number of dimensions.
1275// param typeClass - TypeClass of the element type that is no Sequence, e.g.
1276// Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1277template<class T>
1279 Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc)
1280{
1281 sal_Int32 dimCount= (*static_cast<uno_Sequence* const *>(rSeq.getValue()))->nElements;
1282 if( dimCount > seqElementCounts[ dim-1])
1283 seqElementCounts.getArray()[ dim-1]= dimCount;
1284
1285 // we need the element type to construct the any that is
1286 // passed into getElementCountAndTypeOfSequence again
1287 typelib_TypeDescription* pSeqDesc= nullptr;
1288 rSeq.getValueTypeDescription( &pSeqDesc);
1289 typelib_TypeDescriptionReference* pElementDescRef= reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqDesc)->pType;
1290
1291 // if the elements are Sequences then do recursion
1292 if( dim < seqElementCounts.getLength() )
1293 {
1294 uno_Sequence* pSeq = *static_cast<uno_Sequence* const*>(rSeq.getValue());
1295 uno_Sequence** arSequences= reinterpret_cast<uno_Sequence**>(pSeq->elements);
1296 for( sal_Int32 i=0; i < dimCount; i++)
1297 {
1298 uno_Sequence* arElement= arSequences[ i];
1299 getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc);
1300 }
1301 }
1302 else
1303 {
1304 // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1305 typeDesc= pElementDescRef;
1306 }
1308}
1309
1310
1311template<class T>
1313{
1314 SAFEARRAY* pArray = nullptr;
1315 sal_uInt32 n = 0;
1316
1317 if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE )
1318 throw IllegalArgumentException(
1319 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
1320 "The UNO argument is not a sequence", nullptr, -1);
1321
1322 uno_Sequence * punoSeq= *static_cast<uno_Sequence* const *>(rSeq.getValue());
1323
1324 typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef();
1325 typelib_TypeDescription* pSeqType= nullptr;
1326 TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef);
1327 typelib_IndirectTypeDescription * pSeqIndDec= reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqType);
1328
1329
1330 typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType;
1331 TYPELIB_DANGER_RELEASE( pSeqType);
1332
1333 typelib_TypeDescription* pSeqElementDesc= nullptr;
1334 TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef);
1335 sal_Int32 nElementSize= pSeqElementDesc->nSize;
1336 n= punoSeq->nElements;
1337
1338 SAFEARRAYBOUND rgsabound[1];
1339 rgsabound[0].lLbound = 0;
1340 rgsabound[0].cElements = n;
1341 VARIANT oleElement;
1342 LONG safeI[1];
1343
1344 pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
1345
1346 Any unoElement;
1347 char * pSeqData= punoSeq->elements;
1348
1349 for (sal_uInt32 i = 0; i < n; i++)
1350 {
1351 unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc);
1352 VariantInit(&oleElement);
1353
1354 anyToVariant(&oleElement, unoElement);
1355
1356 safeI[0] = i;
1357 SafeArrayPutElement(pArray, safeI, &oleElement);
1358
1359 VariantClear(&oleElement);
1360 }
1361 TYPELIB_DANGER_RELEASE( pSeqElementDesc);
1362
1363 return pArray;
1364}
1365
1366/* The argument rObj can contain
1367- UNO struct
1368- UNO interface
1369- UNO interface created by this bridge (adapter factory)
1370- UNO interface created by this bridge ( COM Wrapper)
1371
1372pVar must be initialized.
1373*/
1374template<class T>
1375void UnoConversionUtilities<T>::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar)
1376{
1377 MutexGuard guard(getBridgeMutex());
1378
1380
1381 TypeClass tc = rObj.getValueTypeClass();
1382 if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT)
1383 throw IllegalArgumentException(
1384 "[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
1385 "Cannot create an Automation interface for a UNO type which is not "
1386 "a struct or interface!", nullptr, -1);
1387
1388 if (rObj.getValueTypeClass() == TypeClass_INTERFACE)
1389 {
1390 if (! (rObj >>= xInt))
1391 throw IllegalArgumentException(
1392 "[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
1393 "Could not create wrapper object for UNO object!", nullptr, -1);
1394 //If XInterface is NULL, which is a valid value, then simply return NULL.
1395 if ( ! xInt.is())
1396 {
1397 pVar->vt = VT_UNKNOWN;
1398 pVar->punkVal = nullptr;
1399 return;
1400 }
1401 //make sure we have the main XInterface which is used with a map
1402 xInt.set(xInt, UNO_QUERY);
1403 //If there is already a wrapper for the UNO object then use it
1404
1405 Reference<XInterface> xIntWrapper;
1406 // Does a UNO wrapper exist already ?
1407 auto it_uno = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(xInt.get()));
1408 if(it_uno != UnoObjToWrapperMap.end())
1409 {
1410 xIntWrapper = it_uno->second;
1411 if (xIntWrapper.is())
1412 {
1413 convertSelfToCom(xIntWrapper, pVar);
1414 return;
1415 }
1416 }
1417 // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1418 // or does it supply an IDispatch by its own ?
1419 else
1420 {
1421 Reference<XInterface> xIntComWrapper = xInt;
1422
1423 // Adapter? then get the COM wrapper to which the adapter delegates its calls
1424 auto it = AdapterToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(xInt.get()));
1425 if( it != AdapterToWrapperMap.end() )
1426 xIntComWrapper= reinterpret_cast<XInterface*>(it->second);
1427
1428 if (convertSelfToCom(xIntComWrapper, pVar))
1429 return;
1430 }
1431 }
1432 // If we have no UNO wrapper nor the IDispatch yet then we have to create
1433 // a wrapper. For that we need an XInvocation.
1434
1435 // create an XInvocation using the invocation service
1437 Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj);
1438 if (xInvFactory.is())
1439 {
1440 Sequence<Any> params(2);
1441 params.getArray()[0] = rObj;
1442 params.getArray()[1] <<= OUString("FromOLE");
1443 Reference<XInterface> xInt2 = xInvFactory->createInstanceWithArguments(params);
1444 xInv.set(xInt2, UNO_QUERY);
1445 }
1446
1447 if (xInv.is())
1448 {
1449 Reference<XInterface> xNewWrapper = createUnoWrapperInstance();
1450 Reference<css::lang::XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY);
1451 if (xInitWrapper.is())
1452 {
1453 VARTYPE vartype= getVarType( rObj);
1454
1455 if (xInt.is())
1456 {
1457 Any params[3];
1458 params[0] <<= xInv;
1459 params[1] <<= xInt;
1460 params[2] <<= vartype;
1461 xInitWrapper->initialize( Sequence<Any>(params, 3));
1462 }
1463 else
1464 {
1465 Any params[2];
1466 params[0] <<= xInv;
1467 params[1] <<= vartype;
1468 xInitWrapper->initialize( Sequence<Any>(params, 2));
1469 }
1470
1471 // put the newly created object into a map. If the same object will
1472 // be mapped again and there is already a wrapper then the old wrapper
1473 // will be used.
1474 if(xInt.is()) // only interfaces
1475 UnoObjToWrapperMap[reinterpret_cast<sal_uIntPtr>(xInt.get())]= xNewWrapper;
1476 convertSelfToCom(xNewWrapper, pVar);
1477 return;
1478 }
1479 }
1480}
1481
1482template<class T>
1483void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny,
1484 bool bReduceValueRange /* = sal_True */)
1485{
1486 HRESULT hr = S_OK;
1487 try
1488 {
1489 CComVariant var;
1490
1491 // There is no need to support indirect values, since they're not supported by UNO
1492 if( FAILED(hr= VariantCopyInd( &var, pVariant))) // remove VT_BYREF
1493 throw BridgeRuntimeError(
1494 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
1495 "VariantCopyInd failed for reason : " + OUString::number(hr));
1496
1497 if ( ! convertValueObject( & var, rAny))
1498 {
1499 if ((var.vt & VT_ARRAY) > 0)
1500 {
1501 VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
1502
1503 Sequence<Any> unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags);
1504 rAny.setValue( &unoSeq, cppu::UnoType<decltype(unoSeq)>::get());
1505 }
1506 else
1507 {
1508 switch (var.vt)
1509 {
1510 case VT_EMPTY:
1511 rAny.setValue(nullptr, Type());
1512 break;
1513 case VT_NULL:
1514 rAny.setValue(nullptr, Type());
1515 break;
1516 case VT_I2:
1517 rAny.setValue( & var.iVal, cppu::UnoType<sal_Int16>::get());
1518 break;
1519 case VT_I4:
1520 rAny.setValue( & var.lVal, cppu::UnoType<sal_Int32>::get());
1521 // necessary for use in JavaScript ( see "reduceRange")
1522 if( bReduceValueRange)
1523 reduceRange(rAny);
1524 break;
1525 case VT_R4:
1526 rAny.setValue( & var.fltVal, cppu::UnoType<float>::get());
1527 break;
1528 case VT_R8:
1529 rAny.setValue(& var.dblVal, cppu::UnoType<double>::get());
1530 break;
1531 case VT_CY:
1532 {
1533 Currency cy(var.cyVal.int64);
1534 rAny <<= cy;
1535 break;
1536 }
1537 case VT_DATE:
1538 {
1539 Date d(var.date);
1540 rAny <<= d;
1541 break;
1542 }
1543 case VT_BSTR:
1544 {
1545 OUString b(o3tl::toU(var.bstrVal));
1546 rAny.setValue( &b, cppu::UnoType<decltype(b)>::get());
1547 break;
1548 }
1549 case VT_UNKNOWN:
1550 case VT_DISPATCH:
1551 {
1552 //check if it is a UNO type
1553 CComQIPtr<IUnoTypeWrapper> spType(static_cast<IUnknown*>(var.byref));
1554 if (spType)
1555 {
1556 CComBSTR sName;
1557 if (FAILED(spType->get_Name(&sName)))
1558 throw BridgeRuntimeError(
1559 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1560 "Failed to get the type name from a UnoTypeWrapper!");
1561 Type type;
1562 if (!getType(sName, type))
1563 {
1564 throw CannotConvertException(
1565 OUString::Concat("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1566 "A UNO type with the name: ") + o3tl::toU(LPCOLESTR(sName)) +
1567 "does not exist!",
1568 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
1569 }
1570 rAny <<= type;
1571 }
1572 else
1573 {
1574 rAny = createOleObjectWrapper( & var);
1575 }
1576 break;
1577 }
1578 case VT_ERROR:
1579 {
1580 SCode scode(var.scode);
1581 rAny <<= scode;
1582 break;
1583 }
1584 case VT_BOOL:
1585 {
1586 rAny <<= (var.boolVal == VARIANT_TRUE);
1587 break;
1588 }
1589 case VT_I1:
1590 rAny.setValue( & var.cVal, cppu::UnoType<sal_Int8>::get());
1591 break;
1592 case VT_UI1: // there is no unsigned char in UNO
1593 rAny <<= sal_Int8(var.bVal);
1594 break;
1595 case VT_UI2:
1596 rAny.setValue( & var.uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get() );
1597 break;
1598 case VT_UI4:
1599 rAny.setValue( & var.ulVal, cppu::UnoType<sal_uInt32>::get());
1600 break;
1601 case VT_INT:
1602 rAny.setValue( & var.intVal, cppu::UnoType<sal_Int32>::get());
1603 break;
1604 case VT_UINT:
1605 rAny.setValue( & var.uintVal, cppu::UnoType<sal_uInt32>::get());
1606 break;
1607 case VT_VOID:
1608 rAny.setValue( nullptr, Type());
1609 break;
1610 case VT_DECIMAL:
1611 {
1612 Decimal dec;
1613 dec.Scale = var.decVal.scale;
1614 dec.Sign = var.decVal.sign;
1615 dec.LowValue = var.decVal.Lo32;
1616 dec.MiddleValue = var.decVal.Mid32;
1617 dec.HighValue = var.decVal.Hi32;
1618 rAny <<= dec;
1619 break;
1620 }
1621
1622 default:
1623 break;
1624 }
1625 }
1626 }
1627 }
1628 catch (const IllegalArgumentException &)
1629 {
1630 throw;
1631 }
1632 catch (const CannotConvertException &)
1633 {
1634 throw;
1635 }
1636 catch (const BridgeRuntimeError &)
1637 {
1638 throw;
1639 }
1640 catch (const Exception & e)
1641 {
1642 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1643 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
1644 e.Message);
1645 }
1646 catch(...)
1647 {
1648 throw BridgeRuntimeError(
1649 "[automation bridge] unexpected exception in "
1650 "UnoConversionUtilities<T>::variantToAny !");
1651 }
1652
1653}
1654// The function converts an IUnknown* into a UNO interface or struct. The
1655// IUnknown pointer can constitute different kind of objects:
1656// 1. a wrapper of a UNO struct (the wrapper was created by this bridge)
1657// 2. a wrapper of a UNO interface (created by this bridge)
1658// 3. a dispatch object that implements UNO interfaces
1659// 4. a dispatch object.
1660
1661// If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to
1662// implement the interface described by "aType". Moreover it ( pUnknown) can implement
1663// several other
1664// UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see
1665// #define) property. That property contains all names of interfaces.
1666// "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g.
1667// IUnknownWrapper. Additionally an object of type "aType" is created by help
1668// of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of
1669// "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports
1670// more than one UNO interfaces, as can be determined by the property
1671// SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that
1672// implements all these interfaces.
1673// This is only done if "pUnknown" is not already a UNO wrapper,
1674// that is it is actually NOT a UNO object that was converted to a COM object. If it is an
1675// UNO wrapper than the original UNO object is being extracted, queried for "aType" (if
1676// it is no struct) and returned.
1677template<class T>
1679{
1680 //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY
1681 if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY)
1682 throw IllegalArgumentException(
1683 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1684 "The VARIANT does not contain an object type! ", nullptr, -1);
1685
1686 MutexGuard guard( getBridgeMutex());
1687
1688 CComPtr<IUnknown> spUnknown;
1689 CComPtr<IDispatch> spDispatch;
1690
1691 if (pVar->vt == VT_UNKNOWN)
1692 {
1693 spUnknown = pVar->punkVal;
1694 if (spUnknown)
1695 spUnknown.QueryInterface( & spDispatch.p);
1696 }
1697 else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != nullptr)
1698 {
1699 CComPtr<IDispatch> spDispatch2(pVar->pdispVal);
1700 if (spDispatch2)
1701 spDispatch2.QueryInterface( & spUnknown.p);
1702 }
1703
1704 static Type VOID_TYPE;
1705 Any ret;
1706 //If no Type is provided and pVar contains IUnknown then we return a XInterface.
1707 //If pVar contains an IDispatch then we return a XInvocation.
1708 Type desiredType = aType;
1709
1710 if (aType == VOID_TYPE)
1711 {
1712 switch (pVar->vt)
1713 {
1714 case VT_EMPTY:
1715 case VT_UNKNOWN:
1716 desiredType = cppu::UnoType<XInterface>::get();
1717 break;
1718 case VT_DISPATCH:
1719 desiredType = cppu::UnoType<XInvocation>::get();
1720 break;
1721 default:
1722 desiredType = aType;
1723 }
1724 }
1725
1726 // COM pointer are NULL, no wrapper required
1727 if (spUnknown == nullptr)
1728 {
1730 if( aType.getTypeClass() == TypeClass_INTERFACE)
1731 ret.setValue( &xInt, aType);
1732 else if( aType.getTypeClass() == TypeClass_STRUCT)
1733 ret.setValue( nullptr, aType);
1734 else
1735 ret <<= xInt;
1736 return ret;
1737 }
1738
1739
1740 // Check if "spUnknown" is a UNO wrapper, that is a UNO object that has been
1741 // passed to COM. Then it supports IUnoObjectWrapper
1742 // and we extract the original UNO object.
1743 CComQIPtr<IUnoObjectWrapper> spUno( spUnknown);
1744 if( spUno)
1745 { // it is a wrapper
1747 if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt)))
1748 {
1749 ret <<= xInt;
1750 }
1751 else
1752 {
1753 Any any;
1754 if( SUCCEEDED( spUno->getOriginalUnoStruct(&any)))
1755 ret= any;
1756 }
1757 return ret;
1758 }
1759
1760 // "spUnknown" is a real COM object.
1761 // Before we create a new wrapper object we check if there is an existing wrapper
1762 // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who
1763 // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent
1764 // particular UNO interfaces.
1765 Reference<XInterface> xIntWrapper;
1766 auto cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(spUnknown.p));
1767 if(cit_currWrapper != ComPtrToWrapperMap.end())
1768 xIntWrapper = cit_currWrapper->second;
1769 if (xIntWrapper.is())
1770 {
1771 //Try to find an adapter for the wrapper
1772 //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as
1773 //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references
1774 //to the wrapper.
1775 auto it = WrapperToAdapterMap.find(reinterpret_cast<sal_uIntPtr>(xIntWrapper.get()));
1776 if (it == WrapperToAdapterMap.end())
1777 {
1778 // No adapter available.
1779 //The COM component could be a UNO object. Then we need to provide
1780 // a proxy that implements all interfaces
1781 Sequence<Type> seqTypes= getImplementedInterfaces(spUnknown);
1782 Reference<XInterface> xIntAdapter;
1783 if (seqTypes.getLength() > 0)
1784 {
1785 //It is a COM UNO object
1786 xIntAdapter = createAdapter(seqTypes, xIntWrapper);
1787 }
1788 else
1789 {
1790 // Some ordinary COM object
1791 xIntAdapter = xIntWrapper;
1792 }
1793 // return the wrapper directly, return XInterface or XInvocation
1794 ret = xIntWrapper->queryInterface(desiredType);
1795 if ( ! ret.hasValue())
1796 throw IllegalArgumentException(
1797 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1798 "The COM object is not suitable for the UNO type: " +
1799 desiredType.getTypeName(), nullptr, -1);
1800 }
1801 else
1802 {
1803 //There is an adapter available
1804 Reference<XInterface> xIntAdapter(reinterpret_cast<XInterface*>(it->second));
1805 ret = xIntAdapter->queryInterface( desiredType);
1806 if ( ! ret.hasValue())
1807 throw IllegalArgumentException(
1808 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1809 "The COM object is not suitable for the UNO type: " +
1810 desiredType.getTypeName(), nullptr, -1);
1811 }
1812
1813 return ret;
1814 }
1815 // No existing wrapper. Therefore create a new proxy.
1816 // If the object implements UNO interfaces then get the types.
1817 Sequence<Type> seqTypes = getImplementedInterfaces(spUnknown);
1818 if (seqTypes.getLength() == 0 &&
1819 aType != VOID_TYPE && aType != cppu::UnoType<XInvocation>::get())
1820 {
1821 seqTypes = Sequence<Type>( & aType, 1);
1822 }
1823
1824 //There is no existing wrapper, therefore we create one for the real COM object
1825 Reference<XInterface> xIntNewProxy= createComWrapperInstance();
1826 if ( ! xIntNewProxy.is())
1827 throw BridgeRuntimeError(
1828 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1829 "Could not create proxy object for COM object!");
1830
1831 // initialize the COM wrapper
1832 Reference<XInitialization> xInit( xIntNewProxy, UNO_QUERY);
1833 OSL_ASSERT( xInit.is());
1834
1835 Any params[3];
1836 params[0] <<= reinterpret_cast<sal_uIntPtr>(spUnknown.p);
1837 params[1] <<= (pVar->vt == VT_DISPATCH);
1838 params[2] <<= seqTypes;
1839
1840 xInit->initialize( Sequence<Any>( params, 3));
1841 ComPtrToWrapperMap[reinterpret_cast<sal_uInt64>(spUnknown.p)] = xIntNewProxy;
1842
1843 // we have a wrapper object
1844 //The wrapper implements already XInvocation and XInterface. If
1845 //param aType is void then the object is supposed to have XInvocation.
1846 if (aType == cppu::UnoType<XInvocation>::get()||
1847 (aType == VOID_TYPE && seqTypes.getLength() == 0 ))
1848 {
1849 ret = xIntNewProxy->queryInterface(desiredType);
1850 }
1851 else
1852 {
1853 Reference<XInterface> xIntAdapter =
1854 createAdapter(seqTypes, xIntNewProxy);
1855 ret = xIntAdapter->queryInterface(desiredType);
1856 }
1857 return ret;
1858}
1859template<class T>
1861 const Reference<XInterface>& receiver)
1862{
1863 Reference< XInterface> xIntAdapterFac;
1864 xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY);
1865 // We create an adapter object that does not only implement the required type but also
1866 // all types that the COM object pretends to implement. A COM object must therefore
1867 // support the property "_implementedInterfaces".
1868 Reference<XInterface> xIntAdapted;
1869 Reference<XInvocation> xInv(receiver, UNO_QUERY);
1870 Reference<XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY);
1871 if( xAdapterFac.is())
1872 xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes);
1873
1874 if( !xIntAdapted.is())
1875 {
1876 throw BridgeRuntimeError(
1877 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1878 "Could not create a proxy for COM object! Creation of adapter failed.");
1879 }
1880
1881 // Put the pointer to the wrapper object and the interface pointer of the adapted interface
1882 // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO
1883 // object is a wrapped COM object. In that case we extract the original COM object rather than
1884 // creating a wrapper around the UNO object.
1885 typedef std::unordered_map<sal_uInt64,sal_uInt64>::value_type VALUE;
1886 AdapterToWrapperMap.insert( VALUE( reinterpret_cast<sal_uInt64>(xIntAdapted.get()), reinterpret_cast<sal_uInt64>(receiver.get())));
1887 WrapperToAdapterMap.insert( VALUE( reinterpret_cast<sal_uInt64>(receiver.get()), reinterpret_cast<sal_uInt64>(xIntAdapted.get())));
1888
1889 return xIntAdapted;
1890}
1891// "convertValueObject" converts a JScriptValue object contained in "var" into
1892// an any. The type contained in the any is stipulated by a "type value" thas
1893// was set within the JScript script on the value object ( see JScriptValue).
1894template<class T>
1895bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any)
1896{
1897 bool ret = false;
1898 try
1899 {
1900 bool bFail = false;
1901 HRESULT hr= S_OK;
1902 CComVariant varDisp;
1903
1904 if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var)))
1905 {
1906 CComPtr <IJScriptValueObject> spValue;
1907 VARIANT_BOOL varBool;
1908 CComBSTR bstrType;
1909 CComVariant varValue;
1910 CComPtr<IDispatch> spDisp( varDisp.pdispVal);
1911 if(spDisp)
1912 {
1913 if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject),
1914 reinterpret_cast<void**> (&spValue))))
1915 {
1916 ret = true; // is a ValueObject
1917 //If it is an out - param then it does not need to be converted. In/out and
1918 // in params does so.
1919 if (SUCCEEDED(hr= spValue->IsOutParam( &varBool)))
1920 {
1921 // if varBool == true then no conversion needed because out param
1922 if (varBool == VARIANT_FALSE)
1923 {
1924 if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue)))
1925 {
1926 Type type;
1927 if (getType(bstrType, type))
1928 variantToAny( & varValue, any, type);
1929 else
1930 bFail = true;
1931 }
1932 else
1933 bFail = true;
1934 }
1935 }
1936 else
1937 bFail = true;
1938 }
1939 }
1940 }
1941 else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE)
1942 bFail = true;
1943
1944 if (bFail)
1945 throw BridgeRuntimeError(
1946 "[automation bridge] Conversion of ValueObject failed ");
1947 }
1948 catch (const BridgeRuntimeError &)
1949 {
1950 throw;
1951 }
1952 catch (const Exception & e)
1953 {
1954 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1955 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
1956 e.Message);
1957 }
1958 catch(...)
1959 {
1960 throw BridgeRuntimeError(
1961 "[automation bridge] unexpected exception in "
1962 "UnoConversionUtilities<T>::convertValueObject !");
1963 }
1964 return ret;
1965}
1966
1967template<class T>
1968void UnoConversionUtilities<T>::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type)
1969{
1970 try
1971 {
1972 if( pvar->vt != VT_DISPATCH)
1973 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1974 "Conversion of dispatch object to Sequence failed!");
1975 IDispatchEx* pdispEx;
1976 HRESULT hr;
1977 if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx,
1978 reinterpret_cast<void**>( &pdispEx))))
1979 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1980 "Conversion of dispatch object to Sequence failed!");
1981
1982 DISPID dispid;
1983 DISPPARAMS param= {nullptr,nullptr,0,0};
1984 CComVariant result;
1985
1986 OLECHAR const * sLength= L"length";
1987
1988 // Get the length of the array. Can also be obtained through GetNextDispID. The
1989 // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
1990 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, const_cast<OLECHAR **>(&sLength), 1, LOCALE_USER_DEFAULT, &dispid)))
1991 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1992 "Conversion of dispatch object to Sequence failed!");
1993 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1994 &param, &result, nullptr, nullptr)))
1995 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1996 "Conversion of dispatch object to Sequence failed!");
1997 if( FAILED( VariantChangeType( &result, &result, 0, VT_I4)))
1998 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1999 "Conversion of dispatch object to Sequence failed!");
2000 LONG length= result.lVal;
2001
2002 result.Clear();
2003
2004 // get a few basic facts about the sequence, and reallocate:
2005 // create the Sequences
2006 // get the size of the elements
2007 typelib_TypeDescription *pDesc= nullptr;
2008 type.getDescription( &pDesc);
2009
2010 typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast<typelib_IndirectTypeDescription*>(pDesc);
2011 typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements
2012 Type elemType( pSeqElemDescRef);
2013 _typelib_TypeDescription* pSeqElemDesc=nullptr;
2014 TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef);
2015 sal_uInt32 nelementSize= pSeqElemDesc->nSize;
2016 TYPELIB_DANGER_RELEASE( pSeqElemDesc);
2017
2018 uno_Sequence *p_uno_Seq;
2019 uno_sequence_construct( &p_uno_Seq, pDesc, nullptr, length, cpp_acquire);
2020
2021 typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass;
2022 char *pArray= p_uno_Seq->elements;
2023
2024 // Get All properties in the object, convert their values to the expected type and
2025 // put them into the passed in sequence
2026 for( sal_Int32 i= 0; i< length; i++)
2027 {
2028 OUString ousIndex=OUString::number( i);
2029 OLECHAR* sindex = const_cast<OLECHAR *>(o3tl::toW(ousIndex.getStr()));
2030
2031 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid)))
2032 {
2033 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2034 "Conversion of dispatch object to Sequence failed!");
2035 }
2036 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
2037 &param, &result, nullptr, nullptr)))
2038 {
2039 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2040 "Conversion of dispatch object to Sequence failed!");
2041 }
2042
2043 // If the result is VT_DISPATCH than the Sequence's element type could be Sequence
2044 // Look that up in the CoreReflection to make clear.
2045 // That requires a recursiv conversion
2046 Any any;
2047 // Destination address within the out-Sequence "anySeq" where to copy the next converted element
2048 void* pDest= pArray + (i * nelementSize);
2049
2050 if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE)
2051 {
2052 variantToAny( &result, any, elemType, false);
2053 // copy the converted VARIANT, that is a Sequence to the Sequence
2054 uno_Sequence * p_unoSeq= *static_cast<uno_Sequence* const *>(any.getValue());
2055 // just copy the pointer of the uno_Sequence
2056 // nelementSize should be 4 !!!!
2057 memcpy( pDest, &p_unoSeq, nelementSize);
2058 osl_atomic_increment( &p_unoSeq->nRefCount);
2059 }
2060 else // Element type is no Sequence -> do one conversion
2061 {
2062 variantToAny( &result, any, elemType, false);
2063 if( typeElement == typelib_TypeClass_ANY)
2064 {
2065 // copy the converted VARIANT to the Sequence
2066 uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface,
2067 cpp_acquire, cpp_release);
2068 }
2069 else
2070 {
2071 // type after conversion must be the element type of the sequence
2072 OSL_ENSURE(any.getValueTypeClass() == css::uno::TypeClass(typeElement), "wrong conversion");
2073 uno_type_assignData( pDest, pSeqElemDescRef,const_cast<void*>( any.getValue()), any.getValueTypeRef(),
2074 cpp_queryInterface, cpp_acquire, cpp_release);
2075 }
2076 }
2077 } // else
2078 result.Clear();
2079 anySeq.setValue( &p_uno_Seq, pDesc);
2080 uno_destructData( &p_uno_Seq, pDesc, cpp_release);
2082 }
2083 catch (const BridgeRuntimeError &)
2084 {
2085 throw;
2086 }
2087 catch (const Exception & e)
2088 {
2089 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
2090 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
2091 e.Message);
2092 }
2093 catch(...)
2094 {
2095 throw BridgeRuntimeError(
2096 "[automation bridge] unexpected exception in "
2097 "UnoConversionUtilities<T>::convertValueObject !");
2098 }
2099}
2100
2101/* The argument unotype is the type that is expected by the currently called UNO function.
2102 For example: []long, [][]long. If the function calls itself recursively then the element type
2103 is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then
2104 unotype has to be either void or [][]long. When the function calls itself recursively then
2105 it passes the element type which is []long.
2106*/
2107template<class T>
2109 unsigned int dimCount, unsigned int actDim, LONG* index, VARTYPE type, const Type& unotype)
2110{
2111 LONG lBound;
2112 LONG uBound;
2113 LONG nCountElements;
2114
2115 SafeArrayGetLBound(pArray, actDim, &lBound);
2116 SafeArrayGetUBound(pArray, actDim, &uBound);
2117 nCountElements= uBound - lBound +1;
2118
2119 Sequence<Any> anySeq(nCountElements);
2120 Any* pUnoArray = anySeq.getArray();
2121
2122 for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++)
2123 {
2124 if (actDim > 1 )
2125 {
2126 Sequence<Any> element = createOleArrayWrapperOfDim(pArray, dimCount,
2127 actDim - 1, index, type, getElementTypeOfSequence(unotype));
2128
2129 pUnoArray[index[actDim - 1] - lBound].setValue(&element, cppu::UnoType<decltype(element)>::get());
2130 }
2131 else
2132 {
2133 VARIANT variant;
2134
2135 VariantInit(&variant);
2136
2137 V_VT(&variant) = type;
2138
2139 switch (type)
2140 {
2141 case VT_I2:
2142 SafeArrayGetElement(pArray, index, &V_I2(&variant));
2143 break;
2144 case VT_I4:
2145 SafeArrayGetElement(pArray, index, &V_I4(&variant));
2146 break;
2147 case VT_R4:
2148 SafeArrayGetElement(pArray, index, &V_R4(&variant));
2149 break;
2150 case VT_R8:
2151 SafeArrayGetElement(pArray, index, &V_R8(&variant));
2152 break;
2153 case VT_CY:
2154 SafeArrayGetElement(pArray, index, &V_CY(&variant));
2155 break;
2156 case VT_DATE:
2157 SafeArrayGetElement(pArray, index, &V_DATE(&variant));
2158 break;
2159 case VT_BSTR:
2160 SafeArrayGetElement(pArray, index, &V_BSTR(&variant));
2161 break;
2162 case VT_DISPATCH:
2163 SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant));
2164 break;
2165 case VT_ERROR:
2166 SafeArrayGetElement(pArray, index, &V_ERROR(&variant));
2167 break;
2168 case VT_BOOL:
2169 SafeArrayGetElement(pArray, index, &V_BOOL(&variant));
2170 break;
2171 case VT_VARIANT:
2172 SafeArrayGetElement(pArray, index, &variant);
2173 break;
2174 case VT_UNKNOWN:
2175 SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant));
2176 break;
2177 case VT_I1:
2178 SafeArrayGetElement(pArray, index, &V_I1(&variant));
2179 break;
2180 case VT_UI1:
2181 SafeArrayGetElement(pArray, index, &V_UI1(&variant));
2182 break;
2183 case VT_UI2:
2184 SafeArrayGetElement(pArray, index, &V_UI2(&variant));
2185 break;
2186 case VT_UI4:
2187 SafeArrayGetElement(pArray, index, &V_UI4(&variant));
2188 break;
2189 default:
2190 break;
2191 }
2192
2193 if( unotype.getTypeClass() == TypeClass_VOID)
2194 // the function was called without specifying the destination type
2195 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], false);
2196 else
2197 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound],
2198 getElementTypeOfSequence(unotype), false);
2199
2200 VariantClear(&variant);
2201 }
2202 }
2203 return anySeq;
2204}
2205
2206template<class T>
2208{
2209 Type retValue;
2210 if( seqType.getTypeClass() != TypeClass_VOID)
2211 {
2212 OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE);
2213 typelib_TypeDescription* pDescSeq= nullptr;
2214 seqType.getDescription(& pDescSeq);
2215 retValue = Type(reinterpret_cast<typelib_IndirectTypeDescription *>(pDescSeq)->pType);
2217 }
2218 return retValue;
2219}
2220template<class T>
2221Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType)
2222{
2223 sal_uInt32 dim = SafeArrayGetDim(pArray);
2224
2225 Sequence<Any> ret;
2226
2227 if (dim > 0)
2228 {
2229 std::unique_ptr<LONG[]> sarIndex(new LONG[dim]);
2230 LONG * index = sarIndex.get();
2231
2232 for (unsigned int i = 0; i < dim; i++)
2233 {
2234 index[i] = 0;
2235 }
2236
2237 ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType);
2238 }
2239
2240 return ret;
2241}
2242
2243// If a VARIANT has the type VT_DISPATCH it can either be a JScript Array
2244// or some other object. This function finds out if it is such an array or
2245// not. Currently there's no way to make sure it's an array
2246// so we assume that when the object has a property "0" then it is an Array.
2247// A JScript has property like "0", "1", "2" etc. which represent the
2248// value at the corresponding index of the array
2249template<class T>
2251{
2252 OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH");
2253 HRESULT hr;
2254 OLECHAR const * sindex= L"0";
2255 DISPID id;
2256 if ( rvar->vt == VT_DISPATCH && rvar->pdispVal )
2257 {
2258 hr= rvar->pdispVal->GetIDsOfNames(
2259 IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT,
2260 &id);
2261
2262 if( SUCCEEDED ( hr) )
2263 return true;
2264 }
2265
2266 return false;
2267}
2268
2269template<class T>
2271{
2272 VARTYPE ret;
2273 switch( type)
2274 {
2275 case TypeClass_INTERFACE: ret= VT_DISPATCH;
2276 break;
2277 case TypeClass_STRUCT: ret= VT_DISPATCH;
2278 break;
2279 case TypeClass_ENUM: ret= VT_I4;
2280 break;
2281 case TypeClass_SEQUENCE: ret= VT_ARRAY;
2282 break;
2283 case TypeClass_ANY: ret= VT_VARIANT;
2284 break;
2285 case TypeClass_BOOLEAN: ret= VT_BOOL;
2286 break;
2287 case TypeClass_CHAR: ret= VT_I2;
2288 break;
2289 case TypeClass_STRING: ret= VT_BSTR;
2290 break;
2291 case TypeClass_FLOAT: ret= VT_R4;
2292 break;
2293 case TypeClass_DOUBLE: ret= VT_R8;
2294 break;
2295 case TypeClass_BYTE: ret= VT_UI1;
2296 break;
2297 case TypeClass_SHORT: ret= VT_I2;
2298 break;
2299 case TypeClass_LONG: ret= VT_I4;
2300 break;
2301 case TypeClass_UNSIGNED_SHORT: ret= VT_UI2;
2302 break;
2303 case TypeClass_UNSIGNED_LONG: ret= VT_UI4;
2304 break;
2305 default:
2306 ret= VT_EMPTY;
2307 }
2308 return ret;
2309}
2310
2311template<class T>
2313{
2314 Sequence<Type> seqTypes;
2315 CComDispatchDriver disp( pUnk);
2316 if( disp)
2317 {
2318 CComVariant var;
2319 HRESULT hr= S_OK;
2320 // There are two different property names possible.
2321 if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var)))
2322 {
2323 hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var);
2324 }
2325 if (SUCCEEDED( hr))
2326 {
2327 // we expect an array( SafeArray or IDispatch) of Strings.
2328 Any anyNames;
2329 variantToAny( &var, anyNames, cppu::UnoType<Sequence<Any>>::get());
2330 Sequence<Any> seqAny;
2331 if( anyNames >>= seqAny)
2332 {
2333 seqTypes.realloc( seqAny.getLength());
2334 auto pseqTypes = seqTypes.getArray();
2335 for( sal_Int32 i=0; i < seqAny.getLength(); i++)
2336 {
2337 OUString typeName;
2338 seqAny[i] >>= typeName;
2339 pseqTypes[i]= Type( TypeClass_INTERFACE, typeName);
2340 }
2341 }
2342 }
2343 }
2344 return seqTypes;
2345}
2346template<class T>
2348{
2349 if ( ! m_typeConverter.is())
2350 {
2351 MutexGuard guard(getBridgeMutex());
2352 if ( ! m_typeConverter.is())
2353 {
2354 Reference<XInterface> xIntConverter =
2355 m_smgr->createInstance("com.sun.star.script.Converter");
2356 if (xIntConverter.is())
2357 m_typeConverter.set(xIntConverter, UNO_QUERY);
2358 }
2359 }
2360 return m_typeConverter;
2361}
2362
2363/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const Any & any
double d
All methods are allowed to throw at least a BridgeRuntimeError.
VARTYPE mapTypeClassToVartype(TypeClass type)
Sequence< Any > createOleArrayWrapperOfDim(SAFEARRAY *pArray, unsigned int dimCount, unsigned int actDim, LONG *index, VARTYPE type, const Type &unotype)
Reference< XTypeConverter > getTypeConverter()
Any createOleObjectWrapper(VARIANT *pVar, const Type &aType=Type())
UnoConversionUtilities(const Reference< XMultiServiceFactory > &smgr)
UnoConversionUtilities(const Reference< XMultiServiceFactory > &xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass)
SAFEARRAY * createUnoSequenceWrapper(const Any &rSeq)
void anyToVariant(VARIANT *pVariant, const Any &rAny)
converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4 a sal_Unicode chara...
SAFEARRAY * createUnoSequenceWrapper(const Any &rSeq, VARTYPE elemtype)
void anyToVariant(VARIANT *pVariant, const Any &rAny, VARTYPE type)
static bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 *parDimensionLength, sal_Int32 *parMultidimensionalIndex)
bool convertValueObject(const VARIANTARG *var, Any &any)
void createUnoObjectWrapper(const Any &rObj, VARIANT *pVar)
void dispatchExObject2Sequence(const VARIANTARG *pvar, Any &anySeq, const Type &type)
Reference< XInterface > createAdapter(const Sequence< Type > &types, const Reference< XInterface > &receiver)
Sequence< Type > getImplementedInterfaces(IUnknown *pUnk)
Reference< XTypeConverter > m_typeConverter
void variantToAny(const VARIANT *pVariant, Any &rAny, bool bReduceValueRange=true)
Reference< XMultiServiceFactory > m_smgr
static bool isJScriptArray(const VARIANT *pvar)
Reference< XMultiServiceFactory > m_smgrRemote
Sequence< Any > createOleArrayWrapper(SAFEARRAY *pArray, VARTYPE type, const Type &unotype=Type())
virtual Reference< XInterface > createUnoWrapperInstance()=0
static Type getElementTypeOfSequence(const Type &seqType)
void variantToAny(const VARIANTARG *pArg, Any &rAny, const Type &ptype, bool bReduceValueRange=true)
This method converts variants arguments in calls from COM -> UNO.
virtual Reference< XInterface > createComWrapperInstance()=0
Reference< XSingleServiceFactory > m_xInvocationFactoryLocal
Reference< XSingleServiceFactory > m_xInvocationFactoryRemote
Reference< XSingleServiceFactory > getInvocationFactory(const Any &anyObject)
static size_t getOleElementSize(VARTYPE type)
void getElementCountAndTypeOfSequence(const Any &rSeq, sal_Int32 dim, Sequence< sal_Int32 > &seqElementCounts, TypeDescription &typeDesc)
css::uno::Type const & get()
IJScriptValueObject VARIANT value
Definition: comifaces.hxx:28
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
sal_Bool SAL_CALL uno_type_assignData(void *pDest, typelib_TypeDescriptionReference *pDestType, void *pSource, typelib_TypeDescriptionReference *pSourceType, uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
float v
Reference< XSingleServiceFactory > xFactory
OUString sName
sal_Int64 n
MetadataImporterPluginType * result
Definition: main.m:195
struct _typelib_TypeDescription typelib_TypeDescription
size
@ Exception
Type
int i
index
VBAHELPER_DLLPUBLIC css::uno::Reference< css::script::XTypeConverter > const & getTypeConverter(const css::uno::Reference< css::uno::XComponentContext > &xContext)
Mutex * getBridgeMutex()
Definition: ole2uno.cxx:40
bool getType(BSTR name, Type &type)
Definition: unoobjw.cxx:1557
VARTYPE getVarType(const Any &val)
Definition: unoobjw.cxx:3423
OUString typeName
#define VT_UINT
#define VT_UI2
#define VT_ARRAY
#define VT_DATE
#define VT_EMPTY
#define VT_R4
#define VT_UI4
#define VT_BSTR
#define VT_R8
#define VT_VARIANT
#define VT_INT
#define VT_ERROR
#define VT_DECIMAL
#define VT_BYREF
#define VT_NULL
#define VT_BOOL
#define VT_I1
#define VT_CY
#define VT_I4
#define VT_UI1
#define VT_I2
LONG
sal_Bool SAL_CALL uno_sequence_construct(uno_Sequence **ppSequence, typelib_TypeDescription *pTypeDescr, void *pElements, sal_Int32 len, uno_AcquireFunc acquire) SAL_THROW_EXTERN_C()
return hr
Definition: so_activex.cxx:446
void SAL_CALL typelib_typedescription_release(typelib_TypeDescription *pTD) SAL_THROW_EXTERN_C()
unsigned char sal_uInt8
signed char sal_Int8
ResultType type
#define SUPPORTED_INTERFACES_PROP2
unsigned char BYTE
bool convertSelfToCom(T &unoInterface, VARIANT *pVar)
std::unordered_map< sal_uIntPtr, WeakReference< XInterface > > ComPtrToWrapperMap
Definition: oleobjw.cxx:80
std::unordered_map< sal_uIntPtr, sal_uIntPtr > AdapterToWrapperMap
Definition: oleobjw.cxx:71
std::unordered_map< sal_uIntPtr, sal_uIntPtr > WrapperToAdapterMap
Definition: oleobjw.cxx:78
#define IUNKNOWN_WRAPPER_IMPL
#define INTERFACE_ADAPTER_FACTORY
std::unordered_map< sal_uIntPtr, WeakReference< XInterface > > UnoObjToWrapperMap
Definition: unoobjw.cxx:108
#define INTERFACE_OLE_WRAPPER_IMPL
#define SUPPORTED_INTERFACES_PROP
void reduceRange(Any &any)
#define INVOCATION_SERVICE
bool createUnoTypeWrapper(BSTR sTypeName, VARIANT *pVar)