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 */
PHP_FUNCTION(com_create_instance)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 */
PHP_FUNCTION(com_get_active_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 */
php_com_invoke_helper(php_com_dotnet_object * obj,DISPID id_member,WORD flags,DISPPARAMS * disp_params,VARIANT * v,int silent,int allow_noarg TSRMLS_DC)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 */
php_com_get_id_of_name(php_com_dotnet_object * obj,char * name,int namelen,DISPID * dispid TSRMLS_DC)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 */
php_com_do_invoke_byref(php_com_dotnet_object * obj,char * name,int namelen,WORD flags,VARIANT * v,int nargs,zval *** args TSRMLS_DC)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
php_com_do_invoke_by_id(php_com_dotnet_object * obj,DISPID dispid,WORD flags,VARIANT * v,int nargs,zval ** args,int silent,int allow_noarg TSRMLS_DC)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
php_com_do_invoke(php_com_dotnet_object * obj,char * name,int namelen,WORD flags,VARIANT * v,int nargs,zval ** args,int allow_noarg TSRMLS_DC)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) */
PHP_FUNCTION(com_create_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 */
PHP_FUNCTION(com_event_sink)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 */
PHP_FUNCTION(com_print_typeinfo)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 */
PHP_FUNCTION(com_message_pump)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 */
PHP_FUNCTION(com_load_typelib)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 */
845