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.

625 lines
18 KiB

  1. /*
  2. * datetime.c
  3. *
  4. * Purpose:
  5. * mostly stolen from NT winfile
  6. *
  7. * Call GetInternational(), on startup and WM_WININICHANGE
  8. *
  9. * Owners:
  10. * brettm
  11. */
  12. #include "pch.hxx"
  13. #include <time.h>
  14. #include "dt.h"
  15. #include <BadStrFunctions.h>
  16. ASSERTDATA
  17. CCH CchFmtTime ( PDTR pdtr, LPSTR szBuf, CCH cchBuf, TMTYP tmtyp );
  18. CCH CchFmtDate ( PDTR pdtr, LPSTR szBuf, CCH cchBuf, DTTYP dttyp, LPSTR szDatePicture );
  19. CCH CchFmtDateTime ( PDTR pdtr, LPSTR szDateTime, CCH cch, DTTYP dttyp, TMTYP tmtyp, BOOL fForceWestern);
  20. void GetCurDateTime(PDTR pdtr);
  21. BOOL GetDowDateFormat(char *sz, int cch);
  22. //WIDE VERSIONS
  23. CCH CchFmtTimeW (PDTR pdtr, LPWSTR wszBuf, CCH cchBuf, TMTYP tmtyp,
  24. PFGETTIMEFORMATW pfGetTimeFormatW);
  25. CCH CchFmtDateW (PDTR pdtr, LPWSTR wszBuf, CCH cchBuf, DTTYP dttyp, LPWSTR wszDatePicture,
  26. PFGETDATEFORMATW pfGetDateFormatW);
  27. CCH CchFmtDateTimeW (PDTR pdtr, LPWSTR wszDateTime, CCH cch, DTTYP dttyp, TMTYP tmtyp,
  28. BOOL fForceWestern, PFGETDATEFORMATW pfGetDateFormatW,
  29. PFGETTIMEFORMATW pfGetTimeFormatW);
  30. BOOL GetDowDateFormatW(WCHAR *wsz, int cch, PFGETLOCALEINFOW pfGetLocaleInfoW);
  31. #define LCID_WESTERN MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
  32. /*
  33. * CchFileTimeToDateTimeSz
  34. *
  35. * Purpose:
  36. * Takes the time passed in as a FILETIME stick it into a ized string using
  37. * the short date format.
  38. * For WIN32, the *pft is converted to the time before made
  39. * into a string
  40. *
  41. * Parameters:
  42. * pft Points to FILETIME structure
  43. * szStr String where to put the ized version of the date
  44. * fNoSeconds Don't display seconds
  45. *
  46. * Returns:
  47. * The length of the date string
  48. */
  49. OESTDAPI_(INT) CchFileTimeToDateTimeSz(FILETIME * pft, CHAR * szDateTime, int cch, DWORD dwFlags)
  50. {
  51. int iret;
  52. FILETIME ft;
  53. DTTYP dttyp;
  54. TMTYP tmtyp;
  55. DTR dtr;
  56. SYSTEMTIME st;
  57. char szFmt[CCHMAX_DOWDATEFMT];
  58. // Put the file time in our time zone.
  59. if (!(dwFlags & DTM_NOTIMEZONEOFFSET))
  60. FileTimeToLocalFileTime(pft, &ft);
  61. else
  62. ft = *pft;
  63. FileTimeToSystemTime(&ft, &st);
  64. if (dwFlags & DTM_DOWSHORTDATE)
  65. {
  66. Assert((dwFlags & DTM_DOWSHORTDATE) == DTM_DOWSHORTDATE);
  67. //Use LOCALE_USE_CP_ACP to make sure that CP_ACP is used
  68. if (GetDowDateFormat(szFmt, sizeof(szFmt)))
  69. iret = GetDateFormat(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, &st, szFmt, szDateTime, cch);
  70. else
  71. iret = 0;
  72. return(iret);
  73. }
  74. dtr.yr = st.wYear;
  75. dtr.mon = st.wMonth;
  76. dtr.day = st.wDay;
  77. dtr.hr = st.wHour;
  78. dtr.mn = st.wMinute;
  79. dtr.sec = st.wSecond;
  80. dttyp = ((dwFlags & DTM_LONGDATE) ? dttypLong : dttypShort);
  81. tmtyp = ((dwFlags & DTM_NOSECONDS) ? ftmtypAccuHM : ftmtypAccuHMS);
  82. if (dwFlags & DTM_NODATE)
  83. {
  84. iret = CchFmtTime(&dtr, szDateTime, cch, tmtyp);
  85. }
  86. else if (dwFlags & DTM_NOTIME)
  87. {
  88. iret = CchFmtDate(&dtr, szDateTime, cch, dttyp, NULL);
  89. }
  90. else
  91. {
  92. //For the formatted date, DTM_FORCEWESTERN flag returns English date and time.
  93. //Without DTM_FORCEWESTERN the formatted time may not be representable in ASCII.
  94. iret = CchFmtDateTime(&dtr, szDateTime, cch, dttyp, tmtyp, dwFlags & DTM_FORCEWESTERN);
  95. }
  96. return(iret);
  97. }
  98. CCH CchFmtTime ( PDTR pdtr, LPSTR szBuf, CCH cchBuf, TMTYP tmtyp )
  99. {
  100. DWORD flags;
  101. int cch;
  102. SYSTEMTIME st;
  103. if ( cchBuf == 0 )
  104. {
  105. AssertSz ( fFalse, "0-length buffer passed to CchFmtTime" );
  106. return 0;
  107. }
  108. Assert(szBuf);
  109. if (pdtr == NULL)
  110. {
  111. GetLocalTime(&st);
  112. }
  113. else
  114. {
  115. // Bullet raid #3143
  116. // Validate data. Set to minimums if invalid.
  117. Assert(pdtr->hr >= 0 && pdtr->hr < 24);
  118. Assert(pdtr->mn >= 0 && pdtr->mn < 60);
  119. Assert(pdtr->sec >= 0 && pdtr->sec < 60);
  120. // GetTimeFormat doesn't like invalid values
  121. ZeroMemory(&st, sizeof(SYSTEMTIME));
  122. st.wMonth = 1;
  123. st.wDay = 1;
  124. st.wHour = pdtr->hr;
  125. st.wMinute = pdtr->mn;
  126. st.wSecond = pdtr->sec;
  127. }
  128. Assert((tmtyp & ftmtypHours24) == 0);
  129. if ( tmtyp & ftmtypAccuHMS )
  130. flags = 0;
  131. else if ( tmtyp & ftmtypAccuH )
  132. flags = TIME_NOMINUTESORSECONDS;
  133. else
  134. flags = TIME_NOSECONDS; // default value
  135. //Use LOCALE_USE_CP_ACP to make sure that CP_ACP is used
  136. flags |= LOCALE_USE_CP_ACP;
  137. cch = GetTimeFormat(LOCALE_USER_DEFAULT, flags, &st, NULL, szBuf, cchBuf);
  138. return((cch == 0) ? 0 : (cch - 1));
  139. }
  140. /*
  141. - CchFmtDate
  142. -
  143. * Purpose:
  144. * formats the date passed in the DTR into the LPSTR passed
  145. * according to the formatting "instructions" passed in DTTYP
  146. * and szDatePicture. If values are not explicitly passed,
  147. * values are read in from WIN.INI
  148. *
  149. * Arguments:
  150. * pdtr: pointer to DTR where time is passed - if NULL,
  151. * current date is used.
  152. * szBuf: buffer where formatted info is to be passed
  153. * cchBuf: size of buffer
  154. * dttyp: type of date format
  155. * szDatePicture: picture of the date - if NULL, values are
  156. * read in from WIN.INI
  157. *
  158. * Note: see reply from win-bug at end of function describing
  159. * separator strings in date pictures
  160. *
  161. * Returns:
  162. * count of chars inserted in szBuf
  163. *
  164. * Side effects:
  165. *
  166. *
  167. * Errors:
  168. * returns count of 0 in case of error
  169. *
  170. */
  171. CCH CchFmtDate ( PDTR pdtr, LPSTR szBuf, CCH cchBuf, DTTYP dttyp, LPSTR szDatePicture )
  172. {
  173. SYSTEMTIME st={0};
  174. int cch;
  175. DTR dtr;
  176. DWORD flags;
  177. Assert(szBuf);
  178. if (!cchBuf)
  179. {
  180. AssertSz ( fFalse, "0-length buffer passed to CchFmtDate" );
  181. return 0;
  182. }
  183. if (!pdtr)
  184. {
  185. pdtr = &dtr;
  186. GetCurDateTime ( pdtr );
  187. }
  188. else
  189. {
  190. // Bullet raid #3143
  191. // Validate data. Set to minimums if invalid.
  192. if (pdtr->yr < nMinDtrYear || pdtr->yr >= nMacDtrYear)
  193. pdtr->yr = nMinDtrYear;
  194. if (pdtr->mon <= 0 || pdtr->mon > 12)
  195. pdtr->mon = 1;
  196. if (pdtr->day <= 0 || pdtr->day > 31)
  197. pdtr->day = 1;
  198. if (pdtr->dow < 0 || pdtr->dow >= 7)
  199. pdtr->dow = 0;
  200. }
  201. Assert ( pdtr );
  202. Assert ( pdtr->yr >= nMinDtrYear && pdtr->yr < nMacDtrYear );
  203. Assert ( pdtr->mon > 0 && pdtr->mon <= 12 );
  204. Assert ( pdtr->day > 0 && pdtr->day <= 31 );
  205. Assert((dttyp == dttypShort) || (dttyp == dttypLong));
  206. // TODO: handle dttypSplSDayShort properly...
  207. flags = 0;
  208. if (dttyp == dttypLong)
  209. flags = flags | DATE_LONGDATE;
  210. st.wYear = pdtr->yr;
  211. st.wMonth = pdtr->mon;
  212. st.wDay = pdtr->day;
  213. st.wDayOfWeek = 0;
  214. //Use LOCALE_USE_CP_ACP to make sure that CP_ACP is used
  215. flags |= LOCALE_USE_CP_ACP;
  216. cch = GetDateFormat(LOCALE_USER_DEFAULT, flags, &st, NULL, szBuf, cchBuf);
  217. return((cch == 0) ? 0 : (cch - 1));
  218. }
  219. CCH CchFmtDateTime ( PDTR pdtr, LPSTR szDateTime, CCH cch, DTTYP dttyp, TMTYP tmtyp, BOOL fForceWestern)
  220. {
  221. int cchT;
  222. LPSTR szTime;
  223. DWORD flags;
  224. SYSTEMTIME st={0};
  225. int icch = cch;
  226. st.wYear = pdtr->yr;
  227. st.wMonth = pdtr->mon;
  228. st.wDay = pdtr->day;
  229. st.wHour = pdtr->hr;
  230. st.wMinute = pdtr->mn;
  231. st.wSecond = pdtr->sec;
  232. Assert (LCID_WESTERN == 0x409);
  233. Assert((dttyp == dttypShort) || (dttyp == dttypLong));
  234. if (dttyp == dttypLong)
  235. flags = DATE_LONGDATE;
  236. else
  237. flags = DATE_SHORTDATE;
  238. //Use LOCALE_USE_CP_ACP to make sure that CP_ACP is used
  239. flags |= LOCALE_USE_CP_ACP;
  240. *szDateTime = 0;
  241. cchT = GetDateFormat(fForceWestern? LCID_WESTERN:LOCALE_USER_DEFAULT, flags, &st, NULL, szDateTime, cch);
  242. if (cchT == 0)
  243. return(0);
  244. //Don't do the rest of the stuff if we don't have atleast two chars. because we need to add space between date and time.
  245. //After that theres no point in calling GetTimeFormatW if there isn't atleast one char left.
  246. if (cchT <= (icch - 2))
  247. {
  248. flags = 0;
  249. if (tmtyp & ftmtypHours24)
  250. flags |= TIME_FORCE24HOURFORMAT;
  251. if (tmtyp & ftmtypAccuH)
  252. flags |= TIME_NOMINUTESORSECONDS;
  253. else if (!(tmtyp & ftmtypAccuHMS))
  254. flags |= TIME_NOSECONDS;
  255. // Tack on a space and then the time.
  256. // GetDateFormat returns count of chars INCLUDING the NULL terminator, hence the - 1
  257. szTime = szDateTime + (cchT - 1);
  258. *szTime++ = ' ';
  259. *szTime = 0;
  260. //Use LOCALE_USE_CP_ACP to make sure that CP_ACP is used
  261. flags|= LOCALE_USE_CP_ACP;
  262. cchT = GetTimeFormat(fForceWestern? LCID_WESTERN:LOCALE_USER_DEFAULT, flags, &st, NULL, szTime, (cch - cchT));
  263. }
  264. else
  265. cchT = 0;
  266. return(cchT == 0 ? 0 : lstrlen(szDateTime));
  267. }
  268. /*
  269. - GetCurDateTime
  270. -
  271. * Purpose:
  272. * Gets the current system date/time from the OS, and stores it
  273. * as an expanded date/time in *pdtr.
  274. *
  275. * Parameters:
  276. * pdtr Pointer to the DTR used to store the date/time.
  277. *
  278. * Returns:
  279. * void
  280. *
  281. */
  282. void GetCurDateTime(PDTR pdtr)
  283. {
  284. SYSTEMTIME SystemTime;
  285. GetLocalTime(&SystemTime);
  286. pdtr->hr= SystemTime.wHour;
  287. pdtr->mn= SystemTime.wMinute;
  288. pdtr->sec= SystemTime.wSecond;
  289. pdtr->day = SystemTime.wDay;
  290. pdtr->mon = SystemTime.wMonth;
  291. pdtr->yr = SystemTime.wYear;
  292. pdtr->dow = SystemTime.wDayOfWeek;
  293. }
  294. BOOL GetDowDateFormat(char *sz, int cch)
  295. {
  296. char szDow[] = "ddd ";
  297. Assert(cch > sizeof(szDow));
  298. StrCpyN(sz, szDow, cch);
  299. //Use LOCALE_USE_CP_ACP to make sure that CP_ACP is used
  300. return(0 != GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE | LOCALE_USE_CP_ACP,
  301. &sz[4], cch - 4));
  302. }
  303. //
  304. // CompareSystime
  305. //
  306. // returns 0 if *pst1 == *pst2 (ignores milliseconds)
  307. // returns <0 if *pst1 < *pst2
  308. // return >0 if *pst1 > *pst2
  309. //
  310. int CompareSystime(SYSTEMTIME *pst1, SYSTEMTIME *pst2)
  311. {
  312. int iRet;
  313. if ((iRet = pst1->wYear - pst2->wYear) == 0)
  314. {
  315. if ((iRet = pst1->wMonth - pst2->wMonth) == 0)
  316. {
  317. if ((iRet = pst1->wDay - pst2->wDay) == 0)
  318. {
  319. if ((iRet = pst1->wHour - pst2->wHour) == 0)
  320. {
  321. if ((iRet = pst1->wMinute - pst2->wMinute) == 0)
  322. iRet = pst1->wSecond - pst2->wSecond;
  323. }
  324. }
  325. }
  326. }
  327. return(iRet);
  328. }
  329. OESTDAPI_(INT) CchFileTimeToDateTimeW(FILETIME * pft, WCHAR * wszDateTime,
  330. int cch, DWORD dwFlags,
  331. PFGETDATEFORMATW pfGetDateFormatW,
  332. PFGETTIMEFORMATW pfGetTimeFormatW,
  333. PFGETLOCALEINFOW pfGetLocaleInfoW)
  334. {
  335. int iret;
  336. FILETIME ft;
  337. DTTYP dttyp;
  338. TMTYP tmtyp;
  339. DTR dtr;
  340. SYSTEMTIME st;
  341. WCHAR wszFmt[CCHMAX_DOWDATEFMT];
  342. // Put the file time in our time zone.
  343. if (!(dwFlags & DTM_NOTIMEZONEOFFSET))
  344. FileTimeToLocalFileTime(pft, &ft);
  345. else
  346. ft = *pft;
  347. FileTimeToSystemTime(&ft, &st);
  348. if (dwFlags & DTM_DOWSHORTDATE)
  349. {
  350. Assert((dwFlags & DTM_DOWSHORTDATE) == DTM_DOWSHORTDATE);
  351. if (GetDowDateFormatW(wszFmt, ARRAYSIZE(wszFmt), pfGetLocaleInfoW))
  352. iret = pfGetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, wszFmt, wszDateTime, cch);
  353. else
  354. iret = 0;
  355. return(iret);
  356. }
  357. dtr.yr = st.wYear;
  358. dtr.mon = st.wMonth;
  359. dtr.day = st.wDay;
  360. dtr.hr = st.wHour;
  361. dtr.mn = st.wMinute;
  362. dtr.sec = st.wSecond;
  363. dtr.dow = st.wDayOfWeek;
  364. dttyp = ((dwFlags & DTM_LONGDATE) ? dttypLong : dttypShort);
  365. tmtyp = ((dwFlags & DTM_NOSECONDS) ? ftmtypAccuHM : ftmtypAccuHMS);
  366. if (dwFlags & DTM_NODATE)
  367. {
  368. iret = CchFmtTimeW(&dtr, wszDateTime, cch, tmtyp, pfGetTimeFormatW);
  369. }
  370. else if (dwFlags & DTM_NOTIME)
  371. {
  372. iret = CchFmtDateW(&dtr, wszDateTime, cch, dttyp, NULL, pfGetDateFormatW);
  373. }
  374. else
  375. {
  376. //For the formatted date, DTM_FORCEWESTERN flag returns English date and time.
  377. //Without DTM_FORCEWESTERN the formatted time may not be representable in ASCII.
  378. iret = CchFmtDateTimeW(&dtr, wszDateTime, cch, dttyp, tmtyp,
  379. dwFlags & DTM_FORCEWESTERN, pfGetDateFormatW,
  380. pfGetTimeFormatW);
  381. }
  382. return(iret);
  383. }
  384. CCH CchFmtTimeW( PDTR pdtr, LPWSTR wszBuf, CCH cchBuf, TMTYP tmtyp,
  385. PFGETTIMEFORMATW pfGetTimeFormatW)
  386. {
  387. DWORD flags;
  388. int cch;
  389. SYSTEMTIME st;
  390. if ( cchBuf == 0 )
  391. {
  392. AssertSz ( fFalse, "0-length buffer passed to CchFmtTime" );
  393. return 0;
  394. }
  395. Assert(wszBuf);
  396. if (pdtr == NULL)
  397. {
  398. GetLocalTime(&st);
  399. }
  400. else
  401. {
  402. // Bullet raid #3143
  403. // Validate data. Set to minimums if invalid.
  404. Assert(pdtr->hr >= 0 && pdtr->hr < 24);
  405. Assert(pdtr->mn >= 0 && pdtr->mn < 60);
  406. Assert(pdtr->sec >= 0 && pdtr->sec < 60);
  407. // GetTimeFormat doesn't like invalid values
  408. ZeroMemory(&st, sizeof(SYSTEMTIME));
  409. st.wMonth = 1;
  410. st.wDay = 1;
  411. st.wHour = pdtr->hr;
  412. st.wMinute = pdtr->mn;
  413. st.wSecond = pdtr->sec;
  414. }
  415. Assert((tmtyp & ftmtypHours24) == 0);
  416. if ( tmtyp & ftmtypAccuHMS )
  417. flags = 0;
  418. else if ( tmtyp & ftmtypAccuH )
  419. flags = TIME_NOMINUTESORSECONDS;
  420. else
  421. flags = TIME_NOSECONDS; // default value
  422. cch = pfGetTimeFormatW(LOCALE_USER_DEFAULT, flags, &st, NULL, wszBuf, cchBuf);
  423. return((cch == 0) ? 0 : (cch - 1));
  424. }
  425. CCH CchFmtDateW( PDTR pdtr, LPWSTR wszBuf, CCH cchBuf, DTTYP dttyp, LPWSTR wszDatePicture,
  426. PFGETDATEFORMATW pfGetDateFormatW)
  427. {
  428. SYSTEMTIME st={0};
  429. int cch;
  430. DTR dtr;
  431. DWORD flags;
  432. Assert(wszBuf);
  433. if (!cchBuf)
  434. {
  435. AssertSz ( fFalse, "0-length buffer passed to CchFmtDate" );
  436. return 0;
  437. }
  438. if (!pdtr)
  439. {
  440. pdtr = &dtr;
  441. GetCurDateTime ( pdtr );
  442. }
  443. else
  444. {
  445. // Bullet raid #3143
  446. // Validate data. Set to minimums if invalid.
  447. if (pdtr->yr < nMinDtrYear || pdtr->yr >= nMacDtrYear)
  448. pdtr->yr = nMinDtrYear;
  449. if (pdtr->mon <= 0 || pdtr->mon > 12)
  450. pdtr->mon = 1;
  451. if (pdtr->day <= 0 || pdtr->day > 31)
  452. pdtr->day = 1;
  453. if (pdtr->dow < 0 || pdtr->dow >= 7)
  454. pdtr->dow = 0;
  455. }
  456. Assert ( pdtr );
  457. Assert ( pdtr->yr >= nMinDtrYear && pdtr->yr < nMacDtrYear );
  458. Assert ( pdtr->mon > 0 && pdtr->mon <= 12 );
  459. Assert ( pdtr->day > 0 && pdtr->day <= 31 );
  460. Assert((dttyp == dttypShort) || (dttyp == dttypLong));
  461. // TODO: handle dttypSplSDayShort properly...
  462. flags = 0;
  463. if (dttyp == dttypLong)
  464. flags = flags | DATE_LONGDATE;
  465. st.wYear = pdtr->yr;
  466. st.wMonth = pdtr->mon;
  467. st.wDay = pdtr->day;
  468. st.wDayOfWeek = 0;
  469. cch = pfGetDateFormatW(LOCALE_USER_DEFAULT, flags, &st, NULL, wszBuf, cchBuf);
  470. return((cch == 0) ? 0 : (cch - 1));
  471. }
  472. CCH CchFmtDateTimeW( PDTR pdtr, LPWSTR wszDateTime, CCH cch, DTTYP dttyp, TMTYP tmtyp,
  473. BOOL fForceWestern, PFGETDATEFORMATW pfGetDateFormatW,
  474. PFGETTIMEFORMATW pfGetTimeFormatW)
  475. {
  476. int cchT;
  477. LPWSTR wszTime;
  478. DWORD flags;
  479. SYSTEMTIME st={0};
  480. int icch = cch;
  481. st.wYear = pdtr->yr;
  482. st.wMonth = pdtr->mon;
  483. st.wDay = pdtr->day;
  484. st.wHour = pdtr->hr;
  485. st.wMinute = pdtr->mn;
  486. st.wSecond = pdtr->sec;
  487. Assert (LCID_WESTERN == 0x409);
  488. Assert((dttyp == dttypShort) || (dttyp == dttypLong));
  489. if (dttyp == dttypLong)
  490. flags = DATE_LONGDATE;
  491. else
  492. flags = DATE_SHORTDATE;
  493. *wszDateTime = 0;
  494. cchT = pfGetDateFormatW(fForceWestern? LCID_WESTERN:LOCALE_USER_DEFAULT, flags, &st, NULL, wszDateTime, cch);
  495. if (cchT == 0)
  496. return(0);
  497. //Don't do the rest of the stuff if we don't have atleast two chars. because we need to add space between date and time.
  498. //After that theres no point in calling GetTimeFormatW if there isn't atleast one char left.
  499. if (cchT <= (icch - 2))
  500. {
  501. flags = 0;
  502. if (tmtyp & ftmtypHours24)
  503. flags |= TIME_FORCE24HOURFORMAT;
  504. if (tmtyp & ftmtypAccuH)
  505. flags |= TIME_NOMINUTESORSECONDS;
  506. else if (!(tmtyp & ftmtypAccuHMS))
  507. flags |= TIME_NOSECONDS;
  508. // Tack on a space and then the time.
  509. // GetDateFormat returns count of chars INCLUDING the NULL terminator, hence the - 1
  510. wszTime = wszDateTime + (lstrlenW(wszDateTime));
  511. *wszTime++ = L' ';
  512. *wszTime = 0;
  513. cchT = pfGetTimeFormatW(fForceWestern? LCID_WESTERN:LOCALE_USER_DEFAULT, flags, &st, NULL, wszTime, (cch - cchT));
  514. }
  515. else
  516. cchT = 0;
  517. return(cchT == 0 ? 0 : lstrlenW(wszDateTime));
  518. }
  519. BOOL GetDowDateFormatW(WCHAR *wsz, int cch, PFGETLOCALEINFOW pfGetLocaleInfoW)
  520. {
  521. WCHAR wszDow[] = L"ddd ";
  522. Assert(cch > sizeof(wszDow));
  523. StrCpyNW(wsz, wszDow, cch);
  524. return(0 != (pfGetLocaleInfoW)(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE,
  525. &wsz[4], cch - 4));
  526. }