Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1316 lines
32 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright (c) 2000 Microsoft Corporation
  4. //
  5. // DATETIME.CPP
  6. //
  7. // alanbos 20-Jan-00 Created.
  8. //
  9. // Defines the implementation of ISWbemDateTime
  10. //
  11. //***************************************************************************
  12. #include <sys/timeb.h>
  13. #include <math.h>
  14. #include <time.h>
  15. #include <float.h>
  16. #include "precomp.h"
  17. #ifdef UTILLIB
  18. #include <assertbreak.h>
  19. #else
  20. #define ASSERT_BREAK(a)
  21. #endif //UTILLIB
  22. #define ISWILD(c) (L'*' == c)
  23. #define ISINTERVAL(c) (L':' == c)
  24. #define ISMINUS(c) (L'-' == c)
  25. #define ISPLUS(c) (L'+' == c)
  26. #define ISDOT(c) (L'.' == c)
  27. #define WILD2 L"**"
  28. #define WILD3 L"***"
  29. #define WILD4 L"****"
  30. #define WILD6 L"******"
  31. static void ui64ToFileTime(const ULONGLONG *p64,FILETIME *pft);
  32. //***************************************************************************
  33. //
  34. // CSWbemDateTime::CSWbemDateTime
  35. //
  36. // DESCRIPTION:
  37. //
  38. // Constructor.
  39. //
  40. //***************************************************************************
  41. CSWbemDateTime::CSWbemDateTime() :
  42. m_dwSafetyOptions (INTERFACESAFE_FOR_UNTRUSTED_DATA|
  43. INTERFACESAFE_FOR_UNTRUSTED_CALLER),
  44. m_bYearSpecified (VARIANT_TRUE),
  45. m_bMonthSpecified (VARIANT_TRUE),
  46. m_bDaySpecified (VARIANT_TRUE),
  47. m_bHoursSpecified (VARIANT_TRUE),
  48. m_bMinutesSpecified (VARIANT_TRUE),
  49. m_bSecondsSpecified (VARIANT_TRUE),
  50. m_bMicrosecondsSpecified (VARIANT_TRUE),
  51. m_bUTCSpecified (VARIANT_TRUE),
  52. m_bIsInterval (VARIANT_FALSE),
  53. m_iYear (0),
  54. m_iMonth (1),
  55. m_iDay (1),
  56. m_iHours (0),
  57. m_iMinutes (0),
  58. m_iSeconds (0),
  59. m_iMicroseconds (0),
  60. m_iUTC (0),
  61. m_dw100nsOverflow (0)
  62. {
  63. InterlockedIncrement(&g_cObj);
  64. m_Dispatch.SetObj (this, IID_ISWbemDateTime,
  65. CLSID_SWbemDateTime, L"SWbemDateTime");
  66. m_cRef=0;
  67. }
  68. //***************************************************************************
  69. //
  70. // CSWbemDateTime::~CSWbemDateTime
  71. //
  72. // DESCRIPTION:
  73. //
  74. // Destructor.
  75. //
  76. //***************************************************************************
  77. CSWbemDateTime::~CSWbemDateTime(void)
  78. {
  79. InterlockedDecrement(&g_cObj);
  80. }
  81. //***************************************************************************
  82. // HRESULT CSWbemDateTime::QueryInterface
  83. // long CSWbemDateTime::AddRef
  84. // long CSWbemDateTime::Release
  85. //
  86. // DESCRIPTION:
  87. //
  88. // Standard Com IUNKNOWN functions.
  89. //
  90. //***************************************************************************
  91. STDMETHODIMP CSWbemDateTime::QueryInterface (
  92. IN REFIID riid,
  93. OUT LPVOID *ppv
  94. )
  95. {
  96. *ppv=NULL;
  97. if (IID_IUnknown==riid)
  98. *ppv = reinterpret_cast<IUnknown*>(this);
  99. else if (IID_ISWbemDateTime==riid)
  100. *ppv = (ISWbemDateTime *)this;
  101. else if (IID_IDispatch==riid)
  102. *ppv= (IDispatch *)this;
  103. else if (IID_IObjectSafety==riid)
  104. *ppv = (IObjectSafety *)this;
  105. else if (IID_ISupportErrorInfo==riid)
  106. *ppv = (ISupportErrorInfo *)this;
  107. else if (IID_IProvideClassInfo==riid)
  108. *ppv = (IProvideClassInfo *)this;
  109. if (NULL!=*ppv)
  110. {
  111. ((LPUNKNOWN)*ppv)->AddRef();
  112. return NOERROR;
  113. }
  114. return ResultFromScode(E_NOINTERFACE);
  115. }
  116. STDMETHODIMP_(ULONG) CSWbemDateTime::AddRef(void)
  117. {
  118. InterlockedIncrement(&m_cRef);
  119. return m_cRef;
  120. }
  121. STDMETHODIMP_(ULONG) CSWbemDateTime::Release(void)
  122. {
  123. InterlockedDecrement(&m_cRef);
  124. if (0L!=m_cRef)
  125. return m_cRef;
  126. delete this;
  127. return 0;
  128. }
  129. //***************************************************************************
  130. //
  131. // SCODE CSWbemDateTime::get_Value
  132. //
  133. // DESCRIPTION:
  134. //
  135. // Retrieve the DMTF datetime value
  136. //
  137. // PARAMETERS:
  138. //
  139. // pbsValue pointer to BSTR to hold value on return
  140. //
  141. // RETURN VALUES:
  142. //
  143. // WBEM_S_NO_ERROR success
  144. // WBEM_E_INVALID_PARAMETER bad input parameters
  145. // WBEM_E_FAILED otherwise
  146. //
  147. //***************************************************************************
  148. STDMETHODIMP CSWbemDateTime::get_Value(
  149. OUT BSTR *pbsValue)
  150. {
  151. HRESULT hr = WBEM_E_FAILED;
  152. ResetLastErrors ();
  153. if (NULL == pbsValue)
  154. hr = WBEM_E_INVALID_PARAMETER;
  155. else
  156. {
  157. wchar_t dmtfValue [WBEMDT_DMTF_LEN + 1];
  158. dmtfValue [WBEMDT_DMTF_LEN] = NULL;
  159. if (m_bIsInterval)
  160. {
  161. // Intervals are easy
  162. swprintf (dmtfValue, L"%08d%02d%02d%02d.%06d:000", m_iDay,
  163. m_iHours, m_iMinutes, m_iSeconds, m_iMicroseconds);
  164. }
  165. else
  166. {
  167. if (m_bYearSpecified)
  168. swprintf (dmtfValue, L"%04d", m_iYear);
  169. else
  170. wcscpy (dmtfValue, WILD4);
  171. if (m_bMonthSpecified)
  172. swprintf (dmtfValue + 4, L"%02d", m_iMonth);
  173. else
  174. wcscat (dmtfValue + 4, WILD2);
  175. if (m_bDaySpecified)
  176. swprintf (dmtfValue + 6, L"%02d", m_iDay);
  177. else
  178. wcscat (dmtfValue + 6, WILD2);
  179. if (m_bHoursSpecified)
  180. swprintf (dmtfValue + 8, L"%02d", m_iHours);
  181. else
  182. wcscat (dmtfValue + 8, WILD2);
  183. if (m_bMinutesSpecified)
  184. swprintf (dmtfValue + 10, L"%02d", m_iMinutes);
  185. else
  186. wcscat (dmtfValue + 10, WILD2);
  187. if (m_bSecondsSpecified)
  188. swprintf (dmtfValue + 12, L"%02d.", m_iSeconds);
  189. else
  190. {
  191. wcscat (dmtfValue + 12, WILD2);
  192. wcscat (dmtfValue + 14, L".");
  193. }
  194. if (m_bMicrosecondsSpecified)
  195. swprintf (dmtfValue + 15, L"%06d", m_iMicroseconds);
  196. else
  197. wcscat (dmtfValue + 15, WILD6);
  198. if (m_bUTCSpecified)
  199. swprintf (dmtfValue + 21, L"%C%03d", (0 <= m_iUTC) ? L'+' : L'-',
  200. (0 <= m_iUTC) ? m_iUTC : -m_iUTC);
  201. else
  202. {
  203. wcscat (dmtfValue + 21, L"+");
  204. wcscat (dmtfValue + 22, WILD3);
  205. }
  206. }
  207. *pbsValue = SysAllocString (dmtfValue);
  208. hr = WBEM_S_NO_ERROR;
  209. }
  210. if (FAILED(hr))
  211. m_Dispatch.RaiseException (hr);
  212. return hr;
  213. }
  214. //***************************************************************************
  215. //
  216. // SCODE CSWbemDateTime::put_Value
  217. //
  218. // DESCRIPTION:
  219. //
  220. // Retrieve the DMTF datetime value
  221. //
  222. // PARAMETERS:
  223. //
  224. // bsValue new value
  225. //
  226. // RETURN VALUES:
  227. //
  228. // WBEM_S_NO_ERROR success
  229. // WBEM_E_INVALID_PARAMETER bad input parameters
  230. // WBEM_E_FAILED otherwise
  231. //
  232. //***************************************************************************
  233. STDMETHODIMP CSWbemDateTime::put_Value(
  234. IN BSTR bsValue)
  235. {
  236. HRESULT hr = wbemErrInvalidSyntax;
  237. ResetLastErrors ();
  238. // First check that the value is the right length
  239. if (bsValue && (WBEMDT_DMTF_LEN == wcslen (bsValue)))
  240. {
  241. bool err = false;
  242. long iYear = 0, iMonth = 1, iDay = 1, iHours = 0, iMinutes = 0,
  243. iSeconds = 0, iMicroseconds = 0, iUTC = 0;
  244. VARIANT_BOOL bYearSpecified = VARIANT_TRUE,
  245. bMonthSpecified = VARIANT_TRUE,
  246. bDaySpecified = VARIANT_TRUE,
  247. bHoursSpecified = VARIANT_TRUE,
  248. bMinutesSpecified = VARIANT_TRUE,
  249. bSecondsSpecified = VARIANT_TRUE,
  250. bMicrosecondsSpecified = VARIANT_TRUE,
  251. bUTCSpecified = VARIANT_TRUE,
  252. bIsInterval = VARIANT_TRUE;
  253. LPWSTR pValue = (LPWSTR) bsValue;
  254. // Check whether its an interval
  255. if (ISINTERVAL(pValue [WBEMDT_DMTF_UPOS]))
  256. {
  257. // Check that everything is a digit apart from
  258. // the interval separator
  259. for (int i = 0; i < WBEMDT_DMTF_LEN; i++)
  260. {
  261. if ((WBEMDT_DMTF_UPOS != i) &&
  262. (WBEMDT_DMTF_SPOS != i) && !iswdigit (pValue [i]))
  263. {
  264. err = true;
  265. break;
  266. }
  267. }
  268. if (!err)
  269. {
  270. // Now check all is within bounds
  271. err = !(CheckField (pValue, 8, bDaySpecified, iDay, WBEMDT_MAX_DAYINT, WBEMDT_MIN_DAYINT) &&
  272. (VARIANT_TRUE == bDaySpecified) &&
  273. CheckField (pValue+8, 2, bHoursSpecified, iHours, WBEMDT_MAX_HOURS, WBEMDT_MIN_HOURS) &&
  274. (VARIANT_TRUE == bHoursSpecified) &&
  275. CheckField (pValue+10, 2, bMinutesSpecified, iMinutes, WBEMDT_MAX_MINUTES, WBEMDT_MIN_MINUTES) &&
  276. (VARIANT_TRUE == bMinutesSpecified) &&
  277. CheckField (pValue+12, 2, bSecondsSpecified, iSeconds, WBEMDT_MAX_SECONDS, WBEMDT_MIN_SECONDS) &&
  278. (VARIANT_TRUE == bSecondsSpecified) &&
  279. (ISDOT(pValue [WBEMDT_DMTF_SPOS])) &&
  280. CheckField (pValue+15, 6, bMicrosecondsSpecified, iMicroseconds, WBEMDT_MAX_MICROSEC, WBEMDT_MIN_MICROSEC) &&
  281. (VARIANT_TRUE == bMicrosecondsSpecified) &&
  282. CheckUTC (pValue+21, bUTCSpecified, iUTC, false));
  283. }
  284. }
  285. else
  286. {
  287. // assume it's a datetime
  288. bIsInterval = VARIANT_FALSE;
  289. err = !(CheckField (pValue, 4, bYearSpecified, iYear, WBEMDT_MAX_YEAR, WBEMDT_MIN_YEAR) &&
  290. CheckField (pValue+4, 2, bMonthSpecified, iMonth, WBEMDT_MAX_MONTH, WBEMDT_MIN_MONTH) &&
  291. CheckField (pValue+6, 2, bDaySpecified, iDay, WBEMDT_MAX_DAY, WBEMDT_MIN_DAY) &&
  292. CheckField (pValue+8, 2, bHoursSpecified, iHours, WBEMDT_MAX_HOURS, WBEMDT_MIN_HOURS) &&
  293. CheckField (pValue+10, 2, bMinutesSpecified, iMinutes, WBEMDT_MAX_MINUTES, WBEMDT_MIN_MINUTES) &&
  294. CheckField (pValue+12, 2, bSecondsSpecified, iSeconds, WBEMDT_MAX_SECONDS, WBEMDT_MIN_SECONDS) &&
  295. (ISDOT(pValue [WBEMDT_DMTF_SPOS])) &&
  296. CheckField (pValue+15, 6, bMicrosecondsSpecified, iMicroseconds, WBEMDT_MAX_MICROSEC, WBEMDT_MIN_MICROSEC) &&
  297. CheckUTC (pValue+21, bUTCSpecified, iUTC));
  298. }
  299. if (!err)
  300. {
  301. m_iYear = iYear;
  302. m_iMonth = iMonth;
  303. m_iDay = iDay;
  304. m_iHours = iHours;
  305. m_iMinutes = iMinutes;
  306. m_iSeconds = iSeconds;
  307. m_iMicroseconds = iMicroseconds;
  308. m_iUTC = iUTC;
  309. m_bYearSpecified = bYearSpecified;
  310. m_bMonthSpecified = bMonthSpecified;
  311. m_bDaySpecified = bDaySpecified;
  312. m_bHoursSpecified = bHoursSpecified;
  313. m_bMinutesSpecified = bMinutesSpecified;
  314. m_bSecondsSpecified = bSecondsSpecified;
  315. m_bMicrosecondsSpecified = bMicrosecondsSpecified;
  316. m_bUTCSpecified = bUTCSpecified;
  317. m_bIsInterval = bIsInterval;
  318. m_dw100nsOverflow = 0;
  319. hr = S_OK;
  320. }
  321. }
  322. if (FAILED(hr))
  323. m_Dispatch.RaiseException (hr);
  324. return hr;
  325. }
  326. //***************************************************************************
  327. //
  328. // SCODE CSWbemDateTime::CheckField
  329. //
  330. // DESCRIPTION:
  331. //
  332. // Check a string-based datetime field for correctness
  333. //
  334. // PARAMETERS:
  335. //
  336. // pValue pointer to the value to check
  337. // len number of characters in the value
  338. // bIsSpecified on return defines whether value is wildcard
  339. // iValue on return specifies integer value (if not wildcard)
  340. // maxValue maximum numeric value allowed for this field
  341. // minValue minimum numeric value allowed for this field
  342. //
  343. // RETURN VALUES:
  344. //
  345. // true if value parsed ok, false otherwise
  346. //
  347. //***************************************************************************
  348. bool CSWbemDateTime::CheckField (
  349. LPWSTR pValue,
  350. ULONG len,
  351. VARIANT_BOOL &bIsSpecified,
  352. long &iValue,
  353. long maxValue,
  354. long minValue
  355. )
  356. {
  357. bool status = true;
  358. bIsSpecified = VARIANT_FALSE;
  359. for (int i = 0; i < len; i++)
  360. {
  361. if (ISWILD(pValue [i]))
  362. {
  363. if (VARIANT_TRUE == bIsSpecified)
  364. {
  365. status = false;
  366. break;
  367. }
  368. }
  369. else if (!iswdigit (pValue [i]))
  370. {
  371. status = false;
  372. break;
  373. }
  374. else
  375. bIsSpecified = VARIANT_TRUE;
  376. }
  377. if (status)
  378. {
  379. if (VARIANT_TRUE == bIsSpecified)
  380. {
  381. wchar_t *dummy = NULL;
  382. wchar_t temp [9];
  383. wcsncpy (temp, pValue, len);
  384. temp [len] = NULL;
  385. iValue = wcstol (temp, &dummy, 10);
  386. }
  387. }
  388. return status;
  389. }
  390. //***************************************************************************
  391. //
  392. // SCODE CSWbemDateTime::CheckUTC
  393. //
  394. // DESCRIPTION:
  395. //
  396. // Check a string-based UTC field for correctness
  397. //
  398. // PARAMETERS:
  399. //
  400. // pValue pointer to the value to check
  401. // bIsSpecified on return defines whether value is wildcard
  402. // iValue on return specifies integer value (if not wildcard)
  403. // bParseSign whether first character should be a sign (+/-) or
  404. // a : (for intervals)
  405. //
  406. // RETURN VALUES:
  407. //
  408. // true if value parsed ok, false otherwise
  409. //
  410. //***************************************************************************
  411. bool CSWbemDateTime::CheckUTC (
  412. LPWSTR pValue,
  413. VARIANT_BOOL &bIsSpecified,
  414. long &iValue,
  415. bool bParseSign
  416. )
  417. {
  418. bool status = true;
  419. bool lessThanZero = false;
  420. bIsSpecified = VARIANT_FALSE;
  421. // Check if we have a signed offset
  422. if (bParseSign)
  423. {
  424. if (ISMINUS(pValue [0]))
  425. lessThanZero = true;
  426. else if (!ISPLUS(pValue [0]))
  427. status = false;
  428. }
  429. else
  430. {
  431. if (!ISINTERVAL(pValue[0]))
  432. status = false;
  433. }
  434. if (status)
  435. {
  436. // Check remaining are digits or wildcars
  437. for (int i = 1; i < 4; i++)
  438. {
  439. if (ISWILD(pValue [i]))
  440. {
  441. if (VARIANT_TRUE == bIsSpecified)
  442. {
  443. status = false;
  444. break;
  445. }
  446. }
  447. else if (!iswdigit (pValue [i]))
  448. {
  449. status = false;
  450. break;
  451. }
  452. else
  453. bIsSpecified = VARIANT_TRUE;
  454. }
  455. }
  456. if (status)
  457. {
  458. if (VARIANT_TRUE == bIsSpecified)
  459. {
  460. wchar_t *dummy = NULL;
  461. wchar_t temp [4];
  462. wcsncpy (temp, pValue+1, 3);
  463. temp [3] = NULL;
  464. iValue = wcstol (temp, &dummy, 10);
  465. if (lessThanZero)
  466. iValue = -iValue;
  467. }
  468. }
  469. return status;
  470. }
  471. //***************************************************************************
  472. //
  473. // SCODE CSWbemDateTime::GetVarDate
  474. //
  475. // DESCRIPTION:
  476. //
  477. // Retrieve the value in Variant form
  478. //
  479. // PARAMETERS:
  480. //
  481. // bIsLocal whether to return a local or UTC value
  482. // pVarDate holds result on successful return
  483. //
  484. // RETURN VALUES:
  485. //
  486. // WBEM_S_NO_ERROR success
  487. // WBEM_E_INVALID_SYNTAX input value is bad
  488. // WBEM_E_FAILED otherwise
  489. //
  490. //***************************************************************************
  491. STDMETHODIMP CSWbemDateTime::GetVarDate(
  492. IN VARIANT_BOOL bIsLocal,
  493. OUT DATE *pVarDate)
  494. {
  495. HRESULT hr = wbemErrInvalidSyntax;
  496. ResetLastErrors ();
  497. if (NULL == pVarDate)
  498. hr = wbemErrInvalidParameter;
  499. else
  500. {
  501. // We cannot perform this operation for interval
  502. // or wildcarded values
  503. if ((VARIANT_TRUE == m_bIsInterval) ||
  504. (VARIANT_FALSE == m_bYearSpecified) ||
  505. (VARIANT_FALSE == m_bMonthSpecified) ||
  506. (VARIANT_FALSE == m_bDaySpecified) ||
  507. (VARIANT_FALSE == m_bHoursSpecified) ||
  508. (VARIANT_FALSE == m_bMinutesSpecified) ||
  509. (VARIANT_FALSE == m_bSecondsSpecified) ||
  510. (VARIANT_FALSE == m_bMicrosecondsSpecified) ||
  511. (VARIANT_FALSE == m_bUTCSpecified))
  512. {
  513. hr = wbemErrFailed;
  514. }
  515. else
  516. {
  517. SYSTEMTIME sysTime;
  518. sysTime.wYear = m_iYear;
  519. sysTime.wMonth = m_iMonth;
  520. sysTime.wDay = m_iDay;
  521. sysTime.wHour = m_iHours;
  522. sysTime.wMinute = m_iMinutes;
  523. sysTime.wSecond = m_iSeconds;
  524. sysTime.wMilliseconds = m_iMicroseconds/1000;
  525. if (VARIANT_TRUE == bIsLocal)
  526. {
  527. // Need to convert this to a local DATE value
  528. // This requires that we switch the currently stored
  529. // time to one for the appropriate timezone, lop off
  530. // the UTC and set the rest in a variant.
  531. // Coerce the time to GMT first
  532. WBEMTime wbemTime (sysTime);
  533. if (!wbemTime.GetDMTF (sysTime))
  534. return wbemErrInvalidSyntax;
  535. }
  536. double dVarDate;
  537. if (SystemTimeToVariantTime (&sysTime, &dVarDate))
  538. {
  539. *pVarDate = dVarDate;
  540. hr = S_OK;
  541. }
  542. }
  543. }
  544. if (FAILED(hr))
  545. m_Dispatch.RaiseException (hr);
  546. return hr;
  547. }
  548. //***************************************************************************
  549. //
  550. // SCODE CSWbemDateTime::GetFileTime
  551. //
  552. // DESCRIPTION:
  553. //
  554. // Retrieve the value in FILETIME form
  555. //
  556. // PARAMETERS:
  557. //
  558. // bIsLocal whether to return a local or UTC value
  559. // pbsFileTime holds result on successful return
  560. //
  561. // RETURN VALUES:
  562. //
  563. // WBEM_S_NO_ERROR success
  564. // WBEM_E_INVALID_SYNTAX input value is bad
  565. // WBEM_E_FAILED otherwise
  566. //
  567. //***************************************************************************
  568. STDMETHODIMP CSWbemDateTime::GetFileTime(
  569. IN VARIANT_BOOL bIsLocal,
  570. OUT BSTR *pbsFileTime)
  571. {
  572. HRESULT hr = wbemErrInvalidSyntax;
  573. ResetLastErrors ();
  574. if (NULL == pbsFileTime)
  575. hr = wbemErrInvalidParameter;
  576. else
  577. {
  578. // We cannot perform this operation for interval
  579. // or wildcarded values
  580. if ((VARIANT_TRUE == m_bIsInterval) ||
  581. (VARIANT_FALSE == m_bYearSpecified) ||
  582. (VARIANT_FALSE == m_bMonthSpecified) ||
  583. (VARIANT_FALSE == m_bDaySpecified) ||
  584. (VARIANT_FALSE == m_bHoursSpecified) ||
  585. (VARIANT_FALSE == m_bMinutesSpecified) ||
  586. (VARIANT_FALSE == m_bSecondsSpecified) ||
  587. (VARIANT_FALSE == m_bMicrosecondsSpecified) ||
  588. (VARIANT_FALSE == m_bUTCSpecified))
  589. {
  590. hr = wbemErrFailed;
  591. }
  592. else
  593. {
  594. SYSTEMTIME sysTime;
  595. sysTime.wYear = m_iYear;
  596. sysTime.wMonth = m_iMonth;
  597. sysTime.wDay = m_iDay;
  598. sysTime.wHour = m_iHours;
  599. sysTime.wMinute = m_iMinutes;
  600. sysTime.wSecond = m_iSeconds;
  601. sysTime.wMilliseconds = m_iMicroseconds/1000;
  602. if (VARIANT_TRUE == bIsLocal)
  603. {
  604. // Need to convert this to a local DATE value
  605. // This requires that we switch the currently stored
  606. // time to one for the appropriate timezone, lop off
  607. // the UTC and set the rest in a variant.
  608. // Coerce the time to GMT first
  609. WBEMTime wbemTime (sysTime);
  610. if (!wbemTime.GetDMTF (sysTime))
  611. return wbemErrInvalidSyntax;
  612. }
  613. FILETIME fileTime;
  614. if (SystemTimeToFileTime (&sysTime, &fileTime))
  615. {
  616. wchar_t wcBuf [30];
  617. unsigned __int64 ui64 = fileTime.dwHighDateTime;
  618. ui64 = ui64 << 32;
  619. ui64 += fileTime.dwLowDateTime;
  620. /*
  621. * In converting to SYSTEMTIME we lost sub-millisecond
  622. * precision from our DMTF value, so let's add it back,
  623. * remembering that FILETIME is in 10ns units.
  624. */
  625. ui64 += ((m_iMicroseconds % 1000) * 10);
  626. // Finally add the LSB
  627. ui64 += m_dw100nsOverflow;
  628. _ui64tow (ui64, wcBuf, 10);
  629. *pbsFileTime = SysAllocString (wcBuf);
  630. hr = S_OK;
  631. }
  632. }
  633. }
  634. if (FAILED(hr))
  635. m_Dispatch.RaiseException (hr);
  636. return hr;
  637. }
  638. //***************************************************************************
  639. //
  640. // SCODE CSWbemDateTime::SetVarDate
  641. //
  642. // DESCRIPTION:
  643. //
  644. // Set the value in Variant form
  645. //
  646. // PARAMETERS:
  647. //
  648. // dVarDate the new value
  649. // bIsLocal whether to treat as local or UTC value
  650. //
  651. // RETURN VALUES:
  652. //
  653. // WBEM_S_NO_ERROR success
  654. // WBEM_E_INVALID_SYNTAX input value is bad
  655. //
  656. //***************************************************************************
  657. STDMETHODIMP CSWbemDateTime::SetVarDate(
  658. /*[in]*/ DATE dVarDate,
  659. /*[in, optional]*/ VARIANT_BOOL bIsLocal)
  660. {
  661. HRESULT hr = wbemErrInvalidSyntax;
  662. ResetLastErrors ();
  663. SYSTEMTIME sysTime;
  664. if (TRUE == VariantTimeToSystemTime (dVarDate, &sysTime))
  665. {
  666. long offset = 0;
  667. if (VARIANT_TRUE == bIsLocal)
  668. {
  669. WBEMTime wbemTime (sysTime);
  670. if (!wbemTime.GetDMTF (sysTime, offset))
  671. return wbemErrInvalidSyntax;
  672. }
  673. m_iYear = sysTime.wYear;
  674. m_iMonth = sysTime.wMonth;
  675. m_iDay = sysTime.wDay;
  676. m_iHours = sysTime.wHour;
  677. m_iMinutes = sysTime.wMinute;
  678. m_iSeconds = sysTime.wSecond;
  679. m_iMicroseconds = sysTime.wMilliseconds * 1000;
  680. m_iUTC = offset;
  681. m_dw100nsOverflow = 0;
  682. m_bYearSpecified = VARIANT_TRUE,
  683. m_bMonthSpecified = VARIANT_TRUE,
  684. m_bDaySpecified = VARIANT_TRUE,
  685. m_bHoursSpecified = VARIANT_TRUE,
  686. m_bMinutesSpecified = VARIANT_TRUE,
  687. m_bSecondsSpecified = VARIANT_TRUE,
  688. m_bMicrosecondsSpecified = VARIANT_TRUE,
  689. m_bUTCSpecified = VARIANT_TRUE,
  690. m_bIsInterval = VARIANT_FALSE;
  691. hr = S_OK;
  692. }
  693. if (FAILED(hr))
  694. m_Dispatch.RaiseException (hr);
  695. return hr;
  696. }
  697. //***************************************************************************
  698. //
  699. // SCODE CSWbemDateTime::SetFileTime
  700. //
  701. // DESCRIPTION:
  702. //
  703. // Set the value from a string representation of a FILETIME
  704. //
  705. // PARAMETERS:
  706. //
  707. // bsFileTime the new value
  708. // bIsLocal whether to treat as local or UTC value
  709. //
  710. // RETURN VALUES:
  711. //
  712. // WBEM_S_NO_ERROR success
  713. // WBEM_E_INVALID_SYNTAX input value is bad
  714. //
  715. //***************************************************************************
  716. STDMETHODIMP CSWbemDateTime::SetFileTime(
  717. /*[in]*/ BSTR bsFileTime,
  718. /*[in, optional]*/ VARIANT_BOOL bIsLocal)
  719. {
  720. HRESULT hr = wbemErrInvalidSyntax;
  721. ResetLastErrors ();
  722. // Convert string to 64-bit
  723. unsigned __int64 ri64;
  724. if (ReadUI64(bsFileTime, ri64))
  725. {
  726. // Now convert 64-bit to FILETIME
  727. FILETIME fileTime;
  728. fileTime.dwHighDateTime = (DWORD)(ri64 >> 32);
  729. fileTime.dwLowDateTime = (DWORD)(ri64 & 0xFFFFFFFF);
  730. // Now turn it into a SYSTEMTIME
  731. SYSTEMTIME sysTime;
  732. if (TRUE == FileTimeToSystemTime (&fileTime, &sysTime))
  733. {
  734. long offset = 0;
  735. if (VARIANT_TRUE == bIsLocal)
  736. {
  737. WBEMTime wbemTime (sysTime);
  738. if (!wbemTime.GetDMTF (sysTime, offset))
  739. return wbemErrInvalidSyntax;
  740. }
  741. m_iYear = sysTime.wYear;
  742. m_iMonth = sysTime.wMonth;
  743. m_iDay = sysTime.wDay;
  744. m_iHours = sysTime.wHour;
  745. m_iMinutes = sysTime.wMinute;
  746. m_iSeconds = sysTime.wSecond;
  747. /*
  748. * SYSTEMTIME has only 1 millisecond precision. Since
  749. * a FILETIME has 100 nanosecond precision and a DMTF
  750. * datetime has 1 microsecond, you can see the point
  751. * of the following.
  752. */
  753. m_iMicroseconds = sysTime.wMilliseconds * 1000 +
  754. ((ri64 % (10000)) / 10);
  755. // Record our LSB in case we need it later
  756. m_dw100nsOverflow = ri64 % 10;
  757. // The FILETIME hs 1ns precision
  758. m_iUTC = offset;
  759. m_bYearSpecified = VARIANT_TRUE,
  760. m_bMonthSpecified = VARIANT_TRUE,
  761. m_bDaySpecified = VARIANT_TRUE,
  762. m_bHoursSpecified = VARIANT_TRUE,
  763. m_bMinutesSpecified = VARIANT_TRUE,
  764. m_bSecondsSpecified = VARIANT_TRUE,
  765. m_bMicrosecondsSpecified = VARIANT_TRUE,
  766. m_bUTCSpecified = VARIANT_TRUE,
  767. m_bIsInterval = VARIANT_FALSE;
  768. hr = S_OK;
  769. }
  770. }
  771. if (FAILED(hr))
  772. m_Dispatch.RaiseException (hr);
  773. return hr;
  774. }
  775. // These are here rather than wbemtime.h so we don't have to doc/support
  776. #define INVALID_TIME_FORMAT 0
  777. #define INVALID_TIME_ARITHMETIC 0
  778. #define BAD_TIMEZONE 0
  779. //***************************************************************************
  780. //
  781. // FileTimeToui64
  782. // ui64ToFileTime
  783. //
  784. // Description: Conversion routines for going between FILETIME structures
  785. // and __int64.
  786. //
  787. //***************************************************************************
  788. static void FileTimeToui64(const FILETIME *pft, ULONGLONG *p64)
  789. {
  790. *p64 = pft->dwHighDateTime;
  791. *p64 = *p64 << 32;
  792. *p64 |= pft->dwLowDateTime;
  793. }
  794. static void ui64ToFileTime(const ULONGLONG *p64,FILETIME *pft)
  795. {
  796. unsigned __int64 uTemp = *p64;
  797. pft->dwLowDateTime = (DWORD)uTemp;
  798. uTemp = uTemp >> 32;
  799. pft->dwHighDateTime = (DWORD)uTemp;
  800. }
  801. static int CompareSYSTEMTIME(const SYSTEMTIME *pst1, const SYSTEMTIME *pst2)
  802. {
  803. FILETIME ft1, ft2;
  804. SystemTimeToFileTime(pst1, &ft1);
  805. SystemTimeToFileTime(pst2, &ft2);
  806. return CompareFileTime(&ft1, &ft2);
  807. }
  808. // This function is used to convert the relative values that come
  809. // back from GetTimeZoneInformation into an actual date for the year
  810. // in question. The system time structure that is passed in is updated
  811. // to contain the absolute values.
  812. static void DayInMonthToAbsolute(SYSTEMTIME *pst, const WORD wYear)
  813. {
  814. const static int _lpdays[] = {
  815. -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  816. };
  817. const static int _days[] = {
  818. -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
  819. };
  820. SHORT shYearDay;
  821. // If this is not 0, this is not a relative date
  822. if (pst->wYear == 0)
  823. {
  824. // Was that year a leap year?
  825. BOOL bLeap = ( (( wYear % 400) == 0) || ((( wYear % 4) == 0) && (( wYear % 100) != 0)));
  826. // Figure out the day of the year for the first day of the month in question
  827. if (bLeap)
  828. shYearDay = 1 + _lpdays[pst->wMonth - 1];
  829. else
  830. shYearDay = 1 + _days[pst->wMonth - 1];
  831. // Now, figure out how many leap days there have been since 1/1/1601
  832. WORD yc = wYear - 1601;
  833. WORD y4 = (yc) / 4;
  834. WORD y100 = (yc) / 100;
  835. WORD y400 = (yc) / 400;
  836. // This will tell us the day of the week for the first day of the month in question.
  837. // The '1 +' reflects the fact that 1/1/1601 was a monday (figures). You might ask,
  838. // 'why do we care what day of the week this is?' Well, I'll tell you. The way
  839. // daylight savings time is defined is with things like 'the last sunday of the month
  840. // of october.' Kinda helps to know what day that is.
  841. SHORT monthdow = (1 + (yc * 365 + y4 + y400 - y100) + shYearDay) % 7;
  842. if ( monthdow < pst->wDayOfWeek )
  843. shYearDay += (pst->wDayOfWeek - monthdow) + (pst->wDay - 1) * 7;
  844. else
  845. shYearDay += (pst->wDayOfWeek - monthdow) + pst->wDay * 7;
  846. /*
  847. * May have to adjust the calculation above if week == 5 (meaning
  848. * the last instance of the day in the month). Check if yearday falls
  849. * beyond month and adjust accordingly.
  850. */
  851. if ( (pst->wDay == 5) &&
  852. (shYearDay > (bLeap ? _lpdays[pst->wMonth] :
  853. _days[pst->wMonth])) )
  854. {
  855. shYearDay -= 7;
  856. }
  857. // Now update the structure.
  858. pst->wYear = wYear;
  859. pst->wDay = shYearDay - (bLeap ? _lpdays[pst->wMonth - 1] :
  860. _days[pst->wMonth - 1]);
  861. }
  862. }
  863. // **************************************************************************
  864. // These are static to WBEMTIME, which means they CAN be called from outside
  865. // wbemtime
  866. LONG CSWbemDateTime::WBEMTime::GetLocalOffsetForDate(const SYSTEMTIME *pst)
  867. {
  868. TIME_ZONE_INFORMATION tzTime;
  869. DWORD dwRes = GetTimeZoneInformation(&tzTime);
  870. LONG lRes = 0xffffffff;
  871. switch (dwRes)
  872. {
  873. case TIME_ZONE_ID_UNKNOWN:
  874. {
  875. // Read tz, but no dst defined in this zone
  876. lRes = tzTime.Bias * -1;
  877. break;
  878. }
  879. case TIME_ZONE_ID_STANDARD:
  880. case TIME_ZONE_ID_DAYLIGHT:
  881. {
  882. // Convert the relative dates to absolute dates
  883. DayInMonthToAbsolute(&tzTime.DaylightDate, pst->wYear);
  884. DayInMonthToAbsolute(&tzTime.StandardDate, pst->wYear);
  885. if ( CompareSYSTEMTIME(&tzTime.DaylightDate, &tzTime.StandardDate) < 0 )
  886. {
  887. /*
  888. * Northern hemisphere ordering
  889. */
  890. if ( CompareSYSTEMTIME(pst, &tzTime.DaylightDate) < 0 || CompareSYSTEMTIME(pst, &tzTime.StandardDate) > 0)
  891. {
  892. lRes = tzTime.Bias * -1;
  893. }
  894. else
  895. {
  896. lRes = (tzTime.Bias + tzTime.DaylightBias) * -1;
  897. }
  898. }
  899. else
  900. {
  901. /*
  902. * Southern hemisphere ordering
  903. */
  904. if ( CompareSYSTEMTIME(pst, &tzTime.StandardDate) < 0 || CompareSYSTEMTIME(pst, &tzTime.DaylightDate) > 0)
  905. {
  906. lRes = (tzTime.Bias + tzTime.DaylightBias) * -1;
  907. }
  908. else
  909. {
  910. lRes = tzTime.Bias * -1;
  911. }
  912. }
  913. break;
  914. }
  915. case TIME_ZONE_ID_INVALID:
  916. default:
  917. {
  918. // Can't read the timezone info
  919. ASSERT_BREAK(BAD_TIMEZONE);
  920. break;
  921. }
  922. }
  923. return lRes;
  924. }
  925. ///////////////////////////////////////////////////////////////////////////
  926. // WBEMTime - This class holds time values.
  927. //***************************************************************************
  928. //
  929. // WBEMTime::operator+(const WBEMTimeSpan &uAdd)
  930. //
  931. // Description: dummy function for adding two WBEMTime. It doesnt really
  932. // make sense to add two date, but this is here for Tomas's template.
  933. //
  934. // Return: WBEMTime object.
  935. //
  936. //***************************************************************************
  937. CSWbemDateTime::WBEMTime CSWbemDateTime::WBEMTime::operator+(const WBEMTimeSpan &uAdd) const
  938. {
  939. WBEMTime ret;
  940. if (IsOk())
  941. {
  942. ret.m_uTime = m_uTime + uAdd.m_Time;
  943. }
  944. else
  945. {
  946. ASSERT_BREAK(INVALID_TIME_ARITHMETIC);
  947. }
  948. return ret;
  949. }
  950. //***************************************************************************
  951. //
  952. // WBEMTime::operator=(const SYSTEMTIME)
  953. //
  954. // Description: Assignment operator which is also used by the constructor.
  955. // This takes a standard WIN32 SYSTEMTIME stucture.
  956. //
  957. // Return: WBEMTime object.
  958. //
  959. //***************************************************************************
  960. const CSWbemDateTime::WBEMTime & CSWbemDateTime::WBEMTime::operator=(const SYSTEMTIME & st)
  961. {
  962. Clear(); // set when properly assigned
  963. FILETIME t_ft;
  964. if ( SystemTimeToFileTime(&st, &t_ft) )
  965. {
  966. // now assign using a FILETIME.
  967. *this = t_ft;
  968. }
  969. else
  970. {
  971. ASSERT_BREAK(INVALID_TIME_FORMAT);
  972. }
  973. return *this;
  974. }
  975. //***************************************************************************
  976. //
  977. // WBEMTime::operator=(const FILETIME)
  978. //
  979. // Description: Assignment operator which is also used by the constructor.
  980. // This takes a standard WIN32 FILETIME stucture.
  981. //
  982. // Return: WBEMTime object.
  983. //
  984. //***************************************************************************
  985. const CSWbemDateTime::WBEMTime & CSWbemDateTime::WBEMTime::operator=(const FILETIME & ft)
  986. {
  987. FileTimeToui64(&ft, &m_uTime);
  988. return *this;
  989. }
  990. //***************************************************************************
  991. //
  992. // WBEMTime::operator-(const WBEMTime & sub)
  993. //
  994. // Description: returns a WBEMTimeSpan object as the difference between
  995. // two WBEMTime objects.
  996. //
  997. // Return: WBEMTimeSpan object.
  998. //
  999. //***************************************************************************
  1000. CSWbemDateTime::WBEMTime CSWbemDateTime::WBEMTime::operator-(const WBEMTimeSpan & sub) const
  1001. {
  1002. WBEMTime ret;
  1003. if (IsOk() && (m_uTime >= sub.m_Time))
  1004. {
  1005. ret.m_uTime = m_uTime - sub.m_Time;
  1006. }
  1007. else
  1008. {
  1009. ASSERT_BREAK(INVALID_TIME_ARITHMETIC);
  1010. }
  1011. return ret;
  1012. }
  1013. //***************************************************************************
  1014. //
  1015. // WBEMTime::GetSYSTEMTIME(SYSTEMTIME * pst)
  1016. //
  1017. // Return: TRUE if OK.
  1018. //
  1019. //***************************************************************************
  1020. BOOL CSWbemDateTime::WBEMTime::GetSYSTEMTIME(SYSTEMTIME * pst) const
  1021. {
  1022. if ((pst == NULL) || (!IsOk()))
  1023. {
  1024. ASSERT_BREAK(INVALID_TIME_ARITHMETIC);
  1025. return FALSE;
  1026. }
  1027. FILETIME t_ft;
  1028. if (GetFILETIME(&t_ft))
  1029. {
  1030. if (!FileTimeToSystemTime(&t_ft, pst))
  1031. {
  1032. ASSERT_BREAK(INVALID_TIME_ARITHMETIC);
  1033. return FALSE;
  1034. }
  1035. }
  1036. else
  1037. {
  1038. return FALSE;
  1039. }
  1040. return TRUE;
  1041. }
  1042. //***************************************************************************
  1043. //
  1044. // WBEMTime::GetFILETIME(FILETIME * pst)
  1045. //
  1046. // Return: TRUE if OK.
  1047. //
  1048. //***************************************************************************
  1049. BOOL CSWbemDateTime::WBEMTime::GetFILETIME(FILETIME * pft) const
  1050. {
  1051. if ((pft == NULL) || (!IsOk()))
  1052. {
  1053. ASSERT_BREAK(INVALID_TIME_ARITHMETIC);
  1054. return FALSE;
  1055. }
  1056. ui64ToFileTime(&m_uTime, pft);
  1057. return TRUE;
  1058. }
  1059. //***************************************************************************
  1060. //
  1061. // BSTR WBEMTime::GetDMTF(SYSTEMTIME &st, long &offset)
  1062. //
  1063. // Description: Gets the time in DMTF string local datetime format as a
  1064. // SYSTEMTIME.
  1065. //
  1066. // Return: NULL if not OK.
  1067. //
  1068. //***************************************************************************
  1069. BOOL CSWbemDateTime::WBEMTime::GetDMTF(SYSTEMTIME &st, long &offset) const
  1070. {
  1071. if (!IsOk())
  1072. {
  1073. ASSERT_BREAK(INVALID_TIME_ARITHMETIC);
  1074. return FALSE;
  1075. }
  1076. // If the date to be converted is within 12 hours of
  1077. // 1/1/1601, return the greenwich time
  1078. ULONGLONG t_ConversionZone = 12L * 60L * 60L ;
  1079. t_ConversionZone = t_ConversionZone * 10000000L ;
  1080. if ( m_uTime < t_ConversionZone )
  1081. {
  1082. if(!GetSYSTEMTIME(&st))
  1083. return FALSE;
  1084. }
  1085. else
  1086. {
  1087. if (GetSYSTEMTIME(&st))
  1088. {
  1089. offset = GetLocalOffsetForDate(&st);
  1090. WBEMTime wt;
  1091. if (offset >= 0)
  1092. wt = *this - WBEMTimeSpan(offset);
  1093. else
  1094. wt = *this + WBEMTimeSpan(-offset);
  1095. wt.GetSYSTEMTIME(&st);
  1096. }
  1097. else
  1098. return FALSE;
  1099. }
  1100. return TRUE ;
  1101. }
  1102. //***************************************************************************
  1103. //
  1104. // BSTR WBEMTime::GetDMTF(SYSTEMTIME &st)
  1105. //
  1106. // Description: Gets the time in as local SYSTEMTIME.
  1107. //
  1108. // Return: NULL if not OK.
  1109. //
  1110. //***************************************************************************
  1111. BOOL CSWbemDateTime::WBEMTime::GetDMTF(SYSTEMTIME &st) const
  1112. {
  1113. if (!IsOk())
  1114. {
  1115. ASSERT_BREAK(INVALID_TIME_ARITHMETIC);
  1116. return FALSE;
  1117. }
  1118. // If the date to be converted is within 12 hours of
  1119. // 1/1/1601, return the greenwich time
  1120. ULONGLONG t_ConversionZone = 12L * 60L * 60L ;
  1121. t_ConversionZone = t_ConversionZone * 10000000L ;
  1122. if ( m_uTime < t_ConversionZone )
  1123. {
  1124. if(!GetSYSTEMTIME(&st))
  1125. return FALSE;
  1126. }
  1127. else
  1128. {
  1129. if (GetSYSTEMTIME(&st))
  1130. {
  1131. long offset = GetLocalOffsetForDate(&st);
  1132. WBEMTime wt;
  1133. if (offset >= 0)
  1134. wt = *this + WBEMTimeSpan(offset);
  1135. else
  1136. wt = *this - WBEMTimeSpan(-offset);
  1137. wt.GetSYSTEMTIME(&st);
  1138. }
  1139. else
  1140. return FALSE;
  1141. }
  1142. return TRUE ;
  1143. }