]> granicus.if.org Git - php/commitdiff
Fix for Bug #28161 (and probably others that I can't find in the bug db;
authorWez Furlong <wez@php.net>
Wed, 28 Apr 2004 08:23:22 +0000 (08:23 +0000)
committerWez Furlong <wez@php.net>
Wed, 28 Apr 2004 08:23:22 +0000 (08:23 +0000)
the search interface sucks).

Expand the proxy object so it can handle psuedo array style properties.

ASP/VB code like this:

headObj.Attribute("RID") = rid

can be expressed like this in PHP:

$headObj->Attribute['RID'] = $rid;

In theory, this feature can be used for "multi dimensional" properties:

headObj.Attribute("RID", "Foo") = rid;

like this:

$headObj->Attribute['RID']['Foo'] = $rid;

ext/com_dotnet/com_com.c
ext/com_dotnet/com_extension.c
ext/com_dotnet/com_handlers.c
ext/com_dotnet/com_saproxy.c
ext/com_dotnet/php_com_dotnet_internal.h

index cfce3b93743e9b5e7558cf7d2b280b7cd057636e..09b2beaf3ffc241540e326552c1cb0357f49e8a1 100644 (file)
@@ -333,6 +333,17 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
                                spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
                                LocalFree(desc);
                                break;
+
+                       case DISP_E_BADPARAMCOUNT:
+                               if ((disp_params->cArgs + disp_params->cNamedArgs == 0) && (flags == DISPATCH_PROPERTYGET)) {
+                                       /* if getting a property and they are missing all parameters,
+                                        * we want to create a proxy object for them; so lets not create an
+                                        * exception here */
+                                       msg = NULL;
+                                       break;
+                               }
+                               /* else fall through */
+                               
                        default:
                                desc = php_win_err(hr);
                                spprintf(&msg, 0, "Error %s", desc);
@@ -557,6 +568,10 @@ int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
                efree(vargs);
        }
 
+       /* a bit strange this, but... */
+       if (hr == DISP_E_BADPARAMCOUNT)
+               return hr;
+       
        return SUCCEEDED(hr) ? SUCCESS : FAILURE;
 }
 
index 438536645d553ae35ee051c22aa8aeab5d66582a..7fafce19ca13b6db876b94add433c931001c3d10 100644 (file)
@@ -197,18 +197,16 @@ PHP_MINIT_FUNCTION(com_dotnet)
        INIT_CLASS_ENTRY(ce, "com_safearray_proxy", NULL);
        php_com_saproxy_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
        php_com_saproxy_class_entry->ce_flags |= ZEND_ACC_FINAL;
-//     php_com_saproxy_class_entry->constructor->common.fn_flags |= ZEND_ACC_PROTECTED;
+       php_com_saproxy_class_entry->constructor->common.fn_flags |= ZEND_ACC_PROTECTED;
        php_com_saproxy_class_entry->get_iterator = php_com_saproxy_iter_get;
        
        INIT_CLASS_ENTRY(ce, "variant", NULL);
        ce.create_object = php_com_object_new;
-//     ce.get_iterator = php_com_iter_get;
        php_com_variant_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
        php_com_variant_class_entry->get_iterator = php_com_iter_get;
 
        INIT_CLASS_ENTRY(ce, "com", NULL);
        ce.create_object = php_com_object_new;
-//     ce.get_iterator = php_com_iter_get;
        tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry, "variant" TSRMLS_CC);
        tmp->get_iterator = php_com_iter_get;
 
@@ -217,7 +215,6 @@ PHP_MINIT_FUNCTION(com_dotnet)
 #if HAVE_MSCOREE_H
        INIT_CLASS_ENTRY(ce, "dotnet", NULL);
        ce.create_object = php_com_object_new;
-//     ce.get_iterator = php_com_iter_get;
        tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry, "variant" TSRMLS_CC);
        tmp->get_iterator = php_com_iter_get;
 #endif
index 4b39a4719740e438dc779044779ac4f402cc5f8c..071f9df5f3c2c096b1a00ed2166da2bf7fd4951c 100644 (file)
@@ -34,6 +34,7 @@ static zval *com_property_read(zval *object, zval *member, int type TSRMLS_DC)
        zval *return_value;
        php_com_dotnet_object *obj;
        VARIANT v;
