oleaut32 low level

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Sorry for the size of the patch. You'll need to run configure
afterwards.

Cheers,
Jon

License: X11

ChangeLog:

  Jon Griffiths <jon_p_griffiths@xxxxxxxxx>

  +dlls/oleaut32/vartype.c dlls/oleaut32/oleaut32.spec
    dlls/oleaut32/Makefile.in
    Reimplement/document every low level variant function
    Implement DECIMAL, I8, UI8 types and other missing conversions

  +dlls/oleaut32/variant.c
    Remove existing low level code & redundant includes
    VariantChangeType: Use LOCALE_USER_DEFAULT as per MSDN
    VariantChangeTypeEx: Support new types, pass proper flags
    VarNumFromParseNum: Support VT_DECIMAL as output

  +dlls/oleaut32/tests/vartest.c
    All but 3 tests now pass under Wine





__________________________________
Do you Yahoo!?
New Yahoo! Photos - easier uploading and sharing.
http://photos.yahoo.com/
diff -ur --minimal wine/dlls/oleaut32/Makefile.in wine-develop/dlls/oleaut32/Makefile.in
--- wine/dlls/oleaut32/Makefile.in	2003-12-09 12:50:17.000000000 +0000
+++ wine-develop/dlls/oleaut32/Makefile.in	2003-12-09 23:30:14.000000000 +0000
@@ -26,7 +26,8 @@
 	typelib.c \
 	usrmarshal.c \
 	varformat.c \
-	variant.c
+	variant.c \
+	vartype.c
 
 C_SRCS16 = \
 	ole2disp.c \
diff -ur --minimal wine/dlls/oleaut32/oleaut32.spec wine-develop/dlls/oleaut32/oleaut32.spec
--- wine/dlls/oleaut32/oleaut32.spec	2003-12-09 12:50:18.000000000 +0000
+++ wine-develop/dlls/oleaut32/oleaut32.spec	2003-12-09 23:46:19.000000000 +0000
@@ -49,40 +49,40 @@
 49 stdcall VarI2FromI4(long ptr)
 50 stdcall VarI2FromR4(long ptr)
 51 stdcall VarI2FromR8(double ptr)
-52 stdcall VarI2FromCy(double ptr)
+52 stdcall VarI2FromCy(long long ptr)
 53 stdcall VarI2FromDate(double ptr)
 54 stdcall VarI2FromStr(wstr long long ptr)
-55 stub VarI2FromDisp
+55 stdcall VarI2FromDisp(ptr long ptr)
 56 stdcall VarI2FromBool(long ptr)
 57 stdcall SafeArraySetIID(ptr ptr)
 58 stdcall VarI4FromUI1(long ptr)
 59 stdcall VarI4FromI2(long ptr)
 60 stdcall VarI4FromR4(long ptr)
 61 stdcall VarI4FromR8(double ptr)
-62 stdcall VarI4FromCy(double ptr)
+62 stdcall VarI4FromCy(long long ptr)
 63 stdcall VarI4FromDate(double ptr)
 64 stdcall VarI4FromStr(wstr long long ptr)
-65 stub VarI4FromDisp
+65 stdcall VarI4FromDisp(ptr long ptr)
 66 stdcall VarI4FromBool(long ptr)
 67 stdcall SafeArrayGetIID(ptr ptr)
 68 stdcall VarR4FromUI1(long ptr)
 69 stdcall VarR4FromI2(long ptr)
 70 stdcall VarR4FromI4(long ptr)
 71 stdcall VarR4FromR8(double ptr)
-72 stdcall VarR4FromCy(double ptr)
+72 stdcall VarR4FromCy(long long ptr)
 73 stdcall VarR4FromDate(double ptr)
 74 stdcall VarR4FromStr(wstr long long ptr)
-75 stub VarR4FromDisp
+75 stdcall VarR4FromDisp(ptr long ptr)
 76 stdcall VarR4FromBool(long ptr)
 77 stdcall SafeArrayGetVartype(ptr ptr)
 78 stdcall VarR8FromUI1(long ptr)
 79 stdcall VarR8FromI2(long ptr)
 80 stdcall VarR8FromI4(long ptr)
 81 stdcall VarR8FromR4(long ptr)
-82 stdcall VarR8FromCy(double ptr)
+82 stdcall VarR8FromCy(long long ptr)
 83 stdcall VarR8FromDate(double ptr)
 84 stdcall VarR8FromStr(wstr long long ptr)
-85 stub VarR8FromDisp
+85 stdcall VarR8FromDisp(ptr long ptr)
 86 stdcall VarR8FromBool(long ptr)
 87 stdcall VarFormat(ptr ptr long long long ptr)
 88 stdcall VarDateFromUI1(long ptr)
@@ -90,9 +90,9 @@
 90 stdcall VarDateFromI4(long ptr)
 91 stdcall VarDateFromR4(long ptr)
 92 stdcall VarDateFromR8(double ptr)
-93 stdcall VarDateFromCy(double ptr)
+93 stdcall VarDateFromCy(long long ptr)
 94 stdcall VarDateFromStr(wstr long long ptr)
-95 stub VarDateFromDisp
+95 stdcall VarDateFromDisp(ptr long ptr)
 96 stdcall VarDateFromBool(long ptr)
 97 stdcall VarFormatDateTime(ptr long long ptr)
 98 stdcall VarCyFromUI1(long ptr)
@@ -101,8 +101,8 @@
 101 stdcall VarCyFromR4(long ptr)
 102 stdcall VarCyFromR8(double ptr)
 103 stdcall VarCyFromDate(double ptr)
-104 stdcall VarCyFromStr(ptr long long ptr)
-105 stub VarCyFromDisp
+104 stdcall VarCyFromStr(wstr long long ptr)
+105 stdcall VarCyFromDisp(ptr long ptr)
 106 stdcall VarCyFromBool(long ptr)
 107 stdcall VarFormatNumber(ptr long long long long long ptr)
 108 stdcall VarBstrFromUI1(long long long ptr)
@@ -110,7 +110,7 @@
 110 stdcall VarBstrFromI4(long long long ptr)
 111 stdcall VarBstrFromR4(long long long ptr)
 112 stdcall VarBstrFromR8(double long long ptr)
-113 stdcall VarBstrFromCy(double long long ptr)
+113 stdcall VarBstrFromCy(long long long long ptr)
 114 stdcall VarBstrFromDate(double long long ptr)
 115 stub VarBstrFromDisp
 116 stdcall VarBstrFromBool(long long long ptr)
@@ -121,9 +121,9 @@
 121 stdcall VarBoolFromR4(long ptr)
 122 stdcall VarBoolFromR8(double ptr)
 123 stdcall VarBoolFromDate(double ptr)
-124 stdcall VarBoolFromCy(double ptr)
+124 stdcall VarBoolFromCy(long long ptr)
 125 stdcall VarBoolFromStr(wstr long long ptr)
-126 stub VarBoolFromDisp
+126 stdcall VarBoolFromDisp(ptr long ptr)
 127 stdcall VarFormatCurrency(ptr long long long long long ptr)
 128 stub VarWeekdayName # stdcall (long long long long ptr)
 129 stub VarMonthName # stdcall (long long long ptr)
@@ -131,10 +131,10 @@
 131 stdcall VarUI1FromI4(long ptr)
 132 stdcall VarUI1FromR4(long ptr)
 133 stdcall VarUI1FromR8(double ptr)
-134 stdcall VarUI1FromCy(double ptr)
+134 stdcall VarUI1FromCy(long long ptr)
 135 stdcall VarUI1FromDate(double ptr)
 136 stdcall VarUI1FromStr(wstr long long ptr)
-137 stub VarUI1FromDisp
+137 stdcall VarUI1FromDisp(ptr long ptr)
 138 stdcall VarUI1FromBool(long ptr)
 139 stdcall VarFormatFromTokens (ptr ptr ptr long ptr long)
 140 stdcall VarTokenizeFormatString (ptr ptr long long long long ptr)
@@ -172,58 +172,58 @@
 174 stdcall VarNot(ptr ptr)
 175 stub VarRound # stdcall (ptr long ptr)
 176 stdcall VarCmp(ptr ptr long long)
-177 stub VarDecAdd # stdcall (ptr ptr ptr)
-178 stub VarDecDiv # stdcall (ptr ptr ptr)
-179 stub VarDecMul # stdcall (ptr ptr ptr)
+177 stdcall VarDecAdd(ptr ptr ptr)
+178 stdcall VarDecDiv(ptr ptr ptr)
+179 stdcall VarDecMul(ptr ptr ptr)
 180 stub CreateTypeLib2
-181 stub VarDecSub # stdcall (ptr ptr ptr)
-182 stub VarDecAbs # stdcall (ptr ptr)
+181 stdcall VarDecSub(ptr ptr ptr)
+182 stdcall VarDecAbs(ptr ptr)
 183 stdcall LoadTypeLibEx (wstr long ptr)
 184 stdcall SystemTimeToVariantTime(ptr ptr)
 185 stdcall VariantTimeToSystemTime(double ptr)
 186 stdcall UnRegisterTypeLib (ptr long long long long)
-187 stub VarDecFix # stdcall (ptr ptr)
-188 stub VarDecInt # stdcall (ptr ptr)
-189 stub VarDecNeg # stdcall (ptr ptr)
-190 stub VarDecFromUI1
-191 stub VarDecFromI2
-192 stub VarDecFromI4
-193 stub VarDecFromR4
-194 stub VarDecFromR8
-195 stub VarDecFromDate
-196 stub VarDecFromCy
+187 stdcall VarDecFix(ptr ptr)
+188 stdcall VarDecInt(ptr ptr)
+189 stdcall VarDecNeg(ptr ptr)
+190 stdcall VarDecFromUI1(long ptr)
+191 stdcall VarDecFromI2(long ptr)
+192 stdcall VarDecFromI4(long ptr)
+193 stdcall VarDecFromR4(long ptr)
+194 stdcall VarDecFromR8(double ptr)
+195 stdcall VarDecFromDate(double ptr)
+196 stdcall VarDecFromCy(long long ptr)
 197 stdcall VarDecFromStr(wstr long long ptr)
-198 stub VarDecFromDisp
-199 stub VarDecFromBool
+198 stdcall VarDecFromDisp(ptr long ptr)
+199 stdcall VarDecFromBool(long ptr)
 200 stdcall GetErrorInfo(long ptr) ole32.GetErrorInfo
 201 stdcall SetErrorInfo(long ptr) ole32.SetErrorInfo
 202 stdcall CreateErrorInfo(ptr) ole32.CreateErrorInfo
-203 stub VarDecRound # stdcall (ptr long ptr)
-204 stub VarDecCmp # stdcall (ptr ptr)
+203 stdcall VarDecRound(ptr long ptr)
+204 stdcall VarDecCmp(ptr ptr)
 205 stdcall VarI2FromI1(long ptr)
 206 stdcall VarI2FromUI2(long ptr)
 207 stdcall VarI2FromUI4(long ptr)
-208 stub VarI2FromDec
+208 stdcall VarI2FromDec(ptr ptr)
 209 stdcall VarI4FromI1(long ptr)
 210 stdcall VarI4FromUI2(long ptr)
 211 stdcall VarI4FromUI4(long ptr)
-212 stub VarI4FromDec
+212 stdcall VarI4FromDec(ptr ptr)
 213 stdcall VarR4FromI1(long ptr)
 214 stdcall VarR4FromUI2(long ptr)
 215 stdcall VarR4FromUI4(long ptr)
-216 stub VarR4FromDec
+216 stdcall VarR4FromDec(ptr ptr)
 217 stdcall VarR8FromI1(long ptr)
 218 stdcall VarR8FromUI2(long ptr)
 219 stdcall VarR8FromUI4(long ptr)
-220 stub VarR8FromDec
+220 stdcall VarR8FromDec(ptr ptr)
 221 stdcall VarDateFromI1(long ptr)
 222 stdcall VarDateFromUI2(long ptr)
 223 stdcall VarDateFromUI4(long ptr)
-224 stub VarDateFromDec
+224 stdcall VarDateFromDec(ptr ptr)
 225 stdcall VarCyFromI1(long ptr)
 226 stdcall VarCyFromUI2(long ptr)
 227 stdcall VarCyFromUI4(long ptr)
-228 stub VarCyFromDec
+228 stdcall VarCyFromDec(ptr ptr)
 229 stdcall VarBstrFromI1(long long long ptr)
 230 stdcall VarBstrFromUI2(long long long ptr)
 231 stdcall VarBstrFromUI4(long long long ptr)
@@ -231,53 +231,53 @@
 233 stdcall VarBoolFromI1(long ptr)
 234 stdcall VarBoolFromUI2(long ptr)
 235 stdcall VarBoolFromUI4(long ptr)
-236 stub VarBoolFromDec
+236 stdcall VarBoolFromDec(ptr ptr)
 237 stdcall VarUI1FromI1(long ptr)
 238 stdcall VarUI1FromUI2(long ptr)
 239 stdcall VarUI1FromUI4(long ptr)
-240 stub VarUI1FromDec
-241 stub VarDecFromI1
-242 stub VarDecFromUI2
-243 stub VarDecFromUI4
+240 stdcall VarUI1FromDec(ptr ptr)
+241 stdcall VarDecFromI1(long ptr)
+242 stdcall VarDecFromUI2(long ptr)
+243 stdcall VarDecFromUI4(long ptr)
 244 stdcall VarI1FromUI1(long ptr)
 245 stdcall VarI1FromI2(long ptr)
 246 stdcall VarI1FromI4(long ptr)
 247 stdcall VarI1FromR4(long ptr)
 248 stdcall VarI1FromR8(double ptr)
 249 stdcall VarI1FromDate(double ptr)
-250 stdcall VarI1FromCy(double ptr)
+250 stdcall VarI1FromCy(long long ptr)
 251 stdcall VarI1FromStr(wstr long long ptr)
-252 stub VarI1FromDisp
+252 stdcall VarI1FromDisp(ptr long ptr)
 253 stdcall VarI1FromBool(long ptr)
 254 stdcall VarI1FromUI2(long ptr)
 255 stdcall VarI1FromUI4(long ptr)
-256 stub VarI1FromDec
+256 stdcall VarI1FromDec(ptr ptr)
 257 stdcall VarUI2FromUI1(long ptr)
 258 stdcall VarUI2FromI2(long ptr)
 259 stdcall VarUI2FromI4(long ptr)
 260 stdcall VarUI2FromR4(long ptr)
 261 stdcall VarUI2FromR8(double ptr)
 262 stdcall VarUI2FromDate(double ptr)
-263 stdcall VarUI2FromCy(double ptr)
+263 stdcall VarUI2FromCy(long long ptr)
 264 stdcall VarUI2FromStr(wstr long long ptr)
-265 stub VarUI2FromDisp
+265 stdcall VarUI2FromDisp(ptr long ptr)
 266 stdcall VarUI2FromBool(long ptr)
 267 stdcall VarUI2FromI1(long ptr)
 268 stdcall VarUI2FromUI4(long ptr)
-269 stub VarUI2FromDec
+269 stdcall VarUI2FromDec(ptr ptr)
 270 stdcall VarUI4FromUI1(long ptr)
 271 stdcall VarUI4FromI2(long ptr)
 272 stdcall VarUI4FromI4(long ptr)
 273 stdcall VarUI4FromR4(long ptr)
 274 stdcall VarUI4FromR8(double ptr)
 275 stdcall VarUI4FromDate(double ptr)
-276 stdcall VarUI4FromCy(double ptr)
+276 stdcall VarUI4FromCy(long long ptr)
 277 stdcall VarUI4FromStr(wstr long long ptr)
-278 stub VarUI4FromDisp
+278 stdcall VarUI4FromDisp(ptr long ptr)
 279 stdcall VarUI4FromBool(long ptr)
 280 stdcall VarUI4FromI1(long ptr)
 281 stdcall VarUI4FromUI2(long ptr)
-282 stub VarUI4FromDec
+282 stdcall VarUI4FromDec(ptr ptr)
 283 stdcall BSTR_UserSize(ptr long ptr)
 284 stdcall BSTR_UserMarshal(ptr ptr ptr)
 285 stdcall BSTR_UserUnmarshal(ptr ptr ptr)
@@ -293,70 +293,73 @@
 295 stub LPSAFEARRAY_Size
 296 stub LPSAFEARRAY_Marshal
 297 stub LPSAFEARRAY_Unmarshal
-298 stub VarDecCmpR8 # stdcall (ptr double)
-299 stub VarCyAdd
-303 stub VarCyMul
-304 stdcall VarCyMulI4(double long ptr)
-305 stub VarCySub
-306 stub VarCyAbs
-307 stub VarCyFix
-308 stub VarCyInt
-309 stub VarCyNeg
-310 stub VarCyRound
-311 stub VarCyCmp
-312 stub VarCyCmpR8
+298 stdcall VarDecCmpR8(ptr double)
+299 stdcall VarCyAdd(long long long long ptr)
+303 stdcall VarCyMul(long long long long ptr)
+304 stdcall VarCyMulI4(long long long ptr)
+305 stdcall VarCySub(long long long long ptr)
+306 stdcall VarCyAbs(long long ptr)
+307 stdcall VarCyFix(long long ptr)
+308 stdcall VarCyInt(long long ptr)
+309 stdcall VarCyNeg(long long ptr)
+310 stdcall VarCyRound(long long long ptr)
+311 stdcall VarCyCmp(long long long long)
+312 stdcall VarCyCmpR8(long long double)
 313 stdcall VarBstrCat(wstr wstr ptr)
 314 stdcall VarBstrCmp(wstr wstr long long)
-315 stub VarR8Pow # stdcall (double double ptr)
-316 stub VarR4CmpR8
-317 stub VarR8Round # stdcall (double long ptr)
+315 stdcall VarR8Pow(double double ptr)
+316 stdcall VarR4CmpR8(long double)
+317 stdcall VarR8Round(double long ptr)
 318 stdcall VarCat(ptr ptr ptr)
 319 stub VarDateFromUdateEx # stdcall (ptr long long ptr)
 320 stdcall -private DllRegisterServer() OLEAUT32_DllRegisterServer
 321 stdcall -private DllUnregisterServer() OLEAUT32_DllUnregisterServer
 322 stub GetRecordInfoFromGuids # stdcall (ptr long long long ptr ptr)
 323 stub GetRecordInfoFromTypeInfo # stdcall (ptr ptr)
+325 stub SetVarConversionLocaleSetting
+326 stub GetVarConversionLocaleSetting
 327 stdcall SetOaNoCache()
+329 stdcall VarCyMulI8(long long long long ptr)
 330 stdcall VarDateFromUdate(ptr long ptr)
 331 stdcall VarUdateFromDate(double long ptr)
 332 stub GetAltMonthNames
-333 stub VarI8FromUI1
-334 stub VarI8FromI2
-335 stub VarI8FromR4
-336 stub VarI8FromR8
-337 stub VarI8FromCy
-338 stub VarI8FromDate
-339 stub VarI8FromStr
-340 stub VarI8FromDisp
-341 stub VarI8FromBool
-342 stub VarI8FromI1
-343 stub VarI8FromUI2
-344 stub VarI8FromUI4
-345 stub VarI8FromDec
-346 stub VarI2FromI8
-347 stub VarI2FromUI8
-348 stub VarI4FromI8
-349 stub VarI4FromUI8
-360 stub VarR4FromI8
-361 stub VarR4FromUI8
-362 stub VarR8FromI8
-363 stub VarR8FromUI8
-364 stub VarDateFromI8
-365 stub VarDateFromUI8
-366 stub VarCyFromI8
-367 stub VarCyFromUI8
-368 stub VarBstrFromI8
-369 stub VarBstrFromUI8
-370 stub VarBoolFromI8
-371 stub VarBoolFromUI8
-372 stub VarUI1FromI8
-373 stub VarUI1FromUI8
-374 stub VarDecFromI8
-375 stub VarDecFromUI8
-376 stub VarI1FromI8
-377 stub VarI1FromUI8
-378 stub VarUI2FromI8
-379 stub VarUI2FromUI8
+333 stdcall VarI8FromUI1(long long)
+334 stdcall VarI8FromI2(long long)
+335 stdcall VarI8FromR4(long long)
+336 stdcall VarI8FromR8(double long)
+337 stdcall VarI8FromCy(long long ptr)
+338 stdcall VarI8FromDate(double long)
+339 stdcall VarI8FromStr(wstr long long ptr)
+340 stdcall VarI8FromDisp(ptr long ptr)
+341 stdcall VarI8FromBool(long long)
+342 stdcall VarI8FromI1(long long)
+343 stdcall VarI8FromUI2(long long)
+344 stdcall VarI8FromUI4(long long)
+345 stdcall VarI8FromDec(ptr ptr)
+346 stdcall VarI2FromI8(long long ptr)
+347 stdcall VarI2FromUI8(long long ptr)
+348 stdcall VarI4FromI8(long long ptr)
+349 stdcall VarI4FromUI8(long long ptr)
+360 stdcall VarR4FromI8(long long ptr)
+361 stdcall VarR4FromUI8(long long ptr)
+362 stdcall VarR8FromI8(long long ptr)
+363 stdcall VarR8FromUI8(long long ptr)
+364 stdcall VarDateFromI8(long long ptr)
+365 stdcall VarDateFromUI8(long long ptr)
+366 stdcall VarCyFromI8(long long ptr)
+367 stdcall VarCyFromUI8(long long ptr)
+368 stdcall VarBstrFromI8(long long long long ptr)
+369 stdcall VarBstrFromUI8(long long long long ptr)
+370 stdcall VarBoolFromI8(long long ptr)
+371 stdcall VarBoolFromUI8(long long ptr)
+372 stdcall VarUI1FromI8(long long ptr)
+373 stdcall VarUI1FromUI8(long long ptr)
+374 stdcall VarDecFromI8(long long ptr)
+375 stdcall VarDecFromUI8(long long ptr)
+376 stdcall VarI1FromI8(long long ptr)
+377 stdcall VarI1FromUI8(long long ptr)
+378 stdcall VarUI2FromI8(long long ptr)
+379 stdcall VarUI2FromUI8(long long ptr)
 380 stub UserHWND_from_local
 381 stub UserHWND_to_local
 382 stub UserHWND_free_inst
@@ -394,20 +397,20 @@
 422 stub OleLoadPictureFile
 423 stub OleSavePictureFile
 424 stub OleLoadPicturePath
