Annotation of embedaddon/php/ext/com_dotnet/com_handlers.c, revision 1.1.1.2

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: 
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      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: 
1.1.1.2 ! misho      32: static zval *com_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
1.1       misho      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: 
1.1.1.2 ! misho      67: static void com_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
1.1       misho      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: 
1.1.1.2 ! misho     199: static int com_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
1.1       misho     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: 
1.1.1.2 ! misho     225: static void com_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
1.1       misho     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: 
1.1.1.2 ! misho     249:        efree((char*)f->function_name);
1.1       misho     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: 
1.1.1.2 ! misho     262: static union _zend_function *com_method_get(zval **object_ptr, char *name, int len, const zend_literal *key TSRMLS_DC)
1.1       misho     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;
1.1.1.2 ! misho     286:                f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
1.1       misho     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: 
1.1.1.2 ! misho     367: static int com_call_method(const char *method, INTERNAL_FUNCTION_PARAMETERS)
1.1       misho     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: 
1.1.1.2 ! misho     390:        if (SUCCESS == php_com_do_invoke_byref(obj, (char*)method, -1, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args TSRMLS_CC)) {
1.1       misho     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; \
1.1.1.2 ! misho     412:        f.function_name = (char *) obj->ce->name; \
1.1       misho     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: 
1.1.1.2 ! misho     445: static int com_class_name_get(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
1.1       misho     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,
1.1.1.2 ! misho     583:        com_object_count,
        !           584:        NULL,                                                                   /* get_debug_info */
        !           585:        NULL,                                                                   /* get_closure */
        !           586:        NULL,                                                                   /* get_gc */
1.1       misho     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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>