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