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>