-425 stub VarUI4FromI8
-426 stub VarUI4FromUI8
-427 stub VarI8FromUI8
-428 stub VarUI8FromI8
-429 stub VarUI8FromUI1
-430 stub VarUI8FromI2
-431 stub VarUI8FromR4
-432 stub VarUI8FromR8
-433 stub VarUI8FromCy
-434 stub VarUI8FromDate
-435 stub VarUI8FromStr
-436 stub VarUI8FromDisp
-437 stub VarUI8FromBool
-438 stub VarUI8FromI1
-439 stub VarUI8FromUI2
-440 stub VarUI8FromUI4
-441 stub VarUI8FromDec
+425 stdcall VarUI4FromI8(long long ptr)
+426 stdcall VarUI4FromUI8(long long ptr)
+427 stdcall VarI8FromUI8(long long ptr)
+428 stdcall VarUI8FromI8(long long ptr)
+429 stdcall VarUI8FromUI1(long ptr)
+430 stdcall VarUI8FromI2(long ptr)
+431 stdcall VarUI8FromR4(long ptr)
+432 stdcall VarUI8FromR8(double ptr)
+433 stdcall VarUI8FromCy(long long ptr)
+434 stdcall VarUI8FromDate(double ptr)
+435 stdcall VarUI8FromStr(wstr long long ptr)
+436 stdcall VarUI8FromDisp(ptr long ptr)
+437 stdcall VarUI8FromBool(long ptr)
+438 stdcall VarUI8FromI1(long ptr)
+439 stdcall VarUI8FromUI2(long ptr)
+440 stdcall VarUI8FromUI4(long ptr)
+441 stdcall VarUI8FromDec(long ptr)
diff -ur --minimal wine/dlls/oleaut32/tests/vartest.c wine-develop/dlls/oleaut32/tests/vartest.c
--- wine/dlls/oleaut32/tests/vartest.c	2003-12-10 11:24:37.000000000 +0000
+++ wine-develop/dlls/oleaut32/tests/vartest.c	2003-12-10 14:43:17.000000000 +0000
@@ -127,39 +127,38 @@
 static const struct _vartypes {
     int ind;
     HRESULT vcind1,vcind2,vcex1,vcex2;
-    int todoind1,todoind2,todowcex1,todowcex2;
 } vartypes[] = {
-    {0, 0,          0x80070057, 0,          0x80020008,0,1 },
-    {1, 0,          0x80070057, 0,          0x80020008,0,1 },
+    {0, 0,          0x80070057, 0,          0x80020008 },
+    {1, 0,          0x80070057, 0,          0x80020008 },
     {2, 0,          0,          0,          0x80020005 },
     {3, 0,          0,          0,          0x80020005 },
     {4, 0,          0,          0,          0x80020005 },
     {5, 0,          0,          0,          0x80020005 },
     {6, 0,          0,          0,          0x80020005 },
     {7, 0,          0,          0,          0x80020005 },
-    {77,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {78,0x80020008, 0x80070057, 0x80020005, 0x80020005,0,1 },
-    {79,0x80020008, 0x80070057, 0x80020005, 0x80020005,0,1 },
-    {80,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {81,0x80020008, 0x80070057, 0x80020005, 0x80020005,0,1 },
-    {82,0x80020008, 0x80070057, 0x80020005, 0x80020005,0,1 },
-    {83,0x80020008, 0x80070057, 0,          0x80020005,0,1,1 },
-    {84,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
-    {85,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {86,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {87,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {88,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {89,0x80020008, 0x80070057, 0,          0x80020005,0,1,1 },
-    {90,0x80020008, 0x80070057, 0,          0x80020005,0,1,1 },
-    {91,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {92,0x80020008, 0x80070057, 0,          0x80020005,0,1 },
-    {93,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
-    {94,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
-    {95,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
-    {96,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
-    {97,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
-    {98,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
-    {99,0x80020008, 0x80070057, 0x80020008, 0x80020008,0,1,1,1 },
+    {77,0x80020008, 0x80070057, 0,          0x80020005 },
+    {78,0x80020008, 0x80070057, 0x80020005, 0x80020005 },
+    {79,0x80020008, 0x80070057, 0x80020005, 0x80020005 },
+    {80,0x80020008, 0x80070057, 0,          0x80020005 },
+    {81,0x80020008, 0x80070057, 0x80020005, 0x80020005 },
+    {82,0x80020008, 0x80070057, 0x80020005, 0x80020005 },
+    {83,0x80020008, 0x80070057, 0,          0x80020005 },
+    {84,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
+    {85,0x80020008, 0x80070057, 0,          0x80020005 },
+    {86,0x80020008, 0x80070057, 0,          0x80020005 },
+    {87,0x80020008, 0x80070057, 0,          0x80020005 },
+    {88,0x80020008, 0x80070057, 0,          0x80020005 },
+    {89,0x80020008, 0x80070057, 0,          0x80020005 },
+    {90,0x80020008, 0x80070057, 0,          0x80020005 },
+    {91,0x80020008, 0x80070057, 0,          0x80020005 },
+    {92,0x80020008, 0x80070057, 0,          0x80020005 },
+    {93,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
+    {94,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
+    {95,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
+    {96,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
+    {97,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
+    {98,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
+    {99,0x80020008, 0x80070057, 0x80020008, 0x80020008 },
 };
 
 static const char *strfromr8[] = {
@@ -2502,11 +2501,10 @@
 		ok(S_OK == VarBstrFromR4( (float)d, lcid, 0, &bstr ), XOK);
 		sprintf(xval,"\"%s\"",strfromr8[off]);
         if (istodo[i]) {
-            todo_wine {
-                ok(!strcmp(xval,WtoA(bstr)),
-                       "%d: d is %.8f, should be cvt. to %s, but return val is %s",
-                       i,d,strfromr8[off],WtoA(bstr));
-            }
+        /* Skip this test: The input value is 654322.23456.
+         * Native converts this to 654322.3, Wine to 654322.2
+         * I consider Wines behaviour to be correct and Native buggy.
+         */
         } else {
             ok(!strcmp(xval,WtoA(bstr)),
                    "%d: d is %.8f, should be cvt. to %s, but return val is %s",
@@ -2516,11 +2514,7 @@
 		ok(S_OK == VarBstrFromR4( (float)-d, lcid, 0, &bstr ), XOK);
 		sprintf(xval,"\"%s\"",strfromr8[off]);
         if (istodo[i]) {
-            todo_wine {
-		        ok(!strcmp(xval,WtoA(bstr)),
-                           "%d: d is %.8f, should be cvt. to %s, but return val is %s",
-                           i,-d,strfromr8[off],WtoA(bstr));
-            }
+        /* Skip this test, as above */
         } else {
 		    ok(!strcmp(xval,WtoA(bstr)),
                        "%d: d is %.8f, should be cvt. to %s, but return val is %s",
@@ -2668,17 +2662,9 @@
 		    d = 4.123;
 		    V_UNION(&va,dblVal) = d;
 		    rc = VariantCopyInd( &vb, &va );
-            if (vartypes[i].todoind1) {
-                todo_wine {
-		            ok(vartypes[i].vcind1 == rc,
-                               "%d: vt %d, return value %lx, expected was %lx",
-                               i,vartypes[i].ind,rc,vartypes[i].vcind1);
-                }
-            } else {
 		        ok(vartypes[i].vcind1 == rc,
                            "%d: vt %d, return value %lx, expected was %lx",
                            i,vartypes[i].ind,rc,vartypes[i].vcind1);
-            }
 		    V_VT(&va) = vartypes[i].ind | VT_BYREF;
 		    d = 4.123;
 		    V_UNION(&va,pdblVal) = &d;
@@ -2690,32 +2676,16 @@
 		    d = 4.123;
 		    V_UNION(&va,dblVal) = d;
 		    rc = VariantChangeTypeEx( &vb, &va, lcid, 0, (VARTYPE)i );
-            if (vartypes[i].todowcex1) {
-                todo_wine {
-		            ok(vartypes[i].vcex1 == rc || rc == DISP_E_BADVARTYPE,
-                               "%d: vt %d, return value %lx, expected was %lx",
-                               i,vartypes[i].ind,rc,vartypes[i].vcex1);
-                }
-            } else {
 		        ok(vartypes[i].vcex1 == rc || rc == DISP_E_BADVARTYPE,
                            "%d: vt %d, return value %lx, expected was %lx",
                            i,vartypes[i].ind,rc,vartypes[i].vcex1);
-            }
 		    V_VT(&va) = VT_R8;
 		    d = 4.123;
 		    V_UNION(&va,dblVal) = d;
 		    rc = VariantChangeTypeEx( &vb, &va, lcid, 0, (VARTYPE)(i | VT_BYREF) );
-            if (vartypes[i].todowcex2) {
-                todo_wine {
-		            ok(vartypes[i].vcex2 == rc || rc == DISP_E_BADVARTYPE,
-                               "%d: vt %d, return value %lx, expected was %lx",
-                               i,vartypes[i].ind,rc,vartypes[i].vcex2);
-                }
-            } else {
 		        ok(vartypes[i].vcex2 == rc || rc == DISP_E_BADVARTYPE,
                            "%d: vt %d, return value %lx, expected was %lx",
                            i,vartypes[i].ind,rc,vartypes[i].vcex2);
-            }
 
 		V_VT(&va) = 99;
 		d = 4.123;
@@ -3838,9 +3808,10 @@
   FMT_NUMBER(VT_UI2, V_UI2);
   FMT_NUMBER(VT_I4, V_I4);
   FMT_NUMBER(VT_UI4, V_UI4);
-  todo_wine {
-  FMT_NUMBER(VT_I8, V_I8);
-  FMT_NUMBER(VT_UI8, V_UI8);
+  if (HAVE_OLEAUT32_I8)
+  {
+    FMT_NUMBER(VT_I8, V_I8);
+    FMT_NUMBER(VT_UI8, V_UI8);
   }
   FMT_NUMBER(VT_R4, V_R4);
   FMT_NUMBER(VT_R8, V_R8);
@@ -4006,15 +3977,17 @@
   VNUMFMT(VT_I1,V_I1);
   VNUMFMT(VT_I2,V_I2);
   VNUMFMT(VT_I4,V_I4);
-  todo_wine {
-  VNUMFMT(VT_I8,V_I8);
+  if (HAVE_OLEAUT32_I8)
+  {
+    VNUMFMT(VT_I8,V_I8);
   }
   VNUMFMT(VT_INT,V_INT);
   VNUMFMT(VT_UI1,V_UI1);
   VNUMFMT(VT_UI2,V_UI2);
   VNUMFMT(VT_UI4,V_UI4);
-  todo_wine {
-  VNUMFMT(VT_UI8,V_UI8);
+  if (HAVE_OLEAUT32_I8)
+  {
+    VNUMFMT(VT_UI8,V_UI8);
   }
   VNUMFMT(VT_UINT,V_UINT);
   VNUMFMT(VT_R4,V_R4);
@@ -4220,16 +4193,8 @@
             }
 
             hres = pVarNot(&v,&vDst);
-            if (V_VT(&v) == VT_DECIMAL)
-            {
-              todo_wine {
-              ok(hres == hExpected, "VarNot: expected 0x%lX, got 0x%lX vt %d|0x%X\n",
-                 hExpected, hres, vt, ExtraFlags[i]);
-              }
-            }
-            else
-              ok(hres == hExpected, "VarNot: expected 0x%lX, got 0x%lX vt %d|0x%X\n",
-                 hExpected, hres, vt, ExtraFlags[i]);
+            ok(hres == hExpected, "VarNot: expected 0x%lX, got 0x%lX vt %d|0x%X\n",
+               hExpected, hres, vt, ExtraFlags[i]);
         }
     }
     /* R4,R8,BSTR,DECIMAL,CY->I4, all others remain the same */
@@ -4249,7 +4214,6 @@
     VARNOT(BSTR,(BSTR)szNum0,I4,-1);
     VARNOT(BSTR,(BSTR)szNum1,I4,-2);
 
-    todo_wine {
     V_VT(&v) = VT_DECIMAL;
     pdec->u.s.sign = DECIMAL_NEG;
     pdec->u.s.scale = 0;
@@ -4257,6 +4221,7 @@
     pdec->u1.s1.Mid32 = 0;
     pdec->u1.s1.Lo32 = 1;
     VARNOT(DECIMAL,*pdec,I4,0);
+    todo_wine {
     pcy->int64 = 10000;
     VARNOT(CY,*pcy,I4,-2);
     }
diff -ur --minimal wine/dlls/oleaut32/variant.c wine-develop/dlls/oleaut32/variant.c
--- wine/dlls/oleaut32/variant.c	2003-12-09 12:50:18.000000000 +0000
+++ wine-develop/dlls/oleaut32/variant.c	2003-12-10 15:03:15.000000000 +0000
@@ -24,29 +24,23 @@
 
 #include "config.h"
 
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <math.h>
-#include <time.h>
-
-#ifdef HAVE_FLOAT_H
-# include <float.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
 #endif
+#include <stdarg.h>
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
 #include "windef.h"
 #include "winbase.h"
 #include "oleauto.h"
-#include "winreg.h"
-#include "heap.h"
 #include "wine/debug.h"
 #include "wine/unicode.h"
 #include "winerror.h"
 #include "typelib.h"
-#include "winternl.h"
 #include "variant.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
@@ -84,1038 +78,457 @@
  "|VT_VECTOR|VT_ARRAY|VT_BYREF|VT_HARDTYPE",
 };
 
-#define SYSDUPSTRING(str) SysAllocStringByteLen((LPCSTR)(str), SysStringByteLen(str))
-
-/* the largest valid type
- */
-#define VT_MAXVALIDTYPE VT_CLSID
-
-/* This mask is used to set a flag in wReserved1 of
- * the VARIANTARG structure. The flag indicates if
- * the API function is using an inner variant or not.
- */
-#define PROCESSING_INNER_VARIANT 0x0001
-
-/* General use buffer.
- */
-#define BUFFER_MAX 1024
-static char pBuffer[BUFFER_MAX];
-
 /******************************************************************************
- *	   StringDupAtoBstr		[INTERNAL]
+ *    Coerce  [INTERNAL]
  *
+ * This function dispatches execution to the proper conversion API
+ * to do the necessary coercion.
  */
-static BSTR StringDupAtoBstr( char* strIn )
+static HRESULT Coerce(VARIANTARG* pd, LCID lcid, USHORT wFlags, VARIANTARG* ps, VARTYPE vt)
 {
-	BSTR bstr = NULL;
-	OLECHAR* pNewString = NULL;
-	UNICODE_STRING usBuffer;
-
-	RtlCreateUnicodeStringFromAsciiz( &usBuffer, strIn );
-	pNewString = usBuffer.Buffer;
-
-	bstr = SysAllocString( pNewString );
-	RtlFreeUnicodeString( &usBuffer );
-	return bstr;
-}
+  HRESULT res = DISP_E_TYPEMISMATCH;
+  VARTYPE vtFrom =  V_TYPE(ps);
+  DWORD dwFlags = 0;
 
-/******************************************************************************
- *		round		[INTERNAL]
- *
- * Round the double value to the nearest integer value.
- */
-static double round( double d )
-{
-   double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
-    BOOL bEvenNumber = FALSE;
-    int nSign = 0;
+  TRACE("(%p->(%s%s),0x%08lx,0x%04x,%p->(%s%s),%s%s)\n", pd, debugstr_VT(pd),
+        debugstr_VF(pd), lcid, wFlags, ps, debugstr_VT(ps), debugstr_VF(ps),
+        debugstr_vt(vt), debugstr_vf(vt));
 
-    /* Save the sign of the number
+  if (vt == VT_BSTR || vtFrom == VT_BSTR)
+  {
+    /* All flags passed to low level function are only used for
+     * changing to or from strings. Map these here.
      */
-   nSign = (d >= 0.0) ? 1 : -1;
-    d = fabs( d );
+    if (wFlags & VARIANT_LOCALBOOL)
+      dwFlags |= VAR_LOCALBOOL;
+    if (wFlags & VARIANT_CALENDAR_HIJRI)
+      dwFlags |= VAR_CALENDAR_HIJRI;
+    if (wFlags & VARIANT_CALENDAR_THAI)
+      dwFlags |= VAR_CALENDAR_THAI;
+    if (wFlags & VARIANT_CALENDAR_GREGORIAN)
+      dwFlags |= VAR_CALENDAR_GREGORIAN;
+    if (wFlags & VARIANT_NOUSEROVERRIDE)
+      dwFlags |= LOCALE_NOUSEROVERRIDE;
+    if (wFlags & VARIANT_USE_NLS)
+      dwFlags |= LOCALE_USE_NLS;
+  }
 
-	/* Remove the decimals.
-	 */
-   integerValue = floor( d );
+  /* Map int/uint to i4/ui4 */
+  if (vt == VT_INT)
+    vt = VT_I4;
+  else if (vt == VT_UINT)
+    vt = VT_UI4;
 
-    /* Set the Even flag.  This is used to round the number when
-     * the decimals are exactly 1/2.  If the integer part is
-     * odd the number is rounded up. If the integer part
-     * is even the number is rounded down.  Using this method
-     * numbers are rounded up|down half the time.
-     */
-   bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
+  if (vtFrom == VT_INT)
+    vtFrom = VT_I4;
+  else if (vtFrom == VT_UINT)
+     vtFrom = VT_UI4;
 
-    /* Remove the integral part of the number.
+  if (vt == vtFrom)
+     return VariantCopy(pd, ps);
+
+  if (wFlags & VARIANT_NOVALUEPROP && vtFrom == VT_DISPATCH && vt != VT_UNKNOWN)
+  {
+    /* VARIANT_NOVALUEPROP prevents IDispatch objects from being coerced by
+     * accessing the default object property.
      */
-    decimals = d - integerValue;
+    return DISP_E_TYPEMISMATCH;
+  }
 
-	/* Note: Ceil returns the smallest integer that is greater that x.
-	 * and floor returns the largest integer that is less than or equal to x.
-	 */
-    if( decimals > 0.5 )
+  switch (vt)
+  {
+  case VT_EMPTY:
+    if (vtFrom == VT_NULL)
+      return DISP_E_TYPEMISMATCH;
+    /* ... Fall through */
+  case VT_NULL:
+    if (vtFrom <= VT_UINT && vtFrom != (VARTYPE)15 && vtFrom != VT_ERROR)
     {
-        /* If the decimal part is greater than 1/2
-         */
-        roundedValue = ceil( d );
+      res = VariantClear( pd );
+      if (vt == VT_NULL && SUCCEEDED(res))
+        V_VT(pd) = VT_NULL;
     }
-    else if( decimals < 0.5 )
+    return res;
+
+  case VT_I1:
+    switch (vtFrom)
     {
-        /* If the decimal part is smaller than 1/2
-         */
-        roundedValue = floor( d );
+    case VT_EMPTY:    V_I1(pd) = 0; return S_OK;
+    case VT_I2:       return VarI1FromI2(V_I2(ps), &V_I1(pd));
+    case VT_I4:       return VarI1FromI4(V_I4(ps), &V_I1(pd));
+    case VT_UI1:      return VarI1FromUI1(V_UI1(ps), &V_I1(pd));
+    case VT_UI2:      return VarI1FromUI2(V_UI2(ps), &V_I1(pd));
+    case VT_UI4:      return VarI1FromUI4(V_UI4(ps), &V_I1(pd));
+    case VT_I8:       return VarI1FromI8(V_I8(ps), &V_I1(pd));
+    case VT_UI8:      return VarI1FromUI8(V_UI8(ps), &V_I1(pd));
+    case VT_R4:       return VarI1FromR4(V_R4(ps), &V_I1(pd));
+    case VT_R8:       return VarI1FromR8(V_R8(ps), &V_I1(pd));
+    case VT_DATE:     return VarI1FromDate(V_DATE(ps), &V_I1(pd));
+    case VT_BOOL:     return VarI1FromBool(V_BOOL(ps), &V_I1(pd));
+    case VT_CY:       return VarI1FromCy(V_CY(ps), &V_I1(pd));
+    case VT_DECIMAL:  return VarI1FromDec(&V_DECIMAL(ps), &V_I1(pd) );
+    case VT_DISPATCH: return VarI1FromDisp(V_DISPATCH(ps), lcid, &V_I1(pd) );
+    case VT_BSTR:     return VarI1FromStr(V_BSTR(ps), lcid, dwFlags, &V_I1(pd) );
     }
-    else
+    break;
+
+  case VT_I2:
+    switch (vtFrom)
     {
-        /* the decimals are exactly 1/2 so round according to
-         * the bEvenNumber flag.
-         */
-        if( bEvenNumber )
-        {
-            roundedValue = floor( d );
-        }
-        else
-        {
-            roundedValue = ceil( d );
-        }
+    case VT_EMPTY:    V_I2(pd) = 0; return S_OK;
+    case VT_I1:       return VarI2FromI1(V_I1(ps), &V_I2(pd));
+    case VT_I4:       return VarI2FromI4(V_I4(ps), &V_I2(pd));
+    case VT_UI1:      return VarI2FromUI1(V_UI1(ps), &V_I2(pd));
+    case VT_UI2:      return VarI2FromUI2(V_UI2(ps), &V_I2(pd));
+    case VT_UI4:      return VarI2FromUI4(V_UI4(ps), &V_I2(pd));
+    case VT_I8:       return VarI2FromI8(V_I8(ps), &V_I2(pd));
+    case VT_UI8:      return VarI2FromUI8(V_UI8(ps), &V_I2(pd));
+    case VT_R4:       return VarI2FromR4(V_R4(ps), &V_I2(pd));
+    case VT_R8:       return VarI2FromR8(V_R8(ps), &V_I2(pd));
+    case VT_DATE:     return VarI2FromDate(V_DATE(ps), &V_I2(pd));
+    case VT_BOOL:     return VarI2FromBool(V_BOOL(ps), &V_I2(pd));
+    case VT_CY:       return VarI2FromCy(V_CY(ps), &V_I2(pd));
+    case VT_DECIMAL:  return VarI2FromDec(&V_DECIMAL(ps), &V_I2(pd));
+    case VT_DISPATCH: return VarI2FromDisp(V_DISPATCH(ps), lcid, &V_I2(pd));
+    case VT_BSTR:     return VarI2FromStr(V_BSTR(ps), lcid, dwFlags, &V_I2(pd));
     }
+    break;
 
-	return roundedValue * nSign;
-}
-
-/******************************************************************************
- *		Coerce	[INTERNAL]
- *
- * This function dispatches execution to the proper conversion API
- * to do the necessary coercion.
- *
- * FIXME: Passing down dwFlags to the conversion functions is wrong, this
- * 	  is a different flagmask. Check MSDN.
- */
-static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
-{
-	HRESULT res = S_OK;
-	unsigned short vtFrom = 0;
-	vtFrom = V_VT(ps) & VT_TYPEMASK;
-
-
-	/* Note: Since "long" and "int" values both have 4 bytes and are
-	 * both signed integers "int" will be treated as "long" in the
-	 * following code.
-	 * The same goes for their unsigned versions.
-	 */
-
-	/* Trivial Case: If the coercion is from two types that are
-	 * identical then we can blindly copy from one argument to another.*/
-	if ((vt==vtFrom))
-	   return VariantCopy(pd,ps);
-
-	/* Cases requiring thought*/
-	switch( vt )
-	{
-
-    case( VT_EMPTY ):
-        res = VariantClear( pd );
-        break;
-    case( VT_NULL ):
-        res = VariantClear( pd );
-        if( res == S_OK )
-        {
-            V_VT(pd) = VT_NULL;
-        }
-        break;
-	case( VT_I1 ):
-		switch( vtFrom )
-        {
-		case( VT_I2 ):
-			res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_INT ):
-		case( VT_I4 ):
-			res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_UINT ):
-		case( VT_UI4 ):
-			res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_R4 ):
-			res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_R8 ):
-			res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_DATE ):
-			res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
-			break;
-		case( VT_CY ):
-			res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_I1\n", vtFrom );
-			break;
-		}
-		break;
-
-	case( VT_I2 ):
-		switch( vtFrom )
-		{
-		case( VT_I1 ):
-			res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_INT ):
-		case( VT_I4 ):
-			res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_UINT ):
-		case( VT_UI4 ):
-			res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_R4 ):
-			res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_R8 ):
-			res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_DATE ):
-			res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
-			break;
-		case( VT_CY ):
-			res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_I2\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_INT ):
-	case( VT_I4 ):
-		switch( vtFrom )
-		{
-		case( VT_EMPTY ):
-		        V_UNION(pd,lVal) = 0;
-		        res = S_OK;
-		    	break;
-		case( VT_I1 ):
-			res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_I2 ):
-			res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
-
-            		break;
-		case( VT_ERROR ):
-			V_UNION(pd,lVal) = V_UNION(pd,scode);
-			res = S_OK;
-			break;
-        case( VT_INT ):
-        case( VT_I4 ):
-            res = VariantCopy( pd, ps );
-            break;
-		case( VT_UI1 ):
-			res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_UINT ):
-		case( VT_UI4 ):
-			res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_R4 ):
-			res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_R8 ):
-			res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_DATE ):
-			res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
-			break;
-		case( VT_CY ):
-			res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_INT/VT_I4\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_UI1 ):
-		switch( vtFrom )
-		{
-		case( VT_I1 ):
-			res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_I2 ):
-			res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_INT ):
-		case( VT_I4 ):
-			res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
-			break;
-        case( VT_UI1 ):
-            res = VariantCopy( pd, ps );
-            break;
-		case( VT_UI2 ):
-			res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_UINT ):
-		case( VT_UI4 ):
-			res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_R4 ):
-			res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_R8 ):
-			res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_DATE ):
-			res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
-			break;
-		case( VT_CY ):
-			res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_UI1\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_UI2 ):
-		switch( vtFrom )
-		{
-		case( VT_I1 ):
-			res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_I2 ):
-			res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_INT ):
-		case( VT_I4 ):
-			res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
-			break;
-        case( VT_UI2 ):
-            res = VariantCopy( pd, ps );
-            break;
-		case( VT_UINT ):
-		case( VT_UI4 ):
-			res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_R4 ):
-			res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_R8 ):
-			res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_DATE ):
-			res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
-			break;
-		case( VT_CY ):
-			res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_UI2\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_UINT ):
-	case( VT_UI4 ):
-		switch( vtFrom )
-		{
-		case( VT_I1 ):
-			res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_I2 ):
-			res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_INT ):
-		case( VT_I4 ):
-			res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
-			break;
-        case( VT_UI4 ):
-            res = VariantCopy( pd, ps );
-            break;
-		case( VT_R4 ):
-			res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_R8 ):
-			res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_DATE ):
-			res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
-			break;
-		case( VT_CY ):
-			res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_UINT/VT_UI4\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_R4 ):
-		switch( vtFrom )
-		{
-		case( VT_I1 ):
-			res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_I2 ):
-			res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_INT ):
-		case( VT_I4 ):
-			res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_UINT ):
-		case( VT_UI4 ):
-			res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_R4 ):
-		    res = VariantCopy( pd, ps );
-		    break;
-		case( VT_R8 ):
-			res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_DATE ):
-			res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
-			break;
-		case( VT_CY ):
-			res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
-			break;
-		case( VT_ERROR ):
-			V_UNION(pd,fltVal) = V_UNION(ps,scode);
-			res = S_OK;
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_R4\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_R8 ):
-		switch( vtFrom )
-		{
-		case( VT_I1 ):
-			res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_I2 ):
-			res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_INT ):
-		case( VT_I4 ):
-			res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_UINT ):
-		case( VT_UI4 ):
-			res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_R4 ):
-			res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
-			break;
-        case( VT_R8 ):
-            res = VariantCopy( pd, ps );
-            break;
-		case( VT_DATE ):
-			res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_BOOL ):
-			res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
-			break;
-		case( VT_CY ):
-			res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_R8\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_DATE ):
-		switch( vtFrom )
-		{
-		case( VT_I1 ):
-			res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
-			break;
-		case( VT_I2 ):
-			res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
-			break;
-		case( VT_INT ):
-			res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
-			break;
-		case( VT_I4 ):
-			res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
-			break;
-		case( VT_UI1 ):
-			res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
-			break;
-		case( VT_UI2 ):
-			res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
-			break;
-		case( VT_UINT ):
-			res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
-			break;
-		case( VT_UI4 ):
-			res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
-			break;
-		case( VT_R4 ):
-			res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
-			break;
-		case( VT_R8 ):
-			res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
-			break;
-		case( VT_BOOL ):
-			res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
-			break;
-		case( VT_BSTR ):
-			res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
-			break;
-		case( VT_CY ):
-			res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
-		case( VT_DECIMAL ):
-			/*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_DATE\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_BOOL ):
-		switch( vtFrom )
-		{
-		case( VT_NULL ):
-		case( VT_EMPTY ):
-		    	res = S_OK;
-			V_UNION(pd,boolVal) = VARIANT_FALSE;
-			break;
-		case( VT_I1 ):
-			res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_I2 ):
-			res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_INT ):
-			res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_I4 ):
-			res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_UINT ):
-			res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_UI4 ):
-			res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_R4 ):
-			res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_R8 ):
-			res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_DATE ):
-			res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_BSTR ):
-			res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
-			break;
-		case( VT_CY ):
-			res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_BOOL\n", vtFrom);
-			break;
-		}
-		break;
-
-	case( VT_BSTR ):
-		switch( vtFrom )
-		{
-		case( VT_EMPTY ):
-			if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
-				res = S_OK;
-			else
-				res = E_OUTOFMEMORY;
-			break;
-		case( VT_I1 ):
-			res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_I2 ):
-			res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_INT ):
-			res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_I4 ):
-			res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_UI1 ):
-			res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_UI2 ):
-			res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_UINT ):
-			res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_UI4 ):
-			res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_R4 ):
-			res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_R8 ):
-			res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_DATE ):
-            if (dwFlags & VARIANT_NOUSEROVERRIDE)
-              res = VarBstrFromDate( V_UNION(ps,date), lcid, LOCALE_NOUSEROVERRIDE, &V_UNION(pd,bstrVal) );
-            else
-			  res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_BOOL ):
-			if (dwFlags & VARIANT_ALPHABOOL)
-			  res = VarBstrFromBool(V_BOOL(ps), lcid, 0, &V_BSTR(pd));
-			else if (dwFlags & VARIANT_LOCALBOOL)
-			  res = VarBstrFromBool(V_BOOL(ps), lcid, VAR_LOCALBOOL, &V_BSTR(pd));
-			else
-			  res = VarBstrFromI2(V_BOOL(ps), lcid, dwFlags, &V_BSTR(pd));
-			break;
-		case( VT_BSTR ):
-			res = VariantCopy( pd, ps );
-			break;
-		case( VT_CY ):
-			res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
-			break;
-		case( VT_DISPATCH ):
-			/*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
-		case( VT_DECIMAL ):
-			/*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
-		case( VT_UNKNOWN ):
-		default:
-			res = DISP_E_TYPEMISMATCH;
-			FIXME("Coercion from %d to VT_BSTR\n", vtFrom);
-			break;
-		}
-		break;
-
-     case( VT_CY ):
-	switch( vtFrom )
-	  {
-	  case( VT_I1 ):
-	     res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_I2 ):
-	     res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_INT ):
-	     res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_I4 ):
-	     res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_UI1 ):
-	     res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_UI2 ):
-	     res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_UINT ):
-	     res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_UI4 ):
-	     res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_R4 ):
-	     res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_R8 ):
-	     res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_DATE ):
-	     res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_BOOL ):
-	     res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_CY ):
-	     res = VariantCopy( pd, ps );
-	     break;
-	  case( VT_BSTR ):
-	     res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
-	     break;
-	  case( VT_DISPATCH ):
-	     /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
-	  case( VT_DECIMAL ):
-	     /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
-	     break;
-	  case( VT_UNKNOWN ):
-	  default:
-	     res = DISP_E_TYPEMISMATCH;
-	     FIXME("Coercion from %d to VT_CY\n", vtFrom);
-	     break;
-	  }
-	break;
-
-	case( VT_UNKNOWN ):
-	    switch (vtFrom) {
-	    case VT_DISPATCH:
-		if (V_DISPATCH(ps) == NULL) {
-			V_UNKNOWN(pd) = NULL;
-		} else {
-			res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
-		}
-		break;
-	    case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
-	    case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
-	    case VT_BSTR: case VT_ERROR: case VT_BOOL:
-	    case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
-	    case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
-	    case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
-	    case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
-	    case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
-	    case VT_BLOB: case VT_STREAM: case VT_STORAGE:
-	    case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
-	    case VT_CF: case VT_CLSID:
-		res = DISP_E_TYPEMISMATCH;
-		break;
-	    default:
-		FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom);
-		res = DISP_E_BADVARTYPE;
-		break;
-	    }
-	    break;
+  case VT_I4:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_I4(pd) = 0; return S_OK;
+    case VT_I1:       return VarI4FromI1(V_I1(ps), &V_I4(pd));
+    case VT_I2:       return VarI4FromI2(V_I2(ps), &V_I4(pd));
+    case VT_UI1:      return VarI4FromUI1(V_UI1(ps), &V_I4(pd));
+    case VT_UI2:      return VarI4FromUI2(V_UI2(ps), &V_I4(pd));
+    case VT_UI4:      return VarI4FromUI4(V_UI4(ps), &V_I4(pd));
+    case VT_I8:       return VarI4FromI8(V_I8(ps), &V_I4(pd));
+    case VT_UI8:      return VarI4FromUI8(V_UI8(ps), &V_I4(pd));
+    case VT_R4:       return VarI4FromR4(V_R4(ps), &V_I4(pd));
+    case VT_R8:       return VarI4FromR8(V_R8(ps), &V_I4(pd));
+    case VT_DATE:     return VarI4FromDate(V_DATE(ps), &V_I4(pd));
+    case VT_BOOL:     return VarI4FromBool(V_BOOL(ps), &V_I4(pd));
+    case VT_CY:       return VarI4FromCy(V_CY(ps), &V_I4(pd));
+    case VT_DECIMAL:  return VarI4FromDec(&V_DECIMAL(ps), &V_I4(pd));
+    case VT_DISPATCH: return VarI4FromDisp(V_DISPATCH(ps), lcid, &V_I4(pd));
+    case VT_BSTR:     return VarI4FromStr(V_BSTR(ps), lcid, dwFlags, &V_I4(pd));
+    }
+    break;
 
-	case( VT_DISPATCH ):
-	    switch (vtFrom) {
-	    case VT_UNKNOWN:
-		if (V_UNION(ps,punkVal) == NULL) {
-			V_UNION(pd,pdispVal) = NULL;
-		} else {
-			res = IUnknown_QueryInterface(V_UNION(ps,punkVal), &IID_IDispatch, (LPVOID*)&V_UNION(pd,pdispVal));
-		}
-		break;
-	    case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
-	    case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
-	    case VT_BSTR: case VT_ERROR: case VT_BOOL:
-	    case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
-	    case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
-           case VT_UINT: case VT_VOID: case VT_HRESULT:
-	    case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
-	    case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
-	    case VT_BLOB: case VT_STREAM: case VT_STORAGE:
-	    case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
-	    case VT_CF: case VT_CLSID:
-		res = DISP_E_TYPEMISMATCH;
-		break;
-           case VT_PTR:
-               V_UNION(pd,pdispVal) = V_UNION(ps,pdispVal);
-               break;
-	    default:
-		FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom);
-		res = DISP_E_BADVARTYPE;
-		break;
-	    }
-	    break;
+  case VT_UI1:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_UI1(pd) = 0; return S_OK;
+    case VT_I1:       return VarUI1FromI1(V_I1(ps), &V_UI1(pd));
+    case VT_I2:       return VarUI1FromI2(V_I2(ps), &V_UI1(pd));
+    case VT_I4:       return VarUI1FromI4(V_I4(ps), &V_UI1(pd));
+    case VT_UI2:      return VarUI1FromUI2(V_UI2(ps), &V_UI1(pd));
+    case VT_UI4:      return VarUI1FromUI4(V_UI4(ps), &V_UI1(pd));
+    case VT_I8:       return VarUI1FromI8(V_I8(ps), &V_UI1(pd));
+    case VT_UI8:      return VarUI1FromUI8(V_UI8(ps), &V_UI1(pd));
+    case VT_R4:       return VarUI1FromR4(V_R4(ps), &V_UI1(pd));
+    case VT_R8:       return VarUI1FromR8(V_R8(ps), &V_UI1(pd));
+    case VT_DATE:     return VarUI1FromDate(V_DATE(ps), &V_UI1(pd));
+    case VT_BOOL:     return VarUI1FromBool(V_BOOL(ps), &V_UI1(pd));
+    case VT_CY:       return VarUI1FromCy(V_CY(ps), &V_UI1(pd));
+    case VT_DECIMAL:  return VarUI1FromDec(&V_DECIMAL(ps), &V_UI1(pd));
+    case VT_DISPATCH: return VarUI1FromDisp(V_DISPATCH(ps), lcid, &V_UI1(pd));
+    case VT_BSTR:     return VarUI1FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI1(pd));
+    }
+    break;
 
-	default:
-		res = DISP_E_TYPEMISMATCH;
-		FIXME("Coercion from %d to %d\n", vtFrom, vt );
-		break;
-	}
+  case VT_UI2:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_UI2(pd) = 0; return S_OK;
+    case VT_I1:       return VarUI2FromI1(V_I1(ps), &V_UI2(pd));
+    case VT_I2:       return VarUI2FromI2(V_I2(ps), &V_UI2(pd));
+    case VT_I4:       return VarUI2FromI4(V_I4(ps), &V_UI2(pd));
+    case VT_UI1:      return VarUI2FromUI1(V_UI1(ps), &V_UI2(pd));
+    case VT_UI4:      return VarUI2FromUI4(V_UI4(ps), &V_UI2(pd));
+    case VT_I8:       return VarUI4FromI8(V_I8(ps), &V_UI4(pd));
+    case VT_UI8:      return VarUI4FromUI8(V_UI8(ps), &V_UI4(pd));
+    case VT_R4:       return VarUI2FromR4(V_R4(ps), &V_UI2(pd));
+    case VT_R8:       return VarUI2FromR8(V_R8(ps), &V_UI2(pd));
+    case VT_DATE:     return VarUI2FromDate(V_DATE(ps), &V_UI2(pd));
+    case VT_BOOL:     return VarUI2FromBool(V_BOOL(ps), &V_UI2(pd));
+    case VT_CY:       return VarUI2FromCy(V_CY(ps), &V_UI2(pd));
+    case VT_DECIMAL:  return VarUI2FromDec(&V_DECIMAL(ps), &V_UI2(pd));
+    case VT_DISPATCH: return VarUI2FromDisp(V_DISPATCH(ps), lcid, &V_UI2(pd));
+    case VT_BSTR:     return VarUI2FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI2(pd));
+    }
+    break;
 
-	return res;
-}
+  case VT_UI4:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_UI4(pd) = 0; return S_OK;
+    case VT_I1:       return VarUI4FromI1(V_I1(ps), &V_UI4(pd));
+    case VT_I2:       return VarUI4FromI2(V_I2(ps), &V_UI4(pd));
+    case VT_I4:       return VarUI4FromI4(V_I4(ps), &V_UI4(pd));
+    case VT_UI1:      return VarUI4FromUI1(V_UI1(ps), &V_UI4(pd));
+    case VT_UI2:      return VarUI4FromUI2(V_UI2(ps), &V_UI4(pd));
+    case VT_I8:       return VarUI4FromI8(V_I8(ps), &V_UI4(pd));
+    case VT_UI8:      return VarUI4FromUI8(V_UI8(ps), &V_UI4(pd));
+    case VT_R4:       return VarUI4FromR4(V_R4(ps), &V_UI4(pd));
+    case VT_R8:       return VarUI4FromR8(V_R8(ps), &V_UI4(pd));
+    case VT_DATE:     return VarUI4FromDate(V_DATE(ps), &V_UI4(pd));
+    case VT_BOOL:     return VarUI4FromBool(V_BOOL(ps), &V_UI4(pd));
+    case VT_CY:       return VarUI4FromCy(V_CY(ps), &V_UI4(pd));
+    case VT_DECIMAL:  return VarUI4FromDec(&V_DECIMAL(ps), &V_UI4(pd));
+    case VT_DISPATCH: return VarUI4FromDisp(V_DISPATCH(ps), lcid, &V_UI4(pd));
+    case VT_BSTR:     return VarUI4FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI4(pd));
+    }
+    break;
 
-/******************************************************************************
- *		ValidateVtRange	[INTERNAL]
- *
- * Used internally by the hi-level Variant API to determine
- * if the vartypes are valid.
- */
-static HRESULT ValidateVtRange( VARTYPE vt )
-{
-    /* if by value we must make sure it is in the
-     * range of the valid types.
-     */
-    if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
+  case VT_UI8:
+    switch (vtFrom)
     {
-        return DISP_E_BADVARTYPE;
+    case VT_EMPTY:    V_UI8(pd) = 0; return S_OK;
+    case VT_I4:       if (V_I4(ps) < 0) return DISP_E_OVERFLOW; V_UI8(pd) = V_I4(ps); return S_OK;
+    case VT_I1:       return VarUI8FromI1(V_I1(ps), &V_UI8(pd));
+    case VT_I2:       return VarUI8FromI2(V_I2(ps), &V_UI8(pd));
+    case VT_UI1:      return VarUI8FromUI1(V_UI1(ps), &V_UI8(pd));
+    case VT_UI2:      return VarUI8FromUI2(V_UI2(ps), &V_UI8(pd));
+    case VT_UI4:      return VarUI8FromUI4(V_UI4(ps), &V_UI8(pd));
+    case VT_I8:       return VarUI8FromI8(V_I8(ps), &V_UI8(pd));
+    case VT_R4:       return VarUI8FromR4(V_R4(ps), &V_UI8(pd));
+    case VT_R8:       return VarUI8FromR8(V_R8(ps), &V_UI8(pd));
+    case VT_DATE:     return VarUI8FromDate(V_DATE(ps), &V_UI8(pd));
+    case VT_BOOL:     return VarUI8FromBool(V_BOOL(ps), &V_UI8(pd));
+    case VT_CY:       return VarUI8FromCy(V_CY(ps), &V_UI8(pd));
+    case VT_DECIMAL:  return VarUI8FromDec(&V_DECIMAL(ps), &V_UI8(pd));
+    case VT_DISPATCH: return VarUI8FromDisp(V_DISPATCH(ps), lcid, &V_UI8(pd));
+    case VT_BSTR:     return VarUI8FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI8(pd));
     }
-    return S_OK;
-}
+    break;
 
