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