diff options
| -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); | 
