Index: variant.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/variant.c,v
retrieving revision 1.85
diff -u -r1.85 variant.c
--- variant.c	13 Jan 2004 23:16:04 -0000	1.85
+++ variant.c	30 Jan 2004 03:21:18 -0000
@@ -728,7 +728,10 @@
         {
           V_BSTR(pvargDest) = SysAllocStringByteLen((char*)V_BSTR(pvargSrc), SysStringByteLen(V_BSTR(pvargSrc)));
           if (!V_BSTR(pvargDest))
+	  {
+	    TRACE("!V_BSTR(pvargDest), SysAllocStringByteLen() failed to allocate %d bytes\n", SysStringByteLen(V_BSTR(pvargSrc)));
             hres = E_OUTOFMEMORY;
+	  }
         }
       }
       else if (V_VT(pvargSrc) == VT_RECORD)
@@ -840,7 +843,10 @@
   {
     /* Copy into another variant. Free the variant in pvargDest */
     if (FAILED(hres = VariantClear(pvargDest)))
+    {
+      TRACE("VariantClear() of destination failed\n");
       return hres;
+    }
   }
 
   if (V_ISARRAY(pSrc))
@@ -1504,9 +1510,6 @@
 
   TRACE("(%s,%ld,0x%08lx,%p,%p)\n", debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig);
 
-  if (pNumprs->dwInFlags & NUMPRS_HEX_OCT)
-    FIXME("dwInFlags & NUMPRS_HEX_OCT not yet implemented!\n");
-
   if (!pNumprs || !rgbDig)
     return E_INVALIDARG;
 
@@ -1718,8 +1721,23 @@
   {
     if (dwState & B_INEXACT_ZEROS)
       pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* All zeros doesn't set NUMPRS_INEXACT */
-  }
-  else
+  } else if(pNumprs->dwInFlags & NUMPRS_HEX_OCT)
+  {
+    /* copy all of the digits into the output digit buffer */
+    /* this is exactly what windows does although it also returns */
+    /* cDig of X and writes X+Y where Y>=0 number of digits to rgbDig */
+    memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
+
+    while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
+    {
+      if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
+        pNumprs->nPwr10--;
+      else
+        pNumprs->nPwr10++;
+
+      pNumprs->cDig--;
+    }
+  } else
   {
     /* Remove trailing zeros from the last (whole number or decimal) part */
     while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
@@ -1728,6 +1746,7 @@
         pNumprs->nPwr10--;
       else
         pNumprs->nPwr10++;
+
       pNumprs->cDig--;
     }
   }
@@ -2941,7 +2960,8 @@
             rc = S_OK;
 
         } else {
-            FIXME("unimplemented part\n");
+            FIXME("unimplemented part, V_VT(left) == 0x%X, V_VT(right) == 0x%X\n", 
+		V_VT(left) & VT_TYPEMASK, V_VT(right) & VT_TYPEMASK);
         }
     }
 
@@ -3392,7 +3412,9 @@
         V_VT(pVarOut) = VT_I4;
         break;
     case VT_CY:
-        /* FIXME: */
+        hRet = VarI4FromCy(V_CY(pVarIn), &V_I4(pVarOut));
+        V_I4(pVarOut) = ~V_I4(pVarOut);
+        V_VT(pVarOut) = VT_I4;
         break;
     case VT_EMPTY:
     case VT_NULL:
