diff options
Diffstat (limited to 'ext/com_dotnet/com_wrapper.c')
-rw-r--r-- | ext/com_dotnet/com_wrapper.c | 635 |
1 files changed, 0 insertions, 635 deletions
diff --git a/ext/com_dotnet/com_wrapper.c b/ext/com_dotnet/com_wrapper.c deleted file mode 100644 index 0236d2e1ab..0000000000 --- a/ext/com_dotnet/com_wrapper.c +++ /dev/null @@ -1,635 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2005 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 */ - - DWORD 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 ", GetCurrentThreadId()); - OutputDebugString(buf); - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - - OutputDebugString(buf); - - va_end(ap); -} -/* }}} */ - -#ifdef ZTS -# define TSRMLS_FIXED() TSRMLS_FETCH(); -#else -# define TSRMLS_FIXED() -#endif - -#define FETCH_DISP(methname) \ - TSRMLS_FIXED() \ - php_dispatchex *disp = (php_dispatchex*)This; \ - trace(" PHP:%s %s\n", Z_OBJCE_P(disp->object)->name, methname); \ - if (GetCurrentThreadId() != disp->engine_thread) \ - return RPC_E_WRONG_THREAD; - - -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) || - IsEqualGUID(&disp->sinkid, 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; - 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; - 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; - FETCH_DISP("GetDispID"); - - name = php_com_olestring_to_string(bstrName, &namelen, COMG(code_page) TSRMLS_CC); - - trace("Looking for %s, namelen=%d in %p\n", name, namelen, disp->name_to_dispid); - - /* Lookup the name in the hash */ - if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) { - trace("found it\n"); - *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; - 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 [%d] flags=%08x args=%d\n", id, Z_STRVAL_PP(name), Z_STRLEN_PP(name), wFlags, pdp->cArgs); - - /* convert args into zvals. - * Args are in reverse order */ - if (pdp->cArgs) { - params = (zval ***)safe_emalloc(sizeof(zval **), pdp->cArgs, 0); - 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] = (zval**)emalloc(sizeof(zval**)); - *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) { - zend_try { - if (SUCCESS == call_user_function_ex(EG(function_table), &disp->object, *name, - &retval, pdp->cArgs, params, 1, NULL TSRMLS_CC)) { - ret = S_OK; - trace("function called ok\n"); - } else { - trace("failed to call func\n"); - ret = DISP_E_EXCEPTION; - } - } zend_catch { - trace("something blew up\n"); - ret = DISP_E_EXCEPTION; - } zend_end_try(); - } else { - trace("Don't know how to handle this invocation %08x\n", wFlags); - } - - /* release arguments */ - if (params) { - for (i = 0; i < pdp->cArgs; i++) { - zval_ptr_dtor(params[i]); - efree(params[i]); - } - efree(params); - } - - /* return value */ - if (retval) { - if (pvarRes) { - VariantInit(pvarRes); - 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) -{ - FETCH_DISP("DeleteMemberByName"); - - /* TODO: unset */ - - return S_FALSE; -} - -static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid( - IDispatchEx *This, - /* [in] */ DISPID id) -{ - FETCH_DISP("DeleteMemberByDispID"); - - /* TODO: unset */ - - 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; - 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; - 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 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)+1; - } - - 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, (void**)&tmp) == SUCCESS) - continue; - - /* add the mappings */ - MAKE_STD_ZVAL(tmp); - ZVAL_STRINGL(tmp, name, namelen-1, 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, (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) + 1; - } - - 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, (void**)&tmp) == SUCCESS) - continue; - - /* add the mappings */ - MAKE_STD_ZVAL(tmp); - ZVAL_STRINGL(tmp, name, namelen-1, 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, (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 = GetCurrentThreadId(); - 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; -} - - |