Annotation of embedaddon/php/ext/com_dotnet/com_handlers.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_handlers.c 321634 2012-01-01 13:15:04Z felipe $ */
! 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 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 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 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 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(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 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 = 0;
! 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(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, 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 = 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, 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: };
! 585:
! 586: void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSRMLS_DC)
! 587: {
! 588: if (obj->sink_dispatch) {
! 589: IConnectionPointContainer *cont;
! 590: IConnectionPoint *point;
! 591:
! 592: if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v),
! 593: &IID_IConnectionPointContainer, (void**)&cont))) {
! 594:
! 595: if (SUCCEEDED(IConnectionPointContainer_FindConnectionPoint(cont,
! 596: &obj->sink_id, &point))) {
! 597:
! 598: if (enable) {
! 599: IConnectionPoint_Advise(point, (IUnknown*)obj->sink_dispatch, &obj->sink_cookie);
! 600: } else {
! 601: IConnectionPoint_Unadvise(point, obj->sink_cookie);
! 602: }
! 603: IConnectionPoint_Release(point);
! 604: }
! 605: IConnectionPointContainer_Release(cont);
! 606: }
! 607: }
! 608: }
! 609:
! 610: void php_com_object_free_storage(void *object TSRMLS_DC)
! 611: {
! 612: php_com_dotnet_object *obj = (php_com_dotnet_object*)object;
! 613:
! 614: if (obj->typeinfo) {
! 615: ITypeInfo_Release(obj->typeinfo);
! 616: obj->typeinfo = NULL;
! 617: }
! 618:
! 619: if (obj->sink_dispatch) {
! 620: php_com_object_enable_event_sink(obj, FALSE TSRMLS_CC);
! 621: IDispatch_Release(obj->sink_dispatch);
! 622: obj->sink_dispatch = NULL;
! 623: }
! 624:
! 625: VariantClear(&obj->v);
! 626:
! 627: if (obj->method_cache) {
! 628: zend_hash_destroy(obj->method_cache);
! 629: FREE_HASHTABLE(obj->method_cache);
! 630: }
! 631: if (obj->id_of_name_cache) {
! 632: zend_hash_destroy(obj->id_of_name_cache);
! 633: FREE_HASHTABLE(obj->id_of_name_cache);
! 634: }
! 635: efree(obj);
! 636: }
! 637:
! 638: void php_com_object_clone(void *object, void **clone_ptr TSRMLS_DC)
! 639: {
! 640: php_com_dotnet_object *cloneobj, *origobject;
! 641:
! 642: origobject = (php_com_dotnet_object*)object;
! 643: cloneobj = (php_com_dotnet_object*)emalloc(sizeof(php_com_dotnet_object));
! 644:
! 645: memcpy(cloneobj, origobject, sizeof(*cloneobj));
! 646:
! 647: /* VariantCopy will perform VariantClear; we don't want to clobber
! 648: * the IDispatch that we memcpy'd, so we init a new variant in the
! 649: * clone structure */
! 650: VariantInit(&cloneobj->v);
! 651: /* We use the Indirection-following version of the API since we
! 652: * want to clone as much as possible */
! 653: VariantCopyInd(&cloneobj->v, &origobject->v);
! 654:
! 655: if (cloneobj->typeinfo) {
! 656: ITypeInfo_AddRef(cloneobj->typeinfo);
! 657: }
! 658:
! 659: *clone_ptr = cloneobj;
! 660: }
! 661:
! 662: zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC)
! 663: {
! 664: php_com_dotnet_object *obj;
! 665: zend_object_value retval;
! 666:
! 667: php_com_initialize(TSRMLS_C);
! 668: obj = emalloc(sizeof(*obj));
! 669: memset(obj, 0, sizeof(*obj));
! 670:
! 671: VariantInit(&obj->v);
! 672: obj->code_page = CP_ACP;
! 673: obj->ce = ce;
! 674: obj->zo.ce = ce;
! 675:
! 676: retval.handle = zend_objects_store_put(obj, NULL, php_com_object_free_storage, php_com_object_clone TSRMLS_CC);
! 677: retval.handlers = &php_com_object_handlers;
! 678:
! 679: return retval;
! 680: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>