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

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