From: Wez Furlong Date: Wed, 28 Apr 2004 08:23:22 +0000 (+0000) Subject: Fix for Bug #28161 (and probably others that I can't find in the bug db; X-Git-Tag: RELEASE_0_1~345 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=027d45016653db83d1d61a94cba885b3d5e08304;p=php Fix for Bug #28161 (and probably others that I can't find in the bug db; 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; --- diff --git a/ext/com_dotnet/com_com.c b/ext/com_dotnet/com_com.c index cfce3b9374..09b2beaf3f 100644 --- a/ext/com_dotnet/com_com.c +++ b/ext/com_dotnet/com_com.c @@ -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; } diff --git a/ext/com_dotnet/com_extension.c b/ext/com_dotnet/com_extension.c index 438536645d..7fafce19ca 100644 --- a/ext/com_dotnet/com_extension.c +++ b/ext/com_dotnet/com_extension.c @@ -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 diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 4b39a47197..071f9df5f3 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -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; diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c index 5ac24acae7..cf28d1e647 100644 --- a/ext/com_dotnet/com_saproxy.c +++ b/ext/com_dotnet/com_saproxy.c @@ -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); diff --git a/ext/com_dotnet/php_com_dotnet_internal.h b/ext/com_dotnet/php_com_dotnet_internal.h index 2ff1d16abf..d60da9b075 100644 --- a/ext/com_dotnet/php_com_dotnet_internal.h +++ b/ext/com_dotnet/php_com_dotnet_internal.h @@ -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,