Annotation of embedaddon/php/ext/com_dotnet/com_com.c, revision 1.1.1.2
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 The PHP Group |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Author: Wez Furlong <wez@thebrainroom.com> |
16: +----------------------------------------------------------------------+
17: */
18:
1.1.1.2 ! misho 19: /* $Id$ */
1.1 misho 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:
1.1.1.2 ! misho 227: werr = php_win32_error_to_msg(res);
1.1 misho 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:
1.1.1.2 ! misho 386: desc = php_win32_error_to_msg(hr);
1.1 misho 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:
1.1.1.2 ! misho 402: desc = php_win32_error_to_msg(hr);
1.1 misho 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;
1.1.1.2 ! misho 484: winerr = php_win32_error_to_msg(hr);
1.1 misho 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)) {
1.1.1.2 ! misho 643: winerr = php_win32_error_to_msg(hr);
1.1 misho 644: spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
645: LocalFree(winerr);
646: php_com_throw_exception(hr, msg TSRMLS_CC);
647: efree(msg);
648: return FAILURE;
649: }
650:
651: return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args, 0, allow_noarg TSRMLS_CC);
652: }
653:
654: /* {{{ proto string com_create_guid()
655: Generate a globally unique identifier (GUID) */
656: PHP_FUNCTION(com_create_guid)
657: {
658: GUID retval;
659: OLECHAR *guid_string;
660:
661: if (zend_parse_parameters_none() == FAILURE) {
662: return;
663: }
664:
665: php_com_initialize(TSRMLS_C);
666: if (CoCreateGuid(&retval) == S_OK && StringFromCLSID(&retval, &guid_string) == S_OK) {
667: Z_TYPE_P(return_value) = IS_STRING;
668: Z_STRVAL_P(return_value) = php_com_olestring_to_string(guid_string, &Z_STRLEN_P(return_value), CP_ACP TSRMLS_CC);
669:
670: CoTaskMemFree(guid_string);
671: } else {
672: RETURN_FALSE;
673: }
674: }
675: /* }}} */
676:
677: /* {{{ proto bool com_event_sink(object comobject, object sinkobject [, mixed sinkinterface])
678: Connect events from a COM object to a PHP object */
679: PHP_FUNCTION(com_event_sink)
680: {
681: zval *object, *sinkobject, *sink=NULL;
682: char *dispname = NULL, *typelibname = NULL;
683: zend_bool gotguid = 0;
684: php_com_dotnet_object *obj;
685: ITypeInfo *typeinfo = NULL;
686:
687: RETVAL_FALSE;
688:
689: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oo|z/",
690: &object, php_com_variant_class_entry, &sinkobject, &sink)) {
691: RETURN_FALSE;
692: }
693:
694: php_com_initialize(TSRMLS_C);
695: obj = CDNO_FETCH(object);
696:
697: if (sink && Z_TYPE_P(sink) == IS_ARRAY) {
698: /* 0 => typelibname, 1 => dispname */
699: zval **tmp;
700:
701: if (zend_hash_index_find(Z_ARRVAL_P(sink), 0, (void**)&tmp) == SUCCESS)
702: typelibname = Z_STRVAL_PP(tmp);
703: if (zend_hash_index_find(Z_ARRVAL_P(sink), 1, (void**)&tmp) == SUCCESS)
704: dispname = Z_STRVAL_PP(tmp);
705: } else if (sink != NULL) {
706: convert_to_string(sink);
707: dispname = Z_STRVAL_P(sink);
708: }
709:
710: typeinfo = php_com_locate_typeinfo(typelibname, obj, dispname, 1 TSRMLS_CC);
711:
712: if (typeinfo) {
713: HashTable *id_to_name;
714:
715: ALLOC_HASHTABLE(id_to_name);
716:
717: if (php_com_process_typeinfo(typeinfo, id_to_name, 0, &obj->sink_id, obj->code_page TSRMLS_CC)) {
718:
719: /* Create the COM wrapper for this sink */
720: obj->sink_dispatch = php_com_wrapper_export_as_sink(sinkobject, &obj->sink_id, id_to_name TSRMLS_CC);
721:
722: /* Now hook it up to the source */
723: php_com_object_enable_event_sink(obj, TRUE TSRMLS_CC);
724: RETVAL_TRUE;
725:
726: } else {
727: FREE_HASHTABLE(id_to_name);
728: }
729: }
730:
731: if (typeinfo) {
732: ITypeInfo_Release(typeinfo);
733: }
734:
735: }
736: /* }}} */
737:
738: /* {{{ proto bool com_print_typeinfo(object comobject | string typelib, string dispinterface, bool wantsink)
739: Print out a PHP class definition for a dispatchable interface */
740: PHP_FUNCTION(com_print_typeinfo)
741: {
742: zval *arg1;
743: char *ifacename = NULL;
744: char *typelibname = NULL;
745: int ifacelen;
746: zend_bool wantsink = 0;
747: php_com_dotnet_object *obj = NULL;
748: ITypeInfo *typeinfo;
749:
750: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|s!b", &arg1, &ifacename,
751: &ifacelen, &wantsink)) {
752: RETURN_FALSE;
753: }
754:
755: php_com_initialize(TSRMLS_C);
756: if (Z_TYPE_P(arg1) == IS_OBJECT) {
757: CDNO_FETCH_VERIFY(obj, arg1);
758: } else {
759: convert_to_string(arg1);
760: typelibname = Z_STRVAL_P(arg1);
761: }
762:
763: typeinfo = php_com_locate_typeinfo(typelibname, obj, ifacename, wantsink ? 1 : 0 TSRMLS_CC);
764: if (typeinfo) {
765: php_com_process_typeinfo(typeinfo, NULL, 1, NULL, obj ? obj->code_page : COMG(code_page) TSRMLS_CC);
766: ITypeInfo_Release(typeinfo);
767: RETURN_TRUE;
768: } else {
769: zend_error(E_WARNING, "Unable to find typeinfo using the parameters supplied");
770: }
771: RETURN_FALSE;
772: }
773: /* }}} */
774:
775: /* {{{ proto bool com_message_pump([int timeoutms])
776: Process COM messages, sleeping for up to timeoutms milliseconds */
777: PHP_FUNCTION(com_message_pump)
778: {
779: long timeoutms = 0;
780: MSG msg;
781: DWORD result;
782:
783: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timeoutms) == FAILURE)
784: RETURN_FALSE;
785:
786: php_com_initialize(TSRMLS_C);
787: result = MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutms, QS_ALLINPUT);
788:
789: if (result == WAIT_OBJECT_0) {
790: while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
791: TranslateMessage(&msg);
792: DispatchMessage(&msg);
793: }
794: /* we processed messages */
795: RETVAL_TRUE;
796: } else {
797: /* we did not process messages (timed out) */
798: RETVAL_FALSE;
799: }
800: }
801: /* }}} */
802:
803: /* {{{ proto bool com_load_typelib(string typelib_name [, int case_insensitive])
804: Loads a Typelibrary and registers its constants */
805: PHP_FUNCTION(com_load_typelib)
806: {
807: char *name;
808: int namelen;
809: ITypeLib *pTL = NULL;
810: zend_bool cs = TRUE;
811: int codepage = COMG(code_page);
812: int cached = 0;
813:
814: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &name, &namelen, &cs)) {
815: return;
816: }
817:
818: RETVAL_FALSE;
819:
820: php_com_initialize(TSRMLS_C);
821: pTL = php_com_load_typelib_via_cache(name, codepage, &cached TSRMLS_CC);
822: if (pTL) {
823: if (cached) {
824: RETVAL_TRUE;
825: } else if (php_com_import_typelib(pTL, cs ? CONST_CS : 0, codepage TSRMLS_CC) == SUCCESS) {
826: RETVAL_TRUE;
827: }
828:
829: ITypeLib_Release(pTL);
830: pTL = NULL;
831: }
832: }
833: /* }}} */
834:
835:
836:
837: /*
838: * Local variables:
839: * tab-width: 4
840: * c-basic-offset: 4
841: * End:
842: * vim600: noet sw=4 ts=4 fdm=marker
843: * vim<600: noet sw=4 ts=4
844: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>