-/* Copy data from one variant to another. */
-static void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
-{
-  switch(vt)
-  {
-  case VT_I1:
-  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_R4:
-  case VT_I4:
-  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_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
-  default:
-    FIXME("VT_ type %d unhandled, please report!\n", vt);
-  }
-}
-
-/* Coerce VT_DISPATCH to another type */
-HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
-{
-  VARIANTARG srcVar, dstVar;
-  HRESULT hRet;
-
-  V_VT(&srcVar) = VT_DISPATCH;
-  V_DISPATCH(&srcVar) = pdispIn;
-
-  hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt);
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_I8(pd) = 0; return S_OK;
+    case VT_I4:       V_I8(pd) = V_I4(ps); return S_OK;
+    case VT_I1:       return VarI8FromI1(V_I1(ps), &V_I8(pd));
+    case VT_I2:       return VarI8FromI2(V_I2(ps), &V_I8(pd));
+    case VT_UI1:      return VarI8FromUI1(V_UI1(ps), &V_I8(pd));
+    case VT_UI2:      return VarI8FromUI2(V_UI2(ps), &V_I8(pd));
+    case VT_UI4:      return VarI8FromUI4(V_UI4(ps), &V_I8(pd));
+    case VT_UI8:      return VarI8FromUI8(V_I8(ps), &V_I8(pd));
+    case VT_R4:       return VarI8FromR4(V_R4(ps), &V_I8(pd));
+    case VT_R8:       return VarI8FromR8(V_R8(ps), &V_I8(pd));
+    case VT_DATE:     return VarI8FromDate(V_DATE(ps), &V_I8(pd));
+    case VT_BOOL:     return VarI8FromBool(V_BOOL(ps), &V_I8(pd));
+    case VT_CY:       return VarI8FromCy(V_CY(ps), &V_I8(pd));
+    case VT_DECIMAL:  return VarI8FromDec(&V_DECIMAL(ps), &V_I8(pd));
+    case VT_DISPATCH: return VarI8FromDisp(V_DISPATCH(ps), lcid, &V_I8(pd));
+    case VT_BSTR:     return VarI8FromStr(V_BSTR(ps), lcid, dwFlags, &V_I8(pd));
+    }
+    break;
 
-  if (SUCCEEDED(hRet))
-    VARIANT_CopyData(&dstVar, vt, pOut);
-  return hRet;
-}
+  case VT_R4:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_R4(pd) = 0.0f; return S_OK;
+    case VT_I1:       return VarR4FromI1(V_I1(ps), &V_R4(pd));
+    case VT_I2:       return VarR4FromI2(V_I2(ps), &V_R4(pd));
+    case VT_I4:       return VarR4FromI4(V_I4(ps), &V_R4(pd));
+    case VT_UI1:      return VarR4FromUI1(V_UI1(ps), &V_R4(pd));
+    case VT_UI2:      return VarR4FromUI2(V_UI2(ps), &V_R4(pd));
+    case VT_UI4:      return VarR4FromUI4(V_UI4(ps), &V_R4(pd));
+    case VT_I8:       return VarR4FromI8(V_I8(ps), &V_R4(pd));
+    case VT_UI8:      return VarR4FromUI8(V_UI8(ps), &V_R4(pd));
+    case VT_R8:       return VarR4FromR8(V_R8(ps), &V_R4(pd));
+    case VT_DATE:     return VarR4FromDate(V_DATE(ps), &V_R4(pd));
+    case VT_BOOL:     return VarR4FromBool(V_BOOL(ps), &V_R4(pd));
+    case VT_CY:       return VarR4FromCy(V_CY(ps), &V_R4(pd));
+    case VT_DECIMAL:  return VarR4FromDec(&V_DECIMAL(ps), &V_R4(pd));
+    case VT_DISPATCH: return VarR4FromDisp(V_DISPATCH(ps), lcid, &V_R4(pd));
+    case VT_BSTR:     return VarR4FromStr(V_BSTR(ps), lcid, dwFlags, &V_R4(pd));
+    }
+    break;
 
-/* Coerce VT_BSTR to a numeric type */
-HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
-                               void* pOut, VARTYPE vt)
-{
-  VARIANTARG dstVar;
-  HRESULT hRet;
-  NUMPARSE np;
-  BYTE rgb[1024];
+  case VT_R8:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_R8(pd) = 0.0; return S_OK;
+    case VT_I1:       return VarR8FromI1(V_I1(ps), &V_R8(pd));
+    case VT_I2:       return VarR8FromI2(V_I2(ps), &V_R8(pd));
+    case VT_I4:       return VarR8FromI4(V_I4(ps), &V_R8(pd));
+    case VT_UI1:      return VarR8FromUI1(V_UI1(ps), &V_R8(pd));
+    case VT_UI2:      return VarR8FromUI2(V_UI2(ps), &V_R8(pd));
+    case VT_UI4:      return VarR8FromUI4(V_UI4(ps), &V_R8(pd));
+    case VT_I8:       return VarR8FromI8(V_I8(ps), &V_R8(pd));
+    case VT_UI8:      return VarR8FromUI8(V_UI8(ps), &V_R8(pd));
+    case VT_R4:       return VarR8FromR4(V_R4(ps), &V_R8(pd));
+    case VT_DATE:     return VarR8FromDate(V_DATE(ps), &V_R8(pd));
+    case VT_BOOL:     return VarR8FromBool(V_BOOL(ps), &V_R8(pd));
+    case VT_CY:       return VarR8FromCy(V_CY(ps), &V_R8(pd));
+    case VT_DECIMAL:  return VarR8FromDec(&V_DECIMAL(ps), &V_R8(pd));
+    case VT_DISPATCH: return VarR8FromDisp(V_DISPATCH(ps), lcid, &V_R8(pd));
+    case VT_BSTR:     return VarR8FromStr(V_BSTR(ps), lcid, dwFlags, &V_R8(pd));
+    }
+    break;
 
-  /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
-  np.cDig = sizeof(rgb) / sizeof(BYTE);
-  np.dwInFlags = NUMPRS_STD;
+  case VT_DATE:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_DATE(pd) = 0.0; return S_OK;
+    case VT_I1:       return VarDateFromI1(V_I1(ps), &V_DATE(pd));
+    case VT_I2:       return VarDateFromI2(V_I2(ps), &V_DATE(pd));
+    case VT_I4:       return VarDateFromI4(V_I4(ps), &V_DATE(pd));
+    case VT_UI1:      return VarDateFromUI1(V_UI1(ps), &V_DATE(pd));
+    case VT_UI2:      return VarDateFromUI2(V_UI2(ps), &V_DATE(pd));
+    case VT_UI4:      return VarDateFromUI4(V_UI4(ps), &V_DATE(pd));
+    case VT_I8:       return VarDateFromI8(V_I8(ps), &V_DATE(pd));
+    case VT_UI8:      return VarDateFromUI8(V_UI8(ps), &V_DATE(pd));
+    case VT_R4:       return VarDateFromR4(V_R4(ps), &V_DATE(pd));
+    case VT_R8:       return VarDateFromR8(V_R8(ps), &V_DATE(pd));
+    case VT_BOOL:     return VarDateFromBool(V_BOOL(ps), &V_DATE(pd));
+    case VT_CY:       return VarDateFromCy(V_CY(ps), &V_DATE(pd));
+    case VT_DECIMAL:  return VarDateFromDec(&V_DECIMAL(ps), &V_DATE(pd));
+    case VT_DISPATCH: return VarDateFromDisp(V_DISPATCH(ps), lcid, &V_DATE(pd));
+    case VT_BSTR:     return VarDateFromStr(V_BSTR(ps), lcid, dwFlags, &V_DATE(pd));
+    }
+    break;
 
-  hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
+  case VT_BOOL:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_BOOL(pd) = 0; return S_OK;
+    case VT_I1:       return VarBoolFromI1(V_I1(ps), &V_BOOL(pd));
+    case VT_I2:       return VarBoolFromI2(V_I2(ps), &V_BOOL(pd));
+    case VT_I4:       return VarBoolFromI4(V_I4(ps), &V_BOOL(pd));
+    case VT_UI1:      return VarBoolFromUI1(V_UI1(ps), &V_BOOL(pd));
+    case VT_UI2:      return VarBoolFromUI2(V_UI2(ps), &V_BOOL(pd));
+    case VT_UI4:      return VarBoolFromUI4(V_UI4(ps), &V_BOOL(pd));
+    case VT_I8:       return VarBoolFromI8(V_I8(ps), &V_BOOL(pd));
+    case VT_UI8:      return VarBoolFromUI8(V_UI8(ps), &V_BOOL(pd));
+    case VT_R4:       return VarBoolFromR4(V_R4(ps), &V_BOOL(pd));
+    case VT_R8:       return VarBoolFromR8(V_R8(ps), &V_BOOL(pd));
+    case VT_DATE:     return VarBoolFromDate(V_DATE(ps), &V_BOOL(pd));
+    case VT_CY:       return VarBoolFromCy(V_CY(ps), &V_BOOL(pd));
+    case VT_DECIMAL:  return VarBoolFromDec(&V_DECIMAL(ps), &V_BOOL(pd));
+    case VT_DISPATCH: return VarBoolFromDisp(V_DISPATCH(ps), lcid, &V_BOOL(pd));
+    case VT_BSTR:     return VarBoolFromStr(V_BSTR(ps), lcid, dwFlags, &V_BOOL(pd));
+    }
+    break;
 
