Sync to Wine-20050524:
authorGé van Geldorp <ge@gse.nl>
Sat, 28 May 2005 09:35:29 +0000 (09:35 +0000)
committerGé van Geldorp <ge@gse.nl>
Sat, 28 May 2005 09:35:29 +0000 (09:35 +0000)
Alexandre Julliard <julliard@winehq.org>
- Added rules for building import libraries in the individual dll
  makefiles, and added support for building a .def.a static import
  library too.
Michael Stefaniuc <mstefani@redhat.de>
- Reimplement VarMul(). It can multiply now all variants that the native
  (WinXP) function supports too.
- Fix VariantChangeType: calls to VarDecFromCy and VarDecFromDisp had
  source and destination swapped.
Richard Cohen <richard@daijobu.co.uk>
- Remove unused macro.
- Check for VT_I8 before testing it.
- VarMod returns DISP_E_OVERFLOW not E_INVALIDARG.
Robert Shearman <rob@codeweavers.com>
- Use I_RpcGetBuffer instead of HeapReAlloc for getting the Buffer
  memory.
Vincent Beron <vberon@mecano.gme.usherb.ca>
- Use SUBLANG_NEUTRAL for French resources.
Alex Villacis Lasso <a_villacis@palosanto.com>
- Fix leftover negative sign in height parameter for transparent
  bitmap.
- Properly announce whether bitmap is transparent in get_Attributes.
- GIF transparency is now palette-index based, instead of RGB based.
- Keep original bitmap and XOR mask separate, so that get_Handle
  returns original bitmap.

svn path=/trunk/; revision=15563

reactos/lib/oleaut32/Makefile.in
reactos/lib/oleaut32/oleaut32_Fr.rc
reactos/lib/oleaut32/olepicture.c
reactos/lib/oleaut32/tmarshal.c
reactos/lib/oleaut32/variant.c

index e27d49a..e4569f2 100644 (file)
@@ -4,6 +4,7 @@ TOPOBJDIR = ../..
 SRCDIR    = @srcdir@\r
 VPATH     = @srcdir@\r
 MODULE    = oleaut32.dll\r
 SRCDIR    = @srcdir@\r
 VPATH     = @srcdir@\r
 MODULE    = oleaut32.dll\r
+IMPORTLIB = liboleaut32.$(IMPLIBEXT)\r
 IMPORTS   = ole32 rpcrt4 user32 gdi32 advapi32 kernel32 ntdll\r
 DELAYIMPORTS = comctl32 urlmon\r
 EXTRALIBS = $(LIBUNICODE) -luuid\r
 IMPORTS   = ole32 rpcrt4 user32 gdi32 advapi32 kernel32 ntdll\r
 DELAYIMPORTS = comctl32 urlmon\r
 EXTRALIBS = $(LIBUNICODE) -luuid\r
index 43e7546..553ab80 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
  */\r
 \r
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
  */\r
 \r
-LANGUAGE LANG_FRENCH, SUBLANG_DEFAULT\r
+LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL\r
 \r
 STRINGTABLE DISCARDABLE\r
 {\r
 \r
 STRINGTABLE DISCARDABLE\r
 {\r
index 2dd60cb..1eb9195 100644 (file)
@@ -132,6 +132,7 @@ typedef struct OLEPictureImpl {
 \r
   /* Bitmap transparency mask */\r
     HBITMAP hbmMask;\r
 \r
   /* Bitmap transparency mask */\r
     HBITMAP hbmMask;\r
+    HBITMAP hbmXor;\r
     COLORREF rgbTrans;\r
 \r
   /* data */\r
     COLORREF rgbTrans;\r
 \r
   /* data */\r
@@ -262,6 +263,7 @@ static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
   newObject->keepOrigFormat = TRUE;\r
 \r
   newObject->hbmMask = NULL;\r
   newObject->keepOrigFormat = TRUE;\r
 \r
   newObject->hbmMask = NULL;\r
+  newObject->hbmXor = NULL;\r
   newObject->loadtime_magic = 0xdeadbeef;\r
   newObject->loadtime_format = 0;\r
   newObject->bIsDirty = FALSE;\r
   newObject->loadtime_magic = 0xdeadbeef;\r
   newObject->loadtime_format = 0;\r
   newObject->bIsDirty = FALSE;\r
@@ -320,6 +322,8 @@ static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
     switch(Obj->desc.picType) {\r
     case PICTYPE_BITMAP:\r
       DeleteObject(Obj->desc.u.bmp.hbitmap);\r
     switch(Obj->desc.picType) {\r
     case PICTYPE_BITMAP:\r
       DeleteObject(Obj->desc.u.bmp.hbitmap);\r
+      if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);\r
+      if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);\r
       break;\r
     case PICTYPE_METAFILE:\r
       DeleteMetaFile(Obj->desc.u.wmf.hmeta);\r
       break;\r
     case PICTYPE_METAFILE:\r
       DeleteMetaFile(Obj->desc.u.wmf.hmeta);\r
@@ -588,12 +592,12 @@ static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
       SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);\r
       SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);\r
 \r
       SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);\r
       SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);\r
 \r
