root/ext/com_dotnet/com_handlers.c

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

DEFINITIONS

This source file includes following definitions.
  1. com_property_read
  2. com_property_write
  3. com_read_dimension
  4. com_write_dimension
  5. com_object_set
  6. com_object_get
  7. com_property_exists
  8. com_dimension_exists
  9. com_property_delete
  10. com_dimension_delete
  11. com_properties_get
  12. function_dtor
  13. PHP_FUNCTION
  14. com_method_get
  15. com_call_method
  16. com_constructor_get
  17. com_class_entry_get
  18. com_class_name_get
  19. com_objects_compare
  20. com_object_cast
  21. com_object_count
  22. php_com_object_enable_event_sink
  23. php_com_object_free_storage
  24. php_com_object_clone
  25. php_com_object_new

   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 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 #include "php_ini.h"
  27 #include "ext/standard/info.h"
  28 #include "php_com_dotnet.h"
  29 #include "php_com_dotnet_internal.h"
  30 #include "Zend/zend_exceptions.h"
  31 
  32 static zval *com_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
  33 {
  34         zval *return_value;
  35         php_com_dotnet_object *obj;
  36         VARIANT v;
  37         HRESULT res;
  38 
  39         MAKE_STD_ZVAL(return_value);
  40         ZVAL_NULL(return_value);
  41         Z_SET_REFCOUNT_P(return_value, 0);
  42         Z_UNSET_ISREF_P(return_value);
  43 
  44         obj = CDNO_FETCH(object);
  45 
  46         if (V_VT(&obj->v) == VT_DISPATCH) {
  47                 VariantInit(&v);
  48 
  49                 convert_to_string_ex(&member);
  50 
  51                 res = php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
  52                                 DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1 TSRMLS_CC);
  53 
  54                 if (res == SUCCESS) {
  55                         php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
  56                         VariantClear(&v);
  57                 } else if (res == DISP_E_BADPARAMCOUNT) {
  58                         php_com_saproxy_create(object, return_value, member TSRMLS_CC);
  59                 }
  60         } else {
  61                 php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
  62         }
  63 
  64         return return_value;
  65 }
  66 
  67 static void com_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
  68 {
  69         php_com_dotnet_object *obj;
  70         VARIANT v;
  71 
  72         obj = CDNO_FETCH(object);
  73 
  74         if (V_VT(&obj->v) == VT_DISPATCH) {
  75                 VariantInit(&v);
  76 
  77                 convert_to_string_ex(&member);
  78                 if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
  79                                 DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &v, 1, &value, 0 TSRMLS_CC)) {
  80                         VariantClear(&v);
  81                 }
  82         } else {
  83                 php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
  84         }
  85 }
  86 
  87 static zval *com_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
  88 {
  89         zval *return_value;
  90         php_com_dotnet_object *obj;
  91         VARIANT v;
  92 
  93         MAKE_STD_ZVAL(return_value);
  94         ZVAL_NULL(return_value);
  95         Z_SET_REFCOUNT_P(return_value, 0);
  96         Z_UNSET_ISREF_P(return_value);
  97 
  98         obj = CDNO_FETCH(object);
  99 
 100         if (V_VT(&obj->v) == VT_DISPATCH) {
 101                 VariantInit(&v);
 102 
 103                 if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
 104                                 DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 1, &offset, 0, 0 TSRMLS_CC)) {
 105                         php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
 106                         VariantClear(&v);
 107                 }
 108         } else if (V_ISARRAY(&obj->v)) {
 109                 convert_to_long(offset);
 110 
 111                 if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {   
 112                         if (php_com_safearray_get_elem(&obj->v, &v, Z_LVAL_P(offset) TSRMLS_CC)) {
 113                                 php_com_wrap_variant(return_value, &v, obj->code_page TSRMLS_CC);
 114                                 VariantClear(&v);
 115                         }
 116                 } else {
 117                         php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
 118                 }
 119 
 120         } else {
 121                 php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
 122         }
 123 
 124         return return_value;
 125 }
 126 
 127 static void com_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
 128 {
 129         php_com_dotnet_object *obj;
 130         zval *args[2];
 131         VARIANT v;
 132         HRESULT res;
 133 
 134         obj = CDNO_FETCH(object);
 135 
 136         if (V_VT(&obj->v) == VT_DISPATCH) {
 137                 args[0] = offset;
 138                 args[1] = value;
 139 
 140                 VariantInit(&v);
 141 
 142                 if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
 143                                 DISPATCH_METHOD|DISPATCH_PROPERTYPUT, &v, 2, args, 0, 0 TSRMLS_CC)) {
 144                         VariantClear(&v);
 145                 }
 146         } else if (V_ISARRAY(&obj->v)) {
 147                 LONG indices = 0;
 148                 VARTYPE vt;
 149                 
 150                 if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {   
 151                         if (FAILED(SafeArrayGetVartype(V_ARRAY(&obj->v), &vt)) || vt == VT_EMPTY) {
 152                                 vt = V_VT(&obj->v) & ~VT_ARRAY;
 153                         }
 154 
 155                         convert_to_long(offset);
 156                         indices = Z_LVAL_P(offset);
 157 
 158                         VariantInit(&v);
 159                         php_com_variant_from_zval(&v, value, obj->code_page TSRMLS_CC);
 160 
 161                         if (V_VT(&v) != vt) {
 162                                 VariantChangeType(&v, &v, 0, vt);
 163                         }
 164 
 165                         if (vt == VT_VARIANT) {
 166                                 res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v);
 167                         } else {
 168                                 res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v.lVal);
 169                         }
 170 
 171                         VariantClear(&v);
 172 
 173                         if (FAILED(res)) {
 174                                 php_com_throw_exception(res, NULL TSRMLS_CC);
 175                         }
 176 
 177                 } else {
 178                         php_com_throw_exception(DISP_E_BADINDEX, "this variant has multiple dimensions; you can't set a new value without specifying *all* dimensions" TSRMLS_CC);
 179                 }
 180 
 181         } else {
 182                 php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
 183         }
 184 }
 185 
 186 #if 0
 187 static void com_object_set(zval **property, zval *value TSRMLS_DC)
 188 {
 189         /* Not yet implemented in the engine */
 190 }
 191 
 192 static zval *com_object_get(zval *property TSRMLS_DC)
 193 {
 194         /* Not yet implemented in the engine */
 195         return NULL;
 196 }
 197 #endif
 198 
 199 static int com_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
 200 {
 201         DISPID dispid;
 202         php_com_dotnet_object *obj;
 203 
 204         obj = CDNO_FETCH(object);
 205 
 206         if (V_VT(&obj->v) == VT_DISPATCH) {
 207                 convert_to_string_ex(&member);
 208                 if (SUCCEEDED(php_com_get_id_of_name(obj, Z_STRVAL_P(member), Z_STRLEN_P(member), &dispid TSRMLS_CC))) {
 209                         /* TODO: distinguish between property and method! */
 210                         return 1;
 211                 }
 212         } else {
 213                 /* TODO: check for safearray */
 214         }
 215 
 216         return 0;
 217 }
 218 
 219 static int com_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
 220 {
 221         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Operation not yet supported on a COM object");
 222         return 0;
 223 }
 224 
 225 static void com_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
 226 {
 227         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
 228 }
 229 
 230 static void com_dimension_delete(zval *object, zval *offset TSRMLS_DC)
 231 {
 232         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
 233 }
 234 
 235 static HashTable *com_properties_get(zval *object TSRMLS_DC)
 236 {
 237         /* TODO: use type-info to get all the names and values ?
 238          * DANGER: if we do that, there is a strong possibility for
 239          * infinite recursion when the hash is displayed via var_dump().
 240          * Perhaps it is best to leave it un-implemented.
 241          */
 242         return NULL;
 243 }
 244 
 245 static void function_dtor(void *pDest)
 246 {
 247         zend_internal_function *f = (zend_internal_function*)pDest;
 248 
 249         efree((char*)f->function_name);
 250         if (f->arg_info) {
 251                 efree(f->arg_info);
 252         }
 253 }
 254 
 255 static PHP_FUNCTION(com_method_handler)
 256 {
 257         Z_OBJ_HANDLER_P(getThis(), call_method)(
 258                         ((zend_internal_function*)EG(current_execute_data)->function_state.function)->function_name,
 259                         INTERNAL_FUNCTION_PARAM_PASSTHRU);
 260 }
 261 
 262 static union _zend_function *com_method_get(zval **object_ptr, char *name, int len, const zend_literal *key TSRMLS_DC)
 263 {
 264         zend_internal_function f, *fptr = NULL;
 265         php_com_dotnet_object *obj;
 266         union _zend_function *func;
 267         DISPID dummy;
 268         zval *object = *object_ptr;
 269 
 270         obj = CDNO_FETCH(object);
 271 
 272         if (V_VT(&obj->v) != VT_DISPATCH) {
 273                 return NULL;
 274         }
 275 
 276         if (FAILED(php_com_get_id_of_name(obj, name, len, &dummy TSRMLS_CC))) {
 277                 return NULL;
 278         }
 279 
 280         /* check cache */
 281         if (obj->method_cache == NULL || FAILURE == zend_hash_find(obj->method_cache, name, len, (void**)&fptr)) {
 282                 f.type = ZEND_OVERLOADED_FUNCTION;
 283                 f.num_args = 0;
 284                 f.arg_info = NULL;
 285                 f.scope = obj->ce;
 286                 f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
 287                 f.function_name = estrndup(name, len);
 288                 f.handler = PHP_FN(com_method_handler);
 289 
 290                 fptr = &f;
 291         
 292                 if (obj->typeinfo) {
 293                         /* look for byref params */
 294                         ITypeComp *comp;
 295                         ITypeInfo *TI = NULL;
 296                         DESCKIND kind;
 297                         BINDPTR bindptr;
 298                         OLECHAR *olename;
 299                         ULONG lhash;
 300                         int i;
 301 
 302                         if (SUCCEEDED(ITypeInfo_GetTypeComp(obj->typeinfo, &comp))) {
 303                                 olename = php_com_string_to_olestring(name, len, obj->code_page TSRMLS_CC);
 304                                 lhash = LHashValOfNameSys(SYS_WIN32, LOCALE_SYSTEM_DEFAULT, olename);
 305 
 306                                 if (SUCCEEDED(ITypeComp_Bind(comp, olename, lhash, INVOKE_FUNC, &TI, &kind, &bindptr))) {
 307                                         switch (kind) {
 308                                                 case DESCKIND_FUNCDESC:
 309                                                         f.arg_info = ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info));
 310 
 311                                                         for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) {
 312                                                                 f.arg_info[i].allow_null = 1;
 313                                                                 if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) {
 314                                                                         f.arg_info[i].pass_by_reference = 1;
 315                                                                 }
 316                                                         }
 317 
 318                                                         f.num_args = bindptr.lpfuncdesc->cParams;
 319 
 320                                                         ITypeInfo_ReleaseFuncDesc(TI, bindptr.lpfuncdesc);
 321                                                         break;
 322 
 323                                                         /* these should not happen, but *might* happen if the user
 324                                                          * screws up; lets avoid a leak in that case */
 325                                                 case DESCKIND_VARDESC:
 326                                                         ITypeInfo_ReleaseVarDesc(TI, bindptr.lpvardesc);
 327                                                         break;
 328                                                 case DESCKIND_TYPECOMP:
 329                                                         ITypeComp_Release(bindptr.lptcomp);
 330                                                         break;
 331 
 332                                                 case DESCKIND_NONE:
 333                                                         break;
 334                                         }
 335                                         if (TI) {
 336                                                 ITypeInfo_Release(TI);
 337                                         }
 338                                 }
 339                                 ITypeComp_Release(comp);
 340                                 efree(olename);
 341                         }
 342                 }
 343 
 344                 if (fptr) {
 345                         /* save this method in the cache */
 346                         if (!obj->method_cache) {
 347                                 ALLOC_HASHTABLE(obj->method_cache);
 348                                 zend_hash_init(obj->method_cache, 2, NULL, function_dtor, 0);
 349                         }
 350 
 351                         zend_hash_update(obj->method_cache, name, len, &f, sizeof(f), (void**)&fptr);
 352                 }
 353         }
 354 
 355         if (fptr) {
 356                 /* duplicate this into a new chunk of emalloc'd memory,
 357                  * since the engine will efree it */
 358                 func = emalloc(sizeof(*fptr));
 359                 memcpy(func, fptr, sizeof(*fptr));
 360 
 361                 return func;
 362         }
 363 
 364         return NULL;
 365 }
 366 
 367 static int com_call_method(const char *method, INTERNAL_FUNCTION_PARAMETERS)
 368 {
 369         zval ***args = NULL;
 370         php_com_dotnet_object *obj;
 371         int nargs;
 372         VARIANT v;
 373         int ret = FAILURE;
 374         
 375         obj = CDNO_FETCH(getThis());
 376 
 377         if (V_VT(&obj->v) != VT_DISPATCH) {
 378                 return FAILURE;
 379         }
 380         
 381         nargs = ZEND_NUM_ARGS();
 382 
 383         if (nargs) {
 384                 args = (zval ***)safe_emalloc(sizeof(zval *), nargs, 0);
 385                 zend_get_parameters_array_ex(nargs, args);
 386         }
 387 
 388         VariantInit(&v);
 389 
 390         if (SUCCESS == php_com_do_invoke_byref(obj, (char*)method, -1, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args TSRMLS_CC)) {
 391                 php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
 392                 ret = SUCCESS;
 393                 VariantClear(&v);
 394         }
 395 
 396         if (args) {
 397                 efree(args);
 398         }
 399 
 400         return ret;
 401 }
 402 
 403 static union _zend_function *com_constructor_get(zval *object TSRMLS_DC)
 404 {
 405         php_com_dotnet_object *obj;
 406         static zend_internal_function c, d, v;
 407 
 408         obj = CDNO_FETCH(object);
 409 
 410 #define POPULATE_CTOR(f, fn)    \
 411         f.type = ZEND_INTERNAL_FUNCTION; \
 412         f.function_name = (char *) obj->ce->name; \
 413         f.scope = obj->ce; \
 414         f.arg_info = NULL; \
 415         f.num_args = 0; \
 416         f.fn_flags = 0; \
 417         f.handler = ZEND_FN(fn); \
 418         return (union _zend_function*)&f;
 419         
 420         switch (obj->ce->name[0]) {
 421 #if HAVE_MSCOREE_H
 422                 case 'd':
 423                         POPULATE_CTOR(d, com_dotnet_create_instance);
 424 #endif
 425                 
 426                 case 'c':
 427                         POPULATE_CTOR(c, com_create_instance);
 428                 
 429                 case 'v':
 430                         POPULATE_CTOR(v, com_variant_create_instance);
 431                         
 432                 default:
 433                         return NULL;
 434         }
 435 }
 436 
 437 static zend_class_entry *com_class_entry_get(const zval *object TSRMLS_DC)
 438 {
 439         php_com_dotnet_object *obj;
 440         obj = CDNO_FETCH(object);
 441 
 442         return obj->ce;
 443 }
 444 
 445 static int com_class_name_get(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
 446 {
 447         php_com_dotnet_object *obj;
 448         obj = CDNO_FETCH(object);
 449 
 450         *class_name = estrndup(obj->ce->name, obj->ce->name_length);
 451         *class_name_len = obj->ce->name_length;
 452 
 453         return 0;
 454 }
 455 
 456 /* This compares two variants for equality */
 457 static int com_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
 458 {
 459         php_com_dotnet_object *obja, *objb;
 460         int ret;
 461         /* strange header bug problem here... the headers define the proto without the
 462          * flags parameter.  However, the MSDN docs state that there is a flags parameter,
 463          * and my VC6 won't link unless the code uses the version with 4 parameters.
 464          * So, we have this declaration here to fix it */
 465         STDAPI VarCmp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LCID lcid, DWORD flags);
 466 
 467         obja = CDNO_FETCH(object1);
 468         objb = CDNO_FETCH(object2);
 469 
 470         switch (VarCmp(&obja->v, &objb->v, LOCALE_SYSTEM_DEFAULT, 0)) {
 471                 case VARCMP_LT:
 472                         ret = -1;
 473                         break;
 474                 case VARCMP_GT:
 475                         ret = 1;
 476                         break;
 477                 case VARCMP_EQ:
 478                         ret = 0;
 479                         break;
 480                 default:
 481                         /* either or both operands are NULL...
 482                          * not 100% sure how to handle this */
 483                         ret = -2;
 484         }
 485 
 486         return ret;
 487 }
 488 
 489 static int com_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
 490 {
 491         php_com_dotnet_object *obj;
 492         VARIANT v;
 493         VARTYPE vt = VT_EMPTY;
 494         HRESULT res = S_OK;
 495 
 496         obj = CDNO_FETCH(readobj);
 497         ZVAL_NULL(writeobj);
 498         VariantInit(&v);
 499 
 500         if (V_VT(&obj->v) == VT_DISPATCH) {
 501                 if (SUCCESS != php_com_do_invoke_by_id(obj, DISPID_VALUE,
 502                                 DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1, 0 TSRMLS_CC)) {
 503                         VariantCopy(&v, &obj->v);
 504                 }
 505         } else {
 506                 VariantCopy(&v, &obj->v);
 507         }
 508 
 509         switch(type) {
 510                 case IS_LONG:
 511                         vt = VT_INT;
 512                         break;
 513                 case IS_DOUBLE:
 514                         vt = VT_R8;
 515                         break;
 516                 case IS_BOOL:
 517                         vt = VT_BOOL;
 518                         break;
 519                 case IS_STRING:
 520                         vt = VT_BSTR;
 521                         break;
 522                 default:
 523                         ;
 524         }
 525 
 526         if (vt != VT_EMPTY && vt != V_VT(&v)) {
 527                 res = VariantChangeType(&v, &v, 0, vt);
 528         }
 529 
 530         if (SUCCEEDED(res)) {
 531                 php_com_zval_from_variant(writeobj, &v, obj->code_page TSRMLS_CC);
 532         }
 533 
 534         VariantClear(&v);
 535 
 536         if (SUCCEEDED(res)) {
 537                 return SUCCESS;
 538         }
 539 
 540         return zend_std_cast_object_tostring(readobj, writeobj, type TSRMLS_CC);
 541 }
 542 
 543 static int com_object_count(zval *object, long *count TSRMLS_DC)
 544 {
 545         php_com_dotnet_object *obj;
 546         LONG ubound = 0, lbound = 0;
 547         
 548         obj = CDNO_FETCH(object);
 549         
 550         if (!V_ISARRAY(&obj->v)) {
 551                 return FAILURE;
 552         }
 553 
 554         SafeArrayGetLBound(V_ARRAY(&obj->v), 1, &lbound);
 555         SafeArrayGetUBound(V_ARRAY(&obj->v), 1, &ubound);
 556 
 557         *count = ubound - lbound + 1;
 558 
 559         return SUCCESS;
 560 }
 561 
 562 zend_object_handlers php_com_object_handlers = {
 563         ZEND_OBJECTS_STORE_HANDLERS,
 564         com_property_read,
 565         com_property_write,
 566         com_read_dimension,
 567         com_write_dimension,
 568         NULL,
 569         NULL, /* com_object_get, */
 570         NULL, /* com_object_set, */
 571         com_property_exists,
 572         com_property_delete,
 573         com_dimension_exists,
 574         com_dimension_delete,
 575         com_properties_get,
 576         com_method_get,
 577         com_call_method,
 578         com_constructor_get,
 579         com_class_entry_get,
 580         com_class_name_get,
 581         com_objects_compare,
 582         com_object_cast,
 583         com_object_count,
 584         NULL,                                                                   /* get_debug_info */
 585         NULL,                                                                   /* get_closure */
 586         NULL,                                                                   /* get_gc */
 587 };
 588 
 589 void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSRMLS_DC)
 590 {
 591         if (obj->sink_dispatch) {
 592                 IConnectionPointContainer *cont;
 593                 IConnectionPoint *point;
 594                 
 595                 if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v),
 596                                 &IID_IConnectionPointContainer, (void**)&cont))) {
 597                         
 598                         if (SUCCEEDED(IConnectionPointContainer_FindConnectionPoint(cont,
 599                                         &obj->sink_id, &point))) {
 600 
 601                                 if (enable) {
 602                                         IConnectionPoint_Advise(point, (IUnknown*)obj->sink_dispatch, &obj->sink_cookie);
 603                                 } else {
 604                                         IConnectionPoint_Unadvise(point, obj->sink_cookie);
 605                                 }
 606                                 IConnectionPoint_Release(point);
 607                         }
 608                         IConnectionPointContainer_Release(cont);
 609                 }
 610         }
 611 }
 612 
 613 void php_com_object_free_storage(void *object TSRMLS_DC)
 614 {
 615         php_com_dotnet_object *obj = (php_com_dotnet_object*)object;
 616 
 617         if (obj->typeinfo) {
 618                 ITypeInfo_Release(obj->typeinfo);
 619                 obj->typeinfo = NULL;
 620         }
 621 
 622         if (obj->sink_dispatch) {
 623                 php_com_object_enable_event_sink(obj, FALSE TSRMLS_CC);
 624                 IDispatch_Release(obj->sink_dispatch);
 625                 obj->sink_dispatch = NULL;
 626         }
 627 
 628         VariantClear(&obj->v);
 629 
 630         if (obj->method_cache) {
 631                 zend_hash_destroy(obj->method_cache);
 632                 FREE_HASHTABLE(obj->method_cache);
 633         }
 634         if (obj->id_of_name_cache) {
 635                 zend_hash_destroy(obj->id_of_name_cache);
 636                 FREE_HASHTABLE(obj->id_of_name_cache);
 637         }
 638         efree(obj);
 639 }
 640 
 641 void php_com_object_clone(void *object, void **clone_ptr TSRMLS_DC)
 642 {
 643         php_com_dotnet_object *cloneobj, *origobject;
 644 
 645         origobject = (php_com_dotnet_object*)object;
 646         cloneobj = (php_com_dotnet_object*)emalloc(sizeof(php_com_dotnet_object));
 647         
 648         memcpy(cloneobj, origobject, sizeof(*cloneobj));
 649 
 650         /* VariantCopy will perform VariantClear; we don't want to clobber
 651          * the IDispatch that we memcpy'd, so we init a new variant in the
 652          * clone structure */
 653         VariantInit(&cloneobj->v);
 654         /* We use the Indirection-following version of the API since we
 655          * want to clone as much as possible */
 656         VariantCopyInd(&cloneobj->v, &origobject->v); 
 657 
 658         if (cloneobj->typeinfo) {
 659                 ITypeInfo_AddRef(cloneobj->typeinfo);
 660         }
 661 
 662         *clone_ptr = cloneobj;
 663 }
 664 
 665 zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC)
 666 {
 667         php_com_dotnet_object *obj;
 668         zend_object_value retval;
 669 
 670         php_com_initialize(TSRMLS_C);
 671         obj = emalloc(sizeof(*obj));
 672         memset(obj, 0, sizeof(*obj));
 673 
 674         VariantInit(&obj->v);
 675         obj->code_page = CP_ACP;
 676         obj->ce = ce;
 677         obj->zo.ce = ce;
 678 
 679         retval.handle = zend_objects_store_put(obj, NULL, php_com_object_free_storage, php_com_object_clone TSRMLS_CC);
 680         retval.handlers = &php_com_object_handlers;
 681 
 682         return retval;
 683 }

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