📄 com.c
字号:
char *clsid_str; int mode = 0; ITypeLib *pTL; CLSCTX flags = CLSCTX_SERVER; codepage = CP_ACP; switch (ZEND_NUM_ARGS()) { case 1: zend_get_parameters(ht, 1, &module_name); break; case 2: zend_get_parameters(ht, 2, &module_name, &server_name); break; case 3: zend_get_parameters(ht, 3, &module_name, &server_name, &code_page); convert_to_long_ex(&code_page); codepage = Z_LVAL_P(code_page); break; case 4: zend_get_parameters(ht, 4, &module_name, &server_name, &code_page, &typelib); convert_to_string_ex(&typelib); convert_to_long_ex(&code_page); codepage = Z_LVAL_P(code_page); break; default: ZEND_WRONG_PARAM_COUNT(); } if (server_name != NULL) { /* What is server name? A String or an array? */ if (Z_TYPE_P(server_name) == IS_NULL) { server_name = NULL; } else if (Z_TYPE_P(server_name) == IS_ARRAY) { pval **tmp; /* DAB: 22 Sept 2001 * Aha - we have a number of possible arguments. * They are in the hash By name: Server, Domain, Username, Password * Flags. * This has been crafted to maintian maximum backward compatability. * If the server name is specified as a string, then the function * should behave as before by defaulting username and password and * using the (I believe) incorrect CLSCTX_SERVER instantiation * paramter. However if server is specified in this array then we * use either CLSCTX_REMOTE_SERVER or whatever flags are specified * in the array */ HashTable *ht = Z_ARRVAL(*server_name); if (FAILURE == zend_hash_find(ht, "Server", 7, (void **) &tmp)) { server_name = NULL; } else { server_name = *tmp; convert_to_string_ex(&server_name); /* CLSCTX_SERVER includes INPROC and LOCAL SERVER. This means * that any local server will be instantiated BEFORE even * looking on a remote server. Thus if we have a server name, * probably we want to access a remote machine or we would not * have bothered specifying it. So it would be wrong to to * connect locally. Futher, unless the name passed is a GUID, * there has to be something to map the Prog.Id to GUID and * unless that has been modified to remove the information * about local instantiation CLSCTX_SERVER would force a local * instantiation This setting can be overridden below if the * user specifies a flags element */ flags = CLSCTX_REMOTE_SERVER; } if (FAILURE == zend_hash_find(ht, "Username", 9, (void **) &tmp)) { user_name = NULL; } else { user_name = *tmp; convert_to_string_ex(&user_name); } if (FAILURE == zend_hash_find(ht, "Domain", 7, (void **) &tmp)) { domain = NULL; } else { domain = *tmp; convert_to_string_ex(&domain); } if (FAILURE == zend_hash_find(ht, "Password", 9, (void **) &tmp)) { password=NULL; } else { password = *tmp; convert_to_string_ex(&password); } if (SUCCESS == zend_hash_find(ht, "Flags", 6, (void **) &tmp)) { convert_to_long_ex(tmp); flags = (CLSCTX) Z_LVAL_PP(tmp); } } else { if (!INI_INT("com.allow_dcom")) { php_error(E_WARNING, "%s(): DCOM is disabled", get_active_function_name(TSRMLS_C)); RETURN_NULL(); } else { flags = CLSCTX_REMOTE_SERVER; convert_to_string_ex(&server_name); } } } ALLOC_COM(obj); convert_to_string_ex(&module_name); ProgID = php_char_to_OLECHAR(Z_STRVAL_P(module_name), Z_STRLEN_P(module_name), codepage TSRMLS_CC); /* obtain CLSID */ if (FAILED(CLSIDFromString(ProgID, &clsid))) { /* Perhaps this is a Moniker? */ IBindCtx *pBindCtx; IMoniker *pMoniker; ULONG ulEaten; /* @todo if (server_name) */ if (!server_name) { /* @todo shouldn't the bind context be fetched on module startup and kept as a global shared instance ? * all calls to BindToObject would deliver the same instance then (as desired) * IBindCtx::RegisterObjectBound() should be called then after mkparsedisplayname() * * @todo use mkparsedisplaynameex() ? */ if (SUCCEEDED(hr = CreateBindCtx(0, &pBindCtx))) { if (SUCCEEDED(hr = MkParseDisplayName(pBindCtx, ProgID, &ulEaten, &pMoniker))) { hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL, &IID_IDispatch, (LPVOID *) &C_DISPATCH(obj)); pMoniker->lpVtbl->Release(pMoniker); } pBindCtx->lpVtbl->Release(pBindCtx); } } else { hr = MK_E_SYNTAX; } efree(ProgID); if (FAILED(hr)) { php_COM_destruct(obj TSRMLS_CC); error_message = php_COM_error_message(hr TSRMLS_CC); php_error(E_WARNING, "%s(): Invalid ProgID, GUID string, or Moniker: %s", get_active_function_name(TSRMLS_C), error_message); LocalFree(error_message); RETURN_NULL(); } } else { efree(ProgID); /* obtain IDispatch */ if (!server_name) { hr = CoCreateInstance(&clsid, NULL, flags, &IID_IDispatch, (LPVOID *) &C_DISPATCH(obj)); } else { COSERVERINFO server_info; MULTI_QI pResults; COAUTHIDENTITY authid; COAUTHINFO authinfo = {RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, &authid, EOAC_NONE}; server_info.dwReserved1=0; server_info.dwReserved2=0; server_info.pwszName = php_char_to_OLECHAR(Z_STRVAL_P(server_name), Z_STRLEN_P(server_name), codepage TSRMLS_CC); if (user_name) { /* Z_STRVAL_P(user_name); */ /* Parse Username into domain\username */ authid.User = (WCHAR *) Z_STRVAL_P(user_name); authid.UserLength = Z_STRLEN_P(user_name); if (password) { authid.Password = (USHORT *) Z_STRVAL_P(password); authid.PasswordLength = Z_STRLEN_P(password); } else { authid.Password = (USHORT *) ""; authid.PasswordLength = 0; } if (domain) { authid.Domain = (USHORT *) Z_STRVAL_P(domain); authid.DomainLength = Z_STRLEN_P(domain); } else { authid.Domain = (USHORT *) ""; authid.DomainLength = 0; } authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; server_info.pAuthInfo=&authinfo; } else { server_info.pAuthInfo=NULL; } pResults.pIID = &IID_IDispatch; pResults.pItf = NULL; pResults.hr = S_OK; hr=CoCreateInstanceEx(&clsid, NULL, flags, &server_info, 1, &pResults); if (SUCCEEDED(hr)) { hr = pResults.hr; C_DISPATCH(obj) = (IDispatch *) pResults.pItf; } efree(server_info.pwszName); } if (FAILED(hr)) { error_message = php_COM_error_message(hr TSRMLS_CC); clsid_str = php_string_from_clsid(&clsid TSRMLS_CC); php_error(E_WARNING, "%s(): Unable to obtain IDispatch interface for CLSID %s: %s", get_active_function_name(TSRMLS_C), clsid_str, error_message); LocalFree(error_message); efree(clsid_str); php_COM_destruct(obj TSRMLS_CC); RETURN_NULL(); } } php_COM_set(obj, &C_DISPATCH(obj), TRUE TSRMLS_CC); if (INI_INT("com.autoregister_casesensitive")) { mode |= CONST_CS; } if (C_HASTLIB(obj)) { if (INI_INT("com.autoregister_typelib")) { unsigned int idx; /* @todo check if typlib isn't already loaded */ if (C_TYPEINFO_VT(obj)->GetContainingTypeLib(C_TYPEINFO(obj), &pTL, &idx) == S_OK) { php_COM_load_typelib(pTL, mode TSRMLS_CC); pTL->lpVtbl->Release(pTL); } } } else { if (typelib != NULL) { ITypeLib *pTL; if ((pTL = php_COM_find_typelib(Z_STRVAL_P(typelib), mode TSRMLS_CC)) != NULL) { C_HASTLIB(obj) = SUCCEEDED(pTL->lpVtbl->GetTypeInfo(pTL, 0, &C_TYPEINFO(obj))); /* idx 0 should deliver the ITypeInfo for the IDispatch Interface */ if (INI_INT("com.autoregister_typelib")) { php_COM_load_typelib(pTL, mode TSRMLS_CC); } pTL->lpVtbl->Release(pTL); } } } RETVAL_COM(obj);}/* }}} */static int do_COM_invoke(comval *obj, WORD dispflags, pval *function_name, VARIANT *var_result, pval **arguments, int arg_count TSRMLS_DC){ DISPID dispid, altdispid; DISPPARAMS dispparams; HRESULT hr; OLECHAR *funcname; SAFEARRAY *pSA; SAFEARRAYBOUND rgsabound[1]; VARIANT *variant_args; char *error_message; int current_arg, current_variant; unsigned long count; if (C_HASENUM(obj) && strstr(Z_STRVAL_P(function_name), "next")) { /* Grab one argument off the stack, allocate enough * VARIANTs * Get the IEnumVariant interface and call ->Next(); */ switch (arg_count) { case 0: count = 1; break; case 1: convert_to_long_ex(&arguments[0]); count = Z_LVAL_P(arguments[0]); break; default: php_error(E_WARNING, "%s(): Wrong argument count to IEnumVariant::Next()", get_active_function_name(TSRMLS_C)); return FAILURE; } rgsabound[0].lLbound = 0; rgsabound[0].cElements = count; if ((pSA = SafeArrayCreate(VT_VARIANT, 1, rgsabound)) == NULL) { VariantInit(var_result); return FAILURE; } else { V_ARRAY(var_result) = pSA; V_VT(var_result) = VT_VARIANT|VT_ARRAY; } if (FAILED(hr = C_ENUMVARIANT_VT(obj)->Next(C_ENUMVARIANT(obj), count, pSA->pvData, &count))) { char *error_message = php_COM_error_message(hr TSRMLS_CC); php_error(E_WARNING, "%s(): IEnumVariant::Next() failed: %s", get_active_function_name(TSRMLS_C), error_message); efree(error_message); VariantClear(var_result); return FAILURE; } if (count != rgsabound[0].cElements) { rgsabound[0].cElements = count; if (FAILED(SafeArrayRedim(pSA, rgsabound))) { char *error_message = php_COM_error_message(hr TSRMLS_CC); php_error(E_WARNING, "%s(): IEnumVariant::Next() failed: %s", get_active_function_name(TSRMLS_C), error_message); efree(error_message); VariantClear(var_result); return FAILURE; } } /* return a single element if next() was called without count */ if ((arg_count == 0) && (count == 1)) { long index[] = {0}; SafeArrayGetElement(pSA, index, var_result); SafeArrayDestroy(pSA); } return SUCCESS; } else if (C_HASENUM(obj) && strstr(Z_STRVAL_P(function_name), "all")) {#define FETCH_BLOCKSIZE 10 /* fetch blocks of 10 elements */ count = FETCH_BLOCKSIZE; rgsabound[0].lLbound = 0; rgsabound[0].cElements = count; if ((pSA = SafeArrayCreate(VT_VARIANT, 1, rgsabound)) == NULL) { VariantInit(var_result); return FAILURE; } else { V_ARRAY(var_result) = pSA; V_VT(var_result) = VT_VARIANT|VT_ARRAY; } /* blah*/ } else if (C_HASENUM(obj) && strstr(Z_STRVAL_P(function_name), "reset")) { if (FAILED(hr = C_ENUMVARIANT_VT(obj)->Reset(C_ENUMVARIANT(obj)))) { char *error_message = php_COM_error_message(hr TSRMLS_CC); php_error(E_WARNING,"%s(): IEnumVariant::Next() failed: %s", get_active_function_name(TSRMLS_C), error_message); efree(error_message); return FAILURE; } return SUCCESS; } else if (C_HASENUM(obj) && strstr(Z_STRVAL_P(function_name), "skip")) { unsigned long count; switch (arg_count) { case 0: count = 1; break; case 1: convert_to_long_ex(&arguments[0]); count = Z_LVAL_P(arguments[0]); break; default: php_error(E_WARNING, "%s(): Wrong argument count to IEnumVariant::Skip()", get_active_function_name(TSRMLS_C)); return FAILURE; } if (FAILED(hr = C_ENUMVARIANT_VT(obj)->Skip(C_ENUMVARIANT(obj), count))) { char *error_message = php_COM_error_message(hr TSRMLS_CC); php_error(E_WARNING,"%s(): IEnumVariant::Next() failed: %s", get_active_function_name(TSRMLS_C), error_message); efree(error_message); return FAILURE; } return SUCCESS; } else { char *ErrString; funcname = php_char_to_OLECHAR(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), codepage TSRMLS_CC); hr = php_COM_get_ids_of_names(obj, &funcname, &dispid TSRMLS_CC); if (FAILED(hr)) { error_message = php_COM_error_message(hr TSRMLS_CC); php_error(E_WARNING, "%s(): Unable to lookup %s: %s", get_active_function_name(TSRMLS_C), Z_STRVAL_P(function_name), error_message); LocalFree(error_message); efree(funcname); return FAILURE; } variant_args = (VARIANT *) emalloc(sizeof(VARIANT) * arg_count); for (current_arg=0; current_arg<arg_count; current_arg++) { current_variant = arg_count - current_arg - 1; php_pval_to_variant(arguments[current_arg], &variant_args[current_variant], codepage TSRMLS_CC); } dispparams.rgvarg = variant_args; dispparams.rgdispidNamedArgs = NULL; dispparams.cArgs = arg_count; dispparams.cNamedArgs = 0; if (dispflags & DISPATCH_PROPERTYPUT) { /* Make this work for property set-ing */ altdispid = DISPID_PROPERTYPUT; dispparams.rgdispidNamedArgs = &altdispid; dispparams.cNamedArgs = 1; } hr = php_COM_invoke(obj, dispid, dispflags, &dispparams, var_result, &ErrString TSRMLS_CC); efree(funcname); for (current_arg=0;current_arg<arg_count;current_arg++) { /* don't release IDispatch pointers as they are used afterwards */ if (V_VT(&(variant_args[current_arg])) != VT_DISPATCH) { /* @todo review this: what happens to an array of IDispatchs or a VARIANT->IDispatch */ VariantClear(&variant_args[current_arg]); } } efree(variant_args); if (FAILED(hr)) { error_message = php_COM_error_message(hr TSRMLS_CC); if (ErrString) { php_error(E_WARNING, "%s(): Invoke() failed: %s %s", get_active_function_name(TSRMLS_C), error_message, ErrString); pefree(ErrString, 1); } else { php_error(E_WARNING, "%s(): Invoke() failed: %s", get_active_function_name(TSRMLS_C), error_message); } LocalFree(error_message); return FAILURE; } } return SUCCESS;}/* {{{ proto mixed com_invoke_ex(int module, int invokeflags, string handler_name [, mixed arg [, mixed ...]]) Invokes a COM module */PHP_FUNCTION(com_invoke_ex){ pval **arguments; pval *object, *function_name, *invokeflags; comval *obj = NULL; WORD dispflags = 0; int arg_count = ZEND_NUM_ARGS(); VARIANT *var_result; if (arg_count<3) { ZEND_WRONG_PARAM_COUNT(); } arguments = (pval **) emalloc(sizeof(pval *)*arg_count); if (zend_get_parameters_array(ht, arg_count, arguments) == FAILURE) { RETURN_NULL(); } object = arguments[0]; function_name = arguments[2]; invokeflags = arguments[1]; /* obtain property/method handler */ convert_to_string_ex(&function_name); convert_to_long(invokeflags); dispflags = (WORD)Z_LVAL_P(invokeflags); /* obtain IDispatch interface */ FETCH_COM_SAFE(object, obj); ALLOC_VARIANT(var_result); if (do_COM_invoke(obj, dispflags, function_name, var_result, arguments+3, arg_count-3 TSRMLS_CC)==FAILURE) { FREE_VARIANT(var_result); efree(arguments); RETURN_NULL(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -