File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / com_dotnet / com_wrapper.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:47:53 2012 UTC (12 years, 5 months ago) by misho
Branches: php, MAIN
CVS tags: v5_3_10, HEAD
php

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

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