Example #1
0
static void com_write_dimension(zval *object, zval *offset, zval *value)
{
	php_com_dotnet_object *obj;
	zval args[2];
	VARIANT v;
	HRESULT res;

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		ZVAL_COPY_VALUE(&args[0], offset);
		ZVAL_COPY_VALUE(&args[1], value);

		VariantInit(&v);

		if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
				DISPATCH_METHOD|DISPATCH_PROPERTYPUT, &v, 2, args, 0, 0)) {
			VariantClear(&v);
		}
	} else if (V_ISARRAY(&obj->v)) {
		LONG indices = 0;
		VARTYPE vt;

		if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {
			if (FAILED(SafeArrayGetVartype(V_ARRAY(&obj->v), &vt)) || vt == VT_EMPTY) {
				vt = V_VT(&obj->v) & ~VT_ARRAY;
			}

			convert_to_long(offset);
			indices = (LONG)Z_LVAL_P(offset);

			VariantInit(&v);
			php_com_variant_from_zval(&v, value, obj->code_page);

			if (V_VT(&v) != vt) {
				VariantChangeType(&v, &v, 0, vt);
			}

			if (vt == VT_VARIANT) {
				res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v);
			} else {
				res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v.lVal);
			}

			VariantClear(&v);

			if (FAILED(res)) {
				php_com_throw_exception(res, NULL);
			}

		} else {
			php_com_throw_exception(DISP_E_BADINDEX, "this variant has multiple dimensions; you can't set a new value without specifying *all* dimensions");
		}

	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant is not an array type");
	}
}
Example #2
0
static zval *com_property_read(zval *object, zval *member, int type TSRMLS_DC)
{
	zval *return_value;
	php_com_dotnet_object *obj;
	VARIANT v;
	HRESULT res;

	MAKE_STD_ZVAL(return_value);
	ZVAL_NULL(return_value);
	Z_SET_REFCOUNT_P(return_value, 0);
	Z_UNSET_ISREF_P(return_value);

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		VariantInit(&v);

		convert_to_string_ex(&member);

		res = php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
				DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1 TSRMLS_CC);

		if (res == SUCCESS) {
			php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
			VariantClear(&v);
		} else if (res == DISP_E_BADPARAMCOUNT) {
			php_com_saproxy_create(object, return_value, member TSRMLS_CC);
		}
	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
	}

	return return_value;
}
Example #3
0
static zval *com_read_dimension(zval *object, zval *offset, int type, zval *rv)
{
	php_com_dotnet_object *obj;
	VARIANT v;

	ZVAL_NULL(rv);

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		VariantInit(&v);

		if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
				DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 1, offset, 0, 0)) {
			php_com_zval_from_variant(rv, &v, obj->code_page);
			VariantClear(&v);
		}
	} else if (V_ISARRAY(&obj->v)) {
		convert_to_long(offset);

		if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {
			if (php_com_safearray_get_elem(&obj->v, &v, (LONG)Z_LVAL_P(offset))) {
				php_com_wrap_variant(rv, &v, obj->code_page);
				VariantClear(&v);
			}
		} else {
			php_com_saproxy_create(object, rv, offset);
		}

	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant is not an array type");
	}

	return rv;
}
Example #4
0
static zval *com_property_read(zval *object, zval *member, int type, void **cahce_slot, zval *rv)
{
	php_com_dotnet_object *obj;
	VARIANT v;
	HRESULT res;

	ZVAL_NULL(rv);

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		VariantInit(&v);

		convert_to_string_ex(member);

		res = php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
				DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1);

		if (res == SUCCESS) {
			php_com_zval_from_variant(rv, &v, obj->code_page);
			VariantClear(&v);
		} else if (res == DISP_E_BADPARAMCOUNT) {
			php_com_saproxy_create(object, rv, member);
		}
	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant has no properties");
	}

	return rv;
}
Example #5
0
static zval *saproxy_property_read(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv)
{
	ZVAL_NULL(rv);

	php_com_throw_exception(E_INVALIDARG, "safearray has no properties");

	return rv;
}
Example #6
0
static zval *saproxy_property_read(zval *object, zval *member, int type TSRMLS_DC)
{
	zval *return_value;
	
	MAKE_STD_ZVAL(return_value);
	ZVAL_NULL(return_value);

	php_com_throw_exception(E_INVALIDARG, "safearray has no properties" TSRMLS_CC);

	return return_value;
}
Example #7
0
static void variant_unary_operation(enum variant_unary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
	VARIANT vres;
	VARIANT left_val;
	VARIANT *vleft = NULL;
	zval *zleft = NULL;
	php_com_dotnet_object *obj;
	HRESULT result;
	int codepage = CP_ACP;

	VariantInit(&left_val);
	VariantInit(&vres);

	if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "O", &zleft, php_com_variant_class_entry)) {
		obj = CDNO_FETCH(zleft);
		vleft = &obj->v;
	} else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
			"z!", &zleft)) {
		vleft = &left_val;
		php_com_variant_from_zval(vleft, zleft, codepage);
	} else {
		return;
	}

	switch (op) {
		case VOP_ABS:
			result = VarAbs(vleft, &vres);
			break;
		case VOP_FIX:
			result = VarFix(vleft, &vres);
			break;
		case VOP_INT:
			result = VarInt(vleft, &vres);
			break;
		case VOP_NEG:
			result = VarNeg(vleft, &vres);
			break;
		case VOP_NOT:
			result = VarNot(vleft, &vres);
			break;
		default:
			result = E_INVALIDARG;
	}

	if (SUCCEEDED(result)) {
		php_com_wrap_variant(return_value, &vres, codepage);
	} else {
		php_com_throw_exception(result, NULL);
	}

	VariantClear(&vres);
	VariantClear(&left_val);
}
Example #8
0
/* this is a convenience function for fetching a particular
 * element from a (possibly multi-dimensional) safe array */
