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

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 3.01 of the PHP license,      |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.php.net/license/3_01.txt                                  |
        !            11:    | If you did not receive a copy of the PHP license and are unable to   |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@php.net so we can mail you a copy immediately.               |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Author: Wez Furlong  <wez@thebrainroom.com>                          |
        !            16:    +----------------------------------------------------------------------+
        !            17:  */
        !            18: 
        !            19: /* $Id: com_com.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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: 
        !           227:                werr = php_win_err(res);
        !           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:
        !           386:                                desc = php_win_err(hr);
        !           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:
        !           402:                                desc = php_win_err(hr);
        !           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;
        !           484:                winerr = php_win_err(hr);
        !           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)) {
        !           643:                winerr = php_win_err(hr);
        !           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>