-      hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);\r
-\r
       if (This->hbmMask) {\r
          HDC hdcMask = CreateCompatibleDC(0);\r
          HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);\r
 \r
       if (This->hbmMask) {\r
          HDC hdcMask = CreateCompatibleDC(0);\r
          HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);\r
 \r
+          hbmpOld = SelectObject(hdcBmp, This->hbmXor);\r
+\r
          SetMapMode(hdcMask, MM_ANISOTROPIC);\r
          SetWindowOrgEx(hdcMask, 0, 0, NULL);\r
          SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);\r
          SetMapMode(hdcMask, MM_ANISOTROPIC);\r
          SetWindowOrgEx(hdcMask, 0, 0, NULL);\r
          SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);\r
@@ -607,8 +611,10 @@ static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
 \r
          SelectObject(hdcMask, hOldbm);\r
          DeleteDC(hdcMask);\r
 \r
          SelectObject(hdcMask, hOldbm);\r
          DeleteDC(hdcMask);\r
-      } else\r
+      } else {\r
+          hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);\r
          StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);\r
          StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);\r
+      }\r
 \r
       SelectObject(hdcBmp, hbmpOld);\r
       DeleteDC(hdcBmp);\r
 \r
       SelectObject(hdcBmp, hbmpOld);\r
       DeleteDC(hdcBmp);\r
@@ -739,7 +745,7 @@ static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
   TRACE("(%p)->(%p).\n", This, pdwAttr);\r
   *pdwAttr = 0;\r
   switch (This->desc.picType) {\r
   TRACE("(%p)->(%p).\n", This, pdwAttr);\r
   *pdwAttr = 0;\r
   switch (This->desc.picType) {\r
-  case PICTYPE_BITMAP:         break;  /* not 'truly' scalable, see MSDN. */\r
+  case PICTYPE_BITMAP:         if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break;       /* not 'truly' scalable, see MSDN. */\r
   case PICTYPE_ICON: *pdwAttr     = PICTURE_TRANSPARENT;break;\r
   case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;\r
   default:FIXME("Unknown pictype %d\n",This->desc.picType);break;\r
   case PICTYPE_ICON: *pdwAttr     = PICTURE_TRANSPARENT;break;\r
   case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;\r
   default:FIXME("Unknown pictype %d\n",This->desc.picType);break;\r
@@ -1175,15 +1181,60 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
        HBITMAP hOldbitmap; \r
        HBITMAP hOldbitmapmask;\r
 \r
        HBITMAP hOldbitmap; \r
        HBITMAP hOldbitmapmask;\r
 \r
-       This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);\r
-\r
-       hOldbitmap = SelectObject(hdc,This->desc.u.bmp.hbitmap);\r
+        unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;\r
+        HBITMAP hTempMask;\r
+\r
+        This->hbmXor = CreateDIBitmap(\r
+            hdcref,\r
+            &bmi->bmiHeader,\r
+            CBM_INIT,\r
+            bytes,\r
+            bmi,\r
+            DIB_RGB_COLORS\r
+        );\r
+\r
+        bmi->bmiColors[0].rgbRed = 0;\r
+        bmi->bmiColors[0].rgbGreen = 0;\r
+        bmi->bmiColors[0].rgbBlue = 0;\r
+        bmi->bmiColors[1].rgbRed = 255;\r
+        bmi->bmiColors[1].rgbGreen = 255;\r
+        bmi->bmiColors[1].rgbBlue = 255;\r
+\r
+        bmi->bmiHeader.biBitCount              = 1;\r
+        bmi->bmiHeader.biSizeImage             = monopadding*gif->SHeight;\r
+        bmi->bmiHeader.biClrUsed               = 2;\r
+\r
+        for (i = 0; i < gif->SHeight; i++) {\r
+            unsigned char * colorPointer = bytes + padding * i;\r
+            unsigned char * monoPointer = bytes + monopadding * i;\r
+            for (j = 0; j < gif->SWidth; j++) {\r
+                unsigned char pixel = colorPointer[j];\r
+                if ((j & 7) == 0) monoPointer[j >> 3] = 0;\r
+                if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));\r
+            }\r
+        }\r
+        hdcref = GetDC(0);\r
+        hTempMask = CreateDIBitmap(\r
+                hdcref,\r
+                &bmi->bmiHeader,\r
+                CBM_INIT,\r
+                bytes,\r
+                bmi,\r
+                DIB_RGB_COLORS\r
+        );\r
+        DeleteDC(hdcref);\r
+\r
+        bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;\r
+        This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);\r
+       hOldbitmap = SelectObject(hdc, hTempMask);\r
        hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);\r
        hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);\r
