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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Author: Wez Furlong  <wez@thebrainroom.com>                          |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      20: 
                     21: #ifdef HAVE_CONFIG_H
                     22: #include "config.h"
                     23: #endif
                     24: 
                     25: #include "php.h"
                     26: #include "php_ini.h"
                     27: #include "ext/standard/info.h"
                     28: #include "php_com_dotnet.h"
                     29: #include "php_com_dotnet_internal.h"
                     30: #include "Zend/zend_exceptions.h"
                     31: 
                     32: /* {{{ com_create_instance - ctor for COM class */
                     33: PHP_FUNCTION(com_create_instance)
                     34: {
                     35:        zval *object = getThis();
                     36:        zval *server_params = NULL;
                     37:        php_com_dotnet_object *obj;
                     38:        char *module_name, *typelib_name = NULL, *server_name = NULL;
                     39:        char *user_name = NULL, *domain_name = NULL, *password = NULL;
                     40:        int module_name_len, typelib_name_len, server_name_len,
                     41:                user_name_len, domain_name_len, password_len;
                     42:        OLECHAR *moniker;
                     43:        CLSID clsid;
                     44:        CLSCTX ctx = CLSCTX_SERVER;
                     45:        HRESULT res = E_FAIL;
                     46:        int mode = COMG(autoreg_case_sensitive) ? CONST_CS : 0;
                     47:        ITypeLib *TL = NULL;
                     48:        COSERVERINFO    info;
                     49:        COAUTHIDENTITY  authid = {0};
                     50:        COAUTHINFO              authinfo = {
                     51:                RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
                     52:                RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE,
                     53:                &authid, EOAC_NONE
                     54:        };
                     55: 
                     56:        php_com_initialize(TSRMLS_C);
                     57:        obj = CDNO_FETCH(object);
                     58: 
                     59:        if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                     60:                        ZEND_NUM_ARGS() TSRMLS_CC, "s|s!ls",
                     61:                        &module_name, &module_name_len, &server_name, &server_name_len,
                     62:                        &obj->code_page, &typelib_name, &typelib_name_len) &&
                     63:                FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                     64:                        ZEND_NUM_ARGS() TSRMLS_CC, "sa|ls",
                     65:                        &module_name, &module_name_len, &server_params, &obj->code_page,
                     66:                        &typelib_name, &typelib_name_len)) {
                     67: 
                     68:                php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid arguments!" TSRMLS_CC);
                     69:                ZVAL_NULL(object);
                     70:                return;
                     71:        }
                     72: 
                     73:        if (server_name) {
                     74:                ctx = CLSCTX_REMOTE_SERVER;
                     75:        } else if (server_params) {
                     76:                zval **tmp;
                     77: 
                     78:                /* decode the data from the array */
                     79: 
                     80:                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                     81:                                "Server", sizeof("Server"), (void**)&tmp)) {
                     82:                        convert_to_string_ex(tmp);
                     83:                        server_name = Z_STRVAL_PP(tmp);
                     84:                        server_name_len = Z_STRLEN_PP(tmp);
                     85:                        ctx = CLSCTX_REMOTE_SERVER;
                     86:                }
                     87: 
                     88:                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                     89:                                "Username", sizeof("Username"), (void**)&tmp)) {
                     90:                        convert_to_string_ex(tmp);
                     91:                        user_name = Z_STRVAL_PP(tmp);
                     92:                        user_name_len = Z_STRLEN_PP(tmp);
                     93:                }
                     94: 
                     95:                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                     96:                                "Password", sizeof("Password"), (void**)&tmp)) {
                     97:                        convert_to_string_ex(tmp);
                     98:                        password = Z_STRVAL_PP(tmp);
                     99:                        password_len = Z_STRLEN_PP(tmp);
                    100:                }
                    101: 
                    102:                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                    103:                                "Domain", sizeof("Domain"), (void**)&tmp)) {
                    104:                        convert_to_string_ex(tmp);
                    105:                        domain_name = Z_STRVAL_PP(tmp);
                    106:                        domain_name_len = Z_STRLEN_PP(tmp);
                    107:                }
                    108: 
                    109:                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                    110:                                "Flags", sizeof("Flags"), (void**)&tmp)) {
                    111:                        convert_to_long_ex(tmp);
                    112:                        ctx = (CLSCTX)Z_LVAL_PP(tmp);
                    113:                }
                    114:        }
                    115: 
                    116:        if (server_name && !COMG(allow_dcom)) {
                    117:                php_com_throw_exception(E_ERROR, "DCOM has been disabled by your administrator [com.allow_dcom=0]" TSRMLS_CC);
                    118:                return;
                    119:        }
                    120: 
                    121:        moniker = php_com_string_to_olestring(module_name, module_name_len, obj->code_page TSRMLS_CC);
                    122: 
                    123:        /* if instantiating a remote object, either directly, or via
                    124:         * a moniker, fill in the relevant info */
                    125:        if (server_name) {
                    126:                info.dwReserved1 = 0;
                    127:                info.dwReserved2 = 0;
                    128:                info.pwszName = php_com_string_to_olestring(server_name, server_name_len, obj->code_page TSRMLS_CC);
                    129: 
                    130:                if (user_name) {
                    131:                        authid.User = php_com_string_to_olestring(user_name, -1, obj->code_page TSRMLS_CC);
                    132:                        authid.UserLength = user_name_len;
                    133: 
                    134:                        if (password) {
                    135:                                authid.Password = (OLECHAR*)password;
                    136:                                authid.PasswordLength = password_len;
                    137:                        } else {
                    138:                                authid.Password = (OLECHAR*)"";
                    139:                                authid.PasswordLength = 0;
                    140:                        }
                    141: 
                    142:                        if (domain_name) {
                    143:                                authid.Domain = (OLECHAR*)domain_name;
                    144:                                authid.DomainLength = domain_name_len;
                    145:                        } else {
                    146:                                authid.Domain = (OLECHAR*)"";
                    147:                                authid.DomainLength = 0;
                    148:                        }
                    149:                        authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
                    150:                        info.pAuthInfo = &authinfo;
                    151:                } else {
                    152:                        info.pAuthInfo = NULL;
                    153:                }
                    154:        }
                    155: 
                    156:        if (FAILED(CLSIDFromString(moniker, &clsid))) {
                    157:                /* try to use it as a moniker */
                    158:                IBindCtx *pBindCtx = NULL;
                    159:                IMoniker *pMoniker = NULL;
                    160:                ULONG ulEaten;
                    161:                BIND_OPTS2 bopt = {0};
                    162: 
                    163:                if (SUCCEEDED(res = CreateBindCtx(0, &pBindCtx))) {
                    164:                        if (server_name) {
                    165:                                /* fill in the remote server info.
                    166:                                 * MSDN docs indicate that this might be ignored in
                    167:                                 * current win32 implementations, but at least we are
                    168:                                 * doing the right thing in readiness for the day that
                    169:                                 * it does work */
                    170:                                bopt.cbStruct = sizeof(bopt);
                    171:                                IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
                    172:                                bopt.pServerInfo = &info;
                    173:                                /* apparently, GetBindOptions will only ever return
                    174:                                 * a regular BIND_OPTS structure.  My gut feeling is
                    175:                                 * that it will modify the size field to reflect that
                    176:                                 * so lets be safe and set it to the BIND_OPTS2 size
                    177:                                 * again */
                    178:                                bopt.cbStruct = sizeof(bopt);
                    179:                                IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
                    180:                        }
                    181:                        
                    182:                        if (SUCCEEDED(res = MkParseDisplayName(pBindCtx, moniker, &ulEaten, &pMoniker))) {
                    183:                                res = IMoniker_BindToObject(pMoniker, pBindCtx,
                    184:                                        NULL, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
                    185:                        
                    186:                                if (SUCCEEDED(res)) {
                    187:                                        V_VT(&obj->v) = VT_DISPATCH;
                    188:                                }
                    189: 
                    190:                                IMoniker_Release(pMoniker);
                    191:                        }
                    192:                }
                    193:                if (pBindCtx) {
                    194:                        IBindCtx_Release(pBindCtx);
                    195:                }
                    196:        } else if (server_name) {
                    197:                MULTI_QI                qi;
                    198: 
                    199:                qi.pIID = &IID_IDispatch;
                    200:                qi.pItf = NULL;
                    201:                qi.hr = S_OK;
                    202: 
                    203:                res = CoCreateInstanceEx(&clsid, NULL, ctx, &info, 1, &qi);
                    204: 
                    205:                if (SUCCEEDED(res)) {
                    206:                        res = qi.hr;
                    207:                        V_DISPATCH(&obj->v) = (IDispatch*)qi.pItf;
                    208:                        V_VT(&obj->v) = VT_DISPATCH;
                    209:                }
                    210:        } else {
                    211:                res = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
                    212:                if (SUCCEEDED(res)) {
                    213:                        V_VT(&obj->v) = VT_DISPATCH;
                    214:                }
                    215:        }
                    216: 
                    217:        if (server_name) {
                    218:                STR_FREE((char*)info.pwszName);
                    219:                STR_FREE((char*)authid.User);
                    220:        }
                    221: 
                    222:        efree(moniker);
                    223: 
                    224:        if (FAILED(res)) {
                    225:                char *werr, *msg;
                    226: 
1.1.1.2 ! misho     227:                werr = php_win32_error_to_msg(res);
1.1       misho     228:                spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, werr);
                    229:                LocalFree(werr);
                    230: 
                    231:                php_com_throw_exception(res, msg TSRMLS_CC);
                    232:                efree(msg);
                    233:                ZVAL_NULL(object);
                    234:                return;
                    235:        }
                    236: 
                    237:        /* we got the object and it lives ! */
                    238: 
                    239:        /* see if it has TypeInfo available */
                    240:        if (FAILED(IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo)) && typelib_name) {
                    241:                /* load up the library from the named file */
                    242:                int cached;
                    243: 
                    244:                TL = php_com_load_typelib_via_cache(typelib_name, obj->code_page, &cached TSRMLS_CC);
                    245: 
                    246:                if (TL) {
                    247:                        if (COMG(autoreg_on) && !cached) {
                    248:                                php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
                    249:                        }
                    250: 
                    251:                        /* cross your fingers... there is no guarantee that this ITypeInfo
                    252:                         * instance has any relation to this IDispatch instance... */
                    253:                        ITypeLib_GetTypeInfo(TL, 0, &obj->typeinfo);
                    254:                        ITypeLib_Release(TL);
                    255:                }
                    256:        } else if (obj->typeinfo && COMG(autoreg_on)) {
                    257:                int idx;
                    258: 
                    259:                if (SUCCEEDED(ITypeInfo_GetContainingTypeLib(obj->typeinfo, &TL, &idx))) {
                    260:                        /* check if the library is already in the cache by getting its name */
                    261:                        BSTR name;
                    262: 
                    263:                        if (SUCCEEDED(ITypeLib_GetDocumentation(TL, -1, &name, NULL, NULL, NULL))) {
                    264:                                typelib_name = php_com_olestring_to_string(name, &typelib_name_len, obj->code_page TSRMLS_CC);
                    265: 
                    266:                                if (SUCCESS == zend_ts_hash_add(&php_com_typelibraries, typelib_name, typelib_name_len+1, (void*)&TL, sizeof(ITypeLib*), NULL)) {
                    267:                                        php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
                    268: 
                    269:                                        /* add a reference for the hash */
                    270:                                        ITypeLib_AddRef(TL);
                    271:                                }
                    272: 
                    273:                        } else {
                    274:                                /* try it anyway */
                    275:                                php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
                    276:                        }
                    277: 
                    278:                        ITypeLib_Release(TL);
                    279:                }
                    280:        }
                    281: 
                    282: }
                    283: /* }}} */
                    284: 
                    285: /* {{{ proto object com_get_active_object(string progid [, int code_page ])
                    286:    Returns a handle to an already running instance of a COM object */
                    287: PHP_FUNCTION(com_get_active_object)
                    288: {
                    289:        CLSID clsid;
                    290:        char *module_name;
                    291:        int module_name_len;
                    292:        long code_page = COMG(code_page);
                    293:        IUnknown *unk = NULL;
                    294:        IDispatch *obj = NULL;
                    295:        HRESULT res;
                    296:        OLECHAR *module = NULL;
                    297: 
                    298:        php_com_initialize(TSRMLS_C);
                    299:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
                    300:                                &module_name, &module_name_len, &code_page)) {
                    301:                php_com_throw_exception(E_INVALIDARG, "Invalid arguments!" TSRMLS_CC);
                    302:                return;
                    303:        }
                    304: 
                    305:        module = php_com_string_to_olestring(module_name, module_name_len, code_page TSRMLS_CC);
                    306: 
                    307:        res = CLSIDFromString(module, &clsid);
                    308: 
                    309:        if (FAILED(res)) {
                    310:                php_com_throw_exception(res, NULL TSRMLS_CC);
                    311:        } else {
                    312:                res = GetActiveObject(&clsid, NULL, &unk);
                    313: 
                    314:                if (FAILED(res)) {
                    315:                        php_com_throw_exception(res, NULL TSRMLS_CC);
                    316:                } else {
                    317:                        res = IUnknown_QueryInterface(unk, &IID_IDispatch, &obj);
                    318: 
                    319:                        if (FAILED(res)) {
                    320:                                php_com_throw_exception(res, NULL TSRMLS_CC);
                    321:                        } else if (obj) {
                    322:                                /* we got our dispatchable object */
                    323:                                php_com_wrap_dispatch(return_value, obj, code_page TSRMLS_CC);
                    324:                        }
                    325:                }
                    326:        }
                    327: 
                    328:        if (obj) {
                    329:                IDispatch_Release(obj);
                    330:        }
                    331:        if (unk) {
                    332:                IUnknown_Release(obj);
                    333:        }
                    334:        efree(module);
                    335: }
                    336: /* }}} */
                    337: 
                    338: /* Performs an Invoke on the given com object.
                    339:  * returns a failure code and creates an exception if there was an error */
                    340: HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
                    341:                WORD flags, DISPPARAMS *disp_params, VARIANT *v, int silent, int allow_noarg TSRMLS_DC)
                    342: {
                    343:        HRESULT hr;
                    344:        unsigned int arg_err;
                    345:        EXCEPINFO e = {0};
                    346: 
                    347:        hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
                    348:                &IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, v, &e, &arg_err);
                    349: 
                    350:        if (silent == 0 && FAILED(hr)) {
                    351:                char *source = NULL, *desc = NULL, *msg = NULL;
                    352:                int source_len, desc_len;
                    353: 
                    354:                switch (hr) {
                    355:                        case DISP_E_EXCEPTION:
                    356:                                if (e.bstrSource) {
                    357:                                        source = php_com_olestring_to_string(e.bstrSource, &source_len, obj->code_page TSRMLS_CC);
                    358:                                        SysFreeString(e.bstrSource);
                    359:                                }
                    360:                                if (e.bstrDescription) {
                    361:                                        desc = php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page TSRMLS_CC);
                    362:                                        SysFreeString(e.bstrDescription);
                    363:                                }
                    364:                                if (PG(html_errors)) {
                    365:                                        spprintf(&msg, 0, "<b>Source:</b> %s<br/><b>Description:</b> %s",
                    366:                                                source ? source : "Unknown",
                    367:                                                desc ? desc : "Unknown");
                    368:                                } else {
                    369:                                        spprintf(&msg, 0, "Source: %s\nDescription: %s",
                    370:                                                source ? source : "Unknown",
                    371:                                                desc ? desc : "Unknown");
                    372:                                }
                    373:                                if (desc) {
                    374:                                        efree(desc);
                    375:                                }
                    376:                                if (source) {
                    377:                                        efree(source);
                    378:                                }
                    379:                                if (e.bstrHelpFile) {
                    380:                                        SysFreeString(e.bstrHelpFile);
                    381:                                }
                    382:                                break;
                    383: 
                    384:                        case DISP_E_PARAMNOTFOUND:
                    385:                        case DISP_E_TYPEMISMATCH:
1.1.1.2 ! misho     386:                                desc = php_win32_error_to_msg(hr);
1.1       misho     387:                                spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
                    388:                                LocalFree(desc);
                    389:                                break;
                    390: 
                    391:                        case DISP_E_BADPARAMCOUNT:
                    392:                                if ((disp_params->cArgs + disp_params->cNamedArgs == 0) && (allow_noarg == 1)) {
                    393:                                        /* if getting a property and they are missing all parameters,
                    394:                                         * we want to create a proxy object for them; so lets not create an
                    395:                                         * exception here */
                    396:                                        msg = NULL;
                    397:                                        break;
                    398:                                }
                    399:                                /* else fall through */
                    400:                                
                    401:                        default:
1.1.1.2 ! misho     402:                                desc = php_win32_error_to_msg(hr);
1.1       misho     403:                                spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
                    404:                                LocalFree(desc);
                    405:                                break;
                    406:                }
                    407: 
                    408:                if (msg) {
                    409:                        php_com_throw_exception(hr, msg TSRMLS_CC);
                    410:                        efree(msg);
                    411:                }
                    412:        }
                    413: 
                    414:        return hr;
                    415: }
                    416: 
                    417: /* map an ID to a name */
                    418: HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
                    419:                int namelen, DISPID *dispid TSRMLS_DC)
                    420: {
                    421:        OLECHAR *olename;
                    422:        HRESULT hr;
                    423:        DISPID *dispid_ptr;
                    424: 
                    425:        if (namelen == -1) {
                    426:                namelen = strlen(name);
                    427:        }
                    428: 
                    429:        if (obj->id_of_name_cache && SUCCESS == zend_hash_find(obj->id_of_name_cache, name, namelen, (void**)&dispid_ptr)) {
                    430:                *dispid = *dispid_ptr;
                    431:                return S_OK;
                    432:        }
                    433:        
                    434:        olename = php_com_string_to_olestring(name, namelen, obj->code_page TSRMLS_CC);
                    435: 
                    436:        if (obj->typeinfo) {
                    437:                hr = ITypeInfo_GetIDsOfNames(obj->typeinfo, &olename, 1, dispid);
                    438:                if (FAILED(hr)) {
                    439:                        hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
                    440:                        if (SUCCEEDED(hr)) {
                    441:                                /* fall back on IDispatch direct */
                    442:                                ITypeInfo_Release(obj->typeinfo);
                    443:                                obj->typeinfo = NULL;
                    444:                        }
                    445:                }
                    446:        } else {
                    447:                hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
                    448:        }
                    449:        efree(olename);
                    450: 
                    451:        if (SUCCEEDED(hr)) {
                    452:                /* cache the mapping */
                    453:                if (!obj->id_of_name_cache) {
                    454:                        ALLOC_HASHTABLE(obj->id_of_name_cache);
                    455:                        zend_hash_init(obj->id_of_name_cache, 2, NULL, NULL, 0);
                    456:                }
                    457:                zend_hash_update(obj->id_of_name_cache, name, namelen, dispid, sizeof(*dispid), NULL);
                    458:        }
                    459:        
                    460:        return hr;
                    461: }
                    462: 
                    463: /* the core of COM */
                    464: int php_com_do_invoke_byref(php_com_dotnet_object *obj, char *name, int namelen,
                    465:                WORD flags,     VARIANT *v, int nargs, zval ***args TSRMLS_DC)
                    466: {
                    467:        DISPID dispid, altdispid;
                    468:        DISPPARAMS disp_params;
                    469:        HRESULT hr;
                    470:        VARIANT *vargs = NULL, *byref_vals = NULL;
                    471:        int i, byref_count = 0, j;
                    472:        zend_internal_function *f = (zend_internal_function*)EG(current_execute_data)->function_state.function;
                    473: 
                    474:        /* assumption: that the active function (f) is the function we generated for the engine */
                    475:        if (!f || f->arg_info == NULL) {
                    476:           f = NULL;
                    477:        }
                    478:        
                    479:        hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);
                    480: 
                    481:        if (FAILED(hr)) {
                    482:                char *winerr = NULL;
                    483:                char *msg = NULL;
1.1.1.2 ! misho     484:                winerr = php_win32_error_to_msg(hr);
1.1       misho     485:                spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
                    486:                LocalFree(winerr);
                    487:                php_com_throw_exception(hr, msg TSRMLS_CC);
                    488:                efree(msg);
                    489:                return FAILURE;
                    490:        }
                    491: 
                    492: 
                    493:        if (nargs) {
                    494:                vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
                    495:        }
                    496: 
                    497:        if (f) {
                    498:                for (i = 0; i < nargs; i++) {
                    499:                        if (f->arg_info[nargs - i - 1].pass_by_reference) {
                    500:                                byref_count++;
                    501:                        }
                    502:                }
                    503:        }
                    504: 
                    505:        if (byref_count) {
                    506:                byref_vals = (VARIANT*)safe_emalloc(sizeof(VARIANT), byref_count, 0);
                    507:                for (j = 0, i = 0; i < nargs; i++) {
                    508:                        if (f->arg_info[nargs - i - 1].pass_by_reference) {
                    509:                                /* put the value into byref_vals instead */
                    510:                                php_com_variant_from_zval(&byref_vals[j], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
                    511: 
                    512:                                /* if it is already byref, "move" it into the vargs array, otherwise
                    513:                                 * make vargs a reference to this value */
                    514:                                if (V_VT(&byref_vals[j]) & VT_BYREF) {
                    515:                                        memcpy(&vargs[i], &byref_vals[j], sizeof(vargs[i]));
                    516:                                        VariantInit(&byref_vals[j]); /* leave the variant slot empty to simplify cleanup */
                    517:                                } else {
                    518:                                        VariantInit(&vargs[i]);
                    519:                                        V_VT(&vargs[i]) = V_VT(&byref_vals[j]) | VT_BYREF;
                    520:                                        /* union magic ensures that this works out */
                    521:                                        vargs[i].byref = &V_UINT(&byref_vals[j]);
                    522:                                }
                    523:                                j++;
                    524:                        } else {
                    525:                                php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
                    526:                        }
                    527:                }
                    528:                
                    529:        } else {
                    530:                /* Invoke'd args are in reverse order */
                    531:                for (i = 0; i < nargs; i++) {
                    532:                        php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
                    533:                }
                    534:        }
                    535: 
                    536:        disp_params.cArgs = nargs;
                    537:        disp_params.cNamedArgs = 0;
                    538:        disp_params.rgvarg = vargs;
                    539:        disp_params.rgdispidNamedArgs = NULL;
                    540: 
                    541:        if (flags & DISPATCH_PROPERTYPUT) {
                    542:                altdispid = DISPID_PROPERTYPUT;
                    543:                disp_params.rgdispidNamedArgs = &altdispid;
                    544:                disp_params.cNamedArgs = 1;
                    545:        }
                    546: 
                    547:        /* this will create an exception if needed */
                    548:        hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, 0, 0 TSRMLS_CC);        
                    549: 
                    550:        /* release variants */
                    551:        if (vargs) {
                    552:                for (i = 0, j = 0; i < nargs; i++) {
                    553:                        /* if this was byref, update the zval */
                    554:                        if (f && f->arg_info[nargs - i - 1].pass_by_reference) {
                    555:                                SEPARATE_ZVAL_IF_NOT_REF(args[nargs - i - 1]);
                    556: 
                    557:                                /* if the variant is pointing at the byref_vals, we need to map
                    558:                                 * the pointee value as a zval; otherwise, the value is pointing
                    559:                                 * into an existing PHP variant record */
                    560:                                if (V_VT(&vargs[i]) & VT_BYREF) {
                    561:                                        if (vargs[i].byref == &V_UINT(&byref_vals[j])) {
                    562:                                                /* copy that value */
                    563:                                                php_com_zval_from_variant(*args[nargs - i - 1], &byref_vals[j],
                    564:                                                        obj->code_page TSRMLS_CC);
                    565:                                        }
                    566:                                } else {
                    567:                                        /* not sure if this can ever happen; the variant we marked as BYREF
                    568:                                         * is no longer BYREF - copy its value */
                    569:                                        php_com_zval_from_variant(*args[nargs - i - 1], &vargs[i],
                    570:                                                obj->code_page TSRMLS_CC);
                    571:                                }
                    572:                                VariantClear(&byref_vals[j]);
                    573:                                j++;
                    574:                        }       
                    575:                        VariantClear(&vargs[i]);
                    576:                }
                    577:                efree(vargs);
                    578:        }
                    579: 
                    580:        return SUCCEEDED(hr) ? SUCCESS : FAILURE;
                    581: }
                    582: 
                    583: 
                    584: 
                    585: int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
                    586:                WORD flags,     VARIANT *v, int nargs, zval **args, int silent, int allow_noarg TSRMLS_DC)
                    587: {
                    588:        DISPID altdispid;
                    589:        DISPPARAMS disp_params;
                    590:        HRESULT hr;
                    591:        VARIANT *vargs = NULL;
                    592:        int i;
                    593: 
                    594:        if (nargs) {
                    595:                vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
                    596:        }
                    597: 
                    598:        /* Invoke'd args are in reverse order */
                    599:        for (i = 0; i < nargs; i++) {
                    600:                php_com_variant_from_zval(&vargs[i], args[nargs - i - 1], obj->code_page TSRMLS_CC);
                    601:        }
                    602: 
                    603:        disp_params.cArgs = nargs;
                    604:        disp_params.cNamedArgs = 0;
                    605:        disp_params.rgvarg = vargs;
                    606:        disp_params.rgdispidNamedArgs = NULL;
                    607: 
                    608:        if (flags & DISPATCH_PROPERTYPUT) {
                    609:                altdispid = DISPID_PROPERTYPUT;
                    610:                disp_params.rgdispidNamedArgs = &altdispid;
                    611:                disp_params.cNamedArgs = 1;
                    612:        }
                    613: 
                    614:        /* this will create an exception if needed */
                    615:        hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, silent, allow_noarg TSRMLS_CC); 
                    616: 
                    617:        /* release variants */
                    618:        if (vargs) {
                    619:                for (i = 0; i < nargs; i++) {
                    620:                        VariantClear(&vargs[i]);
                    621:                }
                    622:                efree(vargs);
                    623:        }
                    624: 
                    625:        /* a bit of a hack this, but it's needed for COM array access. */
                    626:        if (hr == DISP_E_BADPARAMCOUNT)
                    627:                return hr;
                    628:        
                    629:        return SUCCEEDED(hr) ? SUCCESS : FAILURE;
                    630: }
                    631: 
                    632: int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
                    633:                WORD flags,     VARIANT *v, int nargs, zval **args, int allow_noarg TSRMLS_DC)
                    634: {
                    635:        DISPID dispid;
                    636:        HRESULT hr;
                    637:        char *winerr = NULL;
                    638:        char *msg = NULL;
                    639: 
                    640:        hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);
                    641: 
                    642:        if (FAILED(hr)) {
1.1.1.2 ! misho     643:                winerr = php_win32_error_to_msg(hr);
1.1       misho     644:                spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
                    645:                LocalFree(winerr);
                    646:                php_com_throw_exception(hr, msg TSRMLS_CC);
                    647:                efree(msg);
                    648:                return FAILURE;
                    649:        }
                    650: 
                    651:        return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args, 0, allow_noarg TSRMLS_CC);
                    652: }
                    653: 
                    654: /* {{{ proto string com_create_guid()
                    655:    Generate a globally unique identifier (GUID) */
                    656: PHP_FUNCTION(com_create_guid)
                    657: {
                    658:        GUID retval;
                    659:        OLECHAR *guid_string;
                    660: 
                    661:        if (zend_parse_parameters_none() == FAILURE) {
                    662:                return;
                    663:        }
                    664: 
                    665:        php_com_initialize(TSRMLS_C);
                    666:        if (CoCreateGuid(&retval) == S_OK && StringFromCLSID(&retval, &guid_string) == S_OK) {
                    667:                Z_TYPE_P(return_value) = IS_STRING;
                    668:                Z_STRVAL_P(return_value) = php_com_olestring_to_string(guid_string, &Z_STRLEN_P(return_value), CP_ACP TSRMLS_CC);
                    669: 
                    670:                CoTaskMemFree(guid_string);
                    671:        } else {
                    672:                RETURN_FALSE;
                    673:        }
                    674: }
                    675: /* }}} */
                    676: 
                    677: /* {{{ proto bool com_event_sink(object comobject, object sinkobject [, mixed sinkinterface])
                    678:    Connect events from a COM object to a PHP object */
                    679: PHP_FUNCTION(com_event_sink)
                    680: {
                    681:        zval *object, *sinkobject, *sink=NULL;
                    682:        char *dispname = NULL, *typelibname = NULL;
                    683:        zend_bool gotguid = 0;
                    684:        php_com_dotnet_object *obj;
                    685:        ITypeInfo *typeinfo = NULL;
                    686: 
                    687:        RETVAL_FALSE;
                    688:        
                    689:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oo|z/",
                    690:                        &object, php_com_variant_class_entry, &sinkobject, &sink)) {
                    691:                RETURN_FALSE;
                    692:        }
                    693: 
                    694:        php_com_initialize(TSRMLS_C);
                    695:        obj = CDNO_FETCH(object);
                    696:        
                    697:        if (sink && Z_TYPE_P(sink) == IS_ARRAY) {
                    698:                /* 0 => typelibname, 1 => dispname */
                    699:                zval **tmp;
                    700: 
                    701:                if (zend_hash_index_find(Z_ARRVAL_P(sink), 0, (void**)&tmp) == SUCCESS)
                    702:                        typelibname = Z_STRVAL_PP(tmp);
                    703:                if (zend_hash_index_find(Z_ARRVAL_P(sink), 1, (void**)&tmp) == SUCCESS)
                    704:                        dispname = Z_STRVAL_PP(tmp);
                    705:        } else if (sink != NULL) {
                    706:                convert_to_string(sink);
                    707:                dispname = Z_STRVAL_P(sink);
                    708:        }
                    709:        
                    710:        typeinfo = php_com_locate_typeinfo(typelibname, obj, dispname, 1 TSRMLS_CC);
                    711: 
                    712:        if (typeinfo) {
                    713:                HashTable *id_to_name;
                    714:                
                    715:                ALLOC_HASHTABLE(id_to_name);
                    716:                
                    717:                if (php_com_process_typeinfo(typeinfo, id_to_name, 0, &obj->sink_id, obj->code_page TSRMLS_CC)) {
                    718: 
                    719:                        /* Create the COM wrapper for this sink */
                    720:                        obj->sink_dispatch = php_com_wrapper_export_as_sink(sinkobject, &obj->sink_id, id_to_name TSRMLS_CC);
                    721: 
                    722:                        /* Now hook it up to the source */
                    723:                        php_com_object_enable_event_sink(obj, TRUE TSRMLS_CC);
                    724:                        RETVAL_TRUE;
                    725: 
                    726:                } else {
                    727:                        FREE_HASHTABLE(id_to_name);
                    728:                }
                    729:        }
                    730:        
                    731:        if (typeinfo) {
                    732:                ITypeInfo_Release(typeinfo);
                    733:        }
                    734: 
                    735: }
                    736: /* }}} */
                    737: 
                    738: /* {{{ proto bool com_print_typeinfo(object comobject | string typelib, string dispinterface, bool wantsink)
                    739:    Print out a PHP class definition for a dispatchable interface */
                    740: PHP_FUNCTION(com_print_typeinfo)
                    741: {
                    742:        zval *arg1;
                    743:        char *ifacename = NULL;
                    744:        char *typelibname = NULL;
                    745:        int ifacelen;
                    746:        zend_bool wantsink = 0;
                    747:        php_com_dotnet_object *obj = NULL;
                    748:        ITypeInfo *typeinfo;
                    749:        
                    750:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|s!b", &arg1, &ifacename,
                    751:                                &ifacelen, &wantsink)) {
                    752:                RETURN_FALSE;
                    753:        }
                    754: 
                    755:        php_com_initialize(TSRMLS_C);
                    756:        if (Z_TYPE_P(arg1) == IS_OBJECT) {
                    757:                CDNO_FETCH_VERIFY(obj, arg1);
                    758:        } else {
                    759:                convert_to_string(arg1);
                    760:                typelibname = Z_STRVAL_P(arg1);
                    761:        }
                    762: 
                    763:        typeinfo = php_com_locate_typeinfo(typelibname, obj, ifacename, wantsink ? 1 : 0 TSRMLS_CC);
                    764:        if (typeinfo) {
                    765:                php_com_process_typeinfo(typeinfo, NULL, 1, NULL, obj ? obj->code_page : COMG(code_page) TSRMLS_CC);
                    766:                ITypeInfo_Release(typeinfo);
                    767:                RETURN_TRUE;
                    768:        } else {
                    769:                zend_error(E_WARNING, "Unable to find typeinfo using the parameters supplied");
                    770:        }
                    771:        RETURN_FALSE;
                    772: }
                    773: /* }}} */
                    774: 
                    775: /* {{{ proto bool com_message_pump([int timeoutms])
                    776:    Process COM messages, sleeping for up to timeoutms milliseconds */
                    777: PHP_FUNCTION(com_message_pump)
                    778: {
                    779:        long timeoutms = 0;
                    780:        MSG msg;
                    781:        DWORD result;
                    782:        
                    783:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timeoutms) == FAILURE)
                    784:                RETURN_FALSE;
                    785:        
                    786:        php_com_initialize(TSRMLS_C);
                    787:        result = MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutms, QS_ALLINPUT);
                    788: 
                    789:        if (result == WAIT_OBJECT_0) {
                    790:                while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
                    791:                        TranslateMessage(&msg);
                    792:                        DispatchMessage(&msg);
                    793:                }
                    794:                /* we processed messages */
                    795:                RETVAL_TRUE;
                    796:        } else {
                    797:                /* we did not process messages (timed out) */
                    798:                RETVAL_FALSE;
                    799:        }
                    800: }
                    801: /* }}} */
                    802: 
                    803: /* {{{ proto bool com_load_typelib(string typelib_name [, int case_insensitive]) 
                    804:    Loads a Typelibrary and registers its constants */
                    805: PHP_FUNCTION(com_load_typelib)
                    806: {
                    807:        char *name;
                    808:        int namelen;
                    809:        ITypeLib *pTL = NULL;
                    810:        zend_bool cs = TRUE;
                    811:        int codepage = COMG(code_page);
                    812:        int cached = 0;
                    813: 
                    814:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &name, &namelen, &cs)) {
                    815:                return;
                    816:        }
                    817: 
                    818:        RETVAL_FALSE;
                    819:        
                    820:        php_com_initialize(TSRMLS_C);
                    821:        pTL = php_com_load_typelib_via_cache(name, codepage, &cached TSRMLS_CC);
                    822:        if (pTL) {
                    823:                if (cached) {
                    824:                        RETVAL_TRUE;
                    825:                } else if (php_com_import_typelib(pTL, cs ? CONST_CS : 0, codepage TSRMLS_CC) == SUCCESS) {
                    826:                        RETVAL_TRUE;
                    827:                }
                    828: 
                    829:                ITypeLib_Release(pTL);
                    830:                pTL = NULL;
                    831:        }
                    832: }
                    833: /* }}} */
                    834: 
                    835: 
                    836: 
                    837: /*
                    838:  * Local variables:
                    839:  * tab-width: 4
                    840:  * c-basic-offset: 4
                    841:  * End:
                    842:  * vim600: noet sw=4 ts=4 fdm=marker
                    843:  * vim<600: noet sw=4 ts=4
                    844:  */

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