summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2004-04-28 08:23:22 +0000
committerWez Furlong <wez@php.net>2004-04-28 08:23:22 +0000
commit027d45016653db83d1d61a94cba885b3d5e08304 (patch)
treeef6a6fabfc9a0391855ce751e1f85ef1943a0fea
parentb97ecc182092e2f6893a69e8a5c621532394ca2c (diff)
downloadphp-git-027d45016653db83d1d61a94cba885b3d5e08304.tar.gz
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;
-rw-r--r--ext/com_dotnet/com_com.c15
-rw-r--r--ext/com_dotnet/com_extension.c5
-rw-r--r--ext/com_dotnet/com_handlers.c14
-rw-r--r--ext/com_dotnet/com_saproxy.c132
-rw-r--r--ext/com_dotnet/php_com_dotnet_internal.h2
5 files changed, 141 insertions, 27 deletions
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,