Leaked source code of windows server 2003
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.

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