root/ext/com_dotnet/com_wrapper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dispatch_dtor
  2. php_com_wrapper_minit
  3. trace
  4. disp_queryinterface
  5. disp_addref
  6. disp_release
  7. disp_gettypeinfocount
  8. disp_gettypeinfo
  9. disp_getidsofnames
  10. disp_invoke
  11. disp_getdispid
  12. disp_invokeex
  13. disp_deletememberbyname
  14. disp_deletememberbydispid
  15. disp_getmemberproperties
  16. disp_getmembername
  17. disp_getnextdispid
  18. disp_getnamespaceparent
  19. generate_dispids
  20. disp_constructor
  21. disp_destructor
  22. php_com_wrapper_export_as_sink
  23. php_com_wrapper_export

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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$ */
  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_EXISTENT != (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_EXISTENT != (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 PHP_COM_DOTNET_API 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_EXISTENT != (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 PHP_COM_DOTNET_API 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 

/* [<][>][^][v][top][bottom][index][help] */