Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / oleaut32 / vartype.c
index e40318a..1214752 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+
+#define COBJMACROS
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
+
 #include "wine/debug.h"
 #include "wine/unicode.h"
 #include "winbase.h"
 #include "variant.h"
 #include "resource.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(ole);
-
+WINE_DEFAULT_DEBUG_CHANNEL(variant);
 
 extern HMODULE OLEAUT32_hModule;
 
+#define CY_MULTIPLIER   10000             /* 4 dp of precision */
+#define CY_MULTIPLIER_F 10000.0
+#define CY_HALF         (CY_MULTIPLIER/2) /* 0.5 */
+#define CY_HALF_F       (CY_MULTIPLIER_F/2.0)
+
 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
 
@@ -44,20 +51,17 @@ static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOu
   case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
   case VT_BOOL:
   case VT_I2:
-  case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT));
-       break;
+  case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
   case VT_R4:
   case VT_INT:
   case VT_I4:
   case VT_UINT:
-  case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG));
-       break;
+  case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
   case VT_R8:
   case VT_DATE:
   case VT_CY:
   case VT_I8:
-  case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64));
-       break;
+  case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
   case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
   case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
   default:
@@ -65,10 +69,24 @@ static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOu
   }
 }
 
+/* Macro to inline conversion from a float or double to any integer type,
+ * rounding according to the 'dutch' convention.
+ */
+#define VARIANT_DutchRound(typ, value, res) do { \
+  double whole = value < 0 ? ceil(value) : floor(value); \
+  double fract = value - whole; \
+  if (fract > 0.5) res = (typ)whole + (typ)1; \
+  else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
+  else if (fract >= 0.0) res = (typ)whole; \
+  else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
+  else if (fract > -0.5) res = (typ)whole; \
+  else res = (typ)whole - (typ)1; \
+} while(0);
+
 
 /* Coerce VT_BSTR to a numeric type */
-HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
-                               void* pOut, VARTYPE vt)
+static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
+                                      void* pOut, VARTYPE vt)
 {
   VARIANTARG dstVar;
   HRESULT hRet;
@@ -92,7 +110,7 @@ HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
 }
 
 /* Coerce VT_DISPATCH to another type */
-HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
+static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
 {
   static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
   VARIANTARG srcVar, dstVar;
@@ -123,6 +141,128 @@ HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
   return hRet;
 }
 
+/* Inline return type */
+#define RETTYP inline static HRESULT
+
+
+/* Simple compiler cast from one type to another */
+#define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
+  *out = in; return S_OK; }
+
+/* Compiler cast where input cannot be negative */
+#define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
+  if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
+
+/* Compiler cast where input cannot be > some number */
+#define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
+  if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
+
+/* Compiler cast where input cannot be < some number or >= some other number */
+#define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
+  if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
+
+/* I1 */
+POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX);
+BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX);
+BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX);
+SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool);
+POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX);
+POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX);
+BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX);
+POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX);
+
+/* UI1 */
+BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX);
+SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool);
+NEGTST(BYTE, signed char, VarUI1FromI1);
+POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX);
+BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX);
+POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX);
+BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX);
+POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX);
+
+/* I2 */
+SIMPLE(SHORT, BYTE, VarI2FromUI1);
+BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX);
+SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool);
+SIMPLE(SHORT, signed char, VarI2FromI1);
+POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX);
+POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX);
+BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX);
+POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX);
+
+/* UI2 */
+SIMPLE(USHORT, BYTE, VarUI2FromUI1);
+NEGTST(USHORT, SHORT, VarUI2FromI2);
+BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX);
+SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool);
+NEGTST(USHORT, signed char, VarUI2FromI1);
+POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX);
+BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX);
+POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX);
+
+/* I4 */
+SIMPLE(LONG, BYTE, VarI4FromUI1);
+SIMPLE(LONG, SHORT, VarI4FromI2);
+SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool);
+SIMPLE(LONG, signed char, VarI4FromI1);
+SIMPLE(LONG, USHORT, VarI4FromUI2);
+POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX);
+BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX);
+POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX);
+
+/* UI4 */
+SIMPLE(ULONG, BYTE, VarUI4FromUI1);
+NEGTST(ULONG, SHORT, VarUI4FromI2);
+NEGTST(ULONG, LONG, VarUI4FromI4);
+SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool);
+NEGTST(ULONG, signed char, VarUI4FromI1);
+SIMPLE(ULONG, USHORT, VarUI4FromUI2);
+BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX);
+POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX);
+
+/* I8 */
+SIMPLE(LONG64, BYTE, VarI8FromUI1);
+SIMPLE(LONG64, SHORT, VarI8FromI2);
+SIMPLE(LONG64, signed char, VarI8FromI1);
+SIMPLE(LONG64, USHORT, VarI8FromUI2);
+SIMPLE(LONG64, LONG, VarI8FromI4);
+SIMPLE(LONG64, ULONG, VarI8FromUI4);
+POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX);
+
+/* UI8 */
+SIMPLE(ULONG64, BYTE, VarUI8FromUI1);
+NEGTST(ULONG64, SHORT, VarUI8FromI2);
+NEGTST(ULONG64, signed char, VarUI8FromI1);
+SIMPLE(ULONG64, USHORT, VarUI8FromUI2);
+NEGTST(ULONG64, LONG, VarUI8FromI4);
+SIMPLE(ULONG64, ULONG, VarUI8FromUI4);
+NEGTST(ULONG64, LONG64, VarUI8FromI8);
+
+/* R4 (float) */
+SIMPLE(float, BYTE, VarR4FromUI1);
+SIMPLE(float, SHORT, VarR4FromI2);
+SIMPLE(float, signed char, VarR4FromI1);
+SIMPLE(float, USHORT, VarR4FromUI2);
+SIMPLE(float, LONG, VarR4FromI4);
+SIMPLE(float, ULONG, VarR4FromUI4);
+SIMPLE(float, LONG64, VarR4FromI8);
+SIMPLE(float, ULONG64, VarR4FromUI8);
+
+/* R8 (double) */
+SIMPLE(double, BYTE, VarR8FromUI1);
+SIMPLE(double, SHORT, VarR8FromI2);
+SIMPLE(double, float, VarR8FromR4);
+RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
+SIMPLE(double, DATE, VarR8FromDate);
+SIMPLE(double, signed char, VarR8FromI1);
+SIMPLE(double, USHORT, VarR8FromUI2);
+SIMPLE(double, LONG, VarR8FromI4);
+SIMPLE(double, ULONG, VarR8FromUI4);
+SIMPLE(double, LONG64, VarR8FromI8);
+SIMPLE(double, ULONG64, VarR8FromUI8);
+
+
 /* I1
  */
 
