Implement VarXor and simplify VarEqv to use it.

diff --git a/dlls/oleaut32/oleaut32.spec b/dlls/oleaut32/oleaut32.spec
index 4516cfc..136de5d 100644
--- a/dlls/oleaut32/oleaut32.spec
+++ b/dlls/oleaut32/oleaut32.spec
@@ -162,7 +162,7 @@
 164 stdcall QueryPathOfRegTypeLib(ptr long long long ptr)
 165 stdcall LHashValOfNameSys(long long wstr)
 166 stdcall LHashValOfNameSysA(long long str)
-167 stub VarXor # stdcall (ptr ptr ptr)
+167 stdcall VarXor(ptr ptr ptr)
 168 stdcall VarAbs(ptr ptr)
 169 stdcall VarFix(ptr ptr)
 170 stdcall OaBuildVersion()
diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c
index 76adf26..82f73b1 100644
--- a/dlls/oleaut32/variant.c
+++ b/dlls/oleaut32/variant.c
@@ -3370,26 +3370,21 @@
 }
 
 /**********************************************************************
- *              VarEqv [OLEAUT32.172]
+ *              VarXor [OLEAUT32.167]
  *
- * Determine if two variants contain the same value.
+ * Perform a logical exclusive-or (XOR) operation on two variants.
  *
  * PARAMS
- *  pVarLeft  [I] First variant to compare
- *  pVarRight [I] Variant to compare to pVarLeft
- *  pVarOut   [O] Destination for comparason result
+ *  pVarLeft  [I] First variant
+ *  pVarRight [I] Variant to XOR with pVarLeft
+ *  pVarOut   [O] Destination for XOR result
  *
  * RETURNS
- *  Success: S_OK. pVarOut contains the result of the comparason (VARIANT_TRUE
- *           if equivalent or VARIANT_FALSE or -2 otherwise, with type from the
- *           table below).
+ *  Success: S_OK. pVarOut contains the result of the operation with its type
+ *           taken from the table below).
  *  Failure: An HRESULT error code indicating the error.
  *
  * NOTES
- *  - Equvalence is defined as containing the same value if one variant is
- *    converted to the other.
- *  - Any value in pVarLeft or pVarRight that will not fit in a VT_I4 will
- *    cause overflow (This is compatable with the native implementation).
  *  - The result stored in pVarOut depends on the types of pVarLeft/pVarRight
  *    according to the following table:
  *|  Type 1     Type 2       Result Type
@@ -3412,9 +3407,9 @@
  *|             VT_BOOL      VT_I2
  *|  All Other Combinations  VT_UI4
  */
-HRESULT WINAPI VarEqv(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut)
+HRESULT WINAPI VarXor(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut)
 {
-    VARTYPE vt = VT_UI4;
+    VARTYPE vt = VT_I4;
     VARIANT varLeft, varRight;
     HRESULT hRet;
 
@@ -3469,10 +3464,14 @@
             /* Fall Through ... */
         case VT_DATE: case VT_CY: case VT_DECIMAL: case VT_R4: case VT_R8:
         case VT_I1: case VT_UI2: case VT_I4: case VT_UI4:
-        case VT_INT: case VT_UINT: case VT_I8: case VT_UI8:
+        case VT_INT: case VT_UINT: case VT_UI8:
             V_VT(pVarOut) = VT_I4;
             V_I4(pVarOut) = VARIANT_FALSE;
             return S_OK;
+        case VT_I8:
+            V_VT(pVarOut) = VT_I8;
+            V_I4(pVarOut) = VARIANT_FALSE;
+            return S_OK;
         default:
             return DISP_E_BADVARTYPE;
         }
@@ -3481,26 +3480,14 @@
     if (V_VT(pVarLeft) == VT_BOOL && V_VT(pVarRight) == VT_BOOL)
     {
         V_VT(pVarOut) = VT_BOOL;
-        if (V_BOOL(pVarLeft) == V_BOOL(pVarRight))
-            V_BOOL(pVarOut) = VARIANT_TRUE;
-        else if (V_BOOL(pVarLeft) == VARIANT_TRUE && V_BOOL(pVarRight) == VARIANT_FALSE)
-        {
-            V_BOOL(pVarOut) = VARIANT_FALSE;
-        }
-        else if (V_BOOL(pVarLeft) == VARIANT_FALSE && V_BOOL(pVarRight) == VARIANT_TRUE)
-        {
-            V_BOOL(pVarOut) = VARIANT_FALSE;
-        }
-        else
-            V_BOOL(pVarOut) = -2; /* Go Figure; this matches native */
-
+        V_BOOL(pVarOut) = V_BOOL(pVarLeft) ^ V_BOOL(pVarRight);
         return S_OK;
     }
 
     if (V_VT(pVarLeft) == VT_UI1 && V_VT(pVarRight) == VT_UI1)
     {
         V_VT(pVarOut) = VT_UI1;
-        V_UI1(pVarOut) = V_UI1(pVarLeft) == V_UI1(pVarRight) ? 0xff : 0xfe;
+        V_UI1(pVarOut) = V_UI1(pVarLeft) ^ V_UI1(pVarRight);
         return S_OK;
     }
 