@@ -3414,13 +3436,216 @@
 /**********************************************************************
  *              VarMod [OLEAUT32.154]
  *
- */
-HRESULT WINAPI VarMod(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut)
-{
-    FIXME("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft),
-          debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight),
-          debugstr_VF(pVarRight), pVarOut);
-    return E_FAIL;
+ * Perform the modulus operation of the right hand variant on the left
+ *
+ * PARAMS
+ *  left     [I] Left hand variant
+ *  right    [I] Right hand variant
+ *  result   [O] Destination for converted value
+ *
+ * RETURNS
+ *  Success: S_OK. result contains the remainder.
+ *  Failure: An HRESULT error code indicating the error.
+ *
+ * NOTE:
+ *   If an error occurs the type of result will be modified but the value will not be.
+ *   Doesn't support arrays or any special flags yet.
+ */
+HRESULT WINAPI VarMod(LPVARIANT left, LPVARIANT right, LPVARIANT result)
+{
+    BOOL         lOk        = TRUE;
+    BOOL         rOk        = TRUE;
+    HRESULT      rc         = E_FAIL;
+    int          resT = 0;
+    VARIANT      lv,rv;
+
+    VariantInit(&lv);
+    VariantInit(&rv);
+
+    TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
+		  debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);
+
+    /* check for invalid inputs */
+    lOk = TRUE;
+    switch (V_VT(left) & VT_TYPEMASK) {
+    case VT_BOOL :
+    case VT_I1   :
+    case VT_I2   :
+    case VT_I4   :
+    case VT_I8   :
+    case VT_INT  :
+    case VT_UI1  :
+    case VT_UI2  :
+    case VT_UI4  :
+    case VT_UI8  :
+    case VT_UINT :
+    case VT_R4   :
+    case VT_R8   :
+    case VT_CY   :
+    case VT_EMPTY:
+    case VT_DATE :
+    case VT_BSTR :
+      break;
+    case VT_VARIANT:
+    case VT_UNKNOWN:
+      V_VT(result) = VT_EMPTY;
+      return DISP_E_TYPEMISMATCH;
+    case VT_DECIMAL:
+      V_VT(result) = VT_EMPTY;
+      return E_INVALIDARG;
+    case VT_ERROR:
+      return DISP_E_TYPEMISMATCH;
+    case VT_RECORD:
+      V_VT(result) = VT_EMPTY;
+      return DISP_E_TYPEMISMATCH;
+    case VT_NULL:
+      break;
+    default:
+      V_VT(result) = VT_EMPTY;
+      return DISP_E_BADVARTYPE;
+    }
+
+
+    rOk = TRUE;
+    switch (V_VT(right) & VT_TYPEMASK) {
+    case VT_BOOL :
+    case VT_I1   :
+    case VT_I2   :
+    case VT_I4   :
+    case VT_I8   :
+      if((V_VT(left) == VT_INT) && (V_VT(right) == VT_I8))
+      {
+	V_VT(result) = VT_EMPTY;
+	return DISP_E_TYPEMISMATCH;
+      }
+    case VT_INT  :
+      if((V_VT(right) == VT_INT) && (V_VT(left) == VT_I8))
+      {
+	V_VT(result) = VT_EMPTY;
+	return DISP_E_TYPEMISMATCH;
+      }
+    case VT_UI1  :
+    case VT_UI2  :
+    case VT_UI4  :
+    case VT_UI8  :
+    case VT_UINT :
+    case VT_R4   :
+    case VT_R8   :
+    case VT_CY   :
+      if(V_VT(left) == VT_EMPTY)
+      {
+	V_VT(result) = VT_I4;
+	return S_OK;
+      }
+    case VT_EMPTY:
+    case VT_DATE :
+    case VT_BSTR:
+      if(V_VT(left) == VT_NULL)
+      {
+	V_VT(result) = VT_NULL;
+	return S_OK;
+      }
+      break;
+
+    case VT_VOID:
+      V_VT(result) = VT_EMPTY;
+      return DISP_E_BADVARTYPE;
+    case VT_NULL:
+      if(V_VT(left) == VT_VOID)
+      {
+	V_VT(result) = VT_EMPTY;
+	return DISP_E_BADVARTYPE;
+      } else if((V_VT(left) == VT_NULL) || (V_VT(left) == VT_EMPTY) || (V_VT(left) == VT_ERROR) ||
+		lOk)
+      {
+        V_VT(result) = VT_NULL;
+	return S_OK;
+      } else
+      {
+	V_VT(result) = VT_NULL;
+	return DISP_E_BADVARTYPE;
+      }
+    case VT_VARIANT:
+    case VT_UNKNOWN:
+      V_VT(result) = VT_EMPTY;
+      return DISP_E_TYPEMISMATCH;
+    case VT_DECIMAL:
+      if(V_VT(left) == VT_ERROR)
+      {
+	V_VT(result) = VT_EMPTY;
+	return DISP_E_TYPEMISMATCH;
+      } else
+      {
+	V_VT(result) = VT_EMPTY;
+        return E_INVALIDARG;
+      }
+    case VT_ERROR:
+      return DISP_E_TYPEMISMATCH;
+    case VT_RECORD:
+      if((V_VT(left) == 15) || ((V_VT(left) >= 24) && (V_VT(left) <= 35)) || !lOk)
+      {
+	V_VT(result) = VT_EMPTY;
+	return DISP_E_BADVARTYPE;
+      } else
+      {
+	V_VT(result) = VT_EMPTY;
+	return DISP_E_TYPEMISMATCH;
+      }
+    default:
+      V_VT(result) = VT_EMPTY;
+      return DISP_E_BADVARTYPE;
+    }
+
+    /* determine the result type */
+    if((V_VT(left) == VT_I8)        || (V_VT(right) == VT_I8))   resT = VT_I8;
+    else if((V_VT(left) == VT_UI1)  && (V_VT(right) == VT_BOOL)) resT = VT_I2;
+    else if((V_VT(left) == VT_UI1)  && (V_VT(right) == VT_UI1))  resT = VT_UI1;
+    else if((V_VT(left) == VT_UI1)  && (V_VT(right) == VT_I2))   resT = VT_I2;
+    else if((V_VT(left) == VT_I2)   && (V_VT(right) == VT_BOOL)) resT = VT_I2;
+    else if((V_VT(left) == VT_I2)   && (V_VT(right) == VT_UI1))  resT = VT_I2;
+    else if((V_VT(left) == VT_I2)   && (V_VT(right) == VT_I2))   resT = VT_I2;
+    else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_BOOL)) resT = VT_I2;
+    else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_UI1))  resT = VT_I2;
+    else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_I2))   resT = VT_I2;
+    else resT = VT_I4; /* most outputs are I4 */
+
+    /* convert to I8 for the modulo */
+    rc = VariantChangeType(&lv, left, 0, VT_I8);
+    if(FAILED(rc))
+    {
+      FIXME("Could not convert left type %d to %d? rc == 0x%lX\n", V_VT(left), VT_I8, rc);
+      return rc;
+    }
+
+    rc = VariantChangeType(&rv, right, 0, VT_I8);
+    if(FAILED(rc))
+    {
+      FIXME("Could not convert right type %d to %d? rc == 0x%lX\n", V_VT(right), VT_I8, rc);
+      return rc;
+    }
+
+    /* if right is zero set VT_EMPTY and return divide by zero */
+    if(V_I8(&rv) == 0)
+    {
+      V_VT(result) = VT_EMPTY;
+      return DISP_E_DIVBYZERO;
+    }
+
+    /* perform the modulo operation */
+    V_VT(result) = VT_I8;
+    V_I8(result) = V_I8(&lv) % V_I8(&rv);
+
+    TRACE("V_I8(left) == %ld, V_I8(right) == %ld, V_I8(result) == %ld\n", (long)V_I8(&lv), (long)V_I8(&rv), (long)V_I8(result));
+
+    /* convert left and right to the destination type */
+    rc = VariantChangeType(result, result, 0, resT);
+    if(FAILED(rc))
+    {
+      FIXME("Could not convert 0x%x to %d?\n", V_VT(result), resT);
+      return rc;
+    }
+
+    return S_OK;
 }
 
 /**********************************************************************
