⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 variant.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
      {
        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 + -