@@ -199,7 +339,7 @@ HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
  */
 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
 {
-  return _VarI1FromR4(fltIn, pcOut);
+  return VarI1FromR8(fltIn, pcOut);
 }
 
 /************************************************************************
@@ -223,7 +363,7 @@ HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
 {
   if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(CHAR, dblIn, *pcOut);
+  VARIANT_DutchRound(CHAR, dblIn, *pcOut);
   return S_OK;
 }
 
@@ -243,7 +383,7 @@ HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
  */
 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
 {
-  return _VarI1FromDate(dateIn, pcOut);
+  return VarI1FromR8(dateIn, pcOut);
 }
 
 /************************************************************************
@@ -264,7 +404,7 @@ HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
 {
   LONG i = I1_MAX + 1;
 
-  _VarI4FromCy(cyIn, &i);
+  VarI4FromCy(cyIn, &i);
   return _VarI1FromI4(i, pcOut);
 }
 
@@ -287,7 +427,7 @@ HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
  */
 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
 {
-  return _VarI1FromStr(strIn, lcid, dwFlags, pcOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
 }
 
 /************************************************************************
@@ -308,7 +448,7 @@ HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed cha
  */
 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
 {
-  return _VarI1FromDisp(pdispIn, lcid, pcOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1);
 }
 
 /************************************************************************
@@ -386,7 +526,7 @@ HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
   LONG64 i64;
   HRESULT hRet;
 
-  hRet = _VarI8FromDec(pdecIn, &i64);
+  hRet = VarI8FromDec(pdecIn, &i64);
 
   if (SUCCEEDED(hRet))
     hRet = _VarI1FromI8(i64, pcOut);
@@ -489,7 +629,7 @@ HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
  */
 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
 {
-  return _VarUI1FromR4(fltIn, pbOut);
+  return VarUI1FromR8(fltIn, pbOut);
 }
 
 /************************************************************************
@@ -513,7 +653,7 @@ HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
 {
   if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(BYTE, dblIn, *pbOut);
+  VARIANT_DutchRound(BYTE, dblIn, *pbOut);
   return S_OK;
 }
 
@@ -538,7 +678,7 @@ HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
 {
   ULONG i = UI1_MAX + 1;
 
-  _VarUI4FromCy(cyIn, &i);
+  VarUI4FromCy(cyIn, &i);
   return _VarUI1FromUI4(i, pbOut);
 }
 
@@ -558,7 +698,7 @@ HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
  */
 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
 {
-  return _VarUI1FromDate(dateIn, pbOut);
+  return VarUI1FromR8(dateIn, pbOut);
 }
 
 /************************************************************************
@@ -580,7 +720,7 @@ HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
  */
 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
 {
-  return _VarUI1FromStr(strIn, lcid, dwFlags, pbOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
 }
 
 /************************************************************************
@@ -601,7 +741,7 @@ HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbO
  */
 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
 {
-  return _VarUI1FromDisp(pdispIn, lcid, pbOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1);
 }
 
 /************************************************************************
@@ -697,7 +837,7 @@ HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
   LONG64 i64;
   HRESULT hRet;
 
-  hRet = _VarI8FromDec(pdecIn, &i64);
+  hRet = VarI8FromDec(pdecIn, &i64);
 
   if (SUCCEEDED(hRet))
     hRet = _VarUI1FromI8(i64, pbOut);
@@ -796,7 +936,7 @@ HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
  */
 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
 {
-  return _VarI2FromR4(fltIn, psOut);
+  return VarI2FromR8(fltIn, psOut);
 }
 
 /************************************************************************
@@ -819,7 +959,7 @@ HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
 {
   if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(SHORT, dblIn, *psOut);
+  VARIANT_DutchRound(SHORT, dblIn, *psOut);
   return S_OK;
 }
 
@@ -840,7 +980,7 @@ HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
 {
   LONG i = I2_MAX + 1;
 
-  _VarI4FromCy(cyIn, &i);
+  VarI4FromCy(cyIn, &i);
   return _VarI2FromI4(i, psOut);
 }
 
@@ -859,7 +999,7 @@ HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
  */
 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
 {
-  return _VarI2FromDate(dateIn, psOut);
+  return VarI2FromR8(dateIn, psOut);
 }
 
 /************************************************************************
@@ -881,7 +1021,7 @@ HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
  */
 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
 {
-  return _VarI2FromStr(strIn, lcid, dwFlags, psOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
 }
 
 /************************************************************************
@@ -902,7 +1042,7 @@ HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psO
  */
 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
 {
-  return _VarI2FromDisp(pdispIn, lcid, psOut);
+  return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2);
 }
 
 /************************************************************************
@@ -994,7 +1134,7 @@ HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
   LONG64 i64;
   HRESULT hRet;
 
-  hRet = _VarI8FromDec(pdecIn, &i64);
+  hRet = VarI8FromDec(pdecIn, &i64);
 
   if (SUCCEEDED(hRet))
     hRet = _VarI2FromI8(i64, psOut);
@@ -1108,7 +1248,7 @@ HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
  */
 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
 {
-  return _VarUI2FromR4(fltIn, pusOut);
+  return VarUI2FromR8(fltIn, pusOut);
 }
 
 /************************************************************************
@@ -1131,7 +1271,7 @@ HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
 {
   if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(USHORT, dblIn, *pusOut);
+  VARIANT_DutchRound(USHORT, dblIn, *pusOut);
   return S_OK;
 }
 
@@ -1150,7 +1290,7 @@ HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
  */
 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
 {
-  return _VarUI2FromDate(dateIn, pusOut);
+  return VarUI2FromR8(dateIn, pusOut);
 }
 
 /************************************************************************
@@ -1173,7 +1313,7 @@ HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
 {
   ULONG i = UI2_MAX + 1;
 
-  _VarUI4FromCy(cyIn, &i);
+  VarUI4FromCy(cyIn, &i);
   return _VarUI2FromUI4(i, pusOut);
 }
 
@@ -1195,7 +1335,7 @@ HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
  */
 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
 {
-  return _VarUI2FromStr(strIn, lcid, dwFlags, pusOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
 }
 
 /************************************************************************
@@ -1216,7 +1356,7 @@ HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* p
  */
 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
 {
-  return _VarUI2FromDisp(pdispIn, lcid, pusOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2);
 }
 
 /************************************************************************
@@ -1291,7 +1431,7 @@ HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
   LONG64 i64;
   HRESULT hRet;
 
-  hRet = _VarI8FromDec(pdecIn, &i64);
+  hRet = VarI8FromDec(pdecIn, &i64);
 
   if (SUCCEEDED(hRet))
     hRet = _VarUI2FromI8(i64, pusOut);
@@ -1360,7 +1500,7 @@ HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
  * Convert a VT_I2 to a VT_I4.
  *
  * PARAMS
- *  iIn     [I] Source
+ *  sIn     [I] Source
  *  piOut   [O] Destination
  *
  * RETURNS
@@ -1388,7 +1528,7 @@ HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
  */
 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
 {
-  return _VarI4FromR4(fltIn, piOut);
+  return VarI4FromR8(fltIn, piOut);
 }
 
 /************************************************************************
@@ -1411,7 +1551,7 @@ HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
 {
   if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(LONG, dblIn, *piOut);
+  VARIANT_DutchRound(LONG, dblIn, *piOut);
   return S_OK;
 }
 
@@ -1431,7 +1571,7 @@ HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
 {
   double d = cyIn.int64 / CY_MULTIPLIER_F;
-  return _VarI4FromR8(d, piOut);
+  return VarI4FromR8(d, piOut);
 }
 
 /************************************************************************
@@ -1449,7 +1589,7 @@ HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
  */
 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
 {
-  return _VarI4FromDate(dateIn, piOut);
+  return VarI4FromR8(dateIn, piOut);
 }
 
 /************************************************************************
@@ -1471,7 +1611,7 @@ HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
  */
 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
 {
-  return _VarI4FromStr(strIn, lcid, dwFlags, piOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
 }
 
 /************************************************************************
@@ -1492,7 +1632,7 @@ HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOu
  */
 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
 {
-  return _VarI4FromDisp(pdispIn, lcid, piOut);
+  return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4);
 }
 
 /************************************************************************
@@ -1583,7 +1723,7 @@ HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
   LONG64 i64;
   HRESULT hRet;
 
-  hRet = _VarI8FromDec(pdecIn, &i64);
+  hRet = VarI8FromDec(pdecIn, &i64);
 
   if (SUCCEEDED(hRet))
     hRet = _VarI4FromI8(i64, piOut);
@@ -1697,7 +1837,7 @@ HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
  */
 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
 {
-  return _VarUI4FromR4(fltIn, pulOut);
+  return VarUI4FromR8(fltIn, pulOut);
 }
 
 /************************************************************************
@@ -1720,7 +1860,7 @@ HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
 {
   if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(ULONG, dblIn, *pulOut);
+  VARIANT_DutchRound(ULONG, dblIn, *pulOut);
   return S_OK;
 }
 
@@ -1739,7 +1879,7 @@ HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
  */
 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
 {
-  return _VarUI4FromDate(dateIn, pulOut);
+  return VarUI4FromR8(dateIn, pulOut);
 }
 
 /************************************************************************
@@ -1758,10 +1898,9 @@ HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
 {
   double d = cyIn.int64 / CY_MULTIPLIER_F;
-  return _VarUI4FromR8(d, pulOut);
+  return VarUI4FromR8(d, pulOut);
 }
 
-
 /************************************************************************
  * VarUI4FromStr (OLEAUT32.277)
  *
@@ -1781,7 +1920,7 @@ HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
  */
 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
 {
-  return _VarUI4FromStr(strIn, lcid, dwFlags, pulOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
 }
 
 /************************************************************************
@@ -1802,7 +1941,7 @@ HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pu
  */
 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
 {
-  return _VarUI4FromDisp(pdispIn, lcid, pulOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4);
 }
 
 /************************************************************************
@@ -1876,7 +2015,7 @@ HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
   LONG64 i64;
   HRESULT hRet;
 
-  hRet = _VarI8FromDec(pdecIn, &i64);
+  hRet = VarI8FromDec(pdecIn, &i64);
 
   if (SUCCEEDED(hRet))
     hRet = _VarUI4FromI8(i64, pulOut);
@@ -1973,7 +2112,7 @@ HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
  */
 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
 {
-  return _VarI8FromR4(fltIn, pi64Out);
+  return VarI8FromR8(fltIn, pi64Out);
 }
 
 /************************************************************************
@@ -2011,11 +2150,10 @@ HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
 {
   if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(LONG64, dblIn, *pi64Out);
+  VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
   return S_OK;
 }
 
-
 /************************************************************************
  * VarI8FromCy (OLEAUT32.337)
  *
@@ -2067,7 +2205,7 @@ HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
  */
 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
 {
-  return _VarI8FromDate(dateIn, pi64Out);
+  return VarI8FromR8(dateIn, pi64Out);
 }
 
 /************************************************************************
@@ -2089,7 +2227,7 @@ HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
  */
 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
 {
-  return _VarI8FromStr(strIn, lcid, dwFlags, pi64Out);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
 }
 
 /************************************************************************
@@ -2110,7 +2248,7 @@ HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi
  */
 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
 {
-  return _VarI8FromDisp(pdispIn, lcid, pi64Out);
+  return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8);
 }
 
 /************************************************************************
@@ -2127,7 +2265,7 @@ HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
  */
 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
 {
-  return _VarI8FromBool(boolIn, pi64Out);
+  return VarI8FromI2(boolIn, pi64Out);
 }
 
 /************************************************************************
@@ -2218,7 +2356,7 @@ HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
     HRESULT hRet;
     double dbl;
 
-    hRet = _VarR8FromDec(pdecIn, &dbl);
+    hRet = VarR8FromDec(pdecIn, &dbl);
     if (SUCCEEDED(hRet))
       hRet = VarI8FromR8(dbl, pi64Out);
     return hRet;
@@ -2313,7 +2451,7 @@ HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
  */
 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
 {
-  return _VarUI8FromR4(fltIn, pui64Out);
+  return VarUI8FromR8(fltIn, pui64Out);
 }
 
 /************************************************************************
@@ -2337,7 +2475,7 @@ HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
 {
   if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
     return DISP_E_OVERFLOW;
-  OLEAUT32_DutchRound(ULONG64, dblIn, *pui64Out);
+  VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
   return S_OK;
 }
 
@@ -2395,7 +2533,7 @@ HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
  */
 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
 {
-  return _VarUI8FromDate(dateIn, pui64Out);
+  return VarUI8FromR8(dateIn, pui64Out);
 }
 
 /************************************************************************
@@ -2417,7 +2555,7 @@ HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
  */
 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
 {
-  return _VarUI8FromStr(strIn, lcid, dwFlags, pui64Out);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
 }
 
 /************************************************************************
@@ -2438,7 +2576,7 @@ HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64*
  */
 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
 {
-  return _VarUI8FromDisp(pdispIn, lcid, pui64Out);
+  return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8);
 }
 
 /************************************************************************
@@ -2456,7 +2594,7 @@ HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
  */
 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
 {
-  return _VarUI8FromBool(boolIn, pui64Out);
+  return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
 }
 /************************************************************************
  * VarUI8FromI1 (OLEAUT32.438)
@@ -2556,7 +2694,7 @@ HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
     HRESULT hRet;
     double dbl;
 
-    hRet = _VarR8FromDec(pdecIn, &dbl);
+    hRet = VarR8FromDec(pdecIn, &dbl);
     if (SUCCEEDED(hRet))
       hRet = VarUI8FromR8(dbl, pui64Out);
     return hRet;
@@ -2632,7 +2770,10 @@ HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
  */
 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
 {
-  return _VarR4FromR8(dblIn, pFltOut);
+  double d = dblIn < 0.0 ? -dblIn : dblIn;
+  if (d > R4_MAX) return DISP_E_OVERFLOW;
+  *pFltOut = dblIn;
+  return S_OK;
 }
 
 /************************************************************************
@@ -2649,7 +2790,8 @@ HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
  */
 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
 {
-  return _VarR4FromCy(cyIn, pFltOut);
+  *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
+  return S_OK;
 }
 
 /************************************************************************
@@ -2667,7 +2809,7 @@ HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
  */
 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
 {
-  return _VarR4FromDate(dateIn, pFltOut);
+  return VarR4FromR8(dateIn, pFltOut);
 }
 
 /************************************************************************
@@ -2688,7 +2830,7 @@ HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
  */
 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
 {
-  return _VarR4FromStr(strIn, lcid, dwFlags, pFltOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
 }
 
 /************************************************************************
@@ -2709,7 +2851,7 @@ HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFl
  */
 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
 {
-  return _VarR4FromDisp(pdispIn, lcid, pFltOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4);
 }
 
 /************************************************************************
@@ -2726,7 +2868,7 @@ HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
  */
 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
 {
-  return _VarR4FromBool(boolIn, pFltOut);
+  return VarR4FromI2(boolIn, pFltOut);
 }
 
 /************************************************************************
@@ -2820,7 +2962,8 @@ HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
   if (DEC_HI32(pDecIn))
   {
     highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
-    highPart *= 1.0e64;
+    highPart *= 4294967296.0F;
+    highPart *= 4294967296.0F;
   }
   else
     highPart = 0.0;
@@ -2829,7 +2972,6 @@ HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
   return S_OK;
 }
 
-
 /************************************************************************
  * VarR4FromI8 (OLEAUT32.360)
  *
@@ -3009,7 +3151,7 @@ HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
  */
 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
 {
-  return _VarR8FromStr(strIn, lcid, dwFlags, pDblOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
 }
 
 /************************************************************************
@@ -3030,7 +3172,7 @@ HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pD
  */
 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
 {
-  return _VarR8FromDisp(pdispIn, lcid, pDblOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8);
 }
 
 /************************************************************************
@@ -3047,7 +3189,7 @@ HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
  */
 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
 {
-  return _VarR8FromBool(boolIn, pDblOut);
+  return VarR8FromI2(boolIn, pDblOut);
 }
 
 /************************************************************************
@@ -3140,7 +3282,8 @@ HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
   if (DEC_HI32(pDecIn))
   {
     highPart = (double)DEC_HI32(pDecIn) / divisor;
-    highPart *= 1.0e64;
+    highPart *= 4294967296.0F;
+    highPart *= 4294967296.0F;
   }
   else
     highPart = 0.0;
@@ -3277,7 +3420,7 @@ static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
  */
 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
 {
-  return _VarCyFromUI1(bIn, pCyOut);
+  return VarCyFromR8(bIn, pCyOut);
 }
 
 /************************************************************************
@@ -3297,7 +3440,7 @@ HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
 {
-  return _VarCyFromI2(sIn, pCyOut);
+  return VarCyFromR8(sIn, pCyOut);
 }
 
 /************************************************************************
@@ -3317,7 +3460,7 @@ HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
 {
-  return _VarCyFromI4(lIn, pCyOut);
+  return VarCyFromR8(lIn, pCyOut);
 }
 
 /************************************************************************
@@ -3337,7 +3480,7 @@ HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
 {
-  return _VarCyFromR4(fltIn, pCyOut);
+  return VarCyFromR8(fltIn, pCyOut);
 }
 
 /************************************************************************
@@ -3386,7 +3529,7 @@ HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
   if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
     return DISP_E_OVERFLOW;
   dblIn *= CY_MULTIPLIER_F;
-  OLEAUT32_DutchRound(LONG64, dblIn, pCyOut->int64);
+  VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
 #endif
   return S_OK;
 }
@@ -3408,7 +3551,7 @@ HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
 {
-  return _VarCyFromDate(dateIn, pCyOut);
+  return VarCyFromR8(dateIn, pCyOut);
 }
 
 /************************************************************************
@@ -3430,7 +3573,7 @@ HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
 {
-  return _VarCyFromStr(strIn, lcid, dwFlags, pCyOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
 }
 
 /************************************************************************
@@ -3451,10 +3594,9 @@ HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut
  */
 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
 {
-  return _VarCyFromDisp(pdispIn, lcid, pCyOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY);
 }
 
-
 /************************************************************************
  * VarCyFromBool (OLEAUT32.106)
  *
@@ -3476,7 +3618,7 @@ HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
 {
-  return _VarCyFromBool(boolIn, pCyOut);
+  return VarCyFromR8(boolIn, pCyOut);
 }
 
 /************************************************************************
@@ -3496,7 +3638,7 @@ HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
 {
-  return _VarCyFromI1(cIn, pCyOut);
+  return VarCyFromR8(cIn, pCyOut);
 }
 
 /************************************************************************
@@ -3516,7 +3658,7 @@ HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
 {
-  return _VarCyFromUI2(usIn, pCyOut);
+  return VarCyFromR8(usIn, pCyOut);
 }
 
 /************************************************************************
@@ -3536,7 +3678,7 @@ HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
 {
-  return _VarCyFromUI4(ulIn, pCyOut);
+  return VarCyFromR8(ulIn, pCyOut);
 }
 
 /************************************************************************
@@ -3572,7 +3714,7 @@ HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
     d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
     if (DEC_SIGN(&rounded))
       d = -d;
-    return _VarCyFromR8(d, pCyOut);
+    return VarCyFromR8(d, pCyOut);
   }
   return hRet;
 }
@@ -3594,7 +3736,9 @@ HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
 {
-  return _VarCyFromI8(llIn, pCyOut);
+  if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
+  pCyOut->int64 = llIn * CY_MULTIPLIER;
+  return S_OK;
 }
 
 /************************************************************************
@@ -3614,7 +3758,7 @@ HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
  */
 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
 {
-  return _VarCyFromUI8(ullIn, pCyOut);
+  return VarCyFromR8(ullIn, pCyOut);
 }
 
 /************************************************************************
@@ -3637,7 +3781,7 @@ HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
   _VarR8FromCy(cyLeft, &l);
   _VarR8FromCy(cyRight, &r);
   l = l + r;
-  return _VarCyFromR8(l, pCyOut);
+  return VarCyFromR8(l, pCyOut);
 }
 
 /************************************************************************
@@ -3660,7 +3804,7 @@ HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
   _VarR8FromCy(cyLeft, &l);
   _VarR8FromCy(cyRight, &r);
   l = l * r;
-  return _VarCyFromR8(l, pCyOut);
+  return VarCyFromR8(l, pCyOut);
 }
 
 /************************************************************************
@@ -3683,7 +3827,7 @@ HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
 
   _VarR8FromCy(cyLeft, &d);
   d = d * lRight;
-  return _VarCyFromR8(d, pCyOut);
+  return VarCyFromR8(d, pCyOut);
 }
 
 /************************************************************************
@@ -3706,7 +3850,7 @@ HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
   _VarR8FromCy(cyLeft, &l);
   _VarR8FromCy(cyRight, &r);
   l = l - r;
-  return _VarCyFromR8(l, pCyOut);
+  return VarCyFromR8(l, pCyOut);
 }
 
 /************************************************************************
@@ -3837,9 +3981,9 @@ HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
 
     _VarR8FromCy(cyIn, &d);
     d = d * div;
-    OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64)
+    VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
     d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
-    OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64)
+    VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
     return S_OK;
   }
 }
@@ -3856,7 +4000,7 @@ HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
  * RETURNS
  *  Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
  *           compare is less, equal or greater than source respectively.
- *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparason
+ *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
  */
 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
 {
@@ -3890,14 +4034,14 @@ HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
  * RETURNS
  *  Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
  *           less than, equal to or greater than cyLeft respectively.
- *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparason
+ *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
  */
 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
 {
   HRESULT hRet;
   CY cyRight;
 
-  hRet = _VarCyFromR8(dblRight, &cyRight);
+  hRet = VarCyFromR8(dblRight, &cyRight);
 
   if (SUCCEEDED(hRet))
     hRet = VarCyCmp(cyLeft, cyRight);
@@ -3925,7 +4069,7 @@ HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
 
   _VarR8FromCy(cyLeft, &d);
   d = d  * (double)llRight;
-  return _VarCyFromR8(d, pCyOut);
+  return VarCyFromR8(d, pCyOut);
 }
 
 /* DECIMAL
@@ -3945,7 +4089,7 @@ HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
  */
 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
 {
-  return _VarDecFromUI1(bIn, pDecOut);
+  return VarDecFromUI4(bIn, pDecOut);
 }
 
 /************************************************************************
@@ -3962,7 +4106,7 @@ HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
  */
 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
 {
-  return _VarDecFromI2(sIn, pDecOut);
+  return VarDecFromI4(sIn, pDecOut);
 }
 
 /************************************************************************
@@ -3995,6 +4139,8 @@ HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
   return S_OK;
 }
 
+#define LOCALE_EN_US           (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
+
 /************************************************************************
  * VarDecFromR4 (OLEAUT32.193)
  *
@@ -4012,7 +4158,7 @@ HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
   WCHAR buff[256];
 
   sprintfW( buff, szFloatFormatW, fltIn );
-  return _VarDecFromStr(buff, LOCALE_SYSTEM_DEFAULT, 0, pDecOut);
+  return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
 }
 
 /************************************************************************
@@ -4032,7 +4178,7 @@ HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
   WCHAR buff[256];
 
   sprintfW( buff, szDoubleFormatW, dblIn );
-  return _VarDecFromStr(buff, LOCALE_USER_DEFAULT, 0, pDecOut);
+  return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
 }
 
 /************************************************************************
@@ -4049,7 +4195,7 @@ HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
  */
 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
 {
-  return _VarDecFromDate(dateIn, pDecOut);
+  return VarDecFromR8(dateIn, pDecOut);
 }
 
 /************************************************************************
@@ -4083,7 +4229,6 @@ HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
   return S_OK;
 }
 
-
 /************************************************************************
  * VarDecFromStr (OLEAUT32.197)
  *
@@ -4101,7 +4246,7 @@ HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
  */
 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
 {
-  return _VarDecFromStr(strIn, lcid, dwFlags, pDecOut);
+  return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
 }
 
 /************************************************************************
@@ -4120,7 +4265,7 @@ HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL*
  */
 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
 {
-  return _VarDecFromDisp(pdispIn, lcid, pDecOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL);
 }
 
 /************************************************************************
@@ -4169,7 +4314,7 @@ HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
  */
 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
 {
-  return _VarDecFromI1(cIn, pDecOut);
+  return VarDecFromI4(cIn, pDecOut);
 }
 
 /************************************************************************
@@ -4186,7 +4331,7 @@ HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
  */
 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
 {
-  return _VarDecFromUI2(usIn, pDecOut);
+  return VarDecFromUI4(usIn, pDecOut);
 }
 
 /************************************************************************
@@ -4449,6 +4594,600 @@ VarDecAdd_AsPositive:
   return hRet;
 }
 
+/* internal representation of the value stored in a DECIMAL. The bytes are
+   stored from LSB at index 0 to MSB at index 11
+ */
+typedef struct DECIMAL_internal
+{
+    DWORD bitsnum[3];  /* 96 significant bits, unsigned */
+    unsigned char scale;      /* number scaled * 10 ^ -(scale) */
+    unsigned int  sign : 1;   /* 0 - positive, 1 - negative */
+} VARIANT_DI;
+
+/* translate from external DECIMAL format into an internal representation */
+static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
+{
+    to->scale = DEC_SCALE(from);
+    to->sign = DEC_SIGN(from) ? 1 : 0;
+
+    to->bitsnum[0] = DEC_LO32(from);
+    to->bitsnum[1] = DEC_MID32(from);
+    to->bitsnum[2] = DEC_HI32(from);
+}
+
+static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
+{
+    if (from->sign) {
+        DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
+    } else {
+        DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
+    }
+
+    DEC_LO32(to) = from->bitsnum[0];
+    DEC_MID32(to) = from->bitsnum[1];
+    DEC_HI32(to) = from->bitsnum[2];
+}
+
+/* clear an internal representation of a DECIMAL */
+static void VARIANT_DI_clear(VARIANT_DI * i)
+{
+    memset(i, 0, sizeof(VARIANT_DI));
+}
+
+/* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
+   size is supported. The value in p is replaced by the quotient of the division, and
+   the remainder is returned as a result. This routine is most often used with a divisor
+   of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
+ */
+static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
+{
+    if (divisor == 0) {
+        /* division by 0 */
+        return 0xFF;
+    } else if (divisor == 1) {
+        /* dividend remains unchanged */
+        return 0;
+    } else {
+        unsigned char remainder = 0;
+        ULONGLONG iTempDividend;
+        signed int i;
+        
+        for (i = n - 1; i >= 0 && !p[i]; i--);  /* skip leading zeros */
+        for (; i >= 0; i--) {
+            iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
+            remainder = iTempDividend % divisor;
+            p[i] = iTempDividend / divisor;
+        }
+        
+        return remainder;
+    }
+}
+
+/* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
+static int VARIANT_int_iszero(DWORD * p, unsigned int n)
+{
+    for (; n > 0; n--) if (*p++ != 0) return 0;
+    return 1;
+}
+
+/* multiply two DECIMALS, without changing either one, and place result in third
+   parameter. Result is normalized when scale is > 0. Attempts to remove significant
+   digits when scale > 0 in order to fit an overflowing result. Final overflow
+   flag is returned.
+ */
+static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
+{
+    int r_overflow = 0;
+    DWORD running[6];
+    signed int mulstart;
+
+    VARIANT_DI_clear(result);
+    result->sign = (a->sign ^ b->sign) ? 1 : 0;
+
+    /* Multiply 128-bit operands into a (max) 256-bit result. The scale
+       of the result is formed by adding the scales of the operands.
+     */
+    result->scale = a->scale + b->scale;
+    memset(running, 0, sizeof(running));
+
+    /* count number of leading zero-bytes in operand A */
+    for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
+    if (mulstart < 0) {
+        /* result is 0, because operand A is 0 */
+        result->scale = 0;
+        result->sign = 0;
+    } else {
+        unsigned char remainder = 0;
+        int iA;        
+
+        /* perform actual multiplication */
+        for (iA = 0; iA <= mulstart; iA++) {
+            ULONG iOverflowMul;
+            int iB;
+            
+            for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
+                ULONG iRV;
+                int iR;
+                
+                iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
+                iR = iA + iB;
+                do {
+                    running[iR] = VARIANT_Add(running[iR], 0, &iRV);
+                    iR++;
+                } while (iRV);
+            }
+        }
+
+/* Too bad - native oleaut does not do this, so we should not either */
+#if 0
+        /* While the result is divisible by 10, and the scale > 0, divide by 10.
+           This operation should not lose significant digits, and gives an
+           opportunity to reduce the possibility of overflows in future
+           operations issued by the application.
+         */
+        while (result->scale > 0) {
+            memcpy(quotient, running, sizeof(quotient));
+            remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
+            if (remainder > 0) break;
+            memcpy(running, quotient, sizeof(quotient));
+            result->scale--;
+        }
+#endif
+        /* While the 256-bit result overflows, and the scale > 0, divide by 10.
+           This operation *will* lose significant digits of the result because
+           all the factors of 10 were consumed by the previous operation.
+        */
+        while (result->scale > 0 && !VARIANT_int_iszero(
+            running + sizeof(result->bitsnum) / sizeof(DWORD),
+            (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
+            
+            remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
+            if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
+            result->scale--;
+        }
+        
+        /* round up the result - native oleaut32 does this */
+        if (remainder >= 5) {
+            unsigned int i;
+            for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
+                ULONGLONG digit = running[i] + 1;
+                remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
+                running[i] = digit & 0xFFFFFFFF;
+            }
+        }
+
+        /* Signal overflow if scale == 0 and 256-bit result still overflows,
+           and copy result bits into result structure
+        */
+        r_overflow = !VARIANT_int_iszero(
+            running + sizeof(result->bitsnum)/sizeof(DWORD), 
+            (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
+        memcpy(result->bitsnum, running, sizeof(result->bitsnum));
+    }
+    return r_overflow;
+}
+
+/* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
+   hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
+   success, nonzero if insufficient space in output buffer.
+ */
+static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
+{
+    int overflow = 0;
+    DWORD quotient[3];
+    unsigned char remainder;
+    unsigned int i;
+
+    /* place negative sign */
+    if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
+        if (n > 0) {
+            *s++ = '-';
+            n--;
+        }
+        else overflow = 1;
+    }
+
+    /* prepare initial 0 */
+    if (!overflow) {
+        if (n >= 2) {
+            s[0] = '0';
+            s[1] = '\0';
+        } else overflow = 1;
+    }
+
+    i = 0;
+    memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
+    while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
+        remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
+        if (i + 2 > n) {
+            overflow = 1;
+        } else {
+            s[i++] = '0' + remainder;
+            s[i] = '\0';
+        }
+    }
+
+    if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
+
+        /* reverse order of digits */
+        WCHAR * x = s; WCHAR * y = s + i - 1;
+        while (x < y) {
+            *x ^= *y;
+            *y ^= *x;
+            *x++ ^= *y--;
+        }
+
+        /* check for decimal point. "i" now has string length */
+        if (i <= a->scale) {
+            unsigned int numzeroes = a->scale + 1 - i;
+            if (i + 1 + numzeroes >= n) {
+                overflow = 1;
+            } else {
+                memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
+                i += numzeroes;
+                while (numzeroes > 0) {
+                    s[--numzeroes] = '0';
+                }
+            }
+        }
+
+        /* place decimal point */
+        if (a->scale > 0) {
+            unsigned int periodpos = i - a->scale;
+            if (i + 2 >= n) {
+                overflow = 1;
+            } else {
+                memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
+                s[periodpos] = '.'; i++;
+                
+                /* remove extra zeros at the end, if any */
+                while (s[i - 1] == '0') s[--i] = '\0';
+                if (s[i - 1] == '.') s[--i] = '\0';
+            }
+        }
+    }
+
+    return overflow;
+}
+
+/* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
+static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
+{
+    DWORD shifted;
+    unsigned int i;
+    
+    /* shift whole DWORDs to the left */
+    while (shift >= 32)
+    {
+        memmove(p + 1, p, (n - 1) * sizeof(DWORD));
+        *p = 0; shift -= 32;
+    }
+    
+    /* shift remainder (1..31 bits) */
+    shifted = 0;
+    if (shift > 0) for (i = 0; i < n; i++)
+    {
+        DWORD b;
+        b = p[i] >> (32 - shift);
+        p[i] = (p[i] << shift) | shifted;
+        shifted = b;
+    }
+}
+
+/* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
+   Value at v is incremented by the value at p. Any size is supported, provided
+   that v is not shorter than p. Any unapplied carry is returned as a result.
+ */
+static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p, 
+    unsigned int np)
+{
+    unsigned char carry = 0;
+
+    if (nv >= np) {
+        ULONGLONG sum;
+        unsigned int i;
+
+        for (i = 0; i < np; i++) {
+            sum = (ULONGLONG)v[i]
+                + (ULONGLONG)p[i]
+                + (ULONGLONG)carry;
+            v[i] = sum & 0xffffffff;
+            carry = sum >> 32;
+        }
+        for (; i < nv && carry; i++) {
+            sum = (ULONGLONG)v[i]
+                + (ULONGLONG)carry;
+            v[i] = sum & 0xffffffff;
+            carry = sum >> 32;
+        }
+    }
+    return carry;
+}
+
+/* perform integral division with operand p as dividend. Parameter n indicates 
+   number of available DWORDs in divisor p, but available space in p must be 
+   actually at least 2 * n DWORDs, because the remainder of the integral 
+   division is built in the next n DWORDs past the start of the quotient. This 
+   routine replaces the dividend in p with the quotient, and appends n 
+   additional DWORDs for the remainder.
+
+   Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
+   C/C++ :-) where the "longhand binary division" algorithm was exposed for the
+   source code to the VLI (Very Large Integer) division operator. This algorithm
+   was then heavily modified by me (Alex Villacis Lasso) in order to handle
+   variably-scaled integers such as the MS DECIMAL representation.
+ */
+static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
+    unsigned int dn)
+{
+    unsigned int i;
+    DWORD tempsub[8];
+    DWORD * negdivisor = tempsub + n;
+
+    /* build 2s-complement of divisor */
+    for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
+    p[n] = 1;
+    VARIANT_int_add(negdivisor, n, p + n, 1);
+    memset(p + n, 0, n * sizeof(DWORD));
+
+    /* skip all leading zero DWORDs in quotient */
+    for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
+    /* i is now number of DWORDs left to process */
+    for (i <<= 5; i < (n << 5); i++) {
+        VARIANT_int_shiftleft(p, n << 1, 1);    /* shl quotient+remainder */
+
+        /* trial subtraction */
+        memcpy(tempsub, p + n, n * sizeof(DWORD));
+        VARIANT_int_add(tempsub, n, negdivisor, n);
+
+        /* check whether result of subtraction was negative */
+        if ((tempsub[n - 1] & 0x80000000) == 0) {
+            memcpy(p + n, tempsub, n * sizeof(DWORD));
+            p[0] |= 1;
+        }
+    }
+}
+
+/* perform integral multiplication by a byte operand. Used for scaling by 10 */
+static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
+{
+    unsigned int i;
+    ULONG iOverflowMul;
+    
+    for (iOverflowMul = 0, i = 0; i < n; i++)
+        p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
+    return (unsigned char)iOverflowMul;
+}
+
+/* increment value in A by the value indicated in B, with scale adjusting. 
+   Modifies parameters by adjusting scales. Returns 0 if addition was 
+   successful, nonzero if a parameter underflowed before it could be 
+   successfully used in the addition.
+ */
+static int VARIANT_int_addlossy(
+    DWORD * a, int * ascale, unsigned int an,
+    DWORD * b, int * bscale, unsigned int bn)
+{
+    int underflow = 0;
+
+    if (VARIANT_int_iszero(a, an)) {
+        /* if A is zero, copy B into A, after removing digits */
+        while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
+            VARIANT_int_divbychar(b, bn, 10);
+            (*bscale)--;
+        }
+        memcpy(a, b, an * sizeof(DWORD));
+        *ascale = *bscale;
+    } else if (!VARIANT_int_iszero(b, bn)) {
+        unsigned int tn = an + 1;
+        DWORD t[5];
+
+        if (bn + 1 > tn) tn = bn + 1;
+        if (*ascale != *bscale) {
+            /* first (optimistic) try - try to scale down the one with the bigger
+               scale, while this number is divisible by 10 */
+            DWORD * digitchosen;
+            unsigned int nchosen;
+            int * scalechosen;
+            int targetscale;
+
+            if (*ascale < *bscale) {
+                targetscale = *ascale;
+                scalechosen = bscale;
+                digitchosen = b;
+                nchosen = bn;
+            } else {
+                targetscale = *bscale;
+                scalechosen = ascale;
+                digitchosen = a;
+                nchosen = an;
+            }
+            memset(t, 0, tn * sizeof(DWORD));
+            memcpy(t, digitchosen, nchosen * sizeof(DWORD));
+
+            /* divide by 10 until target scale is reached */
+            while (*scalechosen > targetscale) {
+                unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
+                if (!remainder) {
+                    (*scalechosen)--;
+                    memcpy(digitchosen, t, nchosen * sizeof(DWORD));
+                } else break;
+            }
+        }
+
+        if (*ascale != *bscale) {
+            DWORD * digitchosen;
+            unsigned int nchosen;
+            int * scalechosen;
+            int targetscale;
+
+            /* try to scale up the one with the smaller scale */
+            if (*ascale > *bscale) {
+                targetscale = *ascale;
+                scalechosen = bscale;
+                digitchosen = b;
+                nchosen = bn;
+            } else {
+                targetscale = *bscale;
+                scalechosen = ascale;
+                digitchosen = a;
+                nchosen = an;
+            }
+            memset(t, 0, tn * sizeof(DWORD));
+            memcpy(t, digitchosen, nchosen * sizeof(DWORD));
+
+            /* multiply by 10 until target scale is reached, or
+               significant bytes overflow the number
+             */
+            while (*scalechosen < targetscale && t[nchosen] == 0) {
+                VARIANT_int_mulbychar(t, tn, 10);
+                if (t[nchosen] == 0) {
+                    /* still does not overflow */
+                    (*scalechosen)++;
+                    memcpy(digitchosen, t, nchosen * sizeof(DWORD));
+                }
+            }
+        }
+
+        if (*ascale != *bscale) {
+            /* still different? try to scale down the one with the bigger scale
+               (this *will* lose significant digits) */
+            DWORD * digitchosen;
+            unsigned int nchosen;
+            int * scalechosen;
+            int targetscale;
+
+            if (*ascale < *bscale) {
+                targetscale = *ascale;
+                scalechosen = bscale;
+                digitchosen = b;
+                nchosen = bn;
+            } else {
+                targetscale = *bscale;
+                scalechosen = ascale;
+                digitchosen = a;
+                nchosen = an;
+            }
+            memset(t, 0, tn * sizeof(DWORD));
+            memcpy(t, digitchosen, nchosen * sizeof(DWORD));
+
+            /* divide by 10 until target scale is reached */
+            while (*scalechosen > targetscale) {
+                VARIANT_int_divbychar(t, tn, 10);
+                (*scalechosen)--;
+                memcpy(digitchosen, t, nchosen * sizeof(DWORD));
+            }
+        }
+
+        /* check whether any of the operands still has significant digits
+           (underflow case 1)
+         */
+        if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
+            underflow = 1;
+        } else {
+            /* at this step, both numbers have the same scale and can be added
+               as integers. However, the result might not fit in A, so further
+               scaling down might be necessary.
+             */
+            while (!underflow) {
+                memset(t, 0, tn * sizeof(DWORD));
+                memcpy(t, a, an * sizeof(DWORD));
+
+                VARIANT_int_add(t, tn, b, bn);
+                if (VARIANT_int_iszero(t + an, tn - an)) {
+                    /* addition was successful */
+                    memcpy(a, t, an * sizeof(DWORD));
+                    break;
+                } else {
+                    /* addition overflowed - remove significant digits
+                       from both operands and try again */
+                    VARIANT_int_divbychar(a, an, 10); (*ascale)--;
+                    VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
+                    /* check whether any operand keeps significant digits after
+                       scaledown (underflow case 2)
+                     */
+                    underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
+                }
+            }
+        }
+    }
+    return underflow;
+}
+
+/* perform complete DECIMAL division in the internal representation. Returns
+   0 if the division was completed (even if quotient is set to 0), or nonzero
+   in case of quotient overflow.
+ */
+static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
+{
+    HRESULT r_overflow = S_OK;
+
+    if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
+        /* division by 0 */
+        r_overflow = DISP_E_DIVBYZERO;
+    } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
+        VARIANT_DI_clear(quotient);
+    } else {
+        int quotientscale, remainderscale, tempquotientscale;
+        DWORD remainderplusquotient[8];
+        int underflow;
+
+        quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
+        tempquotientscale = quotientscale;
+        VARIANT_DI_clear(quotient);
+        quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
+
+        /*  The following strategy is used for division
+            1) if there was a nonzero remainder from previous iteration, use it as
+               dividend for this iteration, else (for first iteration) use intended
+               dividend
+            2) perform integer division in temporary buffer, develop quotient in
+               low-order part, remainder in high-order part
+            3) add quotient from step 2 to final result, with possible loss of
+               significant digits
+            4) multiply integer part of remainder by 10, while incrementing the
+               scale of the remainder. This operation preserves the intended value
+               of the remainder.
+            5) loop to step 1 until one of the following is true:
+                a) remainder is zero (exact division achieved)
+                b) addition in step 3 fails to modify bits in quotient (remainder underflow)
+         */
+        memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
+        memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
+        do {
+            VARIANT_int_div(
+                remainderplusquotient, 4,
+                divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
+            underflow = VARIANT_int_addlossy(
+                quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
+                remainderplusquotient, &tempquotientscale, 4);
+            VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
+            memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
+            tempquotientscale = ++remainderscale;
+        } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
+
+        /* quotient scale might now be negative (extremely big number). If, so, try
+           to multiply quotient by 10 (without overflowing), while adjusting the scale,
+           until scale is 0. If this cannot be done, it is a real overflow.
+         */
+        while (!r_overflow && quotientscale < 0) {
+            memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
+            memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
+            VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
+            if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
+                (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
+                quotientscale++;
+                memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
+            } else r_overflow = DISP_E_OVERFLOW;
+        }
+        if (!r_overflow) {
+            if (quotientscale <= 255) quotient->scale = quotientscale;
+            else VARIANT_DI_clear(quotient);
+        }
+    }
+    return r_overflow;
+}
+
 /************************************************************************
  * VarDecDiv (OLEAUT32.178)
  *
@@ -4465,8 +5204,59 @@ VarDecAdd_AsPositive:
  */
 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
 {
-  FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut);
-  return DISP_E_OVERFLOW;
+  HRESULT hRet = S_OK;
+  VARIANT_DI di_left, di_right, di_result;
+  HRESULT divresult;
+
+  if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
+
+  VARIANT_DIFromDec(pDecLeft, &di_left);
+  VARIANT_DIFromDec(pDecRight, &di_right);
+  divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
+  if (divresult)
+  {
+      /* division actually overflowed */
+      hRet = divresult;
+  }
+  else
+  {
+      hRet = S_OK;
+
+      if (di_result.scale > DEC_MAX_SCALE)
+      {
+        unsigned char remainder = 0;
+      
+        /* division underflowed. In order to comply with the MSDN
+           specifications for DECIMAL ranges, some significant digits
+           must be removed
+         */
+        WARN("result scale is %u, scaling (with loss of significant digits)...\n",
+            di_result.scale);
+        while (di_result.scale > DEC_MAX_SCALE && 
+               !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
+        {
+            remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
+            di_result.scale--;
+        }
+        if (di_result.scale > DEC_MAX_SCALE)
+        {
+            WARN("result underflowed, setting to 0\n");
+            di_result.scale = 0;
+            di_result.sign = 0;
+        }
+        else if (remainder >= 5)    /* round up result - native oleaut32 does this */
+        {
+            unsigned int i;
+            for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
+                ULONGLONG digit = di_result.bitsnum[i] + 1;
+                remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
+                di_result.bitsnum[i] = digit & 0xFFFFFFFF;
+            }
+        }
+      }
+      VARIANT_DecFromDI(&di_result, pDecOut);
+  }
+  return hRet;
 }
 
 /************************************************************************
@@ -4485,42 +5275,44 @@ HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECI
  */
 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
 {
-  /* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */
+  HRESULT hRet = S_OK;
+  VARIANT_DI di_left, di_right, di_result;
+  int mulresult;
 
-  if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight))
+  VARIANT_DIFromDec(pDecLeft, &di_left);
+  VARIANT_DIFromDec(pDecRight, &di_right);
+  mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
+  if (mulresult)
   {
-    /* At least one term is an integer */
-    const DECIMAL* pDecInteger = DEC_SCALE(pDecLeft) ? pDecRight : pDecLeft;
-    const DECIMAL* pDecOperand = DEC_SCALE(pDecLeft) ? pDecLeft  : pDecRight;
-    HRESULT hRet = S_OK;
-    unsigned int multiplier = DEC_LO32(pDecInteger);
-    ULONG overflow = 0;
-
-    if (DEC_HI32(pDecInteger) || DEC_MID32(pDecInteger))
-    {
-      FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
-      return DISP_E_OVERFLOW;
-    }
-
-    DEC_LO32(pDecOut)  = VARIANT_Mul(DEC_LO32(pDecOperand),  multiplier, &overflow);
-    DEC_MID32(pDecOut) = VARIANT_Mul(DEC_MID32(pDecOperand), multiplier, &overflow);
-    DEC_HI32(pDecOut)  = VARIANT_Mul(DEC_HI32(pDecOperand),  multiplier, &overflow);
-
-    if (overflow)
-       hRet = DISP_E_OVERFLOW;
-    else
+    /* multiplication actually overflowed */
+    hRet = DISP_E_OVERFLOW;
+  }
+  else
+  {
+    if (di_result.scale > DEC_MAX_SCALE)
     {
-      BYTE sign = DECIMAL_POS;
-
-      if (DEC_SIGN(pDecLeft) != DEC_SIGN(pDecRight))
-        sign = DECIMAL_NEG; /* pos * neg => negative */
-      DEC_SIGN(pDecOut) = sign;
-      DEC_SCALE(pDecOut) = DEC_SCALE(pDecOperand);
+      /* multiplication underflowed. In order to comply with the MSDN
+         specifications for DECIMAL ranges, some significant digits
+         must be removed
+       */
+      WARN("result scale is %u, scaling (with loss of significant digits)...\n",
+          di_result.scale);
+      while (di_result.scale > DEC_MAX_SCALE && 
+            !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
+      {
+        VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
+        di_result.scale--;
+      }
+      if (di_result.scale > DEC_MAX_SCALE)
+      {
+        WARN("result underflowed, setting to 0\n");
+        di_result.scale = 0;
+        di_result.sign = 0;
+      }
     }
-    return hRet;
+    VARIANT_DecFromDI(&di_result, pDecOut);
   }
-  FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
-  return DISP_E_OVERFLOW;
+  return hRet;
 }
 
 /************************************************************************
@@ -4583,7 +5375,7 @@ HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
  */
 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
 {
-  if (DEC_SIGN(pDecOut) & ~DECIMAL_NEG)
+  if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
     return E_INVALIDARG;
 
   if (!DEC_SCALE(pDecIn))
@@ -4615,10 +5407,10 @@ HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
  */
 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
 {
-  if (DEC_SIGN(pDecOut) & ~DECIMAL_NEG)
+  if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
     return E_INVALIDARG;
 
-  if (!(DEC_SIGN(pDecOut) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
+  if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
     return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
 
   FIXME("semi-stub!\n");
@@ -4686,7 +5478,7 @@ HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOu
  * RETURNS
  *  Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
  *           is less than, equal to or greater than pDecRight respectively.
- *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparason
+ *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
  */
 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
 {
@@ -4710,7 +5502,6 @@ HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
   return hRet;
 }
 
-
 /************************************************************************
  * VarDecCmpR8 (OLEAUT32.298)
  *
@@ -4723,7 +5514,7 @@ HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
  * RETURNS
  *  Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
  *           is less than, equal to or greater than pDecLeft respectively.
- *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparason
+ *  Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
  */
 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
 {
@@ -4755,7 +5546,8 @@ HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
  */
 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromUI1(bIn, pBoolOut);
+  *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -4772,7 +5564,8 @@ HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromI2(sIn, pBoolOut);
+  *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -4789,7 +5582,8 @@ HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromI4(lIn, pBoolOut);
+  *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -4806,7 +5600,8 @@ HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromR4(fltIn, pBoolOut);
+  *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -4823,7 +5618,8 @@ HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromR8(dblIn, pBoolOut);
+  *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -4840,7 +5636,8 @@ HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromDate(dateIn, pBoolOut);
+  *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -4857,7 +5654,8 @@ HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromCy(cyIn, pBoolOut);
+  *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
@@ -4865,7 +5663,7 @@ static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
   HRSRC hrsrc;
 
   hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
-                           (LPCWSTR)((dwId >> 4) + 1), langId );
+                           MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
   if (hrsrc)
   {
     HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
@@ -4984,9 +5782,8 @@ VarBoolFromStr_CheckLocalised:
     double d;
 
     /* If this string is a number, convert it as one */
-    hRes = _VarR8FromStr(strIn, lcid, dwFlags, &d);
-    if (SUCCEEDED(hRes))
-      hRes = _VarBoolFromR8(d, pBoolOut);
+    hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
+    if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
   }
   return hRes;
 }
@@ -5009,7 +5806,7 @@ VarBoolFromStr_CheckLocalised:
  */
 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromDisp(pdispIn, lcid, pBoolOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL);
 }
 
 /************************************************************************
@@ -5026,7 +5823,8 @@ HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoo
  */
 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromI1(cIn, pBoolOut);
+  *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -5043,7 +5841,8 @@ HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromUI2(usIn, pBoolOut);
+  *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -5060,7 +5859,8 @@ HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromUI4(ulIn, pBoolOut);
+  *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -5102,7 +5902,8 @@ HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromI8(llIn, pBoolOut);
+  *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /************************************************************************
@@ -5119,7 +5920,8 @@ HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
  */
 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
 {
-  return _VarBoolFromUI8(ullIn, pBoolOut);
+  *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
+  return S_OK;
 }
 
 /* BSTR
@@ -5248,12 +6050,64 @@ HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
 
   if (lIn < 0)
   {
-    ul64 = -lIn;
+    ul64 = (ULONG)-lIn;
     dwFlags |= VAR_NEGATIVE;
   }
   return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
 }
 
+static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
+{
+  BSTR bstrOut;
+  WCHAR lpDecimalSep[16];
+
+  /* Native oleaut32 uses the locale-specific decimal separator even in the
+     absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin 
+     American locales will see "one thousand and one tenth" as "1000,1" 
+     instead of "1000.1" (notice the comma). The following code checks for
+     the need to replace the decimal separator, and if so, will prepare an
+     appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
+   */
+  GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
+  if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
+  {
+    /* locale is compatible with English - return original string */
+    bstrOut = SysAllocString(buff);
+  }
+  else
+  {
+    WCHAR *p;
+    WCHAR numbuff[256];
+    WCHAR empty[1] = {'\0'};
+    NUMBERFMTW minFormat;
+
+    minFormat.NumDigits = 0;
+    minFormat.LeadingZero = 0;
+    minFormat.Grouping = 0;
+    minFormat.lpDecimalSep = lpDecimalSep;
+    minFormat.lpThousandSep = empty;
+    minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
+
+    /* count number of decimal digits in string */
+    p = strchrW( buff, '.' );
+    if (p) minFormat.NumDigits = strlenW(p + 1);
+
+    numbuff[0] = '\0';
+    if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
+                   buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
+    {
+      WARN("GetNumberFormatW() failed, returning raw number string instead\n");
+      bstrOut = SysAllocString(buff);
+    }
+    else
+    {
+      TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
+      bstrOut = SysAllocString(numbuff);
+    }
+  }
+  return bstrOut;
+}
+
 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
                                     BSTR* pbstrOut, LPCWSTR lpszFormat)
 {
@@ -5263,6 +6117,19 @@ static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
     return E_INVALIDARG;
 
   sprintfW( buff, lpszFormat, dblIn );
+
+  /* Negative zeroes are disallowed (some applications depend on this).
+     If buff starts with a minus, and then nothing follows but zeroes
+     and/or a period, it is a negative zero and is replaced with a
+     canonical zero. This duplicates native oleaut32 behavior.
+   */
+  if (buff[0] == '-')
+  {
+    const WCHAR szAccept[] = {'0', '.', '\0'};
+    if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
+    { buff[0] = '0'; buff[1] = '\0'; }
+  }
+
   TRACE("created string %s\n", debugstr_w(buff));
   if (dwFlags & LOCALE_USE_NLS)
   {
@@ -5276,7 +6143,9 @@ static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
     *pbstrOut = SysAllocString(numbuff);
   }
   else
-    *pbstrOut = SysAllocString(buff);
+  {
+    *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
+  }
   return *pbstrOut ? S_OK : E_OUTOFMEMORY;
 }
 
@@ -5597,25 +6466,33 @@ HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrO
  */
 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
 {
+  WCHAR buff[256];
+  VARIANT_DI temp;
+
   if (!pbstrOut)
     return E_INVALIDARG;
 
-  if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn))
-  {
-    WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
+  VARIANT_DIFromDec(pDecIn, &temp);
+  VARIANT_DI_tostringW(&temp, buff, 256);
 
-    /* Create the basic number string */
-    *szOut-- = '\0';
-    szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
-    if (DEC_SIGN(pDecIn))
-      dwFlags |= VAR_NEGATIVE;
+  if (dwFlags & LOCALE_USE_NLS)
+  {
+    WCHAR numbuff[256];
 
-    *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
-    TRACE("returning %s\n", debugstr_w(*pbstrOut));
-    return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+    /* Format the number for the locale */
+    numbuff[0] = '\0';
+    GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
+                     buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
+    TRACE("created NLS string %s\n", debugstr_w(numbuff));
+    *pbstrOut = SysAllocString(numbuff);
+  }
+  else
+  {
+    *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
   }
-  FIXME("semi-stub\n");
-  return E_INVALIDARG;
+  
+  TRACE("returning %s\n", debugstr_w(*pbstrOut));
+  return *pbstrOut ? S_OK : E_OUTOFMEMORY;
 }
 
 /************************************************************************
@@ -5716,29 +6593,27 @@ HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
  * PARAMS
  *  pbstrLeft  [I] Source
  *  pbstrRight [I] Value to compare
- *  lcid       [I] LCID for the comparason
+ *  lcid       [I] LCID for the comparison
  *  dwFlags    [I] Flags to pass directly to CompareStringW().
  *
  * RETURNS
  *  VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
  *  than, equal to or greater than pbstrRight respectively.
- *  VARCMP_NULL is returned if either string is NULL, unless both are NULL
- *  in which case VARCMP_EQ is returned.
+ *
+ * NOTES
+ *  VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
+ *  states. A NULL BSTR pointer is equivalent to an empty string.
  */
 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
 {
-    if (!pbstrLeft)
+    if (!pbstrLeft || !*pbstrLeft)
     {
       if (!pbstrRight || !*pbstrRight)
         return VARCMP_EQ;
-      return VARCMP_NULL;
-    }
-    else if (!pbstrRight)
-    {
-      if (!*pbstrLeft)
-        return VARCMP_EQ;
-      return VARCMP_NULL;
+      return VARCMP_LT;
     }
+    else if (!pbstrRight || !*pbstrRight)
+        return VARCMP_GT;
 
     return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
 }
