Annotation of embedaddon/php/ext/com_dotnet/com_wrapper.c, revision 1.1
1.1 ! misho 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 321634 2012-01-01 13:15:04Z felipe $ */
! 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>