@@ -128,9 +128,13 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep
128
128
}
129
129
V_DISPATCH (v ) = V_DISPATCH (& obj -> v );
130
130
} else {
131
- /* pass the variant by reference */
132
- V_VT (v ) = VT_VARIANT | VT_BYREF ;
133
- V_VARIANTREF (v ) = & obj -> v ;
131
+ if (V_VT (& obj -> v ) & VT_BYREF ) { //Allready by reference
132
+ memcpy (v , & obj -> v , sizeof (VARIANT ));
133
+ } else {
134
+ /* pass the variant by reference */
135
+ V_VT (v ) = VT_VARIANT | VT_BYREF ;
136
+ V_VARIANTREF (v ) = & obj -> v ;
137
+ }
134
138
}
135
139
} else {
136
140
/* export the PHP object using our COM wrapper */
@@ -429,6 +433,7 @@ PHP_METHOD(variant, __construct)
429
433
php_com_dotnet_object * obj ;
430
434
zval * zvalue = NULL ;
431
435
HRESULT res ;
436
+ char * msg = NULL ;
432
437
433
438
if (ZEND_NUM_ARGS () == 0 ) {
434
439
/* just leave things as-is - an empty variant */
@@ -454,22 +459,113 @@ PHP_METHOD(variant, __construct)
454
459
/* Only perform conversion if variant not already of type passed */
455
460
if ((ZEND_NUM_ARGS () >= 2 ) && (vt != V_VT (& obj -> v ))) {
456
461
457
- /* If already an array and VT_ARRAY is passed then:
458
- - if only VT_ARRAY passed then do not perform a conversion
459
- - if VT_ARRAY plus other type passed then perform conversion
460
- */
462
+ /**
463
+ * VT_BYREF, VT_VARIANT and VT_PTR functionality
464
+ *
465
+ * All of those types makes reference to another php_com_dotnet_object incrementing their refcounters.
466
+ * If you use VT_VARIANT then it will be VT_BYREF | VT_VARIANT.
467
+ * If you use VT_PTR then you get reference to VARIANTTAG.
468
+ * If you use VT_PTR | VT_BYREF then you get reference to VARIANTTAG's variable dependently of their type.
469
+ *
470
+ * For future: may be need to check if remote variable is changed.
471
+ */
472
+ if ((vt & VT_BYREF ) || ((vt & ~VT_BYREF ) == VT_VARIANT ) || ((vt & ~VT_BYREF ) == VT_PTR )) {
473
+
474
+ if ((vt & VT_BYREF ) && (vt & ~VT_BYREF != VT_VARIANT ) && (vt & ~VT_BYREF != VT_PTR )) {
475
+ spprintf (& msg , E_INVALIDARG , "VT_BYREF should be used alone or with VT_VARIANT or with VT_PTR" );
476
+ php_com_throw_exception (res , msg );
477
+ efree (msg );
478
+ return ;
479
+ }
480
+
481
+ ZVAL_DEREF (zvalue );
482
+ if (!php_com_is_valid_object (zvalue )) {
483
+ spprintf (& msg , 0 , "To use VT_BYREF or VT_VARIANT you must have another VARIANT object as 'value'" );
484
+ php_com_throw_exception (E_INVALIDARG , msg );
485
+ efree (msg );
486
+ return ;
487
+ }
488
+
489
+ //Save a reference to original object
490
+ zval_dtor (& obj -> byref ); //Remove old value if exist
491
+ ZVAL_NEW_REF (& obj -> byref , zvalue ); //Set new reference to zvalue
492
+ Z_ADDREF_P (zvalue ); //Increment their counter
493
+
494
+ php_com_dotnet_object * src = CDNO_FETCH (zvalue );
495
+ VariantClear (& obj -> v ); //Remove our default value
496
+
497
+ switch (V_VT (& src -> v )) {
498
+ case VT_I2 :
499
+ case VT_I4 :
500
+ case VT_R4 :
501
+ case VT_R8 :
502
+ case VT_CY :
503
+ case VT_DATE :
504
+ case VT_BSTR :
505
+ case VT_DISPATCH :
506
+ case VT_ERROR :
507
+ case VT_BOOL :
508
+ case VT_UNKNOWN :
509
+ case VT_I1 :
510
+ case VT_UI1 :
511
+ case VT_UI2 :
512
+ case VT_UI4 :
513
+ case VT_I8 :
514
+ case VT_UI8 :
515
+ case VT_INT :
516
+ case VT_UINT :
517
+ case VT_VOID :
518
+ case VT_HRESULT :
519
+ case VT_PTR :
520
+ case VT_SAFEARRAY :
521
+ case VT_INT_PTR :
522
+ case VT_UINT_PTR :
523
+ obj -> v .byref = & V_NONE (& src -> v );
524
+ break ;
525
+ case VT_DECIMAL :
526
+ obj -> v .byref = & V_DECIMAL (& src -> v );
527
+ break ;
528
+ default :
529
+ obj -> v .byref = & src -> v ;
530
+ V_VT (& obj -> v ) = VT_BYREF | VT_VARIANT ;
531
+ break ;
532
+ }
533
+
534
+ switch (vt & ~VT_BYREF ) {
535
+ case VT_PTR :
536
+ V_VT (& obj -> v ) = VT_PTR ;
537
+ if (!(vt & VT_BYREF )) //If only VT_PTR is used, then ptr is referenced to VARIANT, otherway to value
538
+ obj -> v .byref = & src -> v ;
539
+ break ;
540
+ case VT_VARIANT :
541
+ V_VT (& obj -> v ) = vt ;
542
+ V_VARIANTREF (& obj -> v ) = & src -> v ;
543
+ break ;
544
+ default :
545
+ V_VT (& obj -> v ) = V_VT (& src -> v ) | VT_BYREF ;
546
+ break ;
547
+ }
548
+ vt = VT_EMPTY ; //Prevent future VariantChangeType
549
+ }
550
+
551
+
552
+ /**
553
+ * VT_ARRAY functionality
554
+ *
555
+ * If already an array and VT_ARRAY is passed then:
556
+ * - if only VT_ARRAY passed then do not perform a conversion
557
+ * - if VT_ARRAY plus other type passed then perform conversion
558
+ */
461
559
462
560
res = S_OK ;
463
561
SAFEARRAYBOUND Bound ;
464
562
465
- if (!(V_VT (& obj -> v ) & VT_BYREF ) && //not supported
466
- (vt & ~VT_ARRAY ) && //new variant have some type except VT_ARRAY
467
- (V_VT (& obj -> v ) & VT_ARRAY ) && //old variant is array
468
- SafeArrayGetDim (V_ARRAY (& obj -> v )) == 1 && //old array have one dimension
563
+ if ((vt & ~VT_ARRAY ) && //new variant have some type except VT_ARRAY
564
+ (V_VT (& obj -> v ) & VT_ARRAY ) && //our variant is array
565
+ SafeArrayGetDim (V_ARRAY (& obj -> v )) == 1 && //our array have one dimension
469
566
SUCCEEDED (res = SafeArrayGetLBound (V_ARRAY (& obj -> v ), 1 , & Bound .lLbound )) &&
470
567
SUCCEEDED (res = SafeArrayGetUBound (V_ARRAY (& obj -> v ), 1 , & Bound .cElements )))
471
568
{
472
-
473
569
zend_long need_vt = vt & ~VT_ARRAY ;
474
570
zend_long old_vt = V_VT (& obj -> v ) & ~VT_ARRAY ;
475
571
0 commit comments