]> granicus.if.org Git - php/commitdiff
Port other major parts of PHP 4 COM extension into PHP 5 com_dotnet
authorWez Furlong <wez@php.net>
Wed, 7 Jan 2004 21:00:07 +0000 (21:00 +0000)
committerWez Furlong <wez@php.net>
Wed, 7 Jan 2004 21:00:07 +0000 (21:00 +0000)
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?

14 files changed:
ext/com_dotnet/com_com.c
ext/com_dotnet/com_dotnet.c
ext/com_dotnet/com_extension.c
ext/com_dotnet/com_handlers.c
ext/com_dotnet/com_iterator.c
ext/com_dotnet/com_misc.c
ext/com_dotnet/com_olechar.c
ext/com_dotnet/com_saproxy.c [new file with mode: 0644]
ext/com_dotnet/com_typeinfo.c
ext/com_dotnet/com_variant.c
ext/com_dotnet/com_wrapper.c [new file with mode: 0644]
ext/com_dotnet/config.w32
ext/com_dotnet/php_com_dotnet.h
ext/com_dotnet/php_com_dotnet_internal.h

index 9183a013a0095cc456b2094db072f82e78dbeeb4..73c8337d11cff26bcca771c38a9877948ea9008c 100644 (file)
@@ -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
+ */
index 9b39b678e46cf73123518e5e396eebecb1f80f5d..481fdaa815c5fcd2b2a675ef9adc53d91b3f5913 100644 (file)
@@ -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;
        }
index 3c562672e9d62daf6afcd99924adc16796d36d4d..6ecbb48886dda42537b1ff73b633162220ec50f5 100644 (file)
@@ -1,6 +1,6 @@
 /*
    +----------------------------------------------------------------------+
-   | PHP Version 4                                                        |
+   | PHP Version 5                                                        |
    +----------------------------------------------------------------------+
    | Copyright (c) 1997-2003 The PHP Group                                |
    +----------------------------------------------------------------------+
 
 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)
index f75aa1c355a317fe323e6580d804be0f9803f589..d47922fe2ad3dcfcfa0fd379a2e3ac87aa9e0f1b 100644 (file)
@@ -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);
 }
 
index e4c31c6b30b04ac402cd580f90d3c8d810d4250a..c34460539d9222e45b9b94edf22568862210570d 100644 (file)
@@ -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;
 }
 
index 01d29cd3cfed6283088dbbd7064a4e9d6a9c6647..b100c3d5090183ffc157e5254cb4c37fddb092b6 100644 (file)
@@ -1,6 +1,6 @@
 /*
    +----------------------------------------------------------------------+
-   | PHP Version 4                                                        |
+   | PHP Version 5                                                        |
    +----------------------------------------------------------------------+
    | Copyright (c) 1997-2003 The PHP Group                                |
    +----------------------------------------------------------------------+
 #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;       
+}
index 578f5cb544a2c14ce83139444a0f110bde620d76..326de1d287c83af7169d3a63540f0bb9cb1a4a19 100644 (file)
@@ -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 (file)
index 0000000..9368264
--- /dev/null
@@ -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;
+}
+
index 4acc88b6b0af5845ee7c18cb59be16d9f39627f5..84f38566595f23f5d6d0b615e60b18ed3418bd3c 100644 (file)
@@ -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;
+}
+
+
index a9b89c19ee1ece07b3ce540282351fcf5553e06f..c848660a4c1cd31996b30c6ab53825755132842e 100644 (file)
@@ -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 (file)
index 0000000..349c937
--- /dev/null
@@ -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;
+}
+
+
index 917c62a0405dbf540540fcd92a7957eea3dc03a6..cc1f3b86f62b996f779b254f807c3772f763114c 100644 (file)
@@ -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');
 }
index 831c7ad3c0faf1b08891c306decab1395197cd73..cfb234072634c020997502959ce025b9ad6bc76a 100644 (file)
@@ -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
index 7aae5b353870b98338b973cf8f1396aee7a6109d..37fbf94bcb057478fab07858679a19e061d6e3ec 100644 (file)
@@ -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);