]> granicus.if.org Git - php/commitdiff
Support automatic handling of byref parameters
authorWez Furlong <wez@php.net>
Tue, 13 Jan 2004 00:40:14 +0000 (00:40 +0000)
committerWez Furlong <wez@php.net>
Tue, 13 Jan 2004 00:40:14 +0000 (00:40 +0000)
ext/com_dotnet/com_com.c
ext/com_dotnet/com_handlers.c
ext/com_dotnet/php_com_dotnet_internal.h

index 3106e977b4333dc914ba8fddc30b0046133cc2aa..135d1c98ba6a4ebea98ed6950ace446a4a3b7448 100644 (file)
@@ -377,6 +377,127 @@ HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
 }
 
 /* the core of COM */
+int php_com_do_invoke_byref(php_com_dotnet_object *obj, char *name, int namelen,
+               WORD flags,     VARIANT *v, int nargs, zval ***args TSRMLS_DC)
+{
+       DISPID dispid, altdispid;
+       DISPPARAMS disp_params;
+       HRESULT hr;
+       VARIANT *vargs = NULL, *byref_vals = NULL;
+       int i, byref_count = 0, j;
+       zend_internal_function *f = (zend_internal_function*)EG(function_state_ptr)->function;
+
+       /* assumption: that the active function (f) is the function we generated for the engine */
+       if (!f || f->type != ZEND_OVERLOADED_FUNCTION_TEMPORARY || f->arg_info == NULL) {
+          f = NULL;
+       }
+       
+       hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);
+
+       if (FAILED(hr)) {
+               char *winerr = NULL;
+               char *msg = NULL;
+               winerr = php_win_err(hr);
+               spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
+               LocalFree(winerr);
+               php_com_throw_exception(hr, msg TSRMLS_CC);
+               efree(msg);
+               return FAILURE;
+       }
+
+
+       if (nargs) {
+               vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
+       }
+
+       if (f) {
+               for (i = 0; i < nargs; i++) {
+                       if (f->arg_info[nargs - i - 1].pass_by_reference) {
+                               byref_count++;
+                       }
+               }
+       }
+
+       if (byref_count) {
+               byref_vals = (VARIANT*)safe_emalloc(sizeof(VARIANT), byref_count, 0);
+               for (j = 0, i = 0; i < nargs; i++) {
+                       if (f->arg_info[nargs - i - 1].pass_by_reference) {
+                               /* put the value into byref_vals instead */
+                               php_com_variant_from_zval(&byref_vals[j], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
+
+                               /* if it is already byref, "move" it into the vargs array, otherwise
+                                * make vargs a reference to this value */
+                               if (V_VT(&byref_vals[j]) & VT_BYREF) {
+                                       memcpy(&vargs[i], &byref_vals[j], sizeof(vargs[i]));
+                                       VariantInit(&byref_vals[j]); /* leave the variant slot empty to simplify cleanup */
+                               } else {
+                                       VariantInit(&vargs[i]);
+                                       V_VT(&vargs[i]) = V_VT(&byref_vals[j]) | VT_BYREF;
+                                       /* union magic ensures that this works out */
+                                       vargs[i].byref = &V_UINT(&byref_vals[j]);
+                               }
+                               j++;
+                       } else {
+                               php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
+                       }
+               }
+               
+       } else {
+               /* Invoke'd args are in reverse order */
+               for (i = 0; i < nargs; i++) {
+                       php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
+               }
+       }
+
+       disp_params.cArgs = nargs;
+       disp_params.cNamedArgs = 0;
+       disp_params.rgvarg = vargs;
+       disp_params.rgdispidNamedArgs = NULL;
+
+       if (flags & DISPATCH_PROPERTYPUT) {
+               altdispid = DISPID_PROPERTYPUT;
+               disp_params.rgdispidNamedArgs = &altdispid;
+               disp_params.cNamedArgs = 1;
+       }
+
+       /* this will create an exception if needed */
+       hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v TSRMLS_CC);      
+
+       /* release variants */
+       if (vargs) {
+               for (i = 0, j = 0; i < nargs; i++) {
+                       /* if this was byref, update the zval */
+                       if (f && f->arg_info[nargs - i - 1].pass_by_reference) {
+                               SEPARATE_ZVAL_IF_NOT_REF(args[nargs - i - 1]);
+
+                               /* if the variant is pointing at the byref_vals, we need to map
+                                * the pointee value as a zval; otherwise, the value is pointing
+                                * into an existing PHP variant record */
+                               if (V_VT(&vargs[i]) & VT_BYREF) {
+                                       if (vargs[i].byref == &V_UINT(&byref_vals[j])) {
+                                               /* copy that value */
+                                               php_com_zval_from_variant(*args[nargs - i - 1], &byref_vals[j],
+                                                       obj->code_page TSRMLS_CC);
+                                       }
+                               } else {
+                                       /* not sure if this can ever happen; the variant we marked as BYREF
+                                        * is no longer BYREF - copy its value */
+                                       php_com_zval_from_variant(*args[nargs - i - 1], &vargs[i],
+                                               obj->code_page TSRMLS_CC);
+                               }
+                               VariantClear(&byref_vals[j]);
+                               j++;
+                       }       
+                       VariantClear(&vargs[i]);
+               }
+               efree(vargs);
+       }
+
+       return SUCCEEDED(hr) ? SUCCESS : FAILURE;
+}
+
+
+
 int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
                WORD flags,     VARIANT *v, int nargs, zval **args TSRMLS_DC)
 {
index 3ed189aa0f0fd40a93ed91477a88c29b8acc7059..5cb69b5ec37c312f512de3e9829b00b2be97cf30 100644 (file)
@@ -306,7 +306,7 @@ static union _zend_function *com_method_get(zval *object, char *name, int len TS
 
 static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
 {
-       zval **args = NULL;
+       zval ***args = NULL;
        php_com_dotnet_object *obj;
        int nargs;
        VARIANT v;
@@ -321,13 +321,13 @@ static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
        nargs = ZEND_NUM_ARGS();
 
        if (nargs) {
-               args = (zval **)safe_emalloc(sizeof(zval *), nargs, 0);
-               zend_get_parameters_array(ht, nargs, args);
+               args = (zval ***)safe_emalloc(sizeof(zval *), nargs, 0);
+               zend_get_parameters_array_ex(nargs, args);
        }
 
        VariantInit(&v);
 
-       if (SUCCESS == php_com_do_invoke(obj, method, -1, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args TSRMLS_CC)) {
+       if (SUCCESS == php_com_do_invoke_byref(obj, method, -1, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args TSRMLS_CC)) {
                php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
                ret = SUCCESS;
                VariantClear(&v);
index 19681d7ba908f04fd7f66de39ba2258786784da0..131a9180592c7bcebdafd7cd6d3118fad470ea3b 100644 (file)
@@ -103,6 +103,8 @@ int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
                WORD flags,     VARIANT *v, int nargs, zval **args TSRMLS_DC);
 int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
                WORD flags,     VARIANT *v, int nargs, zval **args TSRMLS_DC);
+int php_com_do_invoke_byref(php_com_dotnet_object *obj, char *name, int namelen,
+               WORD flags,     VARIANT *v, int nargs, zval ***args TSRMLS_DC);
 
 /* com_wrapper.c */
 int php_com_wrapper_minit(INIT_FUNC_ARGS);