📄 variant.c
字号:
{
if (V_UNKNOWN(pvargSrc))
IUnknown_AddRef(V_UNKNOWN(pvargSrc));
}
}
}
return hres;
}
/* Return the byte size of a variants data */
static inline size_t VARIANT_DataSize(const VARIANT* pv)
{
switch (V_TYPE(pv))
{
case VT_I1:
case VT_UI1: return sizeof(BYTE);
case VT_I2:
case VT_UI2: return sizeof(SHORT);
case VT_INT:
case VT_UINT:
case VT_I4:
case VT_UI4: return sizeof(LONG);
case VT_I8:
case VT_UI8: return sizeof(LONGLONG);
case VT_R4: return sizeof(float);
case VT_R8: return sizeof(double);
case VT_DATE: return sizeof(DATE);
case VT_BOOL: return sizeof(VARIANT_BOOL);
case VT_DISPATCH:
case VT_UNKNOWN:
case VT_BSTR: return sizeof(void*);
case VT_CY: return sizeof(CY);
case VT_ERROR: return sizeof(SCODE);
}
TRACE("Shouldn't be called for vt %s%s!\n", debugstr_VT(pv), debugstr_VF(pv));
return 0;
}
/******************************************************************************
* VariantCopyInd [OLEAUT32.11]
*
* Copy a variant, dereferencing it if it is by-reference.
*
* PARAMS
* pvargDest [O] Destination for copy
* pvargSrc [I] Source variant to copy
*
* RETURNS
* Success: S_OK. pvargDest contains a copy of pvargSrc.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* Failure: DISP_E_BADVARTYPE, if either variant has an invalid by-value type.
* E_INVALIDARG, if pvargSrc is an invalid by-reference type.
* E_OUTOFMEMORY, if memory cannot be allocated. Otherwise an
* HRESULT error code from SafeArrayCopy(), IRecordInfo_GetSize(),
* or IRecordInfo_RecordCopy(), depending on the type of pvargSrc.
*
* NOTES
* - If pvargSrc is by-value, this function behaves exactly as VariantCopy().
* - If pvargSrc is by-reference, the value copied to pvargDest is the pointed-to
* value.
* - if pvargSrc == pvargDest, this function dereferences in place. Otherwise,
* pvargDest is always cleared using VariantClear() before pvargSrc is copied
* to it. If clearing pvargDest fails, so does this function.
*/
HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
{
VARIANTARG vTmp, *pSrc = pvargSrc;
VARTYPE vt;
HRESULT hres = S_OK;
TRACE("(%p->(%s%s),%p->(%s%s))\n", pvargDest, debugstr_VT(pvargDest),
debugstr_VF(pvargDest), pvargSrc, debugstr_VT(pvargSrc),
debugstr_VF(pvargSrc));
if (!V_ISBYREF(pvargSrc))
return VariantCopy(pvargDest, pvargSrc);
/* Argument checking is more lax than VariantCopy()... */
vt = V_TYPE(pvargSrc);
if (V_ISARRAY(pvargSrc) ||
(vt > VT_NULL && vt != (VARTYPE)15 && vt < VT_VOID &&
!(V_VT(pvargSrc) & (VT_VECTOR|VT_RESERVED))))
{
/* OK */
}
else
return E_INVALIDARG; /* ...And the return value for invalid types differs too */
if (pvargSrc == pvargDest)
{
/* In place copy. Use a shallow copy of pvargSrc & init pvargDest.
* This avoids an expensive VariantCopy() call - e.g. SafeArrayCopy().
*/
vTmp = *pvargSrc;
pSrc = &vTmp;
V_VT(pvargDest) = VT_EMPTY;
}
else
{
/* Copy into another variant. Free the variant in pvargDest */
if (FAILED(hres = VariantClear(pvargDest)))
{
TRACE("VariantClear() of destination failed\n");
return hres;
}
}
if (V_ISARRAY(pSrc))
{
/* Native doesn't check that *V_ARRAYREF(pSrc) is valid */
hres = SafeArrayCopy(*V_ARRAYREF(pSrc), &V_ARRAY(pvargDest));
}
else if (V_VT(pSrc) == (VT_BSTR|VT_BYREF))
{
/* Native doesn't check that *V_BSTRREF(pSrc) is valid */
V_BSTR(pvargDest) = SysAllocStringByteLen((char*)*V_BSTRREF(pSrc), SysStringByteLen(*V_BSTRREF(pSrc)));
}
else if (V_VT(pSrc) == (VT_RECORD|VT_BYREF))
{
V_UNION(pvargDest,brecVal) = V_UNION(pvargSrc,brecVal);
hres = VARIANT_CopyIRecordInfo(&V_UNION(pvargDest,brecVal));
}
else if (V_VT(pSrc) == (VT_DISPATCH|VT_BYREF) ||
V_VT(pSrc) == (VT_UNKNOWN|VT_BYREF))
{
/* Native doesn't check that *V_UNKNOWNREF(pSrc) is valid */
V_UNKNOWN(pvargDest) = *V_UNKNOWNREF(pSrc);
if (*V_UNKNOWNREF(pSrc))
IUnknown_AddRef(*V_UNKNOWNREF(pSrc));
}
else if (V_VT(pSrc) == (VT_VARIANT|VT_BYREF))
{
/* Native doesn't check that *V_VARIANTREF(pSrc) is valid */
if (V_VT(V_VARIANTREF(pSrc)) == (VT_VARIANT|VT_BYREF))
hres = E_INVALIDARG; /* Don't dereference more than one level */
else
hres = VariantCopyInd(pvargDest, V_VARIANTREF(pSrc));
/* Use the dereferenced variants type value, not VT_VARIANT */
goto VariantCopyInd_Return;
}
else if (V_VT(pSrc) == (VT_DECIMAL|VT_BYREF))
{
memcpy(&DEC_SCALE(&V_DECIMAL(pvargDest)), &DEC_SCALE(V_DECIMALREF(pSrc)),
sizeof(DECIMAL) - sizeof(USHORT));
}
else
{
/* Copy the pointed to data into this variant */
memcpy(&V_BYREF(pvargDest), V_BYREF(pSrc), VARIANT_DataSize(pSrc));
}
V_VT(pvargDest) = V_VT(pSrc) & ~VT_BYREF;
VariantCopyInd_Return:
if (pSrc != pvargSrc)
VariantClear(pSrc);
TRACE("returning 0x%08x, %p->(%s%s)\n", hres, pvargDest,
debugstr_VT(pvargDest), debugstr_VF(pvargDest));
return hres;
}
/******************************************************************************
* VariantChangeType [OLEAUT32.12]
*
* Change the type of a variant.
*
* PARAMS
* pvargDest [O] Destination for the converted variant
* pvargSrc [O] Source variant to change the type of
* wFlags [I] VARIANT_ flags from "oleauto.h"
* vt [I] Variant type to change pvargSrc into
*
* RETURNS
* Success: S_OK. pvargDest contains the converted value.
* Failure: An HRESULT error code describing the failure.
*
* NOTES
* The LCID used for the conversion is LOCALE_USER_DEFAULT.
* See VariantChangeTypeEx.
*/
HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
USHORT wFlags, VARTYPE vt)
{
return VariantChangeTypeEx( pvargDest, pvargSrc, LOCALE_USER_DEFAULT, wFlags, vt );
}
/******************************************************************************
* VariantChangeTypeEx [OLEAUT32.147]
*
* Change the type of a variant.
*
* PARAMS
* pvargDest [O] Destination for the converted variant
* pvargSrc [O] Source variant to change the type of
* lcid [I] LCID for the conversion
* wFlags [I] VARIANT_ flags from "oleauto.h"
* vt [I] Variant type to change pvargSrc into
*
* RETURNS
* Success: S_OK. pvargDest contains the converted value.
* Failure: An HRESULT error code describing the failure.
*
* NOTES
* pvargDest and pvargSrc can point to the same variant to perform an in-place
* conversion. If the conversion is successful, pvargSrc will be freed.
*/
HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
LCID lcid, USHORT wFlags, VARTYPE vt)
{
HRESULT res = S_OK;
TRACE("(%p->(%s%s),%p->(%s%s),0x%08x,0x%04x,%s%s)\n", pvargDest,
debugstr_VT(pvargDest), debugstr_VF(pvargDest), pvargSrc,
debugstr_VT(pvargSrc), debugstr_VF(pvargSrc), lcid, wFlags,
debugstr_vt(vt), debugstr_vf(vt));
if (vt == VT_CLSID)
res = DISP_E_BADVARTYPE;
else
{
res = VARIANT_ValidateType(V_VT(pvargSrc));
if (SUCCEEDED(res))
{
res = VARIANT_ValidateType(vt);
if (SUCCEEDED(res))
{
VARIANTARG vTmp, vSrcDeref;
if(V_ISBYREF(pvargSrc) && !V_BYREF(pvargSrc))
res = DISP_E_TYPEMISMATCH;
else
{
V_VT(&vTmp) = VT_EMPTY;
V_VT(&vSrcDeref) = VT_EMPTY;
VariantClear(&vTmp);
VariantClear(&vSrcDeref);
}
if (SUCCEEDED(res))
{
res = VariantCopyInd(&vSrcDeref, pvargSrc);
if (SUCCEEDED(res))
{
if (V_ISARRAY(&vSrcDeref) || (vt & VT_ARRAY))
res = VARIANT_CoerceArray(&vTmp, &vSrcDeref, vt);
else
res = VARIANT_Coerce(&vTmp, lcid, wFlags, &vSrcDeref, vt);
if (SUCCEEDED(res)) {
V_VT(&vTmp) = vt;
VariantCopy(pvargDest, &vTmp);
}
VariantClear(&vTmp);
VariantClear(&vSrcDeref);
}
}
}
}
}
TRACE("returning 0x%08x, %p->(%s%s)\n", res, pvargDest,
debugstr_VT(pvargDest), debugstr_VF(pvargDest));
return res;
}
/* Date Conversions */
#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
/* Convert a VT_DATE value to a Julian Date */
static inline int VARIANT_JulianFromDate(int dateIn)
{
int julianDays = dateIn;
julianDays -= DATE_MIN; /* Convert to + days from 1 Jan 100 AD */
julianDays += 1757585; /* Convert to + days from 23 Nov 4713 BC (Julian) */
return julianDays;
}
/* Convert a Julian Date to a VT_DATE value */
static inline int VARIANT_DateFromJulian(int dateIn)
{
int julianDays = dateIn;
julianDays -= 1757585; /* Convert to + days from 1 Jan 100 AD */
julianDays += DATE_MIN; /* Convert to +/- days from 1 Jan 1899 AD */
return julianDays;
}
/* Convert a Julian date to Day/Month/Year - from PostgreSQL */
static inline void VARIANT_DMYFromJulian(int jd, USHORT *year, USHORT *month, USHORT *day)
{
int j, i, l, n;
l = jd + 68569;
n = l * 4 / 146097;
l -= (n * 146097 + 3) / 4;
i = (4000 * (l + 1)) / 1461001;
l += 31 - (i * 1461) / 4;
j = (l * 80) / 2447;
*day = l - (j * 2447) / 80;
l = j / 11;
*month = (j + 2) - (12 * l);
*year = 100 * (n - 49) + i + l;
}
/* Convert Day/Month/Year to a Julian date - from PostgreSQL */
static inline double VARIANT_JulianFromDMY(USHORT year, USHORT month, USHORT day)
{
int m12 = (month - 14) / 12;
return ((1461 * (year + 4800 + m12)) / 4 + (367 * (month - 2 - 12 * m12)) / 12 -
(3 * ((year + 4900 + m12) / 100)) / 4 + day - 32075);
}
/* Macros for accessing DOS format date/time fields */
#define DOS_YEAR(x) (1980 + (x >> 9))
#define DOS_MONTH(x) ((x >> 5) & 0xf)
#define DOS_DAY(x) (x & 0x1f)
#define DOS_HOUR(x) (x >> 11)
#define DOS_MINUTE(x) ((x >> 5) & 0x3f)
#define DOS_SECOND(x) ((x & 0x1f) << 1)
/* Create a DOS format date/time */
#define DOS_DATE(d,m,y) (d | (m << 5) | ((y-1980) << 9))
#define DOS_TIME(h,m,s) ((s >> 1) | (m << 5) | (h << 11))
/* Roll a date forwards or backwards to correct it */
static HRESULT VARIANT_RollUdate(UDATE *lpUd)
{
static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
TRACE("Raw date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth,
lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond);
/* Years < 100 are treated as 1900 + year */
if (lpUd->st.wYear < 100)
lpUd->st.wYear += 1900;
if (!lpUd->st.wMonth)
{
/* Roll back to December of the previous year */
lpUd->st.wMonth = 12;
lpUd->st.wYear--;
}
else while (lpUd->st.wMonth > 12)
{
/* Roll forward the correct number of months */
lpUd->st.wYear++;
lpUd->st.wMonth -= 12;
}
if (lpUd->st.wYear > 9999 || lpUd->st.wHour > 23 ||
lpUd->st.wMinute > 59 || lpUd->st.wSecond > 59)
return E_INVALIDARG; /* Invalid values */
if (!lpUd->st.wDay)
{
/* Roll back the date one day */
if (lpUd->st.wMonth == 1)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -