File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / com_dotnet / com_wrapper.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:36 2012 UTC (12 years, 2 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2012 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Author: Wez Furlong  <wez@thebrainroom.com>                          |
   16:    +----------------------------------------------------------------------+
   17:  */
   18: 
   19: /* $Id: com_wrapper.c,v 1.1.1.2 2012/05/29 12:34:36 misho Exp $ */
   20: 
   21: /* This module exports a PHP object as a COM object by wrapping it
   22:  * using IDispatchEx */
   23: 
   24: #ifdef HAVE_CONFIG_H
   25: #include "config.h"
   26: #endif
   27: 
   28: #include "php.h"
   29: #include "php_ini.h"
   30: #include "ext/standard/info.h"
   31: #include "php_com_dotnet.h"
   32: #include "php_com_dotnet_internal.h"
   33: 
   34: typedef struct {
   35: 	/* This first part MUST match the declaration
   36: 	 * of interface IDispatchEx */
   37: 	CONST_VTBL struct IDispatchExVtbl *lpVtbl;
   38: 
   39: 	/* now the PHP stuff */
   40: 	
   41: 	DWORD engine_thread; /* for sanity checking */
   42: 	zval *object;			/* the object exported */
   43: 	LONG refcount;			/* COM reference count */
   44: 
   45: 	HashTable *dispid_to_name;	/* keep track of dispid -> name mappings */
   46: 	HashTable *name_to_dispid;	/* keep track of name -> dispid mappings */
   47: 
   48: 	GUID sinkid;	/* iid that we "implement" for event sinking */
   49: 	
   50: 	int id;
   51: } php_dispatchex;
   52: 
   53: static int le_dispatch;
   54: 
   55: static void disp_destructor(php_dispatchex *disp TSRMLS_DC);
   56: 
   57: static void dispatch_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
   58: {
   59: 	php_dispatchex *disp = (php_dispatchex *)rsrc->ptr;
   60: 	disp_destructor(disp TSRMLS_CC);
   61: }
   62: 
   63: int php_com_wrapper_minit(INIT_FUNC_ARGS)
   64: {
   65: 	le_dispatch = zend_register_list_destructors_ex(dispatch_dtor,
   66: 		NULL, "com_dotnet_dispatch_wrapper", module_number);
   67: 	return le_dispatch;
   68: }
   69: 
   70: 
   71: /* {{{ trace */
   72: static inline void trace(char *fmt, ...)
   73: {
   74: 	va_list ap;
   75: 	char buf[4096];
   76: 
   77: 	snprintf(buf, sizeof(buf), "T=%08x ", GetCurrentThreadId());
   78: 	OutputDebugString(buf);
   79: 	
   80: 	va_start(ap, fmt);
   81: 	vsnprintf(buf, sizeof(buf), fmt, ap);
   82: 
   83: 	OutputDebugString(buf);
   84: 	
   85: 	va_end(ap);
   86: }
   87: /* }}} */
   88: 
   89: #define FETCH_DISP(methname)																			\
   90: 	php_dispatchex *disp = (php_dispatchex*)This; 														\
   91: 	TSRMLS_FETCH();																						\
   92: 	if (COMG(rshutdown_started)) {																		\
   93: 		trace(" PHP Object:%p (name:unknown) %s\n", disp->object,  methname); 							\
   94: 	} else {																							\
   95: 		trace(" PHP Object:%p (name:%s) %s\n", disp->object, Z_OBJCE_P(disp->object)->name, methname); 	\
   96: 	}																									\
   97: 	if (GetCurrentThreadId() != disp->engine_thread) {													\
   98: 		return RPC_E_WRONG_THREAD;																		\
   99: 	}
  100: 
  101: static HRESULT STDMETHODCALLTYPE disp_queryinterface( 
  102: 	IDispatchEx *This,
  103: 	/* [in] */ REFIID riid,
  104: 	/* [iid_is][out] */ void **ppvObject)
  105: {
  106: 	FETCH_DISP("QueryInterface");
  107: 
  108: 	if (IsEqualGUID(&IID_IUnknown, riid) ||
  109: 			IsEqualGUID(&IID_IDispatch, riid) ||
  110: 			IsEqualGUID(&IID_IDispatchEx, riid) ||
  111: 			IsEqualGUID(&disp->sinkid, riid)) {
  112: 		*ppvObject = This;
  113: 		InterlockedIncrement(&disp->refcount);
  114: 		return S_OK;
  115: 	}
  116: 
  117: 	*ppvObject = NULL;
  118: 	return E_NOINTERFACE;
  119: }
  120:         
  121: static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
  122: {
  123: 	FETCH_DISP("AddRef");
  124: 
  125: 	return InterlockedIncrement(&disp->refcount);
  126: }
  127:         
  128: static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
  129: {
  130: 	ULONG ret;
  131: 	FETCH_DISP("Release");
  132: 
  133: 	ret = InterlockedDecrement(&disp->refcount);
  134: 	trace("-- refcount now %d\n", ret);
  135: 	if (ret == 0) {
  136: 		/* destroy it */
  137: 		if (disp->id)
  138: 			zend_list_delete(disp->id);
  139: 	}
  140: 	return ret;
  141: }
  142: 
  143: static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount( 
  144: 	IDispatchEx *This,
  145: 	/* [out] */ UINT *pctinfo)
  146: {
  147: 	FETCH_DISP("GetTypeInfoCount");
  148: 
  149: 	*pctinfo = 0;
  150: 	return S_OK;
  151: }
  152:         
  153: static HRESULT STDMETHODCALLTYPE disp_gettypeinfo( 
  154: 	IDispatchEx *This,
  155: 	/* [in] */ UINT iTInfo,
  156: 	/* [in] */ LCID lcid,
  157: 	/* [out] */ ITypeInfo **ppTInfo)
  158: {
  159: 	FETCH_DISP("GetTypeInfo");
  160: 	
  161: 	*ppTInfo = NULL;
  162: 	return DISP_E_BADINDEX;
  163: }
  164: 
  165: static HRESULT STDMETHODCALLTYPE disp_getidsofnames( 
  166: 	IDispatchEx *This,
  167: 	/* [in] */ REFIID riid,
  168: 	/* [size_is][in] */ LPOLESTR *rgszNames,
  169: 	/* [in] */ UINT cNames,
  170: 	/* [in] */ LCID lcid,
  171: 	/* [size_is][out] */ DISPID *rgDispId)
  172: {
  173: 	UINT i;
  174: 	HRESULT ret = S_OK;
  175: 	FETCH_DISP("GetIDsOfNames");
  176: 
  177: 	for (i = 0; i < cNames; i++) {
  178: 		char *name;
  179: 		unsigned int namelen;
  180: 		zval **tmp;
  181: 		
  182: 		name = php_com_olestring_to_string(rgszNames[i], &namelen, COMG(code_page) TSRMLS_CC);
  183: 		
  184: 		/* Lookup the name in the hash */
  185: 		if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == FAILURE) {
  186: 			ret = DISP_E_UNKNOWNNAME;
  187: 			rgDispId[i] = 0;
  188: 		} else {
  189: 			rgDispId[i] = Z_LVAL_PP(tmp);
  190: 		}
  191: 
  192: 		efree(name);
  193: 
  194: 	}
  195: 	
  196: 	return ret;
  197: }
  198: 
  199: static HRESULT STDMETHODCALLTYPE disp_invoke( 
  200: 	IDispatchEx *This,
  201: 	/* [in] */ DISPID dispIdMember,
  202: 	/* [in] */ REFIID riid,
  203: 	/* [in] */ LCID lcid,
  204: 	/* [in] */ WORD wFlags,
  205: 	/* [out][in] */ DISPPARAMS *pDispParams,
  206: 	/* [out] */ VARIANT *pVarResult,
  207: 	/* [out] */ EXCEPINFO *pExcepInfo,
  208: 	/* [out] */ UINT *puArgErr)
  209: {
  210: 	return This->lpVtbl->InvokeEx(This, dispIdMember,
  211: 			lcid, wFlags, pDispParams,
  212: 			pVarResult, pExcepInfo, NULL);
  213: }
  214: 
  215: static HRESULT STDMETHODCALLTYPE disp_getdispid( 
  216: 	IDispatchEx *This,
  217: 	/* [in] */ BSTR bstrName,
  218: 	/* [in] */ DWORD grfdex,
  219: 	/* [out] */ DISPID *pid)
  220: {
  221: 	HRESULT ret = DISP_E_UNKNOWNNAME;
  222: 	char *name;
  223: 	unsigned int namelen;
  224: 	zval **tmp;
  225: 	FETCH_DISP("GetDispID");
  226: 
  227: 	name = php_com_olestring_to_string(bstrName, &namelen, COMG(code_page) TSRMLS_CC);
  228: 
  229: 	trace("Looking for %s, namelen=%d in %p\n", name, namelen, disp->name_to_dispid);
  230: 	
  231: 	/* Lookup the name in the hash */
  232: 	if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) {
  233: 		trace("found it\n");
  234: 		*pid = Z_LVAL_PP(tmp);
  235: 		ret = S_OK;
  236: 	}
  237: 
  238: 	efree(name);
  239: 	
  240: 	return ret;
  241: }
  242: 
  243: static HRESULT STDMETHODCALLTYPE disp_invokeex( 
  244: 	IDispatchEx *This,
  245: 	/* [in] */ DISPID id,
  246: 	/* [in] */ LCID lcid,
  247: 	/* [in] */ WORD wFlags,
  248: 	/* [in] */ DISPPARAMS *pdp,
  249: 	/* [out] */ VARIANT *pvarRes,
  250: 	/* [out] */ EXCEPINFO *pei,
  251: 	/* [unique][in] */ IServiceProvider *pspCaller)
  252: {
  253: 	zval **name;
  254: 	UINT i;
  255: 	zval *retval = NULL;
  256: 	zval ***params = NULL;
  257: 	HRESULT ret = DISP_E_MEMBERNOTFOUND;
  258: 	FETCH_DISP("InvokeEx");
  259: 
  260: 	if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
  261: 		/* TODO: add support for overloaded objects */
  262: 
  263: 		trace("-- Invoke: %d %20s [%d] flags=%08x args=%d\n", id, Z_STRVAL_PP(name), Z_STRLEN_PP(name), wFlags, pdp->cArgs);
  264: 		
  265: 		/* convert args into zvals.
  266: 		 * Args are in reverse order */
  267: 		if (pdp->cArgs) {
  268: 			params = (zval ***)safe_emalloc(sizeof(zval **), pdp->cArgs, 0);
  269: 			for (i = 0; i < pdp->cArgs; i++) {
  270: 				VARIANT *arg;
  271: 				zval *zarg;
  272: 
  273: 				arg = &pdp->rgvarg[ pdp->cArgs - 1 - i];
  274: 
  275: 				trace("alloc zval for arg %d VT=%08x\n", i, V_VT(arg));
  276: 
  277: 				ALLOC_INIT_ZVAL(zarg);
  278: 				php_com_wrap_variant(zarg, arg, COMG(code_page) TSRMLS_CC);
  279: 				params[i] = (zval**)emalloc(sizeof(zval**));
  280: 				*params[i] = zarg;
  281: 			}
  282: 		}
  283: 
  284: 		trace("arguments processed, prepare to do some work\n");	
  285: 	
  286: 		/* TODO: if PHP raises an exception here, we should catch it
  287: 		 * and expose it as a COM exception */
  288: 		
  289: 		if (wFlags & DISPATCH_PROPERTYGET) {
  290: 			retval = zend_read_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, 1 TSRMLS_CC);
  291: 		} else if (wFlags & DISPATCH_PROPERTYPUT) {
  292: 			zend_update_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, *params[0] TSRMLS_CC);
  293: 		} else if (wFlags & DISPATCH_METHOD) {
  294: 			zend_try {
  295: 				if (SUCCESS == call_user_function_ex(EG(function_table), &disp->object, *name,
  296: 							&retval, pdp->cArgs, params, 1, NULL TSRMLS_CC)) {
  297: 					ret = S_OK;
  298: 					trace("function called ok\n");
  299: 
  300: 					/* Copy any modified values to callers copy of variant*/
  301: 					for (i = 0; i < pdp->cArgs; i++) {
  302: 						php_com_dotnet_object *obj = CDNO_FETCH(*params[i]);
  303: 						VARIANT *srcvar = &obj->v;
  304: 						VARIANT *dstvar = &pdp->rgvarg[ pdp->cArgs - 1 - i];
  305: 						if ((V_VT(dstvar) & VT_BYREF) && obj->modified ) {
  306: 							trace("percolate modified value for arg %d VT=%08x\n", i, V_VT(dstvar));
  307: 							php_com_copy_variant(dstvar, srcvar TSRMLS_CC);   
  308: 						}
  309: 					}
  310: 				} else {
  311: 					trace("failed to call func\n");
  312: 					ret = DISP_E_EXCEPTION;
  313: 				}
  314: 			} zend_catch {
  315: 				trace("something blew up\n");
  316: 				ret = DISP_E_EXCEPTION;
  317: 			} zend_end_try();
  318: 		} else {
  319: 			trace("Don't know how to handle this invocation %08x\n", wFlags);
  320: 		}
  321: 	
  322: 		/* release arguments */
  323: 		if (params) {
  324: 			for (i = 0; i < pdp->cArgs; i++) {
  325: 				zval_ptr_dtor(params[i]);
  326: 				efree(params[i]);
  327: 			}
  328: 			efree(params);
  329: 		}
  330: 		
  331: 		/* return value */
  332: 		if (retval) {
  333: 			if (pvarRes) {
  334: 				VariantInit(pvarRes);
  335: 				php_com_variant_from_zval(pvarRes, retval, COMG(code_page) TSRMLS_CC);
  336: 			}
  337: 			zval_ptr_dtor(&retval);
  338: 		} else if (pvarRes) {
  339: 			VariantInit(pvarRes);
  340: 		}
  341: 		
  342: 	} else {
  343: 		trace("InvokeEx: I don't support DISPID=%d\n", id);
  344: 	}
  345: 
  346: 	return ret;
  347: }
  348: 
  349: static HRESULT STDMETHODCALLTYPE disp_deletememberbyname( 
  350: 	IDispatchEx *This,
  351: 	/* [in] */ BSTR bstrName,
  352: 	/* [in] */ DWORD grfdex)
  353: {
  354: 	FETCH_DISP("DeleteMemberByName");
  355: 
  356: 	/* TODO: unset */
  357: 
  358: 	return S_FALSE;
  359: }
  360: 
  361: static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid( 
  362: 	IDispatchEx *This,
  363: 	/* [in] */ DISPID id)
  364: {
  365: 	FETCH_DISP("DeleteMemberByDispID");
  366: 	
  367: 	/* TODO: unset */
  368: 	
  369: 	return S_FALSE;
  370: }
  371: 
  372: static HRESULT STDMETHODCALLTYPE disp_getmemberproperties( 
  373: 	IDispatchEx *This,
  374: 	/* [in] */ DISPID id,
  375: 	/* [in] */ DWORD grfdexFetch,
  376: 	/* [out] */ DWORD *pgrfdex)
  377: {
  378: 	FETCH_DISP("GetMemberProperties");
  379: 
  380: 	return DISP_E_UNKNOWNNAME;
  381: }
  382: 
  383: static HRESULT STDMETHODCALLTYPE disp_getmembername( 
  384: 	IDispatchEx *This,
  385: 	/* [in] */ DISPID id,
  386: 	/* [out] */ BSTR *pbstrName)
  387: {
  388: 	zval *name;
  389: 	FETCH_DISP("GetMemberName");
  390: 
  391: 	if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
  392: 		OLECHAR *olestr = php_com_string_to_olestring(Z_STRVAL_P(name), Z_STRLEN_P(name), COMG(code_page) TSRMLS_CC);
  393: 		*pbstrName = SysAllocString(olestr);
  394: 		efree(olestr);
  395: 		return S_OK;
  396: 	} else {
  397: 		return DISP_E_UNKNOWNNAME;
  398: 	}
  399: }
  400: 
  401: static HRESULT STDMETHODCALLTYPE disp_getnextdispid( 
  402: 	IDispatchEx *This,
  403: 	/* [in] */ DWORD grfdex,
  404: 	/* [in] */ DISPID id,
  405: 	/* [out] */ DISPID *pid)
  406: {
  407: 	ulong next = id+1;
  408: 	FETCH_DISP("GetNextDispID");
  409: 
  410: 	while(!zend_hash_index_exists(disp->dispid_to_name, next))
  411: 		next++;
  412: 
  413: 	if (zend_hash_index_exists(disp->dispid_to_name, next)) {
  414: 		*pid = next;
  415: 		return S_OK;
  416: 	}
  417: 	return S_FALSE;
  418: }
  419: 
  420: static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent( 
  421: 	IDispatchEx *This,
  422: 	/* [out] */ IUnknown **ppunk)
  423: {
  424: 	FETCH_DISP("GetNameSpaceParent");
  425: 
  426: 	*ppunk = NULL;
  427: 	return E_NOTIMPL;
  428: }
  429:         
  430: static struct IDispatchExVtbl php_dispatch_vtbl = {
  431: 	disp_queryinterface,
  432: 	disp_addref,
  433: 	disp_release,
  434: 	disp_gettypeinfocount,
  435: 	disp_gettypeinfo,
  436: 	disp_getidsofnames,
  437: 	disp_invoke,
  438: 	disp_getdispid,
  439: 	disp_invokeex,
  440: 	disp_deletememberbyname,
  441: 	disp_deletememberbydispid,
  442: 	disp_getmemberproperties,
  443: 	disp_getmembername,
  444: 	disp_getnextdispid,
  445: 	disp_getnamespaceparent
  446: };
  447: 
  448: 
  449: /* enumerate functions and properties of the object and assign
  450:  * dispatch ids */
  451: static void generate_dispids(php_dispatchex *disp TSRMLS_DC)
  452: {
  453: 	HashPosition pos;
  454: 	char *name = NULL;
  455: 	zval *tmp;
  456: 	int namelen;
  457: 	int keytype;
  458: 	ulong pid;
  459: 
  460: 	if (disp->dispid_to_name == NULL) {
  461: 		ALLOC_HASHTABLE(disp->dispid_to_name);
  462: 		ALLOC_HASHTABLE(disp->name_to_dispid);
  463: 		zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
  464: 		zend_hash_init(disp->dispid_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
  465: 	}
  466: 
  467: 	/* properties */
  468: 	if (Z_OBJPROP_P(disp->object)) {
  469: 		zend_hash_internal_pointer_reset_ex(Z_OBJPROP_P(disp->object), &pos);
  470: 		while (HASH_KEY_NON_EXISTANT != (keytype =
  471: 				zend_hash_get_current_key_ex(Z_OBJPROP_P(disp->object), &name,
  472: 			   	&namelen, &pid, 0, &pos))) {
  473: 			char namebuf[32];
  474: 			if (keytype == HASH_KEY_IS_LONG) {
  475: 				snprintf(namebuf, sizeof(namebuf), "%d", pid);
  476: 				name = namebuf;
  477: 				namelen = strlen(namebuf)+1;
  478: 			}
  479: 
  480: 			zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
  481: 
  482: 			/* Find the existing id */
  483: 			if (zend_hash_find(disp->name_to_dispid, name, namelen, (void**)&tmp) == SUCCESS)
  484: 				continue;
  485: 
  486: 			/* add the mappings */
  487: 			MAKE_STD_ZVAL(tmp);
  488: 			ZVAL_STRINGL(tmp, name, namelen-1, 1);
  489: 			pid = zend_hash_next_free_element(disp->dispid_to_name);
  490: 			zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
  491: 
  492: 			MAKE_STD_ZVAL(tmp);
  493: 			ZVAL_LONG(tmp, pid);
  494: 			zend_hash_update(disp->name_to_dispid, name, namelen, (void*)&tmp, sizeof(zval *), NULL);
  495: 		}
  496: 	}
  497: 	
  498: 	/* functions */
  499: 	if (Z_OBJCE_P(disp->object)) {
  500: 		zend_hash_internal_pointer_reset_ex(&Z_OBJCE_P(disp->object)->function_table, &pos);
  501: 		while (HASH_KEY_NON_EXISTANT != (keytype =
  502: 				zend_hash_get_current_key_ex(&Z_OBJCE_P(disp->object)->function_table,
  503: 			 	&name, &namelen, &pid, 0, &pos))) {
  504: 
  505: 			char namebuf[32];
  506: 			if (keytype == HASH_KEY_IS_LONG) {
  507: 				snprintf(namebuf, sizeof(namebuf), "%d", pid);
  508: 				name = namebuf;
  509: 				namelen = strlen(namebuf) + 1;
  510: 			}
  511: 
  512: 			zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
  513: 
  514: 			/* Find the existing id */
  515: 			if (zend_hash_find(disp->name_to_dispid, name, namelen, (void**)&tmp) == SUCCESS)
  516: 				continue;
  517: 
  518: 			/* add the mappings */
  519: 			MAKE_STD_ZVAL(tmp);
  520: 			ZVAL_STRINGL(tmp, name, namelen-1, 1);
  521: 			pid = zend_hash_next_free_element(disp->dispid_to_name);
  522: 			zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
  523: 
  524: 			MAKE_STD_ZVAL(tmp);
  525: 			ZVAL_LONG(tmp, pid);
  526: 			zend_hash_update(disp->name_to_dispid, name, namelen, (void*)&tmp, sizeof(zval *), NULL);
  527: 		}
  528: 	}
  529: }
  530: 
  531: static php_dispatchex *disp_constructor(zval *object TSRMLS_DC)
  532: {
  533: 	php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
  534: 
  535: 	trace("constructing a COM wrapper for PHP object %p (%s)\n", object, Z_OBJCE_P(object)->name);
  536: 	
  537: 	if (disp == NULL)
  538: 		return NULL;
  539: 
  540: 	memset(disp, 0, sizeof(php_dispatchex));
  541: 
  542: 	disp->engine_thread = GetCurrentThreadId();
  543: 	disp->lpVtbl = &php_dispatch_vtbl;
  544: 	disp->refcount = 1;
  545: 
  546: 
  547: 	if (object)
  548: 		Z_ADDREF_P(object);
  549: 	disp->object = object;
  550: 
  551: 	disp->id = zend_list_insert(disp, le_dispatch TSRMLS_CC);
  552: 	
  553: 	return disp;
  554: }
  555: 
  556: static void disp_destructor(php_dispatchex *disp TSRMLS_DC)
  557: {	
  558: 	/* Object store not available during request shutdown */
  559: 	if (COMG(rshutdown_started)) {
  560: 		trace("destroying COM wrapper for PHP object %p (name:unknown)\n", disp->object);
  561: 	} else {
  562: 		trace("destroying COM wrapper for PHP object %p (name:%s)\n", disp->object, Z_OBJCE_P(disp->object)->name);
  563: 	}
  564: 	
  565: 	disp->id = 0;
  566: 	
  567: 	if (disp->refcount > 0)
  568: 		CoDisconnectObject((IUnknown*)disp, 0);
  569: 
  570: 	zend_hash_destroy(disp->dispid_to_name);
  571: 	zend_hash_destroy(disp->name_to_dispid);
  572: 	FREE_HASHTABLE(disp->dispid_to_name);
  573: 	FREE_HASHTABLE(disp->name_to_dispid);
  574: 			
  575: 	if (disp->object)
  576: 		zval_ptr_dtor(&disp->object);
  577: 
  578: 	CoTaskMemFree(disp);
  579: }
  580: 
  581: PHPAPI IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid,
  582: 	   HashTable *id_to_name TSRMLS_DC)
  583: {
  584: 	php_dispatchex *disp = disp_constructor(val TSRMLS_CC);
  585: 	HashPosition pos;
  586: 	char *name = NULL;
  587: 	zval *tmp, **ntmp;
  588: 	int namelen;
  589: 	int keytype;
  590: 	ulong pid;
  591: 
  592: 	disp->dispid_to_name = id_to_name;
  593: 
  594: 	memcpy(&disp->sinkid, sinkid, sizeof(disp->sinkid));
  595: 	
  596: 	/* build up the reverse mapping */
  597: 	ALLOC_HASHTABLE(disp->name_to_dispid);
  598: 	zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
  599: 	
  600: 	zend_hash_internal_pointer_reset_ex(id_to_name, &pos);
  601: 	while (HASH_KEY_NON_EXISTANT != (keytype =
  602: 				zend_hash_get_current_key_ex(id_to_name, &name, &namelen, &pid, 0, &pos))) {
  603: 
  604: 		if (keytype == HASH_KEY_IS_LONG) {
  605: 
  606: 			zend_hash_get_current_data_ex(id_to_name, (void**)&ntmp, &pos);
  607: 			
  608: 			MAKE_STD_ZVAL(tmp);
  609: 			ZVAL_LONG(tmp, pid);
  610: 			zend_hash_update(disp->name_to_dispid, Z_STRVAL_PP(ntmp),
  611: 				Z_STRLEN_PP(ntmp)+1, (void*)&tmp, sizeof(zval *), NULL);
  612: 		}
  613: 
  614: 		zend_hash_move_forward_ex(id_to_name, &pos);
  615: 	}
  616: 
  617: 	return (IDispatch*)disp;
  618: }
  619: 
  620: PHPAPI IDispatch *php_com_wrapper_export(zval *val TSRMLS_DC)
  621: {
  622: 	php_dispatchex *disp = NULL;
  623: 
  624: 	if (Z_TYPE_P(val) != IS_OBJECT) {
  625: 		return NULL;
  626: 	}
  627: 
  628: 	if (php_com_is_valid_object(val TSRMLS_CC)) {
  629: 		/* pass back its IDispatch directly */
  630: 		php_com_dotnet_object *obj = CDNO_FETCH(val);
  631: 		
  632: 		if (obj == NULL)
  633: 			return NULL;
  634: 
  635: 		if (V_VT(&obj->v) == VT_DISPATCH && V_DISPATCH(&obj->v)) {
  636: 			IDispatch_AddRef(V_DISPATCH(&obj->v));
  637: 			return V_DISPATCH(&obj->v);
  638: 		}
  639: 			
  640: 		return NULL;
  641: 	}
  642: 
  643: 	disp = disp_constructor(val TSRMLS_CC);
  644: 	generate_dispids(disp TSRMLS_CC);
  645: 
  646: 	return (IDispatch*)disp;
  647: }
  648: 
  649: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>