-       SetBkColor(hdc, This->rgbTrans);\r
+\r
+        SetBkColor(hdc, RGB(255, 255, 255));\r
        BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);\r
 \r
        /* We no longer need the original bitmap, so we apply the first\r
           transformation with the mask to speed up the rendering */\r
        BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);\r
 \r
        /* We no longer need the original bitmap, so we apply the first\r
           transformation with the mask to speed up the rendering */\r
+        SelectObject(hdc, This->hbmXor);\r
        SetBkColor(hdc, RGB(0,0,0));\r
        SetTextColor(hdc, RGB(255,255,255));\r
        BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, \r
        SetBkColor(hdc, RGB(0,0,0));\r
        SetTextColor(hdc, RGB(255,255,255));\r
        BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, \r
@@ -1193,6 +1244,7 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
        SelectObject(hdcMask, hOldbitmapmask);\r
        DeleteDC(hdcMask);\r
        DeleteDC(hdc);\r
        SelectObject(hdcMask, hOldbitmapmask);\r
        DeleteDC(hdcMask);\r
        DeleteDC(hdc);\r
+        DeleteObject(hTempMask);\r
     }\r
     \r
     DeleteDC(hdcref);\r
     }\r
     \r
     DeleteDC(hdcref);\r
index 9159122..12aafdb 100644 (file)
@@ -1979,7 +1979,8 @@ TMStubImpl_Invoke(
 \r
     memset(&buf,0,sizeof(buf));\r
     buf.size   = xmsg->cbBuffer;\r
 \r
     memset(&buf,0,sizeof(buf));\r
     buf.size   = xmsg->cbBuffer;\r
-    buf.base   = xmsg->Buffer;\r
+    buf.base   = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);\r
+    memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);\r
     buf.curoff = 0;\r
     buf.iid    = IID_IUnknown;\r
 \r
     buf.curoff = 0;\r
     buf.iid    = IID_IUnknown;\r
 \r
@@ -2173,9 +2174,9 @@ afterserialize:
     if (hres != S_OK)\r
        return hres;\r
    \r
     if (hres != S_OK)\r
        return hres;\r
    \r
-    /* might need to use IRpcChannelBuffer_GetBuffer ? */\r
     xmsg->cbBuffer     = buf.curoff;\r
     xmsg->cbBuffer     = buf.curoff;\r
-    xmsg->Buffer       = buf.base;\r
+    I_RpcGetBuffer((RPC_MESSAGE *)xmsg);\r
+    memcpy(xmsg->Buffer, buf.base, buf.curoff);\r
     HeapFree(GetProcessHeap(),0,args);\r
     return S_OK;\r
 }\r
     HeapFree(GetProcessHeap(),0,args);\r
     return S_OK;\r
 }\r
