xref: /PHP-5.3/ext/com_dotnet/com_typeinfo.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 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    |         Harald Radi <h.radi@nme.at>                                  |
17    +----------------------------------------------------------------------+
18  */
19 
20 /* $Id$ */
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  */
php_com_load_typelib(char * search_string,int codepage TSRMLS_DC)38 PHP_COM_DOTNET_API ITypeLib *php_com_load_typelib(char *search_string, int codepage TSRMLS_DC)
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 */
php_com_import_typelib(ITypeLib * TL,int mode,int codepage TSRMLS_DC)156 PHP_COM_DOTNET_API int php_com_import_typelib(ITypeLib *TL, int mode, int codepage TSRMLS_DC)
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);
190 				c.name_len++; /* include NUL */
191 				SysFreeString(bstr_ids);
192 
193 				/* sanity check for the case where the constant is already defined */
194 				if (zend_get_constant(c.name, c.name_len - 1, &exists TSRMLS_CC)) {
195 					if (COMG(autoreg_verbose) && !compare_function(&results, &c.value, &exists TSRMLS_CC)) {
196 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type library constant %s is already defined", c.name);
197 					}
198 					free(c.name);
199 					ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
200 					continue;
201 				}
202 
203 				/* register the constant */
204 				php_com_zval_from_variant(&value, pVarDesc->lpvarValue, codepage TSRMLS_CC);
205 				if (Z_TYPE(value) == IS_LONG) {
206 					c.flags = mode;
207 					c.value.type = IS_LONG;
208 					c.value.value.lval = Z_LVAL(value);
209 					c.module_number = 0;
210 					zend_register_constant(&c TSRMLS_CC);
211 				}
212 				ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
213 			}
214 			ITypeInfo_Release(TypeInfo);
215 		}
216 	}
217 	return SUCCESS;
218 }
219 
220 /* Type-library stuff */
php_com_typelibrary_dtor(void * pDest)221 void php_com_typelibrary_dtor(void *pDest)
222 {
223 	ITypeLib **Lib = (ITypeLib**)pDest;
224 	ITypeLib_Release(*Lib);
225 }
226 
php_com_load_typelib_via_cache(char * search_string,int codepage,int * cached TSRMLS_DC)227 PHP_COM_DOTNET_API ITypeLib *php_com_load_typelib_via_cache(char *search_string,
228 	int codepage, int *cached TSRMLS_DC)
229 {
230 	ITypeLib **TLp;
231 	ITypeLib *TL;
232 	char *name_dup;
233 	int l;
234 
235 	l = strlen(search_string);
236 
237 	if (zend_ts_hash_find(&php_com_typelibraries, search_string, l+1,
238 			(void**)&TLp) == SUCCESS) {
239 		*cached = 1;
240 		/* add a reference for the caller */
241 		ITypeLib_AddRef(*TLp);
242 		return *TLp;
243 	}
244 
245 	*cached = 0;
246 	name_dup = estrndup(search_string, l);
247 	TL = php_com_load_typelib(name_dup, codepage TSRMLS_CC);
248 	efree(name_dup);
249 
250 	if (TL) {
251 		if (SUCCESS == zend_ts_hash_update(&php_com_typelibraries,
252 				search_string, l+1, (void*)&TL, sizeof(ITypeLib*), NULL)) {
253 			/* add a reference for the hash table */
254 			ITypeLib_AddRef(TL);
255 		}
256 	}
257 
258 	return TL;
259 }
260 
php_com_locate_typeinfo(char * typelibname,php_com_dotnet_object * obj,char * dispname,int sink TSRMLS_DC)261 ITypeInfo *php_com_locate_typeinfo(char *typelibname, php_com_dotnet_object *obj, char *dispname, int sink TSRMLS_DC)
262 {
263 	ITypeInfo *typeinfo = NULL;
264 	ITypeLib *typelib = NULL;
265 	int gotguid = 0;
266 	GUID iid;
267 
268 	if (obj) {
269 		if (dispname == NULL && sink) {
270 			IProvideClassInfo2 *pci2;
271 			IProvideClassInfo *pci;
272 
273 			if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v), &IID_IProvideClassInfo2, (void**)&pci2))) {
274 				gotguid = SUCCEEDED(IProvideClassInfo2_GetGUID(pci2, GUIDKIND_DEFAULT_SOURCE_DISP_IID, &iid));
275 				IProvideClassInfo2_Release(pci2);
276 			}
277 			if (!gotguid && SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v), &IID_IProvideClassInfo, (void**)&pci))) {
278 				/* examine the available interfaces */
279 				/* TODO: write some code here */
280 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "IProvideClassInfo: this code not yet written!");
281 				IProvideClassInfo_Release(pci);
282 			}
283 		} else if (dispname == NULL) {
284 			if (obj->typeinfo) {
285 				ITypeInfo_AddRef(obj->typeinfo);
286 				return obj->typeinfo;
287 			} else {
288 				IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &typeinfo);
289 				if (typeinfo) {
290 					return typeinfo;
291 				}
292 			}
293 		} else if (dispname && obj->typeinfo) {
294 			unsigned int idx;
295 			/* get the library from the object; the rest will be dealt with later */
296 			ITypeInfo_GetContainingTypeLib(obj->typeinfo, &typelib, &idx);
297 		} else if (typelibname == NULL) {
298 			IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &typeinfo);
299 			if (dispname) {
300 				unsigned int idx;
301 				/* get the library from the object; the rest will be dealt with later */
302 				ITypeInfo_GetContainingTypeLib(typeinfo, &typelib, &idx);
303 
304 				if (typelib) {
305 					ITypeInfo_Release(typeinfo);
306 					typeinfo = NULL;
307 				}
308 			}
309 		}
310 	} else if (typelibname) {
311 		/* Fetch the typelibrary and use that to look things up */
312 		typelib = php_com_load_typelib(typelibname, CP_THREAD_ACP TSRMLS_CC);
313 	}
314 
315 	if (!gotguid && dispname && typelib) {
316 		unsigned short cfound;
317 		MEMBERID memid;
318 		OLECHAR *olename = php_com_string_to_olestring(dispname, strlen(dispname), CP_ACP TSRMLS_CC);
319 
320 		cfound = 1;
321 		if (FAILED(ITypeLib_FindName(typelib, olename, 0, &typeinfo, &memid, &cfound)) || cfound == 0) {
322 			CLSID coclass;
323 			ITypeInfo *coinfo;
324 
325 			/* assume that it might be a progid instead */
326 			if (SUCCEEDED(CLSIDFromProgID(olename, &coclass)) &&
327 					SUCCEEDED(ITypeLib_GetTypeInfoOfGuid(typelib, &coclass, &coinfo))) {
328 
329 				/* enumerate implemented interfaces and pick the one as indicated by sink */
330 				TYPEATTR *attr;
331 				int i;
332 
333 				ITypeInfo_GetTypeAttr(coinfo, &attr);
334 
335 				for (i = 0; i < attr->cImplTypes; i++) {
336 					HREFTYPE rt;
337 					int tf;
338 
339 					if (FAILED(ITypeInfo_GetImplTypeFlags(coinfo, i, &tf))) {
340 						continue;
341 					}
342 
343 					if ((sink && tf == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) ||
344 						(!sink && (tf & IMPLTYPEFLAG_FSOURCE) == 0)) {
345 
346 						/* flags match what we are looking for */
347 
348 						if (SUCCEEDED(ITypeInfo_GetRefTypeOfImplType(coinfo, i, &rt)))
349 							if (SUCCEEDED(ITypeInfo_GetRefTypeInfo(coinfo, rt, &typeinfo)))
350 								break;
351 
352 					}
353 				}
354 
355 				ITypeInfo_ReleaseTypeAttr(coinfo, attr);
356 				ITypeInfo_Release(coinfo);
357 			}
358 		}
359 
360 
361 		efree(olename);
362 	} else if (gotguid) {
363 		ITypeLib_GetTypeInfoOfGuid(typelib, &iid, &typeinfo);
364 	}
365 
366 	if (typelib) {
367 		ITypeLib_Release(typelib);
368 	}
369 
370 	return typeinfo;
371 }
372 
373 static const struct {
374 	VARTYPE vt;
375 	const char *name;
376 } vt_names[] = {
377 	{ VT_NULL,		"VT_NULL" },
378 	{ VT_EMPTY,		"VT_EMPTY" },
379 	{ VT_UI1,		"VT_UI1" },
380 	{ VT_I2,		"VT_I2" },
381 	{ VT_I4,		"VT_I4" },
382 	{ VT_R4,		"VT_R4" },
383 	{ VT_R8,		"VT_R8" },
384 	{ VT_BOOL,		"VT_BOOL" },
385 	{ VT_ERROR,		"VT_ERROR" },
386 	{ VT_CY,		"VT_CY" },
387 	{ VT_DATE,		"VT_DATE" },
388 	{ VT_BSTR,		"VT_BSTR" },
389 	{ VT_DECIMAL,	"VT_DECIMAL" },
390 	{ VT_UNKNOWN,	"VT_UNKNOWN" },
391 	{ VT_DISPATCH,	"VT_DISPATCH" },
392 	{ VT_VARIANT,	"VT_VARIANT" },
393 	{ VT_I1,		"VT_I1" },
394 	{ VT_UI2,		"VT_UI2" },
395 	{ VT_UI4,		"VT_UI4" },
396 	{ VT_INT,		"VT_INT" },
397 	{ VT_UINT,		"VT_UINT" },
398 	{ VT_ARRAY,		"VT_ARRAY" },
399 	{ VT_BYREF,		"VT_BYREF" },
400 	{ VT_VOID,		"VT_VOID" },
401 	{ VT_PTR,		"VT_PTR" },
402 	{ VT_HRESULT,	"VT_HRESULT" },
403 	{ VT_SAFEARRAY, "VT_SAFEARRAY" },
404 	{ 0, NULL }
405 };
406 
vt_to_string(VARTYPE vt)407 static inline const char *vt_to_string(VARTYPE vt)
408 {
409 	int i;
410 	for (i = 0; vt_names[i].name != NULL; i++) {
411 		if (vt_names[i].vt == vt)
412 			return vt_names[i].name;
413 	}
414 	return "?";
415 }
416 
php_com_string_from_clsid(const CLSID * clsid,int codepage TSRMLS_DC)417 static char *php_com_string_from_clsid(const CLSID *clsid, int codepage TSRMLS_DC)
418 {
419 	LPOLESTR ole_clsid;
420 	char *clsid_str;
421 
422 	StringFromCLSID(clsid, &ole_clsid);
423 	clsid_str = php_com_olestring_to_string(ole_clsid, NULL, codepage TSRMLS_CC);
424 	LocalFree(ole_clsid);
425 
426 	return clsid_str;
427 }
428 
429 
php_com_process_typeinfo(ITypeInfo * typeinfo,HashTable * id_to_name,int printdef,GUID * guid,int codepage TSRMLS_DC)430 int php_com_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid, int codepage TSRMLS_DC)
431 {
432 	TYPEATTR *attr;
433 	FUNCDESC *func;
434 	int i;
435 	OLECHAR *olename;
436 	char *ansiname = NULL;
437 	unsigned int ansinamelen;
438 	int ret = 0;
439 
440 	if (FAILED(ITypeInfo_GetTypeAttr(typeinfo, &attr))) {
441 		return 0;
442 	}
443 
444 	/* verify that it is suitable */
445 	if (id_to_name == NULL || attr->typekind == TKIND_DISPATCH) {
446 
447 		if (guid) {
448 			memcpy(guid, &attr->guid, sizeof(GUID));
449 		}
450 
451 		if (printdef) {
452 			char *guidstring;
453 
454 			ITypeInfo_GetDocumentation(typeinfo, MEMBERID_NIL, &olename, NULL, NULL, NULL);
455 			ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage TSRMLS_CC);
456 			SysFreeString(olename);
457 
458 			guidstring = php_com_string_from_clsid(&attr->guid, codepage TSRMLS_CC);
459 			php_printf("class %s { /* GUID=%s */\n", ansiname, guidstring);
460 			efree(guidstring);
461 
462 			efree(ansiname);
463 		}
464 
465 		if (id_to_name) {
466 			zend_hash_init(id_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
467 		}
468 
469 		/* So we've got the dispatch interface; lets list the event methods */
470 		for (i = 0; i < attr->cFuncs; i++) {
471 			zval *tmp;
472 			DISPID lastid = 0;	/* for props */
473 			int isprop;
474 
475 			if (FAILED(ITypeInfo_GetFuncDesc(typeinfo, i, &func)))
476 				break;
477 
478 			isprop = (func->invkind & DISPATCH_PROPERTYGET || func->invkind & DISPATCH_PROPERTYPUT);
479 
480 			if (!isprop || lastid != func->memid) {
481 
482 				lastid = func->memid;
483 
484 				ITypeInfo_GetDocumentation(typeinfo, func->memid, &olename, NULL, NULL, NULL);
485 				ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage TSRMLS_CC);
486 				SysFreeString(olename);
487 
488 				if (printdef) {
489 					int j;
490 					char *funcdesc;
491 					unsigned int funcdesclen, cnames = 0;
492 					BSTR *names;
493 
494 					names = (BSTR*)safe_emalloc((func->cParams + 1), sizeof(BSTR), 0);
495 
496 					ITypeInfo_GetNames(typeinfo, func->memid, names, func->cParams + 1, &cnames);
497 					/* first element is the function name */
498 					SysFreeString(names[0]);
499 
500 					php_printf("\t/* DISPID=%d */\n", func->memid);
501 
502 					if (func->elemdescFunc.tdesc.vt != VT_VOID) {
503 						php_printf("\t/* %s [%d] */\n",
504 								vt_to_string(func->elemdescFunc.tdesc.vt),
505 								func->elemdescFunc.tdesc.vt
506 								);
507 					}
508 
509 					if (isprop) {
510 
511 						ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
512 						if (olename) {
513 							funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage TSRMLS_CC);
514 							SysFreeString(olename);
515 							php_printf("\t/* %s */\n", funcdesc);
516 							efree(funcdesc);
517 						}
518 
519 						php_printf("\tvar $%s;\n\n", ansiname);
520 
521 					} else {
522 						/* a function */
523 
524 						php_printf("\tfunction %s(\n", ansiname);
525 
526 						for (j = 0; j < func->cParams; j++) {
527 							ELEMDESC *elem = &func->lprgelemdescParam[j];
528 
529 							php_printf("\t\t/* %s [%d] ", vt_to_string(elem->tdesc.vt), elem->tdesc.vt);
530 
531 							if (elem->paramdesc.wParamFlags & PARAMFLAG_FIN)
532 								php_printf("[in]");
533 							if (elem->paramdesc.wParamFlags & PARAMFLAG_FOUT)
534 								php_printf("[out]");
535 
536 							if (elem->tdesc.vt == VT_PTR) {
537 								/* what does it point to ? */
538 								php_printf(" --> %s [%d] ",
539 										vt_to_string(elem->tdesc.lptdesc->vt),
540 										elem->tdesc.lptdesc->vt
541 										);
542 							}
543 
544 							/* when we handle prop put and get, this will look nicer */
545 							if (j+1 < (int)cnames) {
546 								funcdesc = php_com_olestring_to_string(names[j+1], &funcdesclen, codepage TSRMLS_CC);
547 								SysFreeString(names[j+1]);
548 							} else {
549 								funcdesc = "???";
550 							}
551 
552 							php_printf(" */ %s%s%c\n",
553 									elem->tdesc.vt == VT_PTR ? "&$" : "$",
554 									funcdesc,
555 									j == func->cParams - 1 ? ' ' : ','
556 									);
557 
558 							if (j+1 < (int)cnames) {
559 								efree(funcdesc);
560 							}
561 						}
562 
563 						php_printf("\t\t)\n\t{\n");
564 
565 						ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
566 						if (olename) {
567 							funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage TSRMLS_CC);
568 							SysFreeString(olename);
569 							php_printf("\t\t/* %s */\n", funcdesc);
570 							efree(funcdesc);
571 						}
572 
573 						php_printf("\t}\n");
574 					}
575 
576 					efree(names);
577 				}
578 
579 				if (id_to_name) {
580 					zend_str_tolower(ansiname, ansinamelen);
581 					MAKE_STD_ZVAL(tmp);
582 					ZVAL_STRINGL(tmp, ansiname, ansinamelen, 0);
583 					zend_hash_index_update(id_to_name, func->memid, (void*)&tmp, sizeof(zval *), NULL);
584 				}
585 			}
586 			ITypeInfo_ReleaseFuncDesc(typeinfo, func);
587 		}
588 
589 		if (printdef) {
590 			php_printf("}\n");
591 		}
592 
593 		ret = 1;
594 	} else {
595 		zend_error(E_WARNING, "That's not a dispatchable interface!! type kind = %08x", attr->typekind);
596 	}
597 
598 	ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
599 
600 	return ret;
601 }
602 
603 
604