-  if (SUCCEEDED(hRet))
-  {
-    /* 1 << vt gives us the VTBIT constant for the destination number type */
-    hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
-    if (SUCCEEDED(hRet))
-      VARIANT_CopyData(&dstVar, vt, pOut);
-  }
-  return hRet;
-}
+  case VT_BSTR:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:
+      V_BSTR(pd) = SysAllocStringLen(NULL, 0);
+      return V_BSTR(pd) ? S_OK : E_OUTOFMEMORY;
+    case VT_BOOL:
+      if (wFlags & (VARIANT_ALPHABOOL|VARIANT_LOCALBOOL))
+         return VarBstrFromBool(V_BOOL(ps), lcid, dwFlags, &V_BSTR(pd));
+      return VarBstrFromI2(V_BOOL(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_I1:       return VarBstrFromI1(V_I1(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_I2:       return VarBstrFromI2(V_I2(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_I4:       return VarBstrFromI4(V_I4(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_UI1:      return VarBstrFromUI1(V_UI1(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_UI2:      return VarBstrFromUI2(V_UI2(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_UI4:      return VarBstrFromUI4(V_UI4(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_I8:       return VarBstrFromI8(V_I8(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_UI8:      return VarBstrFromUI8(V_UI8(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_R4:       return VarBstrFromR4(V_R4(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_R8:       return VarBstrFromR8(V_R8(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_DATE:     return VarBstrFromDate(V_DATE(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_CY:       return VarBstrFromCy(V_CY(ps), lcid, dwFlags, &V_BSTR(pd));
+    case VT_DECIMAL:  return VarBstrFromDec(&V_DECIMAL(ps), lcid, dwFlags, &V_BSTR(pd));
+/*  case VT_DISPATCH: return VarBstrFromDisp(V_DISPATCH(ps), lcid, dwFlags, &V_BSTR(pd)); */
+    }
+    break;
 
-/******************************************************************************
- *		ValidateVartype	[INTERNAL]
- *
- * Used internally by the hi-level Variant API to determine
- * if the vartypes are valid.
- */
-static HRESULT ValidateVariantType( VARTYPE vt )
-{
-	HRESULT res = S_OK;
+  case VT_CY:
+    switch (vtFrom)
+    {
+    case VT_EMPTY:    V_CY(pd).int64 = 0; return S_OK;
+    case VT_I1:       return VarCyFromI1(V_I1(ps), &V_CY(pd));
+    case VT_I2:       return VarCyFromI2(V_I2(ps), &V_CY(pd));
+    case VT_I4:       return VarCyFromI4(V_I4(ps), &V_CY(pd));
+    case VT_UI1:      return VarCyFromUI1(V_UI1(ps), &V_CY(pd));
+    case VT_UI2:      return VarCyFromUI2(V_UI2(ps), &V_CY(pd));
+    case VT_UI4:      return VarCyFromUI4(V_UI4(ps), &V_CY(pd));
+    case VT_I8:       return VarCyFromI8(V_I8(ps), &V_CY(pd));
+    case VT_UI8:      return VarCyFromUI8(V_UI8(ps), &V_CY(pd));
+    case VT_R4:       return VarCyFromR4(V_R4(ps), &V_CY(pd));
+    case VT_R8:       return VarCyFromR8(V_R8(ps), &V_CY(pd));
+    case VT_DATE:     return VarCyFromDate(V_DATE(ps), &V_CY(pd));
+    case VT_BOOL:     return VarCyFromBool(V_BOOL(ps), &V_CY(pd));
+    case VT_DECIMAL:  return VarCyFromDec(&V_DECIMAL(ps), &V_CY(pd));
+    case VT_DISPATCH: return VarCyFromDisp(V_DISPATCH(ps), lcid, &V_CY(pd));
+    case VT_BSTR:     return VarCyFromStr(V_BSTR(ps), lcid, dwFlags, &V_CY(pd));
+    }
+    break;
 
-	/* check if we have a valid argument.
-	 */
-	if( vt & VT_BYREF )
+  case VT_DECIMAL:
+    switch (vtFrom)
     {
-        /* if by reference check that the type is in
-         * the valid range and that it is not of empty or null type
+    case VT_EMPTY:
+    case VT_BOOL:
+       DEC_SIGNSCALE(&V_DECIMAL(pd)) = SIGNSCALE(DECIMAL_POS,0);
+       DEC_HI32(&V_DECIMAL(pd)) = 0;
+       DEC_MID32(&V_DECIMAL(pd)) = 0;
+        /* VarDecFromBool() coerces to -1/0, ChangeTypeEx() coerces to 1/0.
+         * VT_NULL and VT_EMPTY always give a 0 value.
          */
-        if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
-            ( vt & VT_TYPEMASK ) == VT_NULL ||
-			( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
-		{
-			res = DISP_E_BADVARTYPE;
-		}
-
+       DEC_LO32(&V_DECIMAL(pd)) = vtFrom == VT_BOOL && V_BOOL(ps) ? 1 : 0;
+       return S_OK;
+    case VT_I1:       return VarDecFromI1(V_I1(ps), &V_DECIMAL(pd));
+    case VT_I2:       return VarDecFromI2(V_I2(ps), &V_DECIMAL(pd));
+    case VT_I4:       return VarDecFromI4(V_I4(ps), &V_DECIMAL(pd));
+    case VT_UI1:      return VarDecFromUI1(V_UI1(ps), &V_DECIMAL(pd));
+    case VT_UI2:      return VarDecFromUI2(V_UI2(ps), &V_DECIMAL(pd));
+    case VT_UI4:      return VarDecFromUI4(V_UI4(ps), &V_DECIMAL(pd));
+    case VT_I8:       return VarDecFromI8(V_I8(ps), &V_DECIMAL(pd));
+    case VT_UI8:      return VarDecFromUI8(V_UI8(ps), &V_DECIMAL(pd));
+    case VT_R4:       return VarDecFromR4(V_R4(ps), &V_DECIMAL(pd));
+    case VT_R8:       return VarDecFromR8(V_R8(ps), &V_DECIMAL(pd));
+    case VT_DATE:     return VarDecFromDate(V_DATE(ps), &V_DECIMAL(pd));
+    case VT_CY:       return VarDecFromCy(V_CY(pd), &V_DECIMAL(ps));
+    case VT_DISPATCH: return VarDecFromDisp(V_DISPATCH(ps), lcid, &V_DECIMAL(ps));
+    case VT_BSTR:     return VarDecFromStr(V_BSTR(ps), lcid, dwFlags, &V_DECIMAL(pd));
     }
-    else
+    break;
+
+  case VT_UNKNOWN:
+    switch (vtFrom)
     {
-        res = ValidateVtRange( vt );
+    case VT_DISPATCH:
+      if (V_DISPATCH(ps) == NULL)
+        V_UNKNOWN(pd) = NULL;
+      else
+        res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
+      break;
     }
+    break;
 
-	return res;
-}
-
-/******************************************************************************
- *		ValidateVt	[INTERNAL]
- *
- * Used internally by the hi-level Variant API to determine
- * if the vartypes are valid.
- */
-static HRESULT ValidateVt( VARTYPE vt )
-{
-	HRESULT res = S_OK;
-
-	/* check if we have a valid argument.
-	 */
-	if( vt & VT_BYREF )
+  case VT_DISPATCH:
+    switch (vtFrom)
     {
-        /* if by reference check that the type is in
-         * the valid range and that it is not of empty or null type
-         */
-        if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
-            ( vt & VT_TYPEMASK ) == VT_NULL ||
-			( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
-		{
-			res = DISP_E_BADVARTYPE;
-		}
-
+    case VT_UNKNOWN:
+      if (V_UNKNOWN(ps) == NULL)
+        V_DISPATCH(pd) = NULL;
+      else
+        res = IUnknown_QueryInterface(V_UNKNOWN(ps), &IID_IDispatch, (LPVOID*)&V_DISPATCH(pd));
+      break;
     }
-    else
+    break;
+
+  case VT_RECORD:
+    switch (vtFrom)
     {
-        res = ValidateVtRange( vt );
+    case VT_EMPTY:
+        V_UNION(pd,brecVal).pvRecord = NULL;
+        V_UNION(pd,brecVal).pRecInfo = NULL;
+        return S_OK;
     }
+    break;
 
-	return res;
+  }
+  return res;
 }
 
 /******************************************************************************
@@ -1530,16 +943,16 @@
 }
 
 /******************************************************************************
- *		VariantChangeType	[OLEAUT32.12]
+ *    VariantChangeType  [OLEAUT32.12]
  *
  * Change the type of a variant.
- *  
+ *
  * PARAMS
  *  pvargDest [O] Destination for the converted variant
  *  pvargSrc  [O] Source variant to change the type of
  *  wFlags    [I] VARIANT_ flags from "oleauto.h"
  *  vt        [I] Variant type to change pvargSrc into
- *    
+ *
  * RETURNS
  *  Success: S_OK. pvargDest contains the converted value.
  *  Failure: An HRESULT error code describing the failure.
@@ -1549,23 +962,23 @@
  *  See VariantChangeTypeEx.
  */
 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
-							USHORT wFlags, VARTYPE vt)
+                                 USHORT wFlags, VARTYPE vt)
 {
-	return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
+  return VariantChangeTypeEx( pvargDest, pvargSrc, LOCALE_USER_DEFAULT, wFlags, vt );
 }
 
 /******************************************************************************
- *		VariantChangeTypeEx	[OLEAUT32.147]
+ *    VariantChangeTypeEx  [OLEAUT32.147]
  *
  * Change the type of a variant.
- *  
+ *
  * PARAMS
  *  pvargDest [O] Destination for the converted variant
  *  pvargSrc  [O] Source variant to change the type of
  *  lcid      [I] LCID for the conversion
  *  wFlags    [I] VARIANT_ flags from "oleauto.h"
  *  vt        [I] Variant type to change pvargSrc into
- *  
+ *
  * RETURNS
  *  Success: S_OK. pvargDest contains the converted value.
  *  Failure: An HRESULT error code describing the failure.
@@ -1575,2663 +988,100 @@
  *  conversion. If the conversion is successful, pvargSrc will be freed.
  */
 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
-							  LCID lcid, USHORT wFlags, VARTYPE vt)
-{
-	HRESULT res = S_OK;
-	VARIANTARG varg;
-	VariantInit( &varg );
-
-	TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
-    TRACE("Src Var:\n");
-    dump_Variant(pvargSrc);
-
-	/* validate our source argument.
-	 */
-	res = ValidateVariantType( V_VT(pvargSrc) );
-
-	/* validate the vartype.
-	 */
-	if( res == S_OK )
-	{
-		res = ValidateVt( vt );
-	}
-
-	/* if we are doing an in-place conversion make a copy of the source.
-	 */
-	if( res == S_OK && pvargDest == pvargSrc )
-	{
-		res = VariantCopy( &varg, pvargSrc );
-		pvargSrc = &varg;
-	}
-
-	if( res == S_OK )
-	{
-		/* free up the destination variant.
-		 */
-		res = VariantClear( pvargDest );
-	}
-
-	if( res == S_OK )
-	{
-		if( V_VT(pvargSrc) & VT_BYREF )
-		{
-			/* Convert the source variant to a "byvalue" variant.
-			 */
-			VARIANTARG Variant;
-
-			if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
-				FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc) & VT_TYPEMASK);
-				return E_FAIL;
-			}
-
-			VariantInit( &Variant );
-			res = VariantCopyInd( &Variant, pvargSrc );
-			if( res == S_OK )
-			{
-				res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
-				/* this should not fail.
-				 */
-				VariantClear( &Variant );
-			}
-		} else {
-			if (V_VT(pvargSrc) & VT_ARRAY) {
-				if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY) {
-					FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc) & VT_TYPEMASK);
-					return E_FAIL;
-				}
-				V_VT(pvargDest) = VT_ARRAY | vt;
-				res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt);
-			} else {
-				if ((V_VT(pvargSrc) & 0xf000)) {
-					FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc) & VT_TYPEMASK);
-					return E_FAIL;
-				}
-				/* Use the current "byvalue" source variant.
-				 */
-				res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
-			}
-		}
-	}
-	/* this should not fail.
-	 */
-	VariantClear( &varg );
-
-	/* set the type of the destination
-	 */
-	if ( res == S_OK )
-		V_VT(pvargDest) = vt;
-
-    TRACE("Dest Var:\n");
-    dump_Variant(pvargDest);
-
-	return res;
-}
-
-
-
-
-/******************************************************************************
- *		VarUI1FromI2		[OLEAUT32.130]
- */
-HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
-{
-	TRACE("( %d, %p ), stub\n", sIn, pbOut );
-
-	/* Check range of value.
-	 */
-	if( sIn < UI1_MIN || sIn > UI1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pbOut = (BYTE) sIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI1FromI4		[OLEAUT32.131]
- */
-HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
-{
-	TRACE("( %ld, %p ), stub\n", lIn, pbOut );
-
-	/* Check range of value.
-	 */
-	if( lIn < UI1_MIN || lIn > UI1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pbOut = (BYTE) lIn;
-
-	return S_OK;
-}
-
-
-/******************************************************************************
- *		VarUI1FromR4		[OLEAUT32.132]
- */
-HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
-{
-	TRACE("( %f, %p ), stub\n", fltIn, pbOut );
-
-	/* Check range of value.
-     */
-    fltIn = round( fltIn );
-	if( fltIn < UI1_MIN || fltIn > UI1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pbOut = (BYTE) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI1FromR8		[OLEAUT32.133]
- */
-HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, pbOut );
-
-	/* Check range of value.
-     */
-    dblIn = round( dblIn );
-	if( dblIn < UI1_MIN || dblIn > UI1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pbOut = (BYTE) dblIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI1FromDate		[OLEAUT32.135]
- */
-HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, pbOut );
-
-	/* Check range of value.
-     */
-    dateIn = round( dateIn );
-	if( dateIn < UI1_MIN || dateIn > UI1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pbOut = (BYTE) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI1FromBool		[OLEAUT32.138]
- */
-HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, pbOut );
-
-	*pbOut = (BYTE) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI1FromI1		[OLEAUT32.237]
- */
-HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, pbOut );
-
-	*pbOut = cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI1FromUI2		[OLEAUT32.238]
- */
-HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pbOut );
-
-	/* Check range of value.
-	 */
-	if( uiIn > UI1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pbOut = (BYTE) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI1FromUI4		[OLEAUT32.239]
- */
-HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
-{
-	TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
-
-	/* Check range of value.
-	 */
-	if( ulIn > UI1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pbOut = (BYTE) ulIn;
-
-	return S_OK;
-}
-
-
-/******************************************************************************
- *		VarUI1FromStr		[OLEAUT32.136]
- */
-HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pbOut);
-  return _VarUI1FromStr(strIn, lcid, dwFlags, pbOut);
-}
-
-/**********************************************************************
- *              VarUI1FromCy [OLEAUT32.134]
- * Convert currency to unsigned char
- */
-HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
-   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
-
-   *pbOut = (BYTE)t;
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromUI1		[OLEAUT32.48]
- */
-HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
-{
-	TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
-
-	*psOut = (short) bIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromI4		[OLEAUT32.49]
- */
-HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
-{
-	TRACE("( %lx, %p ), stub\n", lIn, psOut );
-
-	/* Check range of value.
-	 */
-	if( lIn < I2_MIN || lIn > I2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*psOut = (short) lIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromR4		[OLEAUT32.50]
- */
-HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
-{
-	TRACE("( %f, %p ), stub\n", fltIn, psOut );
-
-	/* Check range of value.
-     */
-    fltIn = round( fltIn );
-	if( fltIn < I2_MIN || fltIn > I2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*psOut = (short) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromR8		[OLEAUT32.51]
- */
-HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, psOut );
-
-	/* Check range of value.
-     */
-    dblIn = round( dblIn );
-	if( dblIn < I2_MIN || dblIn > I2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*psOut = (short) dblIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromDate		[OLEAUT32.53]
- */
-HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, psOut );
-
-	/* Check range of value.
-     */
-    dateIn = round( dateIn );
-	if( dateIn < I2_MIN || dateIn > I2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*psOut = (short) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromBool		[OLEAUT32.56]
- */
-HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, psOut );
-
-	*psOut = (short) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromI1		[OLEAUT32.205]
- */
-HRESULT WINAPI VarI2FromI1(signed char cIn, short* psOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, psOut );
-
-	*psOut = (short) cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromUI2		[OLEAUT32.206]
- */
-HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, psOut );
-
-	/* Check range of value.
-	 */
-	if( uiIn > I2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*psOut = (short) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromUI4		[OLEAUT32.207]
- */
-HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
-{
-	TRACE("( %lx, %p ), stub\n", ulIn, psOut );
-
-	/* Check range of value.
-	 */
-	if( ulIn < I2_MIN || ulIn > I2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*psOut = (short) ulIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI2FromStr		[OLEAUT32.54]
- */
-HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, psOut);
-  return _VarI2FromStr(strIn, lcid, dwFlags, psOut);
-}
-
-/**********************************************************************
- *              VarI2FromCy [OLEAUT32.52]
- * Convert currency to signed short
- */
-HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
-   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
-
-   *psOut = (SHORT)t;
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromUI1		[OLEAUT32.58]
- */
-HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
-{
-	TRACE("( %X, %p ), stub\n", bIn, plOut );
-
-	*plOut = (LONG) bIn;
-
-	return S_OK;
-}
-
-
-/******************************************************************************
- *		VarI4FromR4		[OLEAUT32.60]
- */
-HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
-{
-	TRACE("( %f, %p ), stub\n", fltIn, plOut );
-
-	/* Check range of value.
-     */
-    fltIn = round( fltIn );
-	if( fltIn < I4_MIN || fltIn > I4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*plOut = (LONG) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromR8		[OLEAUT32.61]
- */
-HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, plOut );
-
-	/* Check range of value.
-     */
-    dblIn = round( dblIn );
-	if( dblIn < I4_MIN || dblIn > I4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*plOut = (LONG) dblIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromDate		[OLEAUT32.63]
- */
-HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, plOut );
-
-	/* Check range of value.
-     */
-    dateIn = round( dateIn );
-	if( dateIn < I4_MIN || dateIn > I4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*plOut = (LONG) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromBool		[OLEAUT32.66]
- */
-HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, plOut );
-
-	*plOut = (LONG) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromI1		[OLEAUT32.209]
- */
-HRESULT WINAPI VarI4FromI1(signed char cIn, LONG* plOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, plOut );
-
-	*plOut = (LONG) cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromUI2		[OLEAUT32.210]
- */
-HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, plOut );
-
-	*plOut = (LONG) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromUI4		[OLEAUT32.211]
- */
-HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
-{
-	TRACE("( %lx, %p ), stub\n", ulIn, plOut );
-
-	/* Check range of value.
-	 */
-	if( ulIn < I4_MIN || ulIn > I4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*plOut = (LONG) ulIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromI2		[OLEAUT32.59]
- */
-HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
-{
-	TRACE("( %d, %p ), stub\n", sIn, plOut );
-
-	*plOut = (LONG) sIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI4FromStr		[OLEAUT32.64]
- */
-HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, plOut);
-  return _VarI4FromStr(strIn, lcid, dwFlags, plOut);
-}
-
-/**********************************************************************
- *              VarI4FromCy [OLEAUT32.62]
- * Convert currency to signed long
- */
-HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
-   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
-
-   *plOut = (LONG)t;
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromUI1		[OLEAUT32.68]
- */
-HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
-{
-	TRACE("( %X, %p ), stub\n", bIn, pfltOut );
-
-	*pfltOut = (FLOAT) bIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromI2		[OLEAUT32.69]
- */
-HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
-{
-	TRACE("( %d, %p ), stub\n", sIn, pfltOut );
-
-	*pfltOut = (FLOAT) sIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromI4		[OLEAUT32.70]
- */
-HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
-{
-	TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
-
-	*pfltOut = (FLOAT) lIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromR8		[OLEAUT32.71]
- */
-HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
-
-	/* Check range of value.
-	 */
-	if( dblIn < -(R4_MAX) || dblIn > R4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pfltOut = (FLOAT) dblIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromDate		[OLEAUT32.73]
- */
-HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
-
-	/* Check range of value.
-	 */
-	if( dateIn < -(R4_MAX) || dateIn > R4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pfltOut = (FLOAT) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromBool		[OLEAUT32.76]
- */
-HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
-
-	*pfltOut = (FLOAT) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromI1		[OLEAUT32.213]
- */
-HRESULT WINAPI VarR4FromI1(signed char cIn, FLOAT* pfltOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, pfltOut );
-
-	*pfltOut = (FLOAT) cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromUI2		[OLEAUT32.214]
- */
-HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
-
-	*pfltOut = (FLOAT) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromUI4		[OLEAUT32.215]
- */
-HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
-{
-	TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
-
-	*pfltOut = (FLOAT) ulIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR4FromStr		[OLEAUT32.74]
- */
-HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pfltOut);
-  return _VarR4FromStr(strIn, lcid, dwFlags, pfltOut);
-}
-
-/**********************************************************************
- *              VarR4FromCy [OLEAUT32.72]
- * Convert currency to float
- */
-HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
-   *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromUI1		[OLEAUT32.78]
- */
-HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
-{
-	TRACE("( %d, %p ), stub\n", bIn, pdblOut );
-
-	*pdblOut = (double) bIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromI2		[OLEAUT32.79]
- */
-HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
-{
-	TRACE("( %d, %p ), stub\n", sIn, pdblOut );
-
-	*pdblOut = (double) sIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromI4		[OLEAUT32.80]
- */
-HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
-{
-	TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
-
-	*pdblOut = (double) lIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromR4		[OLEAUT32.81]
- */
-HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
-{
-	TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
-
-	*pdblOut = (double) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromDate		[OLEAUT32.83]
- */
-HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
-
-	*pdblOut = (double) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromBool		[OLEAUT32.86]
- */
-HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
-
-	*pdblOut = (double) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromI1		[OLEAUT32.217]
- */
-HRESULT WINAPI VarR8FromI1(signed char cIn, double* pdblOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, pdblOut );
-
-	*pdblOut = (double) cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromUI2		[OLEAUT32.218]
- */
-HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
-
-	*pdblOut = (double) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromUI4		[OLEAUT32.219]
- */
-HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
-{
-	TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
-
-	*pdblOut = (double) ulIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarR8FromStr		[OLEAUT32.84]
- */
-HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pdblOut);
-  return _VarR8FromStr(strIn, lcid, dwFlags, pdblOut);
-}
-
-/**********************************************************************
- *              VarR8FromCy [OLEAUT32.82]
- * Convert currency to double
- */
-HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
-   *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-   TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromUI1		[OLEAUT32.88]
- */
-HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
-{
-	TRACE("( %d, %p ), stub\n", bIn, pdateOut );
-
-	*pdateOut = (DATE) bIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromI2		[OLEAUT32.89]
- */
-HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
-{
-	TRACE("( %d, %p ), stub\n", sIn, pdateOut );
-
-	*pdateOut = (DATE) sIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromI4		[OLEAUT32.90]
- */
-HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
-{
-	TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
-
-	if( lIn < DATE_MIN || lIn > DATE_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pdateOut = (DATE) lIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromR4		[OLEAUT32.91]
- */
-HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
-{
-    TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
-
-    if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pdateOut = (DATE) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromR8		[OLEAUT32.92]
- */
-HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
-{
-    TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
-
-	if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pdateOut = (DATE) dblIn;
-
-	return S_OK;
-}
-
-/* Date string parsing */
-#define DP_TIMESEP 0x01 /* Time seperator ( _must_ remain 0x1, used as a bitmask) */
-#define DP_DATESEP 0x02 /* Date seperator */
-#define DP_MONTH   0x04 /* Month name */
-#define DP_AM      0x08 /* AM */
-#define DP_PM      0x10 /* PM */
-
-typedef struct tagDATEPARSE
-{
-    DWORD dwCount;      /* Number of fields found so far (maximum 6) */
-    DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
-    DWORD dwFlags[6];   /* Flags for each field */
-    DWORD dwValues[6];  /* Value of each field */
-} DATEPARSE;
-
-#define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
-
-#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
-
-/* Determine if a day is valid in a given month of a given year */
-static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
+                                   LCID lcid, USHORT wFlags, VARTYPE vt)
 {
-  static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-  if (day && month && month < 13)
-  {
-    if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
-      return TRUE;
-  }
-  return FALSE;
-}
-
-/* Possible orders for 3 numbers making up a date */
-#define ORDER_MDY 0x01
-#define ORDER_YMD 0x02
-#define ORDER_YDM 0x04
-#define ORDER_DMY 0x08
-#define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
+  HRESULT res = S_OK;
+  VARIANTARG varg;
 
-/* Determine a date for a particular locale, from 3 numbers */
-static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
-                                       DWORD offset, SYSTEMTIME *st)
-{
-  DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
+  V_VT(&varg) = VT_EMPTY;
 
-  if (!dp->dwCount)
-  {
-    v1 = 30; /* Default to (Variant) 0 date part */
-    v2 = 12;
-    v3 = 1899;
-    goto VARIANT_MakeDate_OK;
-  }
+  TRACE("(%p->(%s%s),%p->(%s%s),0x%08lx,0x%04x,%s%s)\n", pvargDest,
+        debugstr_VT(pvargDest), debugstr_VF(pvargDest), pvargSrc,
+        debugstr_VT(pvargSrc), debugstr_VF(pvargSrc), lcid, wFlags,
+        debugstr_vt(vt), debugstr_vf(vt));
 
-  v1 = dp->dwValues[offset + 0];
-  v2 = dp->dwValues[offset + 1];
-  if (dp->dwCount == 2)
+  if (vt == VT_CLSID)
   {
-    SYSTEMTIME current;
-    GetSystemTime(&current);
-    v3 = current.wYear;
+    res = DISP_E_BADVARTYPE;
   }
   else
-    v3 = dp->dwValues[offset + 2];
+    res = VARIANT_ValidateType(V_VT(pvargSrc));
 
-  TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
+  if ( SUCCEEDED(res) )
+    res = VARIANT_ValidateType(vt);
 
-  /* If one number must be a month (Because a month name was given), then only
-   * consider orders with the month in that position.
-   * If we took the current year as 'v3', then only allow a year in that position.
+  /* if we are doing an in-place conversion make a copy of the source.
    */
-  if (dp->dwFlags[offset + 0] & DP_MONTH)
-  {
-    dwAllOrders = ORDER_MDY;
-  }
-  else if (dp->dwFlags[offset + 1] & DP_MONTH)
-  {
-    dwAllOrders = ORDER_DMY;
-    if (dp->dwCount > 2)
-      dwAllOrders |= ORDER_YMD;
-  }
-  else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
-  {
-    dwAllOrders = ORDER_YDM;
-  }
-  else
-  {
-    dwAllOrders = ORDER_MDY|ORDER_DMY;
-    if (dp->dwCount > 2)
-      dwAllOrders |= (ORDER_YMD|ORDER_YDM);
-  }
-
-VARIANT_MakeDate_Start:
-  TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
-
-  while (dwAllOrders)
-  {
-    DWORD dwTemp;
-
-    if (dwCount == 0)
-    {
-      /* First: Try the order given by iDate */
-      switch (iDate)
-      {
-      case 0:  dwTry = dwAllOrders & ORDER_MDY; break;
-      case 1:  dwTry = dwAllOrders & ORDER_DMY; break;
-      default: dwTry = dwAllOrders & ORDER_YMD; break;
-      }
-    }
-    else if (dwCount == 1)
-    {
-      /* Second: Try all the orders compatable with iDate */
-      switch (iDate)
-      {
-      case 0:  dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
-      case 1:  dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
-      default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
-      }
-    }
-    else
-    {
-      /* Finally: Try any remaining orders */
-      dwTry = dwAllOrders;
-    }
-
-    TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
-
-    dwCount++;
-    if (!dwTry)
-      continue;
-
-#define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
-
-    if (dwTry & ORDER_MDY)
-    {
-      if (VARIANT_IsValidMonthDay(v2,v1,v3))
-      {
-        DATE_SWAP(v1,v2);
-        goto VARIANT_MakeDate_OK;
-      }
-      dwAllOrders &= ~ORDER_MDY;
-    }
-    if (dwTry & ORDER_YMD)
-    {
-      if (VARIANT_IsValidMonthDay(v3,v2,v1))
-      {
-        DATE_SWAP(v1,v3);
-        goto VARIANT_MakeDate_OK;
-      }
-      dwAllOrders &= ~ORDER_YMD;
-    }
-    if (dwTry & ORDER_YDM)
-    {
-      if (VARIANT_IsValidMonthDay(v2,v3,v1))
-      {
-        DATE_SWAP(v1,v2);
-        DATE_SWAP(v2,v3);
-        goto VARIANT_MakeDate_OK;
-      }
-      dwAllOrders &= ~ORDER_YDM;
-    }
-    if (dwTry & ORDER_DMY)
-    {
-      if (VARIANT_IsValidMonthDay(v1,v2,v3))
-        goto VARIANT_MakeDate_OK;
-      dwAllOrders &= ~ORDER_DMY;
-    }
-    if (dwTry & ORDER_MYD)
-    {
-      /* Only occurs if we are trying a 2 year date as M/Y not D/M */
-      if (VARIANT_IsValidMonthDay(v3,v1,v2))
-      {
-        DATE_SWAP(v1,v3);
-        DATE_SWAP(v2,v3);
-        goto VARIANT_MakeDate_OK;
-      }
-      dwAllOrders &= ~ORDER_MYD;
-    }
-  }
-
-  if (dp->dwCount == 2)
+  if ( SUCCEEDED(res) && pvargDest == pvargSrc )
   {
-    /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
-    v3 = 1; /* 1st of the month */
-    dwAllOrders = ORDER_YMD|ORDER_MYD;
-    dp->dwCount = 0; /* Don't return to this code path again */
-    dwCount = 0;
-    goto VARIANT_MakeDate_Start;
+    res = VariantCopy( &varg, pvargSrc );
+    pvargSrc = &varg;
   }
 
-  /* No valid dates were able to be constructed */
-  return DISP_E_TYPEMISMATCH;
-
-VARIANT_MakeDate_OK:
-
-  /* Check that the time part is ok */
-  if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
-    return DISP_E_TYPEMISMATCH;
-
-  TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
-  if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
-    st->wHour += 12;
-  else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
-    st->wHour = 0;
-  TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
-
-  st->wDay = v1;
-  st->wMonth = v2;
-  /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
-   * be retrieved from:
-   * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
-   * But Wine doesn't have/use that key as at the time of writing.
-   */
-  st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
-  TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
-  return S_OK;
-}
-
-/******************************************************************************
- * VarDateFromStr [OLEAUT32.94]
- *
- * Convert a VT_BSTR to at VT_DATE.
- *
- * PARAMS
- *  strIn    [I] String to convert
- *  lcid     [I] Locale identifier for the conversion
- *  dwFlags  [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
- *  pdateOut [O] Destination for the converted value
- *
- * RETURNS
- *  Success: S_OK. pdateOut contains the converted value.
- *  FAILURE: An HRESULT error code indicating the prolem.
- *
- * NOTES
- *  Any date format that can be created using the date formats from lcid
- *  (Either from kernel Nls functions, variant conversion or formatting) is a
- *  valid input to this function. In addition, a few more esoteric formats are
- *  also supported for compatability with the native version. The date is
- *  interpreted according to the date settings in the control panel, unless
- *  the date is invalid in that format, in which the most compatable format
- *  that produces a valid date will be used.
- */
-HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
-{
-  static const USHORT ParseDateTokens[] =
-  {
-    LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
-    LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
-    LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
-    LOCALE_SMONTHNAME13,
-    LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
-    LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
-    LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
-    LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
-    LOCALE_SABBREVMONTHNAME13,
-    LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
-    LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
-    LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
-    LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
-    LOCALE_SABBREVDAYNAME7,
-    LOCALE_S1159, LOCALE_S2359
-  };
-  static const BYTE ParseDateMonths[] =
-  {
-    1,2,3,4,5,6,7,8,9,10,11,12,13,
-    1,2,3,4,5,6,7,8,9,10,11,12,13
-  };
-  size_t i;
-  BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
-  DATEPARSE dp;
-  DWORD dwDateSeps = 0, iDate = 0;
-  HRESULT hRet = S_OK;
-
-  if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
-      (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
-    return E_INVALIDARG;
-
-  if (!strIn)
-    return DISP_E_TYPEMISMATCH;
-
-  *pdateOut = 0.0;
-
-  TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
-
-  memset(&dp, 0, sizeof(dp));
-
-  GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
-                 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
-  TRACE("iDate is %ld\n", iDate);
-
-  /* Get the month/day/am/pm tokens for this locale */
-  for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
+  if ( SUCCEEDED(res) )
   {
-    WCHAR buff[128];
-    LCTYPE lctype =  ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
-
-    /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
-     *        GetAltMonthNames(). We should really cache these strings too.
+    /* free up the destination variant.
      */
-    buff[0] = '\0';
-    GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
-    tokens[i] = SysAllocString(buff);
-    TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
+    res = VariantClear( pvargDest );
   }
 
-  /* Parse the string into our structure */
-  while (*strIn)
+  if ( SUCCEEDED(res) )
   {
-    if (dp.dwCount > 6)
-      break;
-
-    if (isdigitW(*strIn))
-    {
-      dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
-      dp.dwCount++;
-      strIn--;
-    }
-    else if (isalpha(*strIn))
+    if ( V_VT(pvargSrc) & VT_BYREF )
     {
-      BOOL bFound = FALSE;
+      /* Convert the source variant to a "byvalue" variant.
+       */
+      VARIANTARG Variant;
 
-      for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
-      {
-        DWORD dwLen = strlenW(tokens[i]);
-        if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
-        {
-          if (i <= 25)
-          {
-            dp.dwValues[dp.dwCount] = ParseDateMonths[i];
-            dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
-            dp.dwCount++;
-          }
-          else if (i > 39)
-          {
-            if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
-              hRet = DISP_E_TYPEMISMATCH;
-            else
-            {
-              dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
-              dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
-            }
-          }
-          strIn += (dwLen - 1);
-          bFound = TRUE;
-          break;
-        }
+      if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
+        FIXME("VT_TYPEMASK %s is unhandled.\n", debugstr_VF(pvargSrc));
+        return E_FAIL;
       }
 
-      if (!bFound)
+      V_VT(&Variant) = VT_EMPTY;
+      res = VariantCopyInd( &Variant, pvargSrc );
+      if ( SUCCEEDED(res) )
       {
-        if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
-            (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
-        {
-          /* Special case - 'a' and 'p' are recognised as short for am/pm */
-          if (*strIn == 'a' || *strIn == 'A')
-          {
-            dp.dwFlags[dp.dwCount - 1] |= DP_AM;
-            dp.dwParseFlags |=  DP_AM;
-          }
-          else
-          {
-            dp.dwFlags[dp.dwCount - 1] |= DP_PM;
-            dp.dwParseFlags |=  DP_PM;
-          }
-          strIn++;
-        }
-        else
-        {
-          TRACE("No matching token for %s\n", debugstr_w(strIn));
-          hRet = DISP_E_TYPEMISMATCH;
-          break;
-        }
+        res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
+        /* this should not fail.
+         */
+        VariantClear( &Variant );
       }
     }
-    else if (*strIn == ':' ||  *strIn == '.')
-    {
-      if (!dp.dwCount || !strIn[1])
-        hRet = DISP_E_TYPEMISMATCH;
-      else
-        dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
-    }
-    else if (*strIn == '-' || *strIn == '/')
-    {
-      dwDateSeps++;
-      if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
-        hRet = DISP_E_TYPEMISMATCH;
-      else
-        dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
-    }
-    else if (*strIn == ',' || isspaceW(*strIn))
-    {
-      if (*strIn == ',' && !strIn[1])
-        hRet = DISP_E_TYPEMISMATCH;
-    }
     else
     {
-      hRet = DISP_E_TYPEMISMATCH;
-    }
-    strIn++;
-  }
-
-  if (!dp.dwCount || dp.dwCount > 6 ||
-      (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
-    hRet = DISP_E_TYPEMISMATCH;
-
-  if (SUCCEEDED(hRet))
-  {
-    SYSTEMTIME st;
-    DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
-
-    st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
-
-    /* Figure out which numbers correspond to which fields.
-     *
-     * This switch statement works based on the fact that native interprets any
-     * fields that are not joined with a time seperator ('.' or ':') as date
-     * fields. Thus we construct a value from 0-32 where each set bit indicates
-     * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
-     * For valid permutations, we set dwOffset to point to the first date field
-     * and shorten dp.dwCount by the number of time fields found. The real
-     * magic here occurs in VARIANT_MakeDate() above, where we determine what
-     * each date number must represent in the context of iDate.
-     */
-    TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
-
-    switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
-    {
-    case 0x1: /* TT TTDD TTDDD */
-      if (dp.dwCount > 3 &&
-          ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
-          (dp.dwFlags[4] & (DP_AM|DP_PM))))
-        hRet = DISP_E_TYPEMISMATCH;
-      else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
-        hRet = DISP_E_TYPEMISMATCH;
-      st.wHour = dp.dwValues[0];
-      st.wMinute  = dp.dwValues[1];
-      dp.dwCount -= 2;
-      dwOffset = 2;
-      break;
-
-    case 0x3: /* TTT TTTDD TTTDDD */
-      if (dp.dwCount > 4 &&
-          ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
-          (dp.dwFlags[5] & (DP_AM|DP_PM))))
-        hRet = DISP_E_TYPEMISMATCH;
-      else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
-        hRet = DISP_E_TYPEMISMATCH;
-      st.wHour   = dp.dwValues[0];
-      st.wMinute = dp.dwValues[1];
-      st.wSecond = dp.dwValues[2];
-      dwOffset = 3;
-      dp.dwCount -= 3;
-      break;
-
-    case 0x4: /* DDTT */
-      if (dp.dwCount != 4 ||
-          (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
-        hRet = DISP_E_TYPEMISMATCH;
-
-      st.wHour = dp.dwValues[2];
-      st.wMinute  = dp.dwValues[3];
-      dp.dwCount -= 2;
-      break;
-
-   case 0x0: /* T DD DDD TDDD TDDD */
-      if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
-      {
-        st.wHour = dp.dwValues[0]; /* T */
-        dp.dwCount = 0;
-        break;
-      }
-      else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
-      {
-        hRet = DISP_E_TYPEMISMATCH;
-      }
-      else if (dp.dwCount == 3)
+      if (V_VT(pvargSrc) & VT_ARRAY)
       {
-        if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
-        {
-          dp.dwCount = 2;
-          st.wHour = dp.dwValues[0];
-          dwOffset = 1;
-          break;
-        }
-        if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
+        if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY)
         {
-          dp.dwCount = 2;
-          st.wHour = dp.dwValues[2];
-          break;
+          FIXME("VT_TYPEMASK %s is unhandled in VT_ARRAY.\n", debugstr_VF(pvargSrc));
+          return E_FAIL;
         }
-        else if (dp.dwParseFlags & (DP_AM|DP_PM))
-          hRet = DISP_E_TYPEMISMATCH;
+        V_VT(pvargDest) = VT_ARRAY | vt;
+        res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt);
       }
-      else if (dp.dwCount == 4)
+      else
       {
-        dp.dwCount = 3;
-        if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
-        {
-          st.wHour = dp.dwValues[0];
-          dwOffset = 1;
-        }
-        else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
+        if ((V_VT(pvargSrc) & 0xf000))
         {
-          st.wHour = dp.dwValues[3];
+          FIXME("VT_TYPEMASK %s is unhandled in normal case.\n", debugstr_VF(pvargSrc));
+          return E_FAIL;
         }
-        else
-          hRet = DISP_E_TYPEMISMATCH;
-        break;
-      }
-      /* .. fall through .. */
-
-    case 0x8: /* DDDTT */
-      if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
-          (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
-           (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
-           dp.dwCount == 4 || dp.dwCount == 6)
-        hRet = DISP_E_TYPEMISMATCH;
-      st.wHour   = dp.dwValues[3];
-      st.wMinute = dp.dwValues[4];
-      if (dp.dwCount == 5)
-        dp.dwCount -= 2;
-      break;
-
-    case 0xC: /* DDTTT */
-      if (dp.dwCount != 5 ||
-          (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
-        hRet = DISP_E_TYPEMISMATCH;
-      st.wHour   = dp.dwValues[2];
-      st.wMinute = dp.dwValues[3];
-      st.wSecond = dp.dwValues[4];
-      dp.dwCount -= 3;
-      break;
-
-    case 0x18: /* DDDTTT */
-      if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
-          (dp.dwFlags[2] & (DP_AM|DP_PM)))
-        hRet = DISP_E_TYPEMISMATCH;
-      st.wHour   = dp.dwValues[3];
-      st.wMinute = dp.dwValues[4];
-      st.wSecond = dp.dwValues[5];
-      dp.dwCount -= 3;
-      break;
-
-    default:
-      hRet = DISP_E_TYPEMISMATCH;
-      break;
-    }
-
-    if (SUCCEEDED(hRet))
-    {
-      hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
-
-      if (dwFlags & VAR_TIMEVALUEONLY)
-      {
-        st.wYear = 1899;
-        st.wMonth = 12;
-        st.wDay = 30;
+        /* Use the current "byvalue" source variant.
+         */
+        res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
       }
-      else if (dwFlags & VAR_DATEVALUEONLY)
-       st.wHour = st.wMinute = st.wSecond = 0;
-
-      /* Finally, convert the value to a VT_DATE */
-      if (SUCCEEDED(hRet))
-        hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
     }
   }
 
-  for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
-    SysFreeString(tokens[i]);
-  return hRet;
-}
-
-/******************************************************************************
- *		VarDateFromI1		[OLEAUT32.221]
- */
-HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, pdateOut );
-
-	*pdateOut = (DATE) cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromUI2		[OLEAUT32.222]
- */
-HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
-
-	*pdateOut = (DATE) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromUI4		[OLEAUT32.223]
- */
-HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
-{
-	TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
-
-	if( ulIn < DATE_MIN || ulIn > DATE_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pdateOut = (DATE) ulIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarDateFromBool		[OLEAUT32.96]
- */
-HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
-
-	*pdateOut = (DATE) boolIn;
-
-	return S_OK;
-}
-
-/**********************************************************************
- *              VarDateFromCy [OLEAUT32.93]
- * Convert currency to date
- */
-HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
-   *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromUI1		[OLEAUT32.108]
- */
-HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
-	sprintf( pBuffer, "%d", bVal );
-
-	*pbstrOut =  StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromI2		[OLEAUT32.109]
- */
-HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
-	sprintf( pBuffer, "%d", iVal );
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromI4		[OLEAUT32.110]
- */
-HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
-
-	sprintf( pBuffer, "%ld", lIn );
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromR4		[OLEAUT32.111]
- */
-HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
-
-	sprintf( pBuffer, "%.7G", fltIn );
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromR8		[OLEAUT32.112]
- */
-HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
-
-	sprintf( pBuffer, "%.15G", dblIn );
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *    VarBstrFromCy   [OLEAUT32.113]
- */
-HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
-    HRESULT rc = S_OK;
-    double curVal = 0.0;
-
-	TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
-
-    /* Firstly get the currency in a double, then put it in a buffer */
-    rc = VarR8FromCy(cyIn, &curVal);
-    if (rc == S_OK) {
-        sprintf(pBuffer, "%G", curVal);
-        *pbstrOut = StringDupAtoBstr( pBuffer );
-    }
-	return rc;
-}
-
-
-/******************************************************************************
- *    VarBstrFromDate    [OLEAUT32.114]
- *
- * Convert a VT_DATE to a VT_BSTR.
- *
- * PARAMS
- *  dateIn   [I] Source
- *  lcid     [I] LCID for the conversion
- *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
- *  pbstrOut [O] Destination
- *
- * RETURNS
- *  Success: S_OK.
- *  Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
- *           E_OUTOFMEMORY, if memory allocation fails.
- */
-HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-  SYSTEMTIME st;
-  DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
-  WCHAR date[128], *time;
-
-  TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
-
-  if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
-    return E_INVALIDARG;
-
-  *pbstrOut = NULL;
-
-  if (dwFlags & VAR_CALENDAR_THAI)
-      st.wYear += 553; /* Use the Thai buddhist calendar year */
-  else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
-      FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
-
-  if (dwFlags & LOCALE_USE_NLS)
-    dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
-  else
-  {
-    double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
-    double partial = dateIn - whole;
-
-    if (whole == 0.0)
-      dwFlags |= VAR_TIMEVALUEONLY;
-    else if (partial < 1e-12)
-      dwFlags |= VAR_DATEVALUEONLY;
-  }
-
-  if (dwFlags & VAR_TIMEVALUEONLY)
-    date[0] = '\0';
-  else
-    if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
-                        sizeof(date)/sizeof(WCHAR)))
-      return E_INVALIDARG;
-
-  if (!(dwFlags & VAR_DATEVALUEONLY))
-  {
-    time = date + strlenW(date);
-    if (time != date)
-      *time++ = ' ';
-    if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
-                        sizeof(date)/sizeof(WCHAR)-(time-date)))
-      return E_INVALIDARG;
-  }
-
-  *pbstrOut = SysAllocString(date);
-  if (*pbstrOut)
-    TRACE("returning %s\n", debugstr_w(*pbstrOut));
-  return *pbstrOut ? S_OK : E_OUTOFMEMORY;
-}
-
-/******************************************************************************
- *		VarBstrFromBool		[OLEAUT32.116]
- */
-HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
-
-	sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
-
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromI1		[OLEAUT32.229]
- */
-HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
-	sprintf( pBuffer, "%d", cIn );
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromUI2		[OLEAUT32.230]
- */
-HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
-	sprintf( pBuffer, "%d", uiIn );
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromUI4		[OLEAUT32.231]
- */
-HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
-	sprintf( pBuffer, "%ld", ulIn );
-	*pbstrOut = StringDupAtoBstr( pBuffer );
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBstrFromDec		[OLEAUT32.@]
- */
-HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
-{
-	if(!pDecIn->u.s.sign && !pDecIn->u.s.scale &&
-	   !pDecIn->Hi32 && !pDecIn->u1.s1.Mid32)
-	    return VarBstrFromUI4(pDecIn->u1.s1.Lo32, lcid, dwFlags, pbstrOut);
-	FIXME("%c%08lx%08lx%08lx E%02x stub\n",
-	(pDecIn->u.s.sign == DECIMAL_NEG) ? '-' :
-	(pDecIn->u.s.sign == 0) ? '+' : '?',
-	pDecIn->Hi32, pDecIn->u1.s1.Mid32, pDecIn->u1.s1.Lo32,
-	pDecIn->u.s.scale);
-	return E_INVALIDARG;
-}
-
-/******************************************************************************
- *		VarBoolFromUI1		[OLEAUT32.118]
- */
-HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %d, %p ), stub\n", bIn, pboolOut );
-
-	if( bIn == 0 )
-	{
-		*pboolOut = VARIANT_FALSE;
-	}
-	else
-	{
-		*pboolOut = VARIANT_TRUE;
-	}
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromI2		[OLEAUT32.119]
- */
-HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %d, %p ), stub\n", sIn, pboolOut );
-
-	*pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromI4		[OLEAUT32.120]
- */
-HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
-
-	*pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromR4		[OLEAUT32.121]
- */
-HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
-
-	*pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromR8		[OLEAUT32.122]
- */
-HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
-
-	*pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromDate		[OLEAUT32.123]
- */
-HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
-
-	*pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromStr		[OLEAUT32.125]
- */
-HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
-{
-	static const WCHAR szTrue[] = { 'T','r','u','e','\0' };
-	static const WCHAR szFalse[] = { 'F','a','l','s','e','\0' };
-	HRESULT ret = S_OK;
-
-	TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
-
-	if( strIn == NULL || strlenW( strIn ) == 0 )
-	{
-		ret = DISP_E_TYPEMISMATCH;
-	}
-
-	if( ret == S_OK )
-	{
-		if( strcmpiW( (LPCWSTR)strIn, szTrue ) == 0 )
-		{
-			*pboolOut = VARIANT_TRUE;
-		}
-		else if( strcmpiW( (LPCWSTR)strIn, szFalse ) == 0 )
-		{
-			*pboolOut = VARIANT_FALSE;
-		}
-		else
-		{
-			/* Try converting the string to a floating point number.
-			 */
-			double dValue = 0.0;
-			HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
-			if( res != S_OK )
-			{
-				ret = DISP_E_TYPEMISMATCH;
-			}
-			else
-				*pboolOut = (dValue == 0.0) ?
-						VARIANT_FALSE : VARIANT_TRUE;
-		}
-	}
-
-	return ret;
-}
-
-/******************************************************************************
- *		VarBoolFromI1		[OLEAUT32.233]
- */
-HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, pboolOut );
-
-	*pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromUI2		[OLEAUT32.234]
- */
-HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
-
-	*pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarBoolFromUI4		[OLEAUT32.235]
- */
-HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
-{
-	TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
-
-	*pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
-
-	return S_OK;
-}
-
-/**********************************************************************
- *              VarBoolFromCy [OLEAUT32.124]
- * Convert currency to boolean
- */
-HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
-      if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
-      else *pboolOut = 0;
-
-      return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromUI1		[OLEAUT32.244]
- */
-HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char *pcOut)
-{
-	TRACE("( %d, %p ), stub\n", bIn, pcOut );
-
-	/* Check range of value.
-	 */
-	if( bIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) bIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromI2		[OLEAUT32.245]
- */
-HRESULT WINAPI VarI1FromI2(short uiIn, signed char *pcOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pcOut );
-
-	if( uiIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromI4		[OLEAUT32.246]
- */
-HRESULT WINAPI VarI1FromI4(LONG lIn, signed char *pcOut)
-{
-	TRACE("( %ld, %p ), stub\n", lIn, pcOut );
-
-	if( lIn < I1_MIN || lIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) lIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromR4		[OLEAUT32.247]
- */
-HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char *pcOut)
-{
-	TRACE("( %f, %p ), stub\n", fltIn, pcOut );
-
-    fltIn = round( fltIn );
-	if( fltIn < I1_MIN || fltIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromR8		[OLEAUT32.248]
- */
-HRESULT WINAPI VarI1FromR8(double dblIn, signed char *pcOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, pcOut );
-
-    dblIn = round( dblIn );
-    if( dblIn < I1_MIN || dblIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) dblIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromDate		[OLEAUT32.249]
- */
-HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char *pcOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, pcOut );
-
-    dateIn = round( dateIn );
-	if( dateIn < I1_MIN || dateIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromStr		[OLEAUT32.251]
- */
-HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char *pcOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pcOut);
-  return _VarI1FromStr(strIn, lcid, dwFlags, pcOut);
-}
-
-/******************************************************************************
- *		VarI1FromBool		[OLEAUT32.253]
- */
-HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char *pcOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, pcOut );
-
-	*pcOut = (CHAR) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromUI2		[OLEAUT32.254]
- */
-HRESULT WINAPI VarI1FromUI2(USHORT uiIn, signed char *pcOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pcOut );
-
-	if( uiIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarI1FromUI4		[OLEAUT32.255]
- */
-HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char *pcOut)
-{
-	TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
-
-	if( ulIn > I1_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pcOut = (CHAR) ulIn;
-
-	return S_OK;
-}
-
-/**********************************************************************
- *              VarI1FromCy [OLEAUT32.250]
- * Convert currency to signed char
- */
-HRESULT WINAPI VarI1FromCy(CY cyIn, signed char *pcOut) {
-   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   if (t > I1_MAX || t < I1_MIN) return DISP_E_OVERFLOW;
-
-   *pcOut = (CHAR)t;
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromUI1		[OLEAUT32.257]
- */
-HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
-{
-	TRACE("( %d, %p ), stub\n", bIn, puiOut );
-
-	*puiOut = (USHORT) bIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromI2		[OLEAUT32.258]
- */
-HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, puiOut );
-
-	if( uiIn < UI2_MIN )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*puiOut = (USHORT) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromI4		[OLEAUT32.259]
- */
-HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
-{
-	TRACE("( %ld, %p ), stub\n", lIn, puiOut );
-
-	if( lIn < UI2_MIN || lIn > UI2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*puiOut = (USHORT) lIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromR4		[OLEAUT32.260]
- */
-HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
-{
-	TRACE("( %f, %p ), stub\n", fltIn, puiOut );
-
-    fltIn = round( fltIn );
-	if( fltIn < UI2_MIN || fltIn > UI2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*puiOut = (USHORT) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromR8		[OLEAUT32.261]
- */
-HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, puiOut );
-
-    dblIn = round( dblIn );
-    if( dblIn < UI2_MIN || dblIn > UI2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*puiOut = (USHORT) dblIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromDate		[OLEAUT32.262]
- */
-HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, puiOut );
-
-    dateIn = round( dateIn );
-	if( dateIn < UI2_MIN || dateIn > UI2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*puiOut = (USHORT) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromStr		[OLEAUT32.264]
- */
-HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, puiOut);
-  return _VarUI2FromStr(strIn, lcid, dwFlags, puiOut);
-}
-
-/******************************************************************************
- *		VarUI2FromBool		[OLEAUT32.266]
- */
-HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, puiOut );
-
-	*puiOut = (USHORT) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromI1		[OLEAUT32.267]
- */
-HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* puiOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, puiOut );
-
-	*puiOut = (USHORT) cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI2FromUI4		[OLEAUT32.268]
- */
-HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
-{
-	TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
-
-	if( ulIn > UI2_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*puiOut = (USHORT) ulIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromStr		[OLEAUT32.277]
- */
-HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pulOut);
-  return _VarUI4FromStr(strIn, lcid, dwFlags, pulOut);
-}
-
-/**********************************************************************
- *              VarUI2FromCy [OLEAUT32.263]
- * Convert currency to unsigned short
- */
-HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
-   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
-
-   *pusOut = (USHORT)t;
-
-   return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromUI1		[OLEAUT32.270]
- */
-HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
-{
-	TRACE("( %d, %p ), stub\n", bIn, pulOut );
-
-	*pulOut = (USHORT) bIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromI2		[OLEAUT32.271]
- */
-HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pulOut );
-
-	if( uiIn < UI4_MIN )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pulOut = (ULONG) uiIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromI4		[OLEAUT32.272]
- */
-HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
-{
-	TRACE("( %ld, %p ), stub\n", lIn, pulOut );
-
-	if( lIn < 0 )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pulOut = (ULONG) lIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromR4		[OLEAUT32.273]
- */
-HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
-{
-    fltIn = round( fltIn );
-    if( fltIn < UI4_MIN || fltIn > UI4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pulOut = (ULONG) fltIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromR8		[OLEAUT32.274]
- */
-HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
-{
-	TRACE("( %f, %p ), stub\n", dblIn, pulOut );
-
-	dblIn = round( dblIn );
-	if( dblIn < UI4_MIN || dblIn > UI4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pulOut = (ULONG) dblIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromDate		[OLEAUT32.275]
- */
-HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
-{
-	TRACE("( %f, %p ), stub\n", dateIn, pulOut );
-
-	dateIn = round( dateIn );
-	if( dateIn < UI4_MIN || dateIn > UI4_MAX )
-	{
-		return DISP_E_OVERFLOW;
-	}
-
-	*pulOut = (ULONG) dateIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromBool		[OLEAUT32.279]
- */
-HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
-{
-	TRACE("( %d, %p ), stub\n", boolIn, pulOut );
-
-	*pulOut = (ULONG) boolIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromI1		[OLEAUT32.280]
- */
-HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG* pulOut)
-{
-	TRACE("( %c, %p ), stub\n", cIn, pulOut );
-
-	*pulOut = (ULONG) cIn;
-
-	return S_OK;
-}
-
-/******************************************************************************
- *		VarUI4FromUI2		[OLEAUT32.281]
- */
-HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
-{
-	TRACE("( %d, %p ), stub\n", uiIn, pulOut );
-
-	*pulOut = (ULONG) uiIn;
-
-	return S_OK;
-}
-
-/**********************************************************************
- *              VarUI4FromCy [OLEAUT32.276]
- * Convert currency to unsigned long
- */
-HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
-   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
-
-   if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
-
-   *pulOut = (ULONG)t;
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromUI1 [OLEAUT32.98]
- * Convert unsigned char to currency
- */
-HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
-    pcyOut->s.Hi = 0;
-    pcyOut->s.Lo = ((ULONG)bIn) * 10000;
-
-    return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromI2 [OLEAUT32.99]
- * Convert signed short to currency
- */
-HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
-    if (sIn < 0) pcyOut->s.Hi = -1;
-    else pcyOut->s.Hi = 0;
-    pcyOut->s.Lo = ((ULONG)sIn) * 10000;
-
-    return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromI4 [OLEAUT32.100]
- * Convert signed long to currency
- */
-HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
-      double t = (double)lIn * (double)10000;
-      pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
-      pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
-      if (lIn < 0) pcyOut->s.Hi--;
-
-      return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromR4 [OLEAUT32.101]
- * Convert float to currency
- */
-HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
-   double t = round((double)fltIn * (double)10000);
-   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
-   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
-   if (fltIn < 0) pcyOut->s.Hi--;
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromR8 [OLEAUT32.102]
- * Convert double to currency
- */
-HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
-   double t = round(dblIn * (double)10000);
-   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
-   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
-   if (dblIn < 0) pcyOut->s.Hi--;
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromDate [OLEAUT32.103]
- * Convert date to currency
- */
-HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
-   double t = round((double)dateIn * (double)10000);
-   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
-   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
-   if (dateIn < 0) pcyOut->s.Hi--;
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromStr [OLEAUT32.104]
- * FIXME: Never tested with decimal separator other than '.'
- */
-HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut)
-{
-  TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pcyOut);
-  return _VarCyFromStr(strIn, lcid, dwFlags, pcyOut);
-}
-
-
-/**********************************************************************
- *              VarCyFromBool [OLEAUT32.106]
- * Convert boolean to currency
- */
-HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
-   if (boolIn < 0) pcyOut->s.Hi = -1;
-   else pcyOut->s.Hi = 0;
-   pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromI1 [OLEAUT32.225]
- * Convert signed char to currency
- */
-HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
-   if (cIn < 0) pcyOut->s.Hi = -1;
-   else pcyOut->s.Hi = 0;
-   pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromUI2 [OLEAUT32.226]
- * Convert unsigned short to currency
- */
-HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
-   pcyOut->s.Hi = 0;
-   pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarCyFromUI4 [OLEAUT32.227]
- * Convert unsigned long to currency
- */
-HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
-   double t = (double)ulIn * (double)10000;
-   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
-   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
-
-   return S_OK;
-}
-
-/**********************************************************************
- *              VarDecFromStr [OLEAUT32.@]
- */
-HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags,
-                             DECIMAL* pdecOut)
-{   WCHAR *p=strIn;
-    ULONGLONG t;
-    ULONG  cy;
-
-    DECIMAL_SETZERO(pdecOut);
-
-    if(*p == (WCHAR)'-')pdecOut->u.s.sign= DECIMAL_NEG;
-    if((*p == (WCHAR)'-') || (*p == (WCHAR)'+')) p++;
-    for(;*p != (WCHAR)0; p++) {
-        if((*p < (WCHAR)'0')||(*p > (WCHAR)'9')) goto error ;
-        t = (ULONGLONG)pdecOut->u1.s1.Lo32 *(ULONGLONG)10
-          + (ULONGLONG)(*p -(WCHAR)'0');
-        cy = (ULONG)(t >> 32);
-        pdecOut->u1.s1.Lo32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
-        t = (ULONGLONG)pdecOut->u1.s1.Mid32 * (ULONGLONG)10
-          + (ULONGLONG)cy;
-        cy = (ULONG)(t >> 32);
-        pdecOut->u1.s1.Mid32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
-        t = (ULONGLONG)pdecOut->Hi32 * (ULONGLONG)10
-          + (ULONGLONG)cy;
-        cy = (ULONG)(t >> 32);
-        pdecOut->Hi32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
-        if(cy) goto overflow ;
-    }
-    TRACE("%s -> sign %02x,hi %08lx,mid %08lx, lo%08lx, scale %08x\n",
-          debugstr_w(strIn),
-          pdecOut->u.s.sign, pdecOut->Hi32, pdecOut->u1.s1.Mid32,
-          pdecOut->u1.s1.Lo32, pdecOut->u.s.scale);
-    return S_OK;
+  VariantClear( &varg );
 
-overflow:
-    /* like NT4 SP5 */
-    pdecOut->Hi32 = pdecOut->u1.s1.Mid32 = pdecOut->u1.s1.Lo32 = 0xffffffff;
-    return DISP_E_OVERFLOW;
+  if ( SUCCEEDED(res) )
+    V_VT(pvargDest) = vt;
 
-error:
-    ERR("%s: unknown char at pos %d\n",
-              debugstr_w(strIn),  p - strIn + 1);
-    return DISP_E_TYPEMISMATCH;
+  TRACE("returning 0x%08lx, %p->(%s%s)\n", res, pvargDest,
+        debugstr_VT(pvargDest), debugstr_VF(pvargDest));
+  return res;
 }
 
 /* Date Conversions */
@@ -5035,7 +1885,7 @@
 /* VTBIT flags indicating an integer value */
 #define INTEGER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8)
 /* VTBIT flags indicating a real number value */
-#define REAL_VTBITS (VTBIT_R4|VTBIT_R8|VTBIT_CY|VTBIT_DECIMAL)
+#define REAL_VTBITS (VTBIT_R4|VTBIT_R8|VTBIT_CY)
 
 /**********************************************************************
  *              VarNumFromParseNum [OLEAUT32.47]
@@ -5065,7 +1915,7 @@
 HRESULT WINAPI VarNumFromParseNum(NUMPARSE *pNumprs, BYTE *rgbDig,
                                   ULONG dwVtBits, VARIANT *pVarDst)
 {
-  /* Scale factors and limits for double arithmetics */
+  /* Scale factors and limits for double arithmatic */
   static const double dblMultipliers[11] = {
     1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0,
     1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0
@@ -5130,12 +1980,14 @@
         pNumprs->nPwr10, wholeNumberDigits, fractionalDigits);
   TRACE("mult %d; div %d\n", multiplier10, divisor10);
 
-  if (dwVtBits & INTEGER_VTBITS &&
+  if (dwVtBits & (INTEGER_VTBITS|VTBIT_DECIMAL) &&
       (!fractionalDigits || !(dwVtBits & (REAL_VTBITS|VTBIT_CY|VTBIT_DECIMAL))))
   {
     /* We have one or more integer output choices, and either:
      *  1) An integer input value, or
      *  2) A real number input value but no floating output choices.
+     * Alternately, we have a DECIMAL output available and an integer input.
+     *
      * So, place the integer value into pVarDst, using the smallest type
      * possible and preferring signed over unsigned types.
      */
@@ -5243,6 +2095,15 @@
           V_I8(pVarDst) = -ul64;
           return S_OK;
         }
+        else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL)
+        {
+          /* Decimal is only output choice left - fast path */
+          V_VT(pVarDst) = VT_DECIMAL;
+          DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_NEG,0);
+          DEC_HI32(&V_DECIMAL(pVarDst)) = 0;
+          DEC_LO64(&V_DECIMAL(pVarDst)) = -ul64;
+          return S_OK;
+        }
       }
     }
     else if (!bOverflow)
@@ -5254,48 +2115,57 @@
         V_I1(pVarDst) = ul64;
         return S_OK;
       }
-      if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX)
+      else if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX)
       {
         V_VT(pVarDst) = VT_UI1;
         V_UI1(pVarDst) = ul64;
         return S_OK;
       }
-      if (dwVtBits & VTBIT_I2 && ul64 <= I2_MAX)
+      else if (dwVtBits & VTBIT_I2 && ul64 <= I2_MAX)
       {
         V_VT(pVarDst) = VT_I2;
         V_I2(pVarDst) = ul64;
         return S_OK;
       }
-      if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX)
+      else if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX)
       {
         V_VT(pVarDst) = VT_UI2;
         V_UI2(pVarDst) = ul64;
         return S_OK;
       }
-      if (dwVtBits & VTBIT_I4 && ul64 <= I4_MAX)
+      else if (dwVtBits & VTBIT_I4 && ul64 <= I4_MAX)
       {
         V_VT(pVarDst) = VT_I4;
         V_I4(pVarDst) = ul64;
         return S_OK;
       }
-      if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX)
+      else if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX)
       {
         V_VT(pVarDst) = VT_UI4;
         V_UI4(pVarDst) = ul64;
         return S_OK;
       }
-      if (dwVtBits & VTBIT_I8 && ul64 <= I8_MAX)
+      else if (dwVtBits & VTBIT_I8 && ul64 <= I8_MAX)
       {
         V_VT(pVarDst) = VT_I8;
         V_I8(pVarDst) = ul64;
         return S_OK;
       }
-      if (dwVtBits & VTBIT_UI8)
+      else if (dwVtBits & VTBIT_UI8)
       {
         V_VT(pVarDst) = VT_UI8;
         V_UI8(pVarDst) = ul64;
         return S_OK;
       }
+      else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL)
+      {
+        /* Decimal is only output choice left - fast path */
+        V_VT(pVarDst) = VT_DECIMAL;
+        DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0);
+        DEC_HI32(&V_DECIMAL(pVarDst)) = 0;
+        DEC_LO64(&V_DECIMAL(pVarDst)) = ul64;
+        return S_OK;
+      }
     }
   }
 
@@ -5388,85 +2258,66 @@
       }
       TRACE("Value Overflows CY\n");
     }
-
-    if (!bOverflow && dwVtBits & VTBIT_DECIMAL)
-    {
-      WARN("VTBIT_DECIMAL not yet implemented\n");
-#if 0
-      if (SUCCEEDED(VarDecFromR8(bNegative ? -whole : whole, &V_DECIMAL(pVarDst))))
-      {
-        V_VT(pVarDst) = VT_DECIMAL; /* Fits into a decimal */
-        TRACE("Set DECIMAL to final value\n");
-        return S_OK;
-      }
-#endif
-    }
   }
 
   if (dwVtBits & VTBIT_DECIMAL)
   {
-    FIXME("VT_DECIMAL > R8 not yet supported, returning overflow\n");
-  }
-  return DISP_E_OVERFLOW; /* No more output choices */
-}
-
-/**********************************************************************
- *              VarBstrCmp [OLEAUT32.314]
- *
- * flags can be:
- *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
- *   NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
- *
- */
-HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
-{
-    INT r;
-
-    TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
-
-    /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
-    if((!left) || (!right)) {
+    int i;
+    ULONG carry;
+    ULONG64 tmp;
+    DECIMAL* pDec = &V_DECIMAL(pVarDst);
 
-        if (!left && (!right || *right==0)) return VARCMP_EQ;
-        else if (!right && (!left || *left==0)) return VARCMP_EQ;
-        else return VARCMP_NULL;
-    }
+    DECIMAL_SETZERO(pDec);
+    DEC_LO32(pDec) = 0;
 
-    if(flags&NORM_IGNORECASE)
-        r = lstrcmpiW(left,right);
+    if (pNumprs->dwOutFlags & NUMPRS_NEG)
+      DEC_SIGN(pDec) = DECIMAL_NEG;
     else
-        r = lstrcmpW(left,right);
-
-    if(r<0)
-        return VARCMP_LT;
-    if(r>0)
-        return VARCMP_GT;
-
-    return VARCMP_EQ;
-}
+      DEC_SIGN(pDec) = DECIMAL_POS;
 
-/**********************************************************************
- *              VarBstrCat [OLEAUT32.313]
- */
-HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
-{
-    BSTR result;
-    int size = 0;
+    /* Factor the significant digits */
+    for (i = 0; i < pNumprs->cDig; i++)
+    {
+      tmp = (ULONG64)DEC_LO32(pDec) * 10 + rgbDig[i];
+      carry = (ULONG)(tmp >> 32);
+      DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX);
+      tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry;
+      carry = (ULONG)(tmp >> 32);
+      DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX);
+      tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry;
+      DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX);
 
-    TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
+      if (tmp >> 32 & UI4_MAX)
+      {
+VarNumFromParseNum_DecOverflow:
+        TRACE("Overflow\n");
+        DEC_LO32(pDec) = DEC_MID32(pDec) = DEC_HI32(pDec) = UI4_MAX;
+        return DISP_E_OVERFLOW;
+      }
+    }
 
-    /* On Windows, NULL parms are still handled (as empty strings) */
-    if (left)  size=size + lstrlenW(left);
-    if (right) size=size + lstrlenW(right);
+    /* Account for the scale of the number */
+    while (multiplier10 > 0)
+    {
+      tmp = (ULONG64)DEC_LO32(pDec) * 10;
+      carry = (ULONG)(tmp >> 32);
+      DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX);
+      tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry;
+      carry = (ULONG)(tmp >> 32);
+      DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX);
+      tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry;
+      DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX);
 
-    if (out) {
-        result = SysAllocStringLen(NULL, size);
-        *out = result;
-        if (left) lstrcatW(result,left);
-        if (right) lstrcatW(result,right);
-        TRACE("result = %s, [%p]\n", debugstr_w(result), result);
+      if (tmp >> 32 & UI4_MAX)
+        goto VarNumFromParseNum_DecOverflow;
+      multiplier10--;
     }
+    DEC_SCALE(pDec) = divisor10;
+
+    V_VT(pVarDst) = VT_DECIMAL;
     return S_OK;
+  }
+  return DISP_E_OVERFLOW; /* No more output choices */
 }
 
 /**********************************************************************
@@ -6204,10 +3055,7 @@
     case VT_DATE:
     ABS_CASE(R8,R8_MIN);
     case VT_CY:
-        /* FIXME: Waiting for this function to be implemented */
-#if 0
         hRet = VarCyAbs(V_CY(pVarIn), & V_CY(pVarOut));
-#endif
         break;
     case VT_DECIMAL:
         DEC_SIGN(&V_DECIMAL(pVarOut)) &= ~DECIMAL_NEG;
@@ -6278,9 +3126,7 @@
     case VT_I2:  V_I2(pVarOut) = ~V_I2(pVarIn); break;
     case VT_UI2: V_UI2(pVarOut) = ~V_UI2(pVarIn); break;
     case VT_DECIMAL:
-        /* FIXME  Waiting for this function to be implemented */
-/*        hRet = VarI4FromDec(&V_DECIMAL(pVarIn), &V_I4(&varIn)); */
-        hRet = DISP_E_OVERFLOW;
+        hRet = VarI4FromDec(&V_DECIMAL(pVarIn), &V_I4(&varIn));
         if (FAILED(hRet))
             break;
         pVarIn = &varIn;
@@ -6330,24 +3176,6 @@
 }
 
 /**********************************************************************
- *              VarCyMulI4 [OLEAUT32.304]
- * Multiply currency value by integer
- */
-HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
-
-    double cyVal = 0;
-    HRESULT rc = S_OK;
-
-    rc = VarR8FromCy(cyIn, &cyVal);
-    if (rc == S_OK) {
-        rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
-        TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
-                    pcyOut->s.Hi, pcyOut->s.Lo);
-    }
-    return rc;
-}
-
-/**********************************************************************
  *              VarMod [OLEAUT32.154]
  *
  */
--- wine/dlls/oleaut32/vartype.c	1970-01-01 00:00:00.000000000 +0000
+++ wine-develop/dlls/oleaut32/vartype.c	2003-12-09 23:33:23.000000000 +0000
@@ -0,0 +1,6543 @@
+/*
+ * Low level variant functions
+ *
+ * Copyright 2003 Jon Griffiths
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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 NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winnt.h"
+#include "variant.h"
+#include "resource.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ole);
+
+extern HMODULE OLEAUT32_hModule;
+
+static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
+static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
+
+/* Copy data from one variant to another. */
+static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
+{
+  switch (vt)
+  {
+  case VT_I1:
+  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_R4:
+  case VT_INT:
+#ifndef _WIN64
+  case VT_INT_PTR:
+#endif
+  case VT_I4:
+  case VT_UINT:
+  case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
+  case VT_R8:
+  case VT_DATE:
+  case VT_CY:
+#ifdef _WIN64
+  case VT_INT_PTR:
+#endif
+  case VT_I8:
+  case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
+  case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
+  default:
+    FIXME("VT_ type %d unhandled, please report!\n", vt);
+  }
+}
+
+
+/* Coerce VT_BSTR to a numeric type */
+HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
+                               void* pOut, VARTYPE vt)
+{
+  VARIANTARG dstVar;
+  HRESULT hRet;
+  NUMPARSE np;
+  BYTE rgb[1024];
+
+  /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
+  np.cDig = sizeof(rgb) / sizeof(BYTE);
+  np.dwInFlags = NUMPRS_STD;
+
+  hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
+
+  if (SUCCEEDED(hRet))
+  {
+    /* 1 << vt gives us the VTBIT constant for the destination number type */
+    hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
+    if (SUCCEEDED(hRet))
+      VARIANT_CopyData(&dstVar, vt, pOut);
+  }
+  return hRet;
+}
+
+/* Coerce VT_DISPATCH to another type */
+HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
+{
+  static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
+  VARIANTARG srcVar, dstVar;
+  HRESULT hRet;
+
+  if (!pdispIn)
+    return DISP_E_BADVARTYPE;
+
+  /* Get the default 'value' property from the IDispatch */
+  hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
+                          (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL);
+
+  if (SUCCEEDED(hRet))
+  {
+    /* Convert the property to the requested type */
+    V_VT(&dstVar) = VT_EMPTY;
+    hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt);
+    VariantClear(&srcVar);
+
+    if (SUCCEEDED(hRet))
+    {
+      VARIANT_CopyData(&dstVar, vt, pOut);
+      VariantClear(&srcVar);
+    }
+  }
+  else
+    hRet = DISP_E_TYPEMISMATCH;
+  return hRet;
+}
+
+/* I1
+ */
+
+/************************************************************************
+ * VarI1FromUI1 (OLEAUT32.244)
+ *
+ * Convert a VT_UI1 to a VT_I1.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
+{
+  return _VarI1FromUI1(bIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromI2 (OLEAUT32.245)
+ *
+ * Convert a VT_I2 to a VT_I1.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
+{
+  return _VarI1FromI2(sIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromI4 (OLEAUT32.246)
+ *
+ * Convert a VT_I4 to a VT_I1.
+ *
+ * PARAMS
+ *  iIn     [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
+{
+  return _VarI1FromI4(iIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromR4 (OLEAUT32.247)
+ *
+ * Convert a VT_R4 to a VT_I1.
+ *
+ * PARAMS
+ *  fltIn   [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
+{
+  return _VarI1FromR4(fltIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromR8 (OLEAUT32.248)
+ *
+ * Convert a VT_R8 to a VT_I1.
+ *
+ * PARAMS
+ *  dblIn   [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  See VarI8FromR8() for details concerning rounding.
+ */
+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);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarI1FromDate (OLEAUT32.249)
+ *
+ * Convert a VT_DATE to a VT_I1.
+ *
+ * PARAMS
+ *  dateIn  [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
+{
+  return _VarI1FromDate(dateIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromCy (OLEAUT32.250)
+ *
+ * Convert a VT_CY to a VT_I1.
+ *
+ * PARAMS
+ *  cyIn    [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
+{
+  LONG i = I1_MAX + 1;
+
+  _VarI4FromCy(cyIn, &i);
+  return _VarI1FromI4(i, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromStr (OLEAUT32.251)
+ *
+ * Convert a VT_BSTR to a VT_I1.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
+{
+  return _VarI1FromStr(strIn, lcid, dwFlags, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromDisp (OLEAUT32.252)
+ *
+ * Convert a VT_DISPATCH to a VT_I1.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pcOut    [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
+{
+  return _VarI1FromDisp(pdispIn, lcid, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromBool (OLEAUT32.253)
+ *
+ * Convert a VT_BOOL to a VT_I1.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
+{
+  return _VarI1FromBool(boolIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromUI2 (OLEAUT32.254)
+ *
+ * Convert a VT_UI2 to a VT_I1.
+ *
+ * PARAMS
+ *  usIn    [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
+{
+  return _VarI1FromUI2(usIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromUI4 (OLEAUT32.255)
+ *
+ * Convert a VT_UI4 to a VT_I1.
+ *
+ * PARAMS
+ *  ulIn    [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
+{
+  return _VarI1FromUI4(ulIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromDec (OLEAUT32.256)
+ *
+ * Convert a VT_DECIMAL to a VT_I1.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
+{
+  LONG64 i64;
+  HRESULT hRet;
+
+  hRet = _VarI8FromDec(pdecIn, &i64);
+
+  if (SUCCEEDED(hRet))
+    hRet = _VarI1FromI8(i64, pcOut);
+  return hRet;
+}
+
+/************************************************************************
+ * VarI1FromI8 (OLEAUT32.376)
+ *
+ * Convert a VT_I8 to a VT_I1.
+ *
+ * PARAMS
+ *  llIn  [I] Source
+ *  pcOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
+{
+  return _VarI1FromI8(llIn, pcOut);
+}
+
+/************************************************************************
+ * VarI1FromUI8 (OLEAUT32.377)
+ *
+ * Convert a VT_UI8 to a VT_I1.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pcOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
+{
+  return _VarI1FromUI8(ullIn, pcOut);
+}
+
+/* UI1
+ */
+
+/************************************************************************
+ * VarUI1FromI2 (OLEAUT32.130)
+ *
+ * Convert a VT_I2 to a VT_UI1.
+ *
+ * PARAMS
+ *  sIn   [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
+{
+  return _VarUI1FromI2(sIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromI4 (OLEAUT32.131)
+ *
+ * Convert a VT_I4 to a VT_UI1.
+ *
+ * PARAMS
+ *  iIn   [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
+{
+  return _VarUI1FromI4(iIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromR4 (OLEAUT32.132)
+ *
+ * Convert a VT_R4 to a VT_UI1.
+ *
+ * PARAMS
+ *  fltIn [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
+{
+  return _VarUI1FromR4(fltIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromR8 (OLEAUT32.133)
+ *
+ * Convert a VT_R8 to a VT_UI1.
+ *
+ * PARAMS
+ *  dblIn [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  See VarI8FromR8() for details concerning rounding.
+ */
+HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
+{
+  if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
+    return DISP_E_OVERFLOW;
+  OLEAUT32_DutchRound(BYTE, dblIn, *pbOut);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarUI1FromCy (OLEAUT32.134)
+ *
+ * Convert a VT_CY to a VT_UI1.
+ *
+ * PARAMS
+ *  cyIn     [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  Negative values >= -5000 will be converted to 0.
+ */
+HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
+{
+  ULONG i = UI1_MAX + 1;
+
+  _VarUI4FromCy(cyIn, &i);
+  return _VarUI1FromUI4(i, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromDate (OLEAUT32.135)
+ *
+ * Convert a VT_DATE to a VT_UI1.
+ *
+ * PARAMS
+ *  dateIn [I] Source
+ *  pbOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
+{
+  return _VarUI1FromDate(dateIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromStr (OLEAUT32.136)
+ *
+ * Convert a VT_BSTR to a VT_UI1.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
+{
+  return _VarUI1FromStr(strIn, lcid, dwFlags, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromDisp (OLEAUT32.137)
+ *
+ * Convert a VT_DISPATCH to a VT_UI1.
+ *
+ * PARAMS
+ *  pdispIn [I] Source
+ *  lcid    [I] LCID for conversion
+ *  pbOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
+{
+  return _VarUI1FromDisp(pdispIn, lcid, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromBool (OLEAUT32.138)
+ *
+ * Convert a VT_BOOL to a VT_UI1.
+ *
+ * PARAMS
+ *  boolIn [I] Source
+ *  pbOut  [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
+{
+  return _VarUI1FromBool(boolIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromI1 (OLEAUT32.237)
+ *
+ * Convert a VT_I1 to a VT_UI1.
+ *
+ * PARAMS
+ *  cIn   [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
+{
+  return _VarUI1FromI1(cIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromUI2 (OLEAUT32.238)
+ *
+ * Convert a VT_UI2 to a VT_UI1.
+ *
+ * PARAMS
+ *  usIn  [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
+{
+  return _VarUI1FromUI2(usIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromUI4 (OLEAUT32.239)
+ *
+ * Convert a VT_UI4 to a VT_UI1.
+ *
+ * PARAMS
+ *  ulIn  [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
+{
+  return _VarUI1FromUI4(ulIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromDec (OLEAUT32.240)
+ *
+ * Convert a VT_DECIMAL to a VT_UI1.
+ *
+ * PARAMS
+ *  pDecIn [I] Source
+ *  pbOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
+{
+  LONG64 i64;
+  HRESULT hRet;
+
+  hRet = _VarI8FromDec(pdecIn, &i64);
+
+  if (SUCCEEDED(hRet))
+    hRet = _VarUI1FromI8(i64, pbOut);
+  return hRet;
+}
+
+/************************************************************************
+ * VarUI1FromI8 (OLEAUT32.372)
+ *
+ * Convert a VT_I8 to a VT_UI1.
+ *
+ * PARAMS
+ *  llIn  [I] Source
+ *  pbOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
+{
+  return _VarUI1FromI8(llIn, pbOut);
+}
+
+/************************************************************************
+ * VarUI1FromUI8 (OLEAUT32.373)
+ *
+ * Convert a VT_UI8 to a VT_UI1.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pbOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
+{
+  return _VarUI1FromUI8(ullIn, pbOut);
+}
+
+
+/* I2
+ */
+
+/************************************************************************
+ * VarI2FromUI1 (OLEAUT32.48)
+ *
+ * Convert a VT_UI2 to a VT_I2.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
+{
+  return _VarI2FromUI1(bIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromI4 (OLEAUT32.49)
+ *
+ * Convert a VT_I4 to a VT_I2.
+ *
+ * PARAMS
+ *  iIn     [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
+{
+  return _VarI2FromI4(iIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromR4 (OLEAUT32.50)
+ *
+ * Convert a VT_R4 to a VT_I2.
+ *
+ * PARAMS
+ *  fltIn   [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
+{
+  return _VarI2FromR4(fltIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromR8 (OLEAUT32.51)
+ *
+ * Convert a VT_R8 to a VT_I2.
+ *
+ * PARAMS
+ *  dblIn   [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  See VarI8FromR8() for details concerning rounding.
+ */
+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);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarI2FromCy (OLEAUT32.52)
+ *
+ * Convert a VT_CY to a VT_I2.
+ *
+ * PARAMS
+ *  cyIn    [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
+{
+  LONG i = I2_MAX + 1;
+
+  _VarI4FromCy(cyIn, &i);
+  return _VarI2FromI4(i, psOut);
+}
+
+/************************************************************************
+ * VarI2FromDate (OLEAUT32.53)
+ *
+ * Convert a VT_DATE to a VT_I2.
+ *
+ * PARAMS
+ *  dateIn  [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
+{
+  return _VarI2FromDate(dateIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromStr (OLEAUT32.54)
+ *
+ * Convert a VT_BSTR to a VT_I2.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if any parameter is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
+{
+  return _VarI2FromStr(strIn, lcid, dwFlags, psOut);
+}
+
+/************************************************************************
+ * VarI2FromDisp (OLEAUT32.55)
+ *
+ * Convert a VT_DISPATCH to a VT_I2.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  psOut    [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pdispIn is invalid,
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination,
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
+{
+  return _VarI2FromDisp(pdispIn, lcid, psOut);
+}
+
+/************************************************************************
+ * VarI2FromBool (OLEAUT32.56)
+ *
+ * Convert a VT_BOOL to a VT_I2.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
+{
+  return _VarI2FromBool(boolIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromI1 (OLEAUT32.205)
+ *
+ * Convert a VT_I1 to a VT_I2.
+ *
+ * PARAMS
+ *  cIn     [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
+{
+  return _VarI2FromI1(cIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromUI2 (OLEAUT32.206)
+ *
+ * Convert a VT_UI2 to a VT_I2.
+ *
+ * PARAMS
+ *  usIn    [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
+{
+  return _VarI2FromUI2(usIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromUI4 (OLEAUT32.207)
+ *
+ * Convert a VT_UI4 to a VT_I2.
+ *
+ * PARAMS
+ *  ulIn    [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
+{
+  return _VarI2FromUI4(ulIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromDec (OLEAUT32.208)
+ *
+ * Convert a VT_DECIMAL to a VT_I2.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  psOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
+{
+  LONG64 i64;
+  HRESULT hRet;
+
+  hRet = _VarI8FromDec(pdecIn, &i64);
+
+  if (SUCCEEDED(hRet))
+    hRet = _VarI2FromI8(i64, psOut);
+  return hRet;
+}
+
+/************************************************************************
+ * VarI2FromI8 (OLEAUT32.346)
+ *
+ * Convert a VT_I8 to a VT_I2.
+ *
+ * PARAMS
+ *  llIn  [I] Source
+ *  psOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
+{
+  return _VarI2FromI8(llIn, psOut);
+}
+
+/************************************************************************
+ * VarI2FromUI8 (OLEAUT32.347)
+ *
+ * Convert a VT_UI8 to a VT_I2.
+ *
+ * PARAMS
+ *  ullIn [I] Source
+ *  psOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
+{
+  return _VarI2FromUI8(ullIn, psOut);
+}
+
+/* UI2
+ */
+
+/************************************************************************
+ * VarUI2FromUI1 (OLEAUT32.257)
+ *
+ * Convert a VT_UI1 to a VT_UI2.
+ *
+ * PARAMS
+ *  bIn    [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
+{
+  return _VarUI2FromUI1(bIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromI2 (OLEAUT32.258)
+ *
+ * Convert a VT_I2 to a VT_UI2.
+ *
+ * PARAMS
+ *  sIn    [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
+{
+  return _VarUI2FromI2(sIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromI4 (OLEAUT32.259)
+ *
+ * Convert a VT_I4 to a VT_UI2.
+ *
+ * PARAMS
+ *  iIn    [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
+{
+  return _VarUI2FromI4(iIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromR4 (OLEAUT32.260)
+ *
+ * Convert a VT_R4 to a VT_UI2.
+ *
+ * PARAMS
+ *  fltIn  [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
+{
+  return _VarUI2FromR4(fltIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromR8 (OLEAUT32.261)
+ *
+ * Convert a VT_R8 to a VT_UI2.
+ *
+ * PARAMS
+ *  dblIn  [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  See VarI8FromR8() for details concerning rounding.
+ */
+HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
+{
+  if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
+    return DISP_E_OVERFLOW;
+  OLEAUT32_DutchRound(USHORT, dblIn, *pusOut);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarUI2FromDate (OLEAUT32.262)
+ *
+ * Convert a VT_DATE to a VT_UI2.
+ *
+ * PARAMS
+ *  dateIn [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
+{
+  return _VarUI2FromDate(dateIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromCy (OLEAUT32.263)
+ *
+ * Convert a VT_CY to a VT_UI2.
+ *
+ * PARAMS
+ *  cyIn   [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  Negative values >= -5000 will be converted to 0.
+ */
+HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
+{
+  ULONG i = UI2_MAX + 1;
+
+  _VarUI4FromCy(cyIn, &i);
+  return _VarUI2FromUI4(i, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromStr (OLEAUT32.264)
+ *
+ * Convert a VT_BSTR to a VT_UI2.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pusOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
+{
+  return _VarUI2FromStr(strIn, lcid, dwFlags, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromDisp (OLEAUT32.265)
+ *
+ * Convert a VT_DISPATCH to a VT_UI2.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pusOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
+{
+  return _VarUI2FromDisp(pdispIn, lcid, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromBool (OLEAUT32.266)
+ *
+ * Convert a VT_BOOL to a VT_UI2.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  pusOut  [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
+{
+  return _VarUI2FromBool(boolIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromI1 (OLEAUT32.267)
+ *
+ * Convert a VT_I1 to a VT_UI2.
+ *
+ * PARAMS
+ *  cIn    [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
+{
+  return _VarUI2FromI1(cIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromUI4 (OLEAUT32.268)
+ *
+ * Convert a VT_UI4 to a VT_UI2.
+ *
+ * PARAMS
+ *  ulIn   [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
+{
+  return _VarUI2FromUI4(ulIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromDec (OLEAUT32.269)
+ *
+ * Convert a VT_DECIMAL to a VT_UI2.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pusOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
+{
+  LONG64 i64;
+  HRESULT hRet;
+
+  hRet = _VarI8FromDec(pdecIn, &i64);
+
+  if (SUCCEEDED(hRet))
+    hRet = _VarUI2FromI8(i64, pusOut);
+  return hRet;
+}
+
+/************************************************************************
+ * VarUI2FromI8 (OLEAUT32.378)
+ *
+ * Convert a VT_I8 to a VT_UI2.
+ *
+ * PARAMS
+ *  llIn   [I] Source
+ *  pusOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
+{
+  return _VarUI2FromI8(llIn, pusOut);
+}
+
+/************************************************************************
+ * VarUI2FromUI8 (OLEAUT32.379)
+ *
+ * Convert a VT_UI8 to a VT_UI2.
+ *
+ * PARAMS
+ *  ullIn    [I] Source
+ *  pusOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
+{
+  return _VarUI2FromUI8(ullIn, pusOut);
+}
+
+/* I4
+ */
+
+/************************************************************************
+ * VarI4FromUI1 (OLEAUT32.58)
+ *
+ * Convert a VT_UI1 to a VT_I4.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
+{
+  return _VarI4FromUI1(bIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromI2 (OLEAUT32.59)
+ *
+ * Convert a VT_I2 to a VT_I4.
+ *
+ * PARAMS
+ *  iIn     [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
+{
+  return _VarI4FromI2(sIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromR4 (OLEAUT32.60)
+ *
+ * Convert a VT_R4 to a VT_I4.
+ *
+ * PARAMS
+ *  fltIn   [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
+{
+  return _VarI4FromR4(fltIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromR8 (OLEAUT32.61)
+ *
+ * Convert a VT_R8 to a VT_I4.
+ *
+ * PARAMS
+ *  dblIn   [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  See VarI8FromR8() for details concerning rounding.
+ */
+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);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarI4FromCy (OLEAUT32.62)
+ *
+ * Convert a VT_CY to a VT_I4.
+ *
+ * PARAMS
+ *  cyIn    [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
+{
+  double d = cyIn.int64 / CY_MULTIPLIER_F;
+  return _VarI4FromR8(d, piOut);
+}
+
+/************************************************************************
+ * VarI4FromDate (OLEAUT32.63)
+ *
+ * Convert a VT_DATE to a VT_I4.
+ *
+ * PARAMS
+ *  dateIn  [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
+{
+  return _VarI4FromDate(dateIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromStr (OLEAUT32.64)
+ *
+ * Convert a VT_BSTR to a VT_I4.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if any parameter is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if strIn cannot be converted
+ */
+HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
+{
+  return _VarI4FromStr(strIn, lcid, dwFlags, piOut);
+}
+
+/************************************************************************
+ * VarI4FromDisp (OLEAUT32.65)
+ *
+ * Convert a VT_DISPATCH to a VT_I4.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  piOut    [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
+{
+  return _VarI4FromDisp(pdispIn, lcid, piOut);
+}
+
+/************************************************************************
+ * VarI4FromBool (OLEAUT32.66)
+ *
+ * Convert a VT_BOOL to a VT_I4.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
+{
+  return _VarI4FromBool(boolIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromI1 (OLEAUT32.209)
+ *
+ * Convert a VT_I4 to a VT_I4.
+ *
+ * PARAMS
+ *  cIn     [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
+{
+  return _VarI4FromI1(cIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromUI2 (OLEAUT32.210)
+ *
+ * Convert a VT_UI2 to a VT_I4.
+ *
+ * PARAMS
+ *  usIn    [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
+{
+  return _VarI4FromUI2(usIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromUI4 (OLEAUT32.211)
+ *
+ * Convert a VT_UI4 to a VT_I4.
+ *
+ * PARAMS
+ *  ulIn    [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
+{
+  return _VarI4FromUI4(ulIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromDec (OLEAUT32.212)
+ *
+ * Convert a VT_DECIMAL to a VT_I4.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  piOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pdecIn is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
+{
+  LONG64 i64;
+  HRESULT hRet;
+
+  hRet = _VarI8FromDec(pdecIn, &i64);
+
+  if (SUCCEEDED(hRet))
+    hRet = _VarI4FromI8(i64, piOut);
+  return hRet;
+}
+
+/************************************************************************
+ * VarI4FromI8 (OLEAUT32.348)
+ *
+ * Convert a VT_I8 to a VT_I4.
+ *
+ * PARAMS
+ *  llIn  [I] Source
+ *  piOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
+{
+  return _VarI4FromI8(llIn, piOut);
+}
+
+/************************************************************************
+ * VarI4FromUI8 (OLEAUT32.349)
+ *
+ * Convert a VT_UI8 to a VT_I4.
+ *
+ * PARAMS
+ *  ullIn [I] Source
+ *  piOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
+{
+  return _VarI4FromUI8(ullIn, piOut);
+}
+
+/* UI4
+ */
+
+/************************************************************************
+ * VarUI4FromUI1 (OLEAUT32.270)
+ *
+ * Convert a VT_UI1 to a VT_UI4.
+ *
+ * PARAMS
+ *  bIn    [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
+{
+  return _VarUI4FromUI1(bIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromI2 (OLEAUT32.271)
+ *
+ * Convert a VT_I2 to a VT_UI4.
+ *
+ * PARAMS
+ *  sIn    [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
+{
+  return _VarUI4FromI2(sIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromI4 (OLEAUT32.272)
+ *
+ * Convert a VT_I4 to a VT_UI4.
+ *
+ * PARAMS
+ *  iIn    [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
+{
+  return _VarUI4FromI4(iIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromR4 (OLEAUT32.273)
+ *
+ * Convert a VT_R4 to a VT_UI4.
+ *
+ * PARAMS
+ *  fltIn  [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
+{
+  return _VarUI4FromR4(fltIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromR8 (OLEAUT32.274)
+ *
+ * Convert a VT_R8 to a VT_UI4.
+ *
+ * PARAMS
+ *  dblIn  [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  See VarI8FromR8() for details concerning rounding.
+ */
+HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
+{
+  if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
+    return DISP_E_OVERFLOW;
+  OLEAUT32_DutchRound(ULONG, dblIn, *pulOut);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarUI4FromDate (OLEAUT32.275)
+ *
+ * Convert a VT_DATE to a VT_UI4.
+ *
+ * PARAMS
+ *  dateIn [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
+{
+  return _VarUI4FromDate(dateIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromCy (OLEAUT32.276)
+ *
+ * Convert a VT_CY to a VT_UI4.
+ *
+ * PARAMS
+ *  cyIn   [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
+{
+  double d = cyIn.int64 / CY_MULTIPLIER_F;
+  return _VarUI4FromR8(d, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromStr (OLEAUT32.277)
+ *
+ * Convert a VT_BSTR to a VT_UI4.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pulOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if any parameter is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if strIn cannot be converted
+ */
+HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
+{
+  return _VarUI4FromStr(strIn, lcid, dwFlags, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromDisp (OLEAUT32.278)
+ *
+ * Convert a VT_DISPATCH to a VT_UI4.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pulOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
+{
+  return _VarUI4FromDisp(pdispIn, lcid, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromBool (OLEAUT32.279)
+ *
+ * Convert a VT_BOOL to a VT_UI4.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  pulOut  [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
+{
+  return _VarUI4FromBool(boolIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromI1 (OLEAUT32.280)
+ *
+ * Convert a VT_I1 to a VT_UI4.
+ *
+ * PARAMS
+ *  cIn    [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
+{
+  return _VarUI4FromI1(cIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromUI2 (OLEAUT32.281)
+ *
+ * Convert a VT_UI2 to a VT_UI4.
+ *
+ * PARAMS
+ *  usIn   [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
+{
+  return _VarUI4FromUI2(usIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromDec (OLEAUT32.282)
+ *
+ * Convert a VT_DECIMAL to a VT_UI4.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pulOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pdecIn is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
+{
+  LONG64 i64;
+  HRESULT hRet;
+
+  hRet = _VarI8FromDec(pdecIn, &i64);
+
+  if (SUCCEEDED(hRet))
+    hRet = _VarUI4FromI8(i64, pulOut);
+  return hRet;
+}
+
+/************************************************************************
+ * VarUI4FromI8 (OLEAUT32.425)
+ *
+ * Convert a VT_I8 to a VT_UI4.
+ *
+ * PARAMS
+ *  llIn   [I] Source
+ *  pulOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
+{
+  return _VarUI4FromI8(llIn, pulOut);
+}
+
+/************************************************************************
+ * VarUI4FromUI8 (OLEAUT32.426)
+ *
+ * Convert a VT_UI8 to a VT_UI4.
+ *
+ * PARAMS
+ *  ullIn    [I] Source
+ *  pulOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
+{
+  return _VarUI4FromUI8(ullIn, pulOut);
+}
+
+/* I8
+ */
+
+/************************************************************************
+ * VarI8FromUI1 (OLEAUT32.333)
+ *
+ * Convert a VT_UI1 to a VT_I8.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
+{
+  return _VarI8FromUI1(bIn, pi64Out);
+}
+
+
+/************************************************************************
+ * VarI8FromI2 (OLEAUT32.334)
+ *
+ * Convert a VT_I2 to a VT_I8.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
+{
+  return _VarI8FromI2(sIn, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromR4 (OLEAUT32.335)
+ *
+ * Convert a VT_R4 to a VT_I8.
+ *
+ * PARAMS
+ *  fltIn   [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
+{
+  return _VarI8FromR4(fltIn, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromR8 (OLEAUT32.336)
+ *
+ * Convert a VT_R8 to a VT_I8.
+ *
+ * PARAMS
+ *  dblIn   [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  Only values that fit into 63 bits are accepted. Due to rounding issues,
+ *  very high or low values will not be accurately converted.
+ *
+ *  Numbers are rounded using Dutch rounding, as follows:
+ *
+ *|  Fractional Part   Sign  Direction  Example
+ *|  ---------------   ----  ---------  -------
+ *|  < 0.5              +    Down        0.4 ->  0.0
+ *|  < 0.5              -    Up         -0.4 ->  0.0
+ *|  > 0.5              +    Up          0.6 ->  1.0
+ *|  < 0.5              -    Up         -0.6 -> -1.0
+ *|  = 0.5              +    Up/Down    Down if even, Up if odd
+ *|  = 0.5              -    Up/Down    Up if even, Down if odd
+ *
+ *  This system is often used in supermarkets.
+ */
+HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
+{
+  if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
+    return DISP_E_OVERFLOW;
+  OLEAUT32_DutchRound(LONG64, dblIn, *pi64Out);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarI8FromCy (OLEAUT32.337)
+ *
+ * Convert a VT_CY to a VT_I8.
+ *
+ * PARAMS
+ *  cyIn    [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ *
+ * NOTES
+ *  All negative numbers are rounded down by 1, including those that are
+ *  evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
+ *  Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
+ *  for details.
+ */
+HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
+{
+  *pi64Out = cyIn.int64 / CY_MULTIPLIER;
+
+  if (cyIn.int64 < 0)
+    (*pi64Out)--; /* Mimic Win32 bug */
+  else
+  {
+    cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
+
+    if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
+      (*pi64Out)++;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * VarI8FromDate (OLEAUT32.338)
+ *
+ * Convert a VT_DATE to a VT_I8.
+ *
+ * PARAMS
+ *  dateIn  [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
+{
+  return _VarI8FromDate(dateIn, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromStr (OLEAUT32.339)
+ *
+ * Convert a VT_BSTR to a VT_I8.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
+{
+  return _VarI8FromStr(strIn, lcid, dwFlags, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromDisp (OLEAUT32.340)
+ *
+ * Convert a VT_DISPATCH to a VT_I8.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pi64Out  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
+{
+  return _VarI8FromDisp(pdispIn, lcid, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromBool (OLEAUT32.341)
+ *
+ * Convert a VT_BOOL to a VT_I8.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
+{
+  return _VarI8FromBool(boolIn, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromI1 (OLEAUT32.342)
+ *
+ * Convert a VT_I1 to a VT_I8.
+ *
+ * PARAMS
+ *  cIn     [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
+{
+  return _VarI8FromI1(cIn, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromUI2 (OLEAUT32.343)
+ *
+ * Convert a VT_UI2 to a VT_I8.
+ *
+ * PARAMS
+ *  usIn    [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
+{
+  return _VarI8FromUI2(usIn, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromUI4 (OLEAUT32.344)
+ *
+ * Convert a VT_UI4 to a VT_I8.
+ *
+ * PARAMS
+ *  ulIn    [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
+{
+  return _VarI8FromUI4(ulIn, pi64Out);
+}
+
+/************************************************************************
+ * VarI8FromDec (OLEAUT32.345)
+ *
+ * Convert a VT_DECIMAL to a VT_I8.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
+{
+  if (!DEC_SCALE(pdecIn))
+  {
+    /* This decimal is just a 96 bit integer */
+    if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
+      return E_INVALIDARG;
+
+    if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
+      return DISP_E_OVERFLOW;
+
+    if (DEC_SIGN(pdecIn))
+      *pi64Out = -DEC_LO64(pdecIn);
+    else
+      *pi64Out = DEC_LO64(pdecIn);
+    return S_OK;
+  }
+  else
+  {
+    /* Decimal contains a floating point number */
+    HRESULT hRet;
+    double dbl;
+
+    hRet = _VarR8FromDec(pdecIn, &dbl);
+    if (SUCCEEDED(hRet))
+      hRet = VarI8FromR8(dbl, pi64Out);
+    return hRet;
+  }
+}
+
+/************************************************************************
+ * VarI8FromUI8 (OLEAUT32.427)
+ *
+ * Convert a VT_UI8 to a VT_I8.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pi64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
+{
+  return _VarI8FromUI8(ullIn, pi64Out);
+}
+
+/* UI8
+ */
+
+/************************************************************************
+ * VarUI8FromI8 (OLEAUT32.428)
+ *
+ * Convert a VT_I8 to a VT_UI8.
+ *
+ * PARAMS
+ *  ulIn     [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromI8(llIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromUI1 (OLEAUT32.429)
+ *
+ * Convert a VT_UI1 to a VT_UI8.
+ *
+ * PARAMS
+ *  bIn      [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromUI1(bIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromI2 (OLEAUT32.430)
+ *
+ * Convert a VT_I2 to a VT_UI8.
+ *
+ * PARAMS
+ *  sIn      [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromI2(sIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromR4 (OLEAUT32.431)
+ *
+ * Convert a VT_R4 to a VT_UI8.
+ *
+ * PARAMS
+ *  fltIn    [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromR4(fltIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromR8 (OLEAUT32.432)
+ *
+ * Convert a VT_R8 to a VT_UI8.
+ *
+ * PARAMS
+ *  dblIn    [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  See VarI8FromR8() for details concerning rounding.
+ */
+HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
+{
+  if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
+    return DISP_E_OVERFLOW;
+  OLEAUT32_DutchRound(ULONG64, dblIn, *pui64Out);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarUI8FromCy (OLEAUT32.433)
+ *
+ * Convert a VT_CY to a VT_UI8.
+ *
+ * PARAMS
+ *  cyIn     [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  Negative values >= -5000 will be converted to 0.
+ */
+HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
+{
+  if (cyIn.int64 < 0)
+  {
+    if (cyIn.int64 < -CY_HALF)
+      return DISP_E_OVERFLOW;
+    *pui64Out = 0;
+  }
+  else
+  {
+    *pui64Out = cyIn.int64 / CY_MULTIPLIER;
+
+    cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
+
+    if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
+      (*pui64Out)++;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * VarUI8FromDate (OLEAUT32.434)
+ *
+ * Convert a VT_DATE to a VT_UI8.
+ *
+ * PARAMS
+ *  dateIn   [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromDate(dateIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromStr (OLEAUT32.435)
+ *
+ * Convert a VT_BSTR to a VT_UI8.
+ *
+ * PARAMS
+ *  strIn    [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
+{
+  return _VarUI8FromStr(strIn, lcid, dwFlags, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromDisp (OLEAUT32.436)
+ *
+ * Convert a VT_DISPATCH to a VT_UI8.
+ *
+ * PARAMS
+ *  pdispIn   [I] Source
+ *  lcid      [I] LCID for conversion
+ *  pui64Out  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
+{
+  return _VarUI8FromDisp(pdispIn, lcid, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromBool (OLEAUT32.437)
+ *
+ * Convert a VT_BOOL to a VT_UI8.
+ *
+ * PARAMS
+ *  boolIn   [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromBool(boolIn, pui64Out);
+}
+/************************************************************************
+ * VarUI8FromI1 (OLEAUT32.438)
+ *
+ * Convert a VT_I1 to a VT_UI8.
+ *
+ * PARAMS
+ *  cIn      [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromI1(cIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromUI2 (OLEAUT32.439)
+ *
+ * Convert a VT_UI2 to a VT_UI8.
+ *
+ * PARAMS
+ *  usIn     [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromUI2(usIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromUI4 (OLEAUT32.440)
+ *
+ * Convert a VT_UI4 to a VT_UI8.
+ *
+ * PARAMS
+ *  ulIn     [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
+{
+  return _VarUI8FromUI4(ulIn, pui64Out);
+}
+
+/************************************************************************
+ * VarUI8FromDec (OLEAUT32.441)
+ *
+ * Convert a VT_DECIMAL to a VT_UI8.
+ *
+ * PARAMS
+ *  pDecIn   [I] Source
+ *  pui64Out [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *
+ * NOTES
+ *  Under native Win32, if the source value has a scale of 0, its sign is
+ *  ignored, i.e. this function takes the absolute value rather than fail
+ *  with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
+ *  (use VarAbs() on pDecIn first if you really want this behaviour).
+ */
+HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
+{
+  if (!DEC_SCALE(pdecIn))
+  {
+    /* This decimal is just a 96 bit integer */
+    if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
+      return E_INVALIDARG;
+
+    if (DEC_HI32(pdecIn))
+      return DISP_E_OVERFLOW;
+
+    if (DEC_SIGN(pdecIn))
+    {
+      WARN("Sign would be ignored under Win32!\n");
+      return DISP_E_OVERFLOW;
+    }
+
+    *pui64Out = DEC_LO64(pdecIn);
+    return S_OK;
+  }
+  else
+  {
+    /* Decimal contains a floating point number */
+    HRESULT hRet;
+    double dbl;
+
+    hRet = _VarR8FromDec(pdecIn, &dbl);
+    if (SUCCEEDED(hRet))
+      hRet = VarUI8FromR8(dbl, pui64Out);
+    return hRet;
+  }
+}
+
+/* R4
+ */
+
+/************************************************************************
+ * VarR4FromUI1 (OLEAUT32.68)
+ *
+ * Convert a VT_UI1 to a VT_R4.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
+{
+  return _VarR4FromUI1(bIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromI2 (OLEAUT32.69)
+ *
+ * Convert a VT_I2 to a VT_R4.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
+{
+  return _VarR4FromI2(sIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromI4 (OLEAUT32.70)
+ *
+ * Convert a VT_I4 to a VT_R4.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
+{
+  return _VarR4FromI4(lIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromR8 (OLEAUT32.71)
+ *
+ * Convert a VT_R8 to a VT_R4.
+ *
+ * PARAMS
+ *  dblIn   [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
+ */
+HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
+{
+  return _VarR4FromR8(dblIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromCy (OLEAUT32.72)
+ *
+ * Convert a VT_CY to a VT_R4.
+ *
+ * PARAMS
+ *  cyIn    [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
+{
+  return _VarR4FromCy(cyIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromDate (OLEAUT32.73)
+ *
+ * Convert a VT_DATE to a VT_R4.
+ *
+ * PARAMS
+ *  dateIn  [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
+ */
+HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
+{
+  return _VarR4FromDate(dateIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromStr (OLEAUT32.74)
+ *
+ * Convert a VT_BSTR to a VT_R4.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
+{
+  return _VarR4FromStr(strIn, lcid, dwFlags, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromDisp (OLEAUT32.75)
+ *
+ * Convert a VT_DISPATCH to a VT_R4.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pFltOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
+{
+  return _VarR4FromDisp(pdispIn, lcid, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromBool (OLEAUT32.76)
+ *
+ * Convert a VT_BOOL to a VT_R4.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
+{
+  return _VarR4FromBool(boolIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromI1 (OLEAUT32.213)
+ *
+ * Convert a VT_I1 to a VT_R4.
+ *
+ * PARAMS
+ *  cIn     [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
+{
+  return _VarR4FromI1(cIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromUI2 (OLEAUT32.214)
+ *
+ * Convert a VT_UI2 to a VT_R4.
+ *
+ * PARAMS
+ *  usIn    [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
+{
+  return _VarR4FromUI2(usIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromUI4 (OLEAUT32.215)
+ *
+ * Convert a VT_UI4 to a VT_R4.
+ *
+ * PARAMS
+ *  ulIn    [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
+{
+  return _VarR4FromUI4(ulIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromDec (OLEAUT32.216)
+ *
+ * Convert a VT_DECIMAL to a VT_R4.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid.
+ */
+HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
+{
+  BYTE scale = DEC_SCALE(pDecIn);
+  int divisor = 1;
+  double highPart;
+
+  if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
+    return E_INVALIDARG;
+
+  while (scale--)
+    divisor *= 10;
+
+  if (DEC_SIGN(pDecIn))
+    divisor = -divisor;
+
+  if (DEC_HI32(pDecIn))
+  {
+    highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
+    highPart *= 1.0e64;
+  }
+  else
+    highPart = 0.0;
+
+  *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarR4FromI8 (OLEAUT32.360)
+ *
+ * Convert a VT_I8 to a VT_R4.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
+{
+  return _VarR4FromI8(llIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4FromUI8 (OLEAUT32.361)
+ *
+ * Convert a VT_UI8 to a VT_R4.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pFltOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
+{
+  return _VarR4FromUI8(ullIn, pFltOut);
+}
+
+/************************************************************************
+ * VarR4CmpR8 (OLEAUT32.316)
+ *
+ * Compare a VT_R4 to a VT_R8.
+ *
+ * PARAMS
+ *  fltLeft  [I] Source
+ *  dblRight [I] Value to compare
+ *
+ * RETURNS
+ *  VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
+ *  equal to or greater than dblRight respectively.
+ */
+HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
+{
+  if (fltLeft < dblRight)
+    return VARCMP_LT;
+  else if (fltLeft > dblRight)
+    return VARCMP_GT;
+  return VARCMP_EQ;
+}
+
+/* R8
+ */
+
+/************************************************************************
+ * VarR8FromUI1 (OLEAUT32.78)
+ *
+ * Convert a VT_UI1 to a VT_R8.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
+{
+  return _VarR8FromUI1(bIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromI2 (OLEAUT32.79)
+ *
+ * Convert a VT_I2 to a VT_R8.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
+{
+  return _VarR8FromI2(sIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromI4 (OLEAUT32.80)
+ *
+ * Convert a VT_I4 to a VT_R8.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
+{
+  return _VarR8FromI4(lIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromR4 (OLEAUT32.81)
+ *
+ * Convert a VT_R4 to a VT_R8.
+ *
+ * PARAMS
+ *  fltIn   [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
+{
+  return _VarR8FromR4(fltIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromCy (OLEAUT32.82)
+ *
+ * Convert a VT_CY to a VT_R8.
+ *
+ * PARAMS
+ *  cyIn    [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
+{
+  return _VarR8FromCy(cyIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromDate (OLEAUT32.83)
+ *
+ * Convert a VT_DATE to a VT_R8.
+ *
+ * PARAMS
+ *  dateIn  [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
+{
+  return _VarR8FromDate(dateIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromStr (OLEAUT32.84)
+ *
+ * Convert a VT_BSTR to a VT_R8.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
+{
+  return _VarR8FromStr(strIn, lcid, dwFlags, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromDisp (OLEAUT32.85)
+ *
+ * Convert a VT_DISPATCH to a VT_R8.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pDblOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
+{
+  return _VarR8FromDisp(pdispIn, lcid, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromBool (OLEAUT32.86)
+ *
+ * Convert a VT_BOOL to a VT_R8.
+ *
+ * PARAMS
+ *  boolIn  [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
+{
+  return _VarR8FromBool(boolIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromI1 (OLEAUT32.217)
+ *
+ * Convert a VT_I1 to a VT_R8.
+ *
+ * PARAMS
+ *  cIn     [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
+{
+  return _VarR8FromI1(cIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromUI2 (OLEAUT32.218)
+ *
+ * Convert a VT_UI2 to a VT_R8.
+ *
+ * PARAMS
+ *  usIn    [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
+{
+  return _VarR8FromUI2(usIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromUI4 (OLEAUT32.219)
+ *
+ * Convert a VT_UI4 to a VT_R8.
+ *
+ * PARAMS
+ *  ulIn    [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
+{
+  return _VarR8FromUI4(ulIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromDec (OLEAUT32.220)
+ *
+ * Convert a VT_DECIMAL to a VT_R8.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid.
+ */
+HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
+{
+  BYTE scale = DEC_SCALE(pDecIn);
+  double divisor = 1.0, highPart;
+
+  if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
+    return E_INVALIDARG;
+
+  while (scale--)
+    divisor *= 10;
+
+  if (DEC_SIGN(pDecIn))
+    divisor = -divisor;
+
+  if (DEC_HI32(pDecIn))
+  {
+    highPart = (double)DEC_HI32(pDecIn) / divisor;
+    highPart *= 1.0e64;
+  }
+  else
+    highPart = 0.0;
+
+  *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarR8FromI8 (OLEAUT32.362)
+ *
+ * Convert a VT_I8 to a VT_R8.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
+{
+  return _VarR8FromI8(llIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8FromUI8 (OLEAUT32.363)
+ *
+ * Convert a VT_UI8 to a VT_R8.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
+{
+  return _VarR8FromUI8(ullIn, pDblOut);
+}
+
+/************************************************************************
+ * VarR8Pow (OLEAUT32.315)
+ *
+ * Raise a VT_R8 to a power.
+ *
+ * PARAMS
+ *  dblLeft [I] Source
+ *  dblPow  [I] Power to raise dblLeft by
+ *  pDblOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK. pDblOut contains dblLeft to the power of dblRight.
+ */
+HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
+{
+  *pDblOut = pow(dblLeft, dblPow);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarR8Round (OLEAUT32.317)
+ *
+ * Round a VT_R8 to a given number of decimal points.
+ *
+ * PARAMS
+ *  dblIn   [I] Source
+ *  nDig    [I] Number of decimal points to round to
+ *  pDblOut [O] Destination for rounded number
+ *
+ * RETURNS
+ *  Success: S_OK. pDblOut is rounded to nDig digits.
+ *  Failure: E_INVALIDARG, if cDecimals is less than 0.
+ *
+ * NOTES
+ *  The native version of this function rounds using the internal
+ *  binary representation of the number. Wine uses the dutch rounding
+ *  convention, so therefore small differences can occur in the value returned.
+ *  MSDN says that you should use your own rounding function if you want
+ *  rounding to be predictable in your application.
+ */
+HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
+{
+  double scale, whole, fract;
+
+  if (nDig < 0)
+    return E_INVALIDARG;
+
+  scale = pow(10.0, nDig);
+
+  dblIn *= scale;
+  whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
+  fract = dblIn - whole;
+
+  if (fract > 0.5)
+    dblIn = whole + 1.0;
+  else if (fract == 0.5)
+    dblIn = whole + fmod(whole, 2.0);
+  else if (fract >= 0.0)
+    dblIn = whole;
+  else if (fract == -0.5)
+    dblIn = whole - fmod(whole, 2.0);
+  else if (fract > -0.5)
+    dblIn = whole;
+  else
+    dblIn = whole - 1.0;
+
+  *pDblOut = dblIn / scale;
+  return S_OK;
+}
+
+/* CY
+ */
+
+/* Powers of 10 from 0..4 D.P. */
+static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
+  CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
+
+/************************************************************************
+ * VarCyFromUI1 (OLEAUT32.98)
+ *
+ * Convert a VT_UI1 to a VT_CY.
+ *
+ * PARAMS
+ *  bIn    [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
+{
+  return _VarCyFromUI1(bIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromI2 (OLEAUT32.99)
+ *
+ * Convert a VT_I2 to a VT_CY.
+ *
+ * PARAMS
+ *  sIn    [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
+{
+  return _VarCyFromI2(sIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromI4 (OLEAUT32.100)
+ *
+ * Convert a VT_I4 to a VT_CY.
+ *
+ * PARAMS
+ *  sIn    [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
+{
+  return _VarCyFromI4(lIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromR4 (OLEAUT32.101)
+ *
+ * Convert a VT_R4 to a VT_CY.
+ *
+ * PARAMS
+ *  fltIn  [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
+{
+  return _VarCyFromR4(fltIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromR8 (OLEAUT32.102)
+ *
+ * Convert a VT_R8 to a VT_CY.
+ *
+ * PARAMS
+ *  dblIn  [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
+{
+#if defined(__GNUC__) && defined(__i386__)
+  /* This code gives identical results to Win32 on Intel.
+   * Here we use fp exceptions to catch overflows when storing the value.
+   */
+  static const unsigned short r8_fpcontrol = 0x137f;
+  static const double r8_multiplier = CY_MULTIPLIER_F;
+  unsigned short old_fpcontrol, result_fpstatus;
+
+  /* Clear exceptions, save the old fp state and load the new state */
+  __asm__ __volatile__( "fnclex" );
+  __asm__ __volatile__( "fstcw %0"   :   "=m" (old_fpcontrol) : );
+  __asm__ __volatile__( "fldcw %0"   : : "m"  (r8_fpcontrol) );
+  /* Perform the conversion. */
+  __asm__ __volatile__( "fldl  %0"   : : "m"  (dblIn) );
+  __asm__ __volatile__( "fmull %0"   : : "m"  (r8_multiplier) );
+  __asm__ __volatile__( "fistpll %0" : : "m"  (*pCyOut) );
+  /* Save the resulting fp state, load the old state and clear exceptions */
+  __asm__ __volatile__( "fstsw %0"   :   "=m" (result_fpstatus) : );
+  __asm__ __volatile__( "fnclex" );
+  __asm__ __volatile__( "fldcw %0"   : : "m"  (old_fpcontrol) );
+
+  if (result_fpstatus & 0x9) /* Overflow | Invalid */
+    return DISP_E_OVERFLOW;
+  return S_OK;
+#else
+  /* This version produces slightly different results for boundary cases */
+  if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
+    return DISP_E_OVERFLOW;
+  dblIn *= CY_MULTIPLIER_F;
+  OLEAUT32_DutchRound(LONG64, dblIn, pCyOut->int64);
+#endif
+  return S_OK;
+}
+
+/************************************************************************
+ * VarCyFromDate (OLEAUT32.103)
+ *
+ * Convert a VT_DATE to a VT_CY.
+ *
+ * PARAMS
+ *  dateIn [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
+{
+  return _VarCyFromDate(dateIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromStr (OLEAUT32.104)
+ *
+ * Convert a VT_BSTR to a VT_CY.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
+{
+  return _VarCyFromStr(strIn, lcid, dwFlags, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromDisp (OLEAUT32.105)
+ *
+ * Convert a VT_DISPATCH to a VT_CY.
+ *
+ * PARAMS
+ *  pdispIn [I] Source
+ *  lcid    [I] LCID for conversion
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
+{
+  return _VarCyFromDisp(pdispIn, lcid, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromBool (OLEAUT32.106)
+ *
+ * Convert a VT_BOOL to a VT_CY.
+ *
+ * PARAMS
+ *  boolIn [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ *
+ * NOTES
+ *  While the sign of the boolean is stored in the currency, the value is
+ *  converted to either 0 or 1.
+ */
+HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
+{
+  return _VarCyFromBool(boolIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromI1 (OLEAUT32.225)
+ *
+ * Convert a VT_I1 to a VT_CY.
+ *
+ * PARAMS
+ *  cIn    [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
+{
+  return _VarCyFromI1(cIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromUI2 (OLEAUT32.226)
+ *
+ * Convert a VT_UI2 to a VT_CY.
+ *
+ * PARAMS
+ *  usIn   [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
+{
+  return _VarCyFromUI2(usIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromUI4 (OLEAUT32.227)
+ *
+ * Convert a VT_UI4 to a VT_CY.
+ *
+ * PARAMS
+ *  ulIn   [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
+{
+  return _VarCyFromUI4(ulIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromDec (OLEAUT32.228)
+ *
+ * Convert a VT_DECIMAL to a VT_CY.
+ *
+ * PARAMS
+ *  pdecIn  [I] Source
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
+{
+  DECIMAL rounded;
+  HRESULT hRet;
+
+  hRet = VarDecRound(pdecIn, 4, &rounded);
+
+  if (SUCCEEDED(hRet))
+  {
+    double d;
+
+    if (DEC_HI32(&rounded))
+      return DISP_E_OVERFLOW;
+
+    /* Note: Without the casts this promotes to int64 which loses precision */
+    d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
+    if (DEC_SIGN(&rounded))
+      d = -d;
+    return _VarCyFromR8(d, pCyOut);
+  }
+  return hRet;
+}
+
+/************************************************************************
+ * VarCyFromI8 (OLEAUT32.366)
+ *
+ * Convert a VT_I8 to a VT_CY.
+ *
+ * PARAMS
+ *  ullIn  [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
+{
+  return _VarCyFromI8(llIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyFromUI8 (OLEAUT32.375)
+ *
+ * Convert a VT_UI8 to a VT_CY.
+ *
+ * PARAMS
+ *  ullIn  [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
+{
+  return _VarCyFromUI8(ullIn, pCyOut);
+}
+
+/************************************************************************
+ * VarCyAdd (OLEAUT32.299)
+ *
+ * Add one CY to another.
+ *
+ * PARAMS
+ *  cyLeft  [I] Source
+ *  cyRight [I] Value to add
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
+{
+  double l,r;
+  _VarR8FromCy(cyLeft, &l);
+  _VarR8FromCy(cyRight, &r);
+  l = l + r;
+  return _VarCyFromR8(l, pCyOut);
+}
+
+/************************************************************************
+ * VarCyMul (OLEAUT32.303)
+ *
+ * Multiply one CY by another.
+ *
+ * PARAMS
+ *  cyLeft  [I] Source
+ *  cyRight [I] Value to multiply by
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
+{
+  double l,r;
+  _VarR8FromCy(cyLeft, &l);
+  _VarR8FromCy(cyRight, &r);
+  l = l * r;
+  return _VarCyFromR8(l, pCyOut);
+}
+
+/************************************************************************
+ * VarCyMulI4 (OLEAUT32.304)
+ *
+ * Multiply one CY by a VT_I4.
+ *
+ * PARAMS
+ *  cyLeft  [I] Source
+ *  lRight  [I] Value to multiply by
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
+{
+  double d;
+
+  _VarR8FromCy(cyLeft, &d);
+  d = d * lRight;
+  return _VarCyFromR8(d, pCyOut);
+}
+
+/************************************************************************
+ * VarCySub (OLEAUT32.305)
+ *
+ * Subtract one CY from another.
+ *
+ * PARAMS
+ *  cyLeft  [I] Source
+ *  cyRight [I] Value to subtract
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
+{
+  double l,r;
+  _VarR8FromCy(cyLeft, &l);
+  _VarR8FromCy(cyRight, &r);
+  l = l - r;
+  return _VarCyFromR8(l, pCyOut);
+}
+
+/************************************************************************
+ * VarCyAbs (OLEAUT32.306)
+ *
+ * Convert a VT_CY into its absolute value.
+ *
+ * PARAMS
+ *  cyIn   [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK. pCyOut contains the absolute value.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
+{
+  if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
+    return DISP_E_OVERFLOW;
+
+  pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarCyFix (OLEAUT32.307)
+ *
+ * Return the integer part of a VT_CY.
+ *
+ * PARAMS
+ *  cyIn   [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
+{
+  pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
+  pCyOut->int64 *= CY_MULTIPLIER;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarCyInt (OLEAUT32.308)
+ *
+ * Return the integer part of a VT_CY.
+ *
+ * PARAMS
+ *  cyIn   [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
+{
+  double d;
+
+  _VarR8FromCy(cyIn, &d);
+  d = floor(d) * CY_MULTIPLIER_F;
+  OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64);
+  return S_OK;
+}
+
+/************************************************************************
+ * VarCyNeg (OLEAUT32.309)
+ *
+ * Change the sign of a VT_CY.
+ *
+ * PARAMS
+ *  cyIn   [I] Source
+ *  pCyOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
+{
+  if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
+    return DISP_E_OVERFLOW;
+
+  pCyOut->int64 = -cyIn.int64;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarCyRound (OLEAUT32.310)
+ *
+ * Change the precision of a VT_CY.
+ *
+ * PARAMS
+ *  cyIn      [I] Source
+ *  cDecimals [I] New number of decimals to keep
+ *  pCyOut    [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if cDecimals is less than 0.
+ */
+HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
+{
+  if (cDecimals < 0)
+    return E_INVALIDARG;
+
+  if (cDecimals > 3)
+  {
+    /* Rounding to more precision than we have */
+    *pCyOut = cyIn;
+    return S_OK;
+  }
+  else
+  {
+    double d, div = CY_Divisors[cDecimals];
+
+    _VarR8FromCy(cyIn, &d);
+    d = d * div;
+    OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64)
+    d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
+    OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64)
+    return S_OK;
+  }
+}
+
+/************************************************************************
+ * VarCyCmp (OLEAUT32.311)
+ *
+ * Compare two VT_CY values.
+ *
+ * PARAMS
+ *  cyLeft  [I] Source
+ *  cyRight [I] Value to compare
+ *
+ * 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
+ */
+HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
+{
+  HRESULT hRet;
+  CY result;
+
+  /* Subtract right from left, and compare the result to 0 */
+  hRet = VarCySub(cyLeft, cyRight, &result);
+
+  if (SUCCEEDED(hRet))
+  {
+    if (result.int64 < 0)
+      hRet = (HRESULT)VARCMP_LT;
+    else if (result.int64 > 0)
+      hRet = (HRESULT)VARCMP_GT;
+    else
+      hRet = (HRESULT)VARCMP_EQ;
+  }
+  return hRet;
+}
+
+/************************************************************************
+ * VarCyCmpR8 (OLEAUT32.312)
+ *
+ * Compare a VT_CY to a double
+ *
+ * PARAMS
+ *  cyLeft   [I] Currency Source
+ *  dblRight [I] double to compare to cyLeft
+ *
+ * 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
+ */
+HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
+{
+  HRESULT hRet;
+  CY cyRight;
+
+  hRet = _VarCyFromR8(dblRight, &cyRight);
+
+  if (SUCCEEDED(hRet))
+    hRet = VarCyCmp(cyLeft, cyRight);
+
+  return hRet;
+}
+
+/************************************************************************
+ * VarCyMulI8 (OLEAUT32.329)
+ *
+ * Multiply a VT_CY by a VT_I8.
+ *
+ * PARAMS
+ *  cyLeft  [I] Source
+ *  llRight [I] Value to multiply by
+ *  pCyOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
+{
+  double d;
+
+  _VarR8FromCy(cyLeft, &d);
+  d = d  * (double)llRight;
+  return _VarCyFromR8(d, pCyOut);
+}
+
+/* DECIMAL
+ */
+
+/************************************************************************
+ * VarDecFromUI1 (OLEAUT32.190)
+ *
+ * Convert a VT_UI1 to a DECIMAL.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
+{
+  return _VarDecFromUI1(bIn, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromI2 (OLEAUT32.191)
+ *
+ * Convert a VT_I2 to a DECIMAL.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
+{
+  return _VarDecFromI2(sIn, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromI4 (OLEAUT32.192)
+ *
+ * Convert a VT_I4 to a DECIMAL.
+ *
+ * PARAMS
+ *  sIn     [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
+{
+  DEC_HI32(pDecOut) = 0;
+  DEC_MID32(pDecOut) = 0;
+
+  if (lIn < 0)
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
+    DEC_LO32(pDecOut) = -lIn;
+  }
+  else
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
+    DEC_LO32(pDecOut) = lIn;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * VarDecFromR4 (OLEAUT32.193)
+ *
+ * Convert a VT_R4 to a DECIMAL.
+ *
+ * PARAMS
+ *  fltIn   [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
+{
+  WCHAR buff[256];
+
+  sprintfW( buff, szFloatFormatW, fltIn );
+  return _VarDecFromStr(buff, LOCALE_SYSTEM_DEFAULT, 0, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromR8 (OLEAUT32.194)
+ *
+ * Convert a VT_R8 to a DECIMAL.
+ *
+ * PARAMS
+ *  dblIn   [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
+{
+  WCHAR buff[256];
+
+  sprintfW( buff, szDoubleFormatW, dblIn );
+  return _VarDecFromStr(buff, LOCALE_USER_DEFAULT, 0, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromDate (OLEAUT32.195)
+ *
+ * Convert a VT_DATE to a DECIMAL.
+ *
+ * PARAMS
+ *  dateIn  [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
+{
+  return _VarDecFromDate(dateIn, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromCy (OLEAUT32.196)
+ *
+ * Convert a VT_CY to a DECIMAL.
+ *
+ * PARAMS
+ *  cyIn    [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
+{
+  DEC_HI32(pDecOut) = 0;
+
+  /* Note: This assumes 2s complement integer representation */
+  if (cyIn.s.Hi & 0x80000000)
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
+    DEC_LO64(pDecOut) = -cyIn.int64;
+  }
+  else
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
+    DEC_MID32(pDecOut) = cyIn.s.Hi;
+    DEC_LO32(pDecOut) = cyIn.s.Lo;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * VarDecFromStr (OLEAUT32.197)
+ *
+ * Convert a VT_BSTR to a DECIMAL.
+ *
+ * PARAMS
+ *  strIn   [I] Source
+ *  lcid    [I] LCID for the conversion
+ *  dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
+{
+  return _VarDecFromStr(strIn, lcid, dwFlags, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromDisp (OLEAUT32.198)
+ *
+ * Convert a VT_DISPATCH to a DECIMAL.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pDecOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
+{
+  return _VarDecFromDisp(pdispIn, lcid, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromBool (OLEAUT32.199)
+ *
+ * Convert a VT_BOOL to a DECIMAL.
+ *
+ * PARAMS
+ *  bIn     [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ *
+ * NOTES
+ *  The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
+ */
+HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
+{
+  DEC_HI32(pDecOut) = 0;
+  DEC_MID32(pDecOut) = 0;
+  if (bIn)
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
+    DEC_LO32(pDecOut) = 1;
+  }
+  else
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
+    DEC_LO32(pDecOut) = 0;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * VarDecFromI1 (OLEAUT32.241)
+ *
+ * Convert a VT_I1 to a DECIMAL.
+ *
+ * PARAMS
+ *  cIn     [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
+{
+  return _VarDecFromI1(cIn, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromUI2 (OLEAUT32.242)
+ *
+ * Convert a VT_UI2 to a DECIMAL.
+ *
+ * PARAMS
+ *  usIn    [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
+{
+  return _VarDecFromUI2(usIn, pDecOut);
+}
+
+/************************************************************************
+ * VarDecFromUI4 (OLEAUT32.243)
+ *
+ * Convert a VT_UI4 to a DECIMAL.
+ *
+ * PARAMS
+ *  ulIn    [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
+{
+  DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
+  DEC_HI32(pDecOut) = 0;
+  DEC_MID32(pDecOut) = 0;
+  DEC_LO32(pDecOut) = ulIn;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarDecFromI8 (OLEAUT32.374)
+ *
+ * Convert a VT_I8 to a DECIMAL.
+ *
+ * PARAMS
+ *  llIn    [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
+{
+  PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
+
+  DEC_HI32(pDecOut) = 0;
+
+  /* Note: This assumes 2s complement integer representation */
+  if (pLi->s.HighPart & 0x80000000)
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
+    DEC_LO64(pDecOut) = -pLi->QuadPart;
+  }
+  else
+  {
+    DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
+    DEC_MID32(pDecOut) = pLi->s.HighPart;
+    DEC_LO32(pDecOut) = pLi->s.LowPart;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * VarDecFromUI8 (OLEAUT32.375)
+ *
+ * Convert a VT_UI8 to a DECIMAL.
+ *
+ * PARAMS
+ *  ullIn   [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
+{
+  DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
+  DEC_HI32(pDecOut) = 0;
+  DEC_LO64(pDecOut) = ullIn;
+  return S_OK;
+}
+
+/* Make two DECIMALS the same scale; used by math functions below */
+static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
+                                const DECIMAL** ppDecRight,
+                                DECIMAL* pDecOut)
+{
+  static DECIMAL scaleFactor;
+  DECIMAL decTemp;
+  int scaleAmount, i;
+  HRESULT hRet = S_OK;
+
+  if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
+    return E_INVALIDARG;
+
+  DEC_LO32(&scaleFactor) = 10;
+
+  i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
+
+  if (!scaleAmount)
+    return S_OK; /* Same scale */
+
+  if (scaleAmount > 0)
+  {
+    decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
+    *ppDecRight = pDecOut;
+  }
+  else
+  {
+    decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
+    *ppDecLeft = pDecOut;
+    i = scaleAmount = -scaleAmount;
+  }
+
+  if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
+    return DISP_E_OVERFLOW; /* Can't scale up */
+
+  /* Multiply up the value to be scaled by the correct amount */
+  while (SUCCEEDED(hRet) && i--)
+  {
+    /* Note we are multiplying by a value with a scale of 0, so we dont recurse */
+    hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
+    decTemp = *pDecOut;
+  }
+  DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
+  return hRet;
+}
+
+/* Add two unsigned 32 bit values with overflow */
+static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
+{
+  ULARGE_INTEGER ul64;
+
+  ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
+  *pulHigh = ul64.s.HighPart;
+  return ul64.s.LowPart;
+}
+
+/* Subtract two unsigned 32 bit values with underflow */
+static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
+{
+  int invert = 0;
+  ULARGE_INTEGER ul64;
+
+  ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
+  if (ulLeft < ulRight)
+    invert = 1;
+
+  if (ul64.QuadPart > (ULONG64)*pulHigh)
+    ul64.QuadPart -= (ULONG64)*pulHigh;
+  else
+  {
+    ul64.QuadPart -= (ULONG64)*pulHigh;
+    invert = 1;
+  }
+  if (invert)
+    ul64.s.HighPart = -ul64.s.HighPart ;
+
+  *pulHigh = ul64.s.HighPart;
+  return ul64.s.LowPart;
+}
+
+/* Multiply two unsigned 32 bit values with overflow */
+static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
+{
+  ULARGE_INTEGER ul64;
+
+  ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
+  *pulHigh = ul64.s.HighPart;
+  return ul64.s.LowPart;
+}
+
+/* Compare two decimals that have the same scale */
+static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
+{
+  if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
+      (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
+    return -1;
+  else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
+    return 0;
+  return 1;
+}
+
+/************************************************************************
+ * VarDecAdd (OLEAUT32.177)
+ *
+ * Add one DECIMAL to another.
+ *
+ * PARAMS
+ *  pDecLeft  [I] Source
+ *  pDecRight [I] Value to add
+ *  pDecOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
+{
+  HRESULT hRet;
+  DECIMAL scaled;
+
+  hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
+
+  if (SUCCEEDED(hRet))
+  {
+    /* Our decimals now have the same scale, we can add them as 96 bit integers */
+    ULONG overflow = 0;
+    BYTE sign = DECIMAL_POS;
+
+    /* Correct for the sign of the result */
+    if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
+    {
+      /* -x + -y : Negative */
+      sign = DECIMAL_NEG;
+      goto VarDecAdd_AsPositive;
+    }
+    else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
+    {
+      int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
+
+      /* -x + y : Negative if x > y */
+      if (cmp > 0)
+      {
+        sign = DECIMAL_NEG;
+VarDecAdd_AsNegative:
+        DEC_LO32(pDecOut)  = VARIANT_Sub(DEC_LO32(pDecLeft),  DEC_LO32(pDecRight),  &overflow);
+        DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
+        DEC_HI32(pDecOut)  = VARIANT_Sub(DEC_HI32(pDecLeft),  DEC_HI32(pDecRight),  &overflow);
+      }
+      else
+      {
+VarDecAdd_AsInvertedNegative:
+        DEC_LO32(pDecOut)  = VARIANT_Sub(DEC_LO32(pDecRight),  DEC_LO32(pDecLeft),  &overflow);
+        DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
+        DEC_HI32(pDecOut)  = VARIANT_Sub(DEC_HI32(pDecRight),  DEC_HI32(pDecLeft),  &overflow);
+      }
+    }
+    else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
+    {
+      int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
+
+      /* x + -y : Negative if x <= y */
+      if (cmp <= 0)
+      {
+        sign = DECIMAL_NEG;
+        goto VarDecAdd_AsInvertedNegative;
+      }
+      goto VarDecAdd_AsNegative;
+    }
+    else
+    {
+      /* x + y : Positive */
+VarDecAdd_AsPositive:
+      DEC_LO32(pDecOut)  = VARIANT_Add(DEC_LO32(pDecLeft),  DEC_LO32(pDecRight),  &overflow);
+      DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
+      DEC_HI32(pDecOut)  = VARIANT_Add(DEC_HI32(pDecLeft),  DEC_HI32(pDecRight),  &overflow);
+    }
+
+    if (overflow)
+      return DISP_E_OVERFLOW; /* overflowed */
+
+    DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
+    DEC_SIGN(pDecOut) = sign;
+  }
+  return hRet;
+}
+
+/************************************************************************
+ * VarDecDiv (OLEAUT32.178)
+ *
+ * Divide one DECIMAL by another.
+ *
+ * PARAMS
+ *  pDecLeft  [I] Source
+ *  pDecRight [I] Value to divide by
+ *  pDecOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
+{
+  FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut);
+  return DISP_E_OVERFLOW;
+}
+
+/************************************************************************
+ * VarDecMul (OLEAUT32.179)
+ *
+ * Multiply one DECIMAL by another.
+ *
+ * PARAMS
+ *  pDecLeft  [I] Source
+ *  pDecRight [I] Value to multiply by
+ *  pDecOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
+{
+  /* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */
+
+  if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight))
+  {
+    /* 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
+    {
+      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);
+    }
+    return hRet;
+  }
+  FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
+  return DISP_E_OVERFLOW;
+}
+
+/************************************************************************
+ * VarDecSub (OLEAUT32.181)
+ *
+ * Subtract one DECIMAL from another.
+ *
+ * PARAMS
+ *  pDecLeft  [I] Source
+ *  pDecRight [I] DECIMAL to subtract from pDecLeft
+ *  pDecOut   [O] Destination
+ *
+ * RETURNS
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
+{
+  DECIMAL decRight;
+
+  /* Implement as addition of the negative */
+  VarDecNeg(pDecRight, &decRight);
+  return VarDecAdd(pDecLeft, &decRight, pDecOut);
+}
+
+/************************************************************************
+ * VarDecAbs (OLEAUT32.182)
+ *
+ * Convert a DECIMAL into its absolute value.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK. This function does not fail.
+ */
+HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
+{
+  *pDecOut = *pDecIn;
+  DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarDecFix (OLEAUT32.187)
+ *
+ * Return the integer portion of a DECIMAL.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
+{
+  if (DEC_SIGN(pDecOut) & ~DECIMAL_NEG)
+    return E_INVALIDARG;
+
+  if (!DEC_SCALE(pDecIn))
+  {
+    *pDecOut = *pDecIn; /* Already an integer */
+    return S_OK;
+  }
+
+  FIXME("semi-stub!\n");
+  return DISP_E_OVERFLOW;
+}
+
+/************************************************************************
+ * VarDecInt (OLEAUT32.188)
+ *
+ * Return the integer portion of a DECIMAL.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
+{
+  if (DEC_SIGN(pDecOut) & ~DECIMAL_NEG)
+    return E_INVALIDARG;
+
+  if (!DEC_SCALE(pDecIn))
+  {
+    *pDecOut = *pDecIn; /* Already an integer */
+    return S_OK;
+  }
+
+  FIXME("semi-stub!\n");
+  return DISP_E_OVERFLOW;
+}
+
+/************************************************************************
+ * VarDecNeg (OLEAUT32.189)
+ *
+ * Change the sign of a DECIMAL.
+ *
+ * PARAMS
+ *  pDecIn  [I] Source
+ *  pDecOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK. This function does not fail.
+ */
+HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
+{
+  *pDecOut = *pDecIn;
+  DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarDecRound (OLEAUT32.203)
+ *
+ * Change the precision of a DECIMAL.
+ *
+ * PARAMS
+ *  pDecIn    [I] Source
+ *  cDecimals [I] New number of decimals to keep
+ *  pDecOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK. pDecOut contains the rounded value.
+ *  Failure: E_INVALIDARG if any argument is invalid.
+ */
+HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
+{
+  if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
+    return E_INVALIDARG;
+
+  if (cDecimals >= DEC_SCALE(pDecIn))
+  {
+    *pDecOut = *pDecIn; /* More precision than we have */
+    return S_OK;
+  }
+
+  FIXME("semi-stub!\n");
+
+  return DISP_E_OVERFLOW;
+}
+
+/************************************************************************
+ * VarDecCmp (OLEAUT32.204)
+ *
+ * Compare two DECIMAL values.
+ *
+ * PARAMS
+ *  pDecLeft  [I] Source
+ *  pDecRight [I] Value to compare
+ *
+ * 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
+ */
+HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
+{
+  HRESULT hRet;
+  DECIMAL result;
+
+  /* Subtract right from left, and compare the result to 0 */
+  hRet = VarDecSub(pDecLeft, pDecRight, &result);
+
+  if (SUCCEEDED(hRet))
+  {
+    int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
+
+    if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
+      hRet = (HRESULT)VARCMP_LT;
+    else if (non_zero)
+      hRet = (HRESULT)VARCMP_GT;
+    else
+      hRet = (HRESULT)VARCMP_EQ;
+  }
+  return hRet;
+}
+
+/************************************************************************
+ * VarDecCmpR8 (OLEAUT32.298)
+ *
+ * Compare a DECIMAL to a double
+ *
+ * PARAMS
+ *  pDecLeft [I] DECIMAL Source
+ *  dblRight [I] double to compare to pDecLeft
+ *
+ * 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
+ */
+HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
+{
+  HRESULT hRet;
+  DECIMAL decRight;
+
+  hRet = VarDecFromR8(dblRight, &decRight);
+
+  if (SUCCEEDED(hRet))
+    hRet = VarDecCmp(pDecLeft, &decRight);
+
+  return hRet;
+}
+
+/* BOOL
+ */
+
+/************************************************************************
+ * VarBoolFromUI1 (OLEAUT32.118)
+ *
+ * Convert a VT_UI1 to a VT_BOOL.
+ *
+ * PARAMS
+ *  bIn      [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromUI1(bIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromI2 (OLEAUT32.119)
+ *
+ * Convert a VT_I2 to a VT_BOOL.
+ *
+ * PARAMS
+ *  sIn      [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromI2(sIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromI4 (OLEAUT32.120)
+ *
+ * Convert a VT_I4 to a VT_BOOL.
+ *
+ * PARAMS
+ *  sIn      [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromI4(lIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromR4 (OLEAUT32.121)
+ *
+ * Convert a VT_R4 to a VT_BOOL.
+ *
+ * PARAMS
+ *  fltIn    [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromR4(fltIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromR8 (OLEAUT32.122)
+ *
+ * Convert a VT_R8 to a VT_BOOL.
+ *
+ * PARAMS
+ *  dblIn    [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromR8(dblIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromDate (OLEAUT32.123)
+ *
+ * Convert a VT_DATE to a VT_BOOL.
+ *
+ * PARAMS
+ *  dateIn   [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromDate(dateIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromCy (OLEAUT32.124)
+ *
+ * Convert a VT_CY to a VT_BOOL.
+ *
+ * PARAMS
+ *  cyIn     [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromCy(cyIn, pBoolOut);
+}
+
+static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
+{
+  HRSRC hrsrc;
+
+  hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
+                           (LPCWSTR)((dwId >> 4) + 1), langId );
+  if (hrsrc)
+  {
+    HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
+
+    if (hmem)
+    {
+      const WCHAR *p;
+      unsigned int i;
+
+      p = LockResource( hmem );
+      for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
+
+      memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
+      lpszDest[*p] = '\0';
+      TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/************************************************************************
+ * VarBoolFromStr (OLEAUT32.125)
+ *
+ * Convert a VT_BSTR to a VT_BOOL.
+ *
+ * PARAMS
+ *  strIn    [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pBoolOut is invalid.
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ *
+ * NOTES
+ *  - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
+ *  it may contain (in any case mapping) the text "true" or "false".
+ *  - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
+ *  localised text of "True" or "False" in the language specified by lcid.
+ *  - If none of these matches occur, the string is treated as a numeric string
+ *  and the boolean pBoolOut will be set according to whether the number is zero
+ *  or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
+ *  - If the text is not numeric and does not match any of the above, then
+ *  DISP_E_TYPEMISMATCH is returned.
+ */
+HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
+{
+  /* Any VB/VBA programmers out there should recognise these strings... */
+  static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
+  static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
+  WCHAR szBuff[64];
+  LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
+  HRESULT hRes = S_OK;
+
+  if (!strIn || !pBoolOut)
+    return DISP_E_TYPEMISMATCH;
+
+  /* Check if we should be comparing against localised text */
+  if (dwFlags & VAR_LOCALBOOL)
+  {
+    /* Convert our LCID into a usable value */
+    lcid = ConvertDefaultLocale(lcid);
+
+    langId = LANGIDFROMLCID(lcid);
+
+    if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
+      langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
+
+    /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
+     * I don't think this is needed unless any of the localised text strings
+     * contain characters that can be so mapped. In the event that this is
+     * true for a given language (possibly some Asian languages), then strIn
+     * should be mapped here _only_ if langId is an Id for which this can occur.
+     */
+  }
+
+  /* Note that if we are not comparing against localised strings, langId
+   * will have its default value of LANG_ENGLISH. This allows us to mimic
+   * the native behaviour of always checking against English strings even
+   * after we've checked for localised ones.
+   */
+VarBoolFromStr_CheckLocalised:
+  if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
+  {
+    /* Compare against localised strings, ignoring case */
+    if (!strcmpiW(strIn, szBuff))
+    {
+      *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
+      return hRes;
+    }
+    VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
+    if (!strcmpiW(strIn, szBuff))
+    {
+      *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
+      return hRes;
+    }
+  }
+
+  if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
+  {
+    /* We have checked the localised text, now check English */
+    langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
+    goto VarBoolFromStr_CheckLocalised;
+  }
+
+  /* All checks against localised text have failed, try #TRUE#/#FALSE# */
+  if (!strcmpW(strIn, szFalse))
+    *pBoolOut = VARIANT_FALSE;
+  else if (!strcmpW(strIn, szTrue))
+    *pBoolOut = VARIANT_TRUE;
+  else
+  {
+    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);
+  }
+  return hRes;
+}
+
+/************************************************************************
+ * VarBoolFromDisp (OLEAUT32.126)
+ *
+ * Convert a VT_DISPATCH to a VT_BOOL.
+ *
+ * PARAMS
+ *  pdispIn   [I] Source
+ *  lcid      [I] LCID for conversion
+ *  pBoolOut  [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromDisp(pdispIn, lcid, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromI1 (OLEAUT32.233)
+ *
+ * Convert a VT_I1 to a VT_BOOL.
+ *
+ * PARAMS
+ *  cIn      [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromI1(cIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromUI2 (OLEAUT32.234)
+ *
+ * Convert a VT_UI2 to a VT_BOOL.
+ *
+ * PARAMS
+ *  usIn     [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromUI2(usIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromUI4 (OLEAUT32.235)
+ *
+ * Convert a VT_UI4 to a VT_BOOL.
+ *
+ * PARAMS
+ *  ulIn     [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromUI4(ulIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromDec (OLEAUT32.236)
+ *
+ * Convert a VT_DECIMAL to a VT_BOOL.
+ *
+ * PARAMS
+ *  pDecIn   [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pDecIn is invalid.
+ */
+HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
+{
+  if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
+    return E_INVALIDARG;
+
+  if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
+    *pBoolOut = VARIANT_TRUE;
+  else
+    *pBoolOut = VARIANT_FALSE;
+  return S_OK;
+}
+
+/************************************************************************
+ * VarBoolFromI8 (OLEAUT32.370)
+ *
+ * Convert a VT_I8 to a VT_BOOL.
+ *
+ * PARAMS
+ *  ullIn    [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromI8(llIn, pBoolOut);
+}
+
+/************************************************************************
+ * VarBoolFromUI8 (OLEAUT32.371)
+ *
+ * Convert a VT_UI8 to a VT_BOOL.
+ *
+ * PARAMS
+ *  ullIn    [I] Source
+ *  pBoolOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
+{
+  return _VarBoolFromUI8(ullIn, pBoolOut);
+}
+
+/* BSTR
+ */
+
+/* Write a number from a UI8 and sign */
+static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
+{
+  do
+  {
+    WCHAR ulNextDigit = ulVal % 10;
+
+    *szOut-- = '0' + ulNextDigit;
+    ulVal = (ulVal - ulNextDigit) / 10;
+  } while (ulVal);
+
+  szOut++;
+  return szOut;
+}
+
+/* Create a (possibly localised) BSTR from a UI8 and sign */
+static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
+{
+  WCHAR szConverted[256];
+
+  if (dwFlags & VAR_NEGATIVE)
+    *--szOut = '-';
+
+  if (dwFlags & LOCALE_USE_NLS)
+  {
+    /* Format the number for the locale */
+    szConverted[0] = '\0';
+    GetNumberFormatW(lcid,
+                     dwFlags & LOCALE_NOUSEROVERRIDE,
+                     szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
+    szOut = szConverted;
+  }
+  return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
+}
+
+/* Create a (possibly localised) BSTR from a UI8 and sign */
+static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
+{
+  WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
+
+  if (!pbstrOut)
+    return E_INVALIDARG;
+
+  /* Create the basic number string */
+  *szOut-- = '\0';
+  szOut = VARIANT_WriteNumber(ulVal, szOut);
+
+  *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
+  TRACE("returning %s\n", debugstr_w(*pbstrOut));
+  return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+}
+
+/******************************************************************************
+ * VarBstrFromUI1 (OLEAUT32.108)
+ *
+ * Convert a VT_UI1 to a VT_BSTR.
+ *
+ * PARAMS
+ *  bIn      [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
+}
+
+/******************************************************************************
+ * VarBstrFromI2 (OLEAUT32.109)
+ *
+ * Convert a VT_I2 to a VT_BSTR.
+ *
+ * PARAMS
+ *  sIn      [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  ULONG64 ul64 = sIn;
+
+  if (sIn < 0)
+  {
+    ul64 = -sIn;
+    dwFlags |= VAR_NEGATIVE;
+  }
+  return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
+}
+
+/******************************************************************************
+ * VarBstrFromI4 (OLEAUT32.110)
+ *
+ * Convert a VT_I4 to a VT_BSTR.
+ *
+ * PARAMS
+ *  lIn      [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  ULONG64 ul64 = lIn;
+
+  if (lIn < 0)
+  {
+    ul64 = -lIn;
+    dwFlags |= VAR_NEGATIVE;
+  }
+  return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
+}
+
+static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
+                                    BSTR* pbstrOut, LPCWSTR lpszFormat)
+{
+  WCHAR buff[256];
+
+  if (!pbstrOut)
+    return E_INVALIDARG;
+
+  sprintfW( buff, lpszFormat, dblIn );
+  TRACE("created string %s\n", debugstr_w(buff));
+  if (dwFlags & LOCALE_USE_NLS)
+  {
+    WCHAR numbuff[256];
+
+    /* 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 = SysAllocString(buff);
+  return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+}
+
+/******************************************************************************
+ * VarBstrFromR4 (OLEAUT32.111)
+ *
+ * Convert a VT_R4 to a VT_BSTR.
+ *
+ * PARAMS
+ *  fltIn    [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
+}
+
+/******************************************************************************
+ * VarBstrFromR8 (OLEAUT32.112)
+ *
+ * Convert a VT_R8 to a VT_BSTR.
+ *
+ * PARAMS
+ *  dblIn    [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
+}
+
+/******************************************************************************
+ *    VarBstrFromCy   [OLEAUT32.113]
+ *
+ * Convert a VT_CY to a VT_BSTR.
+ *
+ * PARAMS
+ *  cyIn     [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
+{
+  WCHAR buff[256];
+  double dblVal;
+
+  if (!pbstrOut)
+    return E_INVALIDARG;
+
+  VarR8FromCy(cyIn, &dblVal);
+  sprintfW(buff, szDoubleFormatW, dblVal);
+
+  if (dwFlags & LOCALE_USE_NLS)
+  {
+    WCHAR cybuff[256];
+
+    /* Format the currency for the locale */
+    cybuff[0] = '\0';
+    GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
+                       buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
+    *pbstrOut = SysAllocString(cybuff);
+  }
+  else
+    *pbstrOut = SysAllocString(buff);
+
+  return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+}
+
+/******************************************************************************
+ *    VarBstrFromDate    [OLEAUT32.114]
+ *
+ * Convert a VT_DATE to a VT_BSTR.
+ *
+ * PARAMS
+ *  dateIn   [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  SYSTEMTIME st;
+  DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
+  WCHAR date[128], *time;
+
+  TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
+
+  if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
+    return E_INVALIDARG;
+
+  *pbstrOut = NULL;
+
+  if (dwFlags & VAR_CALENDAR_THAI)
+      st.wYear += 553; /* Use the Thai buddhist calendar year */
+  else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
+      FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
+
+  if (dwFlags & LOCALE_USE_NLS)
+    dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
+  else
+  {
+    double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
+    double partial = dateIn - whole;
+
+    if (whole == 0.0)
+      dwFlags |= VAR_TIMEVALUEONLY;
+    else if (partial < 1e-12)
+      dwFlags |= VAR_DATEVALUEONLY;
+  }
+
+  if (dwFlags & VAR_TIMEVALUEONLY)
+    date[0] = '\0';
+  else
+    if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
+                        sizeof(date)/sizeof(WCHAR)))
+      return E_INVALIDARG;
+
+  if (!(dwFlags & VAR_DATEVALUEONLY))
+  {
+    time = date + strlenW(date);
+    if (time != date)
+      *time++ = ' ';
+    if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
+                        sizeof(date)/sizeof(WCHAR)-(time-date)))
+      return E_INVALIDARG;
+  }
+
+  *pbstrOut = SysAllocString(date);
+  if (*pbstrOut)
+    TRACE("returning %s\n", debugstr_w(*pbstrOut));
+  return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+}
+
+/******************************************************************************
+ * VarBstrFromBool (OLEAUT32.116)
+ *
+ * Convert a VT_BOOL to a VT_BSTR.
+ *
+ * PARAMS
+ *  boolIn   [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ *
+ * NOTES
+ *  If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
+ *  localised text of "True" or "False". To convert a bool into a
+ *  numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
+ */
+HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  WCHAR szBuff[64];
+  DWORD dwResId = IDS_TRUE;
+  LANGID langId;
+
+  TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut);
+
+  if (!pbstrOut)
+    return E_INVALIDARG;
+
+  /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
+   * for variant formatting */
+  switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
+  {
+  case VAR_BOOLONOFF:
+      dwResId = IDS_ON;
+      break;
+  case VAR_BOOLYESNO:
+      dwResId = IDS_YES;
+      break;
+  case VAR_LOCALBOOL:
+      break;
+  default:
+    lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
+  }
+
+  lcid = ConvertDefaultLocale(lcid);
+  langId = LANGIDFROMLCID(lcid);
+  if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
+    langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
+
+  if (boolIn == VARIANT_FALSE)
+    dwResId++; /* Use negative form */
+
+VarBstrFromBool_GetLocalised:
+  if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
+  {
+    *pbstrOut = SysAllocString(szBuff);
+    return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+  }
+
+  if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
+  {
+    langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
+    goto VarBstrFromBool_GetLocalised;
+  }
+
+  /* Should never get here */
+  WARN("Failed to load bool text!\n");
+  return E_OUTOFMEMORY;
+}
+
+/******************************************************************************
+ * VarBstrFromI1 (OLEAUT32.229)
+ *
+ * Convert a VT_I1 to a VT_BSTR.
+ *
+ * PARAMS
+ *  cIn      [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  ULONG64 ul64 = cIn;
+
+  if (cIn < 0)
+  {
+    ul64 = -cIn;
+    dwFlags |= VAR_NEGATIVE;
+  }
+  return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
+}
+
+/******************************************************************************
+ * VarBstrFromUI2 (OLEAUT32.230)
+ *
+ * Convert a VT_UI2 to a VT_BSTR.
+ *
+ * PARAMS
+ *  usIn     [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
+}
+
+/******************************************************************************
+ * VarBstrFromUI4 (OLEAUT32.231)
+ *
+ * Convert a VT_UI4 to a VT_BSTR.
+ *
+ * PARAMS
+ *  ulIn     [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
+}
+
+/******************************************************************************
+ * VarBstrFromDec (OLEAUT32.232)
+ *
+ * Convert a VT_DECIMAL to a VT_BSTR.
+ *
+ * PARAMS
+ *  pDecIn   [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  if (!pbstrOut)
+    return E_INVALIDARG;
+
+  if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn))
+  {
+    WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
+
+    /* Create the basic number string */
+    *szOut-- = '\0';
+    szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
+    if (DEC_SIGN(pDecIn))
+      dwFlags |= VAR_NEGATIVE;
+
+    *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
+    TRACE("returning %s\n", debugstr_w(*pbstrOut));
+    return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+  }
+  FIXME("semi-stub\n");
+  return E_INVALIDARG;
+}
+
+/************************************************************************
+ * VarBstrFromI8 (OLEAUT32.370)
+ *
+ * Convert a VT_I8 to a VT_BSTR.
+ *
+ * PARAMS
+ *  llIn     [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  ULONG64 ul64 = llIn;
+
+  if (llIn < 0)
+  {
+    ul64 = -llIn;
+    dwFlags |= VAR_NEGATIVE;
+  }
+  return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
+}
+
+/************************************************************************
+ * VarBstrFromUI8 (OLEAUT32.371)
+ *
+ * Convert a VT_UI8 to a VT_BSTR.
+ *
+ * PARAMS
+ *  ullIn    [I] Source
+ *  lcid     [I] LCID for the conversion
+ *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
+ *  pbstrOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+  return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
+}
+
+/**********************************************************************
+ * VarBstrCat (OLEAUT32.313)
+ *
+ * Concatenate two BSTR values.
+ *
+ * PARAMS
+ *  pbstrLeft  [I] Source
+ *  pbstrRight [I] Value to concatenate
+ *  pbstrOut   [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if pbstrOut is invalid.
+ *           E_OUTOFMEMORY, if memory allocation fails.
+ */
+HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
+{
+  unsigned int len;
+
+  if (!pbstrOut)
+    return E_INVALIDARG;
+
+  len = pbstrLeft ? strlenW(pbstrLeft) : 0;
+  if (pbstrRight)
+    len += strlenW(pbstrRight);
+
+  *pbstrOut = SysAllocStringLen(NULL, len);
+  if (!*pbstrOut)
+    return E_OUTOFMEMORY;
+
+  *pbstrOut = '\0';
+
+  if (pbstrLeft)
+    strcpyW(*pbstrOut, pbstrLeft);
+
+  if (pbstrRight)
+    strcatW(*pbstrOut, pbstrRight);
+
+  return S_OK;
+}
+
+/**********************************************************************
+ * VarBstrCmp (OLEAUT32.314)
+ *
+ * Compare two BSTR values.
+ *
+ * PARAMS
+ *  pbstrLeft  [I] Source
+ *  pbstrRight [I] Value to compare
+ *  lcid       [I] LCID for the comparason
+ *  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.
+ */
+HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
+{
+    if (!pbstrLeft)
+    {
+      if (!pbstrRight || !*pbstrRight)
+        return VARCMP_EQ;
+      return VARCMP_NULL;
+    }
+    else if (!pbstrRight)
+    {
+      if (!*pbstrLeft)
+        return VARCMP_EQ;
+      return VARCMP_NULL;
+    }
+
+    return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
+}
+
+/*
+ * DATE
+ */
+
+/******************************************************************************
+ * VarDateFromUI1 (OLEAUT32.88)
+ *
+ * Convert a VT_UI1 to a VT_DATE.
+ *
+ * PARAMS
+ *  bIn      [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
+{
+  return _VarDateFromUI1(bIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromI2 (OLEAUT32.89)
+ *
+ * Convert a VT_I2 to a VT_DATE.
+ *
+ * PARAMS
+ *  sIn      [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
+{
+  return _VarDateFromI2(sIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromI4 (OLEAUT32.90)
+ *
+ * Convert a VT_I4 to a VT_DATE.
+ *
+ * PARAMS
+ *  lIn      [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
+{
+  return _VarDateFromI4(lIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromR4 (OLEAUT32.91)
+ *
+ * Convert a VT_R4 to a VT_DATE.
+ *
+ * PARAMS
+ *  fltIn    [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
+{
+  return _VarDateFromR4(fltIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromR8 (OLEAUT32.92)
+ *
+ * Convert a VT_R8 to a VT_DATE.
+ *
+ * PARAMS
+ *  dblIn    [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
+{
+  return _VarDateFromR8(dblIn, pdateOut);
+}
+
+/**********************************************************************
+ * VarDateFromDisp (OLEAUT32.95)
+ *
+ * Convert a VT_DISPATCH to a VT_DATE.
+ *
+ * PARAMS
+ *  pdispIn  [I] Source
+ *  lcid     [I] LCID for conversion
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: E_INVALIDARG, if the source value is invalid
+ *           DISP_E_OVERFLOW, if the value will not fit in the destination
+ *           DISP_E_TYPEMISMATCH, if the type cannot be converted
+ */
+HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
+{
+  return _VarDateFromDisp(pdispIn, lcid, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromBool (OLEAUT32.96)
+ *
+ * Convert a VT_BOOL to a VT_DATE.
+ *
+ * PARAMS
+ *  boolIn   [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
+{
+  return _VarDateFromBool(boolIn, pdateOut);
+}
+
+/**********************************************************************
+ * VarDateFromCy (OLEAUT32.93)
+ *
+ * Convert a VT_CY to a VT_DATE.
+ *
+ * PARAMS
+ *  lIn      [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
+{
+  return _VarDateFromCy(cyIn, pdateOut);
+}
+
+/* Date string parsing */
+#define DP_TIMESEP 0x01 /* Time seperator ( _must_ remain 0x1, used as a bitmask) */
+#define DP_DATESEP 0x02 /* Date seperator */
+#define DP_MONTH   0x04 /* Month name */
+#define DP_AM      0x08 /* AM */
+#define DP_PM      0x10 /* PM */
+
+typedef struct tagDATEPARSE
+{
+    DWORD dwCount;      /* Number of fields found so far (maximum 6) */
+    DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
+    DWORD dwFlags[6];   /* Flags for each field */
+    DWORD dwValues[6];  /* Value of each field */
+} DATEPARSE;
+
+#define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
+
+#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
+
+/* Determine if a day is valid in a given month of a given year */
+static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
+{
+  static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+  if (day && month && month < 13)
+  {
+    if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+/* Possible orders for 3 numbers making up a date */
+#define ORDER_MDY 0x01
+#define ORDER_YMD 0x02
+#define ORDER_YDM 0x04
+#define ORDER_DMY 0x08
+#define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
+
+/* Determine a date for a particular locale, from 3 numbers */
+static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
+                                       DWORD offset, SYSTEMTIME *st)
+{
+  DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
+
+  if (!dp->dwCount)
+  {
+    v1 = 30; /* Default to (Variant) 0 date part */
+    v2 = 12;
+    v3 = 1899;
+    goto VARIANT_MakeDate_OK;
+  }
+
+  v1 = dp->dwValues[offset + 0];
+  v2 = dp->dwValues[offset + 1];
+  if (dp->dwCount == 2)
+  {
+    SYSTEMTIME current;
+    GetSystemTime(&current);
+    v3 = current.wYear;
+  }
+  else
+    v3 = dp->dwValues[offset + 2];
+
+  TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
+
+  /* If one number must be a month (Because a month name was given), then only
+   * consider orders with the month in that position.
+   * If we took the current year as 'v3', then only allow a year in that position.
+   */
+  if (dp->dwFlags[offset + 0] & DP_MONTH)
+  {
+    dwAllOrders = ORDER_MDY;
+  }
+  else if (dp->dwFlags[offset + 1] & DP_MONTH)
+  {
+    dwAllOrders = ORDER_DMY;
+    if (dp->dwCount > 2)
+      dwAllOrders |= ORDER_YMD;
+  }
+  else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
+  {
+    dwAllOrders = ORDER_YDM;
+  }
+  else
+  {
+    dwAllOrders = ORDER_MDY|ORDER_DMY;
+    if (dp->dwCount > 2)
+      dwAllOrders |= (ORDER_YMD|ORDER_YDM);
+  }
+
+VARIANT_MakeDate_Start:
+  TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
+
+  while (dwAllOrders)
+  {
+    DWORD dwTemp;
+
+    if (dwCount == 0)
+    {
+      /* First: Try the order given by iDate */
+      switch (iDate)
+      {
+      case 0:  dwTry = dwAllOrders & ORDER_MDY; break;
+      case 1:  dwTry = dwAllOrders & ORDER_DMY; break;
+      default: dwTry = dwAllOrders & ORDER_YMD; break;
+      }
+    }
+    else if (dwCount == 1)
+    {
+      /* Second: Try all the orders compatable with iDate */
+      switch (iDate)
+      {
+      case 0:  dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
+      case 1:  dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
+      default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
+      }
+    }
+    else
+    {
+      /* Finally: Try any remaining orders */
+      dwTry = dwAllOrders;
+    }
+
+    TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
+
+    dwCount++;
+    if (!dwTry)
+      continue;
+
+#define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
+
+    if (dwTry & ORDER_MDY)
+    {
+      if (VARIANT_IsValidMonthDay(v2,v1,v3))
+      {
+        DATE_SWAP(v1,v2);
+        goto VARIANT_MakeDate_OK;
+      }
+      dwAllOrders &= ~ORDER_MDY;
+    }
+    if (dwTry & ORDER_YMD)
+    {
+      if (VARIANT_IsValidMonthDay(v3,v2,v1))
+      {
+        DATE_SWAP(v1,v3);
+        goto VARIANT_MakeDate_OK;
+      }
+      dwAllOrders &= ~ORDER_YMD;
+    }
+    if (dwTry & ORDER_YDM)
+    {
+      if (VARIANT_IsValidMonthDay(v2,v3,v1))
+      {
+        DATE_SWAP(v1,v2);
+        DATE_SWAP(v2,v3);
+        goto VARIANT_MakeDate_OK;
+      }
+      dwAllOrders &= ~ORDER_YDM;
+    }
+    if (dwTry & ORDER_DMY)
+    {
+      if (VARIANT_IsValidMonthDay(v1,v2,v3))
+        goto VARIANT_MakeDate_OK;
+      dwAllOrders &= ~ORDER_DMY;
+    }
+    if (dwTry & ORDER_MYD)
+    {
+      /* Only occurs if we are trying a 2 year date as M/Y not D/M */
+      if (VARIANT_IsValidMonthDay(v3,v1,v2))
+      {
+        DATE_SWAP(v1,v3);
+        DATE_SWAP(v2,v3);
+        goto VARIANT_MakeDate_OK;
+      }
+      dwAllOrders &= ~ORDER_MYD;
+    }
+  }
+
+  if (dp->dwCount == 2)
+  {
+    /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
+    v3 = 1; /* 1st of the month */
+    dwAllOrders = ORDER_YMD|ORDER_MYD;
+    dp->dwCount = 0; /* Don't return to this code path again */
+    dwCount = 0;
+    goto VARIANT_MakeDate_Start;
+  }
+
+  /* No valid dates were able to be constructed */
+  return DISP_E_TYPEMISMATCH;
+
+VARIANT_MakeDate_OK:
+
+  /* Check that the time part is ok */
+  if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
+    return DISP_E_TYPEMISMATCH;
+
+  TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
+  if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
+    st->wHour += 12;
+  else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
+    st->wHour = 0;
+  TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
+
+  st->wDay = v1;
+  st->wMonth = v2;
+  /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
+   * be retrieved from:
+   * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
+   * But Wine doesn't have/use that key as at the time of writing.
+   */
+  st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
+  TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
+  return S_OK;
+}
+
+/******************************************************************************
+ * VarDateFromStr [OLEAUT32.94]
+ *
+ * Convert a VT_BSTR to at VT_DATE.
+ *
+ * PARAMS
+ *  strIn    [I] String to convert
+ *  lcid     [I] Locale identifier for the conversion
+ *  dwFlags  [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
+ *  pdateOut [O] Destination for the converted value
+ *
+ * RETURNS
+ *  Success: S_OK. pdateOut contains the converted value.
+ *  FAILURE: An HRESULT error code indicating the prolem.
+ *
+ * NOTES
+ *  Any date format that can be created using the date formats from lcid
+ *  (Either from kernel Nls functions, variant conversion or formatting) is a
+ *  valid input to this function. In addition, a few more esoteric formats are
+ *  also supported for compatability with the native version. The date is
+ *  interpreted according to the date settings in the control panel, unless
+ *  the date is invalid in that format, in which the most compatable format
+ *  that produces a valid date will be used.
+ */
+HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
+{
+  static const USHORT ParseDateTokens[] =
+  {
+    LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
+    LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
+    LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
+    LOCALE_SMONTHNAME13,
+    LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
+    LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
+    LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
+    LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
+    LOCALE_SABBREVMONTHNAME13,
+    LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
+    LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
+    LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
+    LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
+    LOCALE_SABBREVDAYNAME7,
+    LOCALE_S1159, LOCALE_S2359
+  };
+  static const BYTE ParseDateMonths[] =
+  {
+    1,2,3,4,5,6,7,8,9,10,11,12,13,
+    1,2,3,4,5,6,7,8,9,10,11,12,13
+  };
+  size_t i;
+  BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
+  DATEPARSE dp;
+  DWORD dwDateSeps = 0, iDate = 0;
+  HRESULT hRet = S_OK;
+
+  if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
+      (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
+    return E_INVALIDARG;
+
+  if (!strIn)
+    return DISP_E_TYPEMISMATCH;
+
+  *pdateOut = 0.0;
+
+  TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
+
+  memset(&dp, 0, sizeof(dp));
+
+  GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
+                 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
+  TRACE("iDate is %ld\n", iDate);
+
+  /* Get the month/day/am/pm tokens for this locale */
+  for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
+  {
+    WCHAR buff[128];
+    LCTYPE lctype =  ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
+
+    /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
+     *        GetAltMonthNames(). We should really cache these strings too.
+     */
+    buff[0] = '\0';
+    GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
+    tokens[i] = SysAllocString(buff);
+    TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
+  }
+
+  /* Parse the string into our structure */
+  while (*strIn)
+  {
+    if (dp.dwCount > 6)
+      break;
+
+    if (isdigitW(*strIn))
+    {
+      dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
+      dp.dwCount++;
+      strIn--;
+    }
+    else if (isalpha(*strIn))
+    {
+      BOOL bFound = FALSE;
+
+      for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
+      {
+        DWORD dwLen = strlenW(tokens[i]);
+        if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
+        {
+          if (i <= 25)
+          {
+            dp.dwValues[dp.dwCount] = ParseDateMonths[i];
+            dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
+            dp.dwCount++;
+          }
+          else if (i > 39)
+          {
+            if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
+              hRet = DISP_E_TYPEMISMATCH;
+            else
+            {
+              dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
+              dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
+            }
+          }
+          strIn += (dwLen - 1);
+          bFound = TRUE;
+          break;
+        }
+      }
+
+      if (!bFound)
+      {
+        if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
+            (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
+        {
+          /* Special case - 'a' and 'p' are recognised as short for am/pm */
+          if (*strIn == 'a' || *strIn == 'A')
+          {
+            dp.dwFlags[dp.dwCount - 1] |= DP_AM;
+            dp.dwParseFlags |=  DP_AM;
+          }
+          else
+          {
+            dp.dwFlags[dp.dwCount - 1] |= DP_PM;
+            dp.dwParseFlags |=  DP_PM;
+          }
+          strIn++;
+        }
+        else
+        {
+          TRACE("No matching token for %s\n", debugstr_w(strIn));
+          hRet = DISP_E_TYPEMISMATCH;
+          break;
+        }
+      }
+    }
+    else if (*strIn == ':' ||  *strIn == '.')
+    {
+      if (!dp.dwCount || !strIn[1])
+        hRet = DISP_E_TYPEMISMATCH;
+      else
+        dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
+    }
+    else if (*strIn == '-' || *strIn == '/')
+    {
+      dwDateSeps++;
+      if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
+        hRet = DISP_E_TYPEMISMATCH;
+      else
+        dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
+    }
+    else if (*strIn == ',' || isspaceW(*strIn))
+    {
+      if (*strIn == ',' && !strIn[1])
+        hRet = DISP_E_TYPEMISMATCH;
+    }
+    else
+    {
+      hRet = DISP_E_TYPEMISMATCH;
+    }
+    strIn++;
+  }
+
+  if (!dp.dwCount || dp.dwCount > 6 ||
+      (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
+    hRet = DISP_E_TYPEMISMATCH;
+
+  if (SUCCEEDED(hRet))
+  {
+    SYSTEMTIME st;
+    DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
+
+    st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
+
+    /* Figure out which numbers correspond to which fields.
+     *
+     * This switch statement works based on the fact that native interprets any
+     * fields that are not joined with a time seperator ('.' or ':') as date
+     * fields. Thus we construct a value from 0-32 where each set bit indicates
+     * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
+     * For valid permutations, we set dwOffset to point to the first date field
+     * and shorten dp.dwCount by the number of time fields found. The real
+     * magic here occurs in VARIANT_MakeDate() above, where we determine what
+     * each date number must represent in the context of iDate.
+     */
+    TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
+
+    switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
+    {
+    case 0x1: /* TT TTDD TTDDD */
+      if (dp.dwCount > 3 &&
+          ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
+          (dp.dwFlags[4] & (DP_AM|DP_PM))))
+        hRet = DISP_E_TYPEMISMATCH;
+      else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
+        hRet = DISP_E_TYPEMISMATCH;
+      st.wHour = dp.dwValues[0];
+      st.wMinute  = dp.dwValues[1];
+      dp.dwCount -= 2;
+      dwOffset = 2;
+      break;
+
+    case 0x3: /* TTT TTTDD TTTDDD */
+      if (dp.dwCount > 4 &&
+          ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
+          (dp.dwFlags[5] & (DP_AM|DP_PM))))
+        hRet = DISP_E_TYPEMISMATCH;
+      else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
+        hRet = DISP_E_TYPEMISMATCH;
+      st.wHour   = dp.dwValues[0];
+      st.wMinute = dp.dwValues[1];
+      st.wSecond = dp.dwValues[2];
+      dwOffset = 3;
+      dp.dwCount -= 3;
+      break;
+
+    case 0x4: /* DDTT */
+      if (dp.dwCount != 4 ||
+          (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
+        hRet = DISP_E_TYPEMISMATCH;
+
+      st.wHour = dp.dwValues[2];
+      st.wMinute  = dp.dwValues[3];
+      dp.dwCount -= 2;
+      break;
+
+   case 0x0: /* T DD DDD TDDD TDDD */
+      if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
+      {
+        st.wHour = dp.dwValues[0]; /* T */
+        dp.dwCount = 0;
+        break;
+      }
+      else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
+      {
+        hRet = DISP_E_TYPEMISMATCH;
+      }
+      else if (dp.dwCount == 3)
+      {
+        if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
+        {
+          dp.dwCount = 2;
+          st.wHour = dp.dwValues[0];
+          dwOffset = 1;
+          break;
+        }
+        if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
+        {
+          dp.dwCount = 2;
+          st.wHour = dp.dwValues[2];
+          break;
+        }
+        else if (dp.dwParseFlags & (DP_AM|DP_PM))
+          hRet = DISP_E_TYPEMISMATCH;
+      }
+      else if (dp.dwCount == 4)
+      {
+        dp.dwCount = 3;
+        if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
+        {
+          st.wHour = dp.dwValues[0];
+          dwOffset = 1;
+        }
+        else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
+        {
+          st.wHour = dp.dwValues[3];
+        }
+        else
+          hRet = DISP_E_TYPEMISMATCH;
+        break;
+      }
+      /* .. fall through .. */
+
+    case 0x8: /* DDDTT */
+      if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
+          (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
+           (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
+           dp.dwCount == 4 || dp.dwCount == 6)
+        hRet = DISP_E_TYPEMISMATCH;
+      st.wHour   = dp.dwValues[3];
+      st.wMinute = dp.dwValues[4];
+      if (dp.dwCount == 5)
+        dp.dwCount -= 2;
+      break;
+
+    case 0xC: /* DDTTT */
+      if (dp.dwCount != 5 ||
+          (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
+        hRet = DISP_E_TYPEMISMATCH;
+      st.wHour   = dp.dwValues[2];
+      st.wMinute = dp.dwValues[3];
+      st.wSecond = dp.dwValues[4];
+      dp.dwCount -= 3;
+      break;
+
+    case 0x18: /* DDDTTT */
+      if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
+          (dp.dwFlags[2] & (DP_AM|DP_PM)))
+        hRet = DISP_E_TYPEMISMATCH;
+      st.wHour   = dp.dwValues[3];
+      st.wMinute = dp.dwValues[4];
+      st.wSecond = dp.dwValues[5];
+      dp.dwCount -= 3;
+      break;
+
+    default:
+      hRet = DISP_E_TYPEMISMATCH;
+      break;
+    }
+
+    if (SUCCEEDED(hRet))
+    {
+      hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
+
+      if (dwFlags & VAR_TIMEVALUEONLY)
+      {
+        st.wYear = 1899;
+        st.wMonth = 12;
+        st.wDay = 30;
+      }
+      else if (dwFlags & VAR_DATEVALUEONLY)
+       st.wHour = st.wMinute = st.wSecond = 0;
+
+      /* Finally, convert the value to a VT_DATE */
+      if (SUCCEEDED(hRet))
+        hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
+    }
+  }
+
+  for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
+    SysFreeString(tokens[i]);
+  return hRet;
+}
+
+/******************************************************************************
+ * VarDateFromI1 (OLEAUT32.221)
+ *
+ * Convert a VT_I1 to a VT_DATE.
+ *
+ * PARAMS
+ *  cIn      [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
+{
+  return _VarDateFromI1(cIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromUI2 (OLEAUT32.222)
+ *
+ * Convert a VT_UI2 to a VT_DATE.
+ *
+ * PARAMS
+ *  uiIn     [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
+{
+  return _VarDateFromUI2(uiIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromUI4 (OLEAUT32.223)
+ *
+ * Convert a VT_UI4 to a VT_DATE.
+ *
+ * PARAMS
+ *  ulIn     [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
+{
+  return _VarDateFromUI4(ulIn, pdateOut);
+}
+
+/**********************************************************************
+ * VarDateFromDec (OLEAUT32.224)
+ *
+ * Convert a VT_DECIMAL to a VT_DATE.
+ *
+ * PARAMS
+ *  pdecIn   [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  S_OK.
+ */
+HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
+{
+  return _VarDateFromDec(pdecIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromI8 (OLEAUT32.364)
+ *
+ * Convert a VT_I8 to a VT_DATE.
+ *
+ * PARAMS
+ *  llIn     [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
+{
+  return _VarDateFromI8(llIn, pdateOut);
+}
+
+/******************************************************************************
+ * VarDateFromUI8 (OLEAUT32.365)
+ *
+ * Convert a VT_UI8 to a VT_DATE.
+ *
+ * PARAMS
+ *  ullIn    [I] Source
+ *  pdateOut [O] Destination
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
+ */
+HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
+{
+  return _VarDateFromUI8(ullIn, pdateOut);
+}

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux