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