PHP_COM_DOTNET_API int php_com_safearray_get_elem(VARIANT *array, VARIANT *dest, LONG dim1)
{
    UINT dims;
    LONG lbound, ubound;
    LONG indices[1];
    VARTYPE vt;

    if (!V_ISARRAY(array)) {
        return 0;
    }

    dims = SafeArrayGetDim(V_ARRAY(array));

    if (dims != 1) {
        php_error_docref(NULL, E_WARNING,
                         "Can only handle single dimension variant arrays (this array has %d)", dims);
        return 0;
    }

    if (FAILED(SafeArrayGetVartype(V_ARRAY(array), &vt)) || vt == VT_EMPTY) {
        vt = V_VT(array) & ~VT_ARRAY;
    }

    /* determine the bounds */
    SafeArrayGetLBound(V_ARRAY(array), 1, &lbound);
    SafeArrayGetUBound(V_ARRAY(array), 1, &ubound);

    /* check bounds */
    if (dim1 < lbound || dim1 > ubound) {
        php_com_throw_exception(DISP_E_BADINDEX, "index out of bounds");
        return 0;
    }

    /* now fetch that element */
    VariantInit(dest);

    indices[0] = dim1;

    if (vt == VT_VARIANT) {
        SafeArrayGetElement(V_ARRAY(array), indices, dest);
    } else {
        V_VT(dest) = vt;
        /* store the value into "lVal" member of the variant.
         * This works because it is a union; since we know the variant
         * type, we end up with a working variant */
        SafeArrayGetElement(V_ARRAY(array), indices, &dest->lVal);
    }

    return 1;
}
Example #9
0
static void com_property_write(zval *object, zval *member, zval *value, void **cache_slot)
{
	php_com_dotnet_object *obj;
	VARIANT v;

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		VariantInit(&v);

		convert_to_string_ex(member);
		if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
				DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &v, 1, value, 0)) {
			VariantClear(&v);
		}
	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant has no properties");
	}
}
Example #10
0
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);
}
Example #11
0
/* Performs an Invoke on the given com object.
 * returns a failure code and creates an exception if there was an error */
HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
		WORD flags, DISPPARAMS *disp_params, VARIANT *v, int silent, int allow_noarg TSRMLS_DC)
{
	HRESULT hr;
	unsigned int arg_err;
	EXCEPINFO e = {0};

	hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
		&IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, v, &e, &arg_err);

	if (silent == 0 && FAILED(hr)) {
		char *source = NULL, *desc = NULL, *msg = NULL;
		int source_len, desc_len;

		switch (hr) {
			case DISP_E_EXCEPTION:
				if (e.bstrSource) {
					source = php_com_olestring_to_string(e.bstrSource, &source_len, obj->code_page TSRMLS_CC);
					SysFreeString(e.bstrSource);
				}
				if (e.bstrDescription) {
					desc = php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page TSRMLS_CC);
					SysFreeString(e.bstrDescription);
				}
				if (PG(html_errors)) {
					spprintf(&msg, 0, "<b>Source:</b> %s<br/><b>Description:</b> %s",
						source ? source : "Unknown",
						desc ? desc : "Unknown");
				} else {
					spprintf(&msg, 0, "Source: %s\nDescription: %s",
						source ? source : "Unknown",
						desc ? desc : "Unknown");
				}
				if (desc) {
					efree(desc);
				}
				if (source) {
					efree(source);
				}
				if (e.bstrHelpFile) {
					SysFreeString(e.bstrHelpFile);
				}
				break;

			case DISP_E_PARAMNOTFOUND:
			case DISP_E_TYPEMISMATCH:
				desc = php_win_err(hr);
				spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
				LocalFree(desc);
				break;

			case DISP_E_BADPARAMCOUNT:
				if ((disp_params->cArgs + disp_params->cNamedArgs == 0) && (allow_noarg == 1)) {
					/* if getting a property and they are missing all parameters,
					 * we want to create a proxy object for them; so lets not create an
					 * exception here */
					msg = NULL;
					break;
				}
				/* else fall through */
				
			default:
				desc = php_win_err(hr);
				spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
				LocalFree(desc);
				break;
		}

		if (msg) {
			php_com_throw_exception(hr, msg TSRMLS_CC);
			efree(msg);
		}
	}

	return hr;
}
Example #12
0
/* 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) {
					SEPARATE_ZVAL_IF_NOT_REF(&args[nargs - i - 1]);

					/* 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(&args[nargs - i - 1], &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(&args[nargs - i - 1], &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;
}
Example #13
0
static zval *saproxy_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
{
	php_com_saproxy *proxy = (php_com_saproxy*) object;
	UINT dims, i;
	SAFEARRAY *sa;
	LONG ubound, lbound;
	HRESULT res;

	ZVAL_NULL(rv);

	if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
		VARIANT v;
		zval *args;

		/* prop-get using first dimension as the property name,
		 * all subsequent dimensions and the offset as parameters */

		args = safe_emalloc(proxy->dimensions + 1, sizeof(zval), 0);

		for (i = 1; i < (UINT) proxy->dimensions; i++) {
			args[i-1] = proxy->indices[i];
		}
		ZVAL_COPY_VALUE(&args[i-1], offset);

		convert_to_string(&proxy->indices[0]);
		VariantInit(&v);

		res = php_com_do_invoke(proxy->obj, Z_STRVAL(proxy->indices[0]),
			   	Z_STRLEN(proxy->indices[0]), DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v,
			   	proxy->dimensions, args, 0);

		if (res == SUCCESS) {
			php_com_zval_from_variant(rv, &v, proxy->obj->code_page);
			VariantClear(&v);
		} else if (res == DISP_E_BADPARAMCOUNT) {
			/* return another proxy */
			php_com_saproxy_create(object, rv, offset);
		}

		return rv;

	} else if (!V_ISARRAY(&proxy->obj->v)) {
		php_com_throw_exception(E_INVALIDARG, "invalid read from com proxy object");
		return rv;
	}

	/* the SafeArray case */

	/* offset/index must be an integer */
	convert_to_long(offset);

	sa = V_ARRAY(&proxy->obj->v);
	dims = SafeArrayGetDim(sa);

	if ((UINT) proxy->dimensions >= dims) {
		/* too many dimensions */
		php_com_throw_exception(E_INVALIDARG, "too many dimensions!");
		return rv;
	}

	/* bounds check */
	SafeArrayGetLBound(sa, proxy->dimensions, &lbound);
	SafeArrayGetUBound(sa, proxy->dimensions, &ubound);

	if (Z_LVAL_P(offset) < lbound || Z_LVAL_P(offset) > ubound) {
		php_com_throw_exception(DISP_E_BADINDEX, "index out of bounds");
		return rv;
	}

	if (dims - 1 == proxy->dimensions) {
		LONG *indices;
		VARTYPE vt;
		VARIANT v;

		VariantInit(&v);

		/* we can return a real value */
		indices = safe_emalloc(dims, sizeof(LONG), 0);

		/* copy indices from proxy */
		for (i = 0; i < dims; i++) {
			convert_to_long(&proxy->indices[i]);
			indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
		}

		/* add user-supplied index */
		indices[dims-1] = (LONG)Z_LVAL_P(offset);

		/* now fetch the value */
		if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
			vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
		}

		if (vt == VT_VARIANT) {
			res = SafeArrayGetElement(sa, indices, &v);
		} else {
			V_VT(&v) = vt;
			res = SafeArrayGetElement(sa, indices, &v.lVal);
		}

		efree(indices);

		if (SUCCEEDED(res)) {
			php_com_wrap_variant(rv, &v, proxy->obj->code_page);
		} else {
			php_com_throw_exception(res, NULL);
		}

		VariantClear(&v);

	} else {
		/* return another proxy */
		php_com_saproxy_create(object, rv, offset);
	}

	return rv;
}
Example #14
0
static zval *saproxy_property_write(zend_object *object, zend_string *member, zval *value, void **cache_slot)
{
	php_com_throw_exception(E_INVALIDARG, "safearray has no properties");
	return value;
}
Example #15
0
static void saproxy_write_dimension(zend_object *object, zval *offset, zval *value)
{
	php_com_saproxy *proxy = (php_com_saproxy*) object;
	UINT dims, i;
	HRESULT res;
	VARIANT v;

	if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
		/* We do a prop-set using the first dimension as the property name,
		 * all subsequent dimensions and offset as parameters, with value as
		 * the final value */
		zval *args = safe_emalloc(proxy->dimensions + 2, sizeof(zval), 0);

		for (i = 1; i < (UINT) proxy->dimensions; i++) {
			ZVAL_COPY_VALUE(&args[i-1], &proxy->indices[i]);
		}
		ZVAL_COPY_VALUE(&args[i-1], offset);
		ZVAL_COPY_VALUE(&args[i], value);

		convert_to_string(&proxy->indices[0]);
		VariantInit(&v);
		if (SUCCESS == php_com_do_invoke(proxy->obj, Z_STRVAL(proxy->indices[0]),
					Z_STRLEN(proxy->indices[0]), DISPATCH_PROPERTYPUT, &v, proxy->dimensions + 1,
					args, 0)) {
			VariantClear(&v);
		}

		efree(args);

	} else if (V_ISARRAY(&proxy->obj->v)) {
		LONG *indices;
		VARTYPE vt;

		dims = SafeArrayGetDim(V_ARRAY(&proxy->obj->v));
		indices = safe_emalloc(dims, sizeof(LONG), 0);
		/* copy indices from proxy */
		for (i = 0; i < dims; i++) {
			convert_to_long(&proxy->indices[i]);
			indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
		}

		/* add user-supplied index */
		convert_to_long(offset);
		indices[dims-1] = (LONG)Z_LVAL_P(offset);

		if (FAILED(SafeArrayGetVartype(V_ARRAY(&proxy->obj->v), &vt)) || vt == VT_EMPTY) {
			vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
		}

		VariantInit(&v);
		php_com_variant_from_zval(&v, value, proxy->obj->code_page);

		if (V_VT(&v) != vt) {
			VariantChangeType(&v, &v, 0, vt);
		}

		if (vt == VT_VARIANT) {
			res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v);
		} else {
			res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v.lVal);
		}

		efree(indices);
		VariantClear(&v);

		if (FAILED(res)) {
			php_com_throw_exception(res, NULL);
		}
	} else {
		php_com_throw_exception(E_NOTIMPL, "invalid write to com proxy object");
	}
}
Example #16
0
static void variant_binary_operation(enum variant_binary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
	VARIANT vres;
	VARIANT left_val, right_val;
	VARIANT *vleft = NULL, *vright = NULL;
	zval *zleft = NULL, *zright = NULL;
	php_com_dotnet_object *obj;
	HRESULT result;
	int codepage = CP_ACP;

	VariantInit(&left_val);
	VariantInit(&right_val);
	VariantInit(&vres);

	if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "OO", &zleft, php_com_variant_class_entry,
			&zright, php_com_variant_class_entry)) {
		obj = CDNO_FETCH(zleft);
		vleft = &obj->v;
		obj = CDNO_FETCH(zright);
		vright = &obj->v;
	} else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "Oz!", &zleft, php_com_variant_class_entry,
			&zright)) {
		obj = CDNO_FETCH(zleft);
		vleft = &obj->v;
		vright = &right_val;
		php_com_variant_from_zval(vright, zright, codepage);
	} else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "z!O", &zleft, &zright, php_com_variant_class_entry)) {
		obj = CDNO_FETCH(zright);
		vright = &obj->v;
		vleft = &left_val;
		php_com_variant_from_zval(vleft, zleft, codepage);
	} else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
			"z!z!", &zleft, &zright)) {

		vleft = &left_val;
		php_com_variant_from_zval(vleft, zleft, codepage);

		vright = &right_val;
		php_com_variant_from_zval(vright, zright, codepage);

	} else {
		return;
	}

	switch (op) {
		case VOP_ADD:
			result = VarAdd(vleft, vright, &vres);
			break;
		case VOP_CAT:
			result = VarCat(vleft, vright, &vres);
			break;
		case VOP_SUB:
			result = VarSub(vleft, vright, &vres);
			break;
		case VOP_MUL:
			result = VarMul(vleft, vright, &vres);
			break;
		case VOP_AND:
			result = VarAnd(vleft, vright, &vres);
			break;
		case VOP_DIV:
			result = VarDiv(vleft, vright, &vres);
			break;
		case VOP_EQV:
			result = VarEqv(vleft, vright, &vres);
			break;
		case VOP_IDIV:
			result = VarIdiv(vleft, vright, &vres);
			break;
		case VOP_IMP:
			result = VarImp(vleft, vright, &vres);
			break;
		case VOP_MOD:
			result = VarMod(vleft, vright, &vres);
			break;
		case VOP_OR:
			result = VarOr(vleft, vright, &vres);
			break;
		case VOP_POW:
			result = VarPow(vleft, vright, &vres);
			break;
		case VOP_XOR:
			result = VarXor(vleft, vright, &vres);
			break;
		/*Let say it fails as no valid op has been given */
		default:
			result = E_INVALIDARG;
	}

	if (SUCCEEDED(result)) {
		php_com_wrap_variant(return_value, &vres, codepage);
	} else {
		php_com_throw_exception(result, NULL);
	}

	VariantClear(&vres);
	VariantClear(&left_val);
	VariantClear(&right_val);
}