Annotation of embedaddon/php/ext/com_dotnet/com_wrapper.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_wrapper.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            20: 
        !            21: /* This module exports a PHP object as a COM object by wrapping it
        !            22:  * using IDispatchEx */
        !            23: 
        !            24: #ifdef HAVE_CONFIG_H
        !            25: #include "config.h"
        !            26: #endif
        !            27: 
        !            28: #include "php.h"
        !            29: #include "php_ini.h"
        !            30: #include "ext/standard/info.h"
        !            31: #include "php_com_dotnet.h"
        !            32: #include "php_com_dotnet_internal.h"
        !            33: 
        !            34: typedef struct {
        !            35:        /* This first part MUST match the declaration
        !            36:         * of interface IDispatchEx */
        !            37:        CONST_VTBL struct IDispatchExVtbl *lpVtbl;
        !            38: 
        !            39:        /* now the PHP stuff */
        !            40:        
        !            41:        DWORD engine_thread; /* for sanity checking */
        !            42:        zval *object;                   /* the object exported */
        !            43:        LONG refcount;                  /* COM reference count */
        !            44: 
        !            45:        HashTable *dispid_to_name;      /* keep track of dispid -> name mappings */
        !            46:        HashTable *name_to_dispid;      /* keep track of name -> dispid mappings */
        !            47: 
        !            48:        GUID sinkid;    /* iid that we "implement" for event sinking */
        !            49:        
        !            50:        int id;
        !            51: } php_dispatchex;
        !            52: 
        !            53: static int le_dispatch;
        !            54: 
        !            55: static void disp_destructor(php_dispatchex *disp);
        !            56: 
        !            57: static void dispatch_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
        !            58: {
        !            59:        php_dispatchex *disp = (php_dispatchex *)rsrc->ptr;
        !            60:        disp_destructor(disp);
        !            61: }
        !            62: 
        !            63: int php_com_wrapper_minit(INIT_FUNC_ARGS)
        !            64: {
        !            65:        le_dispatch = zend_register_list_destructors_ex(dispatch_dtor,
        !            66:                NULL, "com_dotnet_dispatch_wrapper", module_number);
        !            67:        return le_dispatch;
        !            68: }
        !            69: 
        !            70: 
        !            71: /* {{{ trace */
        !            72: static inline void trace(char *fmt, ...)
        !            73: {
        !            74:        va_list ap;
        !            75:        char buf[4096];
        !            76: 
        !            77:        snprintf(buf, sizeof(buf), "T=%08x ", GetCurrentThreadId());
        !            78:        OutputDebugString(buf);
        !            79:        
        !            80:        va_start(ap, fmt);
        !            81:        vsnprintf(buf, sizeof(buf), fmt, ap);
        !            82: 
        !            83:        OutputDebugString(buf);
        !            84:        
        !            85:        va_end(ap);
        !            86: }
        !            87: /* }}} */
        !            88: 
        !            89: #ifdef ZTS
        !            90: # define TSRMLS_FIXED()        TSRMLS_FETCH();
        !            91: #else
        !            92: # define TSRMLS_FIXED()
        !            93: #endif
        !            94: 
        !            95: #define FETCH_DISP(methname)                                                                                                                                                   \
        !            96:        TSRMLS_FIXED()                                                                                                                                                                          \
        !            97:        php_dispatchex *disp = (php_dispatchex*)This;                                                                                                           \
        !            98:        if (COMG(rshutdown_started)) {                                                                                                                                          \
        !            99:                trace(" PHP Object:%p (name:unknown) %s\n", disp->object,  methname);                                                   \
        !           100:        } else {                                                                                                                                                                                        \
        !           101:                trace(" PHP Object:%p (name:%s) %s\n", disp->object, Z_OBJCE_P(disp->object)->name, methname);  \
        !           102:        }                                                                                                                                                                                                       \
        !           103:        if (GetCurrentThreadId() != disp->engine_thread) {                                                                                                      \
        !           104:                return RPC_E_WRONG_THREAD;                                                                                                                                              \
        !           105:        }
        !           106: 
        !           107: static HRESULT STDMETHODCALLTYPE disp_queryinterface( 
        !           108:        IDispatchEx *This,
        !           109:        /* [in] */ REFIID riid,
        !           110:        /* [iid_is][out] */ void **ppvObject)
        !           111: {
        !           112:        FETCH_DISP("QueryInterface");
        !           113: 
        !           114:        if (IsEqualGUID(&IID_IUnknown, riid) ||
        !           115:                        IsEqualGUID(&IID_IDispatch, riid) ||
        !           116:                        IsEqualGUID(&IID_IDispatchEx, riid) ||
        !           117:                        IsEqualGUID(&disp->sinkid, riid)) {
        !           118:                *ppvObject = This;
        !           119:                InterlockedIncrement(&disp->refcount);
        !           120:                return S_OK;
        !           121:        }
        !           122: 
        !           123:        *ppvObject = NULL;
        !           124:        return E_NOINTERFACE;
        !           125: }
        !           126:         
        !           127: static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
        !           128: {
        !           129:        FETCH_DISP("AddRef");
        !           130: 
        !           131:        return InterlockedIncrement(&disp->refcount);
        !           132: }
        !           133:         
        !           134: static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
        !           135: {
        !           136:        ULONG ret;
        !           137:        FETCH_DISP("Release");
        !           138: 
        !           139:        ret = InterlockedDecrement(&disp->refcount);
        !           140:        trace("-- refcount now %d\n", ret);
        !           141:        if (ret == 0) {
        !           142:                /* destroy it */
        !           143:                if (disp->id)
        !           144:                        zend_list_delete(disp->id);
        !           145:        }
        !           146:        return ret;
        !           147: }
        !           148: 
        !           149: static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount( 
        !           150:        IDispatchEx *This,
        !           151:        /* [out] */ UINT *pctinfo)
        !           152: {
        !           153:        FETCH_DISP("GetTypeInfoCount");
        !           154: 
        !           155:        *pctinfo = 0;
        !           156:        return S_OK;
        !           157: }
        !           158:         
        !           159: static HRESULT STDMETHODCALLTYPE disp_gettypeinfo( 
        !           160:        IDispatchEx *This,
        !           161:        /* [in] */ UINT iTInfo,
        !           162:        /* [in] */ LCID lcid,
        !           163:        /* [out] */ ITypeInfo **ppTInfo)
        !           164: {
        !           165:        FETCH_DISP("GetTypeInfo");
        !           166:        
        !           167:        *ppTInfo = NULL;
        !           168:        return DISP_E_BADINDEX;
        !           169: }
        !           170: 
        !           171: static HRESULT STDMETHODCALLTYPE disp_getidsofnames( 
        !           172:        IDispatchEx *This,
        !           173:        /* [in] */ REFIID riid,
        !           174:        /* [size_is][in] */ LPOLESTR *rgszNames,
        !           175:        /* [in] */ UINT cNames,
        !           176:        /* [in] */ LCID lcid,
        !           177:        /* [size_is][out] */ DISPID *rgDispId)
        !           178: {
        !           179:        UINT i;
        !           180:        HRESULT ret = S_OK;
        !           181:        FETCH_DISP("GetIDsOfNames");
        !           182: 
        !           183:        for (i = 0; i < cNames; i++) {
        !           184:                char *name;
        !           185:                unsigned int namelen;
        !           186:                zval **tmp;
        !           187:                
        !           188:                name = php_com_olestring_to_string(rgszNames[i], &namelen, COMG(code_page) TSRMLS_CC);
        !           189:                
        !           190:                /* Lookup the name in the hash */
        !           191:                if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == FAILURE) {
        !           192:                        ret = DISP_E_UNKNOWNNAME;
        !           193:                        rgDispId[i] = 0;
        !           194:                } else {
        !           195:                        rgDispId[i] = Z_LVAL_PP(tmp);
        !           196:                }
        !           197: 
        !           198:                efree(name);
        !           199: 
        !           200:        }
        !           201:        
        !           202:        return ret;
        !           203: }
        !           204: 
        !           205: static HRESULT STDMETHODCALLTYPE disp_invoke( 
        !           206:        IDispatchEx *This,
        !           207:        /* [in] */ DISPID dispIdMember,
        !           208:        /* [in] */ REFIID riid,
        !           209:        /* [in] */ LCID lcid,
        !           210:        /* [in] */ WORD wFlags,
        !           211:        /* [out][in] */ DISPPARAMS *pDispParams,
        !           212:        /* [out] */ VARIANT *pVarResult,
        !           213:        /* [out] */ EXCEPINFO *pExcepInfo,
        !           214:        /* [out] */ UINT *puArgErr)
        !           215: {
        !           216:        return This->lpVtbl->InvokeEx(This, dispIdMember,
        !           217:                        lcid, wFlags, pDispParams,
        !           218:                        pVarResult, pExcepInfo, NULL);
        !           219: }
        !           220: 
        !           221: static HRESULT STDMETHODCALLTYPE disp_getdispid( 
        !           222:        IDispatchEx *This,
        !           223:        /* [in] */ BSTR bstrName,
        !           224:        /* [in] */ DWORD grfdex,
        !           225:        /* [out] */ DISPID *pid)
        !           226: {
        !           227:        HRESULT ret = DISP_E_UNKNOWNNAME;
        !           228:        char *name;
        !           229:        unsigned int namelen;
        !           230:        zval **tmp;
        !           231:        FETCH_DISP("GetDispID");
        !           232: 
        !           233:        name = php_com_olestring_to_string(bstrName, &namelen, COMG(code_page) TSRMLS_CC);
        !           234: 
        !           235:        trace("Looking for %s, namelen=%d in %p\n", name, namelen, disp->name_to_dispid);
        !           236:        
        !           237:        /* Lookup the name in the hash */
        !           238:        if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) {
        !           239:                trace("found it\n");
        !           240:                *pid = Z_LVAL_PP(tmp);
        !           241:                ret = S_OK;
        !           242:        }
        !           243: 
        !           244:        efree(name);
        !           245:        
        !           246:        return ret;
        !           247: }
        !           248: 
        !           249: static HRESULT STDMETHODCALLTYPE disp_invokeex( 
        !           250:        IDispatchEx *This,
        !           251:        /* [in] */ DISPID id,
        !           252:        /* [in] */ LCID lcid,
        !           253:        /* [in] */ WORD wFlags,
        !           254:        /* [in] */ DISPPARAMS *pdp,
        !           255:        /* [out] */ VARIANT *pvarRes,
        !           256:        /* [out] */ EXCEPINFO *pei,
        !           257:        /* [unique][in] */ IServiceProvider *pspCaller)
        !           258: {
        !           259:        zval **name;
        !           260:        UINT i;
        !           261:        zval *retval = NULL;
        !           262:        zval ***params = NULL;
        !           263:        HRESULT ret = DISP_E_MEMBERNOTFOUND;
        !           264:        FETCH_DISP("InvokeEx");
        !           265: 
        !           266:        if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
        !           267:                /* TODO: add support for overloaded objects */
        !           268: 
        !           269:                trace("-- Invoke: %d %20s [%d] flags=%08x args=%d\n", id, Z_STRVAL_PP(name), Z_STRLEN_PP(name), wFlags, pdp->cArgs);
        !           270:                
        !           271:                /* convert args into zvals.
        !           272:                 * Args are in reverse order */
        !           273:                if (pdp->cArgs) {
        !           274:                        params = (zval ***)safe_emalloc(sizeof(zval **), pdp->cArgs, 0);
        !           275:                        for (i = 0; i < pdp->cArgs; i++) {
        !           276:                                VARIANT *arg;
        !           277:                                zval *zarg;
        !           278: 
        !           279:                                arg = &pdp->rgvarg[ pdp->cArgs - 1 - i];
        !           280: 
        !           281:                                trace("alloc zval for arg %d VT=%08x\n", i, V_VT(arg));
        !           282: 
        !           283:                                ALLOC_INIT_ZVAL(zarg);
        !           284:                                php_com_wrap_variant(zarg, arg, COMG(code_page) TSRMLS_CC);
        !           285:                                params[i] = (zval**)emalloc(sizeof(zval**));
        !           286:                                *params[i] = zarg;
        !           287:                        }
        !           288:                }
        !           289: 
        !           290:                trace("arguments processed, prepare to do some work\n");        
        !           291:        
        !           292:                /* TODO: if PHP raises an exception here, we should catch it
        !           293:                 * and expose it as a COM exception */
        !           294:                
        !           295:                if (wFlags & DISPATCH_PROPERTYGET) {
        !           296:                        retval = zend_read_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, 1 TSRMLS_CC);
        !           297:                } else if (wFlags & DISPATCH_PROPERTYPUT) {
        !           298:                        zend_update_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, *params[0] TSRMLS_CC);
        !           299:                } else if (wFlags & DISPATCH_METHOD) {
        !           300:                        zend_try {
        !           301:                                if (SUCCESS == call_user_function_ex(EG(function_table), &disp->object, *name,
        !           302:                                                        &retval, pdp->cArgs, params, 1, NULL TSRMLS_CC)) {
        !           303:                                        ret = S_OK;
        !           304:                                        trace("function called ok\n");
        !           305: 
        !           306:                                        /* Copy any modified values to callers copy of variant*/
        !           307:                                        for (i = 0; i < pdp->cArgs; i++) {
        !           308:                                                php_com_dotnet_object *obj = CDNO_FETCH(*params[i]);
        !           309:                                                VARIANT *srcvar = &obj->v;
        !           310:                                                VARIANT *dstvar = &pdp->rgvarg[ pdp->cArgs - 1 - i];
        !           311:                                                if ((V_VT(dstvar) & VT_BYREF) && obj->modified ) {
        !           312:                                                        trace("percolate modified value for arg %d VT=%08x\n", i, V_VT(dstvar));
        !           313:                                                        php_com_copy_variant(dstvar, srcvar TSRMLS_CC);   
        !           314:                                                }
        !           315:                                        }
        !           316:                                } else {
        !           317:                                        trace("failed to call func\n");
        !           318:                                        ret = DISP_E_EXCEPTION;
        !           319:                                }
        !           320:                        } zend_catch {
        !           321:                                trace("something blew up\n");
        !           322:                                ret = DISP_E_EXCEPTION;
        !           323:                        } zend_end_try();
        !           324:                } else {
        !           325:                        trace("Don't know how to handle this invocation %08x\n", wFlags);
        !           326:                }
        !           327:        
        !           328:                /* release arguments */
        !           329:                if (params) {
        !           330:                        for (i = 0; i < pdp->cArgs; i++) {
        !           331:                                zval_ptr_dtor(params[i]);
        !           332:                                efree(params[i]);
        !           333:                        }
        !           334:                        efree(params);
        !           335:                }
        !           336:                
        !           337:                /* return value */
        !           338:                if (retval) {
        !           339:                        if (pvarRes) {
        !           340:                                VariantInit(pvarRes);
        !           341:                                php_com_variant_from_zval(pvarRes, retval, COMG(code_page) TSRMLS_CC);
        !           342:                        }
        !           343:                        zval_ptr_dtor(&retval);
        !           344:                } else if (pvarRes) {
        !           345:                        VariantInit(pvarRes);
        !           346:                }
        !           347:                
        !           348:        } else {
        !           349:                trace("InvokeEx: I don't support DISPID=%d\n", id);
        !           350:        }
        !           351: 
        !           352:        return ret;
        !           353: }
        !           354: 
        !           355: static HRESULT STDMETHODCALLTYPE disp_deletememberbyname( 
        !           356:        IDispatchEx *This,
        !           357:        /* [in] */ BSTR bstrName,
        !           358:        /* [in] */ DWORD grfdex)
        !           359: {
        !           360:        FETCH_DISP("DeleteMemberByName");
        !           361: 
        !           362:        /* TODO: unset */
        !           363: 
        !           364:        return S_FALSE;
        !           365: }
        !           366: 
        !           367: static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid( 
        !           368:        IDispatchEx *This,
        !           369:        /* [in] */ DISPID id)
        !           370: {
        !           371:        FETCH_DISP("DeleteMemberByDispID");
        !           372:        
        !           373:        /* TODO: unset */
        !           374:        
        !           375:        return S_FALSE;
        !           376: }
        !           377: 
        !           378: static HRESULT STDMETHODCALLTYPE disp_getmemberproperties( 
        !           379:        IDispatchEx *This,
        !           380:        /* [in] */ DISPID id,
        !           381:        /* [in] */ DWORD grfdexFetch,
        !           382:        /* [out] */ DWORD *pgrfdex)
        !           383: {
        !           384:        FETCH_DISP("GetMemberProperties");
        !           385: 
        !           386:        return DISP_E_UNKNOWNNAME;
        !           387: }
        !           388: 
        !           389: static HRESULT STDMETHODCALLTYPE disp_getmembername( 
        !           390:        IDispatchEx *This,
        !           391:        /* [in] */ DISPID id,
        !           392:        /* [out] */ BSTR *pbstrName)
        !           393: {
        !           394:        zval *name;
        !           395:        FETCH_DISP("GetMemberName");
        !           396: 
        !           397:        if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
        !           398:                OLECHAR *olestr = php_com_string_to_olestring(Z_STRVAL_P(name), Z_STRLEN_P(name), COMG(code_page) TSRMLS_CC);
        !           399:                *pbstrName = SysAllocString(olestr);
        !           400:                efree(olestr);
        !           401:                return S_OK;
        !           402:        } else {
        !           403:                return DISP_E_UNKNOWNNAME;
        !           404:        }
        !           405: }
        !           406: 
        !           407: static HRESULT STDMETHODCALLTYPE disp_getnextdispid( 
        !           408:        IDispatchEx *This,
        !           409:        /* [in] */ DWORD grfdex,
        !           410:        /* [in] */ DISPID id,
        !           411:        /* [out] */ DISPID *pid)
        !           412: {
        !           413:        ulong next = id+1;
        !           414:        FETCH_DISP("GetNextDispID");
        !           415: 
        !           416:        while(!zend_hash_index_exists(disp->dispid_to_name, next))
        !           417:                next++;
        !           418: 
        !           419:        if (zend_hash_index_exists(disp->dispid_to_name, next)) {
        !           420:                *pid = next;
        !           421:                return S_OK;
        !           422:        }
        !           423:        return S_FALSE;
        !           424: }
        !           425: 
        !           426: static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent( 
        !           427:        IDispatchEx *This,
        !           428:        /* [out] */ IUnknown **ppunk)
        !           429: {
        !           430:        FETCH_DISP("GetNameSpaceParent");
        !           431: 
        !           432:        *ppunk = NULL;
        !           433:        return E_NOTIMPL;
        !           434: }
        !           435:         
        !           436: static struct IDispatchExVtbl php_dispatch_vtbl = {
        !           437:        disp_queryinterface,
        !           438:        disp_addref,
        !           439:        disp_release,
        !           440:        disp_gettypeinfocount,
        !           441:        disp_gettypeinfo,
        !           442:        disp_getidsofnames,
        !           443:        disp_invoke,
        !           444:        disp_getdispid,
        !           445:        disp_invokeex,
        !           446:        disp_deletememberbyname,
        !           447:        disp_deletememberbydispid,
        !           448:        disp_getmemberproperties,
        !           449:        disp_getmembername,
        !           450:        disp_getnextdispid,
        !           451:        disp_getnamespaceparent
        !           452: };
        !           453: 
        !           454: 
        !           455: /* enumerate functions and properties of the object and assign
        !           456:  * dispatch ids */
        !           457: static void generate_dispids(php_dispatchex *disp TSRMLS_DC)
        !           458: {
        !           459:        HashPosition pos;
        !           460:        char *name = NULL;
        !           461:        zval *tmp;
        !           462:        int namelen;
        !           463:        int keytype;
        !           464:        ulong pid;
        !           465: 
        !           466:        if (disp->dispid_to_name == NULL) {
        !           467:                ALLOC_HASHTABLE(disp->dispid_to_name);
        !           468:                ALLOC_HASHTABLE(disp->name_to_dispid);
        !           469:                zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
        !           470:                zend_hash_init(disp->dispid_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
        !           471:        }
        !           472: 
        !           473:        /* properties */
        !           474:        if (Z_OBJPROP_P(disp->object)) {
        !           475:                zend_hash_internal_pointer_reset_ex(Z_OBJPROP_P(disp->object), &pos);
        !           476:                while (HASH_KEY_NON_EXISTANT != (keytype =
        !           477:                                zend_hash_get_current_key_ex(Z_OBJPROP_P(disp->object), &name,
        !           478:                                &namelen, &pid, 0, &pos))) {
        !           479:                        char namebuf[32];
        !           480:                        if (keytype == HASH_KEY_IS_LONG) {
        !           481:                                snprintf(namebuf, sizeof(namebuf), "%d", pid);
        !           482:                                name = namebuf;
        !           483:                                namelen = strlen(namebuf)+1;
        !           484:                        }
        !           485: 
        !           486:                        zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
        !           487: 
        !           488:                        /* Find the existing id */
        !           489:                        if (zend_hash_find(disp->name_to_dispid, name, namelen, (void**)&tmp) == SUCCESS)
        !           490:                                continue;
        !           491: 
        !           492:                        /* add the mappings */
        !           493:                        MAKE_STD_ZVAL(tmp);
        !           494:                        ZVAL_STRINGL(tmp, name, namelen-1, 1);
        !           495:                        pid = zend_hash_next_free_element(disp->dispid_to_name);
        !           496:                        zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
        !           497: 
        !           498:                        MAKE_STD_ZVAL(tmp);
        !           499:                        ZVAL_LONG(tmp, pid);
        !           500:                        zend_hash_update(disp->name_to_dispid, name, namelen, (void*)&tmp, sizeof(zval *), NULL);
        !           501:                }
        !           502:        }
        !           503:        
        !           504:        /* functions */
        !           505:        if (Z_OBJCE_P(disp->object)) {
        !           506:                zend_hash_internal_pointer_reset_ex(&Z_OBJCE_P(disp->object)->function_table, &pos);
        !           507:                while (HASH_KEY_NON_EXISTANT != (keytype =
        !           508:                                zend_hash_get_current_key_ex(&Z_OBJCE_P(disp->object)->function_table,
        !           509:                                &name, &namelen, &pid, 0, &pos))) {
        !           510: 
        !           511:                        char namebuf[32];
        !           512:                        if (keytype == HASH_KEY_IS_LONG) {
        !           513:                                snprintf(namebuf, sizeof(namebuf), "%d", pid);
        !           514:                                name = namebuf;
        !           515:                                namelen = strlen(namebuf) + 1;
        !           516:                        }
        !           517: 
        !           518:                        zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
        !           519: 
        !           520:                        /* Find the existing id */
        !           521:                        if (zend_hash_find(disp->name_to_dispid, name, namelen, (void**)&tmp) == SUCCESS)
        !           522:                                continue;
        !           523: 
        !           524:                        /* add the mappings */
        !           525:                        MAKE_STD_ZVAL(tmp);
        !           526:                        ZVAL_STRINGL(tmp, name, namelen-1, 1);
        !           527:                        pid = zend_hash_next_free_element(disp->dispid_to_name);
        !           528:                        zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
        !           529: 
        !           530:                        MAKE_STD_ZVAL(tmp);
        !           531:                        ZVAL_LONG(tmp, pid);
        !           532:                        zend_hash_update(disp->name_to_dispid, name, namelen, (void*)&tmp, sizeof(zval *), NULL);
        !           533:                }
        !           534:        }
        !           535: }
        !           536: 
        !           537: static php_dispatchex *disp_constructor(zval *object TSRMLS_DC)
        !           538: {
        !           539:        php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
        !           540: 
        !           541:        trace("constructing a COM wrapper for PHP object %p (%s)\n", object, Z_OBJCE_P(object)->name);
        !           542:        
        !           543:        if (disp == NULL)
        !           544:                return NULL;
        !           545: 
        !           546:        memset(disp, 0, sizeof(php_dispatchex));
        !           547: 
        !           548:        disp->engine_thread = GetCurrentThreadId();
        !           549:        disp->lpVtbl = &php_dispatch_vtbl;
        !           550:        disp->refcount = 1;
        !           551: 
        !           552: 
        !           553:        if (object)
        !           554:                Z_ADDREF_P(object);
        !           555:        disp->object = object;
        !           556: 
        !           557:        disp->id = zend_list_insert(disp, le_dispatch);
        !           558:        
        !           559:        return disp;
        !           560: }
        !           561: 
        !           562: static void disp_destructor(php_dispatchex *disp)
        !           563: {
        !           564:        TSRMLS_FETCH();
        !           565:        
        !           566:        /* Object store not available during request shutdown */
        !           567:        if (COMG(rshutdown_started)) {
        !           568:                trace("destroying COM wrapper for PHP object %p (name:unknown)\n", disp->object);
        !           569:        } else {
        !           570:                trace("destroying COM wrapper for PHP object %p (name:%s)\n", disp->object, Z_OBJCE_P(disp->object)->name);
        !           571:        }
        !           572:        
        !           573:        disp->id = 0;
        !           574:        
        !           575:        if (disp->refcount > 0)
        !           576:                CoDisconnectObject((IUnknown*)disp, 0);
        !           577: 
        !           578:        zend_hash_destroy(disp->dispid_to_name);
        !           579:        zend_hash_destroy(disp->name_to_dispid);
        !           580:        FREE_HASHTABLE(disp->dispid_to_name);
        !           581:        FREE_HASHTABLE(disp->name_to_dispid);
        !           582:                        
        !           583:        if (disp->object)
        !           584:                zval_ptr_dtor(&disp->object);
        !           585: 
        !           586:        CoTaskMemFree(disp);
        !           587: }
        !           588: 
        !           589: PHPAPI IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid,
        !           590:           HashTable *id_to_name TSRMLS_DC)
        !           591: {
        !           592:        php_dispatchex *disp = disp_constructor(val TSRMLS_CC);
        !           593:        HashPosition pos;
        !           594:        char *name = NULL;
        !           595:        zval *tmp, **ntmp;
        !           596:        int namelen;
        !           597:        int keytype;
        !           598:        ulong pid;
        !           599: 
        !           600:        disp->dispid_to_name = id_to_name;
        !           601: 
        !           602:        memcpy(&disp->sinkid, sinkid, sizeof(disp->sinkid));
        !           603:        
        !           604:        /* build up the reverse mapping */
        !           605:        ALLOC_HASHTABLE(disp->name_to_dispid);
        !           606:        zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
        !           607:        
        !           608:        zend_hash_internal_pointer_reset_ex(id_to_name, &pos);
        !           609:        while (HASH_KEY_NON_EXISTANT != (keytype =
        !           610:                                zend_hash_get_current_key_ex(id_to_name, &name, &namelen, &pid, 0, &pos))) {
        !           611: 
        !           612:                if (keytype == HASH_KEY_IS_LONG) {
        !           613: 
        !           614:                        zend_hash_get_current_data_ex(id_to_name, (void**)&ntmp, &pos);
        !           615:                        
        !           616:                        MAKE_STD_ZVAL(tmp);
        !           617:                        ZVAL_LONG(tmp, pid);
        !           618:                        zend_hash_update(disp->name_to_dispid, Z_STRVAL_PP(ntmp),
        !           619:                                Z_STRLEN_PP(ntmp)+1, (void*)&tmp, sizeof(zval *), NULL);
        !           620:                }
        !           621: 
        !           622:                zend_hash_move_forward_ex(id_to_name, &pos);
        !           623:        }
        !           624: 
        !           625:        return (IDispatch*)disp;
        !           626: }
        !           627: 
        !           628: PHPAPI IDispatch *php_com_wrapper_export(zval *val TSRMLS_DC)
        !           629: {
        !           630:        php_dispatchex *disp = NULL;
        !           631: 
        !           632:        if (Z_TYPE_P(val) != IS_OBJECT) {
        !           633:                return NULL;
        !           634:        }
        !           635: 
        !           636:        if (php_com_is_valid_object(val TSRMLS_CC)) {
        !           637:                /* pass back its IDispatch directly */
        !           638:                php_com_dotnet_object *obj = CDNO_FETCH(val);
        !           639:                
        !           640:                if (obj == NULL)
        !           641:                        return NULL;
        !           642: 
        !           643:                if (V_VT(&obj->v) == VT_DISPATCH && V_DISPATCH(&obj->v)) {
        !           644:                        IDispatch_AddRef(V_DISPATCH(&obj->v));
        !           645:                        return V_DISPATCH(&obj->v);
        !           646:                }
        !           647:                        
        !           648:                return NULL;
        !           649:        }
        !           650: 
        !           651:        disp = disp_constructor(val TSRMLS_CC);
        !           652:        generate_dispids(disp TSRMLS_CC);
        !           653: 
        !           654:        return (IDispatch*)disp;
        !           655: }
        !           656: 
        !           657: 

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