1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 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$ */ 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 */ 33PHP_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 */ 287PHP_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 */ 340HRESULT 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 */ 418HRESULT 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 */ 464int 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 585int 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 632int 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) */ 656PHP_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 */ 679PHP_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 */ 740PHP_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 */ 777PHP_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 */ 805PHP_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 */ 845