+       HRESULT res;
 
        MAKE_STD_ZVAL(return_value);
        ZVAL_NULL(return_value);
@@ -46,10 +47,15 @@ static zval *com_property_read(zval *object, zval *member, int type TSRMLS_DC)
                VariantInit(&v);
 
                convert_to_string_ex(&member);
-               if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
-                               DISPATCH_PROPERTYGET, &v, 0, NULL TSRMLS_CC)) {
+
+               res = php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
+                               DISPATCH_PROPERTYGET, &v, 0, NULL TSRMLS_CC);
+
+               if (res == SUCCESS) {
                        php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
                        VariantClear(&v);
+               } else if (res == DISP_E_BADPARAMCOUNT) {
+                       php_com_saproxy_create(object, return_value, member TSRMLS_CC);
                }
        } else {
                php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
@@ -137,7 +143,7 @@ static zval *com_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
                                VariantClear(&v);
                        }
                } else {
-                       php_com_saproxy_create(object, return_value, Z_LVAL_P(offset) TSRMLS_CC);
+                       php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
                }
 
        } else {
@@ -555,7 +561,6 @@ void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSR
 void php_com_object_free_storage(void *object TSRMLS_DC)
 {
        php_com_dotnet_object *obj = (php_com_dotnet_object*)object;
-
        if (obj->typeinfo) {
                ITypeInfo_Release(obj->typeinfo);
                obj->typeinfo = NULL;
@@ -614,7 +619,6 @@ zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC)
        obj->code_page = CP_ACP;
        obj->ce = ce;
 
-       
        retval.handle = zend_objects_store_put(obj, NULL, php_com_object_free_storage, php_com_object_clone TSRMLS_CC);
        retval.handlers = &php_com_object_handlers;
 
index 5ac24acae7cb86c106fb28ee29b56cc66fa2242a..cf28d1e647c2df2b306467856f03ab5d6559b6ab 100644 (file)
@@ -20,7 +20,9 @@
 
 /* This module implements a SafeArray proxy which is used internally
  * by the engine when resolving multi-dimensional array accesses on
- * SafeArray types
+ * SafeArray types.
+ * In addition, the proxy is now able to handle properties of COM objects
+ * that smell like PHP arrays.
  * */
 
 #ifdef HAVE_CONFIG_H
@@ -43,7 +45,7 @@ typedef struct {
        LONG dimensions;
        
        /* this is an array whose size_is(dimensions) */
-       LONG *indices;
+       zval **indices;
 
 } php_com_saproxy;
 
@@ -58,6 +60,17 @@ typedef struct {
 
 #define SA_FETCH(zv)                   (php_com_saproxy*)zend_object_store_get_object(zv TSRMLS_CC)
 
+static inline void clone_indices(php_com_saproxy *dest, php_com_saproxy *src, int ndims)
+{
+       int i;
+
+       for (i = 0; i < ndims; i++) {
+               MAKE_STD_ZVAL(dest->indices[i]);
+               *dest->indices[i] = *src->indices[i];
+               zval_copy_ctor(dest->indices[i]);
+       }
+}
+
 static zval *saproxy_property_read(zval *object, zval *member, int type TSRMLS_DC)
 {
        zval *return_value;
@@ -82,15 +95,50 @@ static zval *saproxy_read_dimension(zval *object, zval *offset, int type TSRMLS_
        UINT dims;
        SAFEARRAY *sa;
        LONG ubound, lbound;
+       int i;
+       HRESULT res;
        
        MAKE_STD_ZVAL(return_value);
        ZVAL_NULL(return_value);
        
-       if (!V_ISARRAY(&proxy->obj->v)) {
-               php_com_throw_exception(E_INVALIDARG, "proxied object is no longer a safe array!" TSRMLS_CC);
+       if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
+               VARIANT v;
+               zval **args;
+
+               /* prop-get using first dimension as the property name,
+                * all subsequent dimensions and the offset as parameters */
+
+               args = safe_emalloc(proxy->dimensions + 1, sizeof(zval *), 0);
+
+               for (i = 1; i < proxy->dimensions; i++) {
+                       args[i-1] = proxy->indices[i];
+               }
+               args[i-1] = offset;
+
+               convert_to_string(proxy->indices[0]);
+               VariantInit(&v);
+
+               res = php_com_do_invoke(proxy->obj, Z_STRVAL_P(proxy->indices[0]),
+                               Z_STRLEN_P(proxy->indices[0]), DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v,
+                               proxy->dimensions, args TSRMLS_CC);
+
+               if (res == SUCCESS) {
+                       php_com_zval_from_variant(return_value, &v, proxy->obj->code_page TSRMLS_CC);
+                       VariantClear(&v);
+               } else if (res == DISP_E_BADPARAMCOUNT) {
+                       /* return another proxy */
+                       php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
+               }
+
+               return return_value;
+
+       } else if (!V_ISARRAY(&proxy->obj->v)) {
+               php_com_throw_exception(E_INVALIDARG, "invalid read from com proxy object" TSRMLS_CC);
                return return_value;
        }
 
+       /* the SafeArray case */
+       
        /* offset/index must be an integer */
        convert_to_long(offset);
        
@@ -123,7 +171,10 @@ static zval *saproxy_read_dimension(zval *object, zval *offset, int type TSRMLS_
                indices = do_alloca(dims * sizeof(LONG));
 
                /* copy indices from proxy */
-               memcpy(indices, proxy->indices, (dims-1) * sizeof(LONG));
+               for (i = 0; i < dims; i++) {
+                       convert_to_long(proxy->indices[i]);
+                       indices[i] = Z_LVAL_P(proxy->indices[i]);
+               }
 
                /* add user-supplied index */
                indices[dims-1] = Z_LVAL_P(offset);
@@ -148,7 +199,7 @@ static zval *saproxy_read_dimension(zval *object, zval *offset, int type TSRMLS_
                
        } else {
                /* return another proxy */
-               php_com_saproxy_create(object, return_value, Z_LVAL_P(offset) TSRMLS_CC);
+               php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
        }
 
        return return_value;
@@ -156,7 +207,41 @@ static zval *saproxy_read_dimension(zval *object, zval *offset, int type TSRMLS_
 
 static void saproxy_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
 {
-       php_com_throw_exception(E_NOTIMPL, "writing to safearray not yet implemented" TSRMLS_CC);
+       php_com_saproxy *proxy = SA_FETCH(object);
+       UINT dims;
+       SAFEARRAY *sa;
+       LONG ubound, lbound;
+       int i;
+       HRESULT res;
+       VARIANT v;
+       
+       if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
+               /* We do a prop-set using the first dimension as the property name,
+                * all subsequent dimensions and offset as parameters, with value as
+                * the final value */
+               zval **args = safe_emalloc(proxy->dimensions + 2, sizeof(zval *), 0);
+
+               for (i = 1; i < proxy->dimensions; i++) {
+                       args[i-1] = proxy->indices[i];
+               }
+               args[i-1] = offset;
+               args[i] = value;
+
+               convert_to_string(proxy->indices[0]);
+               VariantInit(&v);
+               if (SUCCESS == php_com_do_invoke(proxy->obj, Z_STRVAL_P(proxy->indices[0]),
+                                       Z_STRLEN_P(proxy->indices[0]), DISPATCH_PROPERTYPUT, &v, proxy->dimensions + 1,
+                                       args TSRMLS_CC)) {
+                       VariantClear(&v);
+               }
+
+               efree(args);
+               
+       } else if (V_ISARRAY(&proxy->obj->v)) {
+               php_com_throw_exception(E_NOTIMPL, "writing to safearray not yet implemented" TSRMLS_CC);
+       } else {
+               php_com_throw_exception(E_NOTIMPL, "invalid write to com proxy object" TSRMLS_CC);
+       }
 }
 
 static void saproxy_object_set(zval **property, zval *value TSRMLS_DC)
@@ -262,6 +347,13 @@ zend_object_handlers php_com_saproxy_handlers = {
 static void saproxy_free_storage(void *object TSRMLS_DC)
 {
        php_com_saproxy *proxy = (php_com_saproxy *)object;
+       int i;
+
+       for (i = 0; i < proxy->dimensions; i++) {
+               if (proxy->indices) {
+                               FREE_ZVAL(proxy->indices[i]);
+               }
+       }
 
        zval_ptr_dtor(&proxy->zobj);
        efree(proxy->indices);
@@ -272,43 +364,45 @@ static void saproxy_clone(void *object, void **clone_ptr TSRMLS_DC)
 {
        php_com_saproxy *proxy = (php_com_saproxy *)object;
        php_com_saproxy *cloneproxy;
+       int i;
 
        cloneproxy = emalloc(sizeof(*cloneproxy));
        memcpy(cloneproxy, proxy, sizeof(*cloneproxy));
 
        ZVAL_ADDREF(cloneproxy->zobj);
-       cloneproxy->indices = safe_emalloc(cloneproxy->dimensions, sizeof(LONG), 0);
-       memcpy(cloneproxy->indices, proxy->indices, cloneproxy->dimensions * sizeof(LONG));
+       cloneproxy->indices = safe_emalloc(cloneproxy->dimensions, sizeof(zval *), 0);
+       clone_indices(cloneproxy, proxy, proxy->dimensions);
 
        *clone_ptr = cloneproxy;
 }
 
-int php_com_saproxy_create(zval *com_object, zval *proxy_out, long index TSRMLS_DC)
+int php_com_saproxy_create(zval *com_object, zval *proxy_out, zval *index TSRMLS_DC)
 {
        php_com_saproxy *proxy, *rel = NULL;
-       php_com_dotnet_object *obj;
 
        proxy = ecalloc(1, sizeof(*proxy));
        proxy->dimensions = 1;
 
        if (Z_OBJCE_P(com_object) == php_com_saproxy_class_entry) {
                rel = SA_FETCH(com_object);
-               obj = rel->obj;
+               proxy->obj = rel->obj;
                proxy->zobj = rel->zobj;
                proxy->dimensions += rel->dimensions;
        } else {
-               obj = CDNO_FETCH(com_object);
+               proxy->obj = CDNO_FETCH(com_object);
                proxy->zobj = com_object;
        }
 
        ZVAL_ADDREF(proxy->zobj);
-       proxy->indices = safe_emalloc(proxy->dimensions, sizeof(LONG), 0);
+       proxy->indices = safe_emalloc(proxy->dimensions, sizeof(zval *), 0);
 
        if (rel) {
-               memcpy(proxy->indices, rel->indices, (proxy->dimensions-1) * sizeof(LONG));
+               clone_indices(proxy, rel, rel->dimensions);
        }
 
-       proxy->indices[proxy->dimensions-1] = index;
+       MAKE_STD_ZVAL(proxy->indices[proxy->dimensions-1]);
+       *proxy->indices[proxy->dimensions-1] = *index;
+       zval_copy_ctor(proxy->indices[proxy->dimensions-1]);
 
        Z_TYPE_P(proxy_out) = IS_OBJECT;
        Z_OBJ_HANDLE_P(proxy_out) = zend_objects_store_put(proxy, NULL, saproxy_free_storage, saproxy_clone TSRMLS_CC);
@@ -406,6 +500,7 @@ zend_object_iterator *php_com_saproxy_iter_get(zend_class_entry *ce, zval *objec
 {
        php_com_saproxy *proxy = SA_FETCH(object);
        php_com_saproxy_iter *I;
+       int i;
 
        I = ecalloc(1, sizeof(*I));
        I->iter.funcs = &saproxy_iter_funcs;
@@ -416,7 +511,10 @@ zend_object_iterator *php_com_saproxy_iter_get(zend_class_entry *ce, zval *objec
        ZVAL_ADDREF(I->proxy_obj);
 
        I->indices = safe_emalloc(proxy->dimensions + 1, sizeof(LONG), 0);
-       memcpy(I->indices, proxy->indices, proxy->dimensions * sizeof(LONG));
+       for (i = 0; i < proxy->dimensions; i++) {
+               convert_to_long(proxy->indices[i]);
+               I->indices[i] = Z_LVAL_P(proxy->indices[i]);
+       }
 
        SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imin);
        SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imax);
index 2ff1d16abf34451449a7f565cfe7b79bb26b4f63..d60da9b075ea3bbfb8846d59a73ea6b5f866805e 100644 (file)
@@ -83,7 +83,7 @@ void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSR
 
 /* com_saproxy.c */
 zend_object_iterator *php_com_saproxy_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC);
-int php_com_saproxy_create(zval *com_object, zval *proxy_out, long index TSRMLS_DC);
+int php_com_saproxy_create(zval *com_object, zval *proxy_out, zval *index TSRMLS_DC);
 
 /* com_olechar.c */
 PHPAPI char *php_com_olestring_to_string(OLECHAR *olestring,