@@ -5761,7 +6636,7 @@ HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFl
  */
 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
 {
-  return _VarDateFromUI1(bIn, pdateOut);
+  return VarR8FromUI1(bIn, pdateOut);
 }
 
 /******************************************************************************
@@ -5778,7 +6653,7 @@ HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
 {
-  return _VarDateFromI2(sIn, pdateOut);
+  return VarR8FromI2(sIn, pdateOut);
 }
 
 /******************************************************************************
@@ -5795,7 +6670,7 @@ HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
 {
-  return _VarDateFromI4(lIn, pdateOut);
+  return VarDateFromR8(lIn, pdateOut);
 }
 
 /******************************************************************************
@@ -5812,7 +6687,7 @@ HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
 {
-  return _VarDateFromR4(fltIn, pdateOut);
+  return VarR8FromR4(fltIn, pdateOut);
 }
 
 /******************************************************************************
@@ -5829,7 +6704,9 @@ HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
 {
-  return _VarDateFromR8(dblIn, pdateOut);
+  if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
+  *pdateOut = (DATE)dblIn;
+  return S_OK;
 }
 
 /**********************************************************************
@@ -5850,7 +6727,7 @@ HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
 {
-  return _VarDateFromDisp(pdispIn, lcid, pdateOut);
+  return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE);
 }
 
 /******************************************************************************
@@ -5867,7 +6744,7 @@ HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
 {
-  return _VarDateFromBool(boolIn, pdateOut);
+  return VarR8FromBool(boolIn, pdateOut);
 }
 
 /**********************************************************************
@@ -5884,7 +6761,7 @@ HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
 {
-  return _VarDateFromCy(cyIn, pdateOut);
+  return VarR8FromCy(cyIn, pdateOut);
 }
 
 /* Date string parsing */
@@ -6472,7 +7349,7 @@ HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pd
  */
 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
 {
-  return _VarDateFromI1(cIn, pdateOut);
+  return VarR8FromI1(cIn, pdateOut);
 }
 
 /******************************************************************************
@@ -6489,7 +7366,7 @@ HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
 {
-  return _VarDateFromUI2(uiIn, pdateOut);
+  return VarR8FromUI2(uiIn, pdateOut);
 }
 
 /******************************************************************************
@@ -6506,7 +7383,7 @@ HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
 {
-  return _VarDateFromUI4(ulIn, pdateOut);
+  return VarDateFromR8(ulIn, pdateOut);
 }
 
 /**********************************************************************
@@ -6523,7 +7400,7 @@ HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
 {
-  return _VarDateFromDec(pdecIn, pdateOut);
+  return VarR8FromDec(pdecIn, pdateOut);
 }
 
 /******************************************************************************
@@ -6541,7 +7418,9 @@ HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
 {
-  return _VarDateFromI8(llIn, pdateOut);
+  if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
+  *pdateOut = (DATE)llIn;
+  return S_OK;
 }
 
 /******************************************************************************
@@ -6559,5 +7438,7 @@ HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
  */
 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
 {
-  return _VarDateFromUI8(ullIn, pdateOut);
+  if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
+  *pdateOut = (DATE)ullIn;
+  return S_OK;
 }