Annotation of embedaddon/php/ext/com_dotnet/com_wrapper.c, revision 1.1.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>