php-src/ext/com_dotnet/com_com.c
Peter Kokot 8d3f8ca12a Remove unused Git attributes ident
The $Id$ keywords were used in Subversion where they can be substituted
with filename, last revision number change, last changed date, and last
user who changed it.

In Git this functionality is different and can be done with Git attribute
ident. These need to be defined manually for each file in the
.gitattributes file and are afterwards replaced with 40-character
hexadecimal blob object name which is based only on the particular file
contents.

This patch simplifies handling of $Id$ keywords by removing them since
they are not used anymore.
2018-07-25 00:53:25 +02:00

863 lines
23 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2018 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@thebrainroom.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"
#include "Zend/zend_exceptions.h"
/* {{{ com_create_instance - ctor for COM class */
PHP_FUNCTION(com_create_instance)
{
zval *object = getThis();
zval *server_params = NULL;
php_com_dotnet_object *obj;
char *module_name, *typelib_name = NULL, *server_name = NULL;
char *user_name = NULL, *domain_name = NULL, *password = NULL;
size_t module_name_len = 0, typelib_name_len = 0, server_name_len = 0,
user_name_len, domain_name_len, password_len;
OLECHAR *moniker;
CLSID clsid;
CLSCTX ctx = CLSCTX_SERVER;
HRESULT res = E_FAIL;
int mode = COMG(autoreg_case_sensitive) ? CONST_CS : 0;
ITypeLib *TL = NULL;
COSERVERINFO info;
COAUTHIDENTITY authid = {0};
COAUTHINFO authinfo = {
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE,
&authid, EOAC_NONE
};
zend_long cp = GetACP();
const struct php_win32_cp *cp_it;
php_com_initialize();
obj = CDNO_FETCH(object);
if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
ZEND_NUM_ARGS(), "s|s!ls",
&module_name, &module_name_len, &server_name, &server_name_len,
&cp, &typelib_name, &typelib_name_len) &&
FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
ZEND_NUM_ARGS(), "sa|ls",
&module_name, &module_name_len, &server_params, &cp,
&typelib_name, &typelib_name_len)) {
php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid arguments!");
return;
}
cp_it = php_win32_cp_get_by_id((DWORD)cp);
if (!cp_it) {
php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid codepage!");
return;
}
obj->code_page = (int)cp;
if (server_name) {
ctx = CLSCTX_REMOTE_SERVER;
} else if (server_params) {
zval *tmp;
/* decode the data from the array */
if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
"Server", sizeof("Server")-1))) {
convert_to_string_ex(tmp);
server_name = Z_STRVAL_P(tmp);
server_name_len = Z_STRLEN_P(tmp);
ctx = CLSCTX_REMOTE_SERVER;
}
if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
"Username", sizeof("Username")-1))) {
convert_to_string_ex(tmp);
user_name = Z_STRVAL_P(tmp);
user_name_len = Z_STRLEN_P(tmp);
}
if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
"Password", sizeof("Password")-1))) {
convert_to_string_ex(tmp);
password = Z_STRVAL_P(tmp);
password_len = Z_STRLEN_P(tmp);
}
if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
"Domain", sizeof("Domain")-1))) {
convert_to_string_ex(tmp);
domain_name = Z_STRVAL_P(tmp);
domain_name_len = Z_STRLEN_P(tmp);
}
if (NULL != (tmp = zend_hash_str_find(Z_ARRVAL_P(server_params),
"Flags", sizeof("Flags")-1))) {
ctx = (CLSCTX)zval_get_long(tmp);
}
}
if (server_name && !COMG(allow_dcom)) {
php_com_throw_exception(E_ERROR, "DCOM has been disabled by your administrator [com.allow_dcom=0]");
return;
}
moniker = php_com_string_to_olestring(module_name, module_name_len, obj->code_page);
/* if instantiating a remote object, either directly, or via
* a moniker, fill in the relevant info */
if (server_name) {
info.dwReserved1 = 0;
info.dwReserved2 = 0;
info.pwszName = php_com_string_to_olestring(server_name, server_name_len, obj->code_page);
if (user_name) {
authid.User = php_com_string_to_olestring(user_name, -1, obj->code_page);
authid.UserLength = (ULONG)user_name_len;
if (password) {
authid.Password = (OLECHAR*)password;
authid.PasswordLength = (ULONG)password_len;
} else {
authid.Password = (OLECHAR*)"";
authid.PasswordLength = 0;
}
if (domain_name) {
authid.Domain = (OLECHAR*)domain_name;
authid.DomainLength = (ULONG)domain_name_len;
} else {
authid.Domain = (OLECHAR*)"";
authid.DomainLength = 0;
}
authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
info.pAuthInfo = &authinfo;
} else {
info.pAuthInfo = NULL;
}
}
if (FAILED(CLSIDFromString(moniker, &clsid))) {
/* try to use it as a moniker */
IBindCtx *pBindCtx = NULL;
IMoniker *pMoniker = NULL;
ULONG ulEaten;
BIND_OPTS2 bopt = {0};
if (SUCCEEDED(res = CreateBindCtx(0, &pBindCtx))) {
if (server_name) {
/* fill in the remote server info.
* MSDN docs indicate that this might be ignored in
* current win32 implementations, but at least we are
* doing the right thing in readiness for the day that
* it does work */
bopt.cbStruct = sizeof(bopt);
IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
bopt.pServerInfo = &info;
/* apparently, GetBindOptions will only ever return
* a regular BIND_OPTS structure. My gut feeling is
* that it will modify the size field to reflect that
* so lets be safe and set it to the BIND_OPTS2 size
* again */
bopt.cbStruct = sizeof(bopt);
IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
}
if (SUCCEEDED(res = MkParseDisplayName(pBindCtx, moniker, &ulEaten, &pMoniker))) {
res = IMoniker_BindToObject(pMoniker, pBindCtx,
NULL, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
if (SUCCEEDED(res)) {
V_VT(&obj->v) = VT_DISPATCH;
}
IMoniker_Release(pMoniker);
}
}
if (pBindCtx) {
IBindCtx_Release(pBindCtx);
}
} else if (server_name) {
MULTI_QI qi;
qi.pIID = &IID_IDispatch;
qi.pItf = NULL;
qi.hr = S_OK;
res = CoCreateInstanceEx(&clsid, NULL, ctx, &info, 1, &qi);
if (SUCCEEDED(res)) {
res = qi.hr;
V_DISPATCH(&obj->v) = (IDispatch*)qi.pItf;
V_VT(&obj->v) = VT_DISPATCH;
}
} else {
res = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
if (SUCCEEDED(res)) {
V_VT(&obj->v) = VT_DISPATCH;
}
}
if (server_name) {
if (info.pwszName) efree(info.pwszName);
if (authid.User) efree(authid.User);
}
efree(moniker);
if (FAILED(res)) {
char *werr, *msg;
werr = php_win32_error_to_msg(res);
spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, werr);
LocalFree(werr);
php_com_throw_exception(res, msg);
efree(msg);
return;
}
/* we got the object and it lives ! */
/* see if it has TypeInfo available */
if (FAILED(IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo)) && typelib_name) {
/* load up the library from the named file */
int cached;
TL = php_com_load_typelib_via_cache(typelib_name, obj->code_page, &cached);
if (TL) {
if (COMG(autoreg_on) && !cached) {
php_com_import_typelib(TL, mode, obj->code_page);
}
/* cross your fingers... there is no guarantee that this ITypeInfo
* instance has any relation to this IDispatch instance... */
ITypeLib_GetTypeInfo(TL, 0, &obj->typeinfo);
ITypeLib_Release(TL);
}
} else if (obj->typeinfo && COMG(autoreg_on)) {
UINT idx;
if (SUCCEEDED(ITypeInfo_GetContainingTypeLib(obj->typeinfo, &TL, &idx))) {
/* check if the library is already in the cache by getting its name */
BSTR name;
if (SUCCEEDED(ITypeLib_GetDocumentation(TL, -1, &name, NULL, NULL, NULL))) {
typelib_name = php_com_olestring_to_string(name, &typelib_name_len, obj->code_page);
if (NULL != zend_ts_hash_str_add_ptr(&php_com_typelibraries, typelib_name, typelib_name_len, TL)) {
php_com_import_typelib(TL, mode, obj->code_page);
/* add a reference for the hash */
ITypeLib_AddRef(TL);
}
} else {
/* try it anyway */
php_com_import_typelib(TL, mode, obj->code_page);
}
ITypeLib_Release(TL);
}
}
}
/* }}} */
/* {{{ proto object com_get_active_object(string progid [, int code_page ])
Returns a handle to an already running instance of a COM object */
PHP_FUNCTION(com_get_active_object)
{
CLSID clsid;
char *module_name;
size_t module_name_len;
zend_long code_page = COMG(code_page);
IUnknown *unk = NULL;
IDispatch *obj = NULL;
HRESULT res;
OLECHAR *module = NULL;
php_com_initialize();
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l",
&module_name, &module_name_len, &code_page)) {
php_com_throw_exception(E_INVALIDARG, "Invalid arguments!");
return;
}
module = php_com_string_to_olestring(module_name, module_name_len, (int)code_page);
res = CLSIDFromString(module, &clsid);
if (FAILED(res)) {
php_com_throw_exception(res, NULL);
} else {
res = GetActiveObject(&clsid, NULL, &unk);
if (FAILED(res)) {
php_com_throw_exception(res, NULL);
} else {
res = IUnknown_QueryInterface(unk, &IID_IDispatch, &obj);
if (FAILED(res)) {
php_com_throw_exception(res, NULL);
} else if (obj) {
/* we got our dispatchable object */
php_com_wrap_dispatch(return_value, obj, (int)code_page);
}
}
}
if (obj) {
IDispatch_Release(obj);
}
if (unk) {
IUnknown_Release(obj);
}
efree(module);
}
/* }}} */
/* 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)
{
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;
size_t 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);
SysFreeString(e.bstrSource);
}
if (e.bstrDescription) {
desc = php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page);
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_win32_error_to_msg(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_win32_error_to_msg(hr);
spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
LocalFree(desc);
break;
}
if (msg) {
php_com_throw_exception(hr, msg);
efree(msg);
}
}
return hr;
}
/* map an ID to a name */
HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
size_t namelen, DISPID *dispid)
{
OLECHAR *olename;
HRESULT hr;
zval *tmp;
if (namelen == -1) {
namelen = strlen(name);
}
if (obj->id_of_name_cache && NULL != (tmp = zend_hash_str_find(obj->id_of_name_cache, name, namelen))) {
*dispid = (DISPID)Z_LVAL_P(tmp);
return S_OK;
}
olename = php_com_string_to_olestring(name, namelen, obj->code_page);
if (obj->typeinfo) {
hr = ITypeInfo_GetIDsOfNames(obj->typeinfo, &olename, 1, dispid);
if (FAILED(hr)) {
hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
if (SUCCEEDED(hr)) {
/* fall back on IDispatch direct */
ITypeInfo_Release(obj->typeinfo);
obj->typeinfo = NULL;
}
}
} else {
hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
}
efree(olename);
if (SUCCEEDED(hr)) {
zval tmp;
/* cache the mapping */
if (!obj->id_of_name_cache) {
ALLOC_HASHTABLE(obj->id_of_name_cache);
zend_hash_init(obj->id_of_name_cache, 2, NULL, NULL, 0);
}
ZVAL_LONG(&tmp, *dispid);
zend_hash_str_update(obj->id_of_name_cache, name, namelen, &tmp);
}
return hr;
}
/* the core of COM */
int php_com_do_invoke_byref(php_com_dotnet_object *obj, zend_internal_function *f,
WORD flags, VARIANT *v, int nargs, zval *args)
{
DISPID dispid, altdispid;
DISPPARAMS disp_params;
HRESULT hr;
VARIANT *vargs = NULL, *byref_vals = NULL;
int i, byref_count = 0, j;
/* assumption: that the active function (f) is the function we generated for the engine */
if (!f) {
return FAILURE;
}
hr = php_com_get_id_of_name(obj, f->function_name->val, f->function_name->len, &dispid);
if (FAILED(hr)) {
char *winerr = NULL;
char *msg = NULL;
winerr = php_win32_error_to_msg(hr);
spprintf(&msg, 0, "Unable to lookup `%s': %s", f->function_name->val, winerr);
LocalFree(winerr);
php_com_throw_exception(hr, msg);
efree(msg);
return FAILURE;
}
if (nargs) {
vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
}
if (f->arg_info) {
for (i = 0; i < nargs; i++) {
if (f->arg_info[nargs - i - 1].pass_by_reference) {
byref_count++;
}
}
}
if (byref_count) {
byref_vals = (VARIANT*)safe_emalloc(sizeof(VARIANT), byref_count, 0);
for (j = 0, i = 0; i < nargs; i++) {
if (f->arg_info[nargs - i - 1].pass_by_reference) {
/* put the value into byref_vals instead */
php_com_variant_from_zval(&byref_vals[j], &args[nargs - i - 1], obj->code_page);
/* if it is already byref, "move" it into the vargs array, otherwise
* make vargs a reference to this value */
if (V_VT(&byref_vals[j]) & VT_BYREF) {
memcpy(&vargs[i], &byref_vals[j], sizeof(vargs[i]));
VariantInit(&byref_vals[j]); /* leave the variant slot empty to simplify cleanup */
} else {
VariantInit(&vargs[i]);
V_VT(&vargs[i]) = V_VT(&byref_vals[j]) | VT_BYREF;
/* union magic ensures that this works out */
vargs[i].byref = &V_UINT(&byref_vals[j]);
}
j++;
} else {
php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
}
}
} else {
/* Invoke'd args are in reverse order */
for (i = 0; i < nargs; i++) {
php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
}
}
disp_params.cArgs = nargs;
disp_params.cNamedArgs = 0;
disp_params.rgvarg = vargs;
disp_params.rgdispidNamedArgs = NULL;
if (flags & DISPATCH_PROPERTYPUT) {
altdispid = DISPID_PROPERTYPUT;
disp_params.rgdispidNamedArgs = &altdispid;
disp_params.cNamedArgs = 1;
}
/* this will create an exception if needed */
hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, 0, 0);
/* release variants */
if (vargs) {
if (f && f->arg_info) {
for (i = 0, j = 0; i < nargs; i++) {
/* if this was byref, update the zval */
if (f->arg_info[nargs - i - 1].pass_by_reference) {
zval *arg = &args[nargs - i - 1];
ZVAL_DEREF(arg);
zval_ptr_dtor(arg);
ZVAL_NULL(arg);
/* if the variant is pointing at the byref_vals, we need to map
* the pointee value as a zval; otherwise, the value is pointing
* into an existing PHP variant record */
if (V_VT(&vargs[i]) & VT_BYREF) {
if (vargs[i].byref == &V_UINT(&byref_vals[j])) {
/* copy that value */
php_com_zval_from_variant(arg, &byref_vals[j], obj->code_page);
}
} else {
/* not sure if this can ever happen; the variant we marked as BYREF
* is no longer BYREF - copy its value */
php_com_zval_from_variant(arg, &vargs[i], obj->code_page);
}
VariantClear(&byref_vals[j]);
j++;
}
VariantClear(&vargs[i]);
}
} else {
for (i = 0, j = 0; i < nargs; i++) {
VariantClear(&vargs[i]);
}
}
efree(vargs);
}
return SUCCEEDED(hr) ? SUCCESS : FAILURE;
}
int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
WORD flags, VARIANT *v, int nargs, zval *args, int silent, int allow_noarg)
{
DISPID altdispid;
DISPPARAMS disp_params;
HRESULT hr;
VARIANT *vargs = NULL;
int i;
if (nargs) {
vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
}
/* Invoke'd args are in reverse order */
for (i = 0; i < nargs; i++) {
php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
}
disp_params.cArgs = nargs;
disp_params.cNamedArgs = 0;
disp_params.rgvarg = vargs;
disp_params.rgdispidNamedArgs = NULL;
if (flags & DISPATCH_PROPERTYPUT) {
altdispid = DISPID_PROPERTYPUT;
disp_params.rgdispidNamedArgs = &altdispid;
disp_params.cNamedArgs = 1;
}
/* this will create an exception if needed */
hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, silent, allow_noarg);
/* release variants */
if (vargs) {
for (i = 0; i < nargs; i++) {
VariantClear(&vargs[i]);
}
efree(vargs);
}
/* a bit of a hack this, but it's needed for COM array access. */
if (hr == DISP_E_BADPARAMCOUNT)
return hr;
return SUCCEEDED(hr) ? SUCCESS : FAILURE;
}
int php_com_do_invoke(php_com_dotnet_object *obj, char *name, size_t namelen,
WORD flags, VARIANT *v, int nargs, zval *args, int allow_noarg)
{
DISPID dispid;
HRESULT hr;
char *winerr = NULL;
char *msg = NULL;
hr = php_com_get_id_of_name(obj, name, namelen, &dispid);
if (FAILED(hr)) {
winerr = php_win32_error_to_msg(hr);
spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
LocalFree(winerr);
php_com_throw_exception(hr, msg);
efree(msg);
return FAILURE;
}
return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args, 0, allow_noarg);
}
/* {{{ proto string com_create_guid()
Generate a globally unique identifier (GUID) */
PHP_FUNCTION(com_create_guid)
{
GUID retval;
OLECHAR *guid_string;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
php_com_initialize();
if (CoCreateGuid(&retval) == S_OK && StringFromCLSID(&retval, &guid_string) == S_OK) {
size_t len;
char *str;
str = php_com_olestring_to_string(guid_string, &len, CP_ACP);
RETVAL_STRINGL(str, len);
// TODO: avoid reallocation ???
efree(str);
CoTaskMemFree(guid_string);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool com_event_sink(object comobject, object sinkobject [, mixed sinkinterface])
Connect events from a COM object to a PHP object */
PHP_FUNCTION(com_event_sink)
{
zval *object, *sinkobject, *sink=NULL;
char *dispname = NULL, *typelibname = NULL;
php_com_dotnet_object *obj;
ITypeInfo *typeinfo = NULL;
RETVAL_FALSE;
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Oo|z/",
&object, php_com_variant_class_entry, &sinkobject, &sink)) {
RETURN_FALSE;
}
php_com_initialize();
obj = CDNO_FETCH(object);
if (sink && Z_TYPE_P(sink) == IS_ARRAY) {
/* 0 => typelibname, 1 => dispname */
zval *tmp;
if ((tmp = zend_hash_index_find(Z_ARRVAL_P(sink), 0)) != NULL && Z_TYPE_P(tmp) == IS_STRING)
typelibname = Z_STRVAL_P(tmp);
if ((tmp = zend_hash_index_find(Z_ARRVAL_P(sink), 1)) != NULL && Z_TYPE_P(tmp) == IS_STRING)
dispname = Z_STRVAL_P(tmp);
} else if (sink != NULL) {
convert_to_string(sink);
dispname = Z_STRVAL_P(sink);
}
typeinfo = php_com_locate_typeinfo(typelibname, obj, dispname, 1);
if (typeinfo) {
HashTable *id_to_name;
ALLOC_HASHTABLE(id_to_name);
if (php_com_process_typeinfo(typeinfo, id_to_name, 0, &obj->sink_id, obj->code_page)) {
/* Create the COM wrapper for this sink */
obj->sink_dispatch = php_com_wrapper_export_as_sink(sinkobject, &obj->sink_id, id_to_name);
/* Now hook it up to the source */
php_com_object_enable_event_sink(obj, TRUE);
RETVAL_TRUE;
} else {
FREE_HASHTABLE(id_to_name);
}
}
if (typeinfo) {
ITypeInfo_Release(typeinfo);
}
}
/* }}} */
/* {{{ proto bool com_print_typeinfo(object comobject | string typelib, string dispinterface, bool wantsink)
Print out a PHP class definition for a dispatchable interface */
PHP_FUNCTION(com_print_typeinfo)
{
zval *arg1;
char *ifacename = NULL;
char *typelibname = NULL;
size_t ifacelen;
zend_bool wantsink = 0;
php_com_dotnet_object *obj = NULL;
ITypeInfo *typeinfo;
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "z/|s!b", &arg1, &ifacename,
&ifacelen, &wantsink)) {
RETURN_FALSE;
}
php_com_initialize();
if (Z_TYPE_P(arg1) == IS_OBJECT) {
CDNO_FETCH_VERIFY(obj, arg1);
} else {
convert_to_string(arg1);
typelibname = Z_STRVAL_P(arg1);
}
typeinfo = php_com_locate_typeinfo(typelibname, obj, ifacename, wantsink ? 1 : 0);
if (typeinfo) {
php_com_process_typeinfo(typeinfo, NULL, 1, NULL, obj ? obj->code_page : COMG(code_page));
ITypeInfo_Release(typeinfo);
RETURN_TRUE;
} else {
zend_error(E_WARNING, "Unable to find typeinfo using the parameters supplied");
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto bool com_message_pump([int timeoutms])
Process COM messages, sleeping for up to timeoutms milliseconds */
PHP_FUNCTION(com_message_pump)
{
zend_long timeoutms = 0;
MSG msg;
DWORD result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &timeoutms) == FAILURE)
RETURN_FALSE;
php_com_initialize();
result = MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)timeoutms, QS_ALLINPUT);
if (result == WAIT_OBJECT_0) {
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* we processed messages */
RETVAL_TRUE;
} else {
/* we did not process messages (timed out) */
RETVAL_FALSE;
}
}
/* }}} */
/* {{{ proto bool com_load_typelib(string typelib_name [, bool case_insensitive])
Loads a Typelibrary and registers its constants */
PHP_FUNCTION(com_load_typelib)
{
char *name;
size_t namelen;
ITypeLib *pTL = NULL;
zend_bool cs = TRUE;
int codepage = COMG(code_page);
int cached = 0;
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &name, &namelen, &cs)) {
return;
}
RETVAL_FALSE;
php_com_initialize();
pTL = php_com_load_typelib_via_cache(name, codepage, &cached);
if (pTL) {
if (cached) {
RETVAL_TRUE;
} else if (php_com_import_typelib(pTL, cs ? CONST_CS : 0, codepage) == SUCCESS) {
RETVAL_TRUE;
}
ITypeLib_Release(pTL);
pTL = NULL;
}
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/