static char *php_com_string_from_clsid(const CLSID *clsid, int codepage) { LPOLESTR ole_clsid; char *clsid_str; StringFromCLSID(clsid, &ole_clsid); clsid_str = php_com_olestring_to_string(ole_clsid, NULL, codepage); LocalFree(ole_clsid); return clsid_str; }
/* Performs an Invoke on the given com object. * returns a failure code and creates an exception if there was an error */ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member, WORD flags, DISPPARAMS *disp_params, VARIANT *v, int silent, int allow_noarg TSRMLS_DC) { HRESULT hr; unsigned int arg_err; EXCEPINFO e = {0}; hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member, &IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, v, &e, &arg_err); if (silent == 0 && FAILED(hr)) { char *source = NULL, *desc = NULL, *msg = NULL; int source_len, desc_len; switch (hr) { case DISP_E_EXCEPTION: if (e.bstrSource) { source = php_com_olestring_to_string(e.bstrSource, &source_len, obj->code_page TSRMLS_CC); SysFreeString(e.bstrSource); } if (e.bstrDescription) { desc = php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page TSRMLS_CC); SysFreeString(e.bstrDescription); } if (PG(html_errors)) { spprintf(&msg, 0, "<b>Source:</b> %s<br/><b>Description:</b> %s", source ? source : "Unknown", desc ? desc : "Unknown"); } else { spprintf(&msg, 0, "Source: %s\nDescription: %s", source ? source : "Unknown", desc ? desc : "Unknown"); } if (desc) { efree(desc); } if (source) { efree(source); } if (e.bstrHelpFile) { SysFreeString(e.bstrHelpFile); } break; case DISP_E_PARAMNOTFOUND: case DISP_E_TYPEMISMATCH: desc = php_win_err(hr); spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc); LocalFree(desc); break; case DISP_E_BADPARAMCOUNT: if ((disp_params->cArgs + disp_params->cNamedArgs == 0) && (allow_noarg == 1)) { /* if getting a property and they are missing all parameters, * we want to create a proxy object for them; so lets not create an * exception here */ msg = NULL; break; } /* else fall through */ default: desc = php_win_err(hr); spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc); LocalFree(desc); break; } if (msg) { php_com_throw_exception(hr, msg TSRMLS_CC); efree(msg); } } return hr; }
/* Given a type-library, merge it into the current engine state */ PHP_COM_DOTNET_API int php_com_import_typelib(ITypeLib *TL, int mode, int codepage TSRMLS_DC) { int i, j, interfaces; TYPEKIND pTKind; ITypeInfo *TypeInfo; VARDESC *pVarDesc; UINT NameCount; BSTR bstr_ids; zend_constant c; zval *exists, results, value; char *const_name; int len; if (TL == NULL) { return FAILURE; } interfaces = ITypeLib_GetTypeInfoCount(TL); for (i = 0; i < interfaces; i++) { ITypeLib_GetTypeInfoType(TL, i, &pTKind); if (pTKind == TKIND_ENUM) { ITypeLib_GetTypeInfo(TL, i, &TypeInfo); for (j = 0; ; j++) { if (FAILED(ITypeInfo_GetVarDesc(TypeInfo, j, &pVarDesc))) { break; } ITypeInfo_GetNames(TypeInfo, pVarDesc->memid, &bstr_ids, 1, &NameCount); if (NameCount != 1) { ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc); continue; } const_name = php_com_olestring_to_string(bstr_ids, &len, codepage TSRMLS_CC); c.name = STR_INIT(const_name, len, 1); // TODO: avoid reallocation??? efree(const_name); if(c.name == NULL) { ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc); continue; } //??? c.name_len++; /* include NUL */ SysFreeString(bstr_ids); /* sanity check for the case where the constant is already defined */ if ((exists = zend_get_constant(c.name TSRMLS_CC)) != NULL) { if (COMG(autoreg_verbose) && !compare_function(&results, &c.value, exists TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type library constant %s is already defined", c.name); } STR_RELEASE(c.name); ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc); continue; } /* register the constant */ php_com_zval_from_variant(&value, pVarDesc->lpvarValue, codepage TSRMLS_CC); if (Z_TYPE(value) == IS_INT) { c.flags = mode; ZVAL_INT(&c.value, Z_IVAL(value)); c.module_number = 0; zend_register_constant(&c TSRMLS_CC); } ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc); } ITypeInfo_Release(TypeInfo); } } return SUCCESS; }
int php_com_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid, int codepage) { TYPEATTR *attr; FUNCDESC *func; int i; OLECHAR *olename; char *ansiname = NULL; size_t ansinamelen; int ret = 0; if (FAILED(ITypeInfo_GetTypeAttr(typeinfo, &attr))) { return 0; } /* verify that it is suitable */ if (id_to_name == NULL || attr->typekind == TKIND_DISPATCH) { if (guid) { memcpy(guid, &attr->guid, sizeof(GUID)); } if (printdef) { char *guidstring; ITypeInfo_GetDocumentation(typeinfo, MEMBERID_NIL, &olename, NULL, NULL, NULL); ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage); SysFreeString(olename); guidstring = php_com_string_from_clsid(&attr->guid, codepage); php_printf("class %s { /* GUID=%s */\n", ansiname, guidstring); efree(guidstring); efree(ansiname); } if (id_to_name) { zend_hash_init(id_to_name, 0, NULL, ZVAL_PTR_DTOR, 0); } /* So we've got the dispatch interface; lets list the event methods */ for (i = 0; i < attr->cFuncs; i++) { zval tmp; DISPID lastid = 0; /* for props */ int isprop; if (FAILED(ITypeInfo_GetFuncDesc(typeinfo, i, &func))) break; isprop = (func->invkind & DISPATCH_PROPERTYGET || func->invkind & DISPATCH_PROPERTYPUT); if (!isprop || lastid != func->memid) { lastid = func->memid; ITypeInfo_GetDocumentation(typeinfo, func->memid, &olename, NULL, NULL, NULL); ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage); SysFreeString(olename); if (printdef) { int j; char *funcdesc; size_t funcdesclen; unsigned int cnames = 0; BSTR *names; names = (BSTR*)safe_emalloc((func->cParams + 1), sizeof(BSTR), 0); ITypeInfo_GetNames(typeinfo, func->memid, names, func->cParams + 1, &cnames); /* first element is the function name */ SysFreeString(names[0]); php_printf("\t/* DISPID=%d */\n", func->memid); if (func->elemdescFunc.tdesc.vt != VT_VOID) { php_printf("\t/* %s [%d] */\n", vt_to_string(func->elemdescFunc.tdesc.vt), func->elemdescFunc.tdesc.vt ); } if (isprop) { ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL); if (olename) { funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage); SysFreeString(olename); php_printf("\t/* %s */\n", funcdesc); efree(funcdesc); } php_printf("\tvar $%s;\n\n", ansiname); } else { /* a function */ php_printf("\tfunction %s(\n", ansiname); for (j = 0; j < func->cParams; j++) { ELEMDESC *elem = &func->lprgelemdescParam[j]; php_printf("\t\t/* %s [%d] ", vt_to_string(elem->tdesc.vt), elem->tdesc.vt); if (elem->paramdesc.wParamFlags & PARAMFLAG_FIN) php_printf("[in]"); if (elem->paramdesc.wParamFlags & PARAMFLAG_FOUT) php_printf("[out]"); if (elem->tdesc.vt == VT_PTR) { /* what does it point to ? */ php_printf(" --> %s [%d] ", vt_to_string(elem->tdesc.lptdesc->vt), elem->tdesc.lptdesc->vt ); } /* when we handle prop put and get, this will look nicer */ if (j+1 < (int)cnames) { funcdesc = php_com_olestring_to_string(names[j+1], &funcdesclen, codepage); SysFreeString(names[j+1]); } else { funcdesc = "???"; } php_printf(" */ %s%s%c\n", elem->tdesc.vt == VT_PTR ? "&$" : "$", funcdesc, j == func->cParams - 1 ? ' ' : ',' ); if (j+1 < (int)cnames) { efree(funcdesc); } } php_printf("\t\t)\n\t{\n"); ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL); if (olename) { funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage); SysFreeString(olename); php_printf("\t\t/* %s */\n", funcdesc); efree(funcdesc); } php_printf("\t}\n"); } efree(names); } if (id_to_name) { zend_str_tolower(ansiname, ansinamelen); ZVAL_STRINGL(&tmp, ansiname, ansinamelen); zend_hash_index_update(id_to_name, func->memid, &tmp); // TODO: avoid reallocation??? efree(ansiname); } } ITypeInfo_ReleaseFuncDesc(typeinfo, func); } if (printdef) { php_printf("}\n"); } ret = 1; } else { zend_error(E_WARNING, "That's not a dispatchable interface!! type kind = %08x", attr->typekind); } ITypeInfo_ReleaseTypeAttr(typeinfo, attr); return ret; }
PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage TSRMLS_DC) { OLECHAR *olestring = NULL; int ret = SUCCESS; switch (V_VT(v)) { case VT_EMPTY: case VT_NULL: case VT_VOID: ZVAL_NULL(z); break; case VT_UI1: ZVAL_LONG(z, (long)V_UI1(v)); break; case VT_I1: ZVAL_LONG(z, (long)V_I1(v)); break; case VT_UI2: ZVAL_LONG(z, (long)V_UI2(v)); break; case VT_I2: ZVAL_LONG(z, (long)V_I2(v)); break; case VT_UI4: /* TODO: promote to double if large? */ ZVAL_LONG(z, (long)V_UI4(v)); break; case VT_I4: ZVAL_LONG(z, (long)V_I4(v)); break; case VT_INT: ZVAL_LONG(z, V_INT(v)); break; case VT_UINT: /* TODO: promote to double if large? */ ZVAL_LONG(z, (long)V_UINT(v)); break; case VT_R4: ZVAL_DOUBLE(z, (double)V_R4(v)); break; case VT_R8: ZVAL_DOUBLE(z, V_R8(v)); break; case VT_BOOL: ZVAL_BOOL(z, V_BOOL(v) ? 1 : 0); break; case VT_BSTR: olestring = V_BSTR(v); if (olestring) { Z_TYPE_P(z) = IS_STRING; Z_STRVAL_P(z) = php_com_olestring_to_string(olestring, &Z_STRLEN_P(z), codepage TSRMLS_CC); olestring = NULL; } break; case VT_UNKNOWN: if (V_UNKNOWN(v) != NULL) { IDispatch *disp; if (SUCCEEDED(IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, &disp))) { php_com_wrap_dispatch(z, disp, codepage TSRMLS_CC); IDispatch_Release(disp); } else { ret = FAILURE; } } break; case VT_DISPATCH: if (V_DISPATCH(v) != NULL) { php_com_wrap_dispatch(z, V_DISPATCH(v), codepage TSRMLS_CC); } break; case VT_VARIANT: /* points to another variant */ return php_com_zval_from_variant(z, V_VARIANTREF(v), codepage TSRMLS_CC); default: php_com_wrap_variant(z, v, codepage TSRMLS_CC); } if (olestring) { efree(olestring); } if (ret == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "variant->zval: conversion from 0x%x ret=%d", V_VT(v), ret); } return ret; }
PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage) { OLECHAR *olestring = NULL; int ret = SUCCESS; switch (V_VT(v)) { case VT_EMPTY: case VT_NULL: case VT_VOID: ZVAL_NULL(z); break; case VT_UI1: ZVAL_LONG(z, (zend_long)V_UI1(v)); break; case VT_I1: ZVAL_LONG(z, (zend_long)V_I1(v)); break; case VT_UI2: ZVAL_LONG(z, (zend_long)V_UI2(v)); break; case VT_I2: ZVAL_LONG(z, (zend_long)V_I2(v)); break; case VT_UI4: /* TODO: promote to double if large? */ ZVAL_LONG(z, (long)V_UI4(v)); break; case VT_I4: ZVAL_LONG(z, (long)V_I4(v)); break; #if SIZEOF_ZEND_LONG == 8 case VT_UI8: ZVAL_LONG(z, (zend_long)V_UI8(v)); break; case VT_I8: ZVAL_LONG(z, (zend_long)V_I8(v)); break; #endif case VT_INT: ZVAL_LONG(z, V_INT(v)); break; case VT_UINT: /* TODO: promote to double if large? */ ZVAL_LONG(z, (zend_long)V_UINT(v)); break; case VT_R4: ZVAL_DOUBLE(z, (double)V_R4(v)); break; case VT_R8: ZVAL_DOUBLE(z, V_R8(v)); break; case VT_BOOL: ZVAL_BOOL(z, V_BOOL(v) ? 1 : 0); break; case VT_BSTR: olestring = V_BSTR(v); if (olestring) { size_t len; char *str = php_com_olestring_to_string(olestring, &len, codepage); ZVAL_STRINGL(z, str, len); // TODO: avoid reallocation??? efree(str); olestring = NULL; } break; case VT_UNKNOWN: if (V_UNKNOWN(v) != NULL) { IDispatch *disp; if (SUCCEEDED(IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, &disp))) { php_com_wrap_dispatch(z, disp, codepage); IDispatch_Release(disp); } else { ret = FAILURE; } } break; case VT_DISPATCH: if (V_DISPATCH(v) != NULL) { php_com_wrap_dispatch(z, V_DISPATCH(v), codepage); } break; case VT_VARIANT: /* points to another variant */ return php_com_zval_from_variant(z, V_VARIANTREF(v), codepage); default: php_com_wrap_variant(z, v, codepage); } if (olestring) { efree(olestring); } if (ret == FAILURE) { php_error_docref(NULL, E_WARNING, "variant->zval: conversion from 0x%x ret=%d", V_VT(v), ret); } return ret; }