Return to com_typeinfo.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / com_dotnet |
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.4 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 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: | Harald Radi <h.radi@nme.at> |
17: +----------------------------------------------------------------------+
18: */
19:
1.1.1.2 misho 20: /* $Id$ */
1.1 misho 21:
22: #ifdef HAVE_CONFIG_H
23: #include "config.h"
24: #endif
25:
26: #include "php.h"
27: #include "php_ini.h"
28: #include "ext/standard/info.h"
29: #include "php_com_dotnet.h"
30: #include "php_com_dotnet_internal.h"
31:
32:
33: /* The search string can be either:
34: * a) a file name
35: * b) a CLSID, major, minor e.g. "{00000200-0000-0010-8000-00AA006D2EA4},2,0"
36: * c) a Type Library name e.g. "Microsoft OLE DB ActiveX Data Objects 1.0 Library"
37: */
1.1.1.3 misho 38: PHP_COM_DOTNET_API ITypeLib *php_com_load_typelib(char *search_string, int codepage TSRMLS_DC)
1.1 misho 39: {
40: ITypeLib *TL = NULL;
41: char *strtok_buf, *major, *minor;
42: CLSID clsid;
43: OLECHAR *p;
44: HRESULT hr;
45:
46: search_string = php_strtok_r(search_string, ",", &strtok_buf);
47:
48: if (search_string == NULL) {
49: return NULL;
50: }
51:
52: major = php_strtok_r(NULL, ",", &strtok_buf);
53: minor = php_strtok_r(NULL, ",", &strtok_buf);
54:
55: p = php_com_string_to_olestring(search_string, strlen(search_string), codepage TSRMLS_CC);
56:
57: if (SUCCEEDED(CLSIDFromString(p, &clsid))) {
58: WORD major_i = 1, minor_i = 0;
59:
60: /* pick up the major/minor numbers; if none specified, default to 1,0 */
61: if (major && minor) {
62: major_i = (WORD)atoi(major);
63: minor_i = (WORD)atoi(minor);
64: }
65:
66: /* Load the TypeLib by GUID */
67: hr = LoadRegTypeLib((REFGUID)&clsid, major_i, minor_i, LANG_NEUTRAL, &TL);
68:
69: /* if that failed, assumed that the GUID is actually a CLSID and
70: * attemp to get the library via an instance of that class */
71: if (FAILED(hr) && (major == NULL || minor == NULL)) {
72: IDispatch *disp = NULL;
73: ITypeInfo *info = NULL;
74: int idx;
75:
76: if (SUCCEEDED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID*)&disp)) &&
77: SUCCEEDED(hr = IDispatch_GetTypeInfo(disp, 0, LANG_NEUTRAL, &info))) {
78: hr = ITypeInfo_GetContainingTypeLib(info, &TL, &idx);
79: }
80:
81: if (info) {
82: ITypeInfo_Release(info);
83: }
84: if (disp) {
85: IDispatch_Release(disp);
86: }
87: }
88: } else {
89: /* Try to load it from a file; if it fails, do a really painful search of
90: * the registry */
91: if (FAILED(LoadTypeLib(p, &TL))) {
92: HKEY hkey, hsubkey;
93: DWORD SubKeys, MaxSubKeyLength;
94: char *keyname;
95: unsigned int i, j;
96: DWORD VersionCount;
97: char version[20];
98: char *libname;
99: DWORD libnamelen;
100:
101: if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, "TypeLib", 0, KEY_READ, &hkey) &&
102: ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, NULL, NULL, &SubKeys,
103: &MaxSubKeyLength, NULL, NULL, NULL, NULL, NULL, NULL)) {
104:
105: MaxSubKeyLength++; /* make room for NUL */
106: keyname = emalloc(MaxSubKeyLength);
107: libname = emalloc(strlen(search_string) + 1);
108:
109: for (i = 0; i < SubKeys && TL == NULL; i++) {
110: if (ERROR_SUCCESS == RegEnumKey(hkey, i, keyname, MaxSubKeyLength) &&
111: ERROR_SUCCESS == RegOpenKeyEx(hkey, keyname, 0, KEY_READ, &hsubkey)) {
112: if (ERROR_SUCCESS == RegQueryInfoKey(hsubkey, NULL, NULL, NULL, &VersionCount,
113: NULL, NULL, NULL, NULL, NULL, NULL, NULL)) {
114: for (j = 0; j < VersionCount; j++) {
115: if (ERROR_SUCCESS != RegEnumKey(hsubkey, j, version, sizeof(version))) {
116: continue;
117: }
118: /* get the default value for this key and compare */
119: libnamelen = strlen(search_string)+1;
120: if (ERROR_SUCCESS == RegQueryValue(hsubkey, version, libname, &libnamelen)) {
121: if (0 == stricmp(libname, search_string)) {
122: char *str = NULL;
123: int major_tmp, minor_tmp;
124:
125: /* fetch the GUID and add the version numbers */
126: if (2 != sscanf(version, "%d.%d", &major_tmp, &minor_tmp)) {
127: major_tmp = 1;
128: minor_tmp = 0;
129: }
130: spprintf(&str, 0, "%s,%d,%d", keyname, major_tmp, minor_tmp);
131: /* recurse */
132: TL = php_com_load_typelib(str, codepage TSRMLS_CC);
133:
134: efree(str);
135: break;
136: }
137: }
138: }
139: }
140: RegCloseKey(hsubkey);
141: }
142: }
143: RegCloseKey(hkey);
144: efree(keyname);
145: efree(libname);
146: }
147: }
148: }
149:
150: efree(p);
151:
152: return TL;
153: }
154:
155: /* Given a type-library, merge it into the current engine state */
1.1.1.3 misho 156: PHP_COM_DOTNET_API int php_com_import_typelib(ITypeLib *TL, int mode, int codepage TSRMLS_DC)
1.1 misho 157: {
158: int i, j, interfaces;
159: TYPEKIND pTKind;
160: ITypeInfo *TypeInfo;
161: VARDESC *pVarDesc;
162: UINT NameCount;
163: BSTR bstr_ids;
164: zend_constant c;
165: zval exists, results, value;
166: char *const_name;
167:
168: if (TL == NULL) {
169: return FAILURE;
170: }
171:
172: interfaces = ITypeLib_GetTypeInfoCount(TL);
173: for (i = 0; i < interfaces; i++) {
174: ITypeLib_GetTypeInfoType(TL, i, &pTKind);
175: if (pTKind == TKIND_ENUM) {
176: ITypeLib_GetTypeInfo(TL, i, &TypeInfo);
177: for (j = 0; ; j++) {
178: if (FAILED(ITypeInfo_GetVarDesc(TypeInfo, j, &pVarDesc))) {
179: break;
180: }
181: ITypeInfo_GetNames(TypeInfo, pVarDesc->memid, &bstr_ids, 1, &NameCount);
182: if (NameCount != 1) {
183: ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
184: continue;
185: }
186:
187: const_name = php_com_olestring_to_string(bstr_ids, &c.name_len, codepage TSRMLS_CC);
188: c.name = zend_strndup(const_name, c.name_len);
189: efree(const_name);
1.1.1.2 misho 190: if(c.name == NULL) {
191: ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
192: continue;
193: }
1.1 misho 194: c.name_len++; /* include NUL */
195: SysFreeString(bstr_ids);
196:
197: /* sanity check for the case where the constant is already defined */
198: if (zend_get_constant(c.name, c.name_len - 1, &exists TSRMLS_CC)) {
199: if (COMG(autoreg_verbose) && !compare_function(&results, &c.value, &exists TSRMLS_CC)) {
200: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type library constant %s is already defined", c.name);
201: }
202: free(c.name);
203: ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
204: continue;
205: }
206:
207: /* register the constant */
208: php_com_zval_from_variant(&value, pVarDesc->lpvarValue, codepage TSRMLS_CC);
209: if (Z_TYPE(value) == IS_LONG) {
210: c.flags = mode;
211: c.value.type = IS_LONG;
212: c.value.value.lval = Z_LVAL(value);
213: c.module_number = 0;
214: zend_register_constant(&c TSRMLS_CC);
215: }
216: ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
217: }
218: ITypeInfo_Release(TypeInfo);
219: }
220: }
221: return SUCCESS;
222: }
223:
224: /* Type-library stuff */
225: void php_com_typelibrary_dtor(void *pDest)
226: {
227: ITypeLib **Lib = (ITypeLib**)pDest;
228: ITypeLib_Release(*Lib);
229: }
230:
1.1.1.3 misho 231: PHP_COM_DOTNET_API ITypeLib *php_com_load_typelib_via_cache(char *search_string,
1.1 misho 232: int codepage, int *cached TSRMLS_DC)
233: {
234: ITypeLib **TLp;
235: ITypeLib *TL;
236: char *name_dup;
237: int l;
238:
239: l = strlen(search_string);
240:
241: if (zend_ts_hash_find(&php_com_typelibraries, search_string, l+1,
242: (void**)&TLp) == SUCCESS) {
243: *cached = 1;
244: /* add a reference for the caller */
245: ITypeLib_AddRef(*TLp);
246: return *TLp;
247: }
248:
249: *cached = 0;
250: name_dup = estrndup(search_string, l);
251: TL = php_com_load_typelib(name_dup, codepage TSRMLS_CC);
252: efree(name_dup);
253:
254: if (TL) {
255: if (SUCCESS == zend_ts_hash_update(&php_com_typelibraries,
256: search_string, l+1, (void*)&TL, sizeof(ITypeLib*), NULL)) {
257: /* add a reference for the hash table */
258: ITypeLib_AddRef(TL);
259: }
260: }
261:
262: return TL;
263: }
264:
265: ITypeInfo *php_com_locate_typeinfo(char *typelibname, php_com_dotnet_object *obj, char *dispname, int sink TSRMLS_DC)
266: {
267: ITypeInfo *typeinfo = NULL;
268: ITypeLib *typelib = NULL;
269: int gotguid = 0;
270: GUID iid;
271:
272: if (obj) {
273: if (dispname == NULL && sink) {
274: IProvideClassInfo2 *pci2;
275: IProvideClassInfo *pci;
276:
277: if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v), &IID_IProvideClassInfo2, (void**)&pci2))) {
278: gotguid = SUCCEEDED(IProvideClassInfo2_GetGUID(pci2, GUIDKIND_DEFAULT_SOURCE_DISP_IID, &iid));
279: IProvideClassInfo2_Release(pci2);
280: }
281: if (!gotguid && SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v), &IID_IProvideClassInfo, (void**)&pci))) {
282: /* examine the available interfaces */
283: /* TODO: write some code here */
284: php_error_docref(NULL TSRMLS_CC, E_WARNING, "IProvideClassInfo: this code not yet written!");
285: IProvideClassInfo_Release(pci);
286: }
287: } else if (dispname == NULL) {
288: if (obj->typeinfo) {
289: ITypeInfo_AddRef(obj->typeinfo);
290: return obj->typeinfo;
291: } else {
292: IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &typeinfo);
293: if (typeinfo) {
294: return typeinfo;
295: }
296: }
297: } else if (dispname && obj->typeinfo) {
298: unsigned int idx;
299: /* get the library from the object; the rest will be dealt with later */
300: ITypeInfo_GetContainingTypeLib(obj->typeinfo, &typelib, &idx);
301: } else if (typelibname == NULL) {
302: IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &typeinfo);
303: if (dispname) {
304: unsigned int idx;
305: /* get the library from the object; the rest will be dealt with later */
306: ITypeInfo_GetContainingTypeLib(typeinfo, &typelib, &idx);
307:
308: if (typelib) {
309: ITypeInfo_Release(typeinfo);
310: typeinfo = NULL;
311: }
312: }
313: }
314: } else if (typelibname) {
315: /* Fetch the typelibrary and use that to look things up */
316: typelib = php_com_load_typelib(typelibname, CP_THREAD_ACP TSRMLS_CC);
317: }
318:
319: if (!gotguid && dispname && typelib) {
320: unsigned short cfound;
321: MEMBERID memid;
322: OLECHAR *olename = php_com_string_to_olestring(dispname, strlen(dispname), CP_ACP TSRMLS_CC);
323:
324: cfound = 1;
325: if (FAILED(ITypeLib_FindName(typelib, olename, 0, &typeinfo, &memid, &cfound)) || cfound == 0) {
326: CLSID coclass;
327: ITypeInfo *coinfo;
328:
329: /* assume that it might be a progid instead */
330: if (SUCCEEDED(CLSIDFromProgID(olename, &coclass)) &&
331: SUCCEEDED(ITypeLib_GetTypeInfoOfGuid(typelib, &coclass, &coinfo))) {
332:
333: /* enumerate implemented interfaces and pick the one as indicated by sink */
334: TYPEATTR *attr;
335: int i;
336:
337: ITypeInfo_GetTypeAttr(coinfo, &attr);
338:
339: for (i = 0; i < attr->cImplTypes; i++) {
340: HREFTYPE rt;
341: int tf;
342:
343: if (FAILED(ITypeInfo_GetImplTypeFlags(coinfo, i, &tf))) {
344: continue;
345: }
346:
347: if ((sink && tf == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) ||
348: (!sink && (tf & IMPLTYPEFLAG_FSOURCE) == 0)) {
349:
350: /* flags match what we are looking for */
351:
352: if (SUCCEEDED(ITypeInfo_GetRefTypeOfImplType(coinfo, i, &rt)))
353: if (SUCCEEDED(ITypeInfo_GetRefTypeInfo(coinfo, rt, &typeinfo)))
354: break;
355:
356: }
357: }
358:
359: ITypeInfo_ReleaseTypeAttr(coinfo, attr);
360: ITypeInfo_Release(coinfo);
361: }
362: }
363:
364:
365: efree(olename);
366: } else if (gotguid) {
367: ITypeLib_GetTypeInfoOfGuid(typelib, &iid, &typeinfo);
368: }
369:
370: if (typelib) {
371: ITypeLib_Release(typelib);
372: }
373:
374: return typeinfo;
375: }
376:
377: static const struct {
378: VARTYPE vt;
379: const char *name;
380: } vt_names[] = {
381: { VT_NULL, "VT_NULL" },
382: { VT_EMPTY, "VT_EMPTY" },
383: { VT_UI1, "VT_UI1" },
384: { VT_I2, "VT_I2" },
385: { VT_I4, "VT_I4" },
386: { VT_R4, "VT_R4" },
387: { VT_R8, "VT_R8" },
388: { VT_BOOL, "VT_BOOL" },
389: { VT_ERROR, "VT_ERROR" },
390: { VT_CY, "VT_CY" },
391: { VT_DATE, "VT_DATE" },
392: { VT_BSTR, "VT_BSTR" },
393: { VT_DECIMAL, "VT_DECIMAL" },
394: { VT_UNKNOWN, "VT_UNKNOWN" },
395: { VT_DISPATCH, "VT_DISPATCH" },
396: { VT_VARIANT, "VT_VARIANT" },
397: { VT_I1, "VT_I1" },
398: { VT_UI2, "VT_UI2" },
399: { VT_UI4, "VT_UI4" },
400: { VT_INT, "VT_INT" },
401: { VT_UINT, "VT_UINT" },
402: { VT_ARRAY, "VT_ARRAY" },
403: { VT_BYREF, "VT_BYREF" },
404: { VT_VOID, "VT_VOID" },
405: { VT_PTR, "VT_PTR" },
406: { VT_HRESULT, "VT_HRESULT" },
407: { VT_SAFEARRAY, "VT_SAFEARRAY" },
408: { 0, NULL }
409: };
410:
411: static inline const char *vt_to_string(VARTYPE vt)
412: {
413: int i;
414: for (i = 0; vt_names[i].name != NULL; i++) {
415: if (vt_names[i].vt == vt)
416: return vt_names[i].name;
417: }
418: return "?";
419: }
420:
421: static char *php_com_string_from_clsid(const CLSID *clsid, int codepage TSRMLS_DC)
422: {
423: LPOLESTR ole_clsid;
424: char *clsid_str;
425:
426: StringFromCLSID(clsid, &ole_clsid);
427: clsid_str = php_com_olestring_to_string(ole_clsid, NULL, codepage TSRMLS_CC);
428: LocalFree(ole_clsid);
429:
430: return clsid_str;
431: }
432:
433:
434: int php_com_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid, int codepage TSRMLS_DC)
435: {
436: TYPEATTR *attr;
437: FUNCDESC *func;
438: int i;
439: OLECHAR *olename;
440: char *ansiname = NULL;
441: unsigned int ansinamelen;
442: int ret = 0;
443:
444: if (FAILED(ITypeInfo_GetTypeAttr(typeinfo, &attr))) {
445: return 0;
446: }
447:
448: /* verify that it is suitable */
449: if (id_to_name == NULL || attr->typekind == TKIND_DISPATCH) {
450:
451: if (guid) {
452: memcpy(guid, &attr->guid, sizeof(GUID));
453: }
454:
455: if (printdef) {
456: char *guidstring;
457:
458: ITypeInfo_GetDocumentation(typeinfo, MEMBERID_NIL, &olename, NULL, NULL, NULL);
459: ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage TSRMLS_CC);
460: SysFreeString(olename);
461:
462: guidstring = php_com_string_from_clsid(&attr->guid, codepage TSRMLS_CC);
463: php_printf("class %s { /* GUID=%s */\n", ansiname, guidstring);
464: efree(guidstring);
465:
466: efree(ansiname);
467: }
468:
469: if (id_to_name) {
470: zend_hash_init(id_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
471: }
472:
473: /* So we've got the dispatch interface; lets list the event methods */
474: for (i = 0; i < attr->cFuncs; i++) {
475: zval *tmp;
476: DISPID lastid = 0; /* for props */
477: int isprop;
478:
479: if (FAILED(ITypeInfo_GetFuncDesc(typeinfo, i, &func)))
480: break;
481:
482: isprop = (func->invkind & DISPATCH_PROPERTYGET || func->invkind & DISPATCH_PROPERTYPUT);
483:
484: if (!isprop || lastid != func->memid) {
485:
486: lastid = func->memid;
487:
488: ITypeInfo_GetDocumentation(typeinfo, func->memid, &olename, NULL, NULL, NULL);
489: ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage TSRMLS_CC);
490: SysFreeString(olename);
491:
492: if (printdef) {
493: int j;
494: char *funcdesc;
495: unsigned int funcdesclen, cnames = 0;
496: BSTR *names;
497:
498: names = (BSTR*)safe_emalloc((func->cParams + 1), sizeof(BSTR), 0);
499:
500: ITypeInfo_GetNames(typeinfo, func->memid, names, func->cParams + 1, &cnames);
501: /* first element is the function name */
502: SysFreeString(names[0]);
503:
504: php_printf("\t/* DISPID=%d */\n", func->memid);
505:
506: if (func->elemdescFunc.tdesc.vt != VT_VOID) {
507: php_printf("\t/* %s [%d] */\n",
508: vt_to_string(func->elemdescFunc.tdesc.vt),
509: func->elemdescFunc.tdesc.vt
510: );
511: }
512:
513: if (isprop) {
514:
515: ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
516: if (olename) {
517: funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage TSRMLS_CC);
518: SysFreeString(olename);
519: php_printf("\t/* %s */\n", funcdesc);
520: efree(funcdesc);
521: }
522:
523: php_printf("\tvar $%s;\n\n", ansiname);
524:
525: } else {
526: /* a function */
527:
528: php_printf("\tfunction %s(\n", ansiname);
529:
530: for (j = 0; j < func->cParams; j++) {
531: ELEMDESC *elem = &func->lprgelemdescParam[j];
532:
533: php_printf("\t\t/* %s [%d] ", vt_to_string(elem->tdesc.vt), elem->tdesc.vt);
534:
535: if (elem->paramdesc.wParamFlags & PARAMFLAG_FIN)
536: php_printf("[in]");
537: if (elem->paramdesc.wParamFlags & PARAMFLAG_FOUT)
538: php_printf("[out]");
539:
540: if (elem->tdesc.vt == VT_PTR) {
541: /* what does it point to ? */
542: php_printf(" --> %s [%d] ",
543: vt_to_string(elem->tdesc.lptdesc->vt),
544: elem->tdesc.lptdesc->vt
545: );
546: }
547:
548: /* when we handle prop put and get, this will look nicer */
549: if (j+1 < (int)cnames) {
550: funcdesc = php_com_olestring_to_string(names[j+1], &funcdesclen, codepage TSRMLS_CC);
551: SysFreeString(names[j+1]);
552: } else {
553: funcdesc = "???";
554: }
555:
556: php_printf(" */ %s%s%c\n",
557: elem->tdesc.vt == VT_PTR ? "&$" : "$",
558: funcdesc,
559: j == func->cParams - 1 ? ' ' : ','
560: );
561:
562: if (j+1 < (int)cnames) {
563: efree(funcdesc);
564: }
565: }
566:
567: php_printf("\t\t)\n\t{\n");
568:
569: ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
570: if (olename) {
571: funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage TSRMLS_CC);
572: SysFreeString(olename);
573: php_printf("\t\t/* %s */\n", funcdesc);
574: efree(funcdesc);
575: }
576:
577: php_printf("\t}\n");
578: }
579:
580: efree(names);
581: }
582:
583: if (id_to_name) {
584: zend_str_tolower(ansiname, ansinamelen);
585: MAKE_STD_ZVAL(tmp);
586: ZVAL_STRINGL(tmp, ansiname, ansinamelen, 0);
587: zend_hash_index_update(id_to_name, func->memid, (void*)&tmp, sizeof(zval *), NULL);
588: }
589: }
590: ITypeInfo_ReleaseFuncDesc(typeinfo, func);
591: }
592:
593: if (printdef) {
594: php_printf("}\n");
595: }
596:
597: ret = 1;
598: } else {
599: zend_error(E_WARNING, "That's not a dispatchable interface!! type kind = %08x", attr->typekind);
600: }
601:
602: ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
603:
604: return ret;
605: }
606:
607: