diff options
-rw-r--r-- | ext/com/COM.c | 39 | ||||
-rw-r--r-- | ext/com/conversion.c | 19 | ||||
-rw-r--r-- | ext/com/dispatch.c | 547 | ||||
-rw-r--r-- | ext/com/php_COM.h | 18 | ||||
-rw-r--r-- | ext/rpc/com/com_wrapper.c | 39 | ||||
-rw-r--r-- | ext/rpc/com/conversion.c | 19 | ||||
-rw-r--r-- | ext/rpc/com/dispatch.c | 547 | ||||
-rw-r--r-- | ext/rpc/com/php_com.h | 18 |
8 files changed, 1234 insertions, 12 deletions
diff --git a/ext/com/COM.c b/ext/com/COM.c index cb42bfc4f7..f8149faf7c 100644 --- a/ext/com/COM.c +++ b/ext/com/COM.c @@ -65,7 +65,6 @@ #include "php_VARIANT.h" static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC); -static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC); static int do_COM_offget(VARIANT *result, comval *array, pval *property, int cleanup TSRMLS_DC); static int do_COM_propget(VARIANT *var_result, comval *obj, pval *arg_property, int cleanup TSRMLS_DC); static void php_register_COM_class(TSRMLS_D); @@ -1424,6 +1423,32 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere return SUCCESS; } +/* create an overloaded COM object from a dispatch pointer */ +PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC) +{ + comval *obj; + long rid; + zval *zobj; + + ALLOC_COM(obj); + C_DISPATCH(obj) = disp; + php_COM_set(obj, &C_DISPATCH(obj), FALSE TSRMLS_CC); + + /* resource */ + rid = zend_list_insert(obj, IS_COM); + + if (val == NULL) + MAKE_STD_ZVAL(val); + ZVAL_RESOURCE(val, rid); + + /* now we want an object */ + MAKE_STD_ZVAL(zobj); + object_init_ex(zobj, &COM_class_entry); + zend_hash_index_update(Z_OBJPROP_P(zobj), 0, &val, sizeof(zval *), NULL); + + return zobj; +} + PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference) { @@ -1672,7 +1697,7 @@ static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC) } -static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC) +PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC) { ITypeComp *TypeComp; int i; @@ -1800,11 +1825,18 @@ static void php_COM_init(int module_number TSRMLS_DC) php_register_COM_class(TSRMLS_C); } +PHPAPI ZEND_DECLARE_MODULE_GLOBALS(com) + +static void php_com_init_globals(zend_com_globals *com_globals) +{ +} PHP_MINIT_FUNCTION(COM) { + ZEND_INIT_MODULE_GLOBALS(com, php_com_init_globals, NULL); php_COM_init(module_number TSRMLS_CC); php_VARIANT_init(module_number TSRMLS_CC); + php_COM_dispatch_init(module_number TSRMLS_CC); REGISTER_LONG_CONSTANT("CLSCTX_INPROC_SERVER", CLSCTX_INPROC_SERVER, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CLSCTX_INPROC_HANDLER", CLSCTX_INPROC_HANDLER, CONST_CS | CONST_PERSISTENT); @@ -1818,7 +1850,6 @@ PHP_MINIT_FUNCTION(COM) return SUCCESS; } - PHP_MSHUTDOWN_FUNCTION(COM) { UNREGISTER_INI_ENTRIES(); @@ -1835,7 +1866,7 @@ zend_module_entry COM_module_entry = { PHP_MSHUTDOWN(COM), NULL, NULL, - PHP_MINFO(COM), + PHP_MINFO(COM), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; diff --git a/ext/com/conversion.c b/ext/com/conversion.c index 0adcefdf47..130885edd9 100644 --- a/ext/com/conversion.c +++ b/ext/com/conversion.c @@ -58,6 +58,8 @@ PHPAPI void php_pval_to_variant(pval *pval_arg, VARIANT *var_arg, int codepage T type = VT_VARIANT|VT_BYREF; } else if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) { type = VT_DISPATCH; + } else { + type = VT_DISPATCH; } break; @@ -155,6 +157,12 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, } } else { switch (V_VT(var_arg)) { + + case VT_NULL: + case VT_VOID: + ZVAL_NULL(pval_arg); + break; + case VT_UI1: convert_to_long_ex(&pval_arg); V_UI1(var_arg) = (unsigned char) Z_LVAL_P(pval_arg); @@ -211,6 +219,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, /** @todo case IS_STRING: + */ /* string representation of a time value */ default: @@ -262,7 +271,13 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, break; case VT_DISPATCH: - comval_to_variant(pval_arg, var_arg TSRMLS_CC); + if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) { + comval_to_variant(pval_arg, var_arg TSRMLS_CC); + } else { + V_DISPATCH(var_arg) = php_COM_export_object(pval_arg TSRMLS_CC); + if (V_DISPATCH(var_arg)) + V_VT(var_arg) = VT_DISPATCH; + } if (V_VT(var_arg) != VT_DISPATCH) { VariantInit(var_arg); } @@ -437,7 +452,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, break; default: - php_error(E_WARNING, "Type not supported or not yet implemented."); + php_error(E_WARNING,"Unsupported variant type: %d (0x%X)", V_VT(var_arg), V_VT(var_arg)); } } } diff --git a/ext/com/dispatch.c b/ext/com/dispatch.c new file mode 100644 index 0000000000..802c4f871e --- /dev/null +++ b/ext/com/dispatch.c @@ -0,0 +1,547 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2002 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.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 is used to export PHP objects to COM and DOTNET by exposing + * them as objects implementing IDispatch. + * */ + +#include "php.h" +#include "php_COM.h" +#include "php_VARIANT.h" +#include "conversion.h" +#include "variant.h" + +#define COBJMACROS +#include <unknwn.h> /* IDispatch */ +#include <dispex.h> /* IDispatchEx */ + + +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 */ + + int id; +} php_dispatchex; + +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); +} + +static int le_dispatch; +int php_COM_dispatch_init(int module_number TSRMLS_DC) +{ + le_dispatch = zend_register_list_destructors_ex(dispatch_dtor, NULL, "COM:Dispatch", 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) +{ + FETCH_DISP("QueryInterface"); + + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDispatch, riid) || + IsEqualGUID(&IID_IDispatchEx, riid)) { + *ppvObject = This; + InterlockedIncrement(&disp->refcount); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This) +{ + 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) +{ + FETCH_DISP("GetTypeInfoCount"); + + *pctinfo = 0; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE disp_gettypeinfo( + IDispatchEx *This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo) +{ + 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_OLECHAR_to_char(rgszNames[i], &namelen, CP_ACP 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_P(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_OLECHAR_to_char(bstrName, &namelen, CP_ACP 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_P(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; + int codepage = CP_ACP; + zval **retval = NULL; + zval ***params = NULL; + 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 %s\n", id, Z_STRVAL_P(name)); + + /* convert args into zvals. + * Args are in reverse order */ + params = (zval ***)emalloc(sizeof(zval **) * pdp->cArgs); + for (i = 0; i < pdp->cArgs; i++) { + ALLOC_INIT_ZVAL(*params[i]); + + if (V_VT(&pdp->rgvarg[pdp->cArgs-i]) == VT_DISPATCH) { + php_COM_object_from_dispatch(V_DISPATCH(&pdp->rgvarg[pdp->cArgs-i]), *params[i] TSRMLS_CC); + } else { + ZVAL_VARIANT(*params[i], &pdp->rgvarg[pdp->cArgs-i]); + } + } + + if (wFlags & DISPATCH_PROPERTYGET) { + zend_hash_find(Z_OBJPROP_P(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&retval); + } else if (wFlags & DISPATCH_PROPERTYPUT) { + add_property_zval(disp->object, Z_STRVAL_P(name), *params[0]); + } else if (wFlags & DISPATCH_METHOD) { + + call_user_function_ex(EG(function_table), &disp->object, name, + retval, pdp->cArgs, params, 1, NULL TSRMLS_CC); + } + + /* release arguments */ + for (i = 0; i < pdp->cArgs; i++) + zval_ptr_dtor(params[i]); + + /* return value */ + if (retval) { + if (pvarRes) { + if (Z_TYPE_PP(retval) == IS_OBJECT) { + /* export the object using a dispatch like ourselves */ + VariantInit(pvarRes); + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = php_COM_export_object(*retval TSRMLS_CC); + } else { + php_pval_to_variant(*retval, pvarRes, codepage TSRMLS_CC); + } + } + zval_ptr_dtor(retval); + } else if (pvarRes) { + VariantInit(pvarRes); + } + + return S_OK; + } else { + trace("InvokeEx: I don't support DISPID=%d\n", id); + } + + return DISP_E_MEMBERNOTFOUND; +} + +static HRESULT STDMETHODCALLTYPE disp_deletememberbyname( + IDispatchEx *This, + /* [in] */ BSTR bstrName, + /* [in] */ DWORD grfdex) +{ + FETCH_DISP("DeleteMemberByName"); + + return S_FALSE; +} + +static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid( + IDispatchEx *This, + /* [in] */ DISPID id) +{ + FETCH_DISP("DeleteMemberByDispID"); + + return S_FALSE; +} + +static HRESULT STDMETHODCALLTYPE disp_getmemberproperties( + IDispatchEx *This, + /* [in] */ DISPID id, + /* [in] */ DWORD grfdexFetch, + /* [out] */ DWORD *pgrfdex) +{ + 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_char_to_OLECHAR(Z_STRVAL_P(name), Z_STRLEN_P(name), CP_ACP 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; + 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) +{ + 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 update_dispids(php_dispatchex *disp TSRMLS_DC) +{ + HashPosition pos; + char *name = NULL; + zval *tmp; + int namelen; + int keytype; + ulong pid; + + /* properties */ + zend_hash_internal_pointer_reset_ex(Z_OBJPROP_PP(&disp->object), &pos); + while (HASH_KEY_NON_EXISTANT != (keytype = + zend_hash_get_current_key_ex(Z_OBJPROP_PP(&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_PP(&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 */ + zend_hash_internal_pointer_reset_ex(&Z_OBJCE_PP(&disp->object)->function_table, &pos); + while (HASH_KEY_NON_EXISTANT != (keytype = + zend_hash_get_current_key_ex(&Z_OBJCE_PP(&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_PP(&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)); + + 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; + + zend_hash_init(&disp->dispid_to_name, 0, NULL, NULL, TRUE); + zend_hash_init(&disp->name_to_dispid, 0, NULL, NULL, TRUE); + + if (object) + ZVAL_ADDREF(object); + disp->object = object; + + update_dispids(disp TSRMLS_CC); + + 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); + + if (disp->object) + zval_ptr_dtor(&disp->object); + + + CoTaskMemFree(disp); +} + + +PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC) +{ + if (Z_TYPE_P(val) != IS_OBJECT) + return NULL; + + if (Z_OBJCE_P(val) == &COM_class_entry) { + /* pass back it's IDispatch directly */ + zval **tmp; + comval *obj; + int type; + + zend_hash_index_find(Z_OBJPROP_P(val), 0, (void**)&tmp); + obj = (comval *)zend_list_find(Z_LVAL_PP(tmp), &type); + if (type != IS_COM) + return NULL; + + C_DISPATCH(obj)->lpVtbl->AddRef(C_DISPATCH(obj)); + return C_DISPATCH(obj); + } + return (IDispatch*)disp_constructor(val TSRMLS_CC); +} + + diff --git a/ext/com/php_COM.h b/ext/com/php_COM.h index 5c0155515b..396df9c93c 100644 --- a/ext/com/php_COM.h +++ b/ext/com/php_COM.h @@ -31,6 +31,12 @@ PHPAPI int php_COM_get_le_comval(); PHPAPI int php_COM_set_property_handler(zend_property_reference *property_reference, pval *value); PHPAPI pval php_COM_get_property_handler(zend_property_reference *property_reference); PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference); +PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC); +PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC); + +/* dispatch.c */ +PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC); +int php_COM_dispatch_init(int module_number TSRMLS_DC); zend_module_entry COM_module_entry; zend_class_entry COM_class_entry; @@ -43,6 +49,18 @@ END_EXTERN_C() #define phpext_com_ptr &COM_module_entry +ZEND_BEGIN_MODULE_GLOBALS(com) + int nothing; +ZEND_END_MODULE_GLOBALS(com) + +PHPAPI ZEND_EXTERN_MODULE_GLOBALS(com); + +#ifdef ZTS +#define COMG(v) TSRMG(com_globals_id, zend_com_globals *, v) +#else +#define COMG(v) (com_globals.v) +#endif + #else #define phpext_com_ptr NULL diff --git a/ext/rpc/com/com_wrapper.c b/ext/rpc/com/com_wrapper.c index cb42bfc4f7..f8149faf7c 100644 --- a/ext/rpc/com/com_wrapper.c +++ b/ext/rpc/com/com_wrapper.c @@ -65,7 +65,6 @@ #include "php_VARIANT.h" static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC); -static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC); static int do_COM_offget(VARIANT *result, comval *array, pval *property, int cleanup TSRMLS_DC); static int do_COM_propget(VARIANT *var_result, comval *obj, pval *arg_property, int cleanup TSRMLS_DC); static void php_register_COM_class(TSRMLS_D); @@ -1424,6 +1423,32 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere return SUCCESS; } +/* create an overloaded COM object from a dispatch pointer */ +PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC) +{ + comval *obj; + long rid; + zval *zobj; + + ALLOC_COM(obj); + C_DISPATCH(obj) = disp; + php_COM_set(obj, &C_DISPATCH(obj), FALSE TSRMLS_CC); + + /* resource */ + rid = zend_list_insert(obj, IS_COM); + + if (val == NULL) + MAKE_STD_ZVAL(val); + ZVAL_RESOURCE(val, rid); + + /* now we want an object */ + MAKE_STD_ZVAL(zobj); + object_init_ex(zobj, &COM_class_entry); + zend_hash_index_update(Z_OBJPROP_P(zobj), 0, &val, sizeof(zval *), NULL); + + return zobj; +} + PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference) { @@ -1672,7 +1697,7 @@ static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC) } -static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC) +PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC) { ITypeComp *TypeComp; int i; @@ -1800,11 +1825,18 @@ static void php_COM_init(int module_number TSRMLS_DC) php_register_COM_class(TSRMLS_C); } +PHPAPI ZEND_DECLARE_MODULE_GLOBALS(com) + +static void php_com_init_globals(zend_com_globals *com_globals) +{ +} PHP_MINIT_FUNCTION(COM) { + ZEND_INIT_MODULE_GLOBALS(com, php_com_init_globals, NULL); php_COM_init(module_number TSRMLS_CC); php_VARIANT_init(module_number TSRMLS_CC); + php_COM_dispatch_init(module_number TSRMLS_CC); REGISTER_LONG_CONSTANT("CLSCTX_INPROC_SERVER", CLSCTX_INPROC_SERVER, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CLSCTX_INPROC_HANDLER", CLSCTX_INPROC_HANDLER, CONST_CS | CONST_PERSISTENT); @@ -1818,7 +1850,6 @@ PHP_MINIT_FUNCTION(COM) return SUCCESS; } - PHP_MSHUTDOWN_FUNCTION(COM) { UNREGISTER_INI_ENTRIES(); @@ -1835,7 +1866,7 @@ zend_module_entry COM_module_entry = { PHP_MSHUTDOWN(COM), NULL, NULL, - PHP_MINFO(COM), + PHP_MINFO(COM), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; diff --git a/ext/rpc/com/conversion.c b/ext/rpc/com/conversion.c index 0adcefdf47..130885edd9 100644 --- a/ext/rpc/com/conversion.c +++ b/ext/rpc/com/conversion.c @@ -58,6 +58,8 @@ PHPAPI void php_pval_to_variant(pval *pval_arg, VARIANT *var_arg, int codepage T type = VT_VARIANT|VT_BYREF; } else if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) { type = VT_DISPATCH; + } else { + type = VT_DISPATCH; } break; @@ -155,6 +157,12 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, } } else { switch (V_VT(var_arg)) { + + case VT_NULL: + case VT_VOID: + ZVAL_NULL(pval_arg); + break; + case VT_UI1: convert_to_long_ex(&pval_arg); V_UI1(var_arg) = (unsigned char) Z_LVAL_P(pval_arg); @@ -211,6 +219,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, /** @todo case IS_STRING: + */ /* string representation of a time value */ default: @@ -262,7 +271,13 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, break; case VT_DISPATCH: - comval_to_variant(pval_arg, var_arg TSRMLS_CC); + if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) { + comval_to_variant(pval_arg, var_arg TSRMLS_CC); + } else { + V_DISPATCH(var_arg) = php_COM_export_object(pval_arg TSRMLS_CC); + if (V_DISPATCH(var_arg)) + V_VT(var_arg) = VT_DISPATCH; + } if (V_VT(var_arg) != VT_DISPATCH) { VariantInit(var_arg); } @@ -437,7 +452,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type, break; default: - php_error(E_WARNING, "Type not supported or not yet implemented."); + php_error(E_WARNING,"Unsupported variant type: %d (0x%X)", V_VT(var_arg), V_VT(var_arg)); } } } diff --git a/ext/rpc/com/dispatch.c b/ext/rpc/com/dispatch.c new file mode 100644 index 0000000000..802c4f871e --- /dev/null +++ b/ext/rpc/com/dispatch.c @@ -0,0 +1,547 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2002 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.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 is used to export PHP objects to COM and DOTNET by exposing + * them as objects implementing IDispatch. + * */ + +#include "php.h" +#include "php_COM.h" +#include "php_VARIANT.h" +#include "conversion.h" +#include "variant.h" + +#define COBJMACROS +#include <unknwn.h> /* IDispatch */ +#include <dispex.h> /* IDispatchEx */ + + +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 */ + + int id; +} php_dispatchex; + +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); +} + +static int le_dispatch; +int php_COM_dispatch_init(int module_number TSRMLS_DC) +{ + le_dispatch = zend_register_list_destructors_ex(dispatch_dtor, NULL, "COM:Dispatch", 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) +{ + FETCH_DISP("QueryInterface"); + + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDispatch, riid) || + IsEqualGUID(&IID_IDispatchEx, riid)) { + *ppvObject = This; + InterlockedIncrement(&disp->refcount); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This) +{ + 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) +{ + FETCH_DISP("GetTypeInfoCount"); + + *pctinfo = 0; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE disp_gettypeinfo( + IDispatchEx *This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo) +{ + 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_OLECHAR_to_char(rgszNames[i], &namelen, CP_ACP 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_P(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_OLECHAR_to_char(bstrName, &namelen, CP_ACP 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_P(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; + int codepage = CP_ACP; + zval **retval = NULL; + zval ***params = NULL; + 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 %s\n", id, Z_STRVAL_P(name)); + + /* convert args into zvals. + * Args are in reverse order */ + params = (zval ***)emalloc(sizeof(zval **) * pdp->cArgs); + for (i = 0; i < pdp->cArgs; i++) { + ALLOC_INIT_ZVAL(*params[i]); + + if (V_VT(&pdp->rgvarg[pdp->cArgs-i]) == VT_DISPATCH) { + php_COM_object_from_dispatch(V_DISPATCH(&pdp->rgvarg[pdp->cArgs-i]), *params[i] TSRMLS_CC); + } else { + ZVAL_VARIANT(*params[i], &pdp->rgvarg[pdp->cArgs-i]); + } + } + + if (wFlags & DISPATCH_PROPERTYGET) { + zend_hash_find(Z_OBJPROP_P(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&retval); + } else if (wFlags & DISPATCH_PROPERTYPUT) { + add_property_zval(disp->object, Z_STRVAL_P(name), *params[0]); + } else if (wFlags & DISPATCH_METHOD) { + + call_user_function_ex(EG(function_table), &disp->object, name, + retval, pdp->cArgs, params, 1, NULL TSRMLS_CC); + } + + /* release arguments */ + for (i = 0; i < pdp->cArgs; i++) + zval_ptr_dtor(params[i]); + + /* return value */ + if (retval) { + if (pvarRes) { + if (Z_TYPE_PP(retval) == IS_OBJECT) { + /* export the object using a dispatch like ourselves */ + VariantInit(pvarRes); + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = php_COM_export_object(*retval TSRMLS_CC); + } else { + php_pval_to_variant(*retval, pvarRes, codepage TSRMLS_CC); + } + } + zval_ptr_dtor(retval); + } else if (pvarRes) { + VariantInit(pvarRes); + } + + return S_OK; + } else { + trace("InvokeEx: I don't support DISPID=%d\n", id); + } + + return DISP_E_MEMBERNOTFOUND; +} + +static HRESULT STDMETHODCALLTYPE disp_deletememberbyname( + IDispatchEx *This, + /* [in] */ BSTR bstrName, + /* [in] */ DWORD grfdex) +{ + FETCH_DISP("DeleteMemberByName"); + + return S_FALSE; +} + +static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid( + IDispatchEx *This, + /* [in] */ DISPID id) +{ + FETCH_DISP("DeleteMemberByDispID"); + + return S_FALSE; +} + +static HRESULT STDMETHODCALLTYPE disp_getmemberproperties( + IDispatchEx *This, + /* [in] */ DISPID id, + /* [in] */ DWORD grfdexFetch, + /* [out] */ DWORD *pgrfdex) +{ + 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_char_to_OLECHAR(Z_STRVAL_P(name), Z_STRLEN_P(name), CP_ACP 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; + 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) +{ + 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 update_dispids(php_dispatchex *disp TSRMLS_DC) +{ + HashPosition pos; + char *name = NULL; + zval *tmp; + int namelen; + int keytype; + ulong pid; + + /* properties */ + zend_hash_internal_pointer_reset_ex(Z_OBJPROP_PP(&disp->object), &pos); + while (HASH_KEY_NON_EXISTANT != (keytype = + zend_hash_get_current_key_ex(Z_OBJPROP_PP(&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_PP(&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 */ + zend_hash_internal_pointer_reset_ex(&Z_OBJCE_PP(&disp->object)->function_table, &pos); + while (HASH_KEY_NON_EXISTANT != (keytype = + zend_hash_get_current_key_ex(&Z_OBJCE_PP(&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_PP(&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)); + + 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; + + zend_hash_init(&disp->dispid_to_name, 0, NULL, NULL, TRUE); + zend_hash_init(&disp->name_to_dispid, 0, NULL, NULL, TRUE); + + if (object) + ZVAL_ADDREF(object); + disp->object = object; + + update_dispids(disp TSRMLS_CC); + + 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); + + if (disp->object) + zval_ptr_dtor(&disp->object); + + + CoTaskMemFree(disp); +} + + +PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC) +{ + if (Z_TYPE_P(val) != IS_OBJECT) + return NULL; + + if (Z_OBJCE_P(val) == &COM_class_entry) { + /* pass back it's IDispatch directly */ + zval **tmp; + comval *obj; + int type; + + zend_hash_index_find(Z_OBJPROP_P(val), 0, (void**)&tmp); + obj = (comval *)zend_list_find(Z_LVAL_PP(tmp), &type); + if (type != IS_COM) + return NULL; + + C_DISPATCH(obj)->lpVtbl->AddRef(C_DISPATCH(obj)); + return C_DISPATCH(obj); + } + return (IDispatch*)disp_constructor(val TSRMLS_CC); +} + + diff --git a/ext/rpc/com/php_com.h b/ext/rpc/com/php_com.h index 5c0155515b..396df9c93c 100644 --- a/ext/rpc/com/php_com.h +++ b/ext/rpc/com/php_com.h @@ -31,6 +31,12 @@ PHPAPI int php_COM_get_le_comval(); PHPAPI int php_COM_set_property_handler(zend_property_reference *property_reference, pval *value); PHPAPI pval php_COM_get_property_handler(zend_property_reference *property_reference); PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference); +PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC); +PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC); + +/* dispatch.c */ +PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC); +int php_COM_dispatch_init(int module_number TSRMLS_DC); zend_module_entry COM_module_entry; zend_class_entry COM_class_entry; @@ -43,6 +49,18 @@ END_EXTERN_C() #define phpext_com_ptr &COM_module_entry +ZEND_BEGIN_MODULE_GLOBALS(com) + int nothing; +ZEND_END_MODULE_GLOBALS(com) + +PHPAPI ZEND_EXTERN_MODULE_GLOBALS(com); + +#ifdef ZTS +#define COMG(v) TSRMG(com_globals_id, zend_com_globals *, v) +#else +#define COMG(v) (com_globals.v) +#endif + #else #define phpext_com_ptr NULL |