index 917d6bc..80b2e39 100644 (file)
@@ -493,8 +493,8 @@ static inline HRESULT VARIANT_Coerce(VARIANTARG* pd, LCID lcid, USHORT wFlags,
     case VT_R4:       return VarDecFromR4(V_R4(ps), &V_DECIMAL(pd));\r
     case VT_R8:       return VarDecFromR8(V_R8(ps), &V_DECIMAL(pd));\r
     case VT_DATE:     return VarDecFromDate(V_DATE(ps), &V_DECIMAL(pd));\r
     case VT_R4:       return VarDecFromR4(V_R4(ps), &V_DECIMAL(pd));\r
     case VT_R8:       return VarDecFromR8(V_R8(ps), &V_DECIMAL(pd));\r
     case VT_DATE:     return VarDecFromDate(V_DATE(ps), &V_DECIMAL(pd));\r
-    case VT_CY:       return VarDecFromCy(V_CY(pd), &V_DECIMAL(ps));\r
-    case VT_DISPATCH: return VarDecFromDisp(V_DISPATCH(ps), lcid, &V_DECIMAL(ps));\r
+    case VT_CY:       return VarDecFromCy(V_CY(ps), &V_DECIMAL(pd));\r
+    case VT_DISPATCH: return VarDecFromDisp(V_DISPATCH(ps), lcid, &V_DECIMAL(pd));\r
     case VT_BSTR:     return VarDecFromStr(V_BSTR(ps), lcid, dwFlags, &V_DECIMAL(pd));\r
     }\r
     break;\r
     case VT_BSTR:     return VarDecFromStr(V_BSTR(ps), lcid, dwFlags, &V_DECIMAL(pd));\r
     }\r
     break;\r
@@ -2914,58 +2914,168 @@ HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
 /**********************************************************************\r
  *              VarMul [OLEAUT32.156]\r
  *\r
 /**********************************************************************\r
  *              VarMul [OLEAUT32.156]\r
  *\r
+ * Multiply two variants.\r
+ *\r
+ * PARAMS\r
+ *  left    [I] First variant\r
+ *  right   [I] Second variant\r
+ *  result  [O] Result variant\r
+ *\r
+ * RETURNS\r
+ *  Success: S_OK.\r
+ *  Failure: An HRESULT error code indicating the error.\r
+ *\r
+ * NOTES\r
+ *  Native VarMul up to and including WinXP dosn't like as input variants\r
+ *  I1, UI2, UI4, UI8, INT and UINT. But it can multiply apples with oranges.\r
+ *\r
+ *  Native VarMul dosn't check for NULL in/out pointers and crashes. We do the\r
+ *  same here.\r
+ *\r
+ * FIXME\r
+ *  Overflow checking for R8 (double) overflow. Return DISP_E_OVERFLOW in that\r
+ *  case.\r
  */\r
 HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)\r
 {\r
  */\r
 HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)\r
 {\r
-    HRESULT rc = E_FAIL;\r
-    VARTYPE lvt,rvt,resvt;\r
-    VARIANT lv,rv;\r
-    BOOL found;\r
+    HRESULT hres;\r
+    VARTYPE lvt, rvt, resvt, tvt;\r
+    VARIANT lv, rv, tv;\r
+    double r8res;\r
+\r
+    /* Variant priority for coercion. Sorted from lowest to highest.\r
+       VT_ERROR shows an invalid input variant type. */\r
+    enum coerceprio { vt_UI1 = 0, vt_I2, vt_I4, vt_I8, vt_CY, vt_R4, vt_R8,\r
+                      vt_DECIMAL, vt_NULL, vt_ERROR };\r
+    /* Mapping from priority to variant type. Keep in sync with coerceprio! */\r
+    VARTYPE prio2vt[] = { VT_UI1, VT_I2, VT_I4, VT_I8, VT_CY, VT_R4, VT_R8,\r
+                          VT_DECIMAL, VT_NULL, VT_ERROR };\r
+\r
+    /* Mapping for coercion from input variant to priority of result variant. */\r
+    static VARTYPE coerce[] = {\r
+        /* VT_EMPTY, VT_NULL, VT_I2, VT_I4, VT_R4 */\r
+        vt_UI1, vt_NULL, vt_I2, vt_I4, vt_R4,\r
+        /* VT_R8, VT_CY, VT_DATE, VT_BSTR, VT_DISPATCH */\r
+        vt_R8, vt_CY, vt_R8, vt_R8, vt_ERROR,\r
+        /* VT_ERROR, VT_BOOL, VT_VARIANT, VT_UNKNOWN, VT_DECIMAL */\r
+        vt_ERROR, vt_I2, vt_ERROR, vt_ERROR, vt_DECIMAL,\r
+        /* 15, VT_I1, VT_UI1, VT_UI2, VT_UI4 VT_I8 */\r
+        vt_ERROR, vt_ERROR, vt_UI1, vt_ERROR, vt_ERROR, vt_I8\r
+    };\r
 \r
     TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),\r
 \r
     TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),\r