@@ -3509,63 +3496,89 @@
         (V_VT(pVarRight) == VT_BOOL || V_VT(pVarRight) == VT_UI1 ||
         V_VT(pVarRight) == VT_I2))
         vt = VT_I2;
+    else if (V_VT(pVarLeft) == VT_I8 || V_VT(pVarRight) == VT_I8)
+    {
+        if (V_VT(pVarLeft) == VT_INT || V_VT(pVarRight) == VT_INT)
+            return DISP_E_TYPEMISMATCH;
+        vt = VT_I8;
+    }
 
     V_VT(&varLeft) = V_VT(&varRight) = VT_EMPTY;
     hRet = VariantCopy(&varLeft, pVarLeft);
     if (FAILED(hRet))
-        goto VarEqv_Exit;
+        goto VarXor_Exit;
 
     hRet = VariantCopy(&varRight, pVarRight);
     if (FAILED(hRet))
-        goto VarEqv_Exit;
+        goto VarXor_Exit;
 
     hRet = VariantChangeTypeEx(&varLeft, pVarLeft, LOCALE_USER_DEFAULT, 0, vt);
     if (FAILED(hRet))
-        goto VarEqv_Exit;
+        goto VarXor_Exit;
 
     hRet = VariantChangeTypeEx(&varRight, pVarRight, LOCALE_USER_DEFAULT, 0, vt);
     if (FAILED(hRet))
-        goto VarEqv_Exit;
+        goto VarXor_Exit;
 
     V_VT(pVarOut) = vt;
-    if (vt == VT_UI4)
+    if (vt == VT_I8)
     {
-        if (V_UI4(&varLeft) == V_UI4(&varRight))
-            V_UI4(pVarOut) = VARIANT_TRUE;
-        else if (V_UI4(&varLeft) == VARIANT_TRUE && V_UI4(&varRight) == VARIANT_FALSE)
-        {
-            V_UI4(pVarOut) = VARIANT_FALSE;
-        }
-        else if (V_UI4(&varLeft) == VARIANT_FALSE && V_UI4(&varRight) == VARIANT_TRUE)
-        {
-            V_UI4(pVarOut) = VARIANT_FALSE;
-        }
-        else
-            V_UI4(pVarOut) = -2;
+        V_I8(pVarOut) = V_I8(&varLeft) ^ V_I8(&varRight);
+    }
+    else if (vt == VT_UI4)
+    {
+        V_I4(pVarOut) = V_I4(&varLeft) ^ V_I4(&varRight);
     }
     else
     {
-        if (V_I2(&varLeft) == V_I2(&varRight))
-            V_I2(pVarOut) = VARIANT_TRUE;
-        else if (V_I2(&varLeft) == VARIANT_TRUE && V_I2(&varRight) == VARIANT_FALSE)
-        {
-            V_I2(pVarOut) = VARIANT_FALSE;
-        }
-        else if (V_I2(&varLeft) == VARIANT_FALSE && V_I2(&varRight) == VARIANT_TRUE)
-        {
-            V_I2(pVarOut) = VARIANT_FALSE;
-        }
-        else
-            V_I2(pVarOut) = -2;
+        V_I2(pVarOut) = V_I2(&varLeft) ^ V_I2(&varRight);
     }
 
-VarEqv_Exit:
+VarXor_Exit:
     VariantClear(&varLeft);
     VariantClear(&varRight);
     return hRet;
 }
 
 /**********************************************************************
+ *              VarEqv [OLEAUT32.172]
+ *
+ * Determine if two variants contain the same value.
+ *
+ * PARAMS
+ *  pVarLeft  [I] First variant to compare
+ *  pVarRight [I] Variant to compare to pVarLeft
+ *  pVarOut   [O] Destination for comparison result
+ *
+ * RETURNS
+ *  Success: S_OK. pVarOut contains the result of the comparason (VARIANT_TRUE
+ *           if equivalent or non-zero otherwise.
+ *  Failure: An HRESULT error code indicating the error.
+ *
+ * NOTES
+ *  - This function simply calls VarXor() on pVarLeft and pVarRight and inverts
+ *    the result.
+ */
+HRESULT WINAPI VarEqv(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut)
+{
+    HRESULT hRet;
+
+    TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft),
+          debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight),
+          debugstr_VF(pVarRight), pVarOut);
+
+    hRet = VarXor(pVarLeft, pVarRight, pVarOut);
+    if (SUCCEEDED(hRet))
+    {
+        if (V_VT(pVarOut) == VT_I8)
+            V_I8(pVarOut) = ~V_I8(pVarOut);
+        else
+            V_UI4(pVarOut) = ~V_UI4(pVarOut);
+    }
+    return hRet;
+}
+
+/**********************************************************************
  *              VarNeg [OLEAUT32.173]
  *
  * Negate the value of a variant.