File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / com_dotnet / com_com.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:36 2012 UTC (12 years, 2 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2012 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:    +----------------------------------------------------------------------+
   17:  */
   18: 
   19: /* $Id: com_com.c,v 1.1.1.2 2012/05/29 12:34:36 misho Exp $ */
   20: 
   21: #ifdef HAVE_CONFIG_H
   22: #include "config.h"
   23: #endif
   24: 
   25: #include "php.h"
   26: #include "php_ini.h"
   27: #include "ext/standard/info.h"
   28: #include "php_com_dotnet.h"
   29: #include "php_com_dotnet_internal.h"
   30: #include "Zend/zend_exceptions.h"
   31: 
   32: /* {{{ com_create_instance - ctor for COM class */
   33: PHP_FUNCTION(com_create_instance)
   34: {
   35: 	zval *object = getThis();
   36: 	zval *server_params = NULL;
   37: 	php_com_dotnet_object *obj;
   38: 	char *module_name, *typelib_name = NULL, *server_name = NULL;
   39: 	char *user_name = NULL, *domain_name = NULL, *password = NULL;
   40: 	int module_name_len, typelib_name_len, server_name_len,
   41: 		user_name_len, domain_name_len, password_len;
   42: 	OLECHAR *moniker;
   43: 	CLSID clsid;
   44: 	CLSCTX ctx = CLSCTX_SERVER;
   45: 	HRESULT res = E_FAIL;
   46: 	int mode = COMG(autoreg_case_sensitive) ? CONST_CS : 0;
   47: 	ITypeLib *TL = NULL;
   48: 	COSERVERINFO	info;
   49: 	COAUTHIDENTITY	authid = {0};
   50: 	COAUTHINFO		authinfo = {
   51: 		RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
   52: 		RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE,
   53: 		&authid, EOAC_NONE
   54: 	};
   55: 
   56: 	php_com_initialize(TSRMLS_C);
   57: 	obj = CDNO_FETCH(object);
   58: 
   59: 	if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
   60: 			ZEND_NUM_ARGS() TSRMLS_CC, "s|s!ls",
   61: 			&module_name, &module_name_len, &server_name, &server_name_len,
   62: 			&obj->code_page, &typelib_name, &typelib_name_len) &&
   63: 		FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
   64: 			ZEND_NUM_ARGS() TSRMLS_CC, "sa|ls",
   65: 			&module_name, &module_name_len, &server_params, &obj->code_page,
   66: 			&typelib_name, &typelib_name_len)) {
   67: 
   68: 		php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid arguments!" TSRMLS_CC);
   69: 		ZVAL_NULL(object);
   70: 		return;
   71: 	}
   72: 
   73: 	if (server_name) {
   74: 		ctx = CLSCTX_REMOTE_SERVER;
   75: 	} else if (server_params) {
   76: 		zval **tmp;
   77: 
   78: 		/* decode the data from the array */
   79: 
   80: 		if (SUCCESS == zend_hash_find(HASH_OF(server_params),
   81: 				"Server", sizeof("Server"), (void**)&tmp)) {
   82: 			convert_to_string_ex(tmp);
   83: 			server_name = Z_STRVAL_PP(tmp);
   84: 			server_name_len = Z_STRLEN_PP(tmp);
   85: 			ctx = CLSCTX_REMOTE_SERVER;
   86: 		}
   87: 
   88: 		if (SUCCESS == zend_hash_find(HASH_OF(server_params),
   89: 				"Username", sizeof("Username"), (void**)&tmp)) {
   90: 			convert_to_string_ex(tmp);
   91: 			user_name = Z_STRVAL_PP(tmp);
   92: 			user_name_len = Z_STRLEN_PP(tmp);
   93: 		}
   94: 
   95: 		if (SUCCESS == zend_hash_find(HASH_OF(server_params),
   96: 				"Password", sizeof("Password"), (void**)&tmp)) {
   97: 			convert_to_string_ex(tmp);
   98: 			password = Z_STRVAL_PP(tmp);
   99: 			password_len = Z_STRLEN_PP(tmp);
  100: 		}
  101: 
  102: 		if (SUCCESS == zend_hash_find(HASH_OF(server_params),
  103: 				"Domain", sizeof("Domain"), (void**)&tmp)) {
  104: 			convert_to_string_ex(tmp);
  105: 			domain_name = Z_STRVAL_PP(tmp);
  106: 			domain_name_len = Z_STRLEN_PP(tmp);
  107: 		}
  108: 
  109: 		if (SUCCESS == zend_hash_find(HASH_OF(server_params),
  110: 				"Flags", sizeof("Flags"), (void**)&tmp)) {
  111: 			convert_to_long_ex(tmp);
  112: 			ctx = (CLSCTX)Z_LVAL_PP(tmp);
  113: 		}
  114: 	}
  115: 
  116: 	if (server_name && !COMG(allow_dcom)) {
  117: 		php_com_throw_exception(E_ERROR, "DCOM has been disabled by your administrator [com.allow_dcom=0]" TSRMLS_CC);
  118: 		return;
  119: 	}
  120: 
  121: 	moniker = php_com_string_to_olestring(module_name, module_name_len, obj->code_page TSRMLS_CC);
  122: 
  123: 	/* if instantiating a remote object, either directly, or via
  124: 	 * a moniker, fill in the relevant info */
  125: 	if (server_name) {
  126: 		info.dwReserved1 = 0;
  127: 		info.dwReserved2 = 0;
  128: 		info.pwszName = php_com_string_to_olestring(server_name, server_name_len, obj->code_page TSRMLS_CC);
  129: 
  130: 		if (user_name) {
  131: 			authid.User = php_com_string_to_olestring(user_name, -1, obj->code_page TSRMLS_CC);
  132: 			authid.UserLength = user_name_len;
  133: 
  134: 			if (password) {
  135: 				authid.Password = (OLECHAR*)password;
  136: 				authid.PasswordLength = password_len;
  137: 			} else {
  138: 				authid.Password = (OLECHAR*)"";
  139: 				authid.PasswordLength = 0;
  140: 			}
  141: 
  142: 			if (domain_name) {
  143: 				authid.Domain = (OLECHAR*)domain_name;
  144: 				authid.DomainLength = domain_name_len;
  145: 			} else {
  146: 				authid.Domain = (OLECHAR*)"";
  147: 				authid.DomainLength = 0;
  148: 			}
  149: 			authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  150: 			info.pAuthInfo = &authinfo;
  151: 		} else {
  152: 			info.pAuthInfo = NULL;
  153: 		}
  154: 	}
  155: 
  156: 	if (FAILED(CLSIDFromString(moniker, &clsid))) {
  157: 		/* try to use it as a moniker */
  158: 		IBindCtx *pBindCtx = NULL;
  159: 		IMoniker *pMoniker = NULL;
  160: 		ULONG ulEaten;
  161: 		BIND_OPTS2 bopt = {0};
  162: 
  163: 		if (SUCCEEDED(res = CreateBindCtx(0, &pBindCtx))) {
  164: 			if (server_name) {
  165: 				/* fill in the remote server info.
  166: 				 * MSDN docs indicate that this might be ignored in
  167: 				 * current win32 implementations, but at least we are
  168: 				 * doing the right thing in readiness for the day that
  169: 				 * it does work */
  170: 				bopt.cbStruct = sizeof(bopt);
  171: 				IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
  172: 				bopt.pServerInfo = &info;
  173: 				/* apparently, GetBindOptions will only ever return
  174: 				 * a regular BIND_OPTS structure.  My gut feeling is
  175: 				 * that it will modify the size field to reflect that
  176: 				 * so lets be safe and set it to the BIND_OPTS2 size
  177: 				 * again */
  178: 				bopt.cbStruct = sizeof(bopt);
  179: 				IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
  180: 			}
  181: 			
  182: 			if (SUCCEEDED(res = MkParseDisplayName(pBindCtx, moniker, &ulEaten, &pMoniker))) {
  183: 				res = IMoniker_BindToObject(pMoniker, pBindCtx,
  184: 					NULL, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
  185: 			
  186: 				if (SUCCEEDED(res)) {
  187: 					V_VT(&obj->v) = VT_DISPATCH;
  188: 				}
  189: 
  190: 				IMoniker_Release(pMoniker);
  191: 			}
  192: 		}
  193: 		if (pBindCtx) {
  194: 			IBindCtx_Release(pBindCtx);
  195: 		}
  196: 	} else if (server_name) {
  197: 		MULTI_QI		qi;
  198: 
  199: 		qi.pIID = &IID_IDispatch;
  200: 		qi.pItf = NULL;
  201: 		qi.hr = S_OK;
  202: 
  203: 		res = CoCreateInstanceEx(&clsid, NULL, ctx, &info, 1, &qi);
  204: 
  205: 		if (SUCCEEDED(res)) {
  206: 			res = qi.hr;
  207: 			V_DISPATCH(&obj->v) = (IDispatch*)qi.pItf;
  208: 			V_VT(&obj->v) = VT_DISPATCH;
  209: 		}
  210: 	} else {
  211: 		res = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
  212: 		if (SUCCEEDED(res)) {
  213: 			V_VT(&obj->v) = VT_DISPATCH;
  214: 		}
  215: 	}
  216: 
  217: 	if (server_name) {
  218: 		STR_FREE((char*)info.pwszName);
  219: 		STR_FREE((char*)authid.User);
  220: 	}
  221: 
  222: 	efree(moniker);
  223: 
  224: 	if (FAILED(res)) {
  225: 		char *werr, *msg;
  226: 
  227: 		werr = php_win32_error_to_msg(res);
  228: 		spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, werr);
  229: 		LocalFree(werr);
  230: 
  231: 		php_com_throw_exception(res, msg TSRMLS_CC);
  232: 		efree(msg);
  233: 		ZVAL_NULL(object);
  234: 		return;
  235: 	}
  236: 
  237: 	/* we got the object and it lives ! */
  238: 
  239: 	/* see if it has TypeInfo available */
  240: 	if (FAILED(IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo)) && typelib_name) {
  241: 		/* load up the library from the named file */
  242: 		int cached;
  243: 
  244: 		TL = php_com_load_typelib_via_cache(typelib_name, obj->code_page, &cached TSRMLS_CC);
  245: 
  246: 		if (TL) {
  247: 			if (COMG(autoreg_on) && !cached) {
  248: 				php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
  249: 			}
  250: 
  251: 			/* cross your fingers... there is no guarantee that this ITypeInfo
  252: 			 * instance has any relation to this IDispatch instance... */
  253: 			ITypeLib_GetTypeInfo(TL, 0, &obj->typeinfo);
  254: 			ITypeLib_Release(TL);
  255: 		}
  256: 	} else if (obj->typeinfo && COMG(autoreg_on)) {
  257: 		int idx;
  258: 
  259: 		if (SUCCEEDED(ITypeInfo_GetContainingTypeLib(obj->typeinfo, &TL, &idx))) {
  260: 			/* check if the library is already in the cache by getting its name */
  261: 			BSTR name;
  262: 
  263: 			if (SUCCEEDED(ITypeLib_GetDocumentation(TL, -1, &name, NULL, NULL, NULL))) {
  264: 				typelib_name = php_com_olestring_to_string(name, &typelib_name_len, obj->code_page TSRMLS_CC);
  265: 
  266: 				if (SUCCESS == zend_ts_hash_add(&php_com_typelibraries, typelib_name, typelib_name_len+1, (void*)&TL, sizeof(ITypeLib*), NULL)) {
  267: 					php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
  268: 
  269: 					/* add a reference for the hash */
  270: 					ITypeLib_AddRef(TL);
  271: 				}
  272: 
  273: 			} else {
  274: 				/* try it anyway */
  275: 				php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
  276: 			}
  277: 
  278: 			ITypeLib_Release(TL);
  279: 		}
  280: 	}
  281: 
  282: }
  283: /* }}} */
  284: 
  285: /* {{{ proto object com_get_active_object(string progid [, int code_page ])
  286:    Returns a handle to an already running instance of a COM object */
  287: PHP_FUNCTION(com_get_active_object)
  288: {
  289: 	CLSID clsid;
  290: 	char *module_name;
  291: 	int module_name_len;
  292: 	long code_page = COMG(code_page);
  293: 	IUnknown *unk = NULL;
  294: 	IDispatch *obj = NULL;
  295: 	HRESULT res;
  296: 	OLECHAR *module = NULL;
  297: 
  298: 	php_com_initialize(TSRMLS_C);
  299: 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
  300: 				&module_name, &module_name_len, &code_page)) {
  301: 		php_com_throw_exception(E_INVALIDARG, "Invalid arguments!" TSRMLS_CC);
  302: 		return;
  303: 	}
  304: 
  305: 	module = php_com_string_to_olestring(module_name, module_name_len, code_page TSRMLS_CC);
  306: 
  307: 	res = CLSIDFromString(module, &clsid);
  308: 
  309: 	if (FAILED(res)) {
  310: 		php_com_throw_exception(res, NULL TSRMLS_CC);
  311: 	} else {
  312: 		res = GetActiveObject(&clsid, NULL, &unk);
  313: 
  314: 		if (FAILED(res)) {
  315: 			php_com_throw_exception(res, NULL TSRMLS_CC);
  316: 		} else {
  317: 			res = IUnknown_QueryInterface(unk, &IID_IDispatch, &obj);
  318: 
  319: 			if (FAILED(res)) {
  320: 				php_com_throw_exception(res, NULL TSRMLS_CC);
  321: 			} else if (obj) {
  322: 				/* we got our dispatchable object */
  323: 				php_com_wrap_dispatch(return_value, obj, code_page TSRMLS_CC);
  324: 			}
  325: 		}
  326: 	}
  327: 
  328: 	if (obj) {
  329: 		IDispatch_Release(obj);
  330: 	}
  331: 	if (unk) {
  332: 		IUnknown_Release(obj);
  333: 	}
  334: 	efree(module);
  335: }
  336: /* }}} */
  337: 
  338: /* Performs an Invoke on the given com object.
  339:  * returns a failure code and creates an exception if there was an error */
  340: HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
  341: 		WORD flags, DISPPARAMS *disp_params, VARIANT *v, int silent, int allow_noarg TSRMLS_DC)
  342: {
  343: 	HRESULT hr;
  344: 	unsigned int arg_err;
  345: 	EXCEPINFO e = {0};
  346: 
  347: 	hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
  348: 		&IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, v, &e, &arg_err);
  349: 
  350: 	if (silent == 0 && FAILED(hr)) {
  351: 		char *source = NULL, *desc = NULL, *msg = NULL;
  352: 		int source_len, desc_len;
  353: 
  354: 		switch (hr) {
  355: 			case DISP_E_EXCEPTION:
  356: 				if (e.bstrSource) {
  357: 					source = php_com_olestring_to_string(e.bstrSource, &source_len, obj->code_page TSRMLS_CC);
  358: 					SysFreeString(e.bstrSource);
  359: 				}
  360: 				if (e.bstrDescription) {
  361: 					desc = php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page TSRMLS_CC);
  362: 					SysFreeString(e.bstrDescription);
  363: 				}
  364: 				if (PG(html_errors)) {
  365: 					spprintf(&msg, 0, "<b>Source:</b> %s<br/><b>Description:</b> %s",
  366: 						source ? source : "Unknown",
  367: 						desc ? desc : "Unknown");
  368: 				} else {
  369: 					spprintf(&msg, 0, "Source: %s\nDescription: %s",
  370: 						source ? source : "Unknown",
  371: 						desc ? desc : "Unknown");
  372: 				}
  373: 				if (desc) {
  374: 					efree(desc);
  375: 				}
  376: 				if (source) {
  377: 					efree(source);
  378: 				}
  379: 				if (e.bstrHelpFile) {
  380: 					SysFreeString(e.bstrHelpFile);
  381: 				}
  382: 				break;
  383: 
  384: 			case DISP_E_PARAMNOTFOUND:
  385: 			case DISP_E_TYPEMISMATCH:
  386: 				desc = php_win32_error_to_msg(hr);
  387: 				spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
  388: 				LocalFree(desc);
  389: 				break;
  390: 
  391: 			case DISP_E_BADPARAMCOUNT:
  392: 				if ((disp_params->cArgs + disp_params->cNamedArgs == 0) && (allow_noarg == 1)) {
  393: 					/* if getting a property and they are missing all parameters,
  394: 					 * we want to create a proxy object for them; so lets not create an
  395: 					 * exception here */
  396: 					msg = NULL;
  397: 					break;
  398: 				}
  399: 				/* else fall through */
  400: 				
  401: 			default:
  402: 				desc = php_win32_error_to_msg(hr);
  403: 				spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
  404: 				LocalFree(desc);
  405: 				break;
  406: 		}
  407: 
  408: 		if (msg) {
  409: 			php_com_throw_exception(hr, msg TSRMLS_CC);
  410: 			efree(msg);
  411: 		}
  412: 	}
  413: 
  414: 	return hr;
  415: }
  416: 
  417: /* map an ID to a name */
  418: HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
  419: 		int namelen, DISPID *dispid TSRMLS_DC)
  420: {
  421: 	OLECHAR *olename;
  422: 	HRESULT hr;
  423: 	DISPID *dispid_ptr;
  424: 
  425: 	if (namelen == -1) {
  426: 		namelen = strlen(name);
  427: 	}
  428: 
  429: 	if (obj->id_of_name_cache && SUCCESS == zend_hash_find(obj->id_of_name_cache, name, namelen, (void**)&dispid_ptr)) {
  430: 		*dispid = *dispid_ptr;
  431: 		return S_OK;
  432: 	}
  433: 	
  434: 	olename = php_com_string_to_olestring(name, namelen, obj->code_page TSRMLS_CC);
  435: 
  436: 	if (obj->typeinfo) {
  437: 		hr = ITypeInfo_GetIDsOfNames(obj->typeinfo, &olename, 1, dispid);
  438: 		if (FAILED(hr)) {
  439: 			hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
  440: 			if (SUCCEEDED(hr)) {
  441: 				/* fall back on IDispatch direct */
  442: 				ITypeInfo_Release(obj->typeinfo);
  443: 				obj->typeinfo = NULL;
  444: 			}
  445: 		}
  446: 	} else {
  447: 		hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
  448: 	}
  449: 	efree(olename);
  450: 
  451: 	if (SUCCEEDED(hr)) {
  452: 		/* cache the mapping */
  453: 		if (!obj->id_of_name_cache) {
  454: 			ALLOC_HASHTABLE(obj->id_of_name_cache);
  455: 			zend_hash_init(obj->id_of_name_cache, 2, NULL, NULL, 0);
  456: 		}
  457: 		zend_hash_update(obj->id_of_name_cache, name, namelen, dispid, sizeof(*dispid), NULL);
  458: 	}
  459: 	
  460: 	return hr;
  461: }
  462: 
  463: /* the core of COM */
  464: int php_com_do_invoke_byref(php_com_dotnet_object *obj, char *name, int namelen,
  465: 		WORD flags,	VARIANT *v, int nargs, zval ***args TSRMLS_DC)
  466: {
  467: 	DISPID dispid, altdispid;
  468: 	DISPPARAMS disp_params;
  469: 	HRESULT hr;
  470: 	VARIANT *vargs = NULL, *byref_vals = NULL;
  471: 	int i, byref_count = 0, j;
  472: 	zend_internal_function *f = (zend_internal_function*)EG(current_execute_data)->function_state.function;
  473: 
  474: 	/* assumption: that the active function (f) is the function we generated for the engine */
  475: 	if (!f || f->arg_info == NULL) {
  476: 	   f = NULL;
  477: 	}
  478: 	
  479: 	hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);
  480: 
  481: 	if (FAILED(hr)) {
  482: 		char *winerr = NULL;
  483: 		char *msg = NULL;
  484: 		winerr = php_win32_error_to_msg(hr);
  485: 		spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
  486: 		LocalFree(winerr);
  487: 		php_com_throw_exception(hr, msg TSRMLS_CC);
  488: 		efree(msg);
  489: 		return FAILURE;
  490: 	}
  491: 
  492: 
  493: 	if (nargs) {
  494: 		vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
  495: 	}
  496: 
  497: 	if (f) {
  498: 		for (i = 0; i < nargs; i++) {
  499: 			if (f->arg_info[nargs - i - 1].pass_by_reference) {
  500: 				byref_count++;
  501: 			}
  502: 		}
  503: 	}
  504: 
  505: 	if (byref_count) {
  506: 		byref_vals = (VARIANT*)safe_emalloc(sizeof(VARIANT), byref_count, 0);
  507: 		for (j = 0, i = 0; i < nargs; i++) {
  508: 			if (f->arg_info[nargs - i - 1].pass_by_reference) {
  509: 				/* put the value into byref_vals instead */
  510: 				php_com_variant_from_zval(&byref_vals[j], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
  511: 
  512: 				/* if it is already byref, "move" it into the vargs array, otherwise
  513: 				 * make vargs a reference to this value */
  514: 				if (V_VT(&byref_vals[j]) & VT_BYREF) {
  515: 					memcpy(&vargs[i], &byref_vals[j], sizeof(vargs[i]));
  516: 					VariantInit(&byref_vals[j]); /* leave the variant slot empty to simplify cleanup */
  517: 				} else {
  518: 					VariantInit(&vargs[i]);
  519: 					V_VT(&vargs[i]) = V_VT(&byref_vals[j]) | VT_BYREF;
  520: 					/* union magic ensures that this works out */
  521: 					vargs[i].byref = &V_UINT(&byref_vals[j]);
  522: 				}
  523: 				j++;
  524: 			} else {
  525: 				php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
  526: 			}
  527: 		}
  528: 		
  529: 	} else {
  530: 		/* Invoke'd args are in reverse order */
  531: 		for (i = 0; i < nargs; i++) {
  532: 			php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
  533: 		}
  534: 	}
  535: 
  536: 	disp_params.cArgs = nargs;
  537: 	disp_params.cNamedArgs = 0;
  538: 	disp_params.rgvarg = vargs;
  539: 	disp_params.rgdispidNamedArgs = NULL;
  540: 
  541: 	if (flags & DISPATCH_PROPERTYPUT) {
  542: 		altdispid = DISPID_PROPERTYPUT;
  543: 		disp_params.rgdispidNamedArgs = &altdispid;
  544: 		disp_params.cNamedArgs = 1;
  545: 	}
  546: 
  547: 	/* this will create an exception if needed */
  548: 	hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, 0, 0 TSRMLS_CC);	
  549: 
  550: 	/* release variants */
  551: 	if (vargs) {
  552: 		for (i = 0, j = 0; i < nargs; i++) {
  553: 			/* if this was byref, update the zval */
  554: 			if (f && f->arg_info[nargs - i - 1].pass_by_reference) {
  555: 				SEPARATE_ZVAL_IF_NOT_REF(args[nargs - i - 1]);
  556: 
  557: 				/* if the variant is pointing at the byref_vals, we need to map
  558: 				 * the pointee value as a zval; otherwise, the value is pointing
  559: 				 * into an existing PHP variant record */
  560: 				if (V_VT(&vargs[i]) & VT_BYREF) {
  561: 					if (vargs[i].byref == &V_UINT(&byref_vals[j])) {
  562: 						/* copy that value */
  563: 						php_com_zval_from_variant(*args[nargs - i - 1], &byref_vals[j],
  564: 							obj->code_page TSRMLS_CC);
  565: 					}
  566: 				} else {
  567: 					/* not sure if this can ever happen; the variant we marked as BYREF
  568: 					 * is no longer BYREF - copy its value */
  569: 					php_com_zval_from_variant(*args[nargs - i - 1], &vargs[i],
  570: 						obj->code_page TSRMLS_CC);
  571: 				}
  572: 				VariantClear(&byref_vals[j]);
  573: 				j++;
  574: 			}	
  575: 			VariantClear(&vargs[i]);
  576: 		}
  577: 		efree(vargs);
  578: 	}
  579: 
  580: 	return SUCCEEDED(hr) ? SUCCESS : FAILURE;
  581: }
  582: 
  583: 
  584: 
  585: int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
  586: 		WORD flags,	VARIANT *v, int nargs, zval **args, int silent, int allow_noarg TSRMLS_DC)
  587: {
  588: 	DISPID altdispid;
  589: 	DISPPARAMS disp_params;
  590: 	HRESULT hr;
  591: 	VARIANT *vargs = NULL;
  592: 	int i;
  593: 
  594: 	if (nargs) {
  595: 		vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
  596: 	}
  597: 
  598: 	/* Invoke'd args are in reverse order */
  599: 	for (i = 0; i < nargs; i++) {
  600: 		php_com_variant_from_zval(&vargs[i], args[nargs - i - 1], obj->code_page TSRMLS_CC);
  601: 	}
  602: 
  603: 	disp_params.cArgs = nargs;
  604: 	disp_params.cNamedArgs = 0;
  605: 	disp_params.rgvarg = vargs;
  606: 	disp_params.rgdispidNamedArgs = NULL;
  607: 
  608: 	if (flags & DISPATCH_PROPERTYPUT) {
  609: 		altdispid = DISPID_PROPERTYPUT;
  610: 		disp_params.rgdispidNamedArgs = &altdispid;
  611: 		disp_params.cNamedArgs = 1;
  612: 	}
  613: 
  614: 	/* this will create an exception if needed */
  615: 	hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, silent, allow_noarg TSRMLS_CC);	
  616: 
  617: 	/* release variants */
  618: 	if (vargs) {
  619: 		for (i = 0; i < nargs; i++) {
  620: 			VariantClear(&vargs[i]);
  621: 		}
  622: 		efree(vargs);
  623: 	}
  624: 
  625: 	/* a bit of a hack this, but it's needed for COM array access. */
  626: 	if (hr == DISP_E_BADPARAMCOUNT)
  627: 		return hr;
  628: 	
  629: 	return SUCCEEDED(hr) ? SUCCESS : FAILURE;
  630: }
  631: 
  632: int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
  633: 		WORD flags,	VARIANT *v, int nargs, zval **args, int allow_noarg TSRMLS_DC)
  634: {
  635: 	DISPID dispid;
  636: 	HRESULT hr;
  637: 	char *winerr = NULL;
  638: 	char *msg = NULL;
  639: 
  640: 	hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);
  641: 
  642: 	if (FAILED(hr)) {
  643: 		winerr = php_win32_error_to_msg(hr);
  644: 		spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
  645: 		LocalFree(winerr);
  646: 		php_com_throw_exception(hr, msg TSRMLS_CC);
  647: 		efree(msg);
  648: 		return FAILURE;
  649: 	}
  650: 
  651: 	return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args, 0, allow_noarg TSRMLS_CC);
  652: }
  653: 
  654: /* {{{ proto string com_create_guid()
  655:    Generate a globally unique identifier (GUID) */
  656: PHP_FUNCTION(com_create_guid)
  657: {
  658: 	GUID retval;
  659: 	OLECHAR *guid_string;
  660: 
  661: 	if (zend_parse_parameters_none() == FAILURE) {
  662: 		return;
  663: 	}
  664: 
  665: 	php_com_initialize(TSRMLS_C);
  666: 	if (CoCreateGuid(&retval) == S_OK && StringFromCLSID(&retval, &guid_string) == S_OK) {
  667: 		Z_TYPE_P(return_value) = IS_STRING;
  668: 		Z_STRVAL_P(return_value) = php_com_olestring_to_string(guid_string, &Z_STRLEN_P(return_value), CP_ACP TSRMLS_CC);
  669: 
  670: 		CoTaskMemFree(guid_string);
  671: 	} else {
  672: 		RETURN_FALSE;
  673: 	}
  674: }
  675: /* }}} */
  676: 
  677: /* {{{ proto bool com_event_sink(object comobject, object sinkobject [, mixed sinkinterface])
  678:    Connect events from a COM object to a PHP object */
  679: PHP_FUNCTION(com_event_sink)
  680: {
  681: 	zval *object, *sinkobject, *sink=NULL;
  682: 	char *dispname = NULL, *typelibname = NULL;
  683: 	zend_bool gotguid = 0;
  684: 	php_com_dotnet_object *obj;
  685: 	ITypeInfo *typeinfo = NULL;
  686: 
  687: 	RETVAL_FALSE;
  688: 	
  689: 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oo|z/",
  690: 			&object, php_com_variant_class_entry, &sinkobject, &sink)) {
  691: 		RETURN_FALSE;
  692: 	}
  693: 
  694: 	php_com_initialize(TSRMLS_C);
  695: 	obj = CDNO_FETCH(object);
  696: 	
  697: 	if (sink && Z_TYPE_P(sink) == IS_ARRAY) {
  698: 		/* 0 => typelibname, 1 => dispname */
  699: 		zval **tmp;
  700: 
  701: 		if (zend_hash_index_find(Z_ARRVAL_P(sink), 0, (void**)&tmp) == SUCCESS)
  702: 			typelibname = Z_STRVAL_PP(tmp);
  703: 		if (zend_hash_index_find(Z_ARRVAL_P(sink), 1, (void**)&tmp) == SUCCESS)
  704: 			dispname = Z_STRVAL_PP(tmp);
  705: 	} else if (sink != NULL) {
  706: 		convert_to_string(sink);
  707: 		dispname = Z_STRVAL_P(sink);
  708: 	}
  709: 	
  710: 	typeinfo = php_com_locate_typeinfo(typelibname, obj, dispname, 1 TSRMLS_CC);
  711: 
  712: 	if (typeinfo) {
  713: 		HashTable *id_to_name;
  714: 		
  715: 		ALLOC_HASHTABLE(id_to_name);
  716: 		
  717: 		if (php_com_process_typeinfo(typeinfo, id_to_name, 0, &obj->sink_id, obj->code_page TSRMLS_CC)) {
  718: 
  719: 			/* Create the COM wrapper for this sink */
  720: 			obj->sink_dispatch = php_com_wrapper_export_as_sink(sinkobject, &obj->sink_id, id_to_name TSRMLS_CC);
  721: 
  722: 			/* Now hook it up to the source */
  723: 			php_com_object_enable_event_sink(obj, TRUE TSRMLS_CC);
  724: 			RETVAL_TRUE;
  725: 
  726: 		} else {
  727: 			FREE_HASHTABLE(id_to_name);
  728: 		}
  729: 	}
  730: 	
  731: 	if (typeinfo) {
  732: 		ITypeInfo_Release(typeinfo);
  733: 	}
  734: 
  735: }
  736: /* }}} */
  737: 
  738: /* {{{ proto bool com_print_typeinfo(object comobject | string typelib, string dispinterface, bool wantsink)
  739:    Print out a PHP class definition for a dispatchable interface */
  740: PHP_FUNCTION(com_print_typeinfo)
  741: {
  742: 	zval *arg1;
  743: 	char *ifacename = NULL;
  744: 	char *typelibname = NULL;
  745: 	int ifacelen;
  746: 	zend_bool wantsink = 0;
  747: 	php_com_dotnet_object *obj = NULL;
  748: 	ITypeInfo *typeinfo;
  749: 	
  750: 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|s!b", &arg1, &ifacename,
  751: 				&ifacelen, &wantsink)) {
  752: 		RETURN_FALSE;
  753: 	}
  754: 
  755: 	php_com_initialize(TSRMLS_C);
  756: 	if (Z_TYPE_P(arg1) == IS_OBJECT) {
  757: 		CDNO_FETCH_VERIFY(obj, arg1);
  758: 	} else {
  759: 		convert_to_string(arg1);
  760: 		typelibname = Z_STRVAL_P(arg1);
  761: 	}
  762: 
  763: 	typeinfo = php_com_locate_typeinfo(typelibname, obj, ifacename, wantsink ? 1 : 0 TSRMLS_CC);
  764: 	if (typeinfo) {
  765: 		php_com_process_typeinfo(typeinfo, NULL, 1, NULL, obj ? obj->code_page : COMG(code_page) TSRMLS_CC);
  766: 		ITypeInfo_Release(typeinfo);
  767: 		RETURN_TRUE;
  768: 	} else {
  769: 		zend_error(E_WARNING, "Unable to find typeinfo using the parameters supplied");
  770: 	}
  771: 	RETURN_FALSE;
  772: }
  773: /* }}} */
  774: 
  775: /* {{{ proto bool com_message_pump([int timeoutms])
  776:    Process COM messages, sleeping for up to timeoutms milliseconds */
  777: PHP_FUNCTION(com_message_pump)
  778: {
  779: 	long timeoutms = 0;
  780: 	MSG msg;
  781: 	DWORD result;
  782: 	
  783: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timeoutms) == FAILURE)
  784: 		RETURN_FALSE;
  785: 	
  786: 	php_com_initialize(TSRMLS_C);
  787: 	result = MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutms, QS_ALLINPUT);
  788: 
  789: 	if (result == WAIT_OBJECT_0) {
  790: 		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  791: 			TranslateMessage(&msg);
  792: 			DispatchMessage(&msg);
  793: 		}
  794: 		/* we processed messages */
  795: 		RETVAL_TRUE;
  796: 	} else {
  797: 		/* we did not process messages (timed out) */
  798: 		RETVAL_FALSE;
  799: 	}
  800: }
  801: /* }}} */
  802: 
  803: /* {{{ proto bool com_load_typelib(string typelib_name [, int case_insensitive]) 
  804:    Loads a Typelibrary and registers its constants */
  805: PHP_FUNCTION(com_load_typelib)
  806: {
  807: 	char *name;
  808: 	int namelen;
  809: 	ITypeLib *pTL = NULL;
  810: 	zend_bool cs = TRUE;
  811: 	int codepage = COMG(code_page);
  812: 	int cached = 0;
  813: 
  814: 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &name, &namelen, &cs)) {
  815: 		return;
  816: 	}
  817: 
  818: 	RETVAL_FALSE;
  819: 	
  820: 	php_com_initialize(TSRMLS_C);
  821: 	pTL = php_com_load_typelib_via_cache(name, codepage, &cached TSRMLS_CC);
  822: 	if (pTL) {
  823: 		if (cached) {
  824: 			RETVAL_TRUE;
  825: 		} else if (php_com_import_typelib(pTL, cs ? CONST_CS : 0, codepage TSRMLS_CC) == SUCCESS) {
  826: 			RETVAL_TRUE;
  827: 		}
  828: 
  829: 		ITypeLib_Release(pTL);
  830: 		pTL = NULL;
  831: 	}
  832: }
  833: /* }}} */
  834: 
  835: 
  836: 
  837: /*
  838:  * Local variables:
  839:  * tab-width: 4
  840:  * c-basic-offset: 4
  841:  * End:
  842:  * vim600: noet sw=4 ts=4 fdm=marker
  843:  * vim<600: noet sw=4 ts=4
  844:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>