📄 dispatch.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 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_01.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: dispatch.c,v 1.3.6.2.4.2 2007/01/01 09:46:40 sebastian Exp $ *//* * 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 */ GUID sinkid; /* iid that we "implement" for event sinking */ 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) || 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; 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_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_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_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; int codepage = CP_ACP; 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); if (V_VT(arg) == VT_DISPATCH) { trace("arg %d is dispatchable\n", i); if (NULL == php_COM_object_from_dispatch(V_DISPATCH(arg), zarg TSRMLS_CC)) { trace("failed to convert arg %d to zval\n", i); ZVAL_NULL(zarg); } } else { /* arg can't be an idispatch, so we don't care for the implicit AddRef() call here */ if (FAILURE == php_variant_to_pval(arg, zarg, codepage TSRMLS_CC)) { trace("failed to convert arg %d to zval\n", i); ZVAL_NULL(zarg); } } params[i] = &zarg; } trace("arguments processed, prepare to do some work\n"); if (wFlags & DISPATCH_PROPERTYGET) { trace("trying to get a property\n"); zend_hash_find(Z_OBJPROP_P(disp->object), Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, (void**)&retval); } else if (wFlags & DISPATCH_PROPERTYPUT) { trace("trying to set a property\n"); add_property_zval(disp->object, Z_STRVAL_PP(name), *params[0]); } else if (wFlags & DISPATCH_METHOD) { trace("Trying to call user function\n"); 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++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -