Skip to content

Commit 959549e

Browse files
Feature (ext/com_dotnet): VT_ARRAY, VT_BYREF, VT_PTR
1 parent 8d74bdd commit 959549e

File tree

4 files changed

+122
-15
lines changed

4 files changed

+122
-15
lines changed

ext/com_dotnet/com_com.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
334334
WORD flags, DISPPARAMS *disp_params, VARIANT *v, bool silent, bool allow_noarg)
335335
{
336336
HRESULT hr;
337-
unsigned int arg_err;
337+
unsigned int arg_err = (unsigned int)-1;
338338
EXCEPINFO e = {0};
339339

340340
hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
@@ -343,6 +343,9 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
343343
if (!silent && FAILED(hr)) {
344344
char *desc = NULL, *msg = NULL;
345345

346+
if(arg_err != (unsigned int)-1)
347+
arg_err = disp_params->cArgs - arg_err; // We have reversed array of params
348+
346349
switch (hr) {
347350
case DISP_E_EXCEPTION: {
348351
zend_string *source = NULL, *desc_str = NULL;
@@ -377,7 +380,7 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
377380
case DISP_E_PARAMNOTFOUND:
378381
case DISP_E_TYPEMISMATCH:
379382
desc = php_win32_error_to_msg(hr);
380-
spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
383+
spprintf(&msg, 0, "Error [0x%08x] Parameter %d: %s", hr, arg_err, desc);
381384
php_win32_error_msg_free(desc);
382385
break;
383386

@@ -393,7 +396,10 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
393396

394397
default:
395398
desc = php_win32_error_to_msg(hr);
396-
spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
399+
if(arg_err != (unsigned int) -1)
400+
spprintf(&msg, 0, "Error [0x%08x] Parameter %d: %s", hr, arg_err, desc);
401+
else
402+
spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
397403
php_win32_error_msg_free(desc);
398404
break;
399405
}

ext/com_dotnet/com_handlers.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ void php_com_object_free_storage(zend_object *object)
573573
}
574574

575575
VariantClear(&obj->v);
576+
zval_dtor(&obj->byref);
576577

577578
if (obj->method_cache) {
578579
zend_hash_destroy(obj->method_cache);
@@ -603,6 +604,9 @@ zend_object* php_com_object_clone(zend_object *object)
603604
* want to clone as much as possible */
604605
VariantCopyInd(&cloneobj->v, &origobject->v);
605606

607+
ZVAL_NULL(&cloneobj->byref);
608+
ZVAL_COPY(&cloneobj->byref, &origobject->byref);
609+
606610
if (cloneobj->typeinfo) {
607611
ITypeInfo_AddRef(cloneobj->typeinfo);
608612
}

ext/com_dotnet/com_variant.c

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,13 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep
128128
}
129129
V_DISPATCH(v) = V_DISPATCH(&obj->v);
130130
} 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+
}
134138
}
135139
} else {
136140
/* export the PHP object using our COM wrapper */
@@ -429,6 +433,7 @@ PHP_METHOD(variant, __construct)
429433
php_com_dotnet_object *obj;
430434
zval *zvalue = NULL;
431435
HRESULT res;
436+
char *msg = NULL;
432437

433438
if (ZEND_NUM_ARGS() == 0) {
434439
/* just leave things as-is - an empty variant */
@@ -454,22 +459,113 @@ PHP_METHOD(variant, __construct)
454459
/* Only perform conversion if variant not already of type passed */
455460
if ((ZEND_NUM_ARGS() >= 2) && (vt != V_VT(&obj->v))) {
456461

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+
*/
461559

462560
res = S_OK;
463561
SAFEARRAYBOUND Bound;
464562

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
469566
SUCCEEDED(res = SafeArrayGetLBound(V_ARRAY(&obj->v), 1, &Bound.lLbound)) &&
470567
SUCCEEDED(res = SafeArrayGetUBound(V_ARRAY(&obj->v), 1, &Bound.cElements)))
471568
{
472-
473569
zend_long need_vt = vt & ~VT_ARRAY;
474570
zend_long old_vt = V_VT(&obj->v) & ~VT_ARRAY;
475571

ext/com_dotnet/php_com_dotnet_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef struct _php_com_dotnet_object {
2929
zend_object zo;
3030

3131
VARIANT v;
32+
zval byref;
3233
bool modified;
3334

3435
int code_page;

0 commit comments

Comments
 (0)