summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2004-01-07 21:00:07 +0000
committerWez Furlong <wez@php.net>2004-01-07 21:00:07 +0000
commite10c206dac0fbd43e20f9ae9b704e76c5c564d2f (patch)
tree9675f1c8d2760ce9e7d3f6bf766d5ad434dc96c0
parent48b96c10d2c9efbe4ff11876c6cd9f9361073bc3 (diff)
downloadphp-git-e10c206dac0fbd43e20f9ae9b704e76c5c564d2f.tar.gz
Port other major parts of PHP 4 COM extension into PHP 5 com_dotnet
extension. This enables: - iteration of SafeArray types via foreach() - proxying of multi-dimensional SafeArray types so that multi-dimension array accesses work (untested!) - Fix COM exceptions, and expose them as their own class of exception "com_exception" - auto typelib file import (com.typelib_file ini option) - event sinking - wrapper to map PHP objects to COM - fix mapping of variant values to PHP values # Could someone please add com_saproxy.c and com_wrapper.c to the .dsp # file?
-rw-r--r--ext/com_dotnet/com_com.c181
-rw-r--r--ext/com_dotnet/com_dotnet.c8
-rw-r--r--ext/com_dotnet/com_extension.c109
-rw-r--r--ext/com_dotnet/com_handlers.c90
-rw-r--r--ext/com_dotnet/com_iterator.c140
-rw-r--r--ext/com_dotnet/com_misc.c91
-rw-r--r--ext/com_dotnet/com_olechar.c4
-rw-r--r--ext/com_dotnet/com_saproxy.c430
-rw-r--r--ext/com_dotnet/com_typeinfo.c356
-rw-r--r--ext/com_dotnet/com_variant.c23
-rw-r--r--ext/com_dotnet/com_wrapper.c640
-rw-r--r--ext/com_dotnet/config.w322
-rw-r--r--ext/com_dotnet/php_com_dotnet.h5
-rw-r--r--ext/com_dotnet/php_com_dotnet_internal.h37
14 files changed, 1957 insertions, 159 deletions
diff --git a/ext/com_dotnet/com_com.c b/ext/com_dotnet/com_com.c
index 9183a013a0..73c8337d11 100644
--- a/ext/com_dotnet/com_com.c
+++ b/ext/com_dotnet/com_com.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -64,7 +64,7 @@ PHP_FUNCTION(com_create_instance)
&module_name, &module_name_len, &server_params, &obj->code_page,
&typelib_name, &typelib_name_len)) {
- php_com_throw_exception("Could not create COM object - invalid arguments!" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid arguments!" TSRMLS_CC);
ZVAL_NULL(object);
return;
}
@@ -113,7 +113,7 @@ PHP_FUNCTION(com_create_instance)
}
if (server_name && !COMG(allow_dcom)) {
- php_com_throw_exception("DCOM has been disabled by your administrator [com.allow_dcom=0]" TSRMLS_CC);
+ php_com_throw_exception(E_ERROR, "DCOM has been disabled by your administrator [com.allow_dcom=0]" TSRMLS_CC);
return;
}
@@ -227,7 +227,7 @@ PHP_FUNCTION(com_create_instance)
spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, werr);
LocalFree(werr);
- php_com_throw_exception(msg TSRMLS_CC);
+ php_com_throw_exception(res, msg TSRMLS_CC);
efree(msg);
ZVAL_NULL(object);
return;
@@ -240,7 +240,7 @@ PHP_FUNCTION(com_create_instance)
/* load up the library from the named file */
int cached;
- TL = php_com_load_typelib_via_cache(typelib_name, mode, obj->code_page, &cached TSRMLS_CC);
+ TL = php_com_load_typelib_via_cache(typelib_name, obj->code_page, &cached TSRMLS_CC);
if (TL) {
if (COMG(autoreg_on) && !cached) {
@@ -341,7 +341,7 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
}
if (msg) {
- php_com_throw_exception(msg TSRMLS_CC);
+ php_com_throw_exception(hr, msg TSRMLS_CC);
efree(msg);
}
}
@@ -434,7 +434,7 @@ int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
winerr = php_win_err(hr);
spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
LocalFree(winerr);
- php_com_throw_exception(msg TSRMLS_CC);
+ php_com_throw_exception(hr, msg TSRMLS_CC);
efree(msg);
return FAILURE;
}
@@ -442,6 +442,8 @@ int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args TSRMLS_CC);
}
+/* {{{ proto string com_create_guid()
+ Generate a globally unique identifier (GUID) */
PHP_FUNCTION(com_create_guid)
{
GUID retval;
@@ -460,4 +462,169 @@ PHP_FUNCTION(com_create_guid)
RETURN_FALSE;
}
}
+/* }}} */
+
+/* {{{ proto bool com_event_sink(object comobject, object sinkobject [, mixed sinkinterface])
+ Connect events from a COM object to a PHP object */
+PHP_FUNCTION(com_event_sink)
+{
+ zval *object, *sinkobject, *sink=NULL;
+ char *dispname = NULL, *typelibname = NULL;
+ zend_bool gotguid = 0;
+ php_com_dotnet_object *obj;
+ ITypeInfo *typeinfo = NULL;
+
+ RETVAL_FALSE;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oo|z/",
+ &object, php_com_variant_class_entry, &sinkobject, &sink)) {
+ RETURN_FALSE;
+ }
+
+ obj = CDNO_FETCH(object);
+
+ if (sink && Z_TYPE_P(sink) == IS_ARRAY) {
+ /* 0 => typelibname, 1 => dispname */
+ zval **tmp;
+
+ if (zend_hash_index_find(Z_ARRVAL_P(sink), 0, (void**)&tmp) == SUCCESS)
+ typelibname = Z_STRVAL_PP(tmp);
+ if (zend_hash_index_find(Z_ARRVAL_P(sink), 1, (void**)&tmp) == SUCCESS)
+ dispname = Z_STRVAL_PP(tmp);
+ } else if (sink != NULL) {
+ convert_to_string(sink);
+ dispname = Z_STRVAL_P(sink);
+ }
+
+ typeinfo = php_com_locate_typeinfo(typelibname, obj, dispname, 1 TSRMLS_CC);
+
+ if (typeinfo) {
+ HashTable *id_to_name;
+
+ ALLOC_HASHTABLE(id_to_name);
+
+ if (php_com_process_typeinfo(typeinfo, id_to_name, 0, &obj->sink_id, obj->code_page TSRMLS_CC)) {
+
+ /* Create the COM wrapper for this sink */
+ obj->sink_dispatch = php_com_wrapper_export_as_sink(sinkobject, &obj->sink_id, id_to_name TSRMLS_CC);
+
+ /* Now hook it up to the source */
+ php_com_object_enable_event_sink(obj, TRUE TSRMLS_CC);
+ RETVAL_TRUE;
+
+ } else {
+ FREE_HASHTABLE(id_to_name);
+ }
+ }
+
+ if (typeinfo) {
+ ITypeInfo_Release(typeinfo);
+ }
+
+}
+/* }}} */
+
+/* {{{ proto bool com_print_typeinfo(object comobject | string typelib, string dispinterface, bool wantsink)
+ Print out a PHP class definition for a dispatchable interface */
+PHP_FUNCTION(com_print_typeinfo)
+{
+ zval *arg1;
+ char *ifacename = NULL;
+ char *typelibname = NULL;
+ int ifacelen;
+ zend_bool wantsink = 0;
+ php_com_dotnet_object *obj = NULL;
+ ITypeInfo *typeinfo;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|s!b", &arg1, &ifacename,
+ &ifacelen, &wantsink)) {
+ RETURN_FALSE;
+ }
+
+ if (Z_TYPE_P(arg1) == IS_OBJECT) {
+ CDNO_FETCH_VERIFY(obj, arg1);
+ } else {
+ convert_to_string(arg1);
+ typelibname = Z_STRVAL_P(arg1);
+ }
+
+ typeinfo = php_com_locate_typeinfo(typelibname, obj, ifacename, wantsink ? 1 : 0 TSRMLS_CC);
+ if (typeinfo) {
+ php_com_process_typeinfo(typeinfo, NULL, 1, NULL, obj ? obj->code_page : COMG(code_page) TSRMLS_CC);
+ ITypeInfo_Release(typeinfo);
+ RETURN_TRUE;
+ } else {
+ zend_error(E_WARNING, "Unable to find typeinfo using the parameters supplied");
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool com_message_pump([int timeoutms])
+ Process COM messages, sleeping for up to timeoutms milliseconds */
+PHP_FUNCTION(com_message_pump)
+{
+ long timeoutms = 0;
+ MSG msg;
+ DWORD result;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timeoutms) == FAILURE)
+ RETURN_FALSE;
+
+ result = MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutms, QS_ALLINPUT);
+
+ if (result == WAIT_OBJECT_0) {
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ /* we processed messages */
+ RETVAL_TRUE;
+ } else {
+ /* we did not process messages (timed out) */
+ RETVAL_FALSE;
+ }
+}
+/* }}} */
+/* {{{ proto bool com_load_typelib(string typelib_name [, int case_insensitive])
+ Loads a Typelibrary and registers its constants */
+PHP_FUNCTION(com_load_typelib)
+{
+ char *name;
+ long namelen;
+ ITypeLib *pTL = NULL;
+ zend_bool cs = TRUE;
+ int codepage = COMG(code_page);
+ int cached = 0;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &name, &namelen, &cs)) {
+ return;
+ }
+
+ RETVAL_FALSE;
+
+ pTL = php_com_load_typelib_via_cache(name, codepage, &cached TSRMLS_CC);
+ if (pTL) {
+ if (cached) {
+ RETVAL_TRUE;
+ } else if (php_com_import_typelib(pTL, cs ? CONST_CS : 0, codepage TSRMLS_CC) == SUCCESS) {
+ RETVAL_TRUE;
+ }
+
+ ITypeLib_Release(pTL);
+ pTL = NULL;
+ }
+}
+/* }}} */
+
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/com_dotnet/com_dotnet.c b/ext/com_dotnet/com_dotnet.c
index 9b39b678e4..481fdaa815 100644
--- a/ext/com_dotnet/com_dotnet.c
+++ b/ext/com_dotnet/com_dotnet.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -109,7 +109,7 @@ PHP_FUNCTION(com_dotnet_create_instance)
if (COMG(dotnet_runtime_stuff) == NULL) {
if (FAILURE == dotnet_init(TSRMLS_C)) {
- php_com_throw_exception("Failed to initialize .Net runtime" TSRMLS_CC);
+ php_com_throw_exception(E_ERROR, "Failed to initialize .Net runtime" TSRMLS_CC);
ZVAL_NULL(object);
return;
}
@@ -123,7 +123,7 @@ PHP_FUNCTION(com_dotnet_create_instance)
&assembly_name, &assembly_name_len,
&datatype_name, &datatype_name_len,
&obj->code_page)) {
- php_com_throw_exception("Could not create .Net object - invalid arguments!" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "Could not create .Net object - invalid arguments!" TSRMLS_CC);
ZVAL_NULL(object);
return;
}
@@ -171,7 +171,7 @@ PHP_FUNCTION(com_dotnet_create_instance)
VariantClear(&vargs[1]);
if (ret == FAILURE) {
- php_com_throw_exception("Failed to instantiate .Net object" TSRMLS_CC);
+ php_com_throw_exception(hr, "Failed to instantiate .Net object" TSRMLS_CC);
ZVAL_NULL(object);
return;
}
diff --git a/ext/com_dotnet/com_extension.c b/ext/com_dotnet/com_extension.c
index 3c562672e9..6ecbb48886 100644
--- a/ext/com_dotnet/com_extension.c
+++ b/ext/com_dotnet/com_extension.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -31,7 +31,10 @@
ZEND_DECLARE_MODULE_GLOBALS(com_dotnet)
TsHashTable php_com_typelibraries;
-zend_class_entry *php_com_variant_class_entry;
+zend_class_entry
+ *php_com_variant_class_entry,
+ *php_com_exception_class_entry,
+ *php_com_saproxy_class_entry;
function_entry com_dotnet_functions[] = {
PHP_FE(variant_set, NULL)
@@ -60,7 +63,12 @@ function_entry com_dotnet_functions[] = {
PHP_FE(variant_get_type, NULL)
PHP_FE(variant_set_type, NULL)
PHP_FE(variant_cast, NULL)
+ /* com_com.c */
PHP_FE(com_create_guid, NULL)
+ PHP_FE(com_event_sink, NULL)
+ PHP_FE(com_print_typeinfo, NULL)
+ PHP_FE(com_message_pump, NULL)
+ PHP_FE(com_load_typelib, NULL)
{ NULL, NULL, NULL }
};
@@ -86,11 +94,77 @@ ZEND_GET_MODULE(com_dotnet)
/* {{{ PHP_INI
*/
+
+/* com.typelib_file is the path to a file containing a
+ * list of typelibraries to register *persistently*.
+ * lines starting with ; are comments
+ * append #cis to end of typelib name to cause its constants
+ * to be loaded case insensitively */
+static PHP_INI_MH(OnTypeLibFileUpdate)
+{
+ FILE *typelib_file;
+ char *typelib_name_buffer;
+ char *strtok_buf = NULL;
+ int cached;
+
+ if (!new_value || (typelib_file = VCWD_FOPEN(new_value, "r"))==NULL) {
+ return FAILURE;
+ }
+
+ typelib_name_buffer = (char *) emalloc(sizeof(char)*1024);
+
+ while (fgets(typelib_name_buffer, 1024, typelib_file)) {
+ ITypeLib *pTL;
+ char *typelib_name;
+ char *modifier, *ptr;
+ int mode = CONST_CS | CONST_PERSISTENT; /* CONST_PERSISTENT is ok here */
+
+ if (typelib_name_buffer[0]==';') {
+ continue;
+ }
+ typelib_name = php_strtok_r(typelib_name_buffer, "\r\n", &strtok_buf); /* get rid of newlines */
+ if (typelib_name == NULL) {
+ continue;
+ }
+ typelib_name = php_strtok_r(typelib_name, "#", &strtok_buf);
+ modifier = php_strtok_r(NULL, "#", &strtok_buf);
+ if (modifier != NULL) {
+ if (!strcmp(modifier, "cis") || !strcmp(modifier, "case_insensitive")) {
+ mode &= ~CONST_CS;
+ }
+ }
+
+ /* Remove leading/training white spaces on search_string */
+ while (isspace(*typelib_name)) {/* Ends on '\0' in worst case */
+ typelib_name ++;
+ }
+ ptr = typelib_name + strlen(typelib_name) - 1;
+ while ((ptr != typelib_name) && isspace(*ptr)) {
+ *ptr = '\0';
+ ptr--;
+ }
+
+ if ((pTL = php_com_load_typelib_via_cache(typelib_name, COMG(code_page), &cached TSRMLS_CC)) != NULL) {
+ if (!cached) {
+ php_com_import_typelib(pTL, mode, COMG(code_page) TSRMLS_CC);
+ }
+ ITypeLib_Release(pTL);
+ }
+ }
+
+ efree(typelib_name_buffer);
+ fclose(typelib_file);
+
+ return SUCCESS;
+}
+
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("com.allow_dcom", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_dcom, zend_com_dotnet_globals, com_dotnet_globals)
STD_PHP_INI_ENTRY("com.autoregister_verbose", "0", PHP_INI_ALL, OnUpdateBool, autoreg_verbose, zend_com_dotnet_globals, com_dotnet_globals)
STD_PHP_INI_ENTRY("com.autoregister_typelib", "0", PHP_INI_ALL, OnUpdateBool, autoreg_on, zend_com_dotnet_globals, com_dotnet_globals)
- STD_PHP_INI_ENTRY("com.autoregister_casesensitive", "0", PHP_INI_ALL, OnUpdateBool, autoreg_case_sensitive, zend_com_dotnet_globals, com_dotnet_globals)
+ STD_PHP_INI_ENTRY("com.autoregister_casesensitive", "1", PHP_INI_ALL, OnUpdateBool, autoreg_case_sensitive, zend_com_dotnet_globals, com_dotnet_globals)
+ STD_PHP_INI_ENTRY("com.code_page", "", PHP_INI_ALL, OnUpdateLong, code_page, zend_com_dotnet_globals, com_dotnet_globals)
+ PHP_INI_ENTRY("com.typelib_file", "", PHP_INI_SYSTEM, OnTypeLibFileUpdate)
PHP_INI_END()
/* }}} */
@@ -99,6 +173,7 @@ PHP_INI_END()
static void php_com_dotnet_init_globals(zend_com_dotnet_globals *com_dotnet_globals)
{
memset(com_dotnet_globals, 0, sizeof(*com_dotnet_globals));
+ com_dotnet_globals->code_page = CP_ACP;
}
/* }}} */
@@ -106,28 +181,44 @@ static void php_com_dotnet_init_globals(zend_com_dotnet_globals *com_dotnet_glob
*/
PHP_MINIT_FUNCTION(com_dotnet)
{
- zend_class_entry ce;
+ zend_class_entry ce, *tmp;
ZEND_INIT_MODULE_GLOBALS(com_dotnet, php_com_dotnet_init_globals, NULL);
REGISTER_INI_ENTRIES();
+ php_com_wrapper_minit(INIT_FUNC_ARGS_PASSTHRU);
+
+ INIT_CLASS_ENTRY(ce, "com_exception", NULL);
+ php_com_exception_class_entry = zend_register_internal_class_ex(&ce, zend_exception_get_default(), NULL TSRMLS_CC);
+ php_com_exception_class_entry->ce_flags |= ZEND_ACC_FINAL;
+ php_com_exception_class_entry->constructor->common.fn_flags |= ZEND_ACC_PROTECTED;
+
+ 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->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;
+// 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;
- zend_register_internal_class_ex(&ce, php_com_variant_class_entry, "variant" TSRMLS_CC);
+// 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;
zend_ts_hash_init(&php_com_typelibraries, 0, NULL, php_com_typelibrary_dtor, 1);
#if HAVE_MSCOREE_H
INIT_CLASS_ENTRY(ce, "dotnet", NULL);
ce.create_object = php_com_object_new;
- ce.get_iterator = php_com_iter_get;
- zend_register_internal_class_ex(&ce, php_com_variant_class_entry, "variant" TSRMLS_CC);
+// 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
#define COM_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS|CONST_PERSISTENT)
diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c
index f75aa1c355..d47922fe2a 100644
--- a/ext/com_dotnet/com_handlers.c
+++ b/ext/com_dotnet/com_handlers.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -51,7 +51,7 @@ static zval *com_property_read(zval *object, zval *member, zend_bool silent TSRM
}
} else {
if (!silent) {
- php_com_throw_exception("this variant has no properties" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
}
}
@@ -74,7 +74,7 @@ static void com_property_write(zval *object, zval *member, zval *value TSRMLS_DC
VariantClear(&v);
}
} else {
- php_com_throw_exception("this variant has no properties" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
}
}
@@ -115,7 +115,7 @@ static zval *com_read_dimension(zval *object, zval *offset TSRMLS_DC)
if (V_VT(&obj->v) == VT_DISPATCH) {
if (!obj->have_default_bind && !com_get_default_binding(obj TSRMLS_CC)) {
- php_com_throw_exception("this COM object has no default property" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "this COM object has no default property" TSRMLS_CC);
return return_value;
}
@@ -127,49 +127,19 @@ static zval *com_read_dimension(zval *object, zval *offset TSRMLS_DC)
VariantClear(&v);
}
} else if (V_ISARRAY(&obj->v)) {
- SAFEARRAY *sa = V_ARRAY(&obj->v);
- UINT dims;
- VARTYPE vt;
- LONG bound_low = 0, bound_high = 0;
- LONG indices[1];
-
- dims = SafeArrayGetDim(sa);
-
- if (dims != 1) {
- php_com_throw_exception("can only handle single dimension arrays" TSRMLS_CC);
- return return_value;
- }
-
- if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
- vt = V_VT(&obj->v) & ~VT_ARRAY;
- }
- SafeArrayGetUBound(sa, 1, &bound_high);
- SafeArrayGetLBound(sa, 1, &bound_low);
-
convert_to_long(offset);
- /* check bounds */
- if (Z_LVAL_P(offset) < bound_low || Z_LVAL_P(offset) > bound_high) {
- php_com_throw_exception("index out of bounds" TSRMLS_CC);
- return return_value;
+ if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {
+ if (php_com_safearray_get_elem(&obj->v, &v, Z_LVAL_P(offset) TSRMLS_CC)) {
+ php_com_wrap_variant(return_value, &v, obj->code_page TSRMLS_CC);
+ VariantClear(&v);
+ }
+ } else {
+ php_com_saproxy_create(object, return_value, Z_LVAL_P(offset) TSRMLS_CC);
}
- indices[0] = Z_LVAL_P(offset);
-
- VariantInit(&v);
- V_VT(&v) = vt;
- /* store the value into "lVal" member of the variant.
- * This works because it is a union; since we know the variant
- * type, we end up with a working variant */
- SafeArrayGetElement(sa, indices, &v.lVal);
-
- /* now we can set the return value from that element */
- php_com_wrap_variant(return_value, &v, obj->code_page TSRMLS_CC);
-
- VariantClear(&v);
-
} else {
- php_com_throw_exception("this variant is not an array type" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
}
return return_value;
@@ -185,7 +155,7 @@ static void com_write_dimension(zval *object, zval *offset, zval *value TSRMLS_D
if (V_VT(&obj->v) == VT_DISPATCH) {
if (!obj->have_default_bind && !com_get_default_binding(obj TSRMLS_CC)) {
- php_com_throw_exception("this COM object has no default property" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "this COM object has no default property" TSRMLS_CC);
return;
}
@@ -200,7 +170,7 @@ static void com_write_dimension(zval *object, zval *offset, zval *value TSRMLS_D
}
} else {
/* TODO: check for safearray */
- php_com_throw_exception("this variant is not an array type" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
}
}
@@ -345,7 +315,6 @@ static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
obj = CDNO_FETCH(getThis());
if (V_VT(&obj->v) != VT_DISPATCH) {
- //php_com_throw_exception("call to member function of non-object");
return FAILURE;
}
@@ -529,6 +498,30 @@ zend_object_handlers php_com_object_handlers = {
com_object_cast
};
+void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSRMLS_DC)
+{
+ if (obj->sink_dispatch) {
+ IConnectionPointContainer *cont;
+ IConnectionPoint *point;
+
+ if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v),
+ &IID_IConnectionPointContainer, (void**)&cont))) {
+
+ if (SUCCEEDED(IConnectionPointContainer_FindConnectionPoint(cont,
+ &obj->sink_id, &point))) {
+
+ if (enable) {
+ IConnectionPoint_Advise(point, (IUnknown*)obj->sink_dispatch, &obj->sink_cookie);
+ } else {
+ IConnectionPoint_Unadvise(point, obj->sink_cookie);
+ }
+ IConnectionPoint_Release(point);
+ }
+ IConnectionPointContainer_Release(cont);
+ }
+ }
+}
+
void php_com_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
{
php_com_dotnet_object *obj = (php_com_dotnet_object*)object;
@@ -538,8 +531,13 @@ void php_com_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
obj->typeinfo = NULL;
}
- VariantClear(&obj->v);
+ if (obj->sink_dispatch) {
+ php_com_object_enable_event_sink(obj, FALSE TSRMLS_CC);
+ IDispatch_Release(obj->sink_dispatch);
+ obj->sink_dispatch = NULL;
+ }
+ VariantClear(&obj->v);
efree(obj);
}
diff --git a/ext/com_dotnet/com_iterator.c b/ext/com_dotnet/com_iterator.c
index e4c31c6b30..c34460539d 100644
--- a/ext/com_dotnet/com_iterator.c
+++ b/ext/com_dotnet/com_iterator.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -33,8 +33,11 @@ struct php_com_iterator {
zend_object_iterator iter;
IEnumVARIANT *ev;
ulong key;
- VARIANT v;
+ VARIANT v; /* cached element */
int code_page;
+ VARIANT safe_array;
+ VARTYPE sa_type;
+ LONG sa_max;
};
static void com_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
@@ -45,6 +48,7 @@ static void com_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
IEnumVARIANT_Release(I->ev);
}
VariantClear(&I->v);
+ VariantClear(&I->safe_array);
efree(I);
}
@@ -71,7 +75,8 @@ static void com_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC
}
MAKE_STD_ZVAL(ptr);
- php_com_wrap_variant(ptr, &I->v, I->code_page TSRMLS_CC);
+ php_com_zval_from_variant(ptr, &I->v, I->code_page TSRMLS_CC);
+ /* php_com_wrap_variant(ptr, &I->v, I->code_page TSRMLS_CC); */
ptr_ptr = emalloc(sizeof(*ptr_ptr));
*ptr_ptr = ptr;
*data = ptr_ptr;
@@ -98,15 +103,30 @@ static int com_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
/* release current cached element */
VariantClear(&I->v);
-
- /* Get the next element */
- if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
- I->key++;
- return SUCCESS;
+
+ if (I->ev) {
+ /* Get the next element */
+ if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
+ I->key++;
+ return SUCCESS;
+ } else {
+ /* indicate that there are no more items */
+ I->key = (ulong)-1;
+ return FAILURE;
+ }
} else {
- /* indicate that there are no more items */
- I->key = (ulong)-1;
- return FAILURE;
+ /* safe array */
+ if (I->key >= I->sa_max) {
+ I->key = (ulong)-1;
+ return FAILURE;
+ }
+ I->key++;
+ if (php_com_safearray_get_elem(&I->safe_array, &I->v, (LONG)I->key TSRMLS_CC)) {
+ return SUCCESS;
+ } else {
+ I->key = (ulong)-1;
+ return FAILURE;
+ }
}
}
@@ -131,49 +151,89 @@ zend_object_iterator *php_com_iter_get(zend_class_entry *ce, zval *object TSRMLS
obj = CDNO_FETCH(object);
- /* TODO: support enumerating through SafeArrays */
- if (V_VT(&obj->v) != VT_DISPATCH) {
+ if (V_VT(&obj->v) != VT_DISPATCH && !V_ISARRAY(&obj->v)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "variant is not an object or array VT=%d", V_VT(&obj->v));
return NULL;
}
memset(&dp, 0, sizeof(dp));
VariantInit(&v);
- /* can we enumerate it? */
- if (FAILED(IDispatch_Invoke(V_DISPATCH(&obj->v), DISPID_NEWENUM,
- &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET,
- &dp, &v, NULL, NULL))) {
- return NULL;
- }
-
- /* get something useful out of it */
- if (V_VT(&v) == VT_UNKNOWN) {
- IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IEnumVARIANT, (void**)&iev);
- } else if (V_VT(&v) == VT_DISPATCH) {
- IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IEnumVARIANT, (void**)&iev);
- }
-
- VariantClear(&v);
-
- if (iev == NULL) {
- return NULL;
- }
-
I = (struct php_com_iterator*)ecalloc(1, sizeof(*I));
I->iter.funcs = &com_iter_funcs;
I->iter.data = I;
- I->ev = iev;
I->code_page = obj->code_page;
+ VariantInit(&I->safe_array);
+ VariantInit(&I->v);
- /* Get the first element now */
- if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
- /* indicate that we have element 0 */
- I->key = 0;
+ if (V_ISARRAY(&obj->v)) {
+ LONG bound;
+ UINT dims;
+
+ dims = SafeArrayGetDim(V_ARRAY(&obj->v));
+
+ if (dims != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Can only handle single dimension variant arrays (this array has %d)", dims);
+ goto fail;
+ }
+
+ /* same semantics as foreach on a PHP array;
+ * make a copy and enumerate that copy */
+ VariantCopy(&I->safe_array, &obj->v);
+
+ /* determine the key value for the array */
+ SafeArrayGetLBound(V_ARRAY(&I->safe_array), 1, &bound);
+ SafeArrayGetUBound(V_ARRAY(&I->safe_array), 1, &I->sa_max);
+
+ /* pre-fetch the element */
+ if (php_com_safearray_get_elem(&I->safe_array, &I->v, bound TSRMLS_CC)) {
+ I->key = bound;
+ } else {
+ I->key = (ulong)-1;
+ }
+
} else {
- /* indicate that there are no more items */
- I->key = (ulong)-1;
+ /* can we enumerate it? */
+ if (FAILED(IDispatch_Invoke(V_DISPATCH(&obj->v), DISPID_NEWENUM,
+ &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET,
+ &dp, &v, NULL, NULL))) {
+ goto fail;
+ }
+
+ /* get something useful out of it */
+ if (V_VT(&v) == VT_UNKNOWN) {
+ IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IEnumVARIANT, (void**)&iev);
+ } else if (V_VT(&v) == VT_DISPATCH) {
+ IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IEnumVARIANT, (void**)&iev);
+ }
+
+ VariantClear(&v);
+
+ if (iev == NULL) {
+ goto fail;
+ }
+
+ I->ev = iev;
+
+ /* Get the first element now */
+ if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
+ /* indicate that we have element 0 */
+ I->key = 0;
+ } else {
+ /* indicate that there are no more items */
+ I->key = (ulong)-1;
+ }
}
return &I->iter;
+
+fail:
+ if (I) {
+ VariantClear(&I->safe_array);
+ VariantClear(&I->v);
+ free(I);
+ }
+ return NULL;
}
diff --git a/ext/com_dotnet/com_misc.c b/ext/com_dotnet/com_misc.c
index 01d29cd3cf..b100c3d509 100644
--- a/ext/com_dotnet/com_misc.c
+++ b/ext/com_dotnet/com_misc.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -29,31 +29,17 @@
#include "php_com_dotnet_internal.h"
#include "Zend/zend_default_classes.h"
-zval *php_com_throw_exception(char *message TSRMLS_DC)
+void php_com_throw_exception(HRESULT code, char *message TSRMLS_DC)
{
- zval *e, *tmp;
-
- ALLOC_ZVAL(e);
- Z_TYPE_P(e) = IS_OBJECT;
- object_init_ex(e, zend_exception_get_default());
- e->refcount = 1;
- e->is_ref = 1;
-
- MAKE_STD_ZVAL(tmp);
- ZVAL_STRING(tmp, message, 1);
- zend_hash_update(Z_OBJPROP_P(e), "message", sizeof("message"), (void**)&tmp, sizeof(zval*), NULL);
-
- MAKE_STD_ZVAL(tmp);
- ZVAL_STRING(tmp, zend_get_executed_filename(TSRMLS_C), 1);
- zend_hash_update(Z_OBJPROP_P(e), "file", sizeof("file"), (void**)&tmp, sizeof(zval*), NULL);
-
- MAKE_STD_ZVAL(tmp);
- ZVAL_LONG(tmp, zend_get_executed_lineno(TSRMLS_C));
- zend_hash_update(Z_OBJPROP_P(e), "line", sizeof("line"), (void**)&tmp, sizeof(zval*), NULL);
-
- EG(exception) = e;
-
- return e;
+ int free_msg = 0;
+ if (message == NULL) {
+ message = php_win_err(code);
+ free_msg = 1;
+ }
+ zend_throw_exception(php_com_exception_class_entry, message, (long)code TSRMLS_CC);
+ if (free_msg) {
+ efree(message);
+ }
}
PHPAPI void php_com_wrap_dispatch(zval *z, IDispatch *disp,
@@ -89,7 +75,7 @@ PHPAPI void php_com_wrap_variant(zval *z, VARIANT *v,
obj->ce = php_com_variant_class_entry;
VariantInit(&obj->v);
- VariantCopy(&obj->v, v);
+ VariantCopyInd(&obj->v, v);
if (V_VT(&obj->v) == VT_DISPATCH) {
IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo);
@@ -100,3 +86,56 @@ PHPAPI void php_com_wrap_variant(zval *z, VARIANT *v,
z->value.obj.handle = zend_objects_store_put(obj, php_com_object_dtor, php_com_object_clone TSRMLS_CC);
z->value.obj.handlers = &php_com_object_handlers;
}
+
+/* this is a convenience function for fetching a particular
+ * element from a (possibly multi-dimensional) safe array */
+PHPAPI int php_com_safearray_get_elem(VARIANT *array, VARIANT *dest, LONG dim1 TSRMLS_DC)
+{
+ UINT dims;
+ LONG lbound, ubound;
+ LONG indices[1];
+ VARTYPE vt;
+
+ if (!V_ISARRAY(array)) {
+ return 0;
+ }
+
+ dims = SafeArrayGetDim(V_ARRAY(array));
+
+ if (dims != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Can only handle single dimension variant arrays (this array has %d)", dims);
+ return 0;
+ }
+
+ if (FAILED(SafeArrayGetVartype(V_ARRAY(array), &vt)) || vt == VT_EMPTY) {
+ vt = V_VT(array) & ~VT_ARRAY;
+ }
+
+ /* determine the bounds */
+ SafeArrayGetLBound(V_ARRAY(array), 1, &lbound);
+ SafeArrayGetUBound(V_ARRAY(array), 1, &ubound);
+
+ /* check bounds */
+ if (dim1 < lbound || dim1 > ubound) {
+ php_com_throw_exception(E_INVALIDARG, "index out of bounds" TSRMLS_CC);
+ return 0;
+ }
+
+ /* now fetch that element */
+ VariantInit(dest);
+
+ indices[0] = dim1;
+
+ if (vt == VT_VARIANT) {
+ SafeArrayGetElement(V_ARRAY(array), indices, dest);
+ } else {
+ V_VT(dest) = vt;
+ /* store the value into "lVal" member of the variant.
+ * This works because it is a union; since we know the variant
+ * type, we end up with a working variant */
+ SafeArrayGetElement(V_ARRAY(array), indices, &dest->lVal);
+ }
+
+ return 1;
+}
diff --git a/ext/com_dotnet/com_olechar.c b/ext/com_dotnet/com_olechar.c
index 578f5cb544..326de1d287 100644
--- a/ext/com_dotnet/com_olechar.c
+++ b/ext/com_dotnet/com_olechar.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -100,4 +100,4 @@ PHPAPI char *php_com_olestring_to_string(OLECHAR *olestring, uint *string_len, i
}
return string;
-} \ No newline at end of file
+}
diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c
new file mode 100644
index 0000000000..93682640e0
--- /dev/null
+++ b/ext/com_dotnet/com_saproxy.c
@@ -0,0 +1,430 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2003 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.0 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_0.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* This module implements a SafeArray proxy which is used internally
+ * by the engine when resolving multi-dimensional array accesses on
+ * SafeArray types
+ * */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_com_dotnet.h"
+#include "php_com_dotnet_internal.h"
+#include "Zend/zend_default_classes.h"
+
+typedef struct {
+ /* the object we a proxying for; we hold a refcount to it */
+ zval *zobj;
+ php_com_dotnet_object *obj;
+
+ /* how many dimensions we are indirecting to get into this element */
+ LONG dimensions;
+
+ /* this is an array whose size_is(dimensions) */
+ LONG *indices;
+
+} php_com_saproxy;
+
+typedef struct {
+ zend_object_iterator iter;
+ zval *proxy_obj;
+ php_com_saproxy *proxy;
+ LONG key;
+ LONG imin, imax;
+ LONG *indices;
+} php_com_saproxy_iter;
+
+#define SA_FETCH(zv) (php_com_saproxy*)zend_object_store_get_object(zv TSRMLS_CC)
+
+static zval *saproxy_property_read(zval *object, zval *member, zend_bool silent TSRMLS_DC)
+{
+ zval *return_value;
+
+ MAKE_STD_ZVAL(return_value);
+ ZVAL_NULL(return_value);
+
+ if (!silent) {
+ php_com_throw_exception(E_INVALIDARG, "safearray has no properties" TSRMLS_CC);
+ }
+
+ return return_value;
+}
+
+static void saproxy_property_write(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+ php_com_throw_exception(E_INVALIDARG, "safearray has no properties" TSRMLS_CC);
+}
+
+static zval *saproxy_read_dimension(zval *object, zval *offset TSRMLS_DC)
+{
+ php_com_saproxy *proxy = SA_FETCH(object);
+ zval *return_value;
+ UINT dims;
+ SAFEARRAY *sa;
+ LONG ubound, lbound;
+
+ 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);
+ return return_value;
+ }
+
+ /* offset/index must be an integer */
+ convert_to_long(offset);
+
+ sa = V_ARRAY(&proxy->obj->v);
+ dims = SafeArrayGetDim(sa);
+
+ if (proxy->dimensions >= dims) {
+ /* too many dimensions */
+ php_com_throw_exception(E_INVALIDARG, "too many dimensions!" TSRMLS_CC);
+ return return_value;
+ }
+
+ /* bounds check */
+ SafeArrayGetLBound(sa, proxy->dimensions, &lbound);
+ SafeArrayGetUBound(sa, proxy->dimensions, &ubound);
+
+ if (Z_LVAL_P(offset) < lbound || Z_LVAL_P(offset) > ubound) {
+ php_com_throw_exception(E_INVALIDARG, "index out of bounds" TSRMLS_CC);
+ return return_value;
+ }
+
+ if (dims - 1 == proxy->dimensions) {
+ LONG *indices;
+ VARTYPE vt;
+ VARIANT v;
+
+ VariantInit(&v);
+
+ /* we can return a real value */
+ indices = do_alloca(dims * sizeof(LONG));
+
+ /* copy indices from proxy */
+ memcpy(indices, proxy->indices, (dims-1) * sizeof(LONG));
+
+ /* add user-supplied index */
+ indices[dims-1] = Z_LVAL_P(offset);
+
+ /* now fetch the value */
+ if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
+ vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
+ }
+
+ if (vt == VT_VARIANT) {
+ SafeArrayGetElement(sa, indices, &v);
+ } else {
+ V_VT(&v) = vt;
+ SafeArrayGetElement(sa, indices, &v.lVal);
+ }
+
+ free_alloca(indices);
+
+ php_com_wrap_variant(return_value, &v, proxy->obj->code_page TSRMLS_CC);
+
+ VariantClear(&v);
+
+ } else {
+ /* return another proxy */
+ php_com_saproxy_create(object, return_value, Z_LVAL_P(offset) TSRMLS_CC);
+ }
+
+ return return_value;
+}
+
+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);
+}
+
+static void saproxy_object_set(zval **property, zval *value TSRMLS_DC)
+{
+}
+
+static zval *saproxy_object_get(zval *property TSRMLS_DC)
+{
+ /* Not yet implemented in the engine */
+ return NULL;
+}
+
+static int saproxy_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
+{
+ /* no properties */
+ return 0;
+}
+
+static int saproxy_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Operation not yet supported on a COM object");
+ return 0;
+}
+
+static void saproxy_property_delete(zval *object, zval *member TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
+}
+
+static void saproxy_dimension_delete(zval *object, zval *offset TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
+}
+
+static HashTable *saproxy_properties_get(zval *object TSRMLS_DC)
+{
+ /* no properties */
+ return NULL;
+}
+
+static union _zend_function *saproxy_method_get(zval *object, char *name, int len TSRMLS_DC)
+{
+ /* no methods */
+ return NULL;
+}
+
+static int saproxy_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
+{
+ return FAILURE;
+}
+
+static union _zend_function *saproxy_constructor_get(zval *object TSRMLS_DC)
+{
+ /* user cannot instanciate */
+ return NULL;
+}
+
+static zend_class_entry *saproxy_class_entry_get(zval *object TSRMLS_DC)
+{
+ return php_com_saproxy_class_entry;
+}
+
+static int saproxy_class_name_get(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
+{
+ *class_name = estrndup(php_com_saproxy_class_entry->name, php_com_saproxy_class_entry->name_length);
+ *class_name_len = php_com_saproxy_class_entry->name_length;
+ return 0;
+}
+
+static int saproxy_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
+{
+ return -1;
+}
+
+static int saproxy_object_cast(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC)
+{
+ return FAILURE;
+}
+
+zend_object_handlers php_com_saproxy_handlers = {
+ ZEND_OBJECTS_STORE_HANDLERS,
+ saproxy_property_read,
+ saproxy_property_write,
+ saproxy_read_dimension,
+ saproxy_write_dimension,
+ NULL,
+ saproxy_object_get,
+ saproxy_object_set,
+ saproxy_property_exists,
+ saproxy_property_delete,
+ saproxy_dimension_exists,
+ saproxy_dimension_delete,
+ saproxy_properties_get,
+ saproxy_method_get,
+ saproxy_call_method,
+ saproxy_constructor_get,
+ saproxy_class_entry_get,
+ saproxy_class_name_get,
+ saproxy_objects_compare,
+ saproxy_object_cast
+};
+
+static void saproxy_dtor(void *object, zend_object_handle handle TSRMLS_DC)
+{
+ php_com_saproxy *proxy = (php_com_saproxy *)object;
+
+ ZVAL_DELREF(proxy->zobj);
+ efree(proxy->indices);
+ efree(proxy);
+}
+
+static void saproxy_clone(void *object, void **clone_ptr TSRMLS_DC)
+{
+ php_com_saproxy *proxy = (php_com_saproxy *)object;
+ php_com_saproxy *cloneproxy;
+
+ 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));
+
+ *clone_ptr = cloneproxy;
+}
+
+int php_com_saproxy_create(zval *com_object, zval *proxy_out, long 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->zobj = rel->zobj;
+ proxy->dimensions += rel->dimensions;
+ } else {
+ obj = CDNO_FETCH(com_object);
+ proxy->zobj = com_object;
+ }
+
+ ZVAL_ADDREF(proxy->zobj);
+ proxy->indices = safe_emalloc(proxy->dimensions, sizeof(LONG), 0);
+
+ if (rel) {
+ memcpy(proxy->indices, rel->indices, (proxy->dimensions-1) * sizeof(LONG));
+ }
+
+ proxy->indices[proxy->dimensions-1] = index;
+
+ Z_TYPE_P(proxy_out) = IS_OBJECT;
+ Z_OBJ_HANDLE_P(proxy_out) = zend_objects_store_put(proxy, saproxy_dtor, saproxy_clone TSRMLS_CC);
+ Z_OBJ_HT_P(proxy_out) = &php_com_saproxy_handlers;
+
+ return 1;
+}
+
+/* iterator */
+
+static void saproxy_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
+{
+ php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
+
+ ZVAL_DELREF(I->proxy_obj);
+
+ efree(I->indices);
+ efree(I);
+}
+
+static int saproxy_iter_has_more(zend_object_iterator *iter TSRMLS_DC)
+{
+ php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
+
+ return (I->key < I->imax) ? SUCCESS : FAILURE;
+}
+
+static void saproxy_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+ php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
+ VARIANT v;
+ VARTYPE vt;
+ zval *return_value, **ptr_ptr;
+ SAFEARRAY *sa;
+
+ I->indices[I->proxy->dimensions-1] = I->key;
+
+ sa = V_ARRAY(&I->proxy->obj->v);
+
+ if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
+ vt = V_VT(&I->proxy->obj->v) & ~VT_ARRAY;
+ }
+
+ VariantInit(&v);
+ if (vt == VT_VARIANT) {
+ SafeArrayGetElement(sa, I->indices, &v);
+ } else {
+ V_VT(&v) = vt;
+ SafeArrayGetElement(sa, I->indices, &v.lVal);
+ }
+
+ MAKE_STD_ZVAL(return_value);
+ php_com_wrap_variant(return_value, &v, I->proxy->obj->code_page TSRMLS_CC);
+ VariantClear(&v);
+
+ ptr_ptr = emalloc(sizeof(*ptr_ptr));
+ *ptr_ptr = return_value;
+ *data = ptr_ptr;
+}
+
+static int saproxy_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
+ ulong *int_key TSRMLS_DC)
+{
+ php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
+
+ if (I->key == -1) {
+ return HASH_KEY_NON_EXISTANT;
+ }
+ *int_key = (ulong)I->key;
+ return HASH_KEY_IS_LONG;
+}
+
+static int saproxy_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
+{
+ php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
+
+ if (++I->key >= I->imax) {
+ I->key = -1;
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+static zend_object_iterator_funcs saproxy_iter_funcs = {
+ saproxy_iter_dtor,
+ saproxy_iter_has_more,
+ saproxy_iter_get_data,
+ saproxy_iter_get_key,
+ saproxy_iter_move_forwards,
+ NULL
+};
+
+
+zend_object_iterator *php_com_saproxy_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC)
+{
+ php_com_saproxy *proxy = SA_FETCH(object);
+ php_com_saproxy_iter *I;
+
+ I = ecalloc(1, sizeof(*I));
+ I->iter.funcs = &saproxy_iter_funcs;
+ I->iter.data = I;
+
+ I->proxy = proxy;
+ I->proxy_obj = object;
+ ZVAL_ADDREF(I->proxy_obj);
+
+ I->indices = safe_emalloc(proxy->dimensions + 1, sizeof(LONG), 0);
+ memcpy(I->indices, proxy->indices, proxy->dimensions * sizeof(LONG));
+
+ SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imin);
+ SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imax);
+
+ I->key = I->imin;
+
+ return &I->iter;
+}
+
diff --git a/ext/com_dotnet/com_typeinfo.c b/ext/com_dotnet/com_typeinfo.c
index 4acc88b6b0..84f3856659 100644
--- a/ext/com_dotnet/com_typeinfo.c
+++ b/ext/com_dotnet/com_typeinfo.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -35,8 +35,7 @@
* b) a CLSID, major, minor e.g. "{00000200-0000-0010-8000-00AA006D2EA4},2,0"
* c) a Type Library name e.g. "Microsoft OLE DB ActiveX Data Objects 1.0 Library"
*/
-PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int mode,
- int codepage TSRMLS_DC)
+PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int codepage TSRMLS_DC)
{
ITypeLib *TL = NULL;
char *strtok_buf, *major, *minor;
@@ -119,7 +118,7 @@ PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int mode,
/* get the default value for this key and compare */
libnamelen = strlen(search_string)+1;
if (ERROR_SUCCESS == RegQueryValue(hsubkey, version, libname, &libnamelen)) {
- if (0 == ((mode & CONST_CS) ? strcmp(libname, search_string) : stricmp(libname, search_string))) {
+ if (0 == stricmp(libname, search_string)) {
char *str = NULL;
int major, minor;
@@ -130,7 +129,7 @@ PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int mode,
}
spprintf(&str, 0, "%s,%d,%d", keyname, major, minor);
/* recurse */
- TL = php_com_load_typelib(str, mode, codepage TSRMLS_CC);
+ TL = php_com_load_typelib(str, codepage TSRMLS_CC);
efree(str);
break;
@@ -226,7 +225,7 @@ void php_com_typelibrary_dtor(void *pDest)
}
PHPAPI ITypeLib *php_com_load_typelib_via_cache(char *search_string,
- int mode, int codepage, int *cached TSRMLS_DC)
+ int codepage, int *cached TSRMLS_DC)
{
ITypeLib **TL;
char *name_dup;
@@ -244,7 +243,7 @@ PHPAPI ITypeLib *php_com_load_typelib_via_cache(char *search_string,
*cached = 0;
name_dup = estrndup(search_string, l);
- *TL = php_com_load_typelib(name_dup, mode, codepage TSRMLS_CC);
+ *TL = php_com_load_typelib(name_dup, codepage TSRMLS_CC);
efree(name_dup);
if (*TL) {
@@ -257,3 +256,346 @@ PHPAPI ITypeLib *php_com_load_typelib_via_cache(char *search_string,
return *TL;
}
+
+ITypeInfo *php_com_locate_typeinfo(char *typelibname, php_com_dotnet_object *obj, char *dispname, int sink TSRMLS_DC)
+{
+ ITypeInfo *typeinfo = NULL;
+ ITypeLib *typelib = NULL;
+ int gotguid = 0;
+ GUID iid;
+
+ if (obj) {
+ if (dispname == NULL && sink) {
+ IProvideClassInfo2 *pci2;
+ IProvideClassInfo *pci;
+
+ if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v), &IID_IProvideClassInfo2, (void**)&pci2))) {
+ gotguid = SUCCEEDED(IProvideClassInfo2_GetGUID(pci2, GUIDKIND_DEFAULT_SOURCE_DISP_IID, &iid));
+ IProvideClassInfo2_Release(pci2);
+ }
+ if (!gotguid && SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v), &IID_IProvideClassInfo, (void**)&pci))) {
+ /* examine the available interfaces */
+ /* TODO: write some code here */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "IProvideClassInfo: this code not yet written!");
+ IProvideClassInfo_Release(pci);
+ }
+ } else if (dispname == NULL) {
+ if (obj->typeinfo) {
+ ITypeInfo_AddRef(obj->typeinfo);
+ return obj->typeinfo;
+ } else {
+ IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &typeinfo);
+ if (typeinfo) {
+ return typeinfo;
+ }
+ }
+ } else if (dispname && obj->typeinfo) {
+ unsigned int idx;
+ /* get the library from the object; the rest will be dealt with later */
+ ITypeInfo_GetContainingTypeLib(obj->typeinfo, &typelib, &idx);
+ } else if (typelibname == NULL) {
+ IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &typeinfo);
+ if (dispname) {
+ unsigned int idx;
+ /* get the library from the object; the rest will be dealt with later */
+ ITypeInfo_GetContainingTypeLib(typeinfo, &typelib, &idx);
+
+ if (typelib) {
+ ITypeInfo_Release(typeinfo);
+ typeinfo = NULL;
+ }
+ }
+ }
+ } else if (typelibname) {
+ /* Fetch the typelibrary and use that to look things up */
+ typelib = php_com_load_typelib(typelibname, obj->code_page TSRMLS_CC);
+ }
+
+ if (!gotguid && dispname && typelib) {
+ unsigned short cfound;
+ MEMBERID memid;
+ OLECHAR *olename = php_com_string_to_olestring(dispname, strlen(dispname), CP_ACP TSRMLS_CC);
+
+ cfound = 1;
+ if (FAILED(ITypeLib_FindName(typelib, olename, 0, &typeinfo, &memid, &cfound)) || cfound == 0) {
+ CLSID coclass;
+ ITypeInfo *coinfo;
+
+ /* assume that it might be a progid instead */
+ if (SUCCEEDED(CLSIDFromProgID(olename, &coclass)) &&
+ SUCCEEDED(ITypeLib_GetTypeInfoOfGuid(typelib, &coclass, &coinfo))) {
+
+ /* enumerate implemented interfaces and pick the one as indicated by sink */
+ TYPEATTR *attr;
+ int i;
+
+ ITypeInfo_GetTypeAttr(coinfo, &attr);
+
+ for (i = 0; i < attr->cImplTypes; i++) {
+ HREFTYPE rt;
+ int tf;
+
+ if (FAILED(ITypeInfo_GetImplTypeFlags(coinfo, i, &tf))) {
+ continue;
+ }
+
+ if ((sink && tf == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) ||
+ (!sink && (tf & IMPLTYPEFLAG_FSOURCE) == 0)) {
+
+ /* flags match what we are looking for */
+
+ if (SUCCEEDED(ITypeInfo_GetRefTypeOfImplType(coinfo, i, &rt)))
+ if (SUCCEEDED(ITypeInfo_GetRefTypeInfo(coinfo, rt, &typeinfo)))
+ break;
+
+ }
+ }
+
+ ITypeInfo_ReleaseTypeAttr(coinfo, attr);
+ ITypeInfo_Release(coinfo);
+ }
+ }
+
+
+ efree(olename);
+ } else if (gotguid) {
+ ITypeLib_GetTypeInfoOfGuid(typelib, &iid, &typeinfo);
+ }
+
+ if (typelib) {
+ ITypeLib_Release(typelib);
+ }
+
+ return typeinfo;
+}
+
+static const struct {
+ VARTYPE vt;
+ const char *name;
+} vt_names[] = {
+ { VT_NULL, "VT_NULL" },
+ { VT_EMPTY, "VT_EMPTY" },
+ { VT_UI1, "VT_UI1" },
+ { VT_I2, "VT_I2" },
+ { VT_I4, "VT_I4" },
+ { VT_R4, "VT_R4" },
+ { VT_R8, "VT_R8" },
+ { VT_BOOL, "VT_BOOL" },
+ { VT_ERROR, "VT_ERROR" },
+ { VT_CY, "VT_CY" },
+ { VT_DATE, "VT_DATE" },
+ { VT_BSTR, "VT_BSTR" },
+ { VT_DECIMAL, "VT_DECIMAL" },
+ { VT_UNKNOWN, "VT_UNKNOWN" },
+ { VT_DISPATCH, "VT_DISPATCH" },
+ { VT_VARIANT, "VT_VARIANT" },
+ { VT_I1, "VT_I1" },
+ { VT_UI2, "VT_UI2" },
+ { VT_UI4, "VT_UI4" },
+ { VT_INT, "VT_INT" },
+ { VT_UINT, "VT_UINT" },
+ { VT_ARRAY, "VT_ARRAY" },
+ { VT_BYREF, "VT_BYREF" },
+ { VT_VOID, "VT_VOID" },
+ { VT_PTR, "VT_PTR" },
+ { VT_HRESULT, "VT_HRESULT" },
+ { 0, NULL }
+};
+
+static inline const char *vt_to_string(VARTYPE vt)
+{
+ int i;
+ for (i = 0; vt_names[i].name != NULL; i++) {
+ if (vt_names[i].vt == vt)
+ return vt_names[i].name;
+ }
+ return "?";
+}
+
+static char *php_com_string_from_clsid(const CLSID *clsid, int codepage TSRMLS_DC)
+{
+ LPOLESTR ole_clsid;
+ char *clsid_str;
+
+ StringFromCLSID(clsid, &ole_clsid);
+ clsid_str = php_com_olestring_to_string(ole_clsid, NULL, codepage TSRMLS_CC);
+ LocalFree(ole_clsid);
+
+ return clsid_str;
+}
+
+
+int php_com_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid, int codepage TSRMLS_DC)
+{
+ TYPEATTR *attr;
+ FUNCDESC *func;
+ int i;
+ OLECHAR *olename;
+ char *ansiname = NULL;
+ unsigned int ansinamelen;
+ int ret = 0;
+
+ if (FAILED(ITypeInfo_GetTypeAttr(typeinfo, &attr))) {
+ return 0;
+ }
+
+ /* verify that it is suitable */
+ if (id_to_name == NULL || attr->typekind == TKIND_DISPATCH) {
+
+ if (guid) {
+ memcpy(guid, &attr->guid, sizeof(GUID));
+ }
+
+ if (printdef) {
+ char *guidstring;
+
+ ITypeInfo_GetDocumentation(typeinfo, MEMBERID_NIL, &olename, NULL, NULL, NULL);
+ ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage TSRMLS_CC);
+ SysFreeString(olename);
+
+ guidstring = php_com_string_from_clsid(&attr->guid, codepage TSRMLS_CC);
+ php_printf("class %s { /* GUID=%s */\n", ansiname, guidstring);
+ efree(guidstring);
+
+ efree(ansiname);
+ }
+
+ if (id_to_name) {
+ zend_hash_init(id_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
+ }
+
+ /* So we've got the dispatch interface; lets list the event methods */
+ for (i = 0; i < attr->cFuncs; i++) {
+ zval *tmp;
+ DISPID lastid = 0; /* for props */
+ int isprop;
+
+ if (FAILED(ITypeInfo_GetFuncDesc(typeinfo, i, &func)))
+ break;
+
+ isprop = (func->invkind & DISPATCH_PROPERTYGET || func->invkind & DISPATCH_PROPERTYPUT);
+
+ if (!isprop || lastid != func->memid) {
+
+ lastid = func->memid;
+
+ ITypeInfo_GetDocumentation(typeinfo, func->memid, &olename, NULL, NULL, NULL);
+ ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage TSRMLS_CC);
+ SysFreeString(olename);
+
+ if (printdef) {
+ int j;
+ char *funcdesc;
+ unsigned int funcdesclen, cnames = 0;
+ BSTR *names;
+
+ names = (BSTR*)emalloc((func->cParams + 1) * sizeof(BSTR));
+
+ ITypeInfo_GetNames(typeinfo, func->memid, names, func->cParams + 1, &cnames);
+ /* first element is the function name */
+ SysFreeString(names[0]);
+
+ php_printf("\t/* DISPID=%d */\n", func->memid);
+
+ if (func->elemdescFunc.tdesc.vt != VT_VOID) {
+ php_printf("\t/* %s [%d] */\n",
+ vt_to_string(func->elemdescFunc.tdesc.vt),
+ func->elemdescFunc.tdesc.vt
+ );
+ }
+
+ if (isprop) {
+
+ ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
+ if (olename) {
+ funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage TSRMLS_CC);
+ SysFreeString(olename);
+ php_printf("\t/* %s */\n", funcdesc);
+ efree(funcdesc);
+ }
+
+ php_printf("\tvar $%s;\n\n", ansiname);
+
+ } else {
+ /* a function */
+
+ php_printf("\tfunction %s(\n", ansiname);
+
+ for (j = 0; j < func->cParams; j++) {
+ ELEMDESC *elem = &func->lprgelemdescParam[j];
+
+ php_printf("\t\t/* %s [%d] ", vt_to_string(elem->tdesc.vt), elem->tdesc.vt);
+
+ if (elem->paramdesc.wParamFlags & PARAMFLAG_FIN)
+ php_printf("[in]");
+ if (elem->paramdesc.wParamFlags & PARAMFLAG_FOUT)
+ php_printf("[out]");
+
+ if (elem->tdesc.vt == VT_PTR) {
+ /* what does it point to ? */
+ php_printf(" --> %s [%d] ",
+ vt_to_string(elem->tdesc.lptdesc->vt),
+ elem->tdesc.lptdesc->vt
+ );
+ }
+
+ /* when we handle prop put and get, this will look nicer */
+ if (j+1 < (int)cnames) {
+ funcdesc = php_com_olestring_to_string(names[j+1], &funcdesclen, codepage TSRMLS_CC);
+ SysFreeString(names[j+1]);
+ } else {
+ funcdesc = "???";
+ }
+
+ php_printf(" */ %s%s%c\n",
+ elem->tdesc.vt == VT_PTR ? "&$" : "$",
+ funcdesc,
+ j == func->cParams - 1 ? ' ' : ','
+ );
+
+ if (j+1 < (int)cnames) {
+ efree(funcdesc);
+ }
+ }
+
+ php_printf("\t\t)\n\t{\n");
+
+ ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
+ if (olename) {
+ funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage TSRMLS_CC);
+ SysFreeString(olename);
+ php_printf("\t\t/* %s */\n", funcdesc);
+ efree(funcdesc);
+ }
+
+ php_printf("\t}\n");
+ }
+
+ efree(names);
+ }
+
+ if (id_to_name) {
+ zend_str_tolower(ansiname, ansinamelen);
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, ansiname, ansinamelen, 0);
+ zend_hash_index_update(id_to_name, func->memid, (void*)&tmp, sizeof(zval *), NULL);
+ }
+ }
+ ITypeInfo_ReleaseFuncDesc(typeinfo, func);
+ }
+
+ if (printdef) {
+ php_printf("}\n");
+ }
+
+ ret = 1;
+ } else {
+ zend_error(E_WARNING, "That's not a dispatchable interface!! type kind = %08x", attr->typekind);
+ }
+
+ ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
+
+ return ret;
+}
+
+
diff --git a/ext/com_dotnet/com_variant.c b/ext/com_dotnet/com_variant.c
index a9b89c19ee..c848660a4c 100644
--- a/ext/com_dotnet/com_variant.c
+++ b/ext/com_dotnet/com_variant.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -59,8 +59,9 @@ PHPAPI void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage TSRMLS_D
V_VARIANTREF(v) = &obj->v;
}
} else {
- /* TODO: export the object using our COM wrapper */
- V_VT(v) = VT_NULL;
+ /* export the PHP object using our COM wrapper */
+ V_VT(v) = VT_DISPATCH;
+ V_DISPATCH(v) = php_com_wrapper_export(z TSRMLS_CC);
}
break;
@@ -168,6 +169,9 @@ PHPAPI int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage TSRMLS_DC
break;
case VT_VARIANT:
+ /* points to another variant */
+ return php_com_zval_from_variant(z, V_VARIANTREF(v), codepage TSRMLS_CC);
+
default:
php_com_wrap_variant(z, v, codepage TSRMLS_CC);
}
@@ -202,7 +206,7 @@ PHP_FUNCTION(com_variant_create_instance)
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"z!|ll", &zvalue, &vt, &codepage)) {
- php_com_throw_exception("Invalid arguments" TSRMLS_CC);
+ php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
return;
}
@@ -223,7 +227,7 @@ PHP_FUNCTION(com_variant_create_instance)
spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
LocalFree(werr);
- php_com_throw_exception(msg TSRMLS_CC);
+ php_com_throw_exception(res, msg TSRMLS_CC);
efree(msg);
}
}
@@ -254,6 +258,11 @@ PHP_FUNCTION(variant_set)
ITypeInfo_Release(obj->typeinfo);
obj->typeinfo = NULL;
}
+ if (obj->sink_dispatch) {
+ php_com_object_enable_event_sink(obj, FALSE TSRMLS_CC);
+ IDispatch_Release(obj->sink_dispatch);
+ obj->sink_dispatch = NULL;
+ }
VariantClear(&obj->v);
@@ -779,7 +788,7 @@ PHP_FUNCTION(variant_set_type)
spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
LocalFree(werr);
- php_com_throw_exception(msg TSRMLS_CC);
+ php_com_throw_exception(res, msg TSRMLS_CC);
efree(msg);
}
}
@@ -813,7 +822,7 @@ PHP_FUNCTION(variant_cast)
spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
LocalFree(werr);
- php_com_throw_exception(msg TSRMLS_CC);
+ php_com_throw_exception(res, msg TSRMLS_CC);
efree(msg);
}
diff --git a/ext/com_dotnet/com_wrapper.c b/ext/com_dotnet/com_wrapper.c
new file mode 100644
index 0000000000..349c937bf4
--- /dev/null
+++ b/ext/com_dotnet/com_wrapper.c
@@ -0,0 +1,640 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2003 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.0 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_0.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* This module exports a PHP object as a COM object by wrapping it
+ * using IDispatchEx */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_com_dotnet.h"
+#include "php_com_dotnet_internal.h"
+
+typedef struct {
+ /* This first part MUST match the declaration
+ * of interface IDispatchEx */
+ CONST_VTBL struct IDispatchExVtbl *lpVtbl;
+
+ /* now the PHP stuff */
+
+ THREAD_T engine_thread; /* for sanity checking */
+ zval *object; /* the object exported */
+ LONG refcount; /* COM reference count */
+
+ HashTable *dispid_to_name; /* keep track of dispid -> name mappings */
+ HashTable *name_to_dispid; /* keep track of name -> dispid mappings */
+
+ GUID sinkid; /* iid that we "implement" for event sinking */
+
+ int id;
+} php_dispatchex;
+
+static int le_dispatch;
+
+static void disp_destructor(php_dispatchex *disp);
+
+static void dispatch_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_dispatchex *disp = (php_dispatchex *)rsrc->ptr;
+ disp_destructor(disp);
+}
+
+int php_com_wrapper_minit(INIT_FUNC_ARGS)
+{
+ le_dispatch = zend_register_list_destructors_ex(dispatch_dtor,
+ NULL, "com_dotnet_dispatch_wrapper", module_number);
+ return le_dispatch;
+}
+
+
+/* {{{ trace */
+static inline void trace(char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ sprintf(buf, "T=%08x ", tsrm_thread_id());
+ OutputDebugString(buf);
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+ OutputDebugString(buf);
+
+ va_end(ap);
+}
+/* }}} */
+
+#define FETCH_DISP(methname) \
+ php_dispatchex *disp = (php_dispatchex*)This; \
+ trace(" PHP:%s %s\n", Z_OBJCE_P(disp->object)->name, methname); \
+ if (tsrm_thread_id() != disp->engine_thread) \
+ return E_UNEXPECTED;
+
+
+static HRESULT STDMETHODCALLTYPE disp_queryinterface(
+ IDispatchEx *This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("QueryInterface");
+
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDispatch, riid) ||
+ IsEqualGUID(&IID_IDispatchEx, riid) ||
+ IsEqualGUID(&disp->sinkid, riid)) {
+ *ppvObject = This;
+ InterlockedIncrement(&disp->refcount);
+ return S_OK;
+ }
+
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("AddRef");
+
+ return InterlockedIncrement(&disp->refcount);
+}
+
+static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
+{
+ ULONG ret;
+ TSRMLS_FETCH();
+
+ FETCH_DISP("Release");
+
+ ret = InterlockedDecrement(&disp->refcount);
+ trace("-- refcount now %d\n", ret);
+ if (ret == 0) {
+ /* destroy it */
+ if (disp->id)
+ zend_list_delete(disp->id);
+ }
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount(
+ IDispatchEx *This,
+ /* [out] */ UINT *pctinfo)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetTypeInfoCount");
+
+ *pctinfo = 0;
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_gettypeinfo(
+ IDispatchEx *This,
+ /* [in] */ UINT iTInfo,
+ /* [in] */ LCID lcid,
+ /* [out] */ ITypeInfo **ppTInfo)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetTypeInfo");
+
+ *ppTInfo = NULL;
+ return DISP_E_BADINDEX;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getidsofnames(
+ IDispatchEx *This,
+ /* [in] */ REFIID riid,
+ /* [size_is][in] */ LPOLESTR *rgszNames,
+ /* [in] */ UINT cNames,
+ /* [in] */ LCID lcid,
+ /* [size_is][out] */ DISPID *rgDispId)
+{
+ UINT i;
+ HRESULT ret = S_OK;
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetIDsOfNames");
+
+ for (i = 0; i < cNames; i++) {
+ char *name;
+ unsigned int namelen;
+ zval **tmp;
+
+ name = php_com_olestring_to_string(rgszNames[i], &namelen, COMG(code_page) TSRMLS_CC);
+
+ /* Lookup the name in the hash */
+ if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == FAILURE) {
+ ret = DISP_E_UNKNOWNNAME;
+ rgDispId[i] = 0;
+ } else {
+ rgDispId[i] = Z_LVAL_PP(tmp);
+ }
+
+ efree(name);
+
+ }
+
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_invoke(
+ IDispatchEx *This,
+ /* [in] */ DISPID dispIdMember,
+ /* [in] */ REFIID riid,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [out][in] */ DISPPARAMS *pDispParams,
+ /* [out] */ VARIANT *pVarResult,
+ /* [out] */ EXCEPINFO *pExcepInfo,
+ /* [out] */ UINT *puArgErr)
+{
+ return This->lpVtbl->InvokeEx(This, dispIdMember,
+ lcid, wFlags, pDispParams,
+ pVarResult, pExcepInfo, NULL);
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getdispid(
+ IDispatchEx *This,
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex,
+ /* [out] */ DISPID *pid)
+{
+ HRESULT ret = DISP_E_UNKNOWNNAME;
+ char *name;
+ unsigned int namelen;
+ zval **tmp;
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetDispID");
+
+ name = php_com_olestring_to_string(bstrName, &namelen, COMG(code_page) TSRMLS_CC);
+
+ /* Lookup the name in the hash */
+ if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) {
+ *pid = Z_LVAL_PP(tmp);
+ ret = S_OK;
+ }
+
+ efree(name);
+
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_invokeex(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [in] */ DISPPARAMS *pdp,
+ /* [out] */ VARIANT *pvarRes,
+ /* [out] */ EXCEPINFO *pei,
+ /* [unique][in] */ IServiceProvider *pspCaller)
+{
+ zval **name;
+ UINT i;
+ zval *retval = NULL;
+ zval ***params = NULL;
+ HRESULT ret = DISP_E_MEMBERNOTFOUND;
+ TSRMLS_FETCH();
+
+ FETCH_DISP("InvokeEx");
+
+ if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
+ /* TODO: add support for overloaded objects */
+
+ trace("-- Invoke: %d %20s flags=%08x args=%d\n", id, Z_STRVAL_PP(name), wFlags, pdp->cArgs);
+
+ /* convert args into zvals.
+ * Args are in reverse order */
+ params = (zval ***)emalloc(sizeof(zval **) * pdp->cArgs);
+ for (i = 0; i < pdp->cArgs; i++) {
+ VARIANT *arg;
+ zval *zarg;
+
+ arg = &pdp->rgvarg[ pdp->cArgs - 1 - i];
+
+ trace("alloc zval for arg %d VT=%08x\n", i, V_VT(arg));
+
+ ALLOC_INIT_ZVAL(zarg);
+ php_com_wrap_variant(zarg, arg, COMG(code_page) TSRMLS_CC);
+ params[i] = &zarg;
+ }
+
+ trace("arguments processed, prepare to do some work\n");
+
+ /* TODO: if PHP raises an exception here, we should catch it
+ * and expose it as a COM exception */
+
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ retval = zend_read_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, 1 TSRMLS_CC);
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ zend_update_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, *params[0] TSRMLS_CC);
+ } else if (wFlags & DISPATCH_METHOD) {
+ if (SUCCESS == call_user_function_ex(EG(function_table), &disp->object, *name,
+ &retval, pdp->cArgs, params, 1, NULL TSRMLS_CC)) {
+ ret = S_OK;
+ } else {
+ ret = DISP_E_EXCEPTION;
+ }
+ } else {
+ trace("Don't know how to handle this invocation %08x\n", wFlags);
+ }
+
+ /* release arguments */
+ for (i = 0; i < pdp->cArgs; i++)
+ zval_ptr_dtor(params[i]);
+ efree(params);
+
+ /* return value */
+ if (retval) {
+ if (pvarRes) {
+ if (Z_TYPE_P(retval) == IS_OBJECT) {
+ /* export the object using a dispatch like ourselves */
+ VariantInit(pvarRes);
+ V_VT(pvarRes) = VT_DISPATCH;
+ V_DISPATCH(pvarRes) = php_com_wrapper_export(retval TSRMLS_CC);
+ } else {
+ php_com_variant_from_zval(pvarRes, retval, COMG(code_page) TSRMLS_CC);
+ }
+ }
+ zval_ptr_dtor(&retval);
+ } else if (pvarRes) {
+ VariantInit(pvarRes);
+ }
+
+ } else {
+ trace("InvokeEx: I don't support DISPID=%d\n", id);
+ }
+
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_deletememberbyname(
+ IDispatchEx *This,
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("DeleteMemberByName");
+
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid(
+ IDispatchEx *This,
+ /* [in] */ DISPID id)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("DeleteMemberByDispID");
+
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getmemberproperties(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [in] */ DWORD grfdexFetch,
+ /* [out] */ DWORD *pgrfdex)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetMemberProperties");
+
+ return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getmembername(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [out] */ BSTR *pbstrName)
+{
+ zval *name;
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetMemberName");
+
+ if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
+ OLECHAR *olestr = php_com_string_to_olestring(Z_STRVAL_P(name), Z_STRLEN_P(name), COMG(code_page) TSRMLS_CC);
+ *pbstrName = SysAllocString(olestr);
+ efree(olestr);
+ return S_OK;
+ } else {
+ return DISP_E_UNKNOWNNAME;
+ }
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getnextdispid(
+ IDispatchEx *This,
+ /* [in] */ DWORD grfdex,
+ /* [in] */ DISPID id,
+ /* [out] */ DISPID *pid)
+{
+ ulong next = id+1;
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetNextDispID");
+
+ while(!zend_hash_index_exists(disp->dispid_to_name, next))
+ next++;
+
+ if (zend_hash_index_exists(disp->dispid_to_name, next)) {
+ *pid = next;
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent(
+ IDispatchEx *This,
+ /* [out] */ IUnknown **ppunk)
+{
+ TSRMLS_FETCH();
+
+ FETCH_DISP("GetNameSpaceParent");
+
+ *ppunk = NULL;
+ return E_NOTIMPL;
+}
+
+static struct IDispatchExVtbl php_dispatch_vtbl = {
+ disp_queryinterface,
+ disp_addref,
+ disp_release,
+ disp_gettypeinfocount,
+ disp_gettypeinfo,
+ disp_getidsofnames,
+ disp_invoke,
+ disp_getdispid,
+ disp_invokeex,
+ disp_deletememberbyname,
+ disp_deletememberbydispid,
+ disp_getmemberproperties,
+ disp_getmembername,
+ disp_getnextdispid,
+ disp_getnamespaceparent
+};
+
+
+/* enumerate functions and properties of the object and assign
+ * dispatch ids */
+static void generate_dispids(php_dispatchex *disp TSRMLS_DC)
+{
+ HashPosition pos;
+ char *name = NULL;
+ zval *tmp;
+ int namelen;
+ int keytype;
+ ulong pid;
+
+ if (disp->dispid_to_name == NULL) {
+ ALLOC_HASHTABLE(disp->dispid_to_name);
+ ALLOC_HASHTABLE(disp->name_to_dispid);
+ zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_init(disp->dispid_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
+ }
+
+ /* properties */
+ if (Z_OBJPROP_P(disp->object)) {
+ zend_hash_internal_pointer_reset_ex(Z_OBJPROP_P(disp->object), &pos);
+ while (HASH_KEY_NON_EXISTANT != (keytype =
+ zend_hash_get_current_key_ex(Z_OBJPROP_P(disp->object), &name,
+ &namelen, &pid, 0, &pos))) {
+ char namebuf[32];
+ if (keytype == HASH_KEY_IS_LONG) {
+ sprintf(namebuf, "%d", pid);
+ name = namebuf;
+ namelen = strlen(namebuf);
+ }
+
+ zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
+
+ /* Find the existing id */
+ if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
+ continue;
+
+ /* add the mappings */
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, name, namelen, 1);
+ zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_LONG(tmp, pid);
+ zend_hash_update(disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
+ }
+ }
+
+ /* functions */
+ if (Z_OBJCE_P(disp->object)) {
+ zend_hash_internal_pointer_reset_ex(&Z_OBJCE_P(disp->object)->function_table, &pos);
+ while (HASH_KEY_NON_EXISTANT != (keytype =
+ zend_hash_get_current_key_ex(&Z_OBJCE_P(disp->object)->function_table,
+ &name, &namelen, &pid, 0, &pos))) {
+
+ char namebuf[32];
+ if (keytype == HASH_KEY_IS_LONG) {
+ sprintf(namebuf, "%d", pid);
+ name = namebuf;
+ namelen = strlen(namebuf);
+ }
+
+ zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
+
+ /* Find the existing id */
+ if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
+ continue;
+
+ /* add the mappings */
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, name, namelen, 1);
+ zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_LONG(tmp, pid);
+ zend_hash_update(disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
+ }
+ }
+}
+
+static php_dispatchex *disp_constructor(zval *object TSRMLS_DC)
+{
+ php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
+
+ trace("constructing a COM proxy\n");
+
+ if (disp == NULL)
+ return NULL;
+
+ memset(disp, 0, sizeof(php_dispatchex));
+
+ disp->engine_thread = tsrm_thread_id();
+ disp->lpVtbl = &php_dispatch_vtbl;
+ disp->refcount = 1;
+
+
+ if (object)
+ ZVAL_ADDREF(object);
+ disp->object = object;
+
+ disp->id = zend_list_insert(disp, le_dispatch);
+
+ return disp;
+}
+
+static void disp_destructor(php_dispatchex *disp)
+{
+ TSRMLS_FETCH();
+
+ trace("destroying COM wrapper for PHP object %s\n", Z_OBJCE_P(disp->object)->name);
+
+ disp->id = 0;
+
+ if (disp->refcount > 0)
+ CoDisconnectObject((IUnknown*)disp, 0);
+
+ zend_hash_destroy(disp->dispid_to_name);
+ zend_hash_destroy(disp->name_to_dispid);
+ FREE_HASHTABLE(disp->dispid_to_name);
+ FREE_HASHTABLE(disp->name_to_dispid);
+
+ if (disp->object)
+ zval_ptr_dtor(&disp->object);
+
+ CoTaskMemFree(disp);
+}
+
+PHPAPI IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid,
+ HashTable *id_to_name TSRMLS_DC)
+{
+ php_dispatchex *disp = disp_constructor(val TSRMLS_CC);
+ HashPosition pos;
+ char *name = NULL;
+ zval *tmp, **ntmp;
+ int namelen;
+ int keytype;
+ ulong pid;
+
+ disp->dispid_to_name = id_to_name;
+
+ memcpy(&disp->sinkid, sinkid, sizeof(disp->sinkid));
+
+ /* build up the reverse mapping */
+ ALLOC_HASHTABLE(disp->name_to_dispid);
+ zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ zend_hash_internal_pointer_reset_ex(id_to_name, &pos);
+ while (HASH_KEY_NON_EXISTANT != (keytype =
+ zend_hash_get_current_key_ex(id_to_name, &name, &namelen, &pid, 0, &pos))) {
+
+ if (keytype == HASH_KEY_IS_LONG) {
+
+ zend_hash_get_current_data_ex(id_to_name, (void**)&ntmp, &pos);
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_LONG(tmp, pid);
+ zend_hash_update(disp->name_to_dispid, Z_STRVAL_PP(ntmp),
+ Z_STRLEN_PP(ntmp)+1, (void*)&tmp, sizeof(zval *), NULL);
+ }
+
+ zend_hash_move_forward_ex(id_to_name, &pos);
+ }
+
+ return (IDispatch*)disp;
+}
+
+PHPAPI IDispatch *php_com_wrapper_export(zval *val TSRMLS_DC)
+{
+ php_dispatchex *disp = NULL;
+
+ if (Z_TYPE_P(val) != IS_OBJECT)
+ return NULL;
+
+ if (php_com_is_valid_object(val TSRMLS_CC)) {
+ /* pass back its IDispatch directly */
+ php_com_dotnet_object *obj = CDNO_FETCH(val);
+
+ if (obj == NULL)
+ return NULL;
+
+ if (V_VT(&obj->v) == VT_DISPATCH && V_DISPATCH(&obj->v)) {
+ IDispatch_AddRef(V_DISPATCH(&obj->v));
+ return V_DISPATCH(&obj->v);
+ }
+
+ return NULL;
+ }
+
+ disp = disp_constructor(val TSRMLS_CC);
+ generate_dispids(disp TSRMLS_CC);
+
+ return (IDispatch*)disp;
+}
+
+
diff --git a/ext/com_dotnet/config.w32 b/ext/com_dotnet/config.w32
index 917c62a040..cc1f3b86f6 100644
--- a/ext/com_dotnet/config.w32
+++ b/ext/com_dotnet/config.w32
@@ -7,7 +7,7 @@ if (PHP_COM_DOTNET == "yes") {
CHECK_LIB('oleaut32.lib', 'com_dotnet');
EXTENSION("com_dotnet", "com_com.c com_dotnet.c com_extension.c \
com_handlers.c com_iterator.c com_misc.c com_olechar.c \
- com_typeinfo.c com_variant.c");
+ com_typeinfo.c com_variant.c com_wrapper.c com_saproxy.c");
AC_DEFINE('HAVE_COM_DOTNET', 1, 'Have COM_DOTNET support');
CHECK_HEADER_ADD_INCLUDE('mscoree.h', 'CFLAGS_COM_DOTNET');
}
diff --git a/ext/com_dotnet/php_com_dotnet.h b/ext/com_dotnet/php_com_dotnet.h
index 831c7ad3c0..cfb2340726 100644
--- a/ext/com_dotnet/php_com_dotnet.h
+++ b/ext/com_dotnet/php_com_dotnet.h
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -40,14 +40,13 @@ PHP_RINIT_FUNCTION(com_dotnet);
PHP_RSHUTDOWN_FUNCTION(com_dotnet);
PHP_MINFO_FUNCTION(com_dotnet);
-PHP_FUNCTION(com_create_guid);
-
ZEND_BEGIN_MODULE_GLOBALS(com_dotnet)
zend_bool allow_dcom;
zend_bool autoreg_verbose;
zend_bool autoreg_on;
zend_bool autoreg_case_sensitive;
void *dotnet_runtime_stuff; /* opaque to avoid cluttering up other modules */
+ int code_page; /* default code_page if left unspecified */
ZEND_END_MODULE_GLOBALS(com_dotnet)
#ifdef ZTS
diff --git a/ext/com_dotnet/php_com_dotnet_internal.h b/ext/com_dotnet/php_com_dotnet_internal.h
index 7aae5b3538..37fbf94bcb 100644
--- a/ext/com_dotnet/php_com_dotnet_internal.h
+++ b/ext/com_dotnet/php_com_dotnet_internal.h
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
@@ -41,6 +41,11 @@ typedef struct _php_com_dotnet_object {
zend_class_entry *ce;
DISPID default_bind; /* default property for array accesses */
+
+ /* associated event sink */
+ IDispatch *sink_dispatch;
+ GUID sink_id;
+ DWORD sink_cookie;
} php_com_dotnet_object;
static inline int php_com_is_valid_object(zval *zv TSRMLS_DC)
@@ -54,7 +59,7 @@ static inline int php_com_is_valid_object(zval *zv TSRMLS_DC)
#define CDNO_FETCH(zv) (php_com_dotnet_object*)zend_object_store_get_object(zv TSRMLS_CC)
#define CDNO_FETCH_VERIFY(obj, zv) do { \
if (!php_com_is_valid_object(zv TSRMLS_CC)) { \
- php_com_throw_exception("expected a variant object" TSRMLS_CC); \
+ php_com_throw_exception(E_UNEXPECTED, "expected a variant object" TSRMLS_CC); \
return; \
} \
obj = (php_com_dotnet_object*)zend_object_store_get_object(zv TSRMLS_CC); \
@@ -62,13 +67,18 @@ static inline int php_com_is_valid_object(zval *zv TSRMLS_DC)
/* com_extension.c */
TsHashTable php_com_typelibraries;
-zend_class_entry *php_com_variant_class_entry;
+zend_class_entry *php_com_variant_class_entry, *php_com_exception_class_entry, *php_com_saproxy_class_entry;
/* com_handlers.c */
zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC);
void php_com_object_clone(void *object, void **clone_ptr TSRMLS_DC);
void php_com_object_dtor(void *object, zend_object_handle handle TSRMLS_DC);
zend_object_handlers php_com_object_handlers;
+void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSRMLS_DC);
+
+/* 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);
/* com_olechar.c */
PHPAPI char *php_com_olestring_to_string(OLECHAR *olestring,
@@ -79,6 +89,12 @@ PHPAPI OLECHAR *php_com_string_to_olestring(char *string,
/* com_com.c */
PHP_FUNCTION(com_create_instance);
+PHP_FUNCTION(com_event_sink);
+PHP_FUNCTION(com_create_guid);
+PHP_FUNCTION(com_print_typeinfo);
+PHP_FUNCTION(com_message_pump);
+PHP_FUNCTION(com_load_typelib);
+
HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
WORD flags, DISPPARAMS *disp_params, VARIANT *v TSRMLS_DC);
HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
@@ -88,6 +104,11 @@ int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
int php_com_do_invoke(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);
+PHPAPI IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid, HashTable *id_to_name TSRMLS_DC);
+PHPAPI IDispatch *php_com_wrapper_export(zval *val TSRMLS_DC);
+
/* com_variant.c */
PHP_FUNCTION(com_variant_create_instance);
PHP_FUNCTION(variant_set);
@@ -127,20 +148,22 @@ void php_com_dotnet_rshutdown(TSRMLS_D);
void php_com_dotnet_mshutdown(TSRMLS_D);
/* com_misc.c */
-zval *php_com_throw_exception(char *message TSRMLS_DC);
+void php_com_throw_exception(HRESULT code, char *message TSRMLS_DC);
PHPAPI void php_com_wrap_dispatch(zval *z, IDispatch *disp,
int codepage TSRMLS_DC);
PHPAPI void php_com_wrap_variant(zval *z, VARIANT *v,
int codepage TSRMLS_DC);
+PHPAPI int php_com_safearray_get_elem(VARIANT *array, VARIANT *dest, LONG dim1 TSRMLS_DC);
/* com_typeinfo.c */
PHPAPI ITypeLib *php_com_load_typelib_via_cache(char *search_string,
- int mode, int codepage, int *cached TSRMLS_DC);
-PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int mode,
- int codepage TSRMLS_DC);
+ int codepage, int *cached TSRMLS_DC);
+PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int codepage TSRMLS_DC);
PHPAPI int php_com_import_typelib(ITypeLib *TL, int mode,
int codepage TSRMLS_DC);
void php_com_typelibrary_dtor(void *pDest);
+ITypeInfo *php_com_locate_typeinfo(char *typelibname, php_com_dotnet_object *obj, char *dispname, int sink TSRMLS_DC);
+int php_com_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid, int codepage TSRMLS_DC);
/* com_iterator.c */
zend_object_iterator *php_com_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC);