Return to com_com.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / com_dotnet |
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: */