root/ext/com_dotnet/com_com.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_FUNCTION
  2. PHP_FUNCTION
  3. php_com_invoke_helper
  4. php_com_get_id_of_name
  5. php_com_do_invoke_byref
  6. php_com_do_invoke_by_id
  7. php_com_do_invoke
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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 */
  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_win32_error_to_msg(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_win32_error_to_msg(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_win32_error_to_msg(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_win32_error_to_msg(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_win32_error_to_msg(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 && Z_TYPE_PP(tmp) == IS_STRING)
 702                         typelibname = Z_STRVAL_PP(tmp);
 703                 if (zend_hash_index_find(Z_ARRVAL_P(sink), 1, (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING)
 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  */

/* [<][>][^][v][top][bottom][index][help] */