Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvartype.c
Go to the documentation of this file.
00001 /* 00002 * Low level variant functions 00003 * 00004 * Copyright 2003 Jon Griffiths 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #define COBJMACROS 00022 #define NONAMELESSUNION 00023 #define NONAMELESSSTRUCT 00024 00025 #include "wine/debug.h" 00026 #include "wine/unicode.h" 00027 #include "winbase.h" 00028 #include "winuser.h" 00029 #include "winnt.h" 00030 #include "variant.h" 00031 #include "resource.h" 00032 00033 WINE_DEFAULT_DEBUG_CHANNEL(variant); 00034 00035 extern HMODULE hProxyDll DECLSPEC_HIDDEN; 00036 00037 #define CY_MULTIPLIER 10000 /* 4 dp of precision */ 00038 #define CY_MULTIPLIER_F 10000.0 00039 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */ 00040 #define CY_HALF_F (CY_MULTIPLIER_F/2.0) 00041 00042 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' }; 00043 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' }; 00044 00045 /* Copy data from one variant to another. */ 00046 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut) 00047 { 00048 switch (vt) 00049 { 00050 case VT_I1: 00051 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break; 00052 case VT_BOOL: 00053 case VT_I2: 00054 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break; 00055 case VT_R4: 00056 case VT_INT: 00057 case VT_I4: 00058 case VT_UINT: 00059 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break; 00060 case VT_R8: 00061 case VT_DATE: 00062 case VT_CY: 00063 case VT_I8: 00064 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break; 00065 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break; 00066 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break; 00067 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break; 00068 default: 00069 FIXME("VT_ type %d unhandled, please report!\n", vt); 00070 } 00071 } 00072 00073 /* Macro to inline conversion from a float or double to any integer type, 00074 * rounding according to the 'dutch' convention. 00075 */ 00076 #define VARIANT_DutchRound(typ, value, res) do { \ 00077 double whole = value < 0 ? ceil(value) : floor(value); \ 00078 double fract = value - whole; \ 00079 if (fract > 0.5) res = (typ)whole + (typ)1; \ 00080 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \ 00081 else if (fract >= 0.0) res = (typ)whole; \ 00082 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \ 00083 else if (fract > -0.5) res = (typ)whole; \ 00084 else res = (typ)whole - (typ)1; \ 00085 } while(0) 00086 00087 00088 /* Coerce VT_BSTR to a numeric type */ 00089 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags, 00090 void* pOut, VARTYPE vt) 00091 { 00092 VARIANTARG dstVar; 00093 HRESULT hRet; 00094 NUMPARSE np; 00095 BYTE rgb[1024]; 00096 00097 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */ 00098 np.cDig = sizeof(rgb) / sizeof(BYTE); 00099 np.dwInFlags = NUMPRS_STD; 00100 00101 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb); 00102 00103 if (SUCCEEDED(hRet)) 00104 { 00105 /* 1 << vt gives us the VTBIT constant for the destination number type */ 00106 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar); 00107 if (SUCCEEDED(hRet)) 00108 VARIANT_CopyData(&dstVar, vt, pOut); 00109 } 00110 return hRet; 00111 } 00112 00113 /* Coerce VT_DISPATCH to another type */ 00114 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, 00115 VARTYPE vt, DWORD dwFlags) 00116 { 00117 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 }; 00118 VARIANTARG srcVar, dstVar; 00119 HRESULT hRet; 00120 00121 if (!pdispIn) 00122 return DISP_E_BADVARTYPE; 00123 00124 /* Get the default 'value' property from the IDispatch */ 00125 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET, 00126 &emptyParams, &srcVar, NULL, NULL); 00127 00128 if (SUCCEEDED(hRet)) 00129 { 00130 /* Convert the property to the requested type */ 00131 V_VT(&dstVar) = VT_EMPTY; 00132 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt); 00133 VariantClear(&srcVar); 00134 00135 if (SUCCEEDED(hRet)) 00136 { 00137 VARIANT_CopyData(&dstVar, vt, pOut); 00138 VariantClear(&srcVar); 00139 } 00140 } 00141 else 00142 hRet = DISP_E_TYPEMISMATCH; 00143 return hRet; 00144 } 00145 00146 /* Inline return type */ 00147 #define RETTYP static inline HRESULT 00148 00149 00150 /* Simple compiler cast from one type to another */ 00151 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \ 00152 *out = in; return S_OK; } 00153 00154 /* Compiler cast where input cannot be negative */ 00155 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \ 00156 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; } 00157 00158 /* Compiler cast where input cannot be > some number */ 00159 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \ 00160 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; } 00161 00162 /* Compiler cast where input cannot be < some number or >= some other number */ 00163 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \ 00164 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; } 00165 00166 /* I1 */ 00167 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX) 00168 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX) 00169 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX) 00170 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool) 00171 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX) 00172 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX) 00173 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX) 00174 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX) 00175 00176 /* UI1 */ 00177 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX) 00178 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool) 00179 NEGTST(BYTE, signed char, VarUI1FromI1) 00180 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX) 00181 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX) 00182 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX) 00183 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX) 00184 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX) 00185 00186 /* I2 */ 00187 SIMPLE(SHORT, BYTE, VarI2FromUI1) 00188 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX) 00189 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool) 00190 SIMPLE(SHORT, signed char, VarI2FromI1) 00191 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX) 00192 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX) 00193 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX) 00194 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX) 00195 00196 /* UI2 */ 00197 SIMPLE(USHORT, BYTE, VarUI2FromUI1) 00198 NEGTST(USHORT, SHORT, VarUI2FromI2) 00199 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX) 00200 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool) 00201 NEGTST(USHORT, signed char, VarUI2FromI1) 00202 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX) 00203 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX) 00204 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX) 00205 00206 /* I4 */ 00207 SIMPLE(LONG, BYTE, VarI4FromUI1) 00208 SIMPLE(LONG, SHORT, VarI4FromI2) 00209 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool) 00210 SIMPLE(LONG, signed char, VarI4FromI1) 00211 SIMPLE(LONG, USHORT, VarI4FromUI2) 00212 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX) 00213 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX) 00214 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX) 00215 00216 /* UI4 */ 00217 SIMPLE(ULONG, BYTE, VarUI4FromUI1) 00218 NEGTST(ULONG, SHORT, VarUI4FromI2) 00219 NEGTST(ULONG, LONG, VarUI4FromI4) 00220 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool) 00221 NEGTST(ULONG, signed char, VarUI4FromI1) 00222 SIMPLE(ULONG, USHORT, VarUI4FromUI2) 00223 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX) 00224 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX) 00225 00226 /* I8 */ 00227 SIMPLE(LONG64, BYTE, VarI8FromUI1) 00228 SIMPLE(LONG64, SHORT, VarI8FromI2) 00229 SIMPLE(LONG64, signed char, VarI8FromI1) 00230 SIMPLE(LONG64, USHORT, VarI8FromUI2) 00231 SIMPLE(LONG64, ULONG, VarI8FromUI4) 00232 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX) 00233 00234 /* UI8 */ 00235 SIMPLE(ULONG64, BYTE, VarUI8FromUI1) 00236 NEGTST(ULONG64, SHORT, VarUI8FromI2) 00237 NEGTST(ULONG64, signed char, VarUI8FromI1) 00238 SIMPLE(ULONG64, USHORT, VarUI8FromUI2) 00239 SIMPLE(ULONG64, ULONG, VarUI8FromUI4) 00240 NEGTST(ULONG64, LONG64, VarUI8FromI8) 00241 00242 /* R4 (float) */ 00243 SIMPLE(float, BYTE, VarR4FromUI1) 00244 SIMPLE(float, SHORT, VarR4FromI2) 00245 SIMPLE(float, signed char, VarR4FromI1) 00246 SIMPLE(float, USHORT, VarR4FromUI2) 00247 SIMPLE(float, LONG, VarR4FromI4) 00248 SIMPLE(float, ULONG, VarR4FromUI4) 00249 SIMPLE(float, LONG64, VarR4FromI8) 00250 SIMPLE(float, ULONG64, VarR4FromUI8) 00251 00252 /* R8 (double) */ 00253 SIMPLE(double, BYTE, VarR8FromUI1) 00254 SIMPLE(double, SHORT, VarR8FromI2) 00255 SIMPLE(double, float, VarR8FromR4) 00256 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; } 00257 SIMPLE(double, DATE, VarR8FromDate) 00258 SIMPLE(double, signed char, VarR8FromI1) 00259 SIMPLE(double, USHORT, VarR8FromUI2) 00260 SIMPLE(double, LONG, VarR8FromI4) 00261 SIMPLE(double, ULONG, VarR8FromUI4) 00262 SIMPLE(double, LONG64, VarR8FromI8) 00263 SIMPLE(double, ULONG64, VarR8FromUI8) 00264 00265 00266 /* I1 00267 */ 00268 00269 /************************************************************************ 00270 * VarI1FromUI1 (OLEAUT32.244) 00271 * 00272 * Convert a VT_UI1 to a VT_I1. 00273 * 00274 * PARAMS 00275 * bIn [I] Source 00276 * pcOut [O] Destination 00277 * 00278 * RETURNS 00279 * Success: S_OK. 00280 * Failure: E_INVALIDARG, if the source value is invalid 00281 * DISP_E_OVERFLOW, if the value will not fit in the destination 00282 */ 00283 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut) 00284 { 00285 return _VarI1FromUI1(bIn, pcOut); 00286 } 00287 00288 /************************************************************************ 00289 * VarI1FromI2 (OLEAUT32.245) 00290 * 00291 * Convert a VT_I2 to a VT_I1. 00292 * 00293 * PARAMS 00294 * sIn [I] Source 00295 * pcOut [O] Destination 00296 * 00297 * RETURNS 00298 * Success: S_OK. 00299 * Failure: E_INVALIDARG, if the source value is invalid 00300 * DISP_E_OVERFLOW, if the value will not fit in the destination 00301 */ 00302 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut) 00303 { 00304 return _VarI1FromI2(sIn, pcOut); 00305 } 00306 00307 /************************************************************************ 00308 * VarI1FromI4 (OLEAUT32.246) 00309 * 00310 * Convert a VT_I4 to a VT_I1. 00311 * 00312 * PARAMS 00313 * iIn [I] Source 00314 * pcOut [O] Destination 00315 * 00316 * RETURNS 00317 * Success: S_OK. 00318 * Failure: E_INVALIDARG, if the source value is invalid 00319 * DISP_E_OVERFLOW, if the value will not fit in the destination 00320 */ 00321 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut) 00322 { 00323 return _VarI1FromI4(iIn, pcOut); 00324 } 00325 00326 /************************************************************************ 00327 * VarI1FromR4 (OLEAUT32.247) 00328 * 00329 * Convert a VT_R4 to a VT_I1. 00330 * 00331 * PARAMS 00332 * fltIn [I] Source 00333 * pcOut [O] Destination 00334 * 00335 * RETURNS 00336 * Success: S_OK. 00337 * Failure: E_INVALIDARG, if the source value is invalid 00338 * DISP_E_OVERFLOW, if the value will not fit in the destination 00339 */ 00340 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut) 00341 { 00342 return VarI1FromR8(fltIn, pcOut); 00343 } 00344 00345 /************************************************************************ 00346 * VarI1FromR8 (OLEAUT32.248) 00347 * 00348 * Convert a VT_R8 to a VT_I1. 00349 * 00350 * PARAMS 00351 * dblIn [I] Source 00352 * pcOut [O] Destination 00353 * 00354 * RETURNS 00355 * Success: S_OK. 00356 * Failure: E_INVALIDARG, if the source value is invalid 00357 * DISP_E_OVERFLOW, if the value will not fit in the destination 00358 * 00359 * NOTES 00360 * See VarI8FromR8() for details concerning rounding. 00361 */ 00362 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut) 00363 { 00364 if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX) 00365 return DISP_E_OVERFLOW; 00366 VARIANT_DutchRound(CHAR, dblIn, *pcOut); 00367 return S_OK; 00368 } 00369 00370 /************************************************************************ 00371 * VarI1FromDate (OLEAUT32.249) 00372 * 00373 * Convert a VT_DATE to a VT_I1. 00374 * 00375 * PARAMS 00376 * dateIn [I] Source 00377 * pcOut [O] Destination 00378 * 00379 * RETURNS 00380 * Success: S_OK. 00381 * Failure: E_INVALIDARG, if the source value is invalid 00382 * DISP_E_OVERFLOW, if the value will not fit in the destination 00383 */ 00384 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut) 00385 { 00386 return VarI1FromR8(dateIn, pcOut); 00387 } 00388 00389 /************************************************************************ 00390 * VarI1FromCy (OLEAUT32.250) 00391 * 00392 * Convert a VT_CY to a VT_I1. 00393 * 00394 * PARAMS 00395 * cyIn [I] Source 00396 * pcOut [O] Destination 00397 * 00398 * RETURNS 00399 * Success: S_OK. 00400 * Failure: E_INVALIDARG, if the source value is invalid 00401 * DISP_E_OVERFLOW, if the value will not fit in the destination 00402 */ 00403 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut) 00404 { 00405 LONG i = I1_MAX + 1; 00406 00407 VarI4FromCy(cyIn, &i); 00408 return _VarI1FromI4(i, pcOut); 00409 } 00410 00411 /************************************************************************ 00412 * VarI1FromStr (OLEAUT32.251) 00413 * 00414 * Convert a VT_BSTR to a VT_I1. 00415 * 00416 * PARAMS 00417 * strIn [I] Source 00418 * lcid [I] LCID for the conversion 00419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 00420 * pcOut [O] Destination 00421 * 00422 * RETURNS 00423 * Success: S_OK. 00424 * Failure: E_INVALIDARG, if the source value is invalid 00425 * DISP_E_OVERFLOW, if the value will not fit in the destination 00426 * DISP_E_TYPEMISMATCH, if the type cannot be converted 00427 */ 00428 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut) 00429 { 00430 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1); 00431 } 00432 00433 /************************************************************************ 00434 * VarI1FromDisp (OLEAUT32.252) 00435 * 00436 * Convert a VT_DISPATCH to a VT_I1. 00437 * 00438 * PARAMS 00439 * pdispIn [I] Source 00440 * lcid [I] LCID for conversion 00441 * pcOut [O] Destination 00442 * 00443 * RETURNS 00444 * Success: S_OK. 00445 * Failure: E_INVALIDARG, if the source value is invalid 00446 * DISP_E_OVERFLOW, if the value will not fit in the destination 00447 * DISP_E_TYPEMISMATCH, if the type cannot be converted 00448 */ 00449 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut) 00450 { 00451 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0); 00452 } 00453 00454 /************************************************************************ 00455 * VarI1FromBool (OLEAUT32.253) 00456 * 00457 * Convert a VT_BOOL to a VT_I1. 00458 * 00459 * PARAMS 00460 * boolIn [I] Source 00461 * pcOut [O] Destination 00462 * 00463 * RETURNS 00464 * S_OK. 00465 */ 00466 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut) 00467 { 00468 return _VarI1FromBool(boolIn, pcOut); 00469 } 00470 00471 /************************************************************************ 00472 * VarI1FromUI2 (OLEAUT32.254) 00473 * 00474 * Convert a VT_UI2 to a VT_I1. 00475 * 00476 * PARAMS 00477 * usIn [I] Source 00478 * pcOut [O] Destination 00479 * 00480 * RETURNS 00481 * Success: S_OK. 00482 * Failure: E_INVALIDARG, if the source value is invalid 00483 * DISP_E_OVERFLOW, if the value will not fit in the destination 00484 */ 00485 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut) 00486 { 00487 return _VarI1FromUI2(usIn, pcOut); 00488 } 00489 00490 /************************************************************************ 00491 * VarI1FromUI4 (OLEAUT32.255) 00492 * 00493 * Convert a VT_UI4 to a VT_I1. 00494 * 00495 * PARAMS 00496 * ulIn [I] Source 00497 * pcOut [O] Destination 00498 * 00499 * RETURNS 00500 * Success: S_OK. 00501 * Failure: E_INVALIDARG, if the source value is invalid 00502 * DISP_E_OVERFLOW, if the value will not fit in the destination 00503 * DISP_E_TYPEMISMATCH, if the type cannot be converted 00504 */ 00505 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut) 00506 { 00507 return _VarI1FromUI4(ulIn, pcOut); 00508 } 00509 00510 /************************************************************************ 00511 * VarI1FromDec (OLEAUT32.256) 00512 * 00513 * Convert a VT_DECIMAL to a VT_I1. 00514 * 00515 * PARAMS 00516 * pDecIn [I] Source 00517 * pcOut [O] Destination 00518 * 00519 * RETURNS 00520 * Success: S_OK. 00521 * Failure: E_INVALIDARG, if the source value is invalid 00522 * DISP_E_OVERFLOW, if the value will not fit in the destination 00523 */ 00524 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut) 00525 { 00526 LONG64 i64; 00527 HRESULT hRet; 00528 00529 hRet = VarI8FromDec(pdecIn, &i64); 00530 00531 if (SUCCEEDED(hRet)) 00532 hRet = _VarI1FromI8(i64, pcOut); 00533 return hRet; 00534 } 00535 00536 /************************************************************************ 00537 * VarI1FromI8 (OLEAUT32.376) 00538 * 00539 * Convert a VT_I8 to a VT_I1. 00540 * 00541 * PARAMS 00542 * llIn [I] Source 00543 * pcOut [O] Destination 00544 * 00545 * RETURNS 00546 * Success: S_OK. 00547 * Failure: E_INVALIDARG, if the source value is invalid 00548 * DISP_E_OVERFLOW, if the value will not fit in the destination 00549 */ 00550 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut) 00551 { 00552 return _VarI1FromI8(llIn, pcOut); 00553 } 00554 00555 /************************************************************************ 00556 * VarI1FromUI8 (OLEAUT32.377) 00557 * 00558 * Convert a VT_UI8 to a VT_I1. 00559 * 00560 * PARAMS 00561 * ullIn [I] Source 00562 * pcOut [O] Destination 00563 * 00564 * RETURNS 00565 * Success: S_OK. 00566 * Failure: E_INVALIDARG, if the source value is invalid 00567 * DISP_E_OVERFLOW, if the value will not fit in the destination 00568 */ 00569 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut) 00570 { 00571 return _VarI1FromUI8(ullIn, pcOut); 00572 } 00573 00574 /* UI1 00575 */ 00576 00577 /************************************************************************ 00578 * VarUI1FromI2 (OLEAUT32.130) 00579 * 00580 * Convert a VT_I2 to a VT_UI1. 00581 * 00582 * PARAMS 00583 * sIn [I] Source 00584 * pbOut [O] Destination 00585 * 00586 * RETURNS 00587 * Success: S_OK. 00588 * Failure: E_INVALIDARG, if the source value is invalid 00589 * DISP_E_OVERFLOW, if the value will not fit in the destination 00590 */ 00591 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut) 00592 { 00593 return _VarUI1FromI2(sIn, pbOut); 00594 } 00595 00596 /************************************************************************ 00597 * VarUI1FromI4 (OLEAUT32.131) 00598 * 00599 * Convert a VT_I4 to a VT_UI1. 00600 * 00601 * PARAMS 00602 * iIn [I] Source 00603 * pbOut [O] Destination 00604 * 00605 * RETURNS 00606 * Success: S_OK. 00607 * Failure: E_INVALIDARG, if the source value is invalid 00608 * DISP_E_OVERFLOW, if the value will not fit in the destination 00609 */ 00610 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut) 00611 { 00612 return _VarUI1FromI4(iIn, pbOut); 00613 } 00614 00615 /************************************************************************ 00616 * VarUI1FromR4 (OLEAUT32.132) 00617 * 00618 * Convert a VT_R4 to a VT_UI1. 00619 * 00620 * PARAMS 00621 * fltIn [I] Source 00622 * pbOut [O] Destination 00623 * 00624 * RETURNS 00625 * Success: S_OK. 00626 * Failure: E_INVALIDARG, if the source value is invalid 00627 * DISP_E_OVERFLOW, if the value will not fit in the destination 00628 * DISP_E_TYPEMISMATCH, if the type cannot be converted 00629 */ 00630 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut) 00631 { 00632 return VarUI1FromR8(fltIn, pbOut); 00633 } 00634 00635 /************************************************************************ 00636 * VarUI1FromR8 (OLEAUT32.133) 00637 * 00638 * Convert a VT_R8 to a VT_UI1. 00639 * 00640 * PARAMS 00641 * dblIn [I] Source 00642 * pbOut [O] Destination 00643 * 00644 * RETURNS 00645 * Success: S_OK. 00646 * Failure: E_INVALIDARG, if the source value is invalid 00647 * DISP_E_OVERFLOW, if the value will not fit in the destination 00648 * 00649 * NOTES 00650 * See VarI8FromR8() for details concerning rounding. 00651 */ 00652 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut) 00653 { 00654 if (dblIn < -0.5 || dblIn > (double)UI1_MAX) 00655 return DISP_E_OVERFLOW; 00656 VARIANT_DutchRound(BYTE, dblIn, *pbOut); 00657 return S_OK; 00658 } 00659 00660 /************************************************************************ 00661 * VarUI1FromCy (OLEAUT32.134) 00662 * 00663 * Convert a VT_CY to a VT_UI1. 00664 * 00665 * PARAMS 00666 * cyIn [I] Source 00667 * pbOut [O] Destination 00668 * 00669 * RETURNS 00670 * Success: S_OK. 00671 * Failure: E_INVALIDARG, if the source value is invalid 00672 * DISP_E_OVERFLOW, if the value will not fit in the destination 00673 * 00674 * NOTES 00675 * Negative values >= -5000 will be converted to 0. 00676 */ 00677 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) 00678 { 00679 ULONG i = UI1_MAX + 1; 00680 00681 VarUI4FromCy(cyIn, &i); 00682 return _VarUI1FromUI4(i, pbOut); 00683 } 00684 00685 /************************************************************************ 00686 * VarUI1FromDate (OLEAUT32.135) 00687 * 00688 * Convert a VT_DATE to a VT_UI1. 00689 * 00690 * PARAMS 00691 * dateIn [I] Source 00692 * pbOut [O] Destination 00693 * 00694 * RETURNS 00695 * Success: S_OK. 00696 * Failure: E_INVALIDARG, if the source value is invalid 00697 * DISP_E_OVERFLOW, if the value will not fit in the destination 00698 */ 00699 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut) 00700 { 00701 return VarUI1FromR8(dateIn, pbOut); 00702 } 00703 00704 /************************************************************************ 00705 * VarUI1FromStr (OLEAUT32.136) 00706 * 00707 * Convert a VT_BSTR to a VT_UI1. 00708 * 00709 * PARAMS 00710 * strIn [I] Source 00711 * lcid [I] LCID for the conversion 00712 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 00713 * pbOut [O] Destination 00714 * 00715 * RETURNS 00716 * Success: S_OK. 00717 * Failure: E_INVALIDARG, if the source value is invalid 00718 * DISP_E_OVERFLOW, if the value will not fit in the destination 00719 * DISP_E_TYPEMISMATCH, if the type cannot be converted 00720 */ 00721 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut) 00722 { 00723 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1); 00724 } 00725 00726 /************************************************************************ 00727 * VarUI1FromDisp (OLEAUT32.137) 00728 * 00729 * Convert a VT_DISPATCH to a VT_UI1. 00730 * 00731 * PARAMS 00732 * pdispIn [I] Source 00733 * lcid [I] LCID for conversion 00734 * pbOut [O] Destination 00735 * 00736 * RETURNS 00737 * Success: S_OK. 00738 * Failure: E_INVALIDARG, if the source value is invalid 00739 * DISP_E_OVERFLOW, if the value will not fit in the destination 00740 * DISP_E_TYPEMISMATCH, if the type cannot be converted 00741 */ 00742 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut) 00743 { 00744 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0); 00745 } 00746 00747 /************************************************************************ 00748 * VarUI1FromBool (OLEAUT32.138) 00749 * 00750 * Convert a VT_BOOL to a VT_UI1. 00751 * 00752 * PARAMS 00753 * boolIn [I] Source 00754 * pbOut [O] Destination 00755 * 00756 * RETURNS 00757 * S_OK. 00758 */ 00759 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut) 00760 { 00761 return _VarUI1FromBool(boolIn, pbOut); 00762 } 00763 00764 /************************************************************************ 00765 * VarUI1FromI1 (OLEAUT32.237) 00766 * 00767 * Convert a VT_I1 to a VT_UI1. 00768 * 00769 * PARAMS 00770 * cIn [I] Source 00771 * pbOut [O] Destination 00772 * 00773 * RETURNS 00774 * Success: S_OK. 00775 * Failure: E_INVALIDARG, if the source value is invalid 00776 * DISP_E_OVERFLOW, if the value will not fit in the destination 00777 */ 00778 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut) 00779 { 00780 return _VarUI1FromI1(cIn, pbOut); 00781 } 00782 00783 /************************************************************************ 00784 * VarUI1FromUI2 (OLEAUT32.238) 00785 * 00786 * Convert a VT_UI2 to a VT_UI1. 00787 * 00788 * PARAMS 00789 * usIn [I] Source 00790 * pbOut [O] Destination 00791 * 00792 * RETURNS 00793 * Success: S_OK. 00794 * Failure: E_INVALIDARG, if the source value is invalid 00795 * DISP_E_OVERFLOW, if the value will not fit in the destination 00796 */ 00797 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut) 00798 { 00799 return _VarUI1FromUI2(usIn, pbOut); 00800 } 00801 00802 /************************************************************************ 00803 * VarUI1FromUI4 (OLEAUT32.239) 00804 * 00805 * Convert a VT_UI4 to a VT_UI1. 00806 * 00807 * PARAMS 00808 * ulIn [I] Source 00809 * pbOut [O] Destination 00810 * 00811 * RETURNS 00812 * Success: S_OK. 00813 * Failure: E_INVALIDARG, if the source value is invalid 00814 * DISP_E_OVERFLOW, if the value will not fit in the destination 00815 */ 00816 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut) 00817 { 00818 return _VarUI1FromUI4(ulIn, pbOut); 00819 } 00820 00821 /************************************************************************ 00822 * VarUI1FromDec (OLEAUT32.240) 00823 * 00824 * Convert a VT_DECIMAL to a VT_UI1. 00825 * 00826 * PARAMS 00827 * pDecIn [I] Source 00828 * pbOut [O] Destination 00829 * 00830 * RETURNS 00831 * Success: S_OK. 00832 * Failure: E_INVALIDARG, if the source value is invalid 00833 * DISP_E_OVERFLOW, if the value will not fit in the destination 00834 */ 00835 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut) 00836 { 00837 LONG64 i64; 00838 HRESULT hRet; 00839 00840 hRet = VarI8FromDec(pdecIn, &i64); 00841 00842 if (SUCCEEDED(hRet)) 00843 hRet = _VarUI1FromI8(i64, pbOut); 00844 return hRet; 00845 } 00846 00847 /************************************************************************ 00848 * VarUI1FromI8 (OLEAUT32.372) 00849 * 00850 * Convert a VT_I8 to a VT_UI1. 00851 * 00852 * PARAMS 00853 * llIn [I] Source 00854 * pbOut [O] Destination 00855 * 00856 * RETURNS 00857 * Success: S_OK. 00858 * Failure: E_INVALIDARG, if the source value is invalid 00859 * DISP_E_OVERFLOW, if the value will not fit in the destination 00860 */ 00861 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut) 00862 { 00863 return _VarUI1FromI8(llIn, pbOut); 00864 } 00865 00866 /************************************************************************ 00867 * VarUI1FromUI8 (OLEAUT32.373) 00868 * 00869 * Convert a VT_UI8 to a VT_UI1. 00870 * 00871 * PARAMS 00872 * ullIn [I] Source 00873 * pbOut [O] Destination 00874 * 00875 * RETURNS 00876 * Success: S_OK. 00877 * Failure: E_INVALIDARG, if the source value is invalid 00878 * DISP_E_OVERFLOW, if the value will not fit in the destination 00879 */ 00880 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut) 00881 { 00882 return _VarUI1FromUI8(ullIn, pbOut); 00883 } 00884 00885 00886 /* I2 00887 */ 00888 00889 /************************************************************************ 00890 * VarI2FromUI1 (OLEAUT32.48) 00891 * 00892 * Convert a VT_UI2 to a VT_I2. 00893 * 00894 * PARAMS 00895 * bIn [I] Source 00896 * psOut [O] Destination 00897 * 00898 * RETURNS 00899 * S_OK. 00900 */ 00901 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut) 00902 { 00903 return _VarI2FromUI1(bIn, psOut); 00904 } 00905 00906 /************************************************************************ 00907 * VarI2FromI4 (OLEAUT32.49) 00908 * 00909 * Convert a VT_I4 to a VT_I2. 00910 * 00911 * PARAMS 00912 * iIn [I] Source 00913 * psOut [O] Destination 00914 * 00915 * RETURNS 00916 * Success: S_OK. 00917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 00918 */ 00919 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut) 00920 { 00921 return _VarI2FromI4(iIn, psOut); 00922 } 00923 00924 /************************************************************************ 00925 * VarI2FromR4 (OLEAUT32.50) 00926 * 00927 * Convert a VT_R4 to a VT_I2. 00928 * 00929 * PARAMS 00930 * fltIn [I] Source 00931 * psOut [O] Destination 00932 * 00933 * RETURNS 00934 * Success: S_OK. 00935 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 00936 */ 00937 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut) 00938 { 00939 return VarI2FromR8(fltIn, psOut); 00940 } 00941 00942 /************************************************************************ 00943 * VarI2FromR8 (OLEAUT32.51) 00944 * 00945 * Convert a VT_R8 to a VT_I2. 00946 * 00947 * PARAMS 00948 * dblIn [I] Source 00949 * psOut [O] Destination 00950 * 00951 * RETURNS 00952 * Success: S_OK. 00953 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 00954 * 00955 * NOTES 00956 * See VarI8FromR8() for details concerning rounding. 00957 */ 00958 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut) 00959 { 00960 if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX) 00961 return DISP_E_OVERFLOW; 00962 VARIANT_DutchRound(SHORT, dblIn, *psOut); 00963 return S_OK; 00964 } 00965 00966 /************************************************************************ 00967 * VarI2FromCy (OLEAUT32.52) 00968 * 00969 * Convert a VT_CY to a VT_I2. 00970 * 00971 * PARAMS 00972 * cyIn [I] Source 00973 * psOut [O] Destination 00974 * 00975 * RETURNS 00976 * Success: S_OK. 00977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 00978 */ 00979 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut) 00980 { 00981 LONG i = I2_MAX + 1; 00982 00983 VarI4FromCy(cyIn, &i); 00984 return _VarI2FromI4(i, psOut); 00985 } 00986 00987 /************************************************************************ 00988 * VarI2FromDate (OLEAUT32.53) 00989 * 00990 * Convert a VT_DATE to a VT_I2. 00991 * 00992 * PARAMS 00993 * dateIn [I] Source 00994 * psOut [O] Destination 00995 * 00996 * RETURNS 00997 * Success: S_OK. 00998 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 00999 */ 01000 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut) 01001 { 01002 return VarI2FromR8(dateIn, psOut); 01003 } 01004 01005 /************************************************************************ 01006 * VarI2FromStr (OLEAUT32.54) 01007 * 01008 * Convert a VT_BSTR to a VT_I2. 01009 * 01010 * PARAMS 01011 * strIn [I] Source 01012 * lcid [I] LCID for the conversion 01013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 01014 * psOut [O] Destination 01015 * 01016 * RETURNS 01017 * Success: S_OK. 01018 * Failure: E_INVALIDARG, if any parameter is invalid 01019 * DISP_E_OVERFLOW, if the value will not fit in the destination 01020 * DISP_E_TYPEMISMATCH, if the type cannot be converted 01021 */ 01022 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut) 01023 { 01024 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2); 01025 } 01026 01027 /************************************************************************ 01028 * VarI2FromDisp (OLEAUT32.55) 01029 * 01030 * Convert a VT_DISPATCH to a VT_I2. 01031 * 01032 * PARAMS 01033 * pdispIn [I] Source 01034 * lcid [I] LCID for conversion 01035 * psOut [O] Destination 01036 * 01037 * RETURNS 01038 * Success: S_OK. 01039 * Failure: E_INVALIDARG, if pdispIn is invalid, 01040 * DISP_E_OVERFLOW, if the value will not fit in the destination, 01041 * DISP_E_TYPEMISMATCH, if the type cannot be converted 01042 */ 01043 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut) 01044 { 01045 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0); 01046 } 01047 01048 /************************************************************************ 01049 * VarI2FromBool (OLEAUT32.56) 01050 * 01051 * Convert a VT_BOOL to a VT_I2. 01052 * 01053 * PARAMS 01054 * boolIn [I] Source 01055 * psOut [O] Destination 01056 * 01057 * RETURNS 01058 * S_OK. 01059 */ 01060 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut) 01061 { 01062 return _VarI2FromBool(boolIn, psOut); 01063 } 01064 01065 /************************************************************************ 01066 * VarI2FromI1 (OLEAUT32.205) 01067 * 01068 * Convert a VT_I1 to a VT_I2. 01069 * 01070 * PARAMS 01071 * cIn [I] Source 01072 * psOut [O] Destination 01073 * 01074 * RETURNS 01075 * S_OK. 01076 */ 01077 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut) 01078 { 01079 return _VarI2FromI1(cIn, psOut); 01080 } 01081 01082 /************************************************************************ 01083 * VarI2FromUI2 (OLEAUT32.206) 01084 * 01085 * Convert a VT_UI2 to a VT_I2. 01086 * 01087 * PARAMS 01088 * usIn [I] Source 01089 * psOut [O] Destination 01090 * 01091 * RETURNS 01092 * Success: S_OK. 01093 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01094 */ 01095 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut) 01096 { 01097 return _VarI2FromUI2(usIn, psOut); 01098 } 01099 01100 /************************************************************************ 01101 * VarI2FromUI4 (OLEAUT32.207) 01102 * 01103 * Convert a VT_UI4 to a VT_I2. 01104 * 01105 * PARAMS 01106 * ulIn [I] Source 01107 * psOut [O] Destination 01108 * 01109 * RETURNS 01110 * Success: S_OK. 01111 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01112 */ 01113 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut) 01114 { 01115 return _VarI2FromUI4(ulIn, psOut); 01116 } 01117 01118 /************************************************************************ 01119 * VarI2FromDec (OLEAUT32.208) 01120 * 01121 * Convert a VT_DECIMAL to a VT_I2. 01122 * 01123 * PARAMS 01124 * pDecIn [I] Source 01125 * psOut [O] Destination 01126 * 01127 * RETURNS 01128 * Success: S_OK. 01129 * Failure: E_INVALIDARG, if the source value is invalid 01130 * DISP_E_OVERFLOW, if the value will not fit in the destination 01131 */ 01132 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut) 01133 { 01134 LONG64 i64; 01135 HRESULT hRet; 01136 01137 hRet = VarI8FromDec(pdecIn, &i64); 01138 01139 if (SUCCEEDED(hRet)) 01140 hRet = _VarI2FromI8(i64, psOut); 01141 return hRet; 01142 } 01143 01144 /************************************************************************ 01145 * VarI2FromI8 (OLEAUT32.346) 01146 * 01147 * Convert a VT_I8 to a VT_I2. 01148 * 01149 * PARAMS 01150 * llIn [I] Source 01151 * psOut [O] Destination 01152 * 01153 * RETURNS 01154 * Success: S_OK. 01155 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01156 */ 01157 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut) 01158 { 01159 return _VarI2FromI8(llIn, psOut); 01160 } 01161 01162 /************************************************************************ 01163 * VarI2FromUI8 (OLEAUT32.347) 01164 * 01165 * Convert a VT_UI8 to a VT_I2. 01166 * 01167 * PARAMS 01168 * ullIn [I] Source 01169 * psOut [O] Destination 01170 * 01171 * RETURNS 01172 * Success: S_OK. 01173 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01174 */ 01175 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut) 01176 { 01177 return _VarI2FromUI8(ullIn, psOut); 01178 } 01179 01180 /* UI2 01181 */ 01182 01183 /************************************************************************ 01184 * VarUI2FromUI1 (OLEAUT32.257) 01185 * 01186 * Convert a VT_UI1 to a VT_UI2. 01187 * 01188 * PARAMS 01189 * bIn [I] Source 01190 * pusOut [O] Destination 01191 * 01192 * RETURNS 01193 * S_OK. 01194 */ 01195 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut) 01196 { 01197 return _VarUI2FromUI1(bIn, pusOut); 01198 } 01199 01200 /************************************************************************ 01201 * VarUI2FromI2 (OLEAUT32.258) 01202 * 01203 * Convert a VT_I2 to a VT_UI2. 01204 * 01205 * PARAMS 01206 * sIn [I] Source 01207 * pusOut [O] Destination 01208 * 01209 * RETURNS 01210 * Success: S_OK. 01211 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01212 */ 01213 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut) 01214 { 01215 return _VarUI2FromI2(sIn, pusOut); 01216 } 01217 01218 /************************************************************************ 01219 * VarUI2FromI4 (OLEAUT32.259) 01220 * 01221 * Convert a VT_I4 to a VT_UI2. 01222 * 01223 * PARAMS 01224 * iIn [I] Source 01225 * pusOut [O] Destination 01226 * 01227 * RETURNS 01228 * Success: S_OK. 01229 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01230 */ 01231 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut) 01232 { 01233 return _VarUI2FromI4(iIn, pusOut); 01234 } 01235 01236 /************************************************************************ 01237 * VarUI2FromR4 (OLEAUT32.260) 01238 * 01239 * Convert a VT_R4 to a VT_UI2. 01240 * 01241 * PARAMS 01242 * fltIn [I] Source 01243 * pusOut [O] Destination 01244 * 01245 * RETURNS 01246 * Success: S_OK. 01247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01248 */ 01249 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut) 01250 { 01251 return VarUI2FromR8(fltIn, pusOut); 01252 } 01253 01254 /************************************************************************ 01255 * VarUI2FromR8 (OLEAUT32.261) 01256 * 01257 * Convert a VT_R8 to a VT_UI2. 01258 * 01259 * PARAMS 01260 * dblIn [I] Source 01261 * pusOut [O] Destination 01262 * 01263 * RETURNS 01264 * Success: S_OK. 01265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01266 * 01267 * NOTES 01268 * See VarI8FromR8() for details concerning rounding. 01269 */ 01270 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut) 01271 { 01272 if (dblIn < -0.5 || dblIn > (double)UI2_MAX) 01273 return DISP_E_OVERFLOW; 01274 VARIANT_DutchRound(USHORT, dblIn, *pusOut); 01275 return S_OK; 01276 } 01277 01278 /************************************************************************ 01279 * VarUI2FromDate (OLEAUT32.262) 01280 * 01281 * Convert a VT_DATE to a VT_UI2. 01282 * 01283 * PARAMS 01284 * dateIn [I] Source 01285 * pusOut [O] Destination 01286 * 01287 * RETURNS 01288 * Success: S_OK. 01289 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01290 */ 01291 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut) 01292 { 01293 return VarUI2FromR8(dateIn, pusOut); 01294 } 01295 01296 /************************************************************************ 01297 * VarUI2FromCy (OLEAUT32.263) 01298 * 01299 * Convert a VT_CY to a VT_UI2. 01300 * 01301 * PARAMS 01302 * cyIn [I] Source 01303 * pusOut [O] Destination 01304 * 01305 * RETURNS 01306 * Success: S_OK. 01307 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01308 * 01309 * NOTES 01310 * Negative values >= -5000 will be converted to 0. 01311 */ 01312 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) 01313 { 01314 ULONG i = UI2_MAX + 1; 01315 01316 VarUI4FromCy(cyIn, &i); 01317 return _VarUI2FromUI4(i, pusOut); 01318 } 01319 01320 /************************************************************************ 01321 * VarUI2FromStr (OLEAUT32.264) 01322 * 01323 * Convert a VT_BSTR to a VT_UI2. 01324 * 01325 * PARAMS 01326 * strIn [I] Source 01327 * lcid [I] LCID for the conversion 01328 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 01329 * pusOut [O] Destination 01330 * 01331 * RETURNS 01332 * Success: S_OK. 01333 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01334 * DISP_E_TYPEMISMATCH, if the type cannot be converted 01335 */ 01336 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut) 01337 { 01338 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2); 01339 } 01340 01341 /************************************************************************ 01342 * VarUI2FromDisp (OLEAUT32.265) 01343 * 01344 * Convert a VT_DISPATCH to a VT_UI2. 01345 * 01346 * PARAMS 01347 * pdispIn [I] Source 01348 * lcid [I] LCID for conversion 01349 * pusOut [O] Destination 01350 * 01351 * RETURNS 01352 * Success: S_OK. 01353 * Failure: E_INVALIDARG, if the source value is invalid 01354 * DISP_E_OVERFLOW, if the value will not fit in the destination 01355 * DISP_E_TYPEMISMATCH, if the type cannot be converted 01356 */ 01357 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut) 01358 { 01359 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0); 01360 } 01361 01362 /************************************************************************ 01363 * VarUI2FromBool (OLEAUT32.266) 01364 * 01365 * Convert a VT_BOOL to a VT_UI2. 01366 * 01367 * PARAMS 01368 * boolIn [I] Source 01369 * pusOut [O] Destination 01370 * 01371 * RETURNS 01372 * S_OK. 01373 */ 01374 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut) 01375 { 01376 return _VarUI2FromBool(boolIn, pusOut); 01377 } 01378 01379 /************************************************************************ 01380 * VarUI2FromI1 (OLEAUT32.267) 01381 * 01382 * Convert a VT_I1 to a VT_UI2. 01383 * 01384 * PARAMS 01385 * cIn [I] Source 01386 * pusOut [O] Destination 01387 * 01388 * RETURNS 01389 * Success: S_OK. 01390 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01391 */ 01392 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut) 01393 { 01394 return _VarUI2FromI1(cIn, pusOut); 01395 } 01396 01397 /************************************************************************ 01398 * VarUI2FromUI4 (OLEAUT32.268) 01399 * 01400 * Convert a VT_UI4 to a VT_UI2. 01401 * 01402 * PARAMS 01403 * ulIn [I] Source 01404 * pusOut [O] Destination 01405 * 01406 * RETURNS 01407 * Success: S_OK. 01408 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01409 */ 01410 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut) 01411 { 01412 return _VarUI2FromUI4(ulIn, pusOut); 01413 } 01414 01415 /************************************************************************ 01416 * VarUI2FromDec (OLEAUT32.269) 01417 * 01418 * Convert a VT_DECIMAL to a VT_UI2. 01419 * 01420 * PARAMS 01421 * pDecIn [I] Source 01422 * pusOut [O] Destination 01423 * 01424 * RETURNS 01425 * Success: S_OK. 01426 * Failure: E_INVALIDARG, if the source value is invalid 01427 * DISP_E_OVERFLOW, if the value will not fit in the destination 01428 */ 01429 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut) 01430 { 01431 LONG64 i64; 01432 HRESULT hRet; 01433 01434 hRet = VarI8FromDec(pdecIn, &i64); 01435 01436 if (SUCCEEDED(hRet)) 01437 hRet = _VarUI2FromI8(i64, pusOut); 01438 return hRet; 01439 } 01440 01441 /************************************************************************ 01442 * VarUI2FromI8 (OLEAUT32.378) 01443 * 01444 * Convert a VT_I8 to a VT_UI2. 01445 * 01446 * PARAMS 01447 * llIn [I] Source 01448 * pusOut [O] Destination 01449 * 01450 * RETURNS 01451 * Success: S_OK. 01452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01453 */ 01454 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut) 01455 { 01456 return _VarUI2FromI8(llIn, pusOut); 01457 } 01458 01459 /************************************************************************ 01460 * VarUI2FromUI8 (OLEAUT32.379) 01461 * 01462 * Convert a VT_UI8 to a VT_UI2. 01463 * 01464 * PARAMS 01465 * ullIn [I] Source 01466 * pusOut [O] Destination 01467 * 01468 * RETURNS 01469 * Success: S_OK. 01470 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01471 */ 01472 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut) 01473 { 01474 return _VarUI2FromUI8(ullIn, pusOut); 01475 } 01476 01477 /* I4 01478 */ 01479 01480 /************************************************************************ 01481 * VarI4FromUI1 (OLEAUT32.58) 01482 * 01483 * Convert a VT_UI1 to a VT_I4. 01484 * 01485 * PARAMS 01486 * bIn [I] Source 01487 * piOut [O] Destination 01488 * 01489 * RETURNS 01490 * S_OK. 01491 */ 01492 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut) 01493 { 01494 return _VarI4FromUI1(bIn, piOut); 01495 } 01496 01497 /************************************************************************ 01498 * VarI4FromI2 (OLEAUT32.59) 01499 * 01500 * Convert a VT_I2 to a VT_I4. 01501 * 01502 * PARAMS 01503 * sIn [I] Source 01504 * piOut [O] Destination 01505 * 01506 * RETURNS 01507 * Success: S_OK. 01508 * Failure: E_INVALIDARG, if the source value is invalid 01509 * DISP_E_OVERFLOW, if the value will not fit in the destination 01510 */ 01511 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut) 01512 { 01513 return _VarI4FromI2(sIn, piOut); 01514 } 01515 01516 /************************************************************************ 01517 * VarI4FromR4 (OLEAUT32.60) 01518 * 01519 * Convert a VT_R4 to a VT_I4. 01520 * 01521 * PARAMS 01522 * fltIn [I] Source 01523 * piOut [O] Destination 01524 * 01525 * RETURNS 01526 * Success: S_OK. 01527 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01528 */ 01529 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut) 01530 { 01531 return VarI4FromR8(fltIn, piOut); 01532 } 01533 01534 /************************************************************************ 01535 * VarI4FromR8 (OLEAUT32.61) 01536 * 01537 * Convert a VT_R8 to a VT_I4. 01538 * 01539 * PARAMS 01540 * dblIn [I] Source 01541 * piOut [O] Destination 01542 * 01543 * RETURNS 01544 * Success: S_OK. 01545 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01546 * 01547 * NOTES 01548 * See VarI8FromR8() for details concerning rounding. 01549 */ 01550 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut) 01551 { 01552 if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX) 01553 return DISP_E_OVERFLOW; 01554 VARIANT_DutchRound(LONG, dblIn, *piOut); 01555 return S_OK; 01556 } 01557 01558 /************************************************************************ 01559 * VarI4FromCy (OLEAUT32.62) 01560 * 01561 * Convert a VT_CY to a VT_I4. 01562 * 01563 * PARAMS 01564 * cyIn [I] Source 01565 * piOut [O] Destination 01566 * 01567 * RETURNS 01568 * Success: S_OK. 01569 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01570 */ 01571 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut) 01572 { 01573 double d = cyIn.int64 / CY_MULTIPLIER_F; 01574 return VarI4FromR8(d, piOut); 01575 } 01576 01577 /************************************************************************ 01578 * VarI4FromDate (OLEAUT32.63) 01579 * 01580 * Convert a VT_DATE to a VT_I4. 01581 * 01582 * PARAMS 01583 * dateIn [I] Source 01584 * piOut [O] Destination 01585 * 01586 * RETURNS 01587 * Success: S_OK. 01588 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01589 */ 01590 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut) 01591 { 01592 return VarI4FromR8(dateIn, piOut); 01593 } 01594 01595 /************************************************************************ 01596 * VarI4FromStr (OLEAUT32.64) 01597 * 01598 * Convert a VT_BSTR to a VT_I4. 01599 * 01600 * PARAMS 01601 * strIn [I] Source 01602 * lcid [I] LCID for the conversion 01603 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 01604 * piOut [O] Destination 01605 * 01606 * RETURNS 01607 * Success: S_OK. 01608 * Failure: E_INVALIDARG, if any parameter is invalid 01609 * DISP_E_OVERFLOW, if the value will not fit in the destination 01610 * DISP_E_TYPEMISMATCH, if strIn cannot be converted 01611 */ 01612 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut) 01613 { 01614 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4); 01615 } 01616 01617 /************************************************************************ 01618 * VarI4FromDisp (OLEAUT32.65) 01619 * 01620 * Convert a VT_DISPATCH to a VT_I4. 01621 * 01622 * PARAMS 01623 * pdispIn [I] Source 01624 * lcid [I] LCID for conversion 01625 * piOut [O] Destination 01626 * 01627 * RETURNS 01628 * Success: S_OK. 01629 * Failure: E_INVALIDARG, if the source value is invalid 01630 * DISP_E_OVERFLOW, if the value will not fit in the destination 01631 * DISP_E_TYPEMISMATCH, if the type cannot be converted 01632 */ 01633 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut) 01634 { 01635 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0); 01636 } 01637 01638 /************************************************************************ 01639 * VarI4FromBool (OLEAUT32.66) 01640 * 01641 * Convert a VT_BOOL to a VT_I4. 01642 * 01643 * PARAMS 01644 * boolIn [I] Source 01645 * piOut [O] Destination 01646 * 01647 * RETURNS 01648 * S_OK. 01649 */ 01650 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut) 01651 { 01652 return _VarI4FromBool(boolIn, piOut); 01653 } 01654 01655 /************************************************************************ 01656 * VarI4FromI1 (OLEAUT32.209) 01657 * 01658 * Convert a VT_I4 to a VT_I4. 01659 * 01660 * PARAMS 01661 * cIn [I] Source 01662 * piOut [O] Destination 01663 * 01664 * RETURNS 01665 * S_OK. 01666 */ 01667 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut) 01668 { 01669 return _VarI4FromI1(cIn, piOut); 01670 } 01671 01672 /************************************************************************ 01673 * VarI4FromUI2 (OLEAUT32.210) 01674 * 01675 * Convert a VT_UI2 to a VT_I4. 01676 * 01677 * PARAMS 01678 * usIn [I] Source 01679 * piOut [O] Destination 01680 * 01681 * RETURNS 01682 * S_OK. 01683 */ 01684 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut) 01685 { 01686 return _VarI4FromUI2(usIn, piOut); 01687 } 01688 01689 /************************************************************************ 01690 * VarI4FromUI4 (OLEAUT32.211) 01691 * 01692 * Convert a VT_UI4 to a VT_I4. 01693 * 01694 * PARAMS 01695 * ulIn [I] Source 01696 * piOut [O] Destination 01697 * 01698 * RETURNS 01699 * Success: S_OK. 01700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01701 */ 01702 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut) 01703 { 01704 return _VarI4FromUI4(ulIn, piOut); 01705 } 01706 01707 /************************************************************************ 01708 * VarI4FromDec (OLEAUT32.212) 01709 * 01710 * Convert a VT_DECIMAL to a VT_I4. 01711 * 01712 * PARAMS 01713 * pDecIn [I] Source 01714 * piOut [O] Destination 01715 * 01716 * RETURNS 01717 * Success: S_OK. 01718 * Failure: E_INVALIDARG, if pdecIn is invalid 01719 * DISP_E_OVERFLOW, if the value will not fit in the destination 01720 */ 01721 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut) 01722 { 01723 LONG64 i64; 01724 HRESULT hRet; 01725 01726 hRet = VarI8FromDec(pdecIn, &i64); 01727 01728 if (SUCCEEDED(hRet)) 01729 hRet = _VarI4FromI8(i64, piOut); 01730 return hRet; 01731 } 01732 01733 /************************************************************************ 01734 * VarI4FromI8 (OLEAUT32.348) 01735 * 01736 * Convert a VT_I8 to a VT_I4. 01737 * 01738 * PARAMS 01739 * llIn [I] Source 01740 * piOut [O] Destination 01741 * 01742 * RETURNS 01743 * Success: S_OK. 01744 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01745 */ 01746 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut) 01747 { 01748 return _VarI4FromI8(llIn, piOut); 01749 } 01750 01751 /************************************************************************ 01752 * VarI4FromUI8 (OLEAUT32.349) 01753 * 01754 * Convert a VT_UI8 to a VT_I4. 01755 * 01756 * PARAMS 01757 * ullIn [I] Source 01758 * piOut [O] Destination 01759 * 01760 * RETURNS 01761 * Success: S_OK. 01762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01763 */ 01764 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut) 01765 { 01766 return _VarI4FromUI8(ullIn, piOut); 01767 } 01768 01769 /* UI4 01770 */ 01771 01772 /************************************************************************ 01773 * VarUI4FromUI1 (OLEAUT32.270) 01774 * 01775 * Convert a VT_UI1 to a VT_UI4. 01776 * 01777 * PARAMS 01778 * bIn [I] Source 01779 * pulOut [O] Destination 01780 * 01781 * RETURNS 01782 * S_OK. 01783 */ 01784 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut) 01785 { 01786 return _VarUI4FromUI1(bIn, pulOut); 01787 } 01788 01789 /************************************************************************ 01790 * VarUI4FromI2 (OLEAUT32.271) 01791 * 01792 * Convert a VT_I2 to a VT_UI4. 01793 * 01794 * PARAMS 01795 * sIn [I] Source 01796 * pulOut [O] Destination 01797 * 01798 * RETURNS 01799 * Success: S_OK. 01800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01801 */ 01802 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut) 01803 { 01804 return _VarUI4FromI2(sIn, pulOut); 01805 } 01806 01807 /************************************************************************ 01808 * VarUI4FromI4 (OLEAUT32.272) 01809 * 01810 * Convert a VT_I4 to a VT_UI4. 01811 * 01812 * PARAMS 01813 * iIn [I] Source 01814 * pulOut [O] Destination 01815 * 01816 * RETURNS 01817 * Success: S_OK. 01818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01819 */ 01820 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut) 01821 { 01822 return _VarUI4FromI4(iIn, pulOut); 01823 } 01824 01825 /************************************************************************ 01826 * VarUI4FromR4 (OLEAUT32.273) 01827 * 01828 * Convert a VT_R4 to a VT_UI4. 01829 * 01830 * PARAMS 01831 * fltIn [I] Source 01832 * pulOut [O] Destination 01833 * 01834 * RETURNS 01835 * Success: S_OK. 01836 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01837 */ 01838 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut) 01839 { 01840 return VarUI4FromR8(fltIn, pulOut); 01841 } 01842 01843 /************************************************************************ 01844 * VarUI4FromR8 (OLEAUT32.274) 01845 * 01846 * Convert a VT_R8 to a VT_UI4. 01847 * 01848 * PARAMS 01849 * dblIn [I] Source 01850 * pulOut [O] Destination 01851 * 01852 * RETURNS 01853 * Success: S_OK. 01854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01855 * 01856 * NOTES 01857 * See VarI8FromR8() for details concerning rounding. 01858 */ 01859 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut) 01860 { 01861 if (dblIn < -0.5 || dblIn > (double)UI4_MAX) 01862 return DISP_E_OVERFLOW; 01863 VARIANT_DutchRound(ULONG, dblIn, *pulOut); 01864 return S_OK; 01865 } 01866 01867 /************************************************************************ 01868 * VarUI4FromDate (OLEAUT32.275) 01869 * 01870 * Convert a VT_DATE to a VT_UI4. 01871 * 01872 * PARAMS 01873 * dateIn [I] Source 01874 * pulOut [O] Destination 01875 * 01876 * RETURNS 01877 * Success: S_OK. 01878 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01879 */ 01880 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut) 01881 { 01882 return VarUI4FromR8(dateIn, pulOut); 01883 } 01884 01885 /************************************************************************ 01886 * VarUI4FromCy (OLEAUT32.276) 01887 * 01888 * Convert a VT_CY to a VT_UI4. 01889 * 01890 * PARAMS 01891 * cyIn [I] Source 01892 * pulOut [O] Destination 01893 * 01894 * RETURNS 01895 * Success: S_OK. 01896 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01897 */ 01898 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut) 01899 { 01900 double d = cyIn.int64 / CY_MULTIPLIER_F; 01901 return VarUI4FromR8(d, pulOut); 01902 } 01903 01904 /************************************************************************ 01905 * VarUI4FromStr (OLEAUT32.277) 01906 * 01907 * Convert a VT_BSTR to a VT_UI4. 01908 * 01909 * PARAMS 01910 * strIn [I] Source 01911 * lcid [I] LCID for the conversion 01912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 01913 * pulOut [O] Destination 01914 * 01915 * RETURNS 01916 * Success: S_OK. 01917 * Failure: E_INVALIDARG, if any parameter is invalid 01918 * DISP_E_OVERFLOW, if the value will not fit in the destination 01919 * DISP_E_TYPEMISMATCH, if strIn cannot be converted 01920 */ 01921 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut) 01922 { 01923 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4); 01924 } 01925 01926 /************************************************************************ 01927 * VarUI4FromDisp (OLEAUT32.278) 01928 * 01929 * Convert a VT_DISPATCH to a VT_UI4. 01930 * 01931 * PARAMS 01932 * pdispIn [I] Source 01933 * lcid [I] LCID for conversion 01934 * pulOut [O] Destination 01935 * 01936 * RETURNS 01937 * Success: S_OK. 01938 * Failure: E_INVALIDARG, if the source value is invalid 01939 * DISP_E_OVERFLOW, if the value will not fit in the destination 01940 * DISP_E_TYPEMISMATCH, if the type cannot be converted 01941 */ 01942 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut) 01943 { 01944 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0); 01945 } 01946 01947 /************************************************************************ 01948 * VarUI4FromBool (OLEAUT32.279) 01949 * 01950 * Convert a VT_BOOL to a VT_UI4. 01951 * 01952 * PARAMS 01953 * boolIn [I] Source 01954 * pulOut [O] Destination 01955 * 01956 * RETURNS 01957 * S_OK. 01958 */ 01959 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut) 01960 { 01961 return _VarUI4FromBool(boolIn, pulOut); 01962 } 01963 01964 /************************************************************************ 01965 * VarUI4FromI1 (OLEAUT32.280) 01966 * 01967 * Convert a VT_I1 to a VT_UI4. 01968 * 01969 * PARAMS 01970 * cIn [I] Source 01971 * pulOut [O] Destination 01972 * 01973 * RETURNS 01974 * Success: S_OK. 01975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 01976 */ 01977 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut) 01978 { 01979 return _VarUI4FromI1(cIn, pulOut); 01980 } 01981 01982 /************************************************************************ 01983 * VarUI4FromUI2 (OLEAUT32.281) 01984 * 01985 * Convert a VT_UI2 to a VT_UI4. 01986 * 01987 * PARAMS 01988 * usIn [I] Source 01989 * pulOut [O] Destination 01990 * 01991 * RETURNS 01992 * S_OK. 01993 */ 01994 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut) 01995 { 01996 return _VarUI4FromUI2(usIn, pulOut); 01997 } 01998 01999 /************************************************************************ 02000 * VarUI4FromDec (OLEAUT32.282) 02001 * 02002 * Convert a VT_DECIMAL to a VT_UI4. 02003 * 02004 * PARAMS 02005 * pDecIn [I] Source 02006 * pulOut [O] Destination 02007 * 02008 * RETURNS 02009 * Success: S_OK. 02010 * Failure: E_INVALIDARG, if pdecIn is invalid 02011 * DISP_E_OVERFLOW, if the value will not fit in the destination 02012 */ 02013 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut) 02014 { 02015 LONG64 i64; 02016 HRESULT hRet; 02017 02018 hRet = VarI8FromDec(pdecIn, &i64); 02019 02020 if (SUCCEEDED(hRet)) 02021 hRet = _VarUI4FromI8(i64, pulOut); 02022 return hRet; 02023 } 02024 02025 /************************************************************************ 02026 * VarUI4FromI8 (OLEAUT32.425) 02027 * 02028 * Convert a VT_I8 to a VT_UI4. 02029 * 02030 * PARAMS 02031 * llIn [I] Source 02032 * pulOut [O] Destination 02033 * 02034 * RETURNS 02035 * Success: S_OK. 02036 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 02037 */ 02038 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut) 02039 { 02040 return _VarUI4FromI8(llIn, pulOut); 02041 } 02042 02043 /************************************************************************ 02044 * VarUI4FromUI8 (OLEAUT32.426) 02045 * 02046 * Convert a VT_UI8 to a VT_UI4. 02047 * 02048 * PARAMS 02049 * ullIn [I] Source 02050 * pulOut [O] Destination 02051 * 02052 * RETURNS 02053 * Success: S_OK. 02054 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 02055 */ 02056 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut) 02057 { 02058 return _VarUI4FromUI8(ullIn, pulOut); 02059 } 02060 02061 /* I8 02062 */ 02063 02064 /************************************************************************ 02065 * VarI8FromUI1 (OLEAUT32.333) 02066 * 02067 * Convert a VT_UI1 to a VT_I8. 02068 * 02069 * PARAMS 02070 * bIn [I] Source 02071 * pi64Out [O] Destination 02072 * 02073 * RETURNS 02074 * S_OK. 02075 */ 02076 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out) 02077 { 02078 return _VarI8FromUI1(bIn, pi64Out); 02079 } 02080 02081 02082 /************************************************************************ 02083 * VarI8FromI2 (OLEAUT32.334) 02084 * 02085 * Convert a VT_I2 to a VT_I8. 02086 * 02087 * PARAMS 02088 * sIn [I] Source 02089 * pi64Out [O] Destination 02090 * 02091 * RETURNS 02092 * S_OK. 02093 */ 02094 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out) 02095 { 02096 return _VarI8FromI2(sIn, pi64Out); 02097 } 02098 02099 /************************************************************************ 02100 * VarI8FromR4 (OLEAUT32.335) 02101 * 02102 * Convert a VT_R4 to a VT_I8. 02103 * 02104 * PARAMS 02105 * fltIn [I] Source 02106 * pi64Out [O] Destination 02107 * 02108 * RETURNS 02109 * Success: S_OK. 02110 * Failure: E_INVALIDARG, if the source value is invalid 02111 * DISP_E_OVERFLOW, if the value will not fit in the destination 02112 */ 02113 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out) 02114 { 02115 return VarI8FromR8(fltIn, pi64Out); 02116 } 02117 02118 /************************************************************************ 02119 * VarI8FromR8 (OLEAUT32.336) 02120 * 02121 * Convert a VT_R8 to a VT_I8. 02122 * 02123 * PARAMS 02124 * dblIn [I] Source 02125 * pi64Out [O] Destination 02126 * 02127 * RETURNS 02128 * Success: S_OK. 02129 * Failure: E_INVALIDARG, if the source value is invalid 02130 * DISP_E_OVERFLOW, if the value will not fit in the destination 02131 * 02132 * NOTES 02133 * Only values that fit into 63 bits are accepted. Due to rounding issues, 02134 * very high or low values will not be accurately converted. 02135 * 02136 * Numbers are rounded using Dutch rounding, as follows: 02137 * 02138 *| Fractional Part Sign Direction Example 02139 *| --------------- ---- --------- ------- 02140 *| < 0.5 + Down 0.4 -> 0.0 02141 *| < 0.5 - Up -0.4 -> 0.0 02142 *| > 0.5 + Up 0.6 -> 1.0 02143 *| < 0.5 - Up -0.6 -> -1.0 02144 *| = 0.5 + Up/Down Down if even, Up if odd 02145 *| = 0.5 - Up/Down Up if even, Down if odd 02146 * 02147 * This system is often used in supermarkets. 02148 */ 02149 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out) 02150 { 02151 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0) 02152 return DISP_E_OVERFLOW; 02153 VARIANT_DutchRound(LONG64, dblIn, *pi64Out); 02154 return S_OK; 02155 } 02156 02157 /************************************************************************ 02158 * VarI8FromCy (OLEAUT32.337) 02159 * 02160 * Convert a VT_CY to a VT_I8. 02161 * 02162 * PARAMS 02163 * cyIn [I] Source 02164 * pi64Out [O] Destination 02165 * 02166 * RETURNS 02167 * S_OK. 02168 * 02169 * NOTES 02170 * All negative numbers are rounded down by 1, including those that are 02171 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics). 02172 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8() 02173 * for details. 02174 */ 02175 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out) 02176 { 02177 *pi64Out = cyIn.int64 / CY_MULTIPLIER; 02178 02179 if (cyIn.int64 < 0) 02180 (*pi64Out)--; /* Mimic Win32 bug */ 02181 else 02182 { 02183 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ 02184 02185 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1))) 02186 (*pi64Out)++; 02187 } 02188 return S_OK; 02189 } 02190 02191 /************************************************************************ 02192 * VarI8FromDate (OLEAUT32.338) 02193 * 02194 * Convert a VT_DATE to a VT_I8. 02195 * 02196 * PARAMS 02197 * dateIn [I] Source 02198 * pi64Out [O] Destination 02199 * 02200 * RETURNS 02201 * Success: S_OK. 02202 * Failure: E_INVALIDARG, if the source value is invalid 02203 * DISP_E_OVERFLOW, if the value will not fit in the destination 02204 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02205 */ 02206 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out) 02207 { 02208 return VarI8FromR8(dateIn, pi64Out); 02209 } 02210 02211 /************************************************************************ 02212 * VarI8FromStr (OLEAUT32.339) 02213 * 02214 * Convert a VT_BSTR to a VT_I8. 02215 * 02216 * PARAMS 02217 * strIn [I] Source 02218 * lcid [I] LCID for the conversion 02219 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 02220 * pi64Out [O] Destination 02221 * 02222 * RETURNS 02223 * Success: S_OK. 02224 * Failure: E_INVALIDARG, if the source value is invalid 02225 * DISP_E_OVERFLOW, if the value will not fit in the destination 02226 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02227 */ 02228 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out) 02229 { 02230 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8); 02231 } 02232 02233 /************************************************************************ 02234 * VarI8FromDisp (OLEAUT32.340) 02235 * 02236 * Convert a VT_DISPATCH to a VT_I8. 02237 * 02238 * PARAMS 02239 * pdispIn [I] Source 02240 * lcid [I] LCID for conversion 02241 * pi64Out [O] Destination 02242 * 02243 * RETURNS 02244 * Success: S_OK. 02245 * Failure: E_INVALIDARG, if the source value is invalid 02246 * DISP_E_OVERFLOW, if the value will not fit in the destination 02247 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02248 */ 02249 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out) 02250 { 02251 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0); 02252 } 02253 02254 /************************************************************************ 02255 * VarI8FromBool (OLEAUT32.341) 02256 * 02257 * Convert a VT_BOOL to a VT_I8. 02258 * 02259 * PARAMS 02260 * boolIn [I] Source 02261 * pi64Out [O] Destination 02262 * 02263 * RETURNS 02264 * S_OK. 02265 */ 02266 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out) 02267 { 02268 return VarI8FromI2(boolIn, pi64Out); 02269 } 02270 02271 /************************************************************************ 02272 * VarI8FromI1 (OLEAUT32.342) 02273 * 02274 * Convert a VT_I1 to a VT_I8. 02275 * 02276 * PARAMS 02277 * cIn [I] Source 02278 * pi64Out [O] Destination 02279 * 02280 * RETURNS 02281 * S_OK. 02282 */ 02283 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out) 02284 { 02285 return _VarI8FromI1(cIn, pi64Out); 02286 } 02287 02288 /************************************************************************ 02289 * VarI8FromUI2 (OLEAUT32.343) 02290 * 02291 * Convert a VT_UI2 to a VT_I8. 02292 * 02293 * PARAMS 02294 * usIn [I] Source 02295 * pi64Out [O] Destination 02296 * 02297 * RETURNS 02298 * S_OK. 02299 */ 02300 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out) 02301 { 02302 return _VarI8FromUI2(usIn, pi64Out); 02303 } 02304 02305 /************************************************************************ 02306 * VarI8FromUI4 (OLEAUT32.344) 02307 * 02308 * Convert a VT_UI4 to a VT_I8. 02309 * 02310 * PARAMS 02311 * ulIn [I] Source 02312 * pi64Out [O] Destination 02313 * 02314 * RETURNS 02315 * S_OK. 02316 */ 02317 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out) 02318 { 02319 return _VarI8FromUI4(ulIn, pi64Out); 02320 } 02321 02322 /************************************************************************ 02323 * VarI8FromDec (OLEAUT32.345) 02324 * 02325 * Convert a VT_DECIMAL to a VT_I8. 02326 * 02327 * PARAMS 02328 * pDecIn [I] Source 02329 * pi64Out [O] Destination 02330 * 02331 * RETURNS 02332 * Success: S_OK. 02333 * Failure: E_INVALIDARG, if the source value is invalid 02334 * DISP_E_OVERFLOW, if the value will not fit in the destination 02335 */ 02336 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out) 02337 { 02338 if (!DEC_SCALE(pdecIn)) 02339 { 02340 /* This decimal is just a 96 bit integer */ 02341 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) 02342 return E_INVALIDARG; 02343 02344 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000) 02345 return DISP_E_OVERFLOW; 02346 02347 if (DEC_SIGN(pdecIn)) 02348 *pi64Out = -DEC_LO64(pdecIn); 02349 else 02350 *pi64Out = DEC_LO64(pdecIn); 02351 return S_OK; 02352 } 02353 else 02354 { 02355 /* Decimal contains a floating point number */ 02356 HRESULT hRet; 02357 double dbl; 02358 02359 hRet = VarR8FromDec(pdecIn, &dbl); 02360 if (SUCCEEDED(hRet)) 02361 hRet = VarI8FromR8(dbl, pi64Out); 02362 return hRet; 02363 } 02364 } 02365 02366 /************************************************************************ 02367 * VarI8FromUI8 (OLEAUT32.427) 02368 * 02369 * Convert a VT_UI8 to a VT_I8. 02370 * 02371 * PARAMS 02372 * ullIn [I] Source 02373 * pi64Out [O] Destination 02374 * 02375 * RETURNS 02376 * Success: S_OK. 02377 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 02378 */ 02379 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out) 02380 { 02381 return _VarI8FromUI8(ullIn, pi64Out); 02382 } 02383 02384 /* UI8 02385 */ 02386 02387 /************************************************************************ 02388 * VarUI8FromI8 (OLEAUT32.428) 02389 * 02390 * Convert a VT_I8 to a VT_UI8. 02391 * 02392 * PARAMS 02393 * ulIn [I] Source 02394 * pui64Out [O] Destination 02395 * 02396 * RETURNS 02397 * Success: S_OK. 02398 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 02399 */ 02400 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out) 02401 { 02402 return _VarUI8FromI8(llIn, pui64Out); 02403 } 02404 02405 /************************************************************************ 02406 * VarUI8FromUI1 (OLEAUT32.429) 02407 * 02408 * Convert a VT_UI1 to a VT_UI8. 02409 * 02410 * PARAMS 02411 * bIn [I] Source 02412 * pui64Out [O] Destination 02413 * 02414 * RETURNS 02415 * S_OK. 02416 */ 02417 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out) 02418 { 02419 return _VarUI8FromUI1(bIn, pui64Out); 02420 } 02421 02422 /************************************************************************ 02423 * VarUI8FromI2 (OLEAUT32.430) 02424 * 02425 * Convert a VT_I2 to a VT_UI8. 02426 * 02427 * PARAMS 02428 * sIn [I] Source 02429 * pui64Out [O] Destination 02430 * 02431 * RETURNS 02432 * S_OK. 02433 */ 02434 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out) 02435 { 02436 return _VarUI8FromI2(sIn, pui64Out); 02437 } 02438 02439 /************************************************************************ 02440 * VarUI8FromR4 (OLEAUT32.431) 02441 * 02442 * Convert a VT_R4 to a VT_UI8. 02443 * 02444 * PARAMS 02445 * fltIn [I] Source 02446 * pui64Out [O] Destination 02447 * 02448 * RETURNS 02449 * Success: S_OK. 02450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 02451 */ 02452 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out) 02453 { 02454 return VarUI8FromR8(fltIn, pui64Out); 02455 } 02456 02457 /************************************************************************ 02458 * VarUI8FromR8 (OLEAUT32.432) 02459 * 02460 * Convert a VT_R8 to a VT_UI8. 02461 * 02462 * PARAMS 02463 * dblIn [I] Source 02464 * pui64Out [O] Destination 02465 * 02466 * RETURNS 02467 * Success: S_OK. 02468 * Failure: E_INVALIDARG, if the source value is invalid 02469 * DISP_E_OVERFLOW, if the value will not fit in the destination 02470 * 02471 * NOTES 02472 * See VarI8FromR8() for details concerning rounding. 02473 */ 02474 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out) 02475 { 02476 if (dblIn < -0.5 || dblIn > 1.844674407370955e19) 02477 return DISP_E_OVERFLOW; 02478 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out); 02479 return S_OK; 02480 } 02481 02482 /************************************************************************ 02483 * VarUI8FromCy (OLEAUT32.433) 02484 * 02485 * Convert a VT_CY to a VT_UI8. 02486 * 02487 * PARAMS 02488 * cyIn [I] Source 02489 * pui64Out [O] Destination 02490 * 02491 * RETURNS 02492 * Success: S_OK. 02493 * Failure: E_INVALIDARG, if the source value is invalid 02494 * DISP_E_OVERFLOW, if the value will not fit in the destination 02495 * 02496 * NOTES 02497 * Negative values >= -5000 will be converted to 0. 02498 */ 02499 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out) 02500 { 02501 if (cyIn.int64 < 0) 02502 { 02503 if (cyIn.int64 < -CY_HALF) 02504 return DISP_E_OVERFLOW; 02505 *pui64Out = 0; 02506 } 02507 else 02508 { 02509 *pui64Out = cyIn.int64 / CY_MULTIPLIER; 02510 02511 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ 02512 02513 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1))) 02514 (*pui64Out)++; 02515 } 02516 return S_OK; 02517 } 02518 02519 /************************************************************************ 02520 * VarUI8FromDate (OLEAUT32.434) 02521 * 02522 * Convert a VT_DATE to a VT_UI8. 02523 * 02524 * PARAMS 02525 * dateIn [I] Source 02526 * pui64Out [O] Destination 02527 * 02528 * RETURNS 02529 * Success: S_OK. 02530 * Failure: E_INVALIDARG, if the source value is invalid 02531 * DISP_E_OVERFLOW, if the value will not fit in the destination 02532 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02533 */ 02534 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out) 02535 { 02536 return VarUI8FromR8(dateIn, pui64Out); 02537 } 02538 02539 /************************************************************************ 02540 * VarUI8FromStr (OLEAUT32.435) 02541 * 02542 * Convert a VT_BSTR to a VT_UI8. 02543 * 02544 * PARAMS 02545 * strIn [I] Source 02546 * lcid [I] LCID for the conversion 02547 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 02548 * pui64Out [O] Destination 02549 * 02550 * RETURNS 02551 * Success: S_OK. 02552 * Failure: E_INVALIDARG, if the source value is invalid 02553 * DISP_E_OVERFLOW, if the value will not fit in the destination 02554 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02555 */ 02556 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out) 02557 { 02558 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8); 02559 } 02560 02561 /************************************************************************ 02562 * VarUI8FromDisp (OLEAUT32.436) 02563 * 02564 * Convert a VT_DISPATCH to a VT_UI8. 02565 * 02566 * PARAMS 02567 * pdispIn [I] Source 02568 * lcid [I] LCID for conversion 02569 * pui64Out [O] Destination 02570 * 02571 * RETURNS 02572 * Success: S_OK. 02573 * Failure: E_INVALIDARG, if the source value is invalid 02574 * DISP_E_OVERFLOW, if the value will not fit in the destination 02575 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02576 */ 02577 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out) 02578 { 02579 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0); 02580 } 02581 02582 /************************************************************************ 02583 * VarUI8FromBool (OLEAUT32.437) 02584 * 02585 * Convert a VT_BOOL to a VT_UI8. 02586 * 02587 * PARAMS 02588 * boolIn [I] Source 02589 * pui64Out [O] Destination 02590 * 02591 * RETURNS 02592 * Success: S_OK. 02593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 02594 */ 02595 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out) 02596 { 02597 return VarI8FromI2(boolIn, (LONG64 *)pui64Out); 02598 } 02599 /************************************************************************ 02600 * VarUI8FromI1 (OLEAUT32.438) 02601 * 02602 * Convert a VT_I1 to a VT_UI8. 02603 * 02604 * PARAMS 02605 * cIn [I] Source 02606 * pui64Out [O] Destination 02607 * 02608 * RETURNS 02609 * Success: S_OK. 02610 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 02611 */ 02612 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out) 02613 { 02614 return _VarUI8FromI1(cIn, pui64Out); 02615 } 02616 02617 /************************************************************************ 02618 * VarUI8FromUI2 (OLEAUT32.439) 02619 * 02620 * Convert a VT_UI2 to a VT_UI8. 02621 * 02622 * PARAMS 02623 * usIn [I] Source 02624 * pui64Out [O] Destination 02625 * 02626 * RETURNS 02627 * S_OK. 02628 */ 02629 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out) 02630 { 02631 return _VarUI8FromUI2(usIn, pui64Out); 02632 } 02633 02634 /************************************************************************ 02635 * VarUI8FromUI4 (OLEAUT32.440) 02636 * 02637 * Convert a VT_UI4 to a VT_UI8. 02638 * 02639 * PARAMS 02640 * ulIn [I] Source 02641 * pui64Out [O] Destination 02642 * 02643 * RETURNS 02644 * S_OK. 02645 */ 02646 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out) 02647 { 02648 return _VarUI8FromUI4(ulIn, pui64Out); 02649 } 02650 02651 /************************************************************************ 02652 * VarUI8FromDec (OLEAUT32.441) 02653 * 02654 * Convert a VT_DECIMAL to a VT_UI8. 02655 * 02656 * PARAMS 02657 * pDecIn [I] Source 02658 * pui64Out [O] Destination 02659 * 02660 * RETURNS 02661 * Success: S_OK. 02662 * Failure: E_INVALIDARG, if the source value is invalid 02663 * DISP_E_OVERFLOW, if the value will not fit in the destination 02664 * 02665 * NOTES 02666 * Under native Win32, if the source value has a scale of 0, its sign is 02667 * ignored, i.e. this function takes the absolute value rather than fail 02668 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation 02669 * (use VarAbs() on pDecIn first if you really want this behaviour). 02670 */ 02671 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out) 02672 { 02673 if (!DEC_SCALE(pdecIn)) 02674 { 02675 /* This decimal is just a 96 bit integer */ 02676 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) 02677 return E_INVALIDARG; 02678 02679 if (DEC_HI32(pdecIn)) 02680 return DISP_E_OVERFLOW; 02681 02682 if (DEC_SIGN(pdecIn)) 02683 { 02684 WARN("Sign would be ignored under Win32!\n"); 02685 return DISP_E_OVERFLOW; 02686 } 02687 02688 *pui64Out = DEC_LO64(pdecIn); 02689 return S_OK; 02690 } 02691 else 02692 { 02693 /* Decimal contains a floating point number */ 02694 HRESULT hRet; 02695 double dbl; 02696 02697 hRet = VarR8FromDec(pdecIn, &dbl); 02698 if (SUCCEEDED(hRet)) 02699 hRet = VarUI8FromR8(dbl, pui64Out); 02700 return hRet; 02701 } 02702 } 02703 02704 /* R4 02705 */ 02706 02707 /************************************************************************ 02708 * VarR4FromUI1 (OLEAUT32.68) 02709 * 02710 * Convert a VT_UI1 to a VT_R4. 02711 * 02712 * PARAMS 02713 * bIn [I] Source 02714 * pFltOut [O] Destination 02715 * 02716 * RETURNS 02717 * S_OK. 02718 */ 02719 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut) 02720 { 02721 return _VarR4FromUI1(bIn, pFltOut); 02722 } 02723 02724 /************************************************************************ 02725 * VarR4FromI2 (OLEAUT32.69) 02726 * 02727 * Convert a VT_I2 to a VT_R4. 02728 * 02729 * PARAMS 02730 * sIn [I] Source 02731 * pFltOut [O] Destination 02732 * 02733 * RETURNS 02734 * S_OK. 02735 */ 02736 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut) 02737 { 02738 return _VarR4FromI2(sIn, pFltOut); 02739 } 02740 02741 /************************************************************************ 02742 * VarR4FromI4 (OLEAUT32.70) 02743 * 02744 * Convert a VT_I4 to a VT_R4. 02745 * 02746 * PARAMS 02747 * sIn [I] Source 02748 * pFltOut [O] Destination 02749 * 02750 * RETURNS 02751 * S_OK. 02752 */ 02753 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut) 02754 { 02755 return _VarR4FromI4(lIn, pFltOut); 02756 } 02757 02758 /************************************************************************ 02759 * VarR4FromR8 (OLEAUT32.71) 02760 * 02761 * Convert a VT_R8 to a VT_R4. 02762 * 02763 * PARAMS 02764 * dblIn [I] Source 02765 * pFltOut [O] Destination 02766 * 02767 * RETURNS 02768 * Success: S_OK. 02769 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. 02770 */ 02771 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut) 02772 { 02773 double d = dblIn < 0.0 ? -dblIn : dblIn; 02774 if (d > R4_MAX) return DISP_E_OVERFLOW; 02775 *pFltOut = dblIn; 02776 return S_OK; 02777 } 02778 02779 /************************************************************************ 02780 * VarR4FromCy (OLEAUT32.72) 02781 * 02782 * Convert a VT_CY to a VT_R4. 02783 * 02784 * PARAMS 02785 * cyIn [I] Source 02786 * pFltOut [O] Destination 02787 * 02788 * RETURNS 02789 * S_OK. 02790 */ 02791 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut) 02792 { 02793 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F; 02794 return S_OK; 02795 } 02796 02797 /************************************************************************ 02798 * VarR4FromDate (OLEAUT32.73) 02799 * 02800 * Convert a VT_DATE to a VT_R4. 02801 * 02802 * PARAMS 02803 * dateIn [I] Source 02804 * pFltOut [O] Destination 02805 * 02806 * RETURNS 02807 * Success: S_OK. 02808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. 02809 */ 02810 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut) 02811 { 02812 return VarR4FromR8(dateIn, pFltOut); 02813 } 02814 02815 /************************************************************************ 02816 * VarR4FromStr (OLEAUT32.74) 02817 * 02818 * Convert a VT_BSTR to a VT_R4. 02819 * 02820 * PARAMS 02821 * strIn [I] Source 02822 * lcid [I] LCID for the conversion 02823 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 02824 * pFltOut [O] Destination 02825 * 02826 * RETURNS 02827 * Success: S_OK. 02828 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid. 02829 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02830 */ 02831 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut) 02832 { 02833 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4); 02834 } 02835 02836 /************************************************************************ 02837 * VarR4FromDisp (OLEAUT32.75) 02838 * 02839 * Convert a VT_DISPATCH to a VT_R4. 02840 * 02841 * PARAMS 02842 * pdispIn [I] Source 02843 * lcid [I] LCID for conversion 02844 * pFltOut [O] Destination 02845 * 02846 * RETURNS 02847 * Success: S_OK. 02848 * Failure: E_INVALIDARG, if the source value is invalid 02849 * DISP_E_OVERFLOW, if the value will not fit in the destination 02850 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02851 */ 02852 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut) 02853 { 02854 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0); 02855 } 02856 02857 /************************************************************************ 02858 * VarR4FromBool (OLEAUT32.76) 02859 * 02860 * Convert a VT_BOOL to a VT_R4. 02861 * 02862 * PARAMS 02863 * boolIn [I] Source 02864 * pFltOut [O] Destination 02865 * 02866 * RETURNS 02867 * S_OK. 02868 */ 02869 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut) 02870 { 02871 return VarR4FromI2(boolIn, pFltOut); 02872 } 02873 02874 /************************************************************************ 02875 * VarR4FromI1 (OLEAUT32.213) 02876 * 02877 * Convert a VT_I1 to a VT_R4. 02878 * 02879 * PARAMS 02880 * cIn [I] Source 02881 * pFltOut [O] Destination 02882 * 02883 * RETURNS 02884 * Success: S_OK. 02885 * Failure: E_INVALIDARG, if the source value is invalid 02886 * DISP_E_OVERFLOW, if the value will not fit in the destination 02887 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02888 */ 02889 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut) 02890 { 02891 return _VarR4FromI1(cIn, pFltOut); 02892 } 02893 02894 /************************************************************************ 02895 * VarR4FromUI2 (OLEAUT32.214) 02896 * 02897 * Convert a VT_UI2 to a VT_R4. 02898 * 02899 * PARAMS 02900 * usIn [I] Source 02901 * pFltOut [O] Destination 02902 * 02903 * RETURNS 02904 * Success: S_OK. 02905 * Failure: E_INVALIDARG, if the source value is invalid 02906 * DISP_E_OVERFLOW, if the value will not fit in the destination 02907 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02908 */ 02909 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut) 02910 { 02911 return _VarR4FromUI2(usIn, pFltOut); 02912 } 02913 02914 /************************************************************************ 02915 * VarR4FromUI4 (OLEAUT32.215) 02916 * 02917 * Convert a VT_UI4 to a VT_R4. 02918 * 02919 * PARAMS 02920 * ulIn [I] Source 02921 * pFltOut [O] Destination 02922 * 02923 * RETURNS 02924 * Success: S_OK. 02925 * Failure: E_INVALIDARG, if the source value is invalid 02926 * DISP_E_OVERFLOW, if the value will not fit in the destination 02927 * DISP_E_TYPEMISMATCH, if the type cannot be converted 02928 */ 02929 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut) 02930 { 02931 return _VarR4FromUI4(ulIn, pFltOut); 02932 } 02933 02934 /************************************************************************ 02935 * VarR4FromDec (OLEAUT32.216) 02936 * 02937 * Convert a VT_DECIMAL to a VT_R4. 02938 * 02939 * PARAMS 02940 * pDecIn [I] Source 02941 * pFltOut [O] Destination 02942 * 02943 * RETURNS 02944 * Success: S_OK. 02945 * Failure: E_INVALIDARG, if the source value is invalid. 02946 */ 02947 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut) 02948 { 02949 BYTE scale = DEC_SCALE(pDecIn); 02950 int divisor = 1; 02951 double highPart; 02952 02953 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 02954 return E_INVALIDARG; 02955 02956 while (scale--) 02957 divisor *= 10; 02958 02959 if (DEC_SIGN(pDecIn)) 02960 divisor = -divisor; 02961 02962 if (DEC_HI32(pDecIn)) 02963 { 02964 highPart = (double)DEC_HI32(pDecIn) / (double)divisor; 02965 highPart *= 4294967296.0F; 02966 highPart *= 4294967296.0F; 02967 } 02968 else 02969 highPart = 0.0; 02970 02971 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart; 02972 return S_OK; 02973 } 02974 02975 /************************************************************************ 02976 * VarR4FromI8 (OLEAUT32.360) 02977 * 02978 * Convert a VT_I8 to a VT_R4. 02979 * 02980 * PARAMS 02981 * ullIn [I] Source 02982 * pFltOut [O] Destination 02983 * 02984 * RETURNS 02985 * S_OK. 02986 */ 02987 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut) 02988 { 02989 return _VarR4FromI8(llIn, pFltOut); 02990 } 02991 02992 /************************************************************************ 02993 * VarR4FromUI8 (OLEAUT32.361) 02994 * 02995 * Convert a VT_UI8 to a VT_R4. 02996 * 02997 * PARAMS 02998 * ullIn [I] Source 02999 * pFltOut [O] Destination 03000 * 03001 * RETURNS 03002 * S_OK. 03003 */ 03004 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut) 03005 { 03006 return _VarR4FromUI8(ullIn, pFltOut); 03007 } 03008 03009 /************************************************************************ 03010 * VarR4CmpR8 (OLEAUT32.316) 03011 * 03012 * Compare a VT_R4 to a VT_R8. 03013 * 03014 * PARAMS 03015 * fltLeft [I] Source 03016 * dblRight [I] Value to compare 03017 * 03018 * RETURNS 03019 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than, 03020 * equal to or greater than dblRight respectively. 03021 */ 03022 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight) 03023 { 03024 if (fltLeft < dblRight) 03025 return VARCMP_LT; 03026 else if (fltLeft > dblRight) 03027 return VARCMP_GT; 03028 return VARCMP_EQ; 03029 } 03030 03031 /* R8 03032 */ 03033 03034 /************************************************************************ 03035 * VarR8FromUI1 (OLEAUT32.78) 03036 * 03037 * Convert a VT_UI1 to a VT_R8. 03038 * 03039 * PARAMS 03040 * bIn [I] Source 03041 * pDblOut [O] Destination 03042 * 03043 * RETURNS 03044 * S_OK. 03045 */ 03046 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut) 03047 { 03048 return _VarR8FromUI1(bIn, pDblOut); 03049 } 03050 03051 /************************************************************************ 03052 * VarR8FromI2 (OLEAUT32.79) 03053 * 03054 * Convert a VT_I2 to a VT_R8. 03055 * 03056 * PARAMS 03057 * sIn [I] Source 03058 * pDblOut [O] Destination 03059 * 03060 * RETURNS 03061 * S_OK. 03062 */ 03063 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut) 03064 { 03065 return _VarR8FromI2(sIn, pDblOut); 03066 } 03067 03068 /************************************************************************ 03069 * VarR8FromI4 (OLEAUT32.80) 03070 * 03071 * Convert a VT_I4 to a VT_R8. 03072 * 03073 * PARAMS 03074 * sIn [I] Source 03075 * pDblOut [O] Destination 03076 * 03077 * RETURNS 03078 * S_OK. 03079 */ 03080 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut) 03081 { 03082 return _VarR8FromI4(lIn, pDblOut); 03083 } 03084 03085 /************************************************************************ 03086 * VarR8FromR4 (OLEAUT32.81) 03087 * 03088 * Convert a VT_R4 to a VT_R8. 03089 * 03090 * PARAMS 03091 * fltIn [I] Source 03092 * pDblOut [O] Destination 03093 * 03094 * RETURNS 03095 * S_OK. 03096 */ 03097 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut) 03098 { 03099 return _VarR8FromR4(fltIn, pDblOut); 03100 } 03101 03102 /************************************************************************ 03103 * VarR8FromCy (OLEAUT32.82) 03104 * 03105 * Convert a VT_CY to a VT_R8. 03106 * 03107 * PARAMS 03108 * cyIn [I] Source 03109 * pDblOut [O] Destination 03110 * 03111 * RETURNS 03112 * S_OK. 03113 */ 03114 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut) 03115 { 03116 return _VarR8FromCy(cyIn, pDblOut); 03117 } 03118 03119 /************************************************************************ 03120 * VarR8FromDate (OLEAUT32.83) 03121 * 03122 * Convert a VT_DATE to a VT_R8. 03123 * 03124 * PARAMS 03125 * dateIn [I] Source 03126 * pDblOut [O] Destination 03127 * 03128 * RETURNS 03129 * S_OK. 03130 */ 03131 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut) 03132 { 03133 return _VarR8FromDate(dateIn, pDblOut); 03134 } 03135 03136 /************************************************************************ 03137 * VarR8FromStr (OLEAUT32.84) 03138 * 03139 * Convert a VT_BSTR to a VT_R8. 03140 * 03141 * PARAMS 03142 * strIn [I] Source 03143 * lcid [I] LCID for the conversion 03144 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 03145 * pDblOut [O] Destination 03146 * 03147 * RETURNS 03148 * Success: S_OK. 03149 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid. 03150 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03151 */ 03152 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut) 03153 { 03154 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8); 03155 } 03156 03157 /************************************************************************ 03158 * VarR8FromDisp (OLEAUT32.85) 03159 * 03160 * Convert a VT_DISPATCH to a VT_R8. 03161 * 03162 * PARAMS 03163 * pdispIn [I] Source 03164 * lcid [I] LCID for conversion 03165 * pDblOut [O] Destination 03166 * 03167 * RETURNS 03168 * Success: S_OK. 03169 * Failure: E_INVALIDARG, if the source value is invalid 03170 * DISP_E_OVERFLOW, if the value will not fit in the destination 03171 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03172 */ 03173 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut) 03174 { 03175 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0); 03176 } 03177 03178 /************************************************************************ 03179 * VarR8FromBool (OLEAUT32.86) 03180 * 03181 * Convert a VT_BOOL to a VT_R8. 03182 * 03183 * PARAMS 03184 * boolIn [I] Source 03185 * pDblOut [O] Destination 03186 * 03187 * RETURNS 03188 * S_OK. 03189 */ 03190 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut) 03191 { 03192 return VarR8FromI2(boolIn, pDblOut); 03193 } 03194 03195 /************************************************************************ 03196 * VarR8FromI1 (OLEAUT32.217) 03197 * 03198 * Convert a VT_I1 to a VT_R8. 03199 * 03200 * PARAMS 03201 * cIn [I] Source 03202 * pDblOut [O] Destination 03203 * 03204 * RETURNS 03205 * Success: S_OK. 03206 * Failure: E_INVALIDARG, if the source value is invalid 03207 * DISP_E_OVERFLOW, if the value will not fit in the destination 03208 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03209 */ 03210 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut) 03211 { 03212 return _VarR8FromI1(cIn, pDblOut); 03213 } 03214 03215 /************************************************************************ 03216 * VarR8FromUI2 (OLEAUT32.218) 03217 * 03218 * Convert a VT_UI2 to a VT_R8. 03219 * 03220 * PARAMS 03221 * usIn [I] Source 03222 * pDblOut [O] Destination 03223 * 03224 * RETURNS 03225 * Success: S_OK. 03226 * Failure: E_INVALIDARG, if the source value is invalid 03227 * DISP_E_OVERFLOW, if the value will not fit in the destination 03228 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03229 */ 03230 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut) 03231 { 03232 return _VarR8FromUI2(usIn, pDblOut); 03233 } 03234 03235 /************************************************************************ 03236 * VarR8FromUI4 (OLEAUT32.219) 03237 * 03238 * Convert a VT_UI4 to a VT_R8. 03239 * 03240 * PARAMS 03241 * ulIn [I] Source 03242 * pDblOut [O] Destination 03243 * 03244 * RETURNS 03245 * Success: S_OK. 03246 * Failure: E_INVALIDARG, if the source value is invalid 03247 * DISP_E_OVERFLOW, if the value will not fit in the destination 03248 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03249 */ 03250 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut) 03251 { 03252 return _VarR8FromUI4(ulIn, pDblOut); 03253 } 03254 03255 /************************************************************************ 03256 * VarR8FromDec (OLEAUT32.220) 03257 * 03258 * Convert a VT_DECIMAL to a VT_R8. 03259 * 03260 * PARAMS 03261 * pDecIn [I] Source 03262 * pDblOut [O] Destination 03263 * 03264 * RETURNS 03265 * Success: S_OK. 03266 * Failure: E_INVALIDARG, if the source value is invalid. 03267 */ 03268 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut) 03269 { 03270 BYTE scale = DEC_SCALE(pDecIn); 03271 double divisor = 1.0, highPart; 03272 03273 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 03274 return E_INVALIDARG; 03275 03276 while (scale--) 03277 divisor *= 10; 03278 03279 if (DEC_SIGN(pDecIn)) 03280 divisor = -divisor; 03281 03282 if (DEC_HI32(pDecIn)) 03283 { 03284 highPart = (double)DEC_HI32(pDecIn) / divisor; 03285 highPart *= 4294967296.0F; 03286 highPart *= 4294967296.0F; 03287 } 03288 else 03289 highPart = 0.0; 03290 03291 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart; 03292 return S_OK; 03293 } 03294 03295 /************************************************************************ 03296 * VarR8FromI8 (OLEAUT32.362) 03297 * 03298 * Convert a VT_I8 to a VT_R8. 03299 * 03300 * PARAMS 03301 * ullIn [I] Source 03302 * pDblOut [O] Destination 03303 * 03304 * RETURNS 03305 * S_OK. 03306 */ 03307 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut) 03308 { 03309 return _VarR8FromI8(llIn, pDblOut); 03310 } 03311 03312 /************************************************************************ 03313 * VarR8FromUI8 (OLEAUT32.363) 03314 * 03315 * Convert a VT_UI8 to a VT_R8. 03316 * 03317 * PARAMS 03318 * ullIn [I] Source 03319 * pDblOut [O] Destination 03320 * 03321 * RETURNS 03322 * S_OK. 03323 */ 03324 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut) 03325 { 03326 return _VarR8FromUI8(ullIn, pDblOut); 03327 } 03328 03329 /************************************************************************ 03330 * VarR8Pow (OLEAUT32.315) 03331 * 03332 * Raise a VT_R8 to a power. 03333 * 03334 * PARAMS 03335 * dblLeft [I] Source 03336 * dblPow [I] Power to raise dblLeft by 03337 * pDblOut [O] Destination 03338 * 03339 * RETURNS 03340 * S_OK. pDblOut contains dblLeft to the power of dblRight. 03341 */ 03342 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut) 03343 { 03344 *pDblOut = pow(dblLeft, dblPow); 03345 return S_OK; 03346 } 03347 03348 /************************************************************************ 03349 * VarR8Round (OLEAUT32.317) 03350 * 03351 * Round a VT_R8 to a given number of decimal points. 03352 * 03353 * PARAMS 03354 * dblIn [I] Source 03355 * nDig [I] Number of decimal points to round to 03356 * pDblOut [O] Destination for rounded number 03357 * 03358 * RETURNS 03359 * Success: S_OK. pDblOut is rounded to nDig digits. 03360 * Failure: E_INVALIDARG, if cDecimals is less than 0. 03361 * 03362 * NOTES 03363 * The native version of this function rounds using the internal 03364 * binary representation of the number. Wine uses the dutch rounding 03365 * convention, so therefore small differences can occur in the value returned. 03366 * MSDN says that you should use your own rounding function if you want 03367 * rounding to be predictable in your application. 03368 */ 03369 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut) 03370 { 03371 double scale, whole, fract; 03372 03373 if (nDig < 0) 03374 return E_INVALIDARG; 03375 03376 scale = pow(10.0, nDig); 03377 03378 dblIn *= scale; 03379 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn); 03380 fract = dblIn - whole; 03381 03382 if (fract > 0.5) 03383 dblIn = whole + 1.0; 03384 else if (fract == 0.5) 03385 dblIn = whole + fmod(whole, 2.0); 03386 else if (fract >= 0.0) 03387 dblIn = whole; 03388 else if (fract == -0.5) 03389 dblIn = whole - fmod(whole, 2.0); 03390 else if (fract > -0.5) 03391 dblIn = whole; 03392 else 03393 dblIn = whole - 1.0; 03394 03395 *pDblOut = dblIn / scale; 03396 return S_OK; 03397 } 03398 03399 /* CY 03400 */ 03401 03402 /* Powers of 10 from 0..4 D.P. */ 03403 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000, 03404 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER }; 03405 03406 /************************************************************************ 03407 * VarCyFromUI1 (OLEAUT32.98) 03408 * 03409 * Convert a VT_UI1 to a VT_CY. 03410 * 03411 * PARAMS 03412 * bIn [I] Source 03413 * pCyOut [O] Destination 03414 * 03415 * RETURNS 03416 * Success: S_OK. 03417 * Failure: E_INVALIDARG, if the source value is invalid 03418 * DISP_E_OVERFLOW, if the value will not fit in the destination 03419 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03420 */ 03421 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut) 03422 { 03423 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER; 03424 return S_OK; 03425 } 03426 03427 /************************************************************************ 03428 * VarCyFromI2 (OLEAUT32.99) 03429 * 03430 * Convert a VT_I2 to a VT_CY. 03431 * 03432 * PARAMS 03433 * sIn [I] Source 03434 * pCyOut [O] Destination 03435 * 03436 * RETURNS 03437 * Success: S_OK. 03438 * Failure: E_INVALIDARG, if the source value is invalid 03439 * DISP_E_OVERFLOW, if the value will not fit in the destination 03440 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03441 */ 03442 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut) 03443 { 03444 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER; 03445 return S_OK; 03446 } 03447 03448 /************************************************************************ 03449 * VarCyFromI4 (OLEAUT32.100) 03450 * 03451 * Convert a VT_I4 to a VT_CY. 03452 * 03453 * PARAMS 03454 * sIn [I] Source 03455 * pCyOut [O] Destination 03456 * 03457 * RETURNS 03458 * Success: S_OK. 03459 * Failure: E_INVALIDARG, if the source value is invalid 03460 * DISP_E_OVERFLOW, if the value will not fit in the destination 03461 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03462 */ 03463 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut) 03464 { 03465 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER; 03466 return S_OK; 03467 } 03468 03469 /************************************************************************ 03470 * VarCyFromR4 (OLEAUT32.101) 03471 * 03472 * Convert a VT_R4 to a VT_CY. 03473 * 03474 * PARAMS 03475 * fltIn [I] Source 03476 * pCyOut [O] Destination 03477 * 03478 * RETURNS 03479 * Success: S_OK. 03480 * Failure: E_INVALIDARG, if the source value is invalid 03481 * DISP_E_OVERFLOW, if the value will not fit in the destination 03482 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03483 */ 03484 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut) 03485 { 03486 return VarCyFromR8(fltIn, pCyOut); 03487 } 03488 03489 /************************************************************************ 03490 * VarCyFromR8 (OLEAUT32.102) 03491 * 03492 * Convert a VT_R8 to a VT_CY. 03493 * 03494 * PARAMS 03495 * dblIn [I] Source 03496 * pCyOut [O] Destination 03497 * 03498 * RETURNS 03499 * Success: S_OK. 03500 * Failure: E_INVALIDARG, if the source value is invalid 03501 * DISP_E_OVERFLOW, if the value will not fit in the destination 03502 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03503 */ 03504 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut) 03505 { 03506 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 03507 /* This code gives identical results to Win32 on Intel. 03508 * Here we use fp exceptions to catch overflows when storing the value. 03509 */ 03510 static const unsigned short r8_fpcontrol = 0x137f; 03511 static const double r8_multiplier = CY_MULTIPLIER_F; 03512 unsigned short old_fpcontrol, result_fpstatus; 03513 03514 /* Clear exceptions, save the old fp state and load the new state */ 03515 __asm__ __volatile__( "fnclex" ); 03516 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : ); 03517 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) ); 03518 /* Perform the conversion. */ 03519 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) ); 03520 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) ); 03521 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) ); 03522 /* Save the resulting fp state, load the old state and clear exceptions */ 03523 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : ); 03524 __asm__ __volatile__( "fnclex" ); 03525 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) ); 03526 03527 if (result_fpstatus & 0x9) /* Overflow | Invalid */ 03528 return DISP_E_OVERFLOW; 03529 #else 03530 /* This version produces slightly different results for boundary cases */ 03531 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807) 03532 return DISP_E_OVERFLOW; 03533 dblIn *= CY_MULTIPLIER_F; 03534 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64); 03535 #endif 03536 return S_OK; 03537 } 03538 03539 /************************************************************************ 03540 * VarCyFromDate (OLEAUT32.103) 03541 * 03542 * Convert a VT_DATE to a VT_CY. 03543 * 03544 * PARAMS 03545 * dateIn [I] Source 03546 * pCyOut [O] Destination 03547 * 03548 * RETURNS 03549 * Success: S_OK. 03550 * Failure: E_INVALIDARG, if the source value is invalid 03551 * DISP_E_OVERFLOW, if the value will not fit in the destination 03552 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03553 */ 03554 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut) 03555 { 03556 return VarCyFromR8(dateIn, pCyOut); 03557 } 03558 03559 /************************************************************************ 03560 * VarCyFromStr (OLEAUT32.104) 03561 * 03562 * Convert a VT_BSTR to a VT_CY. 03563 * 03564 * PARAMS 03565 * strIn [I] Source 03566 * lcid [I] LCID for the conversion 03567 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 03568 * pCyOut [O] Destination 03569 * 03570 * RETURNS 03571 * Success: S_OK. 03572 * Failure: E_INVALIDARG, if the source value is invalid 03573 * DISP_E_OVERFLOW, if the value will not fit in the destination 03574 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03575 */ 03576 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut) 03577 { 03578 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY); 03579 } 03580 03581 /************************************************************************ 03582 * VarCyFromDisp (OLEAUT32.105) 03583 * 03584 * Convert a VT_DISPATCH to a VT_CY. 03585 * 03586 * PARAMS 03587 * pdispIn [I] Source 03588 * lcid [I] LCID for conversion 03589 * pCyOut [O] Destination 03590 * 03591 * RETURNS 03592 * Success: S_OK. 03593 * Failure: E_INVALIDARG, if the source value is invalid 03594 * DISP_E_OVERFLOW, if the value will not fit in the destination 03595 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03596 */ 03597 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut) 03598 { 03599 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0); 03600 } 03601 03602 /************************************************************************ 03603 * VarCyFromBool (OLEAUT32.106) 03604 * 03605 * Convert a VT_BOOL to a VT_CY. 03606 * 03607 * PARAMS 03608 * boolIn [I] Source 03609 * pCyOut [O] Destination 03610 * 03611 * RETURNS 03612 * Success: S_OK. 03613 * Failure: E_INVALIDARG, if the source value is invalid 03614 * DISP_E_OVERFLOW, if the value will not fit in the destination 03615 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03616 * 03617 * NOTES 03618 * While the sign of the boolean is stored in the currency, the value is 03619 * converted to either 0 or 1. 03620 */ 03621 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut) 03622 { 03623 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER; 03624 return S_OK; 03625 } 03626 03627 /************************************************************************ 03628 * VarCyFromI1 (OLEAUT32.225) 03629 * 03630 * Convert a VT_I1 to a VT_CY. 03631 * 03632 * PARAMS 03633 * cIn [I] Source 03634 * pCyOut [O] Destination 03635 * 03636 * RETURNS 03637 * Success: S_OK. 03638 * Failure: E_INVALIDARG, if the source value is invalid 03639 * DISP_E_OVERFLOW, if the value will not fit in the destination 03640 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03641 */ 03642 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut) 03643 { 03644 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER; 03645 return S_OK; 03646 } 03647 03648 /************************************************************************ 03649 * VarCyFromUI2 (OLEAUT32.226) 03650 * 03651 * Convert a VT_UI2 to a VT_CY. 03652 * 03653 * PARAMS 03654 * usIn [I] Source 03655 * pCyOut [O] Destination 03656 * 03657 * RETURNS 03658 * Success: S_OK. 03659 * Failure: E_INVALIDARG, if the source value is invalid 03660 * DISP_E_OVERFLOW, if the value will not fit in the destination 03661 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03662 */ 03663 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut) 03664 { 03665 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER; 03666 return S_OK; 03667 } 03668 03669 /************************************************************************ 03670 * VarCyFromUI4 (OLEAUT32.227) 03671 * 03672 * Convert a VT_UI4 to a VT_CY. 03673 * 03674 * PARAMS 03675 * ulIn [I] Source 03676 * pCyOut [O] Destination 03677 * 03678 * RETURNS 03679 * Success: S_OK. 03680 * Failure: E_INVALIDARG, if the source value is invalid 03681 * DISP_E_OVERFLOW, if the value will not fit in the destination 03682 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03683 */ 03684 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut) 03685 { 03686 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER; 03687 return S_OK; 03688 } 03689 03690 /************************************************************************ 03691 * VarCyFromDec (OLEAUT32.228) 03692 * 03693 * Convert a VT_DECIMAL to a VT_CY. 03694 * 03695 * PARAMS 03696 * pdecIn [I] Source 03697 * pCyOut [O] Destination 03698 * 03699 * RETURNS 03700 * Success: S_OK. 03701 * Failure: E_INVALIDARG, if the source value is invalid 03702 * DISP_E_OVERFLOW, if the value will not fit in the destination 03703 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03704 */ 03705 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut) 03706 { 03707 DECIMAL rounded; 03708 HRESULT hRet; 03709 03710 hRet = VarDecRound(pdecIn, 4, &rounded); 03711 03712 if (SUCCEEDED(hRet)) 03713 { 03714 double d; 03715 03716 if (DEC_HI32(&rounded)) 03717 return DISP_E_OVERFLOW; 03718 03719 /* Note: Without the casts this promotes to int64 which loses precision */ 03720 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)]; 03721 if (DEC_SIGN(&rounded)) 03722 d = -d; 03723 return VarCyFromR8(d, pCyOut); 03724 } 03725 return hRet; 03726 } 03727 03728 /************************************************************************ 03729 * VarCyFromI8 (OLEAUT32.366) 03730 * 03731 * Convert a VT_I8 to a VT_CY. 03732 * 03733 * PARAMS 03734 * ullIn [I] Source 03735 * pCyOut [O] Destination 03736 * 03737 * RETURNS 03738 * Success: S_OK. 03739 * Failure: E_INVALIDARG, if the source value is invalid 03740 * DISP_E_OVERFLOW, if the value will not fit in the destination 03741 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03742 */ 03743 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut) 03744 { 03745 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW; 03746 pCyOut->int64 = llIn * CY_MULTIPLIER; 03747 return S_OK; 03748 } 03749 03750 /************************************************************************ 03751 * VarCyFromUI8 (OLEAUT32.375) 03752 * 03753 * Convert a VT_UI8 to a VT_CY. 03754 * 03755 * PARAMS 03756 * ullIn [I] Source 03757 * pCyOut [O] Destination 03758 * 03759 * RETURNS 03760 * Success: S_OK. 03761 * Failure: E_INVALIDARG, if the source value is invalid 03762 * DISP_E_OVERFLOW, if the value will not fit in the destination 03763 * DISP_E_TYPEMISMATCH, if the type cannot be converted 03764 */ 03765 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut) 03766 { 03767 if (ullIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW; 03768 pCyOut->int64 = ullIn * CY_MULTIPLIER; 03769 return S_OK; 03770 } 03771 03772 /************************************************************************ 03773 * VarCyAdd (OLEAUT32.299) 03774 * 03775 * Add one CY to another. 03776 * 03777 * PARAMS 03778 * cyLeft [I] Source 03779 * cyRight [I] Value to add 03780 * pCyOut [O] Destination 03781 * 03782 * RETURNS 03783 * Success: S_OK. 03784 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03785 */ 03786 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut) 03787 { 03788 double l,r; 03789 _VarR8FromCy(cyLeft, &l); 03790 _VarR8FromCy(cyRight, &r); 03791 l = l + r; 03792 return VarCyFromR8(l, pCyOut); 03793 } 03794 03795 /************************************************************************ 03796 * VarCyMul (OLEAUT32.303) 03797 * 03798 * Multiply one CY by another. 03799 * 03800 * PARAMS 03801 * cyLeft [I] Source 03802 * cyRight [I] Value to multiply by 03803 * pCyOut [O] Destination 03804 * 03805 * RETURNS 03806 * Success: S_OK. 03807 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03808 */ 03809 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut) 03810 { 03811 double l,r; 03812 _VarR8FromCy(cyLeft, &l); 03813 _VarR8FromCy(cyRight, &r); 03814 l = l * r; 03815 return VarCyFromR8(l, pCyOut); 03816 } 03817 03818 /************************************************************************ 03819 * VarCyMulI4 (OLEAUT32.304) 03820 * 03821 * Multiply one CY by a VT_I4. 03822 * 03823 * PARAMS 03824 * cyLeft [I] Source 03825 * lRight [I] Value to multiply by 03826 * pCyOut [O] Destination 03827 * 03828 * RETURNS 03829 * Success: S_OK. 03830 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03831 */ 03832 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut) 03833 { 03834 double d; 03835 03836 _VarR8FromCy(cyLeft, &d); 03837 d = d * lRight; 03838 return VarCyFromR8(d, pCyOut); 03839 } 03840 03841 /************************************************************************ 03842 * VarCySub (OLEAUT32.305) 03843 * 03844 * Subtract one CY from another. 03845 * 03846 * PARAMS 03847 * cyLeft [I] Source 03848 * cyRight [I] Value to subtract 03849 * pCyOut [O] Destination 03850 * 03851 * RETURNS 03852 * Success: S_OK. 03853 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03854 */ 03855 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut) 03856 { 03857 double l,r; 03858 _VarR8FromCy(cyLeft, &l); 03859 _VarR8FromCy(cyRight, &r); 03860 l = l - r; 03861 return VarCyFromR8(l, pCyOut); 03862 } 03863 03864 /************************************************************************ 03865 * VarCyAbs (OLEAUT32.306) 03866 * 03867 * Convert a VT_CY into its absolute value. 03868 * 03869 * PARAMS 03870 * cyIn [I] Source 03871 * pCyOut [O] Destination 03872 * 03873 * RETURNS 03874 * Success: S_OK. pCyOut contains the absolute value. 03875 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03876 */ 03877 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut) 03878 { 03879 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) 03880 return DISP_E_OVERFLOW; 03881 03882 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64; 03883 return S_OK; 03884 } 03885 03886 /************************************************************************ 03887 * VarCyFix (OLEAUT32.307) 03888 * 03889 * Return the integer part of a VT_CY. 03890 * 03891 * PARAMS 03892 * cyIn [I] Source 03893 * pCyOut [O] Destination 03894 * 03895 * RETURNS 03896 * Success: S_OK. 03897 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03898 * 03899 * NOTES 03900 * - The difference between this function and VarCyInt() is that VarCyInt() rounds 03901 * negative numbers away from 0, while this function rounds them towards zero. 03902 */ 03903 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut) 03904 { 03905 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; 03906 pCyOut->int64 *= CY_MULTIPLIER; 03907 return S_OK; 03908 } 03909 03910 /************************************************************************ 03911 * VarCyInt (OLEAUT32.308) 03912 * 03913 * Return the integer part of a VT_CY. 03914 * 03915 * PARAMS 03916 * cyIn [I] Source 03917 * pCyOut [O] Destination 03918 * 03919 * RETURNS 03920 * Success: S_OK. 03921 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03922 * 03923 * NOTES 03924 * - The difference between this function and VarCyFix() is that VarCyFix() rounds 03925 * negative numbers towards 0, while this function rounds them away from zero. 03926 */ 03927 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut) 03928 { 03929 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; 03930 pCyOut->int64 *= CY_MULTIPLIER; 03931 03932 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0) 03933 { 03934 pCyOut->int64 -= CY_MULTIPLIER; 03935 } 03936 return S_OK; 03937 } 03938 03939 /************************************************************************ 03940 * VarCyNeg (OLEAUT32.309) 03941 * 03942 * Change the sign of a VT_CY. 03943 * 03944 * PARAMS 03945 * cyIn [I] Source 03946 * pCyOut [O] Destination 03947 * 03948 * RETURNS 03949 * Success: S_OK. 03950 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 03951 */ 03952 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut) 03953 { 03954 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) 03955 return DISP_E_OVERFLOW; 03956 03957 pCyOut->int64 = -cyIn.int64; 03958 return S_OK; 03959 } 03960 03961 /************************************************************************ 03962 * VarCyRound (OLEAUT32.310) 03963 * 03964 * Change the precision of a VT_CY. 03965 * 03966 * PARAMS 03967 * cyIn [I] Source 03968 * cDecimals [I] New number of decimals to keep 03969 * pCyOut [O] Destination 03970 * 03971 * RETURNS 03972 * Success: S_OK. 03973 * Failure: E_INVALIDARG, if cDecimals is less than 0. 03974 */ 03975 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut) 03976 { 03977 if (cDecimals < 0) 03978 return E_INVALIDARG; 03979 03980 if (cDecimals > 3) 03981 { 03982 /* Rounding to more precision than we have */ 03983 *pCyOut = cyIn; 03984 return S_OK; 03985 } 03986 else 03987 { 03988 double d, div = CY_Divisors[cDecimals]; 03989 03990 _VarR8FromCy(cyIn, &d); 03991 d = d * div; 03992 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64); 03993 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F; 03994 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64); 03995 return S_OK; 03996 } 03997 } 03998 03999 /************************************************************************ 04000 * VarCyCmp (OLEAUT32.311) 04001 * 04002 * Compare two VT_CY values. 04003 * 04004 * PARAMS 04005 * cyLeft [I] Source 04006 * cyRight [I] Value to compare 04007 * 04008 * RETURNS 04009 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to 04010 * compare is less, equal or greater than source respectively. 04011 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 04012 */ 04013 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight) 04014 { 04015 HRESULT hRet; 04016 CY result; 04017 04018 /* Subtract right from left, and compare the result to 0 */ 04019 hRet = VarCySub(cyLeft, cyRight, &result); 04020 04021 if (SUCCEEDED(hRet)) 04022 { 04023 if (result.int64 < 0) 04024 hRet = (HRESULT)VARCMP_LT; 04025 else if (result.int64 > 0) 04026 hRet = (HRESULT)VARCMP_GT; 04027 else 04028 hRet = (HRESULT)VARCMP_EQ; 04029 } 04030 return hRet; 04031 } 04032 04033 /************************************************************************ 04034 * VarCyCmpR8 (OLEAUT32.312) 04035 * 04036 * Compare a VT_CY to a double 04037 * 04038 * PARAMS 04039 * cyLeft [I] Currency Source 04040 * dblRight [I] double to compare to cyLeft 04041 * 04042 * RETURNS 04043 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is 04044 * less than, equal to or greater than cyLeft respectively. 04045 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 04046 */ 04047 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight) 04048 { 04049 HRESULT hRet; 04050 CY cyRight; 04051 04052 hRet = VarCyFromR8(dblRight, &cyRight); 04053 04054 if (SUCCEEDED(hRet)) 04055 hRet = VarCyCmp(cyLeft, cyRight); 04056 04057 return hRet; 04058 } 04059 04060 /************************************************************************ 04061 * VarCyMulI8 (OLEAUT32.329) 04062 * 04063 * Multiply a VT_CY by a VT_I8. 04064 * 04065 * PARAMS 04066 * cyLeft [I] Source 04067 * llRight [I] Value to multiply by 04068 * pCyOut [O] Destination 04069 * 04070 * RETURNS 04071 * Success: S_OK. 04072 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 04073 */ 04074 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut) 04075 { 04076 double d; 04077 04078 _VarR8FromCy(cyLeft, &d); 04079 d = d * (double)llRight; 04080 return VarCyFromR8(d, pCyOut); 04081 } 04082 04083 /* DECIMAL 04084 */ 04085 04086 /************************************************************************ 04087 * VarDecFromUI1 (OLEAUT32.190) 04088 * 04089 * Convert a VT_UI1 to a DECIMAL. 04090 * 04091 * PARAMS 04092 * bIn [I] Source 04093 * pDecOut [O] Destination 04094 * 04095 * RETURNS 04096 * S_OK. 04097 */ 04098 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut) 04099 { 04100 return VarDecFromUI4(bIn, pDecOut); 04101 } 04102 04103 /************************************************************************ 04104 * VarDecFromI2 (OLEAUT32.191) 04105 * 04106 * Convert a VT_I2 to a DECIMAL. 04107 * 04108 * PARAMS 04109 * sIn [I] Source 04110 * pDecOut [O] Destination 04111 * 04112 * RETURNS 04113 * S_OK. 04114 */ 04115 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut) 04116 { 04117 return VarDecFromI4(sIn, pDecOut); 04118 } 04119 04120 /************************************************************************ 04121 * VarDecFromI4 (OLEAUT32.192) 04122 * 04123 * Convert a VT_I4 to a DECIMAL. 04124 * 04125 * PARAMS 04126 * sIn [I] Source 04127 * pDecOut [O] Destination 04128 * 04129 * RETURNS 04130 * S_OK. 04131 */ 04132 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut) 04133 { 04134 DEC_HI32(pDecOut) = 0; 04135 DEC_MID32(pDecOut) = 0; 04136 04137 if (lIn < 0) 04138 { 04139 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); 04140 DEC_LO32(pDecOut) = -lIn; 04141 } 04142 else 04143 { 04144 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 04145 DEC_LO32(pDecOut) = lIn; 04146 } 04147 return S_OK; 04148 } 04149 04150 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT)) 04151 04152 /* internal representation of the value stored in a DECIMAL. The bytes are 04153 stored from LSB at index 0 to MSB at index 11 04154 */ 04155 typedef struct DECIMAL_internal 04156 { 04157 DWORD bitsnum[3]; /* 96 significant bits, unsigned */ 04158 unsigned char scale; /* number scaled * 10 ^ -(scale) */ 04159 unsigned int sign : 1; /* 0 - positive, 1 - negative */ 04160 } VARIANT_DI; 04161 04162 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest); 04163 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest); 04164 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to); 04165 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to); 04166 04167 /************************************************************************ 04168 * VarDecFromR4 (OLEAUT32.193) 04169 * 04170 * Convert a VT_R4 to a DECIMAL. 04171 * 04172 * PARAMS 04173 * fltIn [I] Source 04174 * pDecOut [O] Destination 04175 * 04176 * RETURNS 04177 * S_OK. 04178 */ 04179 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut) 04180 { 04181 VARIANT_DI di; 04182 HRESULT hres; 04183 04184 hres = VARIANT_DI_FromR4(fltIn, &di); 04185 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut); 04186 return hres; 04187 } 04188 04189 /************************************************************************ 04190 * VarDecFromR8 (OLEAUT32.194) 04191 * 04192 * Convert a VT_R8 to a DECIMAL. 04193 * 04194 * PARAMS 04195 * dblIn [I] Source 04196 * pDecOut [O] Destination 04197 * 04198 * RETURNS 04199 * S_OK. 04200 */ 04201 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut) 04202 { 04203 VARIANT_DI di; 04204 HRESULT hres; 04205 04206 hres = VARIANT_DI_FromR8(dblIn, &di); 04207 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut); 04208 return hres; 04209 } 04210 04211 /************************************************************************ 04212 * VarDecFromDate (OLEAUT32.195) 04213 * 04214 * Convert a VT_DATE to a DECIMAL. 04215 * 04216 * PARAMS 04217 * dateIn [I] Source 04218 * pDecOut [O] Destination 04219 * 04220 * RETURNS 04221 * S_OK. 04222 */ 04223 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut) 04224 { 04225 return VarDecFromR8(dateIn, pDecOut); 04226 } 04227 04228 /************************************************************************ 04229 * VarDecFromCy (OLEAUT32.196) 04230 * 04231 * Convert a VT_CY to a DECIMAL. 04232 * 04233 * PARAMS 04234 * cyIn [I] Source 04235 * pDecOut [O] Destination 04236 * 04237 * RETURNS 04238 * S_OK. 04239 */ 04240 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut) 04241 { 04242 DEC_HI32(pDecOut) = 0; 04243 04244 /* Note: This assumes 2s complement integer representation */ 04245 if (cyIn.s.Hi & 0x80000000) 04246 { 04247 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4); 04248 DEC_LO64(pDecOut) = -cyIn.int64; 04249 } 04250 else 04251 { 04252 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4); 04253 DEC_MID32(pDecOut) = cyIn.s.Hi; 04254 DEC_LO32(pDecOut) = cyIn.s.Lo; 04255 } 04256 return S_OK; 04257 } 04258 04259 /************************************************************************ 04260 * VarDecFromStr (OLEAUT32.197) 04261 * 04262 * Convert a VT_BSTR to a DECIMAL. 04263 * 04264 * PARAMS 04265 * strIn [I] Source 04266 * lcid [I] LCID for the conversion 04267 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 04268 * pDecOut [O] Destination 04269 * 04270 * RETURNS 04271 * Success: S_OK. 04272 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 04273 */ 04274 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut) 04275 { 04276 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL); 04277 } 04278 04279 /************************************************************************ 04280 * VarDecFromDisp (OLEAUT32.198) 04281 * 04282 * Convert a VT_DISPATCH to a DECIMAL. 04283 * 04284 * PARAMS 04285 * pdispIn [I] Source 04286 * lcid [I] LCID for conversion 04287 * pDecOut [O] Destination 04288 * 04289 * RETURNS 04290 * Success: S_OK. 04291 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted 04292 */ 04293 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut) 04294 { 04295 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0); 04296 } 04297 04298 /************************************************************************ 04299 * VarDecFromBool (OLEAUT32.199) 04300 * 04301 * Convert a VT_BOOL to a DECIMAL. 04302 * 04303 * PARAMS 04304 * bIn [I] Source 04305 * pDecOut [O] Destination 04306 * 04307 * RETURNS 04308 * S_OK. 04309 * 04310 * NOTES 04311 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE). 04312 */ 04313 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut) 04314 { 04315 DEC_HI32(pDecOut) = 0; 04316 DEC_MID32(pDecOut) = 0; 04317 if (bIn) 04318 { 04319 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); 04320 DEC_LO32(pDecOut) = 1; 04321 } 04322 else 04323 { 04324 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 04325 DEC_LO32(pDecOut) = 0; 04326 } 04327 return S_OK; 04328 } 04329 04330 /************************************************************************ 04331 * VarDecFromI1 (OLEAUT32.241) 04332 * 04333 * Convert a VT_I1 to a DECIMAL. 04334 * 04335 * PARAMS 04336 * cIn [I] Source 04337 * pDecOut [O] Destination 04338 * 04339 * RETURNS 04340 * S_OK. 04341 */ 04342 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut) 04343 { 04344 return VarDecFromI4(cIn, pDecOut); 04345 } 04346 04347 /************************************************************************ 04348 * VarDecFromUI2 (OLEAUT32.242) 04349 * 04350 * Convert a VT_UI2 to a DECIMAL. 04351 * 04352 * PARAMS 04353 * usIn [I] Source 04354 * pDecOut [O] Destination 04355 * 04356 * RETURNS 04357 * S_OK. 04358 */ 04359 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut) 04360 { 04361 return VarDecFromUI4(usIn, pDecOut); 04362 } 04363 04364 /************************************************************************ 04365 * VarDecFromUI4 (OLEAUT32.243) 04366 * 04367 * Convert a VT_UI4 to a DECIMAL. 04368 * 04369 * PARAMS 04370 * ulIn [I] Source 04371 * pDecOut [O] Destination 04372 * 04373 * RETURNS 04374 * S_OK. 04375 */ 04376 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut) 04377 { 04378 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 04379 DEC_HI32(pDecOut) = 0; 04380 DEC_MID32(pDecOut) = 0; 04381 DEC_LO32(pDecOut) = ulIn; 04382 return S_OK; 04383 } 04384 04385 /************************************************************************ 04386 * VarDecFromI8 (OLEAUT32.374) 04387 * 04388 * Convert a VT_I8 to a DECIMAL. 04389 * 04390 * PARAMS 04391 * llIn [I] Source 04392 * pDecOut [O] Destination 04393 * 04394 * RETURNS 04395 * S_OK. 04396 */ 04397 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut) 04398 { 04399 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn; 04400 04401 DEC_HI32(pDecOut) = 0; 04402 04403 /* Note: This assumes 2s complement integer representation */ 04404 if (pLi->u.HighPart & 0x80000000) 04405 { 04406 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); 04407 DEC_LO64(pDecOut) = -pLi->QuadPart; 04408 } 04409 else 04410 { 04411 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 04412 DEC_MID32(pDecOut) = pLi->u.HighPart; 04413 DEC_LO32(pDecOut) = pLi->u.LowPart; 04414 } 04415 return S_OK; 04416 } 04417 04418 /************************************************************************ 04419 * VarDecFromUI8 (OLEAUT32.375) 04420 * 04421 * Convert a VT_UI8 to a DECIMAL. 04422 * 04423 * PARAMS 04424 * ullIn [I] Source 04425 * pDecOut [O] Destination 04426 * 04427 * RETURNS 04428 * S_OK. 04429 */ 04430 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut) 04431 { 04432 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 04433 DEC_HI32(pDecOut) = 0; 04434 DEC_LO64(pDecOut) = ullIn; 04435 return S_OK; 04436 } 04437 04438 /* Make two DECIMALS the same scale; used by math functions below */ 04439 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft, 04440 const DECIMAL** ppDecRight, 04441 DECIMAL* pDecOut) 04442 { 04443 static DECIMAL scaleFactor; 04444 DECIMAL decTemp; 04445 int scaleAmount, i; 04446 HRESULT hRet = S_OK; 04447 04448 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG) 04449 return E_INVALIDARG; 04450 04451 DEC_LO32(&scaleFactor) = 10; 04452 04453 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight); 04454 04455 if (!scaleAmount) 04456 return S_OK; /* Same scale */ 04457 04458 if (scaleAmount > 0) 04459 { 04460 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */ 04461 *ppDecRight = pDecOut; 04462 } 04463 else 04464 { 04465 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */ 04466 *ppDecLeft = pDecOut; 04467 i = scaleAmount = -scaleAmount; 04468 } 04469 04470 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE) 04471 return DISP_E_OVERFLOW; /* Can't scale up */ 04472 04473 /* Multiply up the value to be scaled by the correct amount */ 04474 while (SUCCEEDED(hRet) && i--) 04475 { 04476 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */ 04477 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut); 04478 decTemp = *pDecOut; 04479 } 04480 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */ 04481 return hRet; 04482 } 04483 04484 /* Add two unsigned 32 bit values with overflow */ 04485 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) 04486 { 04487 ULARGE_INTEGER ul64; 04488 04489 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh; 04490 *pulHigh = ul64.u.HighPart; 04491 return ul64.u.LowPart; 04492 } 04493 04494 /* Subtract two unsigned 32 bit values with underflow */ 04495 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) 04496 { 04497 int invert = 0; 04498 ULARGE_INTEGER ul64; 04499 04500 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight; 04501 if (ulLeft < ulRight) 04502 invert = 1; 04503 04504 if (ul64.QuadPart > (ULONG64)*pulHigh) 04505 ul64.QuadPart -= (ULONG64)*pulHigh; 04506 else 04507 { 04508 ul64.QuadPart -= (ULONG64)*pulHigh; 04509 invert = 1; 04510 } 04511 if (invert) 04512 ul64.u.HighPart = -ul64.u.HighPart ; 04513 04514 *pulHigh = ul64.u.HighPart; 04515 return ul64.u.LowPart; 04516 } 04517 04518 /* Multiply two unsigned 32 bit values with overflow */ 04519 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) 04520 { 04521 ULARGE_INTEGER ul64; 04522 04523 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh; 04524 *pulHigh = ul64.u.HighPart; 04525 return ul64.u.LowPart; 04526 } 04527 04528 /* Compare two decimals that have the same scale */ 04529 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight) 04530 { 04531 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) || 04532 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight))) 04533 return -1; 04534 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight)) 04535 return 0; 04536 return 1; 04537 } 04538 04539 /************************************************************************ 04540 * VarDecAdd (OLEAUT32.177) 04541 * 04542 * Add one DECIMAL to another. 04543 * 04544 * PARAMS 04545 * pDecLeft [I] Source 04546 * pDecRight [I] Value to add 04547 * pDecOut [O] Destination 04548 * 04549 * RETURNS 04550 * Success: S_OK. 04551 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 04552 */ 04553 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 04554 { 04555 HRESULT hRet; 04556 DECIMAL scaled; 04557 04558 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled); 04559 04560 if (SUCCEEDED(hRet)) 04561 { 04562 /* Our decimals now have the same scale, we can add them as 96 bit integers */ 04563 ULONG overflow = 0; 04564 BYTE sign = DECIMAL_POS; 04565 04566 /* Correct for the sign of the result */ 04567 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) 04568 { 04569 /* -x + -y : Negative */ 04570 sign = DECIMAL_NEG; 04571 goto VarDecAdd_AsPositive; 04572 } 04573 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight)) 04574 { 04575 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); 04576 04577 /* -x + y : Negative if x > y */ 04578 if (cmp > 0) 04579 { 04580 sign = DECIMAL_NEG; 04581 VarDecAdd_AsNegative: 04582 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); 04583 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); 04584 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); 04585 } 04586 else 04587 { 04588 VarDecAdd_AsInvertedNegative: 04589 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow); 04590 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow); 04591 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow); 04592 } 04593 } 04594 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) 04595 { 04596 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); 04597 04598 /* x + -y : Negative if x <= y */ 04599 if (cmp <= 0) 04600 { 04601 sign = DECIMAL_NEG; 04602 goto VarDecAdd_AsInvertedNegative; 04603 } 04604 goto VarDecAdd_AsNegative; 04605 } 04606 else 04607 { 04608 /* x + y : Positive */ 04609 VarDecAdd_AsPositive: 04610 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); 04611 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); 04612 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); 04613 } 04614 04615 if (overflow) 04616 return DISP_E_OVERFLOW; /* overflowed */ 04617 04618 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft); 04619 DEC_SIGN(pDecOut) = sign; 04620 } 04621 return hRet; 04622 } 04623 04624 /* translate from external DECIMAL format into an internal representation */ 04625 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to) 04626 { 04627 to->scale = DEC_SCALE(from); 04628 to->sign = DEC_SIGN(from) ? 1 : 0; 04629 04630 to->bitsnum[0] = DEC_LO32(from); 04631 to->bitsnum[1] = DEC_MID32(from); 04632 to->bitsnum[2] = DEC_HI32(from); 04633 } 04634 04635 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to) 04636 { 04637 if (from->sign) { 04638 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale); 04639 } else { 04640 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale); 04641 } 04642 04643 DEC_LO32(to) = from->bitsnum[0]; 04644 DEC_MID32(to) = from->bitsnum[1]; 04645 DEC_HI32(to) = from->bitsnum[2]; 04646 } 04647 04648 /* clear an internal representation of a DECIMAL */ 04649 static void VARIANT_DI_clear(VARIANT_DI * i) 04650 { 04651 memset(i, 0, sizeof(VARIANT_DI)); 04652 } 04653 04654 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero 04655 size is supported. The value in p is replaced by the quotient of the division, and 04656 the remainder is returned as a result. This routine is most often used with a divisor 04657 of 10 in order to scale up numbers, and in the DECIMAL->string conversion. 04658 */ 04659 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor) 04660 { 04661 if (divisor == 0) { 04662 /* division by 0 */ 04663 return 0xFF; 04664 } else if (divisor == 1) { 04665 /* dividend remains unchanged */ 04666 return 0; 04667 } else { 04668 unsigned char remainder = 0; 04669 ULONGLONG iTempDividend; 04670 signed int i; 04671 04672 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */ 04673 for (; i >= 0; i--) { 04674 iTempDividend = ((ULONGLONG)remainder << 32) + p[i]; 04675 remainder = iTempDividend % divisor; 04676 p[i] = iTempDividend / divisor; 04677 } 04678 04679 return remainder; 04680 } 04681 } 04682 04683 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */ 04684 static int VARIANT_int_iszero(const DWORD * p, unsigned int n) 04685 { 04686 for (; n > 0; n--) if (*p++ != 0) return 0; 04687 return 1; 04688 } 04689 04690 /* multiply two DECIMALS, without changing either one, and place result in third 04691 parameter. Result is normalized when scale is > 0. Attempts to remove significant 04692 digits when scale > 0 in order to fit an overflowing result. Final overflow 04693 flag is returned. 04694 */ 04695 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result) 04696 { 04697 int r_overflow = 0; 04698 DWORD running[6]; 04699 signed int mulstart; 04700 04701 VARIANT_DI_clear(result); 04702 result->sign = (a->sign ^ b->sign) ? 1 : 0; 04703 04704 /* Multiply 128-bit operands into a (max) 256-bit result. The scale 04705 of the result is formed by adding the scales of the operands. 04706 */ 04707 result->scale = a->scale + b->scale; 04708 memset(running, 0, sizeof(running)); 04709 04710 /* count number of leading zero-bytes in operand A */ 04711 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--); 04712 if (mulstart < 0) { 04713 /* result is 0, because operand A is 0 */ 04714 result->scale = 0; 04715 result->sign = 0; 04716 } else { 04717 unsigned char remainder = 0; 04718 int iA; 04719 04720 /* perform actual multiplication */ 04721 for (iA = 0; iA <= mulstart; iA++) { 04722 ULONG iOverflowMul; 04723 int iB; 04724 04725 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) { 04726 ULONG iRV; 04727 int iR; 04728 04729 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul); 04730 iR = iA + iB; 04731 do { 04732 running[iR] = VARIANT_Add(running[iR], 0, &iRV); 04733 iR++; 04734 } while (iRV); 04735 } 04736 } 04737 04738 /* Too bad - native oleaut does not do this, so we should not either */ 04739 #if 0 04740 /* While the result is divisible by 10, and the scale > 0, divide by 10. 04741 This operation should not lose significant digits, and gives an 04742 opportunity to reduce the possibility of overflows in future 04743 operations issued by the application. 04744 */ 04745 while (result->scale > 0) { 04746 memcpy(quotient, running, sizeof(quotient)); 04747 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10); 04748 if (remainder > 0) break; 04749 memcpy(running, quotient, sizeof(quotient)); 04750 result->scale--; 04751 } 04752 #endif 04753 /* While the 256-bit result overflows, and the scale > 0, divide by 10. 04754 This operation *will* lose significant digits of the result because 04755 all the factors of 10 were consumed by the previous operation. 04756 */ 04757 while (result->scale > 0 && !VARIANT_int_iszero( 04758 running + sizeof(result->bitsnum) / sizeof(DWORD), 04759 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) { 04760 04761 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10); 04762 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder); 04763 result->scale--; 04764 } 04765 04766 /* round up the result - native oleaut32 does this */ 04767 if (remainder >= 5) { 04768 unsigned int i; 04769 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) { 04770 ULONGLONG digit = running[i] + 1; 04771 remainder = (digit > 0xFFFFFFFF) ? 1 : 0; 04772 running[i] = digit & 0xFFFFFFFF; 04773 } 04774 } 04775 04776 /* Signal overflow if scale == 0 and 256-bit result still overflows, 04777 and copy result bits into result structure 04778 */ 04779 r_overflow = !VARIANT_int_iszero( 04780 running + sizeof(result->bitsnum)/sizeof(DWORD), 04781 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD)); 04782 memcpy(result->bitsnum, running, sizeof(result->bitsnum)); 04783 } 04784 return r_overflow; 04785 } 04786 04787 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is 04788 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for 04789 success, nonzero if insufficient space in output buffer. 04790 */ 04791 static int VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n) 04792 { 04793 int overflow = 0; 04794 DWORD quotient[3]; 04795 unsigned char remainder; 04796 unsigned int i; 04797 04798 /* place negative sign */ 04799 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) { 04800 if (n > 0) { 04801 *s++ = '-'; 04802 n--; 04803 } 04804 else overflow = 1; 04805 } 04806 04807 /* prepare initial 0 */ 04808 if (!overflow) { 04809 if (n >= 2) { 04810 s[0] = '0'; 04811 s[1] = '\0'; 04812 } else overflow = 1; 04813 } 04814 04815 i = 0; 04816 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum)); 04817 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) { 04818 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10); 04819 if (i + 2 > n) { 04820 overflow = 1; 04821 } else { 04822 s[i++] = '0' + remainder; 04823 s[i] = '\0'; 04824 } 04825 } 04826 04827 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) { 04828 04829 /* reverse order of digits */ 04830 WCHAR * x = s; WCHAR * y = s + i - 1; 04831 while (x < y) { 04832 *x ^= *y; 04833 *y ^= *x; 04834 *x++ ^= *y--; 04835 } 04836 04837 /* check for decimal point. "i" now has string length */ 04838 if (i <= a->scale) { 04839 unsigned int numzeroes = a->scale + 1 - i; 04840 if (i + 1 + numzeroes >= n) { 04841 overflow = 1; 04842 } else { 04843 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR)); 04844 i += numzeroes; 04845 while (numzeroes > 0) { 04846 s[--numzeroes] = '0'; 04847 } 04848 } 04849 } 04850 04851 /* place decimal point */ 04852 if (a->scale > 0) { 04853 unsigned int periodpos = i - a->scale; 04854 if (i + 2 >= n) { 04855 overflow = 1; 04856 } else { 04857 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR)); 04858 s[periodpos] = '.'; i++; 04859 04860 /* remove extra zeros at the end, if any */ 04861 while (s[i - 1] == '0') s[--i] = '\0'; 04862 if (s[i - 1] == '.') s[--i] = '\0'; 04863 } 04864 } 04865 } 04866 04867 return overflow; 04868 } 04869 04870 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */ 04871 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift) 04872 { 04873 DWORD shifted; 04874 unsigned int i; 04875 04876 /* shift whole DWORDs to the left */ 04877 while (shift >= 32) 04878 { 04879 memmove(p + 1, p, (n - 1) * sizeof(DWORD)); 04880 *p = 0; shift -= 32; 04881 } 04882 04883 /* shift remainder (1..31 bits) */ 04884 shifted = 0; 04885 if (shift > 0) for (i = 0; i < n; i++) 04886 { 04887 DWORD b; 04888 b = p[i] >> (32 - shift); 04889 p[i] = (p[i] << shift) | shifted; 04890 shifted = b; 04891 } 04892 } 04893 04894 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0. 04895 Value at v is incremented by the value at p. Any size is supported, provided 04896 that v is not shorter than p. Any unapplied carry is returned as a result. 04897 */ 04898 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p, 04899 unsigned int np) 04900 { 04901 unsigned char carry = 0; 04902 04903 if (nv >= np) { 04904 ULONGLONG sum; 04905 unsigned int i; 04906 04907 for (i = 0; i < np; i++) { 04908 sum = (ULONGLONG)v[i] 04909 + (ULONGLONG)p[i] 04910 + (ULONGLONG)carry; 04911 v[i] = sum & 0xffffffff; 04912 carry = sum >> 32; 04913 } 04914 for (; i < nv && carry; i++) { 04915 sum = (ULONGLONG)v[i] 04916 + (ULONGLONG)carry; 04917 v[i] = sum & 0xffffffff; 04918 carry = sum >> 32; 04919 } 04920 } 04921 return carry; 04922 } 04923 04924 /* perform integral division with operand p as dividend. Parameter n indicates 04925 number of available DWORDs in divisor p, but available space in p must be 04926 actually at least 2 * n DWORDs, because the remainder of the integral 04927 division is built in the next n DWORDs past the start of the quotient. This 04928 routine replaces the dividend in p with the quotient, and appends n 04929 additional DWORDs for the remainder. 04930 04931 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on 04932 C/C++ :-) where the "longhand binary division" algorithm was exposed for the 04933 source code to the VLI (Very Large Integer) division operator. This algorithm 04934 was then heavily modified by me (Alex Villacis Lasso) in order to handle 04935 variably-scaled integers such as the MS DECIMAL representation. 04936 */ 04937 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor, 04938 unsigned int dn) 04939 { 04940 unsigned int i; 04941 DWORD tempsub[8]; 04942 DWORD * negdivisor = tempsub + n; 04943 04944 /* build 2s-complement of divisor */ 04945 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF; 04946 p[n] = 1; 04947 VARIANT_int_add(negdivisor, n, p + n, 1); 04948 memset(p + n, 0, n * sizeof(DWORD)); 04949 04950 /* skip all leading zero DWORDs in quotient */ 04951 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32); 04952 /* i is now number of DWORDs left to process */ 04953 for (i <<= 5; i < (n << 5); i++) { 04954 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */ 04955 04956 /* trial subtraction */ 04957 memcpy(tempsub, p + n, n * sizeof(DWORD)); 04958 VARIANT_int_add(tempsub, n, negdivisor, n); 04959 04960 /* check whether result of subtraction was negative */ 04961 if ((tempsub[n - 1] & 0x80000000) == 0) { 04962 memcpy(p + n, tempsub, n * sizeof(DWORD)); 04963 p[0] |= 1; 04964 } 04965 } 04966 } 04967 04968 /* perform integral multiplication by a byte operand. Used for scaling by 10 */ 04969 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m) 04970 { 04971 unsigned int i; 04972 ULONG iOverflowMul; 04973 04974 for (iOverflowMul = 0, i = 0; i < n; i++) 04975 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul); 04976 return (unsigned char)iOverflowMul; 04977 } 04978 04979 /* increment value in A by the value indicated in B, with scale adjusting. 04980 Modifies parameters by adjusting scales. Returns 0 if addition was 04981 successful, nonzero if a parameter underflowed before it could be 04982 successfully used in the addition. 04983 */ 04984 static int VARIANT_int_addlossy( 04985 DWORD * a, int * ascale, unsigned int an, 04986 DWORD * b, int * bscale, unsigned int bn) 04987 { 04988 int underflow = 0; 04989 04990 if (VARIANT_int_iszero(a, an)) { 04991 /* if A is zero, copy B into A, after removing digits */ 04992 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) { 04993 VARIANT_int_divbychar(b, bn, 10); 04994 (*bscale)--; 04995 } 04996 memcpy(a, b, an * sizeof(DWORD)); 04997 *ascale = *bscale; 04998 } else if (!VARIANT_int_iszero(b, bn)) { 04999 unsigned int tn = an + 1; 05000 DWORD t[5]; 05001 05002 if (bn + 1 > tn) tn = bn + 1; 05003 if (*ascale != *bscale) { 05004 /* first (optimistic) try - try to scale down the one with the bigger 05005 scale, while this number is divisible by 10 */ 05006 DWORD * digitchosen; 05007 unsigned int nchosen; 05008 int * scalechosen; 05009 int targetscale; 05010 05011 if (*ascale < *bscale) { 05012 targetscale = *ascale; 05013 scalechosen = bscale; 05014 digitchosen = b; 05015 nchosen = bn; 05016 } else { 05017 targetscale = *bscale; 05018 scalechosen = ascale; 05019 digitchosen = a; 05020 nchosen = an; 05021 } 05022 memset(t, 0, tn * sizeof(DWORD)); 05023 memcpy(t, digitchosen, nchosen * sizeof(DWORD)); 05024 05025 /* divide by 10 until target scale is reached */ 05026 while (*scalechosen > targetscale) { 05027 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10); 05028 if (!remainder) { 05029 (*scalechosen)--; 05030 memcpy(digitchosen, t, nchosen * sizeof(DWORD)); 05031 } else break; 05032 } 05033 } 05034 05035 if (*ascale != *bscale) { 05036 DWORD * digitchosen; 05037 unsigned int nchosen; 05038 int * scalechosen; 05039 int targetscale; 05040 05041 /* try to scale up the one with the smaller scale */ 05042 if (*ascale > *bscale) { 05043 targetscale = *ascale; 05044 scalechosen = bscale; 05045 digitchosen = b; 05046 nchosen = bn; 05047 } else { 05048 targetscale = *bscale; 05049 scalechosen = ascale; 05050 digitchosen = a; 05051 nchosen = an; 05052 } 05053 memset(t, 0, tn * sizeof(DWORD)); 05054 memcpy(t, digitchosen, nchosen * sizeof(DWORD)); 05055 05056 /* multiply by 10 until target scale is reached, or 05057 significant bytes overflow the number 05058 */ 05059 while (*scalechosen < targetscale && t[nchosen] == 0) { 05060 VARIANT_int_mulbychar(t, tn, 10); 05061 if (t[nchosen] == 0) { 05062 /* still does not overflow */ 05063 (*scalechosen)++; 05064 memcpy(digitchosen, t, nchosen * sizeof(DWORD)); 05065 } 05066 } 05067 } 05068 05069 if (*ascale != *bscale) { 05070 /* still different? try to scale down the one with the bigger scale 05071 (this *will* lose significant digits) */ 05072 DWORD * digitchosen; 05073 unsigned int nchosen; 05074 int * scalechosen; 05075 int targetscale; 05076 05077 if (*ascale < *bscale) { 05078 targetscale = *ascale; 05079 scalechosen = bscale; 05080 digitchosen = b; 05081 nchosen = bn; 05082 } else { 05083 targetscale = *bscale; 05084 scalechosen = ascale; 05085 digitchosen = a; 05086 nchosen = an; 05087 } 05088 memset(t, 0, tn * sizeof(DWORD)); 05089 memcpy(t, digitchosen, nchosen * sizeof(DWORD)); 05090 05091 /* divide by 10 until target scale is reached */ 05092 while (*scalechosen > targetscale) { 05093 VARIANT_int_divbychar(t, tn, 10); 05094 (*scalechosen)--; 05095 memcpy(digitchosen, t, nchosen * sizeof(DWORD)); 05096 } 05097 } 05098 05099 /* check whether any of the operands still has significant digits 05100 (underflow case 1) 05101 */ 05102 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) { 05103 underflow = 1; 05104 } else { 05105 /* at this step, both numbers have the same scale and can be added 05106 as integers. However, the result might not fit in A, so further 05107 scaling down might be necessary. 05108 */ 05109 while (!underflow) { 05110 memset(t, 0, tn * sizeof(DWORD)); 05111 memcpy(t, a, an * sizeof(DWORD)); 05112 05113 VARIANT_int_add(t, tn, b, bn); 05114 if (VARIANT_int_iszero(t + an, tn - an)) { 05115 /* addition was successful */ 05116 memcpy(a, t, an * sizeof(DWORD)); 05117 break; 05118 } else { 05119 /* addition overflowed - remove significant digits 05120 from both operands and try again */ 05121 VARIANT_int_divbychar(a, an, 10); (*ascale)--; 05122 VARIANT_int_divbychar(b, bn, 10); (*bscale)--; 05123 /* check whether any operand keeps significant digits after 05124 scaledown (underflow case 2) 05125 */ 05126 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)); 05127 } 05128 } 05129 } 05130 } 05131 return underflow; 05132 } 05133 05134 /* perform complete DECIMAL division in the internal representation. Returns 05135 0 if the division was completed (even if quotient is set to 0), or nonzero 05136 in case of quotient overflow. 05137 */ 05138 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor, 05139 VARIANT_DI * quotient) 05140 { 05141 HRESULT r_overflow = S_OK; 05142 05143 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) { 05144 /* division by 0 */ 05145 r_overflow = DISP_E_DIVBYZERO; 05146 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) { 05147 VARIANT_DI_clear(quotient); 05148 } else { 05149 int quotientscale, remainderscale, tempquotientscale; 05150 DWORD remainderplusquotient[8]; 05151 int underflow; 05152 05153 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale; 05154 tempquotientscale = quotientscale; 05155 VARIANT_DI_clear(quotient); 05156 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0; 05157 05158 /* The following strategy is used for division 05159 1) if there was a nonzero remainder from previous iteration, use it as 05160 dividend for this iteration, else (for first iteration) use intended 05161 dividend 05162 2) perform integer division in temporary buffer, develop quotient in 05163 low-order part, remainder in high-order part 05164 3) add quotient from step 2 to final result, with possible loss of 05165 significant digits 05166 4) multiply integer part of remainder by 10, while incrementing the 05167 scale of the remainder. This operation preserves the intended value 05168 of the remainder. 05169 5) loop to step 1 until one of the following is true: 05170 a) remainder is zero (exact division achieved) 05171 b) addition in step 3 fails to modify bits in quotient (remainder underflow) 05172 */ 05173 memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); 05174 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum)); 05175 do { 05176 VARIANT_int_div( 05177 remainderplusquotient, 4, 05178 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD)); 05179 underflow = VARIANT_int_addlossy( 05180 quotient->bitsnum, "ientscale, sizeof(quotient->bitsnum) / sizeof(DWORD), 05181 remainderplusquotient, &tempquotientscale, 4); 05182 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10); 05183 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD)); 05184 tempquotientscale = ++remainderscale; 05185 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4)); 05186 05187 /* quotient scale might now be negative (extremely big number). If, so, try 05188 to multiply quotient by 10 (without overflowing), while adjusting the scale, 05189 until scale is 0. If this cannot be done, it is a real overflow. 05190 */ 05191 while (r_overflow == S_OK && quotientscale < 0) { 05192 memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); 05193 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum)); 05194 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10); 05195 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD), 05196 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) { 05197 quotientscale++; 05198 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum)); 05199 } else r_overflow = DISP_E_OVERFLOW; 05200 } 05201 if (r_overflow == S_OK) { 05202 if (quotientscale <= 255) quotient->scale = quotientscale; 05203 else VARIANT_DI_clear(quotient); 05204 } 05205 } 05206 return r_overflow; 05207 } 05208 05209 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but 05210 with an undefined scale, which will be assigned to (if possible). It also 05211 receives an exponent of 2. This procedure will then manipulate the mantissa 05212 and calculate a corresponding scale, so that the exponent2 value is assimilated 05213 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if 05214 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into 05215 a DECIMAL. */ 05216 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, int isDouble) 05217 { 05218 HRESULT hres = S_OK; 05219 int exponent5, exponent10; 05220 05221 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and 05222 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations, 05223 exponent10 might be used to set the VARIANT_DI scale directly. However, 05224 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */ 05225 exponent5 = -exponent2; 05226 exponent10 = exponent2; 05227 05228 /* Handle exponent5 > 0 */ 05229 while (exponent5 > 0) { 05230 char bPrevCarryBit; 05231 char bCurrCarryBit; 05232 05233 /* In order to multiply the value represented by the VARIANT_DI by 5, it 05234 is best to multiply by 10/2. Therefore, exponent10 is incremented, and 05235 somehow the mantissa should be divided by 2. */ 05236 if ((val->bitsnum[0] & 1) == 0) { 05237 /* The mantissa is divisible by 2. Therefore the division can be done 05238 without losing significant digits. */ 05239 exponent10++; exponent5--; 05240 05241 /* Shift right */ 05242 bPrevCarryBit = val->bitsnum[2] & 1; 05243 val->bitsnum[2] >>= 1; 05244 bCurrCarryBit = val->bitsnum[1] & 1; 05245 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0); 05246 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0); 05247 } else { 05248 /* The mantissa is NOT divisible by 2. Therefore the mantissa should 05249 be multiplied by 5, unless the multiplication overflows. */ 05250 DWORD temp_bitsnum[3]; 05251 05252 exponent5--; 05253 05254 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD)); 05255 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) { 05256 /* Multiplication succeeded without overflow, so copy result back 05257 into VARIANT_DI */ 05258 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD)); 05259 05260 /* Mask out 3 extraneous bits introduced by the multiply */ 05261 } else { 05262 /* Multiplication by 5 overflows. The mantissa should be divided 05263 by 2, and therefore will lose significant digits. */ 05264 exponent10++; 05265 05266 /* Shift right */ 05267 bPrevCarryBit = val->bitsnum[2] & 1; 05268 val->bitsnum[2] >>= 1; 05269 bCurrCarryBit = val->bitsnum[1] & 1; 05270 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0); 05271 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0); 05272 } 05273 } 05274 } 05275 05276 /* Handle exponent5 < 0 */ 05277 while (exponent5 < 0) { 05278 /* In order to divide the value represented by the VARIANT_DI by 5, it 05279 is best to multiply by 2/10. Therefore, exponent10 is decremented, 05280 and the mantissa should be multiplied by 2 */ 05281 if ((val->bitsnum[2] & 0x80000000) == 0) { 05282 /* The mantissa can withstand a shift-left without overflowing */ 05283 exponent10--; exponent5++; 05284 VARIANT_int_shiftleft(val->bitsnum, 3, 1); 05285 } else { 05286 /* The mantissa would overflow if shifted. Therefore it should be 05287 directly divided by 5. This will lose significant digits, unless 05288 by chance the mantissa happens to be divisible by 5 */ 05289 exponent5++; 05290 VARIANT_int_divbychar(val->bitsnum, 3, 5); 05291 } 05292 } 05293 05294 /* At this point, the mantissa has assimilated the exponent5, but the 05295 exponent10 might not be suitable for assignment. The exponent10 must be 05296 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or 05297 down appropriately. */ 05298 while (hres == S_OK && exponent10 > 0) { 05299 /* In order to bring exponent10 down to 0, the mantissa should be 05300 multiplied by 10 to compensate. If the exponent10 is too big, this 05301 will cause the mantissa to overflow. */ 05302 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) { 05303 exponent10--; 05304 } else { 05305 hres = DISP_E_OVERFLOW; 05306 } 05307 } 05308 while (exponent10 < -DEC_MAX_SCALE) { 05309 int rem10; 05310 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should 05311 be divided by 10 to compensate. If the exponent10 is too small, this 05312 will cause the mantissa to underflow and become 0 */ 05313 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10); 05314 exponent10++; 05315 if (VARIANT_int_iszero(val->bitsnum, 3)) { 05316 /* Underflow, unable to keep dividing */ 05317 exponent10 = 0; 05318 } else if (rem10 >= 5) { 05319 DWORD x = 1; 05320 VARIANT_int_add(val->bitsnum, 3, &x, 1); 05321 } 05322 } 05323 /* This step is required in order to remove excess bits of precision from the 05324 end of the bit representation, down to the precision guaranteed by the 05325 floating point number. */ 05326 if (isDouble) { 05327 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[2] == 0 && (val->bitsnum[1] & 0xFFE00000) != 0))) { 05328 int rem10; 05329 05330 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10); 05331 exponent10++; 05332 if (rem10 >= 5) { 05333 DWORD x = 1; 05334 VARIANT_int_add(val->bitsnum, 3, &x, 1); 05335 } 05336 } 05337 } else { 05338 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 || 05339 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) { 05340 int rem10; 05341 05342 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10); 05343 exponent10++; 05344 if (rem10 >= 5) { 05345 DWORD x = 1; 05346 VARIANT_int_add(val->bitsnum, 3, &x, 1); 05347 } 05348 } 05349 } 05350 /* Remove multiples of 10 from the representation */ 05351 while (exponent10 < 0) { 05352 DWORD temp_bitsnum[3]; 05353 05354 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD)); 05355 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) { 05356 exponent10++; 05357 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD)); 05358 } else break; 05359 } 05360 05361 /* Scale assignment */ 05362 if (hres == S_OK) val->scale = -exponent10; 05363 05364 return hres; 05365 } 05366 05367 typedef union 05368 { 05369 struct 05370 { 05371 unsigned int m : 23; 05372 unsigned int exp_bias : 8; 05373 unsigned int sign : 1; 05374 } i; 05375 float f; 05376 } R4_FIELDS; 05377 05378 /* Convert a 32-bit floating point number into a DECIMAL, without using an 05379 intermediate string step. */ 05380 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest) 05381 { 05382 HRESULT hres = S_OK; 05383 R4_FIELDS fx; 05384 05385 fx.f = source; 05386 05387 /* Detect special cases */ 05388 if (fx.i.m == 0 && fx.i.exp_bias == 0) { 05389 /* Floating-point zero */ 05390 VARIANT_DI_clear(dest); 05391 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) { 05392 /* Floating-point infinity */ 05393 hres = DISP_E_OVERFLOW; 05394 } else if (fx.i.exp_bias == 0xFF) { 05395 /* Floating-point NaN */ 05396 hres = DISP_E_BADVARTYPE; 05397 } else { 05398 int exponent2; 05399 VARIANT_DI_clear(dest); 05400 05401 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */ 05402 dest->sign = fx.i.sign; /* Sign is simply copied */ 05403 05404 /* Copy significant bits to VARIANT_DI mantissa */ 05405 dest->bitsnum[0] = fx.i.m; 05406 dest->bitsnum[0] &= 0x007FFFFF; 05407 if (fx.i.exp_bias == 0) { 05408 /* Denormalized number - correct exponent */ 05409 exponent2++; 05410 } else { 05411 /* Add hidden bit to mantissa */ 05412 dest->bitsnum[0] |= 0x00800000; 05413 } 05414 05415 /* The act of copying a FP mantissa as integer bits is equivalent to 05416 shifting left the mantissa 23 bits. The exponent2 is reduced to 05417 compensate. */ 05418 exponent2 -= 23; 05419 05420 hres = VARIANT_DI_normalize(dest, exponent2, 0); 05421 } 05422 05423 return hres; 05424 } 05425 05426 typedef union 05427 { 05428 struct 05429 { 05430 unsigned int m_lo : 32; /* 52 bits of precision */ 05431 unsigned int m_hi : 20; 05432 unsigned int exp_bias : 11; /* bias == 1023 */ 05433 unsigned int sign : 1; 05434 } i; 05435 double d; 05436 } R8_FIELDS; 05437 05438 /* Convert a 64-bit floating point number into a DECIMAL, without using an 05439 intermediate string step. */ 05440 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest) 05441 { 05442 HRESULT hres = S_OK; 05443 R8_FIELDS fx; 05444 05445 fx.d = source; 05446 05447 /* Detect special cases */ 05448 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) { 05449 /* Floating-point zero */ 05450 VARIANT_DI_clear(dest); 05451 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) { 05452 /* Floating-point infinity */ 05453 hres = DISP_E_OVERFLOW; 05454 } else if (fx.i.exp_bias == 0x7FF) { 05455 /* Floating-point NaN */ 05456 hres = DISP_E_BADVARTYPE; 05457 } else { 05458 int exponent2; 05459 VARIANT_DI_clear(dest); 05460 05461 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */ 05462 dest->sign = fx.i.sign; /* Sign is simply copied */ 05463 05464 /* Copy significant bits to VARIANT_DI mantissa */ 05465 dest->bitsnum[0] = fx.i.m_lo; 05466 dest->bitsnum[1] = fx.i.m_hi; 05467 dest->bitsnum[1] &= 0x000FFFFF; 05468 if (fx.i.exp_bias == 0) { 05469 /* Denormalized number - correct exponent */ 05470 exponent2++; 05471 } else { 05472 /* Add hidden bit to mantissa */ 05473 dest->bitsnum[1] |= 0x00100000; 05474 } 05475 05476 /* The act of copying a FP mantissa as integer bits is equivalent to 05477 shifting left the mantissa 52 bits. The exponent2 is reduced to 05478 compensate. */ 05479 exponent2 -= 52; 05480 05481 hres = VARIANT_DI_normalize(dest, exponent2, 1); 05482 } 05483 05484 return hres; 05485 } 05486 05487 /************************************************************************ 05488 * VarDecDiv (OLEAUT32.178) 05489 * 05490 * Divide one DECIMAL by another. 05491 * 05492 * PARAMS 05493 * pDecLeft [I] Source 05494 * pDecRight [I] Value to divide by 05495 * pDecOut [O] Destination 05496 * 05497 * RETURNS 05498 * Success: S_OK. 05499 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 05500 */ 05501 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 05502 { 05503 HRESULT hRet = S_OK; 05504 VARIANT_DI di_left, di_right, di_result; 05505 HRESULT divresult; 05506 05507 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG; 05508 05509 VARIANT_DIFromDec(pDecLeft, &di_left); 05510 VARIANT_DIFromDec(pDecRight, &di_right); 05511 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result); 05512 if (divresult != S_OK) 05513 { 05514 /* division actually overflowed */ 05515 hRet = divresult; 05516 } 05517 else 05518 { 05519 hRet = S_OK; 05520 05521 if (di_result.scale > DEC_MAX_SCALE) 05522 { 05523 unsigned char remainder = 0; 05524 05525 /* division underflowed. In order to comply with the MSDN 05526 specifications for DECIMAL ranges, some significant digits 05527 must be removed 05528 */ 05529 WARN("result scale is %u, scaling (with loss of significant digits)...\n", 05530 di_result.scale); 05531 while (di_result.scale > DEC_MAX_SCALE && 05532 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD))) 05533 { 05534 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10); 05535 di_result.scale--; 05536 } 05537 if (di_result.scale > DEC_MAX_SCALE) 05538 { 05539 WARN("result underflowed, setting to 0\n"); 05540 di_result.scale = 0; 05541 di_result.sign = 0; 05542 } 05543 else if (remainder >= 5) /* round up result - native oleaut32 does this */ 05544 { 05545 unsigned int i; 05546 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) { 05547 ULONGLONG digit = di_result.bitsnum[i] + 1; 05548 remainder = (digit > 0xFFFFFFFF) ? 1 : 0; 05549 di_result.bitsnum[i] = digit & 0xFFFFFFFF; 05550 } 05551 } 05552 } 05553 VARIANT_DecFromDI(&di_result, pDecOut); 05554 } 05555 return hRet; 05556 } 05557 05558 /************************************************************************ 05559 * VarDecMul (OLEAUT32.179) 05560 * 05561 * Multiply one DECIMAL by another. 05562 * 05563 * PARAMS 05564 * pDecLeft [I] Source 05565 * pDecRight [I] Value to multiply by 05566 * pDecOut [O] Destination 05567 * 05568 * RETURNS 05569 * Success: S_OK. 05570 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 05571 */ 05572 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 05573 { 05574 HRESULT hRet = S_OK; 05575 VARIANT_DI di_left, di_right, di_result; 05576 int mulresult; 05577 05578 VARIANT_DIFromDec(pDecLeft, &di_left); 05579 VARIANT_DIFromDec(pDecRight, &di_right); 05580 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result); 05581 if (mulresult) 05582 { 05583 /* multiplication actually overflowed */ 05584 hRet = DISP_E_OVERFLOW; 05585 } 05586 else 05587 { 05588 if (di_result.scale > DEC_MAX_SCALE) 05589 { 05590 /* multiplication underflowed. In order to comply with the MSDN 05591 specifications for DECIMAL ranges, some significant digits 05592 must be removed 05593 */ 05594 WARN("result scale is %u, scaling (with loss of significant digits)...\n", 05595 di_result.scale); 05596 while (di_result.scale > DEC_MAX_SCALE && 05597 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD))) 05598 { 05599 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10); 05600 di_result.scale--; 05601 } 05602 if (di_result.scale > DEC_MAX_SCALE) 05603 { 05604 WARN("result underflowed, setting to 0\n"); 05605 di_result.scale = 0; 05606 di_result.sign = 0; 05607 } 05608 } 05609 VARIANT_DecFromDI(&di_result, pDecOut); 05610 } 05611 return hRet; 05612 } 05613 05614 /************************************************************************ 05615 * VarDecSub (OLEAUT32.181) 05616 * 05617 * Subtract one DECIMAL from another. 05618 * 05619 * PARAMS 05620 * pDecLeft [I] Source 05621 * pDecRight [I] DECIMAL to subtract from pDecLeft 05622 * pDecOut [O] Destination 05623 * 05624 * RETURNS 05625 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 05626 */ 05627 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 05628 { 05629 DECIMAL decRight; 05630 05631 /* Implement as addition of the negative */ 05632 VarDecNeg(pDecRight, &decRight); 05633 return VarDecAdd(pDecLeft, &decRight, pDecOut); 05634 } 05635 05636 /************************************************************************ 05637 * VarDecAbs (OLEAUT32.182) 05638 * 05639 * Convert a DECIMAL into its absolute value. 05640 * 05641 * PARAMS 05642 * pDecIn [I] Source 05643 * pDecOut [O] Destination 05644 * 05645 * RETURNS 05646 * S_OK. This function does not fail. 05647 */ 05648 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut) 05649 { 05650 *pDecOut = *pDecIn; 05651 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG; 05652 return S_OK; 05653 } 05654 05655 /************************************************************************ 05656 * VarDecFix (OLEAUT32.187) 05657 * 05658 * Return the integer portion of a DECIMAL. 05659 * 05660 * PARAMS 05661 * pDecIn [I] Source 05662 * pDecOut [O] Destination 05663 * 05664 * RETURNS 05665 * Success: S_OK. 05666 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 05667 * 05668 * NOTES 05669 * - The difference between this function and VarDecInt() is that VarDecInt() rounds 05670 * negative numbers away from 0, while this function rounds them towards zero. 05671 */ 05672 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut) 05673 { 05674 double dbl; 05675 HRESULT hr; 05676 05677 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 05678 return E_INVALIDARG; 05679 05680 if (!DEC_SCALE(pDecIn)) 05681 { 05682 *pDecOut = *pDecIn; /* Already an integer */ 05683 return S_OK; 05684 } 05685 05686 hr = VarR8FromDec(pDecIn, &dbl); 05687 if (SUCCEEDED(hr)) { 05688 LONGLONG rounded = dbl; 05689 05690 hr = VarDecFromI8(rounded, pDecOut); 05691 } 05692 return hr; 05693 } 05694 05695 /************************************************************************ 05696 * VarDecInt (OLEAUT32.188) 05697 * 05698 * Return the integer portion of a DECIMAL. 05699 * 05700 * PARAMS 05701 * pDecIn [I] Source 05702 * pDecOut [O] Destination 05703 * 05704 * RETURNS 05705 * Success: S_OK. 05706 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 05707 * 05708 * NOTES 05709 * - The difference between this function and VarDecFix() is that VarDecFix() rounds 05710 * negative numbers towards 0, while this function rounds them away from zero. 05711 */ 05712 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut) 05713 { 05714 double dbl; 05715 HRESULT hr; 05716 05717 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 05718 return E_INVALIDARG; 05719 05720 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn)) 05721 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */ 05722 05723 hr = VarR8FromDec(pDecIn, &dbl); 05724 if (SUCCEEDED(hr)) { 05725 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5; 05726 05727 hr = VarDecFromI8(rounded, pDecOut); 05728 } 05729 return hr; 05730 } 05731 05732 /************************************************************************ 05733 * VarDecNeg (OLEAUT32.189) 05734 * 05735 * Change the sign of a DECIMAL. 05736 * 05737 * PARAMS 05738 * pDecIn [I] Source 05739 * pDecOut [O] Destination 05740 * 05741 * RETURNS 05742 * S_OK. This function does not fail. 05743 */ 05744 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut) 05745 { 05746 *pDecOut = *pDecIn; 05747 DEC_SIGN(pDecOut) ^= DECIMAL_NEG; 05748 return S_OK; 05749 } 05750 05751 /************************************************************************ 05752 * VarDecRound (OLEAUT32.203) 05753 * 05754 * Change the precision of a DECIMAL. 05755 * 05756 * PARAMS 05757 * pDecIn [I] Source 05758 * cDecimals [I] New number of decimals to keep 05759 * pDecOut [O] Destination 05760 * 05761 * RETURNS 05762 * Success: S_OK. pDecOut contains the rounded value. 05763 * Failure: E_INVALIDARG if any argument is invalid. 05764 */ 05765 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut) 05766 { 05767 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE) 05768 return E_INVALIDARG; 05769 05770 if (cDecimals >= DEC_SCALE(pDecIn)) 05771 { 05772 *pDecOut = *pDecIn; /* More precision than we have */ 05773 return S_OK; 05774 } 05775 05776 FIXME("semi-stub!\n"); 05777 05778 return DISP_E_OVERFLOW; 05779 } 05780 05781 /************************************************************************ 05782 * VarDecCmp (OLEAUT32.204) 05783 * 05784 * Compare two DECIMAL values. 05785 * 05786 * PARAMS 05787 * pDecLeft [I] Source 05788 * pDecRight [I] Value to compare 05789 * 05790 * RETURNS 05791 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft 05792 * is less than, equal to or greater than pDecRight respectively. 05793 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 05794 */ 05795 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight) 05796 { 05797 HRESULT hRet; 05798 DECIMAL result; 05799 05800 if (!pDecLeft || !pDecRight) 05801 return VARCMP_NULL; 05802 05803 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) && 05804 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft))) 05805 return VARCMP_GT; 05806 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) && 05807 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft))) 05808 return VARCMP_LT; 05809 05810 /* Subtract right from left, and compare the result to 0 */ 05811 hRet = VarDecSub(pDecLeft, pDecRight, &result); 05812 05813 if (SUCCEEDED(hRet)) 05814 { 05815 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result); 05816 05817 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero) 05818 hRet = (HRESULT)VARCMP_LT; 05819 else if (non_zero) 05820 hRet = (HRESULT)VARCMP_GT; 05821 else 05822 hRet = (HRESULT)VARCMP_EQ; 05823 } 05824 return hRet; 05825 } 05826 05827 /************************************************************************ 05828 * VarDecCmpR8 (OLEAUT32.298) 05829 * 05830 * Compare a DECIMAL to a double 05831 * 05832 * PARAMS 05833 * pDecLeft [I] DECIMAL Source 05834 * dblRight [I] double to compare to pDecLeft 05835 * 05836 * RETURNS 05837 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight 05838 * is less than, equal to or greater than pDecLeft respectively. 05839 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 05840 */ 05841 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight) 05842 { 05843 HRESULT hRet; 05844 DECIMAL decRight; 05845 05846 hRet = VarDecFromR8(dblRight, &decRight); 05847 05848 if (SUCCEEDED(hRet)) 05849 hRet = VarDecCmp(pDecLeft, &decRight); 05850 05851 return hRet; 05852 } 05853 05854 /* BOOL 05855 */ 05856 05857 /************************************************************************ 05858 * VarBoolFromUI1 (OLEAUT32.118) 05859 * 05860 * Convert a VT_UI1 to a VT_BOOL. 05861 * 05862 * PARAMS 05863 * bIn [I] Source 05864 * pBoolOut [O] Destination 05865 * 05866 * RETURNS 05867 * S_OK. 05868 */ 05869 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut) 05870 { 05871 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE; 05872 return S_OK; 05873 } 05874 05875 /************************************************************************ 05876 * VarBoolFromI2 (OLEAUT32.119) 05877 * 05878 * Convert a VT_I2 to a VT_BOOL. 05879 * 05880 * PARAMS 05881 * sIn [I] Source 05882 * pBoolOut [O] Destination 05883 * 05884 * RETURNS 05885 * S_OK. 05886 */ 05887 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut) 05888 { 05889 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE; 05890 return S_OK; 05891 } 05892 05893 /************************************************************************ 05894 * VarBoolFromI4 (OLEAUT32.120) 05895 * 05896 * Convert a VT_I4 to a VT_BOOL. 05897 * 05898 * PARAMS 05899 * sIn [I] Source 05900 * pBoolOut [O] Destination 05901 * 05902 * RETURNS 05903 * S_OK. 05904 */ 05905 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut) 05906 { 05907 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE; 05908 return S_OK; 05909 } 05910 05911 /************************************************************************ 05912 * VarBoolFromR4 (OLEAUT32.121) 05913 * 05914 * Convert a VT_R4 to a VT_BOOL. 05915 * 05916 * PARAMS 05917 * fltIn [I] Source 05918 * pBoolOut [O] Destination 05919 * 05920 * RETURNS 05921 * S_OK. 05922 */ 05923 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut) 05924 { 05925 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE; 05926 return S_OK; 05927 } 05928 05929 /************************************************************************ 05930 * VarBoolFromR8 (OLEAUT32.122) 05931 * 05932 * Convert a VT_R8 to a VT_BOOL. 05933 * 05934 * PARAMS 05935 * dblIn [I] Source 05936 * pBoolOut [O] Destination 05937 * 05938 * RETURNS 05939 * S_OK. 05940 */ 05941 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut) 05942 { 05943 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE; 05944 return S_OK; 05945 } 05946 05947 /************************************************************************ 05948 * VarBoolFromDate (OLEAUT32.123) 05949 * 05950 * Convert a VT_DATE to a VT_BOOL. 05951 * 05952 * PARAMS 05953 * dateIn [I] Source 05954 * pBoolOut [O] Destination 05955 * 05956 * RETURNS 05957 * S_OK. 05958 */ 05959 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut) 05960 { 05961 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE; 05962 return S_OK; 05963 } 05964 05965 /************************************************************************ 05966 * VarBoolFromCy (OLEAUT32.124) 05967 * 05968 * Convert a VT_CY to a VT_BOOL. 05969 * 05970 * PARAMS 05971 * cyIn [I] Source 05972 * pBoolOut [O] Destination 05973 * 05974 * RETURNS 05975 * S_OK. 05976 */ 05977 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut) 05978 { 05979 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE; 05980 return S_OK; 05981 } 05982 05983 /************************************************************************ 05984 * VARIANT_GetLocalisedText [internal] 05985 * 05986 * Get a localized string from the resources 05987 * 05988 */ 05989 BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest) 05990 { 05991 HRSRC hrsrc; 05992 05993 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING, 05994 MAKEINTRESOURCEW((dwId >> 4) + 1), langId ); 05995 if (hrsrc) 05996 { 05997 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc ); 05998 05999 if (hmem) 06000 { 06001 const WCHAR *p; 06002 unsigned int i; 06003 06004 p = LockResource( hmem ); 06005 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1; 06006 06007 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) ); 06008 lpszDest[*p] = '\0'; 06009 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId); 06010 return TRUE; 06011 } 06012 } 06013 return FALSE; 06014 } 06015 06016 /************************************************************************ 06017 * VarBoolFromStr (OLEAUT32.125) 06018 * 06019 * Convert a VT_BSTR to a VT_BOOL. 06020 * 06021 * PARAMS 06022 * strIn [I] Source 06023 * lcid [I] LCID for the conversion 06024 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06025 * pBoolOut [O] Destination 06026 * 06027 * RETURNS 06028 * Success: S_OK. 06029 * Failure: E_INVALIDARG, if pBoolOut is invalid. 06030 * DISP_E_TYPEMISMATCH, if the type cannot be converted 06031 * 06032 * NOTES 06033 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally, 06034 * it may contain (in any case mapping) the text "true" or "false". 06035 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the 06036 * localised text of "True" or "False" in the language specified by lcid. 06037 * - If none of these matches occur, the string is treated as a numeric string 06038 * and the boolean pBoolOut will be set according to whether the number is zero 06039 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion. 06040 * - If the text is not numeric and does not match any of the above, then 06041 * DISP_E_TYPEMISMATCH is returned. 06042 */ 06043 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut) 06044 { 06045 /* Any VB/VBA programmers out there should recognise these strings... */ 06046 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' }; 06047 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' }; 06048 WCHAR szBuff[64]; 06049 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 06050 HRESULT hRes = S_OK; 06051 06052 if (!strIn || !pBoolOut) 06053 return DISP_E_TYPEMISMATCH; 06054 06055 /* Check if we should be comparing against localised text */ 06056 if (dwFlags & VAR_LOCALBOOL) 06057 { 06058 /* Convert our LCID into a usable value */ 06059 lcid = ConvertDefaultLocale(lcid); 06060 06061 langId = LANGIDFROMLCID(lcid); 06062 06063 if (PRIMARYLANGID(langId) == LANG_NEUTRAL) 06064 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 06065 06066 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters. 06067 * I don't think this is needed unless any of the localised text strings 06068 * contain characters that can be so mapped. In the event that this is 06069 * true for a given language (possibly some Asian languages), then strIn 06070 * should be mapped here _only_ if langId is an Id for which this can occur. 06071 */ 06072 } 06073 06074 /* Note that if we are not comparing against localised strings, langId 06075 * will have its default value of LANG_ENGLISH. This allows us to mimic 06076 * the native behaviour of always checking against English strings even 06077 * after we've checked for localised ones. 06078 */ 06079 VarBoolFromStr_CheckLocalised: 06080 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff)) 06081 { 06082 /* Compare against localised strings, ignoring case */ 06083 if (!strcmpiW(strIn, szBuff)) 06084 { 06085 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */ 06086 return hRes; 06087 } 06088 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff); 06089 if (!strcmpiW(strIn, szBuff)) 06090 { 06091 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */ 06092 return hRes; 06093 } 06094 } 06095 06096 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) 06097 { 06098 /* We have checked the localised text, now check English */ 06099 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 06100 goto VarBoolFromStr_CheckLocalised; 06101 } 06102 06103 /* All checks against localised text have failed, try #TRUE#/#FALSE# */ 06104 if (!strcmpW(strIn, szFalse)) 06105 *pBoolOut = VARIANT_FALSE; 06106 else if (!strcmpW(strIn, szTrue)) 06107 *pBoolOut = VARIANT_TRUE; 06108 else 06109 { 06110 double d; 06111 06112 /* If this string is a number, convert it as one */ 06113 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d); 06114 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE; 06115 } 06116 return hRes; 06117 } 06118 06119 /************************************************************************ 06120 * VarBoolFromDisp (OLEAUT32.126) 06121 * 06122 * Convert a VT_DISPATCH to a VT_BOOL. 06123 * 06124 * PARAMS 06125 * pdispIn [I] Source 06126 * lcid [I] LCID for conversion 06127 * pBoolOut [O] Destination 06128 * 06129 * RETURNS 06130 * Success: S_OK. 06131 * Failure: E_INVALIDARG, if the source value is invalid 06132 * DISP_E_OVERFLOW, if the value will not fit in the destination 06133 * DISP_E_TYPEMISMATCH, if the type cannot be converted 06134 */ 06135 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut) 06136 { 06137 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0); 06138 } 06139 06140 /************************************************************************ 06141 * VarBoolFromI1 (OLEAUT32.233) 06142 * 06143 * Convert a VT_I1 to a VT_BOOL. 06144 * 06145 * PARAMS 06146 * cIn [I] Source 06147 * pBoolOut [O] Destination 06148 * 06149 * RETURNS 06150 * S_OK. 06151 */ 06152 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut) 06153 { 06154 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE; 06155 return S_OK; 06156 } 06157 06158 /************************************************************************ 06159 * VarBoolFromUI2 (OLEAUT32.234) 06160 * 06161 * Convert a VT_UI2 to a VT_BOOL. 06162 * 06163 * PARAMS 06164 * usIn [I] Source 06165 * pBoolOut [O] Destination 06166 * 06167 * RETURNS 06168 * S_OK. 06169 */ 06170 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut) 06171 { 06172 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE; 06173 return S_OK; 06174 } 06175 06176 /************************************************************************ 06177 * VarBoolFromUI4 (OLEAUT32.235) 06178 * 06179 * Convert a VT_UI4 to a VT_BOOL. 06180 * 06181 * PARAMS 06182 * ulIn [I] Source 06183 * pBoolOut [O] Destination 06184 * 06185 * RETURNS 06186 * S_OK. 06187 */ 06188 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut) 06189 { 06190 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE; 06191 return S_OK; 06192 } 06193 06194 /************************************************************************ 06195 * VarBoolFromDec (OLEAUT32.236) 06196 * 06197 * Convert a VT_DECIMAL to a VT_BOOL. 06198 * 06199 * PARAMS 06200 * pDecIn [I] Source 06201 * pBoolOut [O] Destination 06202 * 06203 * RETURNS 06204 * Success: S_OK. 06205 * Failure: E_INVALIDARG, if pDecIn is invalid. 06206 */ 06207 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut) 06208 { 06209 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)) 06210 return E_INVALIDARG; 06211 06212 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn)) 06213 *pBoolOut = VARIANT_TRUE; 06214 else 06215 *pBoolOut = VARIANT_FALSE; 06216 return S_OK; 06217 } 06218 06219 /************************************************************************ 06220 * VarBoolFromI8 (OLEAUT32.370) 06221 * 06222 * Convert a VT_I8 to a VT_BOOL. 06223 * 06224 * PARAMS 06225 * ullIn [I] Source 06226 * pBoolOut [O] Destination 06227 * 06228 * RETURNS 06229 * S_OK. 06230 */ 06231 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut) 06232 { 06233 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE; 06234 return S_OK; 06235 } 06236 06237 /************************************************************************ 06238 * VarBoolFromUI8 (OLEAUT32.371) 06239 * 06240 * Convert a VT_UI8 to a VT_BOOL. 06241 * 06242 * PARAMS 06243 * ullIn [I] Source 06244 * pBoolOut [O] Destination 06245 * 06246 * RETURNS 06247 * S_OK. 06248 */ 06249 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut) 06250 { 06251 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE; 06252 return S_OK; 06253 } 06254 06255 /* BSTR 06256 */ 06257 06258 /* Write a number from a UI8 and sign */ 06259 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut) 06260 { 06261 do 06262 { 06263 WCHAR ulNextDigit = ulVal % 10; 06264 06265 *szOut-- = '0' + ulNextDigit; 06266 ulVal = (ulVal - ulNextDigit) / 10; 06267 } while (ulVal); 06268 06269 szOut++; 06270 return szOut; 06271 } 06272 06273 /* Create a (possibly localised) BSTR from a UI8 and sign */ 06274 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut) 06275 { 06276 WCHAR szConverted[256]; 06277 06278 if (dwFlags & VAR_NEGATIVE) 06279 *--szOut = '-'; 06280 06281 if (dwFlags & LOCALE_USE_NLS) 06282 { 06283 /* Format the number for the locale */ 06284 szConverted[0] = '\0'; 06285 GetNumberFormatW(lcid, 06286 dwFlags & LOCALE_NOUSEROVERRIDE, 06287 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR)); 06288 szOut = szConverted; 06289 } 06290 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR)); 06291 } 06292 06293 /* Create a (possibly localised) BSTR from a UI8 and sign */ 06294 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut) 06295 { 06296 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; 06297 06298 if (!pbstrOut) 06299 return E_INVALIDARG; 06300 06301 /* Create the basic number string */ 06302 *szOut-- = '\0'; 06303 szOut = VARIANT_WriteNumber(ulVal, szOut); 06304 06305 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); 06306 TRACE("returning %s\n", debugstr_w(*pbstrOut)); 06307 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 06308 } 06309 06310 /****************************************************************************** 06311 * VarBstrFromUI1 (OLEAUT32.108) 06312 * 06313 * Convert a VT_UI1 to a VT_BSTR. 06314 * 06315 * PARAMS 06316 * bIn [I] Source 06317 * lcid [I] LCID for the conversion 06318 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06319 * pbstrOut [O] Destination 06320 * 06321 * RETURNS 06322 * Success: S_OK. 06323 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06324 * E_OUTOFMEMORY, if memory allocation fails. 06325 */ 06326 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06327 { 06328 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut); 06329 } 06330 06331 /****************************************************************************** 06332 * VarBstrFromI2 (OLEAUT32.109) 06333 * 06334 * Convert a VT_I2 to a VT_BSTR. 06335 * 06336 * PARAMS 06337 * sIn [I] Source 06338 * lcid [I] LCID for the conversion 06339 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06340 * pbstrOut [O] Destination 06341 * 06342 * RETURNS 06343 * Success: S_OK. 06344 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06345 * E_OUTOFMEMORY, if memory allocation fails. 06346 */ 06347 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06348 { 06349 ULONG64 ul64 = sIn; 06350 06351 if (sIn < 0) 06352 { 06353 ul64 = -sIn; 06354 dwFlags |= VAR_NEGATIVE; 06355 } 06356 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 06357 } 06358 06359 /****************************************************************************** 06360 * VarBstrFromI4 (OLEAUT32.110) 06361 * 06362 * Convert a VT_I4 to a VT_BSTR. 06363 * 06364 * PARAMS 06365 * lIn [I] Source 06366 * lcid [I] LCID for the conversion 06367 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06368 * pbstrOut [O] Destination 06369 * 06370 * RETURNS 06371 * Success: S_OK. 06372 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06373 * E_OUTOFMEMORY, if memory allocation fails. 06374 */ 06375 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06376 { 06377 ULONG64 ul64 = lIn; 06378 06379 if (lIn < 0) 06380 { 06381 ul64 = (ULONG)-lIn; 06382 dwFlags |= VAR_NEGATIVE; 06383 } 06384 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 06385 } 06386 06387 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags) 06388 { 06389 BSTR bstrOut; 06390 WCHAR lpDecimalSep[16]; 06391 06392 /* Native oleaut32 uses the locale-specific decimal separator even in the 06393 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin 06394 American locales will see "one thousand and one tenth" as "1000,1" 06395 instead of "1000.1" (notice the comma). The following code checks for 06396 the need to replace the decimal separator, and if so, will prepare an 06397 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW(). 06398 */ 06399 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE), 06400 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR)); 06401 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0') 06402 { 06403 /* locale is compatible with English - return original string */ 06404 bstrOut = SysAllocString(buff); 06405 } 06406 else 06407 { 06408 WCHAR *p; 06409 WCHAR numbuff[256]; 06410 WCHAR empty[1] = {'\0'}; 06411 NUMBERFMTW minFormat; 06412 06413 minFormat.NumDigits = 0; 06414 minFormat.LeadingZero = 0; 06415 minFormat.Grouping = 0; 06416 minFormat.lpDecimalSep = lpDecimalSep; 06417 minFormat.lpThousandSep = empty; 06418 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */ 06419 06420 /* count number of decimal digits in string */ 06421 p = strchrW( buff, '.' ); 06422 if (p) minFormat.NumDigits = strlenW(p + 1); 06423 06424 numbuff[0] = '\0'; 06425 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR))) 06426 { 06427 WARN("GetNumberFormatW() failed, returning raw number string instead\n"); 06428 bstrOut = SysAllocString(buff); 06429 } 06430 else 06431 { 06432 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff)); 06433 bstrOut = SysAllocString(numbuff); 06434 } 06435 } 06436 return bstrOut; 06437 } 06438 06439 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags, 06440 BSTR* pbstrOut, LPCWSTR lpszFormat) 06441 { 06442 WCHAR buff[256]; 06443 06444 if (!pbstrOut) 06445 return E_INVALIDARG; 06446 06447 sprintfW( buff, lpszFormat, dblIn ); 06448 06449 /* Negative zeroes are disallowed (some applications depend on this). 06450 If buff starts with a minus, and then nothing follows but zeroes 06451 and/or a period, it is a negative zero and is replaced with a 06452 canonical zero. This duplicates native oleaut32 behavior. 06453 */ 06454 if (buff[0] == '-') 06455 { 06456 const WCHAR szAccept[] = {'0', '.', '\0'}; 06457 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept)) 06458 { buff[0] = '0'; buff[1] = '\0'; } 06459 } 06460 06461 TRACE("created string %s\n", debugstr_w(buff)); 06462 if (dwFlags & LOCALE_USE_NLS) 06463 { 06464 WCHAR numbuff[256]; 06465 06466 /* Format the number for the locale */ 06467 numbuff[0] = '\0'; 06468 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, 06469 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); 06470 TRACE("created NLS string %s\n", debugstr_w(numbuff)); 06471 *pbstrOut = SysAllocString(numbuff); 06472 } 06473 else 06474 { 06475 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags); 06476 } 06477 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 06478 } 06479 06480 /****************************************************************************** 06481 * VarBstrFromR4 (OLEAUT32.111) 06482 * 06483 * Convert a VT_R4 to a VT_BSTR. 06484 * 06485 * PARAMS 06486 * fltIn [I] Source 06487 * lcid [I] LCID for the conversion 06488 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06489 * pbstrOut [O] Destination 06490 * 06491 * RETURNS 06492 * Success: S_OK. 06493 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06494 * E_OUTOFMEMORY, if memory allocation fails. 06495 */ 06496 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06497 { 06498 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW); 06499 } 06500 06501 /****************************************************************************** 06502 * VarBstrFromR8 (OLEAUT32.112) 06503 * 06504 * Convert a VT_R8 to a VT_BSTR. 06505 * 06506 * PARAMS 06507 * dblIn [I] Source 06508 * lcid [I] LCID for the conversion 06509 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06510 * pbstrOut [O] Destination 06511 * 06512 * RETURNS 06513 * Success: S_OK. 06514 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06515 * E_OUTOFMEMORY, if memory allocation fails. 06516 */ 06517 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06518 { 06519 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW); 06520 } 06521 06522 /****************************************************************************** 06523 * VarBstrFromCy [OLEAUT32.113] 06524 * 06525 * Convert a VT_CY to a VT_BSTR. 06526 * 06527 * PARAMS 06528 * cyIn [I] Source 06529 * lcid [I] LCID for the conversion 06530 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06531 * pbstrOut [O] Destination 06532 * 06533 * RETURNS 06534 * Success: S_OK. 06535 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06536 * E_OUTOFMEMORY, if memory allocation fails. 06537 */ 06538 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) 06539 { 06540 WCHAR buff[256]; 06541 VARIANT_DI decVal; 06542 06543 if (!pbstrOut) 06544 return E_INVALIDARG; 06545 06546 decVal.scale = 4; 06547 decVal.sign = 0; 06548 decVal.bitsnum[0] = cyIn.s.Lo; 06549 decVal.bitsnum[1] = cyIn.s.Hi; 06550 if (cyIn.s.Hi & 0x80000000UL) { 06551 DWORD one = 1; 06552 06553 /* Negative number! */ 06554 decVal.sign = 1; 06555 decVal.bitsnum[0] = ~decVal.bitsnum[0]; 06556 decVal.bitsnum[1] = ~decVal.bitsnum[1]; 06557 VARIANT_int_add(decVal.bitsnum, 3, &one, 1); 06558 } 06559 decVal.bitsnum[2] = 0; 06560 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff)/sizeof(buff[0])); 06561 06562 if (dwFlags & LOCALE_USE_NLS) 06563 { 06564 WCHAR cybuff[256]; 06565 06566 /* Format the currency for the locale */ 06567 cybuff[0] = '\0'; 06568 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, 06569 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR)); 06570 *pbstrOut = SysAllocString(cybuff); 06571 } 06572 else 06573 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags); 06574 06575 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 06576 } 06577 06578 /****************************************************************************** 06579 * VarBstrFromDate [OLEAUT32.114] 06580 * 06581 * Convert a VT_DATE to a VT_BSTR. 06582 * 06583 * PARAMS 06584 * dateIn [I] Source 06585 * lcid [I] LCID for the conversion 06586 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06587 * pbstrOut [O] Destination 06588 * 06589 * RETURNS 06590 * Success: S_OK. 06591 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid. 06592 * E_OUTOFMEMORY, if memory allocation fails. 06593 */ 06594 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06595 { 06596 SYSTEMTIME st; 06597 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE; 06598 WCHAR date[128], *time; 06599 06600 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut); 06601 06602 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st)) 06603 return E_INVALIDARG; 06604 06605 *pbstrOut = NULL; 06606 06607 if (dwFlags & VAR_CALENDAR_THAI) 06608 st.wYear += 553; /* Use the Thai buddhist calendar year */ 06609 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN)) 06610 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n"); 06611 06612 if (dwFlags & LOCALE_USE_NLS) 06613 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY); 06614 else 06615 { 06616 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn); 06617 double partial = dateIn - whole; 06618 06619 if (whole == 0.0) 06620 dwFlags |= VAR_TIMEVALUEONLY; 06621 else if (partial < 1e-12) 06622 dwFlags |= VAR_DATEVALUEONLY; 06623 } 06624 06625 if (dwFlags & VAR_TIMEVALUEONLY) 06626 date[0] = '\0'; 06627 else 06628 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date, 06629 sizeof(date)/sizeof(WCHAR))) 06630 return E_INVALIDARG; 06631 06632 if (!(dwFlags & VAR_DATEVALUEONLY)) 06633 { 06634 time = date + strlenW(date); 06635 if (time != date) 06636 *time++ = ' '; 06637 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, 06638 sizeof(date)/sizeof(WCHAR)-(time-date))) 06639 return E_INVALIDARG; 06640 } 06641 06642 *pbstrOut = SysAllocString(date); 06643 if (*pbstrOut) 06644 TRACE("returning %s\n", debugstr_w(*pbstrOut)); 06645 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 06646 } 06647 06648 /****************************************************************************** 06649 * VarBstrFromBool (OLEAUT32.116) 06650 * 06651 * Convert a VT_BOOL to a VT_BSTR. 06652 * 06653 * PARAMS 06654 * boolIn [I] Source 06655 * lcid [I] LCID for the conversion 06656 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06657 * pbstrOut [O] Destination 06658 * 06659 * RETURNS 06660 * Success: S_OK. 06661 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06662 * E_OUTOFMEMORY, if memory allocation fails. 06663 * 06664 * NOTES 06665 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the 06666 * localised text of "True" or "False". To convert a bool into a 06667 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx(). 06668 */ 06669 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06670 { 06671 WCHAR szBuff[64]; 06672 DWORD dwResId = IDS_TRUE; 06673 LANGID langId; 06674 06675 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut); 06676 06677 if (!pbstrOut) 06678 return E_INVALIDARG; 06679 06680 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used 06681 * for variant formatting */ 06682 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO)) 06683 { 06684 case VAR_BOOLONOFF: 06685 dwResId = IDS_ON; 06686 break; 06687 case VAR_BOOLYESNO: 06688 dwResId = IDS_YES; 06689 break; 06690 case VAR_LOCALBOOL: 06691 break; 06692 default: 06693 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT); 06694 } 06695 06696 lcid = ConvertDefaultLocale(lcid); 06697 langId = LANGIDFROMLCID(lcid); 06698 if (PRIMARYLANGID(langId) == LANG_NEUTRAL) 06699 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 06700 06701 if (boolIn == VARIANT_FALSE) 06702 dwResId++; /* Use negative form */ 06703 06704 VarBstrFromBool_GetLocalised: 06705 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff)) 06706 { 06707 *pbstrOut = SysAllocString(szBuff); 06708 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 06709 } 06710 06711 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) 06712 { 06713 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 06714 goto VarBstrFromBool_GetLocalised; 06715 } 06716 06717 /* Should never get here */ 06718 WARN("Failed to load bool text!\n"); 06719 return E_OUTOFMEMORY; 06720 } 06721 06722 /****************************************************************************** 06723 * VarBstrFromI1 (OLEAUT32.229) 06724 * 06725 * Convert a VT_I1 to a VT_BSTR. 06726 * 06727 * PARAMS 06728 * cIn [I] Source 06729 * lcid [I] LCID for the conversion 06730 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06731 * pbstrOut [O] Destination 06732 * 06733 * RETURNS 06734 * Success: S_OK. 06735 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06736 * E_OUTOFMEMORY, if memory allocation fails. 06737 */ 06738 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06739 { 06740 ULONG64 ul64 = cIn; 06741 06742 if (cIn < 0) 06743 { 06744 ul64 = -cIn; 06745 dwFlags |= VAR_NEGATIVE; 06746 } 06747 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 06748 } 06749 06750 /****************************************************************************** 06751 * VarBstrFromUI2 (OLEAUT32.230) 06752 * 06753 * Convert a VT_UI2 to a VT_BSTR. 06754 * 06755 * PARAMS 06756 * usIn [I] Source 06757 * lcid [I] LCID for the conversion 06758 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06759 * pbstrOut [O] Destination 06760 * 06761 * RETURNS 06762 * Success: S_OK. 06763 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06764 * E_OUTOFMEMORY, if memory allocation fails. 06765 */ 06766 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06767 { 06768 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut); 06769 } 06770 06771 /****************************************************************************** 06772 * VarBstrFromUI4 (OLEAUT32.231) 06773 * 06774 * Convert a VT_UI4 to a VT_BSTR. 06775 * 06776 * PARAMS 06777 * ulIn [I] Source 06778 * lcid [I] LCID for the conversion 06779 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06780 * pbstrOut [O] Destination 06781 * 06782 * RETURNS 06783 * Success: S_OK. 06784 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06785 * E_OUTOFMEMORY, if memory allocation fails. 06786 */ 06787 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06788 { 06789 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut); 06790 } 06791 06792 /****************************************************************************** 06793 * VarBstrFromDec (OLEAUT32.232) 06794 * 06795 * Convert a VT_DECIMAL to a VT_BSTR. 06796 * 06797 * PARAMS 06798 * pDecIn [I] Source 06799 * lcid [I] LCID for the conversion 06800 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06801 * pbstrOut [O] Destination 06802 * 06803 * RETURNS 06804 * Success: S_OK. 06805 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06806 * E_OUTOFMEMORY, if memory allocation fails. 06807 */ 06808 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06809 { 06810 WCHAR buff[256]; 06811 VARIANT_DI temp; 06812 06813 if (!pbstrOut) 06814 return E_INVALIDARG; 06815 06816 VARIANT_DIFromDec(pDecIn, &temp); 06817 VARIANT_DI_tostringW(&temp, buff, 256); 06818 06819 if (dwFlags & LOCALE_USE_NLS) 06820 { 06821 WCHAR numbuff[256]; 06822 06823 /* Format the number for the locale */ 06824 numbuff[0] = '\0'; 06825 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, 06826 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); 06827 TRACE("created NLS string %s\n", debugstr_w(numbuff)); 06828 *pbstrOut = SysAllocString(numbuff); 06829 } 06830 else 06831 { 06832 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags); 06833 } 06834 06835 TRACE("returning %s\n", debugstr_w(*pbstrOut)); 06836 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 06837 } 06838 06839 /************************************************************************ 06840 * VarBstrFromI8 (OLEAUT32.370) 06841 * 06842 * Convert a VT_I8 to a VT_BSTR. 06843 * 06844 * PARAMS 06845 * llIn [I] Source 06846 * lcid [I] LCID for the conversion 06847 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06848 * pbstrOut [O] Destination 06849 * 06850 * RETURNS 06851 * Success: S_OK. 06852 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06853 * E_OUTOFMEMORY, if memory allocation fails. 06854 */ 06855 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06856 { 06857 ULONG64 ul64 = llIn; 06858 06859 if (llIn < 0) 06860 { 06861 ul64 = -llIn; 06862 dwFlags |= VAR_NEGATIVE; 06863 } 06864 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 06865 } 06866 06867 /************************************************************************ 06868 * VarBstrFromUI8 (OLEAUT32.371) 06869 * 06870 * Convert a VT_UI8 to a VT_BSTR. 06871 * 06872 * PARAMS 06873 * ullIn [I] Source 06874 * lcid [I] LCID for the conversion 06875 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06876 * pbstrOut [O] Destination 06877 * 06878 * RETURNS 06879 * Success: S_OK. 06880 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06881 * E_OUTOFMEMORY, if memory allocation fails. 06882 */ 06883 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06884 { 06885 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut); 06886 } 06887 06888 /************************************************************************ 06889 * VarBstrFromDisp (OLEAUT32.115) 06890 * 06891 * Convert a VT_DISPATCH to a BSTR. 06892 * 06893 * PARAMS 06894 * pdispIn [I] Source 06895 * lcid [I] LCID for conversion 06896 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 06897 * pbstrOut [O] Destination 06898 * 06899 * RETURNS 06900 * Success: S_OK. 06901 * Failure: E_INVALIDARG, if the source value is invalid 06902 * DISP_E_TYPEMISMATCH, if the type cannot be converted 06903 */ 06904 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 06905 { 06906 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags); 06907 } 06908 06909 /********************************************************************** 06910 * VarBstrCat (OLEAUT32.313) 06911 * 06912 * Concatenate two BSTR values. 06913 * 06914 * PARAMS 06915 * pbstrLeft [I] Source 06916 * pbstrRight [I] Value to concatenate 06917 * pbstrOut [O] Destination 06918 * 06919 * RETURNS 06920 * Success: S_OK. 06921 * Failure: E_INVALIDARG, if pbstrOut is invalid. 06922 * E_OUTOFMEMORY, if memory allocation fails. 06923 */ 06924 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut) 06925 { 06926 unsigned int lenLeft, lenRight; 06927 06928 TRACE("%s,%s,%p\n", 06929 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)), 06930 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut); 06931 06932 if (!pbstrOut) 06933 return E_INVALIDARG; 06934 06935 /* use byte length here to properly handle ansi-allocated BSTRs */ 06936 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0; 06937 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0; 06938 06939 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight); 06940 if (!*pbstrOut) 06941 return E_OUTOFMEMORY; 06942 06943 (*pbstrOut)[0] = '\0'; 06944 06945 if (pbstrLeft) 06946 memcpy(*pbstrOut, pbstrLeft, lenLeft); 06947 06948 if (pbstrRight) 06949 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight); 06950 06951 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut))); 06952 return S_OK; 06953 } 06954 06955 /********************************************************************** 06956 * VarBstrCmp (OLEAUT32.314) 06957 * 06958 * Compare two BSTR values. 06959 * 06960 * PARAMS 06961 * pbstrLeft [I] Source 06962 * pbstrRight [I] Value to compare 06963 * lcid [I] LCID for the comparison 06964 * dwFlags [I] Flags to pass directly to CompareStringW(). 06965 * 06966 * RETURNS 06967 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less 06968 * than, equal to or greater than pbstrRight respectively. 06969 * 06970 * NOTES 06971 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN 06972 * states. A NULL BSTR pointer is equivalent to an empty string. 06973 * If LCID is equal to 0, a byte by byte comparison is performed. 06974 */ 06975 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags) 06976 { 06977 HRESULT hres; 06978 int ret; 06979 06980 TRACE("%s,%s,%d,%08x\n", 06981 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)), 06982 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags); 06983 06984 if (!pbstrLeft || !*pbstrLeft) 06985 { 06986 if (pbstrRight && *pbstrRight) 06987 return VARCMP_LT; 06988 } 06989 else if (!pbstrRight || !*pbstrRight) 06990 return VARCMP_GT; 06991 06992 if (lcid == 0) 06993 { 06994 unsigned int lenLeft = SysStringByteLen(pbstrLeft); 06995 unsigned int lenRight = SysStringByteLen(pbstrRight); 06996 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight)); 06997 if (ret < 0) 06998 return VARCMP_LT; 06999 if (ret > 0) 07000 return VARCMP_GT; 07001 if (lenLeft < lenRight) 07002 return VARCMP_LT; 07003 if (lenLeft > lenRight) 07004 return VARCMP_GT; 07005 return VARCMP_EQ; 07006 } 07007 else 07008 { 07009 unsigned int lenLeft = SysStringLen(pbstrLeft); 07010 unsigned int lenRight = SysStringLen(pbstrRight); 07011 07012 if (lenLeft == 0 || lenRight == 0) 07013 { 07014 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ; 07015 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT; 07016 } 07017 07018 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft, 07019 pbstrRight, lenRight) - 1; 07020 TRACE("%d\n", hres); 07021 return hres; 07022 } 07023 } 07024 07025 /* 07026 * DATE 07027 */ 07028 07029 /****************************************************************************** 07030 * VarDateFromUI1 (OLEAUT32.88) 07031 * 07032 * Convert a VT_UI1 to a VT_DATE. 07033 * 07034 * PARAMS 07035 * bIn [I] Source 07036 * pdateOut [O] Destination 07037 * 07038 * RETURNS 07039 * S_OK. 07040 */ 07041 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut) 07042 { 07043 return VarR8FromUI1(bIn, pdateOut); 07044 } 07045 07046 /****************************************************************************** 07047 * VarDateFromI2 (OLEAUT32.89) 07048 * 07049 * Convert a VT_I2 to a VT_DATE. 07050 * 07051 * PARAMS 07052 * sIn [I] Source 07053 * pdateOut [O] Destination 07054 * 07055 * RETURNS 07056 * S_OK. 07057 */ 07058 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut) 07059 { 07060 return VarR8FromI2(sIn, pdateOut); 07061 } 07062 07063 /****************************************************************************** 07064 * VarDateFromI4 (OLEAUT32.90) 07065 * 07066 * Convert a VT_I4 to a VT_DATE. 07067 * 07068 * PARAMS 07069 * lIn [I] Source 07070 * pdateOut [O] Destination 07071 * 07072 * RETURNS 07073 * S_OK. 07074 */ 07075 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut) 07076 { 07077 return VarDateFromR8(lIn, pdateOut); 07078 } 07079 07080 /****************************************************************************** 07081 * VarDateFromR4 (OLEAUT32.91) 07082 * 07083 * Convert a VT_R4 to a VT_DATE. 07084 * 07085 * PARAMS 07086 * fltIn [I] Source 07087 * pdateOut [O] Destination 07088 * 07089 * RETURNS 07090 * S_OK. 07091 */ 07092 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut) 07093 { 07094 return VarR8FromR4(fltIn, pdateOut); 07095 } 07096 07097 /****************************************************************************** 07098 * VarDateFromR8 (OLEAUT32.92) 07099 * 07100 * Convert a VT_R8 to a VT_DATE. 07101 * 07102 * PARAMS 07103 * dblIn [I] Source 07104 * pdateOut [O] Destination 07105 * 07106 * RETURNS 07107 * S_OK. 07108 */ 07109 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut) 07110 { 07111 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW; 07112 *pdateOut = (DATE)dblIn; 07113 return S_OK; 07114 } 07115 07116 /********************************************************************** 07117 * VarDateFromDisp (OLEAUT32.95) 07118 * 07119 * Convert a VT_DISPATCH to a VT_DATE. 07120 * 07121 * PARAMS 07122 * pdispIn [I] Source 07123 * lcid [I] LCID for conversion 07124 * pdateOut [O] Destination 07125 * 07126 * RETURNS 07127 * Success: S_OK. 07128 * Failure: E_INVALIDARG, if the source value is invalid 07129 * DISP_E_OVERFLOW, if the value will not fit in the destination 07130 * DISP_E_TYPEMISMATCH, if the type cannot be converted 07131 */ 07132 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut) 07133 { 07134 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0); 07135 } 07136 07137 /****************************************************************************** 07138 * VarDateFromBool (OLEAUT32.96) 07139 * 07140 * Convert a VT_BOOL to a VT_DATE. 07141 * 07142 * PARAMS 07143 * boolIn [I] Source 07144 * pdateOut [O] Destination 07145 * 07146 * RETURNS 07147 * S_OK. 07148 */ 07149 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut) 07150 { 07151 return VarR8FromBool(boolIn, pdateOut); 07152 } 07153 07154 /********************************************************************** 07155 * VarDateFromCy (OLEAUT32.93) 07156 * 07157 * Convert a VT_CY to a VT_DATE. 07158 * 07159 * PARAMS 07160 * lIn [I] Source 07161 * pdateOut [O] Destination 07162 * 07163 * RETURNS 07164 * S_OK. 07165 */ 07166 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) 07167 { 07168 return VarR8FromCy(cyIn, pdateOut); 07169 } 07170 07171 /* Date string parsing */ 07172 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */ 07173 #define DP_DATESEP 0x02 /* Date separator */ 07174 #define DP_MONTH 0x04 /* Month name */ 07175 #define DP_AM 0x08 /* AM */ 07176 #define DP_PM 0x10 /* PM */ 07177 07178 typedef struct tagDATEPARSE 07179 { 07180 DWORD dwCount; /* Number of fields found so far (maximum 6) */ 07181 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */ 07182 DWORD dwFlags[6]; /* Flags for each field */ 07183 DWORD dwValues[6]; /* Value of each field */ 07184 } DATEPARSE; 07185 07186 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i) 07187 07188 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) 07189 07190 /* Determine if a day is valid in a given month of a given year */ 07191 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year) 07192 { 07193 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 07194 07195 if (day && month && month < 13) 07196 { 07197 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year))) 07198 return TRUE; 07199 } 07200 return FALSE; 07201 } 07202 07203 /* Possible orders for 3 numbers making up a date */ 07204 #define ORDER_MDY 0x01 07205 #define ORDER_YMD 0x02 07206 #define ORDER_YDM 0x04 07207 #define ORDER_DMY 0x08 07208 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */ 07209 07210 /* Determine a date for a particular locale, from 3 numbers */ 07211 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate, 07212 DWORD offset, SYSTEMTIME *st) 07213 { 07214 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3; 07215 07216 if (!dp->dwCount) 07217 { 07218 v1 = 30; /* Default to (Variant) 0 date part */ 07219 v2 = 12; 07220 v3 = 1899; 07221 goto VARIANT_MakeDate_OK; 07222 } 07223 07224 v1 = dp->dwValues[offset + 0]; 07225 v2 = dp->dwValues[offset + 1]; 07226 if (dp->dwCount == 2) 07227 { 07228 SYSTEMTIME current; 07229 GetSystemTime(¤t); 07230 v3 = current.wYear; 07231 } 07232 else 07233 v3 = dp->dwValues[offset + 2]; 07234 07235 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset); 07236 07237 /* If one number must be a month (Because a month name was given), then only 07238 * consider orders with the month in that position. 07239 * If we took the current year as 'v3', then only allow a year in that position. 07240 */ 07241 if (dp->dwFlags[offset + 0] & DP_MONTH) 07242 { 07243 dwAllOrders = ORDER_MDY; 07244 } 07245 else if (dp->dwFlags[offset + 1] & DP_MONTH) 07246 { 07247 dwAllOrders = ORDER_DMY; 07248 if (dp->dwCount > 2) 07249 dwAllOrders |= ORDER_YMD; 07250 } 07251 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH) 07252 { 07253 dwAllOrders = ORDER_YDM; 07254 } 07255 else 07256 { 07257 dwAllOrders = ORDER_MDY|ORDER_DMY; 07258 if (dp->dwCount > 2) 07259 dwAllOrders |= (ORDER_YMD|ORDER_YDM); 07260 } 07261 07262 VARIANT_MakeDate_Start: 07263 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders); 07264 07265 while (dwAllOrders) 07266 { 07267 DWORD dwTemp; 07268 07269 if (dwCount == 0) 07270 { 07271 /* First: Try the order given by iDate */ 07272 switch (iDate) 07273 { 07274 case 0: dwTry = dwAllOrders & ORDER_MDY; break; 07275 case 1: dwTry = dwAllOrders & ORDER_DMY; break; 07276 default: dwTry = dwAllOrders & ORDER_YMD; break; 07277 } 07278 } 07279 else if (dwCount == 1) 07280 { 07281 /* Second: Try all the orders compatible with iDate */ 07282 switch (iDate) 07283 { 07284 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; 07285 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break; 07286 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; 07287 } 07288 } 07289 else 07290 { 07291 /* Finally: Try any remaining orders */ 07292 dwTry = dwAllOrders; 07293 } 07294 07295 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry); 07296 07297 dwCount++; 07298 if (!dwTry) 07299 continue; 07300 07301 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0) 07302 07303 if (dwTry & ORDER_MDY) 07304 { 07305 if (VARIANT_IsValidMonthDay(v2,v1,v3)) 07306 { 07307 DATE_SWAP(v1,v2); 07308 goto VARIANT_MakeDate_OK; 07309 } 07310 dwAllOrders &= ~ORDER_MDY; 07311 } 07312 if (dwTry & ORDER_YMD) 07313 { 07314 if (VARIANT_IsValidMonthDay(v3,v2,v1)) 07315 { 07316 DATE_SWAP(v1,v3); 07317 goto VARIANT_MakeDate_OK; 07318 } 07319 dwAllOrders &= ~ORDER_YMD; 07320 } 07321 if (dwTry & ORDER_YDM) 07322 { 07323 if (VARIANT_IsValidMonthDay(v2,v3,v1)) 07324 { 07325 DATE_SWAP(v1,v2); 07326 DATE_SWAP(v2,v3); 07327 goto VARIANT_MakeDate_OK; 07328 } 07329 dwAllOrders &= ~ORDER_YDM; 07330 } 07331 if (dwTry & ORDER_DMY) 07332 { 07333 if (VARIANT_IsValidMonthDay(v1,v2,v3)) 07334 goto VARIANT_MakeDate_OK; 07335 dwAllOrders &= ~ORDER_DMY; 07336 } 07337 if (dwTry & ORDER_MYD) 07338 { 07339 /* Only occurs if we are trying a 2 year date as M/Y not D/M */ 07340 if (VARIANT_IsValidMonthDay(v3,v1,v2)) 07341 { 07342 DATE_SWAP(v1,v3); 07343 DATE_SWAP(v2,v3); 07344 goto VARIANT_MakeDate_OK; 07345 } 07346 dwAllOrders &= ~ORDER_MYD; 07347 } 07348 } 07349 07350 if (dp->dwCount == 2) 07351 { 07352 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */ 07353 v3 = 1; /* 1st of the month */ 07354 dwAllOrders = ORDER_YMD|ORDER_MYD; 07355 dp->dwCount = 0; /* Don't return to this code path again */ 07356 dwCount = 0; 07357 goto VARIANT_MakeDate_Start; 07358 } 07359 07360 /* No valid dates were able to be constructed */ 07361 return DISP_E_TYPEMISMATCH; 07362 07363 VARIANT_MakeDate_OK: 07364 07365 /* Check that the time part is ok */ 07366 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59) 07367 return DISP_E_TYPEMISMATCH; 07368 07369 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); 07370 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM)) 07371 st->wHour += 12; 07372 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM)) 07373 st->wHour = 0; 07374 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); 07375 07376 st->wDay = v1; 07377 st->wMonth = v2; 07378 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may 07379 * be retrieved from: 07380 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax 07381 * But Wine doesn't have/use that key as at the time of writing. 07382 */ 07383 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3; 07384 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear); 07385 return S_OK; 07386 } 07387 07388 /****************************************************************************** 07389 * VarDateFromStr [OLEAUT32.94] 07390 * 07391 * Convert a VT_BSTR to at VT_DATE. 07392 * 07393 * PARAMS 07394 * strIn [I] String to convert 07395 * lcid [I] Locale identifier for the conversion 07396 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h") 07397 * pdateOut [O] Destination for the converted value 07398 * 07399 * RETURNS 07400 * Success: S_OK. pdateOut contains the converted value. 07401 * FAILURE: An HRESULT error code indicating the problem. 07402 * 07403 * NOTES 07404 * Any date format that can be created using the date formats from lcid 07405 * (Either from kernel Nls functions, variant conversion or formatting) is a 07406 * valid input to this function. In addition, a few more esoteric formats are 07407 * also supported for compatibility with the native version. The date is 07408 * interpreted according to the date settings in the control panel, unless 07409 * the date is invalid in that format, in which the most compatible format 07410 * that produces a valid date will be used. 07411 */ 07412 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut) 07413 { 07414 static const USHORT ParseDateTokens[] = 07415 { 07416 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, 07417 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, 07418 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, 07419 LOCALE_SMONTHNAME13, 07420 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, 07421 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, 07422 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, 07423 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, 07424 LOCALE_SABBREVMONTHNAME13, 07425 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, 07426 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, 07427 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, 07428 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, 07429 LOCALE_SABBREVDAYNAME7, 07430 LOCALE_S1159, LOCALE_S2359, 07431 LOCALE_SDATE 07432 }; 07433 static const BYTE ParseDateMonths[] = 07434 { 07435 1,2,3,4,5,6,7,8,9,10,11,12,13, 07436 1,2,3,4,5,6,7,8,9,10,11,12,13 07437 }; 07438 unsigned int i; 07439 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])]; 07440 DATEPARSE dp; 07441 DWORD dwDateSeps = 0, iDate = 0; 07442 HRESULT hRet = S_OK; 07443 07444 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) == 07445 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) 07446 return E_INVALIDARG; 07447 07448 if (!strIn) 07449 return DISP_E_TYPEMISMATCH; 07450 07451 *pdateOut = 0.0; 07452 07453 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut); 07454 07455 memset(&dp, 0, sizeof(dp)); 07456 07457 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE), 07458 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR)); 07459 TRACE("iDate is %d\n", iDate); 07460 07461 /* Get the month/day/am/pm tokens for this locale */ 07462 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) 07463 { 07464 WCHAR buff[128]; 07465 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE); 07466 07467 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or 07468 * GetAltMonthNames(). We should really cache these strings too. 07469 */ 07470 buff[0] = '\0'; 07471 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR)); 07472 tokens[i] = SysAllocString(buff); 07473 TRACE("token %d is %s\n", i, debugstr_w(tokens[i])); 07474 } 07475 07476 /* Parse the string into our structure */ 07477 while (*strIn) 07478 { 07479 if (dp.dwCount >= 6) 07480 break; 07481 07482 if (isdigitW(*strIn)) 07483 { 07484 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10); 07485 dp.dwCount++; 07486 strIn--; 07487 } 07488 else if (isalpha(*strIn)) 07489 { 07490 BOOL bFound = FALSE; 07491 07492 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) 07493 { 07494 DWORD dwLen = strlenW(tokens[i]); 07495 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen)) 07496 { 07497 if (i <= 25) 07498 { 07499 dp.dwValues[dp.dwCount] = ParseDateMonths[i]; 07500 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP); 07501 dp.dwCount++; 07502 } 07503 else if (i > 39 && i < 42) 07504 { 07505 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM)) 07506 hRet = DISP_E_TYPEMISMATCH; 07507 else 07508 { 07509 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM); 07510 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM); 07511 } 07512 } 07513 strIn += (dwLen - 1); 07514 bFound = TRUE; 07515 break; 07516 } 07517 } 07518 07519 if (!bFound) 07520 { 07521 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') && 07522 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM)))) 07523 { 07524 /* Special case - 'a' and 'p' are recognised as short for am/pm */ 07525 if (*strIn == 'a' || *strIn == 'A') 07526 { 07527 dp.dwFlags[dp.dwCount - 1] |= DP_AM; 07528 dp.dwParseFlags |= DP_AM; 07529 } 07530 else 07531 { 07532 dp.dwFlags[dp.dwCount - 1] |= DP_PM; 07533 dp.dwParseFlags |= DP_PM; 07534 } 07535 strIn++; 07536 } 07537 else 07538 { 07539 TRACE("No matching token for %s\n", debugstr_w(strIn)); 07540 hRet = DISP_E_TYPEMISMATCH; 07541 break; 07542 } 07543 } 07544 } 07545 else if (*strIn == ':' || *strIn == '.') 07546 { 07547 if (!dp.dwCount || !strIn[1]) 07548 hRet = DISP_E_TYPEMISMATCH; 07549 else 07550 if (tokens[42][0] == *strIn) 07551 { 07552 dwDateSeps++; 07553 if (dwDateSeps > 2) 07554 hRet = DISP_E_TYPEMISMATCH; 07555 else 07556 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP; 07557 } 07558 else 07559 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP; 07560 } 07561 else if (*strIn == '-' || *strIn == '/') 07562 { 07563 dwDateSeps++; 07564 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1]) 07565 hRet = DISP_E_TYPEMISMATCH; 07566 else 07567 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP; 07568 } 07569 else if (*strIn == ',' || isspaceW(*strIn)) 07570 { 07571 if (*strIn == ',' && !strIn[1]) 07572 hRet = DISP_E_TYPEMISMATCH; 07573 } 07574 else 07575 { 07576 hRet = DISP_E_TYPEMISMATCH; 07577 } 07578 strIn++; 07579 } 07580 07581 if (!dp.dwCount || dp.dwCount > 6 || 07582 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM)))) 07583 hRet = DISP_E_TYPEMISMATCH; 07584 07585 if (SUCCEEDED(hRet)) 07586 { 07587 SYSTEMTIME st; 07588 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */ 07589 07590 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; 07591 07592 /* Figure out which numbers correspond to which fields. 07593 * 07594 * This switch statement works based on the fact that native interprets any 07595 * fields that are not joined with a time separator ('.' or ':') as date 07596 * fields. Thus we construct a value from 0-32 where each set bit indicates 07597 * a time field. This encapsulates the hundreds of permutations of 2-6 fields. 07598 * For valid permutations, we set dwOffset to point to the first date field 07599 * and shorten dp.dwCount by the number of time fields found. The real 07600 * magic here occurs in VARIANT_MakeDate() above, where we determine what 07601 * each date number must represent in the context of iDate. 07602 */ 07603 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)); 07604 07605 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)) 07606 { 07607 case 0x1: /* TT TTDD TTDDD */ 07608 if (dp.dwCount > 3 && 07609 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) || 07610 (dp.dwFlags[4] & (DP_AM|DP_PM)))) 07611 hRet = DISP_E_TYPEMISMATCH; 07612 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5) 07613 hRet = DISP_E_TYPEMISMATCH; 07614 st.wHour = dp.dwValues[0]; 07615 st.wMinute = dp.dwValues[1]; 07616 dp.dwCount -= 2; 07617 dwOffset = 2; 07618 break; 07619 07620 case 0x3: /* TTT TTTDD TTTDDD */ 07621 if (dp.dwCount > 4 && 07622 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) || 07623 (dp.dwFlags[5] & (DP_AM|DP_PM)))) 07624 hRet = DISP_E_TYPEMISMATCH; 07625 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6) 07626 hRet = DISP_E_TYPEMISMATCH; 07627 st.wHour = dp.dwValues[0]; 07628 st.wMinute = dp.dwValues[1]; 07629 st.wSecond = dp.dwValues[2]; 07630 dwOffset = 3; 07631 dp.dwCount -= 3; 07632 break; 07633 07634 case 0x4: /* DDTT */ 07635 if (dp.dwCount != 4 || 07636 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) 07637 hRet = DISP_E_TYPEMISMATCH; 07638 07639 st.wHour = dp.dwValues[2]; 07640 st.wMinute = dp.dwValues[3]; 07641 dp.dwCount -= 2; 07642 break; 07643 07644 case 0x0: /* T DD DDD TDDD TDDD */ 07645 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM))) 07646 { 07647 st.wHour = dp.dwValues[0]; /* T */ 07648 dp.dwCount = 0; 07649 break; 07650 } 07651 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM))) 07652 { 07653 hRet = DISP_E_TYPEMISMATCH; 07654 } 07655 else if (dp.dwCount == 3) 07656 { 07657 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */ 07658 { 07659 dp.dwCount = 2; 07660 st.wHour = dp.dwValues[0]; 07661 dwOffset = 1; 07662 break; 07663 } 07664 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */ 07665 { 07666 dp.dwCount = 2; 07667 st.wHour = dp.dwValues[2]; 07668 break; 07669 } 07670 else if (dp.dwParseFlags & (DP_AM|DP_PM)) 07671 hRet = DISP_E_TYPEMISMATCH; 07672 } 07673 else if (dp.dwCount == 4) 07674 { 07675 dp.dwCount = 3; 07676 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */ 07677 { 07678 st.wHour = dp.dwValues[0]; 07679 dwOffset = 1; 07680 } 07681 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */ 07682 { 07683 st.wHour = dp.dwValues[3]; 07684 } 07685 else 07686 hRet = DISP_E_TYPEMISMATCH; 07687 break; 07688 } 07689 /* .. fall through .. */ 07690 07691 case 0x8: /* DDDTT */ 07692 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) || 07693 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) || 07694 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) || 07695 dp.dwCount == 4 || dp.dwCount == 6) 07696 hRet = DISP_E_TYPEMISMATCH; 07697 st.wHour = dp.dwValues[3]; 07698 st.wMinute = dp.dwValues[4]; 07699 if (dp.dwCount == 5) 07700 dp.dwCount -= 2; 07701 break; 07702 07703 case 0xC: /* DDTTT */ 07704 if (dp.dwCount != 5 || 07705 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) 07706 hRet = DISP_E_TYPEMISMATCH; 07707 st.wHour = dp.dwValues[2]; 07708 st.wMinute = dp.dwValues[3]; 07709 st.wSecond = dp.dwValues[4]; 07710 dp.dwCount -= 3; 07711 break; 07712 07713 case 0x18: /* DDDTTT */ 07714 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) || 07715 (dp.dwFlags[2] & (DP_AM|DP_PM))) 07716 hRet = DISP_E_TYPEMISMATCH; 07717 st.wHour = dp.dwValues[3]; 07718 st.wMinute = dp.dwValues[4]; 07719 st.wSecond = dp.dwValues[5]; 07720 dp.dwCount -= 3; 07721 break; 07722 07723 default: 07724 hRet = DISP_E_TYPEMISMATCH; 07725 break; 07726 } 07727 07728 if (SUCCEEDED(hRet)) 07729 { 07730 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st); 07731 07732 if (dwFlags & VAR_TIMEVALUEONLY) 07733 { 07734 st.wYear = 1899; 07735 st.wMonth = 12; 07736 st.wDay = 30; 07737 } 07738 else if (dwFlags & VAR_DATEVALUEONLY) 07739 st.wHour = st.wMinute = st.wSecond = 0; 07740 07741 /* Finally, convert the value to a VT_DATE */ 07742 if (SUCCEEDED(hRet)) 07743 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH; 07744 } 07745 } 07746 07747 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) 07748 SysFreeString(tokens[i]); 07749 return hRet; 07750 } 07751 07752 /****************************************************************************** 07753 * VarDateFromI1 (OLEAUT32.221) 07754 * 07755 * Convert a VT_I1 to a VT_DATE. 07756 * 07757 * PARAMS 07758 * cIn [I] Source 07759 * pdateOut [O] Destination 07760 * 07761 * RETURNS 07762 * S_OK. 07763 */ 07764 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut) 07765 { 07766 return VarR8FromI1(cIn, pdateOut); 07767 } 07768 07769 /****************************************************************************** 07770 * VarDateFromUI2 (OLEAUT32.222) 07771 * 07772 * Convert a VT_UI2 to a VT_DATE. 07773 * 07774 * PARAMS 07775 * uiIn [I] Source 07776 * pdateOut [O] Destination 07777 * 07778 * RETURNS 07779 * S_OK. 07780 */ 07781 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut) 07782 { 07783 return VarR8FromUI2(uiIn, pdateOut); 07784 } 07785 07786 /****************************************************************************** 07787 * VarDateFromUI4 (OLEAUT32.223) 07788 * 07789 * Convert a VT_UI4 to a VT_DATE. 07790 * 07791 * PARAMS 07792 * ulIn [I] Source 07793 * pdateOut [O] Destination 07794 * 07795 * RETURNS 07796 * S_OK. 07797 */ 07798 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut) 07799 { 07800 return VarDateFromR8(ulIn, pdateOut); 07801 } 07802 07803 /********************************************************************** 07804 * VarDateFromDec (OLEAUT32.224) 07805 * 07806 * Convert a VT_DECIMAL to a VT_DATE. 07807 * 07808 * PARAMS 07809 * pdecIn [I] Source 07810 * pdateOut [O] Destination 07811 * 07812 * RETURNS 07813 * S_OK. 07814 */ 07815 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut) 07816 { 07817 return VarR8FromDec(pdecIn, pdateOut); 07818 } 07819 07820 /****************************************************************************** 07821 * VarDateFromI8 (OLEAUT32.364) 07822 * 07823 * Convert a VT_I8 to a VT_DATE. 07824 * 07825 * PARAMS 07826 * llIn [I] Source 07827 * pdateOut [O] Destination 07828 * 07829 * RETURNS 07830 * Success: S_OK. 07831 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 07832 */ 07833 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut) 07834 { 07835 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW; 07836 *pdateOut = (DATE)llIn; 07837 return S_OK; 07838 } 07839 07840 /****************************************************************************** 07841 * VarDateFromUI8 (OLEAUT32.365) 07842 * 07843 * Convert a VT_UI8 to a VT_DATE. 07844 * 07845 * PARAMS 07846 * ullIn [I] Source 07847 * pdateOut [O] Destination 07848 * 07849 * RETURNS 07850 * Success: S_OK. 07851 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 07852 */ 07853 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut) 07854 { 07855 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW; 07856 *pdateOut = (DATE)ullIn; 07857 return S_OK; 07858 } Generated on Sat May 26 2012 04:24:26 for ReactOS by
1.7.6.1
|