-          debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);\r
+          debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right),\r
+          result);\r
 \r
 \r
-    VariantInit(&lv);VariantInit(&rv);\r
+    VariantInit(&lv);\r
+    VariantInit(&rv);\r
+    VariantInit(&tv);\r
     lvt = V_VT(left)&VT_TYPEMASK;\r
     rvt = V_VT(right)&VT_TYPEMASK;\r
     lvt = V_VT(left)&VT_TYPEMASK;\r
     rvt = V_VT(right)&VT_TYPEMASK;\r
-    found = FALSE;resvt=VT_VOID;\r
-    if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8)) {\r
-       found = TRUE;\r
-       resvt = VT_R8;\r
-    }\r
-    if (!found && (((1<<lvt) | (1<<rvt)) & (VTBIT_I1|VTBIT_I2|VTBIT_UI1|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|(1<<VT_INT)|(1<<VT_UINT)))) {\r
-       found = TRUE;\r
-       resvt = VT_I4;\r
-    }\r
-    if (!found) {\r
-       FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);\r
-       return E_FAIL;\r
-    }\r
-    rc = VariantChangeType(&lv, left, 0, resvt);\r
-    if (FAILED(rc)) {\r
-       FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);\r
-       return rc;\r
+\r
+    /* If we have any flag set (VT_ARRAY, VT_VECTOR, etc.) bail out.\r
+       Same for any input variant type > VT_I8 */\r
+    if (V_VT(left) & ~VT_TYPEMASK || V_VT(right) & ~VT_TYPEMASK ||\r
+        lvt > VT_I8 || rvt > VT_I8) {\r
+        hres = DISP_E_BADVARTYPE;\r
+        goto end;\r
     }\r
     }\r
-    rc = VariantChangeType(&rv, right, 0, resvt);\r
-    if (FAILED(rc)) {\r
-       FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);\r
-       return rc;\r
+\r
+    /* Determine the variant type to coerce to. */\r
+    if (coerce[lvt] > coerce[rvt]) {\r
+        resvt = prio2vt[coerce[lvt]];\r
+        tvt = prio2vt[coerce[rvt]];\r
+    } else {\r
+        resvt = prio2vt[coerce[rvt]];\r
+        tvt = prio2vt[coerce[lvt]];\r
     }\r
     }\r
+\r
+    /* Special cases where the result variant type is defined by both\r
+       input variants and not only that with the highest priority */\r
+    if (resvt == VT_R4 && (tvt == VT_CY || tvt == VT_I8 || tvt == VT_I4))\r
+        resvt = VT_R8;\r
+    if (lvt == VT_EMPTY && rvt == VT_EMPTY)\r
+        resvt = VT_I2;\r
+\r
+    /* For overflow detection use the biggest compatible type for the\r
+       multiplication */\r
     switch (resvt) {\r
     switch (resvt) {\r
-    case VT_R8:\r
-       V_VT(result) = resvt;\r
-       V_R8(result) = V_R8(&lv) * V_R8(&rv);\r
-       rc = S_OK;\r
-       break;\r
-    case VT_I4:\r
-       V_VT(result) = resvt;\r
-       V_I4(result) = V_I4(&lv) * V_I4(&rv);\r
-       rc = S_OK;\r
-       break;\r
+        case VT_ERROR:\r
+            hres = DISP_E_BADVARTYPE;\r
+            goto end;\r
+        case VT_NULL:\r
+            hres = S_OK;\r
+            V_VT(result) = VT_NULL;\r
+            goto end;\r
+        case VT_UI1:\r
+        case VT_I2:\r
+        case VT_I4:\r
+        case VT_I8:\r
+            tvt = VT_I8;\r
+            break;\r
+        case VT_R4:\r
+            tvt = VT_R8;\r
+            break;\r
+        default:\r
+            tvt = resvt;\r
+    }\r
+\r
+    /* Now coerce the variants */\r
+    hres = VariantChangeType(&lv, left, 0, tvt);\r
+    if (FAILED(hres))\r
+        goto end;\r
+    hres = VariantChangeType(&rv, right, 0, tvt);\r
+    if (FAILED(hres))\r
+        goto end;\r
+\r
+    /* Do the math */\r
+    hres = S_OK;\r
+    V_VT(&tv) = tvt;\r
+    V_VT(result) = resvt;\r
+    switch (tvt) {\r
+        case VT_DECIMAL:\r
+            hres = VarDecMul(&V_DECIMAL(&lv), &V_DECIMAL(&rv),\r
+                             &V_DECIMAL(result));\r
+            goto end;\r
+        case VT_CY:\r
+            hres = VarCyMul(V_CY(&lv), V_CY(&rv), &V_CY(result));\r
+            goto end;\r
+        case VT_I8:\r
+            /* Overflow detection */\r
+            r8res = (double)V_I8(&lv) * (double)V_I8(&rv);\r
+            if (r8res > (double)I8_MAX || r8res < (double)I8_MIN) {\r
+                V_VT(result) = VT_R8;\r
+                V_R8(result) = r8res;\r
+                goto end;\r
+            } else\r
+                V_I8(&tv) = V_I8(&lv) * V_I8(&rv);\r
+            break;\r
+        case VT_R8:\r
+            /* FIXME: overflow detection */\r
+            V_R8(&tv) = V_R8(&lv) * V_R8(&rv);\r
+            break;\r
+        default:\r
+            ERR("We shouldn't get here! tvt = %d!\n", tvt);\r
+            break;\r
     }\r
     }\r
-    TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result),\r
-          debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result));\r
-    return rc;\r
+    if (rvt != tvt) {\r
+        while ((hres = VariantChangeType(result, &tv, 0, resvt)) != S_OK) {\r
+            /* Overflow! Change to the vartype with the next higher priority */\r
+            resvt = prio2vt[coerce[resvt] + 1];\r
+        }\r
+    } else\r
+        hres = VariantCopy(result, &tv);\r
+\r
+end:\r
+    if (hres != S_OK) {\r
+        V_VT(result) = VT_EMPTY;\r
+        V_I4(result) = 0;       /* No V_EMPTY */\r
+    }\r
+    VariantClear(&lv);\r
+    VariantClear(&rv);\r
+    VariantClear(&tv);\r
+    TRACE("returning 0x%8lx (variant type %s)\n", hres, debugstr_VT(result));\r
+    return hres;\r
 }\r
 \r
 /**********************************************************************\r
 }\r
 \r
 /**********************************************************************\r
@@ -4267,7 +4377,7 @@ HRESULT WINAPI VarMod(LPVARIANT left, LPVARIANT right, LPVARIANT result)
       return DISP_E_TYPEMISMATCH;\r
     case VT_DECIMAL:\r
       V_VT(result) = VT_EMPTY;\r
       return DISP_E_TYPEMISMATCH;\r
     case VT_DECIMAL:\r
       V_VT(result) = VT_EMPTY;\r
-      return E_INVALIDARG;\r
+      return DISP_E_OVERFLOW;\r
     case VT_ERROR:\r
       return DISP_E_TYPEMISMATCH;\r
     case VT_RECORD:\r
     case VT_ERROR:\r
       return DISP_E_TYPEMISMATCH;\r
     case VT_RECORD:\r
@@ -4352,7 +4462,7 @@ HRESULT WINAPI VarMod(LPVARIANT left, LPVARIANT right, LPVARIANT result)
       } else\r
       {\r
        V_VT(result) = VT_EMPTY;\r
       } else\r
       {\r
        V_VT(result) = VT_EMPTY;\r
-        return E_INVALIDARG;\r
+        return DISP_E_OVERFLOW;\r
       }\r
     case VT_ERROR:\r
       return DISP_E_TYPEMISMATCH;\r
       }\r
     case VT_ERROR:\r
       return DISP_E_TYPEMISMATCH;\r