2003-08-14 16:49:56 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2019-01-30 09:03:12 +00:00
| Copyright ( c ) The PHP Group |
2003-08-14 16:49:56 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 12:51:34 +00:00
| This source file is subject to version 3.01 of the PHP license , |
2003-08-14 16:49:56 +00:00
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
2006-01-01 12:51:34 +00:00
| http : //www.php.net/license/3_01.txt |
2003-08-14 16:49:56 +00:00
| 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"
2004-02-12 10:43:27 +00:00
# include "Zend/zend_exceptions.h"
2003-08-14 16:49:56 +00:00
/* {{{ com_create_instance - ctor for COM class */
2020-04-06 08:51:10 +00:00
PHP_METHOD ( com , __construct )
2003-08-14 16:49:56 +00:00
{
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 ;
2014-10-28 15:09:17 +00:00
size_t module_name_len = 0 , typelib_name_len = 0 , server_name_len = 0 ,
2003-08-14 16:49:56 +00:00
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 ;
2003-10-07 18:50:07 +00:00
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
} ;
2016-12-12 00:54:22 +00:00
zend_long cp = GetACP ( ) ;
2016-12-12 00:50:15 +00:00
const struct php_win32_cp * cp_it ;
2003-08-14 16:49:56 +00:00
if ( FAILURE = = zend_parse_parameters_ex ( ZEND_PARSE_PARAMS_QUIET ,
2014-12-13 22:06:14 +00:00
ZEND_NUM_ARGS ( ) , " s|s!ls " ,
2003-08-14 16:49:56 +00:00
& module_name , & module_name_len , & server_name , & server_name_len ,
2016-12-12 00:26:06 +00:00
& cp , & typelib_name , & typelib_name_len ) & &
2019-08-11 20:20:26 +00:00
FAILURE = = zend_parse_parameters (
2014-12-13 22:06:14 +00:00
ZEND_NUM_ARGS ( ) , " sa|ls " ,
2016-12-12 00:26:06 +00:00
& module_name , & module_name_len , & server_params , & cp ,
2003-08-14 16:49:56 +00:00
& typelib_name , & typelib_name_len ) ) {
2020-01-03 19:44:29 +00:00
RETURN_THROWS ( ) ;
2003-08-14 16:49:56 +00:00
}
2020-04-06 08:51:10 +00:00
php_com_initialize ( ) ;
obj = CDNO_FETCH ( object ) ;
2016-12-12 00:50:15 +00:00
cp_it = php_win32_cp_get_by_id ( ( DWORD ) cp ) ;
if ( ! cp_it ) {
2016-12-12 00:26:06 +00:00
php_com_throw_exception ( E_INVALIDARG , " Could not create COM object - invalid codepage! " ) ;
2020-01-03 19:44:29 +00:00
RETURN_THROWS ( ) ;
2016-12-12 00:26:06 +00:00
}
obj - > code_page = ( int ) cp ;
2003-08-14 16:49:56 +00:00
if ( server_name ) {
ctx = CLSCTX_REMOTE_SERVER ;
} else if ( server_params ) {
2014-08-11 14:37:26 +00:00
zval * tmp ;
2003-08-14 16:49:56 +00:00
/* decode the data from the array */
2015-09-24 19:39:59 +00:00
if ( NULL ! = ( tmp = zend_hash_str_find ( Z_ARRVAL_P ( server_params ) ,
2014-08-11 14:37:26 +00:00
" Server " , sizeof ( " Server " ) - 1 ) ) ) {
2003-08-14 16:49:56 +00:00
convert_to_string_ex ( tmp ) ;
2014-08-11 14:37:26 +00:00
server_name = Z_STRVAL_P ( tmp ) ;
2014-08-25 17:24:55 +00:00
server_name_len = Z_STRLEN_P ( tmp ) ;
2003-08-14 16:49:56 +00:00
ctx = CLSCTX_REMOTE_SERVER ;
}
2015-09-24 19:39:59 +00:00
if ( NULL ! = ( tmp = zend_hash_str_find ( Z_ARRVAL_P ( server_params ) ,
2014-08-11 14:37:26 +00:00
" Username " , sizeof ( " Username " ) - 1 ) ) ) {
2003-08-14 16:49:56 +00:00
convert_to_string_ex ( tmp ) ;
2014-08-11 14:37:26 +00:00
user_name = Z_STRVAL_P ( tmp ) ;
2014-08-25 17:24:55 +00:00
user_name_len = Z_STRLEN_P ( tmp ) ;
2003-08-14 16:49:56 +00:00
}
2015-09-24 19:39:59 +00:00
if ( NULL ! = ( tmp = zend_hash_str_find ( Z_ARRVAL_P ( server_params ) ,
2014-08-11 14:37:26 +00:00
" Password " , sizeof ( " Password " ) - 1 ) ) ) {
2003-08-14 16:49:56 +00:00
convert_to_string_ex ( tmp ) ;
2014-08-11 14:37:26 +00:00
password = Z_STRVAL_P ( tmp ) ;
2014-08-25 17:24:55 +00:00
password_len = Z_STRLEN_P ( tmp ) ;
2003-08-14 16:49:56 +00:00
}
2015-09-24 19:39:59 +00:00
if ( NULL ! = ( tmp = zend_hash_str_find ( Z_ARRVAL_P ( server_params ) ,
2014-08-11 14:37:26 +00:00
" Domain " , sizeof ( " Domain " ) - 1 ) ) ) {
2003-08-14 16:49:56 +00:00
convert_to_string_ex ( tmp ) ;
2014-08-11 14:37:26 +00:00
domain_name = Z_STRVAL_P ( tmp ) ;
2014-08-25 17:24:55 +00:00
domain_name_len = Z_STRLEN_P ( tmp ) ;
2003-08-14 16:49:56 +00:00
}
2015-09-24 19:39:59 +00:00
if ( NULL ! = ( tmp = zend_hash_str_find ( Z_ARRVAL_P ( server_params ) ,
2014-08-11 14:37:26 +00:00
" Flags " , sizeof ( " Flags " ) - 1 ) ) ) {
2017-12-07 16:24:55 +00:00
ctx = ( CLSCTX ) zval_get_long ( tmp ) ;
2003-08-14 16:49:56 +00:00
}
}
if ( server_name & & ! COMG ( allow_dcom ) ) {
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( E_ERROR , " DCOM has been disabled by your administrator [com.allow_dcom=0] " ) ;
2020-01-03 19:44:29 +00:00
RETURN_THROWS ( ) ;
2003-08-14 16:49:56 +00:00
}
2014-12-13 22:06:14 +00:00
moniker = php_com_string_to_olestring ( module_name , module_name_len , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
2003-10-07 18:50:07 +00:00
/* if instantiating a remote object, either directly, or via
* a moniker , fill in the relevant info */
if ( server_name ) {
2003-08-14 16:49:56 +00:00
info . dwReserved1 = 0 ;
info . dwReserved2 = 0 ;
2014-12-13 22:06:14 +00:00
info . pwszName = php_com_string_to_olestring ( server_name , server_name_len , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
if ( user_name ) {
2020-07-10 13:43:32 +00:00
authid . User = ( OLECHAR * ) user_name ;
2014-10-28 09:43:58 +00:00
authid . UserLength = ( ULONG ) user_name_len ;
2003-08-14 16:49:56 +00:00
if ( password ) {
authid . Password = ( OLECHAR * ) password ;
2014-10-28 09:43:58 +00:00
authid . PasswordLength = ( ULONG ) password_len ;
2003-08-14 16:49:56 +00:00
} else {
authid . Password = ( OLECHAR * ) " " ;
authid . PasswordLength = 0 ;
}
if ( domain_name ) {
authid . Domain = ( OLECHAR * ) domain_name ;
2014-10-28 09:43:58 +00:00
authid . DomainLength = ( ULONG ) domain_name_len ;
2003-08-14 16:49:56 +00:00
} else {
authid . Domain = ( OLECHAR * ) " " ;
authid . DomainLength = 0 ;
}
authid . Flags = SEC_WINNT_AUTH_IDENTITY_ANSI ;
info . pAuthInfo = & authinfo ;
} else {
info . pAuthInfo = NULL ;
}
2003-10-07 18:50:07 +00:00
}
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 ) ;
}
2015-01-03 09:22:58 +00:00
2003-10-07 18:50:07 +00:00
if ( SUCCEEDED ( res = MkParseDisplayName ( pBindCtx , moniker , & ulEaten , & pMoniker ) ) ) {
res = IMoniker_BindToObject ( pMoniker , pBindCtx ,
NULL , & IID_IDispatch , ( LPVOID * ) & V_DISPATCH ( & obj - > v ) ) ;
2015-01-03 09:22:58 +00:00
2003-10-07 18:50:07 +00:00
if ( SUCCEEDED ( res ) ) {
V_VT ( & obj - > v ) = VT_DISPATCH ;
}
IMoniker_Release ( pMoniker ) ;
}
}
if ( pBindCtx ) {
IBindCtx_Release ( pBindCtx ) ;
}
} else if ( server_name ) {
MULTI_QI qi ;
2003-08-14 16:49:56 +00:00
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 ;
}
}
2003-10-07 18:50:07 +00:00
if ( server_name ) {
2014-08-11 14:37:26 +00:00
if ( info . pwszName ) efree ( info . pwszName ) ;
if ( authid . User ) efree ( authid . User ) ;
2003-10-07 18:50:07 +00:00
}
2003-08-14 16:49:56 +00:00
efree ( moniker ) ;
if ( FAILED ( res ) ) {
char * werr , * msg ;
2010-11-25 23:06:12 +00:00
werr = php_win32_error_to_msg ( res ) ;
2003-08-14 16:49:56 +00:00
spprintf ( & msg , 0 , " Failed to create COM object `%s': %s " , module_name , werr ) ;
2018-09-17 07:48:33 +00:00
php_win32_error_msg_free ( werr ) ;
2003-08-14 16:49:56 +00:00
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( res , msg ) ;
2003-08-14 16:49:56 +00:00
efree ( msg ) ;
2020-01-03 19:44:29 +00:00
RETURN_THROWS ( ) ;
2003-08-14 16:49:56 +00:00
}
/* 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 ;
2014-12-13 22:06:14 +00:00
TL = php_com_load_typelib_via_cache ( typelib_name , obj - > code_page , & cached ) ;
2003-08-14 16:49:56 +00:00
if ( TL ) {
2020-08-04 16:25:50 +00:00
if ( COMG ( autoreg_on ) ) {
2014-12-13 22:06:14 +00:00
php_com_import_typelib ( TL , mode , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
}
/* 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 ) ) {
2014-11-13 13:27:38 +00:00
UINT idx ;
2003-08-14 16:49:56 +00:00
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 ) ) ) {
2014-12-13 22:06:14 +00:00
typelib_name = php_com_olestring_to_string ( name , & typelib_name_len , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
2019-07-01 08:18:19 +00:00
if ( NULL ! = php_com_cache_typelib ( TL , typelib_name , typelib_name_len ) ) {
2014-12-13 22:06:14 +00:00
php_com_import_typelib ( TL , mode , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
/* add a reference for the hash */
ITypeLib_AddRef ( TL ) ;
}
2019-06-29 12:47:06 +00:00
efree ( typelib_name ) ;
2003-08-14 16:49:56 +00:00
} else {
/* try it anyway */
2014-12-13 22:06:14 +00:00
php_com_import_typelib ( TL , mode , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
}
ITypeLib_Release ( TL ) ;
}
}
}
/* }}} */
2020-07-01 13:32:55 +00:00
/* {{{ Returns a handle to an already running instance of a COM object */
2004-05-09 15:21:29 +00:00
PHP_FUNCTION ( com_get_active_object )
{
CLSID clsid ;
char * module_name ;
2014-10-28 09:43:58 +00:00
size_t module_name_len ;
2020-07-28 21:00:44 +00:00
zend_long code_page ;
zend_bool code_page_is_null = 1 ;
2004-05-09 15:21:29 +00:00
IUnknown * unk = NULL ;
IDispatch * obj = NULL ;
HRESULT res ;
OLECHAR * module = NULL ;
2014-12-13 22:06:14 +00:00
php_com_initialize ( ) ;
2020-07-28 21:00:44 +00:00
if ( FAILURE = = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " s|l! " ,
& module_name , & module_name_len , & code_page , & code_page_is_null ) ) {
2019-12-30 17:09:40 +00:00
RETURN_THROWS ( ) ;
2004-05-09 15:21:29 +00:00
}
2020-07-28 21:00:44 +00:00
if ( code_page_is_null ) {
code_page = COMG ( code_page ) ;
}
2014-12-13 22:06:14 +00:00
module = php_com_string_to_olestring ( module_name , module_name_len , ( int ) code_page ) ;
2004-05-09 15:21:29 +00:00
res = CLSIDFromString ( module , & clsid ) ;
if ( FAILED ( res ) ) {
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( res , NULL ) ;
2004-05-09 15:21:29 +00:00
} else {
res = GetActiveObject ( & clsid , NULL , & unk ) ;
if ( FAILED ( res ) ) {
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( res , NULL ) ;
2004-05-09 15:21:29 +00:00
} else {
res = IUnknown_QueryInterface ( unk , & IID_IDispatch , & obj ) ;
if ( FAILED ( res ) ) {
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( res , NULL ) ;
2004-05-09 15:21:29 +00:00
} else if ( obj ) {
/* we got our dispatchable object */
2014-12-13 22:06:14 +00:00
php_com_wrap_dispatch ( return_value , obj , ( int ) code_page ) ;
2004-05-09 15:21:29 +00:00
}
}
}
if ( obj ) {
IDispatch_Release ( obj ) ;
}
if ( unk ) {
IUnknown_Release ( obj ) ;
}
efree ( module ) ;
}
/* }}} */
2003-08-14 16:49:56 +00:00
/* 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 ,
2014-12-13 22:06:14 +00:00
WORD flags , DISPPARAMS * disp_params , VARIANT * v , int silent , int allow_noarg )
2003-08-14 16:49:56 +00:00
{
HRESULT hr ;
unsigned int arg_err ;
2006-10-10 17:32:50 +00:00
EXCEPINFO e = { 0 } ;
2003-08-14 16:49:56 +00:00
2003-11-28 17:11:16 +00:00
hr = IDispatch_Invoke ( V_DISPATCH ( & obj - > v ) , id_member ,
& IID_NULL , LOCALE_SYSTEM_DEFAULT , flags , disp_params , v , & e , & arg_err ) ;
2003-08-14 16:49:56 +00:00
2006-01-26 11:17:34 +00:00
if ( silent = = 0 & & FAILED ( hr ) ) {
2003-08-14 16:49:56 +00:00
char * source = NULL , * desc = NULL , * msg = NULL ;
2014-08-27 13:31:48 +00:00
size_t source_len , desc_len ;
2003-08-14 16:49:56 +00:00
switch ( hr ) {
case DISP_E_EXCEPTION :
if ( e . bstrSource ) {
2014-12-13 22:06:14 +00:00
source = php_com_olestring_to_string ( e . bstrSource , & source_len , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
SysFreeString ( e . bstrSource ) ;
}
if ( e . bstrDescription ) {
2014-12-13 22:06:14 +00:00
desc = php_com_olestring_to_string ( e . bstrDescription , & desc_len , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
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 \n Description: %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 :
2010-11-25 23:06:12 +00:00
desc = php_win32_error_to_msg ( hr ) ;
2003-08-14 16:49:56 +00:00
spprintf ( & msg , 0 , " Parameter %d: %s " , arg_err , desc ) ;
2018-09-17 07:48:33 +00:00
php_win32_error_msg_free ( desc ) ;
2003-08-14 16:49:56 +00:00
break ;
2004-04-28 08:23:22 +00:00
case DISP_E_BADPARAMCOUNT :
2006-12-24 12:32:10 +00:00
if ( ( disp_params - > cArgs + disp_params - > cNamedArgs = = 0 ) & & ( allow_noarg = = 1 ) ) {
2004-04-28 08:23:22 +00:00
/* 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 */
2015-01-03 09:22:58 +00:00
2003-08-14 16:49:56 +00:00
default :
2010-11-25 23:06:12 +00:00
desc = php_win32_error_to_msg ( hr ) ;
2005-04-19 06:14:56 +00:00
spprintf ( & msg , 0 , " Error [0x%08x] %s " , hr , desc ) ;
2018-09-17 07:48:33 +00:00
php_win32_error_msg_free ( desc ) ;
2003-08-14 16:49:56 +00:00
break ;
}
if ( msg ) {
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( hr , msg ) ;
2003-08-14 16:49:56 +00:00
efree ( msg ) ;
}
}
return hr ;
}
/* map an ID to a name */
HRESULT php_com_get_id_of_name ( php_com_dotnet_object * obj , char * name ,
2014-12-13 22:06:14 +00:00
size_t namelen , DISPID * dispid )
2003-08-14 16:49:56 +00:00
{
OLECHAR * olename ;
HRESULT hr ;
2014-08-11 14:37:26 +00:00
zval * tmp ;
2003-08-14 16:49:56 +00:00
2004-01-13 13:38:11 +00:00
if ( namelen = = - 1 ) {
namelen = strlen ( name ) ;
}
2014-08-11 14:37:26 +00:00
if ( obj - > id_of_name_cache & & NULL ! = ( tmp = zend_hash_str_find ( obj - > id_of_name_cache , name , namelen ) ) ) {
2014-10-28 09:43:58 +00:00
* dispid = ( DISPID ) Z_LVAL_P ( tmp ) ;
2004-01-13 13:38:11 +00:00
return S_OK ;
}
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
olename = php_com_string_to_olestring ( name , namelen , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
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 ) ;
2004-01-13 13:38:11 +00:00
if ( SUCCEEDED ( hr ) ) {
2014-08-11 14:37:26 +00:00
zval tmp ;
2004-01-13 13:38:11 +00:00
/* 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 ) ;
}
2014-08-25 17:24:55 +00:00
ZVAL_LONG ( & tmp , * dispid ) ;
2014-08-11 14:37:26 +00:00
zend_hash_str_update ( obj - > id_of_name_cache , name , namelen , & tmp ) ;
2004-01-13 13:38:11 +00:00
}
2015-01-03 09:22:58 +00:00
2003-08-14 16:49:56 +00:00
return hr ;
}
/* the core of COM */
2014-10-03 17:16:53 +00:00
int php_com_do_invoke_byref ( php_com_dotnet_object * obj , zend_internal_function * f ,
2014-12-13 22:06:14 +00:00
WORD flags , VARIANT * v , int nargs , zval * args )
2004-01-13 00:40:14 +00:00
{
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 */
2014-10-28 16:23:40 +00:00
if ( ! f ) {
2014-10-28 16:06:37 +00:00
return FAILURE ;
2004-01-13 00:40:14 +00:00
}
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
hr = php_com_get_id_of_name ( obj , f - > function_name - > val , f - > function_name - > len , & dispid ) ;
2004-01-13 00:40:14 +00:00
if ( FAILED ( hr ) ) {
char * msg = NULL ;
2018-09-17 07:48:33 +00:00
char * winerr = php_win32_error_to_msg ( hr ) ;
2014-10-03 17:16:53 +00:00
spprintf ( & msg , 0 , " Unable to lookup `%s': %s " , f - > function_name - > val , winerr ) ;
2018-09-17 07:48:33 +00:00
php_win32_error_msg_free ( winerr ) ;
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( hr , msg ) ;
2004-01-13 00:40:14 +00:00
efree ( msg ) ;
return FAILURE ;
}
if ( nargs ) {
vargs = ( VARIANT * ) safe_emalloc ( sizeof ( VARIANT ) , nargs , 0 ) ;
}
2014-10-28 16:23:40 +00:00
if ( f - > arg_info ) {
2004-01-13 00:40:14 +00:00
for ( i = 0 ; i < nargs ; i + + ) {
2019-09-20 15:01:19 +00:00
if ( ZEND_ARG_SEND_MODE ( & f - > arg_info [ nargs - i - 1 ] ) ) {
2004-01-13 00:40:14 +00:00
byref_count + + ;
}
}
}
if ( byref_count ) {
byref_vals = ( VARIANT * ) safe_emalloc ( sizeof ( VARIANT ) , byref_count , 0 ) ;
for ( j = 0 , i = 0 ; i < nargs ; i + + ) {
2019-09-20 15:01:19 +00:00
if ( ZEND_ARG_SEND_MODE ( & f - > arg_info [ nargs - i - 1 ] ) ) {
2004-01-13 00:40:14 +00:00
/* put the value into byref_vals instead */
2014-12-13 22:06:14 +00:00
php_com_variant_from_zval ( & byref_vals [ j ] , & args [ nargs - i - 1 ] , obj - > code_page ) ;
2004-01-13 00:40:14 +00:00
/* 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 {
2014-12-13 22:06:14 +00:00
php_com_variant_from_zval ( & vargs [ i ] , & args [ nargs - i - 1 ] , obj - > code_page ) ;
2004-01-13 00:40:14 +00:00
}
}
2015-01-03 09:22:58 +00:00
2004-01-13 00:40:14 +00:00
} else {
/* Invoke'd args are in reverse order */
for ( i = 0 ; i < nargs ; i + + ) {
2014-12-13 22:06:14 +00:00
php_com_variant_from_zval ( & vargs [ i ] , & args [ nargs - i - 1 ] , obj - > code_page ) ;
2004-01-13 00:40:14 +00:00
}
}
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 */
2015-01-03 09:22:58 +00:00
hr = php_com_invoke_helper ( obj , dispid , flags , & disp_params , v , 0 , 0 ) ;
2004-01-13 00:40:14 +00:00
/* release variants */
if ( vargs ) {
2014-10-28 16:23:40 +00:00
if ( f & & f - > arg_info ) {
for ( i = 0 , j = 0 ; i < nargs ; i + + ) {
/* if this was byref, update the zval */
2019-09-20 15:01:19 +00:00
if ( ZEND_ARG_SEND_MODE ( & f - > arg_info [ nargs - i - 1 ] ) ) {
2016-08-25 10:12:45 +00:00
zval * arg = & args [ nargs - i - 1 ] ;
ZVAL_DEREF ( arg ) ;
2018-01-17 00:01:00 +00:00
zval_ptr_dtor ( arg ) ;
ZVAL_NULL ( arg ) ;
2014-10-28 16:23:40 +00:00
/* 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 */
2016-08-25 10:12:45 +00:00
php_com_zval_from_variant ( arg , & byref_vals [ j ] , obj - > code_page ) ;
2014-10-28 16:23:40 +00:00
}
} else {
/* not sure if this can ever happen; the variant we marked as BYREF
* is no longer BYREF - copy its value */
2016-08-25 10:12:45 +00:00
php_com_zval_from_variant ( arg , & vargs [ i ] , obj - > code_page ) ;
2004-01-13 00:40:14 +00:00
}
2014-10-28 16:23:40 +00:00
VariantClear ( & byref_vals [ j ] ) ;
j + + ;
2004-01-13 00:40:14 +00:00
}
2014-10-28 16:23:40 +00:00
VariantClear ( & vargs [ i ] ) ;
}
} else {
for ( i = 0 , j = 0 ; i < nargs ; i + + ) {
VariantClear ( & vargs [ i ] ) ;
}
2004-01-13 00:40:14 +00:00
}
efree ( vargs ) ;
}
return SUCCEEDED ( hr ) ? SUCCESS : FAILURE ;
}
2003-08-14 16:49:56 +00:00
int php_com_do_invoke_by_id ( php_com_dotnet_object * obj , DISPID dispid ,
2014-12-13 22:06:14 +00:00
WORD flags , VARIANT * v , int nargs , zval * args , int silent , int allow_noarg )
2003-08-14 16:49:56 +00:00
{
DISPID altdispid ;
DISPPARAMS disp_params ;
HRESULT hr ;
VARIANT * vargs = NULL ;
int i ;
if ( nargs ) {
2003-08-18 04:41:48 +00:00
vargs = ( VARIANT * ) safe_emalloc ( sizeof ( VARIANT ) , nargs , 0 ) ;
2003-08-14 16:49:56 +00:00
}
/* Invoke'd args are in reverse order */
for ( i = 0 ; i < nargs ; i + + ) {
2014-12-13 22:06:14 +00:00
php_com_variant_from_zval ( & vargs [ i ] , & args [ nargs - i - 1 ] , obj - > code_page ) ;
2003-08-14 16:49:56 +00:00
}
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 */
2015-01-03 09:22:58 +00:00
hr = php_com_invoke_helper ( obj , dispid , flags , & disp_params , v , silent , allow_noarg ) ;
2003-08-14 16:49:56 +00:00
/* release variants */
if ( vargs ) {
for ( i = 0 ; i < nargs ; i + + ) {
VariantClear ( & vargs [ i ] ) ;
}
efree ( vargs ) ;
}
2005-04-19 06:14:56 +00:00
/* a bit of a hack this, but it's needed for COM array access. */
2004-04-28 08:23:22 +00:00
if ( hr = = DISP_E_BADPARAMCOUNT )
return hr ;
2015-01-03 09:22:58 +00:00
2003-08-14 16:49:56 +00:00
return SUCCEEDED ( hr ) ? SUCCESS : FAILURE ;
}
2014-10-28 09:43:58 +00:00
int php_com_do_invoke ( php_com_dotnet_object * obj , char * name , size_t namelen ,
2014-12-13 22:06:14 +00:00
WORD flags , VARIANT * v , int nargs , zval * args , int allow_noarg )
2003-08-14 16:49:56 +00:00
{
DISPID dispid ;
HRESULT hr ;
char * msg = NULL ;
2014-12-13 22:06:14 +00:00
hr = php_com_get_id_of_name ( obj , name , namelen , & dispid ) ;
2003-08-14 16:49:56 +00:00
if ( FAILED ( hr ) ) {
2018-09-17 07:48:33 +00:00
char * winerr = php_win32_error_to_msg ( hr ) ;
2003-08-14 16:49:56 +00:00
spprintf ( & msg , 0 , " Unable to lookup `%s': %s " , name , winerr ) ;
2018-09-17 07:48:33 +00:00
php_win32_error_msg_free ( winerr ) ;
2014-12-13 22:06:14 +00:00
php_com_throw_exception ( hr , msg ) ;
2003-08-14 16:49:56 +00:00
efree ( msg ) ;
return FAILURE ;
}
2014-12-13 22:06:14 +00:00
return php_com_do_invoke_by_id ( obj , dispid , flags , v , nargs , args , 0 , allow_noarg ) ;
2003-08-14 16:49:56 +00:00
}
2003-12-06 17:31:40 +00:00
2020-07-01 13:32:55 +00:00
/* {{{ Generate a globally unique identifier (GUID) */
2003-12-06 17:31:40 +00:00
PHP_FUNCTION ( com_create_guid )
{
GUID retval ;
OLECHAR * guid_string ;
2008-03-10 22:15:36 +00:00
if ( zend_parse_parameters_none ( ) = = FAILURE ) {
2019-12-30 17:09:40 +00:00
RETURN_THROWS ( ) ;
2003-12-06 17:31:40 +00:00
}
2014-12-13 22:06:14 +00:00
php_com_initialize ( ) ;
2003-12-06 17:31:40 +00:00
if ( CoCreateGuid ( & retval ) = = S_OK & & StringFromCLSID ( & retval , & guid_string ) = = S_OK ) {
2014-08-27 17:25:28 +00:00
size_t len ;
2014-08-11 14:37:26 +00:00
char * str ;
2014-12-13 22:06:14 +00:00
str = php_com_olestring_to_string ( guid_string , & len , CP_ACP ) ;
2014-08-11 14:37:26 +00:00
RETVAL_STRINGL ( str , len ) ;
// TODO: avoid reallocation ???
efree ( str ) ;
2003-12-06 17:31:40 +00:00
CoTaskMemFree ( guid_string ) ;
} else {
RETURN_FALSE ;
}
}
2004-01-07 21:00:07 +00:00
/* }}} */
2020-07-01 13:32:55 +00:00
/* {{{ Connect events from a COM object to a PHP object */
2004-01-07 21:00:07 +00:00
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 ;
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
if ( FAILURE = = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " Oo|z/ " ,
2004-01-07 21:00:07 +00:00
& object , php_com_variant_class_entry , & sinkobject , & sink ) ) {
2019-12-30 17:09:40 +00:00
RETURN_THROWS ( ) ;
2004-01-07 21:00:07 +00:00
}
2014-12-13 22:06:14 +00:00
php_com_initialize ( ) ;
2004-01-07 21:00:07 +00:00
obj = CDNO_FETCH ( object ) ;
2015-01-03 09:22:58 +00:00
2004-01-07 21:00:07 +00:00
if ( sink & & Z_TYPE_P ( sink ) = = IS_ARRAY ) {
/* 0 => typelibname, 1 => dispname */
2014-08-11 14:37:26 +00:00
zval * tmp ;
2004-01-07 21:00:07 +00:00
2014-08-11 14:37:26 +00:00
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 ) ;
2004-01-07 21:00:07 +00:00
} else if ( sink ! = NULL ) {
convert_to_string ( sink ) ;
dispname = Z_STRVAL_P ( sink ) ;
}
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
typeinfo = php_com_locate_typeinfo ( typelibname , obj , dispname , 1 ) ;
2004-01-07 21:00:07 +00:00
if ( typeinfo ) {
HashTable * id_to_name ;
2015-01-03 09:22:58 +00:00
2004-01-07 21:00:07 +00:00
ALLOC_HASHTABLE ( id_to_name ) ;
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
if ( php_com_process_typeinfo ( typeinfo , id_to_name , 0 , & obj - > sink_id , obj - > code_page ) ) {
2004-01-07 21:00:07 +00:00
/* Create the COM wrapper for this sink */
2014-12-13 22:06:14 +00:00
obj - > sink_dispatch = php_com_wrapper_export_as_sink ( sinkobject , & obj - > sink_id , id_to_name ) ;
2004-01-07 21:00:07 +00:00
/* Now hook it up to the source */
2014-12-13 22:06:14 +00:00
php_com_object_enable_event_sink ( obj , TRUE ) ;
2004-01-07 21:00:07 +00:00
RETVAL_TRUE ;
} else {
FREE_HASHTABLE ( id_to_name ) ;
}
}
2015-01-03 09:22:58 +00:00
2004-01-07 21:00:07 +00:00
if ( typeinfo ) {
ITypeInfo_Release ( typeinfo ) ;
}
}
/* }}} */
2020-07-01 13:32:55 +00:00
/* {{{ Print out a PHP class definition for a dispatchable interface */
2004-01-07 21:00:07 +00:00
PHP_FUNCTION ( com_print_typeinfo )
{
zval * arg1 ;
char * ifacename = NULL ;
char * typelibname = NULL ;
2014-08-27 13:31:48 +00:00
size_t ifacelen ;
2004-01-07 21:00:07 +00:00
zend_bool wantsink = 0 ;
php_com_dotnet_object * obj = NULL ;
ITypeInfo * typeinfo ;
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
if ( FAILURE = = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " z/|s!b " , & arg1 , & ifacename ,
2004-01-07 21:00:07 +00:00
& ifacelen , & wantsink ) ) {
2019-12-30 17:09:40 +00:00
RETURN_THROWS ( ) ;
2004-01-07 21:00:07 +00:00
}
2014-12-13 22:06:14 +00:00
php_com_initialize ( ) ;
2004-01-07 21:00:07 +00:00
if ( Z_TYPE_P ( arg1 ) = = IS_OBJECT ) {
CDNO_FETCH_VERIFY ( obj , arg1 ) ;
} else {
convert_to_string ( arg1 ) ;
typelibname = Z_STRVAL_P ( arg1 ) ;
}
2014-12-13 22:06:14 +00:00
typeinfo = php_com_locate_typeinfo ( typelibname , obj , ifacename , wantsink ? 1 : 0 ) ;
2004-01-07 21:00:07 +00:00
if ( typeinfo ) {
2014-12-13 22:06:14 +00:00
php_com_process_typeinfo ( typeinfo , NULL , 1 , NULL , obj ? obj - > code_page : COMG ( code_page ) ) ;
2004-01-07 21:00:07 +00:00
ITypeInfo_Release ( typeinfo ) ;
RETURN_TRUE ;
} else {
zend_error ( E_WARNING , " Unable to find typeinfo using the parameters supplied " ) ;
}
RETURN_FALSE ;
}
/* }}} */
2020-07-01 13:32:55 +00:00
/* {{{ Process COM messages, sleeping for up to timeoutms milliseconds */
2004-01-07 21:00:07 +00:00
PHP_FUNCTION ( com_message_pump )
{
2014-08-25 17:24:55 +00:00
zend_long timeoutms = 0 ;
2004-01-07 21:00:07 +00:00
MSG msg ;
DWORD result ;
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " |l " , & timeoutms ) = = FAILURE )
2019-12-30 17:09:40 +00:00
RETURN_THROWS ( ) ;
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
php_com_initialize ( ) ;
2014-10-28 09:43:58 +00:00
result = MsgWaitForMultipleObjects ( 0 , NULL , FALSE , ( DWORD ) timeoutms , QS_ALLINPUT ) ;
2004-01-07 21:00:07 +00:00
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 ;
}
}
/* }}} */
2003-12-06 17:31:40 +00:00
2020-07-01 13:32:55 +00:00
/* {{{ Loads a Typelibrary and registers its constants */
2004-01-07 21:00:07 +00:00
PHP_FUNCTION ( com_load_typelib )
{
char * name ;
2014-08-27 15:31:24 +00:00
size_t namelen ;
2004-01-07 21:00:07 +00:00
ITypeLib * pTL = NULL ;
zend_bool cs = TRUE ;
int codepage = COMG ( code_page ) ;
int cached = 0 ;
2014-12-13 22:06:14 +00:00
if ( FAILURE = = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " s|b " , & name , & namelen , & cs ) ) {
2019-12-30 17:09:40 +00:00
RETURN_THROWS ( ) ;
2004-01-07 21:00:07 +00:00
}
2019-02-14 17:34:47 +00:00
if ( ! cs ) {
2020-07-12 10:40:37 +00:00
php_error_docref ( NULL , E_WARNING , " com_load_typelib(): Argument #2 ($case_insensitive) is ignored since declaration of case-insensitive constants is no longer supported " ) ;
2019-02-14 17:34:47 +00:00
}
2004-01-07 21:00:07 +00:00
RETVAL_FALSE ;
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
php_com_initialize ( ) ;
pTL = php_com_load_typelib_via_cache ( name , codepage , & cached ) ;
2004-01-07 21:00:07 +00:00
if ( pTL ) {
2020-08-04 16:25:50 +00:00
if ( php_com_import_typelib ( pTL , cs ? CONST_CS : 0 , codepage ) = = SUCCESS ) {
2004-01-07 21:00:07 +00:00
RETVAL_TRUE ;
}
ITypeLib_Release ( pTL ) ;
pTL = NULL ;
}
}
/* }}} */