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

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