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>