1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "php.h"
24 #include "php_ini.h"
25 #include "ext/standard/info.h"
26 #include "php_com_dotnet.h"
27 #include "php_com_dotnet_internal.h"
28 #include "Zend/zend_exceptions.h"
29
30 /* {{{ com_create_instance - ctor for COM class */
PHP_FUNCTION(com_create_instance)31 PHP_FUNCTION(com_create_instance)
32 {
33 zval *object = getThis();
34 zval *server_params = NULL;
35 php_com_dotnet_object *obj;
36 char *module_name, *typelib_name = NULL, *server_name = NULL;
37 char *user_name = NULL, *domain_name = NULL, *password = NULL;
38 size_t module_name_len = 0, typelib_name_len = 0, server_name_len = 0,
39 user_name_len, domain_name_len, password_len;
40 OLECHAR *moniker;
41 CLSID clsid;
42 CLSCTX ctx = CLSCTX_SERVER;
43 HRESULT res = E_FAIL;
44 int mode = COMG(autoreg_case_sensitive) ? CONST_CS : 0;
45 ITypeLib *TL = NULL;
46 COSERVERINFO info;
47 COAUTHIDENTITY authid = {0};
48 COAUTHINFO authinfo = {
49 RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
50 RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE,
51 &authid, EOAC_NONE
52 };
53 zend_long cp = GetACP();
54 const struct php_win32_cp *cp_it;
55
56 php_com_initialize();
57 obj = CDNO_FETCH(object);
58
59 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
60 ZEND_NUM_ARGS(), "s|s!ls",
61 &module_name, &module_name_len, &server_name, &server_name_len,
62 &cp, &typelib_name, &typelib_name_len) &&
63 FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
64 ZEND_NUM_ARGS(), "sa/|ls",
65 &module_name, &module_name_len, &server_params, &cp,
66 &typelib_name, &typelib_name_len)) {
67
68 php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid arguments!");
69 return;
70 }
71
72 cp_it = php_win32_cp_get_by_id((DWORD)cp);
73 if (!cp_it) {
74 php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid codepage!");
75 return;
76 }
77 obj->code_page = (int)cp;
78
79 if (server_name) {
80 ctx = CLSCTX_REMOTE_SERVER;
81 } else if (server_params) {
82 zval *tmp;
83
84 /* decode the data from the array */
85
86 if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
87 "Server", sizeof("Server")-1))) {
88 convert_to_string_ex(tmp);
89 server_name = Z_STRVAL_P(tmp);
90 server_name_len = Z_STRLEN_P(tmp);
91 ctx = CLSCTX_REMOTE_SERVER;
92 }
93
94 if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
95 "Username", sizeof("Username")-1))) {
96 convert_to_string_ex(tmp);
97 user_name = Z_STRVAL_P(tmp);
98 user_name_len = Z_STRLEN_P(tmp);
99 }
100
101 if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
102 "Password", sizeof("Password")-1))) {
103 convert_to_string_ex(tmp);
104 password = Z_STRVAL_P(tmp);
105 password_len = Z_STRLEN_P(tmp);
106 }
107
108 if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
109 "Domain", sizeof("Domain")-1))) {
110 convert_to_string_ex(tmp);
111 domain_name = Z_STRVAL_P(tmp);
112 domain_name_len = Z_STRLEN_P(tmp);
113 }
114
115 if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
116 "Flags", sizeof("Flags")-1))) {
117 ctx = (CLSCTX)zval_get_long(tmp);
118 }
119 }
120
121 if (server_name && !COMG(allow_dcom)) {
122 php_com_throw_exception(E_ERROR, "DCOM has been disabled by your administrator [com.allow_dcom=0]");
123 return;
124 }
125
126 moniker = php_com_string_to_olestring(module_name, module_name_len, obj->code_page);
127
128 /* if instantiating a remote object, either directly, or via
129 * a moniker, fill in the relevant info */
130 if (server_name) {
131 info.dwReserved1 = 0;
132 info.dwReserved2 = 0;
133 info.pwszName = php_com_string_to_olestring(server_name, server_name_len, obj->code_page);
134
135 if (user_name) {
136 authid.User = (OLECHAR*)user_name;
137 authid.UserLength = (ULONG)user_name_len;
138
139 if (password) {
140 authid.Password = (OLECHAR*)password;
141 authid.PasswordLength = (ULONG)password_len;
142 } else {
143 authid.Password = (OLECHAR*)"";
144 authid.PasswordLength = 0;
145 }
146
147 if (domain_name) {
148 authid.Domain = (OLECHAR*)domain_name;
149 authid.DomainLength = (ULONG)domain_name_len;
150 } else {
151 authid.Domain = (OLECHAR*)"";
152 authid.DomainLength = 0;
153 }
154 authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
155 info.pAuthInfo = &authinfo;
156 } else {
157 info.pAuthInfo = NULL;
158 }
159 }
160
161 if (FAILED(CLSIDFromString(moniker, &clsid))) {
162 /* try to use it as a moniker */
163 IBindCtx *pBindCtx = NULL;
164 IMoniker *pMoniker = NULL;
165 ULONG ulEaten;
166 BIND_OPTS2 bopt = {0};
167
168 if (SUCCEEDED(res = CreateBindCtx(0, &pBindCtx))) {
169 if (server_name) {
170 /* fill in the remote server info.
171 * MSDN docs indicate that this might be ignored in
172 * current win32 implementations, but at least we are
173 * doing the right thing in readiness for the day that
174 * it does work */
175 bopt.cbStruct = sizeof(bopt);
176 IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
177 bopt.pServerInfo = &info;
178 /* apparently, GetBindOptions will only ever return
179 * a regular BIND_OPTS structure. My gut feeling is
180 * that it will modify the size field to reflect that
181 * so lets be safe and set it to the BIND_OPTS2 size
182 * again */
183 bopt.cbStruct = sizeof(bopt);
184 IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
185 }
186
187 if (SUCCEEDED(res = MkParseDisplayName(pBindCtx, moniker, &ulEaten, &pMoniker))) {
188 res = IMoniker_BindToObject(pMoniker, pBindCtx,
189 NULL, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
190
191 if (SUCCEEDED(res)) {
192 V_VT(&obj->v) = VT_DISPATCH;
193 }
194
195 IMoniker_Release(pMoniker);
196 }
197 }
198 if (pBindCtx) {
199 IBindCtx_Release(pBindCtx);
200 }
201 } else if (server_name) {
202 MULTI_QI qi;
203
204 qi.pIID = &IID_IDispatch;
205 qi.pItf = NULL;
206 qi.hr = S_OK;
207
208 res = CoCreateInstanceEx(&clsid, NULL, ctx, &info, 1, &qi);
209
210 if (SUCCEEDED(res)) {
211 res = qi.hr;
212 V_DISPATCH(&obj->v) = (IDispatch*)qi.pItf;
213 V_VT(&obj->v) = VT_DISPATCH;
214 }
215 } else {
216 res = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
217 if (SUCCEEDED(res)) {
218 V_VT(&obj->v) = VT_DISPATCH;
219 }
220 }
221
222 if (server_name) {
223 if (info.pwszName) efree(info.pwszName);
224 }
225
226 efree(moniker);
227
228 if (FAILED(res)) {
229 char *werr, *msg;
230
231 werr = php_win32_error_to_msg(res);
232 spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, werr);
233 LocalFree(werr);
234
235 php_com_throw_exception(res, msg);
236 efree(msg);
237 return;
238 }
239
240 /* we got the object and it lives ! */
241
242 /* see if it has TypeInfo available */
243 if (FAILED(IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo)) && typelib_name) {
244 /* load up the library from the named file */
245 int cached;
246
247 TL = php_com_load_typelib_via_cache(typelib_name, obj->code_page, &cached);
248
249 if (TL) {
250 if (COMG(autoreg_on)) {
251 php_com_import_typelib(TL, mode, obj->code_page);
252 }
253
254 /* cross your fingers... there is no guarantee that this ITypeInfo
255 * instance has any relation to this IDispatch instance... */
256 ITypeLib_GetTypeInfo(TL, 0, &obj->typeinfo);
257 ITypeLib_Release(TL);
258 }
259 } else if (obj->typeinfo && COMG(autoreg_on)) {
260 UINT idx;
261
262 if (SUCCEEDED(ITypeInfo_GetContainingTypeLib(obj->typeinfo, &TL, &idx))) {
263 /* check if the library is already in the cache by getting its name */
264 BSTR name;
265
266 if (SUCCEEDED(ITypeLib_GetDocumentation(TL, -1, &name, NULL, NULL, NULL))) {
267 typelib_name = php_com_olestring_to_string(name, &typelib_name_len, obj->code_page);
268
269 if (NULL != zend_ts_hash_str_add_ptr(&php_com_typelibraries, typelib_name, typelib_name_len, TL)) {
270 php_com_import_typelib(TL, mode, obj->code_page);
271
272 /* add a reference for the hash */
273 ITypeLib_AddRef(TL);
274 }
275
276 } else {
277 /* try it anyway */
278 php_com_import_typelib(TL, mode, obj->code_page);
279 }
280
281 ITypeLib_Release(TL);
282 }
283 }
284
285 }
286 /* }}} */
287
288 /* {{{ proto object com_get_active_object(string progid [, int code_page ])
289 Returns a handle to an already running instance of a COM object */
PHP_FUNCTION(com_get_active_object)290 PHP_FUNCTION(com_get_active_object)
291 {
292 CLSID clsid;
293 char *module_name;
294 size_t module_name_len;
295 zend_long code_page = COMG(code_page);
296 IUnknown *unk = NULL;
297 IDispatch *obj = NULL;
298 HRESULT res;
299 OLECHAR *module = NULL;
300
301 php_com_initialize();
302 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l",
303 &module_name, &module_name_len, &code_page)) {
304 php_com_throw_exception(E_INVALIDARG, "Invalid arguments!");
305 return;
306 }
307
308 module = php_com_string_to_olestring(module_name, module_name_len, (int)code_page);
309
310 res = CLSIDFromString(module, &clsid);
311
312 if (FAILED(res)) {
313 php_com_throw_exception(res, NULL);
314 } else {
315 res = GetActiveObject(&clsid, NULL, &unk);
316
317 if (FAILED(res)) {
318 php_com_throw_exception(res, NULL);
319 } else {
320 res = IUnknown_QueryInterface(unk, &IID_IDispatch, &obj);
321
322 if (FAILED(res)) {
323 php_com_throw_exception(res, NULL);
324 } else if (obj) {
325 /* we got our dispatchable object */
326 php_com_wrap_dispatch(return_value, obj, (int)code_page);
327 }
328 }
329 }
330
331 if (obj) {
332 IDispatch_Release(obj);
333 }
334 if (unk) {
335 IUnknown_Release(obj);
336 }
337 efree(module);
338 }
339 /* }}} */
340
341 /* Performs an Invoke on the given com object.
342 * 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)343 HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
344 WORD flags, DISPPARAMS *disp_params, VARIANT *v, int silent, int allow_noarg)
345 {
346 HRESULT hr;
347 unsigned int arg_err;
348 EXCEPINFO e = {0};
349
350 hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
351 &IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, v, &e, &arg_err);
352
353 if (silent == 0 && FAILED(hr)) {
354 char *source = NULL, *desc = NULL, *msg = NULL;
355 size_t source_len, desc_len;
356
357 switch (hr) {
358 case DISP_E_EXCEPTION:
359 if (e.bstrSource) {
360 source = php_com_olestring_to_string(e.bstrSource, &source_len, obj->code_page);
361 SysFreeString(e.bstrSource);
362 }
363 if (e.bstrDescription) {
364 desc = php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page);
365 SysFreeString(e.bstrDescription);
366 }
367 if (PG(html_errors)) {
368 spprintf(&msg, 0, "<b>Source:</b> %s<br/><b>Description:</b> %s",
369 source ? source : "Unknown",
370 desc ? desc : "Unknown");
371 } else {
372 spprintf(&msg, 0, "Source: %s\nDescription: %s",
373 source ? source : "Unknown",
374 desc ? desc : "Unknown");
375 }
376 if (desc) {
377 efree(desc);
378 }
379 if (source) {
380 efree(source);
381 }
382 if (e.bstrHelpFile) {
383 SysFreeString(e.bstrHelpFile);
384 }
385 break;
386
387 case DISP_E_PARAMNOTFOUND:
388 case DISP_E_TYPEMISMATCH:
389 desc = php_win32_error_to_msg(hr);
390 spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
391 LocalFree(desc);
392 break;
393
394 case DISP_E_BADPARAMCOUNT:
395 if ((disp_params->cArgs + disp_params->cNamedArgs == 0) && (allow_noarg == 1)) {
396 /* if getting a property and they are missing all parameters,
397 * we want to create a proxy object for them; so lets not create an
398 * exception here */
399 msg = NULL;
400 break;
401 }
402 /* else fall through */
403
404 default:
405 desc = php_win32_error_to_msg(hr);
406 spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
407 LocalFree(desc);
408 break;
409 }
410
411 if (msg) {
412 php_com_throw_exception(hr, msg);
413 efree(msg);
414 }
415 }
416
417 return hr;
418 }
419
420 /* map an ID to a name */
php_com_get_id_of_name(php_com_dotnet_object * obj,char * name,size_t namelen,DISPID * dispid)421 HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
422 size_t namelen, DISPID *dispid)
423 {
424 OLECHAR *olename;
425 HRESULT hr;
426 zval *tmp;
427
428 if (namelen == -1) {
429 namelen = strlen(name);
430 }
431
432 if (obj->id_of_name_cache && NULL != (tmp = zend_hash_str_find(obj->id_of_name_cache, name, namelen))) {
433 *dispid = (DISPID)Z_LVAL_P(tmp);
434 return S_OK;
435 }
436
437 olename = php_com_string_to_olestring(name, namelen, obj->code_page);
438
439 if (obj->typeinfo) {
440 hr = ITypeInfo_GetIDsOfNames(obj->typeinfo, &olename, 1, dispid);
441 if (FAILED(hr)) {
442 HRESULT hr1 = hr;
443 hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
444 if (SUCCEEDED(hr) && hr1 != E_NOTIMPL) {
445 /* fall back on IDispatch direct */
446 ITypeInfo_Release(obj->typeinfo);
447 obj->typeinfo = NULL;
448 }
449 }
450 } else {
451 hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
452 }
453 efree(olename);
454
455 if (SUCCEEDED(hr)) {
456 zval tmp;
457
458 /* cache the mapping */
459 if (!obj->id_of_name_cache) {
460 ALLOC_HASHTABLE(obj->id_of_name_cache);
461 zend_hash_init(obj->id_of_name_cache, 2, NULL, NULL, 0);
462 }
463 ZVAL_LONG(&tmp, *dispid);
464 zend_hash_str_update(obj->id_of_name_cache, name, namelen, &tmp);
465 }
466
467 return hr;
468 }
469
470 /* the core of COM */
php_com_do_invoke_byref(php_com_dotnet_object * obj,zend_internal_function * f,WORD flags,VARIANT * v,int nargs,zval * args)471 int php_com_do_invoke_byref(php_com_dotnet_object *obj, zend_internal_function *f,
472 WORD flags, VARIANT *v, int nargs, zval *args)
473 {
474 DISPID dispid, altdispid;
475 DISPPARAMS disp_params;
476 HRESULT hr;
477 VARIANT *vargs = NULL, *byref_vals = NULL;
478 int i, byref_count = 0, j;
479
480 /* assumption: that the active function (f) is the function we generated for the engine */
481 if (!f) {
482 return FAILURE;
483 }
484
485 hr = php_com_get_id_of_name(obj, f->function_name->val, f->function_name->len, &dispid);
486
487 if (FAILED(hr)) {
488 char *winerr = NULL;
489 char *msg = NULL;
490 winerr = php_win32_error_to_msg(hr);
491 spprintf(&msg, 0, "Unable to lookup `%s': %s", f->function_name->val, winerr);
492 LocalFree(winerr);
493 php_com_throw_exception(hr, msg);
494 efree(msg);
495 return FAILURE;
496 }
497
498
499 if (nargs) {
500 vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
501 }
502
503 if (f->arg_info) {
504 for (i = 0; i < nargs; i++) {
505 if (f->arg_info[nargs - i - 1].pass_by_reference) {
506 byref_count++;
507 }
508 }
509 }
510
511 if (byref_count) {
512 byref_vals = (VARIANT*)safe_emalloc(sizeof(VARIANT), byref_count, 0);
513 for (j = 0, i = 0; i < nargs; i++) {
514 if (f->arg_info[nargs - i - 1].pass_by_reference) {
515 /* put the value into byref_vals instead */
516 php_com_variant_from_zval(&byref_vals[j], &args[nargs - i - 1], obj->code_page);
517
518 /* if it is already byref, "move" it into the vargs array, otherwise
519 * make vargs a reference to this value */
520 if (V_VT(&byref_vals[j]) & VT_BYREF) {
521 memcpy(&vargs[i], &byref_vals[j], sizeof(vargs[i]));
522 VariantInit(&byref_vals[j]); /* leave the variant slot empty to simplify cleanup */
523 } else {
524 VariantInit(&vargs[i]);
525 V_VT(&vargs[i]) = V_VT(&byref_vals[j]) | VT_BYREF;
526 /* union magic ensures that this works out */
527 vargs[i].byref = &V_UINT(&byref_vals[j]);
528 }
529 j++;
530 } else {
531 php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
532 }
533 }
534
535 } else {
536 /* Invoke'd args are in reverse order */
537 for (i = 0; i < nargs; i++) {
538 php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
539 }
540 }
541
542 disp_params.cArgs = nargs;
543 disp_params.cNamedArgs = 0;
544 disp_params.rgvarg = vargs;
545 disp_params.rgdispidNamedArgs = NULL;
546
547 if (flags & DISPATCH_PROPERTYPUT) {
548 altdispid = DISPID_PROPERTYPUT;
549 disp_params.rgdispidNamedArgs = &altdispid;
550 disp_params.cNamedArgs = 1;
551 }
552
553 /* this will create an exception if needed */
554 hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, 0, 0);
555
556 /* release variants */
557 if (vargs) {
558 if (f && f->arg_info) {
559 for (i = 0, j = 0; i < nargs; i++) {
560 /* if this was byref, update the zval */
561 if (f->arg_info[nargs - i - 1].pass_by_reference) {
562 zval *arg = &args[nargs - i - 1];
563
564 ZVAL_DEREF(arg);
565 zval_ptr_dtor(arg);
566 ZVAL_NULL(arg);
567
568 /* if the variant is pointing at the byref_vals, we need to map
569 * the pointee value as a zval; otherwise, the value is pointing
570 * into an existing PHP variant record */
571 if (V_VT(&vargs[i]) & VT_BYREF) {
572 if (vargs[i].byref == &V_UINT(&byref_vals[j])) {
573 /* copy that value */
574 php_com_zval_from_variant(arg, &byref_vals[j], obj->code_page);
575 }
576 } else {
577 /* not sure if this can ever happen; the variant we marked as BYREF
578 * is no longer BYREF - copy its value */
579 php_com_zval_from_variant(arg, &vargs[i], obj->code_page);
580 }
581 VariantClear(&byref_vals[j]);
582 j++;
583 }
584 VariantClear(&vargs[i]);
585 }
586 } else {
587 for (i = 0, j = 0; i < nargs; i++) {
588 VariantClear(&vargs[i]);
589 }
590 }
591 efree(vargs);
592 if (byref_vals) efree(byref_vals);
593 }
594
595 return SUCCEEDED(hr) ? SUCCESS : FAILURE;
596 }
597
598
599
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)600 int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
601 WORD flags, VARIANT *v, int nargs, zval *args, int silent, int allow_noarg)
602 {
603 DISPID altdispid;
604 DISPPARAMS disp_params;
605 HRESULT hr;
606 VARIANT *vargs = NULL;
607 int i;
608
609 if (nargs) {
610 vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
611 }
612
613 /* Invoke'd args are in reverse order */
614 for (i = 0; i < nargs; i++) {
615 php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
616 }
617
618 disp_params.cArgs = nargs;
619 disp_params.cNamedArgs = 0;
620 disp_params.rgvarg = vargs;
621 disp_params.rgdispidNamedArgs = NULL;
622
623 if (flags & DISPATCH_PROPERTYPUT) {
624 altdispid = DISPID_PROPERTYPUT;
625 disp_params.rgdispidNamedArgs = &altdispid;
626 disp_params.cNamedArgs = 1;
627 }
628
629 /* this will create an exception if needed */
630 hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, silent, allow_noarg);
631
632 /* release variants */
633 if (vargs) {
634 for (i = 0; i < nargs; i++) {
635 VariantClear(&vargs[i]);
636 }
637 efree(vargs);
638 }
639
640 /* a bit of a hack this, but it's needed for COM array access. */
641 if (hr == DISP_E_BADPARAMCOUNT)
642 return hr;
643
644 return SUCCEEDED(hr) ? SUCCESS : FAILURE;
645 }
646
php_com_do_invoke(php_com_dotnet_object * obj,char * name,size_t namelen,WORD flags,VARIANT * v,int nargs,zval * args,int allow_noarg)647 int php_com_do_invoke(php_com_dotnet_object *obj, char *name, size_t namelen,
648 WORD flags, VARIANT *v, int nargs, zval *args, int allow_noarg)
649 {
650 DISPID dispid;
651 HRESULT hr;
652 char *winerr = NULL;
653 char *msg = NULL;
654
655 hr = php_com_get_id_of_name(obj, name, namelen, &dispid);
656
657 if (FAILED(hr)) {
658 winerr = php_win32_error_to_msg(hr);
659 spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
660 LocalFree(winerr);
661 php_com_throw_exception(hr, msg);
662 efree(msg);
663 return FAILURE;
664 }
665
666 return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args, 0, allow_noarg);
667 }
668
669 /* {{{ proto string com_create_guid()
670 Generate a globally unique identifier (GUID) */
PHP_FUNCTION(com_create_guid)671 PHP_FUNCTION(com_create_guid)
672 {
673 GUID retval;
674 OLECHAR *guid_string;
675
676 if (zend_parse_parameters_none() == FAILURE) {
677 return;
678 }
679
680 php_com_initialize();
681 if (CoCreateGuid(&retval) == S_OK && StringFromCLSID(&retval, &guid_string) == S_OK) {
682 size_t len;
683 char *str;
684
685 str = php_com_olestring_to_string(guid_string, &len, CP_ACP);
686 RETVAL_STRINGL(str, len);
687 // TODO: avoid reallocation ???
688 efree(str);
689
690 CoTaskMemFree(guid_string);
691 } else {
692 RETURN_FALSE;
693 }
694 }
695 /* }}} */
696
697 /* {{{ proto bool com_event_sink(object comobject, object sinkobject [, mixed sinkinterface])
698 Connect events from a COM object to a PHP object */
PHP_FUNCTION(com_event_sink)699 PHP_FUNCTION(com_event_sink)
700 {
701 zval *object, *sinkobject, *sink=NULL;
702 char *dispname = NULL, *typelibname = NULL;
703 php_com_dotnet_object *obj;
704 ITypeInfo *typeinfo = NULL;
705
706 RETVAL_FALSE;
707
708 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Oo|z/",
709 &object, php_com_variant_class_entry, &sinkobject, &sink)) {
710 RETURN_FALSE;
711 }
712
713 php_com_initialize();
714 obj = CDNO_FETCH(object);
715
716 if (sink && Z_TYPE_P(sink) == IS_ARRAY) {
717 /* 0 => typelibname, 1 => dispname */
718 zval *tmp;
719
720 if ((tmp = zend_hash_index_find(Z_ARRVAL_P(sink), 0)) != NULL && Z_TYPE_P(tmp) == IS_STRING)
721 typelibname = Z_STRVAL_P(tmp);
722 if ((tmp = zend_hash_index_find(Z_ARRVAL_P(sink), 1)) != NULL && Z_TYPE_P(tmp) == IS_STRING)
723 dispname = Z_STRVAL_P(tmp);
724 } else if (sink != NULL) {
725 convert_to_string(sink);
726 dispname = Z_STRVAL_P(sink);
727 }
728
729 typeinfo = php_com_locate_typeinfo(typelibname, obj, dispname, 1);
730
731 if (typeinfo) {
732 HashTable *id_to_name;
733
734 ALLOC_HASHTABLE(id_to_name);
735
736 if (php_com_process_typeinfo(typeinfo, id_to_name, 0, &obj->sink_id, obj->code_page)) {
737
738 /* Create the COM wrapper for this sink */
739 obj->sink_dispatch = php_com_wrapper_export_as_sink(sinkobject, &obj->sink_id, id_to_name);
740
741 /* Now hook it up to the source */
742 php_com_object_enable_event_sink(obj, TRUE);
743 RETVAL_TRUE;
744
745 } else {
746 FREE_HASHTABLE(id_to_name);
747 }
748 }
749
750 if (typeinfo) {
751 ITypeInfo_Release(typeinfo);
752 }
753
754 }
755 /* }}} */
756
757 /* {{{ proto bool com_print_typeinfo(object comobject | string typelib, string dispinterface, bool wantsink)
758 Print out a PHP class definition for a dispatchable interface */
PHP_FUNCTION(com_print_typeinfo)759 PHP_FUNCTION(com_print_typeinfo)
760 {
761 zval *arg1;
762 char *ifacename = NULL;
763 char *typelibname = NULL;
764 size_t ifacelen;
765 zend_bool wantsink = 0;
766 php_com_dotnet_object *obj = NULL;
767 ITypeInfo *typeinfo;
768
769 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "z/|s!b", &arg1, &ifacename,
770 &ifacelen, &wantsink)) {
771 RETURN_FALSE;
772 }
773
774 php_com_initialize();
775 if (Z_TYPE_P(arg1) == IS_OBJECT) {
776 CDNO_FETCH_VERIFY(obj, arg1);
777 } else {
778 convert_to_string(arg1);
779 typelibname = Z_STRVAL_P(arg1);
780 }
781
782 typeinfo = php_com_locate_typeinfo(typelibname, obj, ifacename, wantsink ? 1 : 0);
783 if (typeinfo) {
784 php_com_process_typeinfo(typeinfo, NULL, 1, NULL, obj ? obj->code_page : COMG(code_page));
785 ITypeInfo_Release(typeinfo);
786 RETURN_TRUE;
787 } else {
788 zend_error(E_WARNING, "Unable to find typeinfo using the parameters supplied");
789 }
790 RETURN_FALSE;
791 }
792 /* }}} */
793
794 /* {{{ proto bool com_message_pump([int timeoutms])
795 Process COM messages, sleeping for up to timeoutms milliseconds */
PHP_FUNCTION(com_message_pump)796 PHP_FUNCTION(com_message_pump)
797 {
798 zend_long timeoutms = 0;
799 MSG msg;
800 DWORD result;
801
802 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &timeoutms) == FAILURE)
803 RETURN_FALSE;
804
805 php_com_initialize();
806 result = MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)timeoutms, QS_ALLINPUT);
807
808 if (result == WAIT_OBJECT_0) {
809 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
810 TranslateMessage(&msg);
811 DispatchMessage(&msg);
812 }
813 /* we processed messages */
814 RETVAL_TRUE;
815 } else {
816 /* we did not process messages (timed out) */
817 RETVAL_FALSE;
818 }
819 }
820 /* }}} */
821
822 /* {{{ proto bool com_load_typelib(string typelib_name [, bool case_insensitive])
823 Loads a Typelibrary and registers its constants */
PHP_FUNCTION(com_load_typelib)824 PHP_FUNCTION(com_load_typelib)
825 {
826 char *name;
827 size_t namelen;
828 ITypeLib *pTL = NULL;
829 zend_bool cs = TRUE;
830 int codepage = COMG(code_page);
831 int cached = 0;
832
833 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &name, &namelen, &cs)) {
834 return;
835 }
836
837 RETVAL_FALSE;
838
839 php_com_initialize();
840 pTL = php_com_load_typelib_via_cache(name, codepage, &cached);
841 if (pTL) {
842 if (php_com_import_typelib(pTL, cs ? CONST_CS : 0, codepage) == SUCCESS) {
843 RETVAL_TRUE;
844 }
845
846 ITypeLib_Release(pTL);
847 pTL = NULL;
848 }
849 }
850 /* }}} */
851
852
853
854 /*
855 * Local variables:
856 * tab-width: 4
857 * c-basic-offset: 4
858 * End:
859 * vim600: noet sw=4 ts=4 fdm=marker
860 * vim<600: noet sw=4 ts=4
861 */
862