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.

812 lines
19 KiB

  1. /*++
  2. Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. calendar.c
  5. Abstract:
  6. This module implements the calendar control for the Date/Time applet.
  7. Revision History:
  8. --*/
  9. //
  10. // Include Files.
  11. //
  12. #include "timedate.h"
  13. #include "rc.h"
  14. //
  15. // Constant Declarations.
  16. //
  17. #define DEF_FIRST_WEEKDAY (6)
  18. #define cBorderX 5
  19. #define cBorderY 3
  20. #define cBorderSelect 1
  21. #define IS_FE_LANGUAGE(p) (((p) == LANG_CHINESE) || \
  22. ((p) == LANG_JAPANESE) || \
  23. ((p) == LANG_KOREAN))
  24. //
  25. // Typedef Declarations.
  26. //
  27. //
  28. // Struture for global data.
  29. //
  30. typedef struct _CALINFO
  31. {
  32. HWND hwnd; // the hwnd
  33. HFONT hfontCal; // the font to use
  34. BOOL fFocus; // do we have the focus
  35. int cxBlank; // size of a blank
  36. int cxChar; // the width of digits
  37. int cyChar; // the height of digits
  38. } CALINFO, *PCALINFO;
  39. ////////////////////////////////////////////////////////////////////////////
  40. //
  41. // GetFirstDayOfAnyWeek
  42. //
  43. // For this function ONLY:
  44. // 0 = Monday
  45. // 6 = Sunday
  46. //
  47. ////////////////////////////////////////////////////////////////////////////
  48. int GetFirstDayOfAnyWeek()
  49. {
  50. static int iDay = -1;
  51. if (iDay < 0)
  52. {
  53. TCHAR ch[2] = { 0 };
  54. *ch = TEXT('0') + DEF_FIRST_WEEKDAY;
  55. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, ch, 2);
  56. iDay = ( ((*ch >= TEXT('0')) && (*ch <= TEXT('6')))
  57. ? ((int)*ch - TEXT('0'))
  58. : DEF_FIRST_WEEKDAY );
  59. }
  60. return (iDay);
  61. }
  62. ////////////////////////////////////////////////////////////////////////////
  63. //
  64. // GetLocalWeekday
  65. //
  66. ////////////////////////////////////////////////////////////////////////////
  67. int GetLocalWeekday()
  68. {
  69. //
  70. // Convert local first day to 0==sunday and subtract from today.
  71. //
  72. return ((wDateTime[WEEKDAY] + 7 - ((GetFirstDayOfAnyWeek() + 1) % 7)) % 7);
  73. }
  74. void DetermineDayOfWeek()
  75. {
  76. FILETIME FileTime;
  77. SYSTEMTIME SystemTime;
  78. SystemTime.wHour = wDateTime[HOUR];
  79. SystemTime.wMinute = wDateTime[MINUTE];
  80. SystemTime.wSecond = wDateTime[SECOND];
  81. SystemTime.wMilliseconds = 0;
  82. SystemTime.wMonth = wDateTime[MONTH];
  83. SystemTime.wDay = wDateTime[DAY];
  84. SystemTime.wYear = wDateTime[YEAR];
  85. SystemTimeToFileTime(&SystemTime, &FileTime);
  86. FileTimeToSystemTime(&FileTime, &SystemTime);
  87. wDateTime[WEEKDAY] = SystemTime.wDayOfWeek;
  88. }
  89. ////////////////////////////////////////////////////////////////////////////
  90. //
  91. // GetFirstDayOfTheMonth
  92. //
  93. ////////////////////////////////////////////////////////////////////////////
  94. int GetFirstDayOfTheMonth()
  95. {
  96. DetermineDayOfWeek();
  97. return ((GetLocalWeekday() + 8 - (wDateTime[DAY] % 7)) % 7);
  98. }
  99. ////////////////////////////////////////////////////////////////////////////
  100. //
  101. // GetDaysOfTheMonth
  102. //
  103. ////////////////////////////////////////////////////////////////////////////
  104. int GetDaysOfTheMonth(
  105. int iMonth)
  106. {
  107. int cDays;
  108. int nYear;
  109. //
  110. // Calculate the number of days in the current month -
  111. // add one if this is a leap year and the month is February.
  112. //
  113. if (iMonth <= 7)
  114. {
  115. cDays = 30 + (iMonth % 2);
  116. }
  117. else
  118. {
  119. cDays = 31 - (iMonth % 2);
  120. }
  121. if (iMonth == 2)
  122. {
  123. cDays = 28;
  124. nYear = wDateTime[YEAR];
  125. if ((nYear % 4 == 0) && ((nYear % 100 != 0) || (nYear % 400 == 0)))
  126. {
  127. cDays++;
  128. }
  129. }
  130. return (cDays);
  131. }
  132. ////////////////////////////////////////////////////////////////////////////
  133. //
  134. // AdjustDeltaDay
  135. //
  136. // Adjust the day part of the current date
  137. //
  138. ////////////////////////////////////////////////////////////////////////////
  139. void AdjustDeltaDay(
  140. HWND hwnd,
  141. int iDay)
  142. {
  143. GetTime();
  144. if (wDateTime[DAY] != iDay)
  145. {
  146. wPrevDateTime[DAY] = wDateTime[DAY] = (WORD)iDay;
  147. fDateDirty = TRUE;
  148. //
  149. // Let our parent know that we changed.
  150. //
  151. FORWARD_WM_COMMAND( GetParent(hwnd),
  152. GetWindowLong(hwnd, GWL_ID),
  153. hwnd,
  154. CBN_SELCHANGE,
  155. SendMessage );
  156. }
  157. }
  158. int GetCalendarName(LPTSTR pszName, int cch)
  159. {
  160. TCHAR szDateString[100];
  161. SYSTEMTIME SystemTime;
  162. int cchResult = 0;
  163. SystemTime.wHour = wDateTime[HOUR];
  164. SystemTime.wMinute = wDateTime[MINUTE];
  165. SystemTime.wSecond = wDateTime[SECOND];
  166. SystemTime.wMilliseconds = 0;
  167. SystemTime.wMonth = wDateTime[MONTH];
  168. SystemTime.wDay = wDateTime[DAY];
  169. SystemTime.wYear = wDateTime[YEAR];
  170. if (0 != GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE,
  171. &SystemTime, NULL, szDateString, ARRAYSIZE(szDateString)))
  172. {
  173. if (pszName)
  174. lstrcpyn( pszName, szDateString, cch);
  175. cchResult = lstrlen(szDateString);
  176. }
  177. return cchResult;
  178. }
  179. ////////////////////////////////////////////////////////////////////////////
  180. //
  181. // ChangeCurrentDate
  182. //
  183. // If we pass in iNewCol < 0, we simply want to invalidate todays date.
  184. // This is used when we gain and lose focus.
  185. //
  186. ////////////////////////////////////////////////////////////////////////////
  187. void ChangeCurrentDate(
  188. PCALINFO pci,
  189. int iNewCol,
  190. int iNewRow)
  191. {
  192. int iFirstDay, iRow, iColumn;
  193. RECT rc, rcT;
  194. GetClientRect(pci->hwnd, &rc);
  195. iFirstDay = GetFirstDayOfTheMonth();
  196. iColumn = (wDateTime[DAY] - 1 + iFirstDay) % 7;
  197. iRow = 1 + ((wDateTime[DAY] - 1 + iFirstDay) / 7);
  198. rcT.left = (((rc.right - rc.left) * iColumn) / 7) + cBorderX - cBorderSelect;
  199. rcT.right = rcT.left + (pci->cxChar * 2) + (2 * cBorderSelect);
  200. rcT.top = ((rc.bottom - rc.top) * iRow ) / 7 + cBorderY - cBorderSelect;
  201. rcT.bottom = rcT.top + pci->cyChar + (2 * cBorderSelect);
  202. InvalidateRect(pci->hwnd, &rcT, FALSE);
  203. if (iNewCol >= 0)
  204. {
  205. AdjustDeltaDay(pci->hwnd, ((iNewRow - 1) * 7) + iNewCol + 1 - iFirstDay);
  206. }
  207. }
  208. ////////////////////////////////////////////////////////////////////////////
  209. //
  210. // CalendarPaint
  211. //
  212. ////////////////////////////////////////////////////////////////////////////
  213. #ifdef UNICODE
  214. #define NUM_DBCS_CHARS 1 // 1 Unicode char
  215. #else
  216. #define NUM_DBCS_CHARS 2 // 1 lead byte, 1 trail byte
  217. #endif
  218. BOOL CalendarPaint(
  219. PCALINFO pci,
  220. HWND hwnd)
  221. {
  222. RECT rc, rcT;
  223. PAINTSTRUCT ps;
  224. HDC hdc;
  225. int iWeek, iWeekDay, iDay, iMaxDays;
  226. int iFirstDayOfWeek, iFirstDayOfMonth;
  227. TCHAR pszDate[3];
  228. TCHAR szShortDay[25];
  229. DWORD dwbkColor;
  230. COLORREF o_TextColor;
  231. LCID Locale;
  232. LANGID LangID = GetUserDefaultLangID();
  233. BOOL IsFELang = IS_FE_LANGUAGE(PRIMARYLANGID(LangID));
  234. iFirstDayOfMonth = GetFirstDayOfTheMonth();
  235. iMaxDays = GetDaysOfTheMonth(wDateTime[MONTH]);
  236. iDay = 1;
  237. pszDate[0] = TEXT(' ');
  238. pszDate[1] = TEXT('0');
  239. //
  240. // Paint the background of the dates page.
  241. //
  242. hdc = BeginPaint(hwnd, &ps);
  243. GetClientRect(hwnd, &rc);
  244. FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
  245. //
  246. // The day specifier.
  247. //
  248. rcT.left = rc.left;
  249. rcT.right = rc.right;
  250. rcT.top = rc.top;
  251. rcT.bottom = rc.top + ((rc.bottom - rc.top) / 7);
  252. FillRect(hdc, &rcT, GetSysColorBrush(COLOR_INACTIVECAPTION));
  253. //
  254. // Fill the page.
  255. //
  256. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  257. SelectFont(hdc, pci->hfontCal);
  258. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  259. //
  260. // See if we need to calculate the size of characters.
  261. //
  262. if (pci->cxChar == 0)
  263. {
  264. DrawText(hdc, TEXT("0"), 1, &rcT, DT_CALCRECT);
  265. pci->cxChar = rcT.right - rcT.left;
  266. pci->cyChar = rcT.bottom - rcT.top;
  267. DrawText(hdc, TEXT(" "), 1, &rcT, DT_CALCRECT);
  268. pci->cxBlank = rcT.right - rcT.left;
  269. }
  270. for (iWeek = 1; (iWeek < 7); iWeek++)
  271. {
  272. for (iWeekDay = iFirstDayOfMonth;
  273. (iWeekDay < 7) && (iDay <= iMaxDays);
  274. iWeekDay++)
  275. {
  276. rcT.left = ((((rc.right - rc.left) * iWeekDay) / 7)) + cBorderX;
  277. rcT.top = (((rc.bottom - rc.top) * iWeek) / 7) + cBorderY;
  278. rcT.right = rcT.left + 20;
  279. rcT.bottom = rcT.top + 20;
  280. if (pszDate[1] == TEXT('9'))
  281. {
  282. pszDate[1] = TEXT('0');
  283. if (pszDate[0] == TEXT(' '))
  284. {
  285. pszDate[0] = TEXT('1');
  286. }
  287. else
  288. {
  289. pszDate[0] = pszDate[0] + 1;
  290. }
  291. }
  292. else
  293. {
  294. pszDate[1] = pszDate[1] + 1;
  295. }
  296. if (wDateTime[DAY] == iDay)
  297. {
  298. dwbkColor = GetBkColor(hdc);
  299. SetBkColor(hdc, GetSysColor(COLOR_ACTIVECAPTION));
  300. o_TextColor = GetTextColor(hdc);
  301. SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
  302. }
  303. ExtTextOut( hdc,
  304. rcT.left,
  305. rcT.top,
  306. 0,
  307. &rcT,
  308. (LPTSTR)pszDate,
  309. 2,
  310. NULL );
  311. //
  312. // If we drew it inverted - put it back.
  313. //
  314. if (wDateTime[DAY] == iDay)
  315. {
  316. //
  317. // If we have the focus we also need to draw the focus
  318. // rectangle for this item.
  319. //
  320. if (pci->fFocus)
  321. {
  322. rcT.bottom = rcT.top + pci->cyChar;
  323. if (iDay <= 9)
  324. {
  325. rcT.right = rcT.left + pci->cxChar + pci->cxBlank;
  326. }
  327. else
  328. {
  329. rcT.right = rcT.left + 2 * pci->cxChar;
  330. }
  331. DrawFocusRect(hdc, &rcT);
  332. }
  333. SetBkColor(hdc, dwbkColor);
  334. SetTextColor(hdc, o_TextColor);
  335. }
  336. iFirstDayOfMonth = 0;
  337. iDay++;
  338. }
  339. }
  340. //
  341. // Set the FONT color for the SMTWTFS line.
  342. //
  343. dwbkColor = SetBkColor(hdc, GetSysColor(COLOR_INACTIVECAPTION));
  344. SetTextColor(hdc, GetSysColor(COLOR_INACTIVECAPTIONTEXT));
  345. iFirstDayOfWeek = GetFirstDayOfAnyWeek();
  346. if (!IsFELang)
  347. {
  348. //
  349. // Not a FE locale.
  350. //
  351. // If it's Arabic or Syriac, then we want to use the US locale to get the
  352. // first letter of the abbreviated day name to display in the calendar.
  353. //
  354. Locale = ((PRIMARYLANGID(LangID) == LANG_ARABIC) || (PRIMARYLANGID(LangID) == LANG_SYRIAC))
  355. ? MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)
  356. : LOCALE_USER_DEFAULT;
  357. for (iWeekDay = 0; (iWeekDay < 7); iWeekDay++)
  358. {
  359. GetLocaleInfo( Locale,
  360. LOCALE_SABBREVDAYNAME1 + (iWeekDay + iFirstDayOfWeek) % 7,
  361. szShortDay,
  362. sizeof(szShortDay) / sizeof(TCHAR) );
  363. if (*szShortDay)
  364. {
  365. *szShortDay = (TCHAR)CharUpper((LPTSTR)(DWORD_PTR)*szShortDay);
  366. }
  367. TextOut( hdc,
  368. (((rc.right - rc.left) * iWeekDay) / 7) + cBorderX,
  369. cBorderY,
  370. szShortDay,
  371. 1 );
  372. }
  373. }
  374. else
  375. {
  376. //
  377. // FE Locale.
  378. //
  379. for (iWeekDay = 0; (iWeekDay < 7); iWeekDay++)
  380. {
  381. GetLocaleInfo( LOCALE_USER_DEFAULT,
  382. LOCALE_SABBREVDAYNAME1 + (iWeekDay + iFirstDayOfWeek) % 7,
  383. szShortDay,
  384. sizeof(szShortDay) / sizeof(TCHAR) );
  385. #ifndef UNICODE
  386. if (*szShortDay && !IsDBCSLeadByte(*szShortDay))
  387. #else
  388. if (*szShortDay)
  389. #endif
  390. {
  391. *szShortDay = (TCHAR)CharUpper((LPTSTR)(DWORD_PTR)*szShortDay);
  392. }
  393. if ((PRIMARYLANGID(LangID) == LANG_CHINESE) &&
  394. (lstrlen(szShortDay) == 3 * NUM_DBCS_CHARS))
  395. {
  396. TextOut( hdc,
  397. (((rc.right - rc.left) * iWeekDay) / 7) + cBorderX,
  398. cBorderY,
  399. (LangID == MAKELANGID( LANG_CHINESE,
  400. SUBLANG_CHINESE_HONGKONG ))
  401. ? szShortDay
  402. : szShortDay + (2 * NUM_DBCS_CHARS),
  403. 1 * NUM_DBCS_CHARS );
  404. }
  405. else
  406. {
  407. TextOut( hdc,
  408. (((rc.right - rc.left) * iWeekDay) / 7) + cBorderX,
  409. cBorderY,
  410. szShortDay,
  411. lstrlen(szShortDay) );
  412. }
  413. }
  414. }
  415. SetBkColor(hdc, dwbkColor);
  416. EndPaint(hwnd, &ps);
  417. return (TRUE);
  418. }
  419. ////////////////////////////////////////////////////////////////////////////
  420. //
  421. // IsValidClick
  422. //
  423. ////////////////////////////////////////////////////////////////////////////
  424. BOOL IsValidClick(
  425. HWND hwnd,
  426. int x,
  427. int y)
  428. {
  429. int iT;
  430. if (y == 0)
  431. {
  432. return (FALSE);
  433. }
  434. iT = GetFirstDayOfTheMonth();
  435. if ((y == 1) && (x < iT))
  436. {
  437. return (FALSE);
  438. }
  439. iT += GetDaysOfTheMonth(wDateTime[MONTH]) - 1;
  440. if (y > ((iT / 7) + 1))
  441. {
  442. return (FALSE);
  443. }
  444. if ((y == ((iT / 7) + 1)) && (x > (iT % 7)))
  445. {
  446. return (FALSE);
  447. }
  448. return (TRUE);
  449. }
  450. ////////////////////////////////////////////////////////////////////////////
  451. //
  452. // HandleDateChange
  453. //
  454. ////////////////////////////////////////////////////////////////////////////
  455. BOOL HandleDateChange(
  456. PCALINFO pci,
  457. int x,
  458. int y)
  459. {
  460. RECT rc, rcT;
  461. int ix, iy;
  462. GetClientRect(pci->hwnd, &rc);
  463. ix = (x * 7) / (rc.right - rc.left);
  464. iy = (y * 7) / (rc.bottom - rc.top);
  465. if (IsValidClick(pci->hwnd, ix, iy))
  466. {
  467. rcT.left = (((rc.right - rc.left) * ix)/ 7) + cBorderX - cBorderSelect;
  468. rcT.right = rcT.left + (2 * pci->cxChar) + (2 * cBorderSelect);
  469. rcT.top = ((rc.bottom - rc.top) * iy) / 7 + cBorderY - cBorderSelect;
  470. rcT.bottom = rcT.top + pci->cyChar + (2 * cBorderSelect);
  471. InvalidateRect(pci->hwnd, &rcT, FALSE);
  472. ChangeCurrentDate( pci,
  473. (x * 7) / (rc.right - rc.left),
  474. (y * 7) / (rc.bottom - rc.top) );
  475. NotifyWinEvent(EVENT_OBJECT_NAMECHANGE , pci->hwnd, OBJID_WINDOW, CHILDID_SELF);
  476. return (TRUE);
  477. }
  478. else
  479. {
  480. return (FALSE);
  481. }
  482. }
  483. ////////////////////////////////////////////////////////////////////////////
  484. //
  485. // HandleKeyDown
  486. //
  487. ////////////////////////////////////////////////////////////////////////////
  488. void HandleKeyDown(
  489. PCALINFO pci,
  490. int vk,
  491. LPARAM lParam)
  492. {
  493. RECT rcT;
  494. //
  495. // First thing, lets try to figure out what the current x and y is.
  496. //
  497. int ix = GetLocalWeekday();
  498. int iy = (wDateTime[DAY] + GetFirstDayOfTheMonth() - 1) / 7;
  499. switch (vk)
  500. {
  501. case ( VK_LEFT ) :
  502. {
  503. ix--;
  504. if (ix < 0)
  505. {
  506. ix = 6;
  507. iy--;
  508. }
  509. break;
  510. }
  511. case ( VK_RIGHT ) :
  512. {
  513. ix++;
  514. if (ix == 7)
  515. {
  516. ix = 0;
  517. iy++;
  518. }
  519. break;
  520. }
  521. case ( VK_UP ) :
  522. {
  523. iy--;
  524. break;
  525. }
  526. case ( VK_DOWN ) :
  527. {
  528. iy++;
  529. break;
  530. }
  531. default :
  532. {
  533. //
  534. // Ignore the character.
  535. //
  536. return;
  537. }
  538. }
  539. //
  540. // The y's are offset for the days of the week.
  541. //
  542. iy++;
  543. if (!IsValidClick(pci->hwnd, ix, iy))
  544. {
  545. return;
  546. }
  547. GetClientRect(pci->hwnd, &rcT);
  548. rcT.left = ((rcT.right * ix) / 7) + cBorderX - cBorderSelect;
  549. rcT.right = rcT.left + (2 * pci->cxChar) + (2 * cBorderSelect);
  550. rcT.top = (rcT.bottom * iy) / 7 + cBorderY - cBorderSelect;
  551. rcT.bottom = rcT.top + pci->cyChar + (2 * cBorderSelect);
  552. InvalidateRect(pci->hwnd, &rcT, FALSE);
  553. //
  554. // First try, simply call to change the date.
  555. //
  556. ChangeCurrentDate(pci, ix, iy);
  557. NotifyWinEvent(EVENT_OBJECT_NAMECHANGE , pci->hwnd, OBJID_WINDOW, CHILDID_SELF);
  558. }
  559. ////////////////////////////////////////////////////////////////////////////
  560. //
  561. // CalWndProc
  562. //
  563. ////////////////////////////////////////////////////////////////////////////
  564. LRESULT CALLBACK CalWndProc(
  565. HWND hwnd,
  566. UINT message,
  567. WPARAM wParam,
  568. LPARAM lParam)
  569. {
  570. PCALINFO pci;
  571. pci = (PCALINFO)GetWindowLongPtr(hwnd, 0);
  572. switch (message)
  573. {
  574. case ( WM_CREATE ) :
  575. {
  576. pci = (PCALINFO)LocalAlloc(LPTR, sizeof(CALINFO));
  577. if (pci == 0)
  578. {
  579. return (-1);
  580. }
  581. pci->hwnd = hwnd;
  582. SetWindowLongPtr(hwnd, 0, (LONG_PTR)pci);
  583. GetDate();
  584. break;
  585. }
  586. case ( WM_NCDESTROY ) :
  587. {
  588. if (pci)
  589. {
  590. LocalFree((HLOCAL)pci);
  591. }
  592. break;
  593. }
  594. case ( WM_SETFONT ) :
  595. {
  596. if (wParam)
  597. {
  598. pci->hfontCal = (HFONT)wParam;
  599. pci->cxChar = 0;
  600. }
  601. break;
  602. }
  603. case ( WM_GETTEXT ) :
  604. {
  605. return GetCalendarName((LPTSTR)lParam, (int)wParam);
  606. }
  607. case ( WM_GETTEXTLENGTH ) :
  608. {
  609. return GetCalendarName(NULL, 0);
  610. }
  611. case ( WM_PAINT ) :
  612. {
  613. CalendarPaint(pci, hwnd);
  614. break;
  615. }
  616. case ( WM_LBUTTONDOWN ) :
  617. {
  618. SetFocus(hwnd);
  619. HandleDateChange(pci, LOWORD(lParam), HIWORD(lParam));
  620. break;
  621. }
  622. case ( WM_SETFOCUS ) :
  623. {
  624. pci->fFocus = TRUE;
  625. ChangeCurrentDate(pci, -1, -1);
  626. break;
  627. }
  628. case ( WM_KILLFOCUS ) :
  629. {
  630. pci->fFocus = FALSE;
  631. ChangeCurrentDate(pci, -1, -1);
  632. break;
  633. }
  634. case ( WM_KEYDOWN ) :
  635. {
  636. HandleKeyDown(pci, (int)wParam, lParam);
  637. break;
  638. }
  639. case ( WM_GETDLGCODE ) :
  640. {
  641. return (DLGC_WANTARROWS);
  642. break;
  643. }
  644. default :
  645. {
  646. return ( DefWindowProc(hwnd, message, wParam, lParam) );
  647. }
  648. }
  649. return (0);
  650. }
  651. ////////////////////////////////////////////////////////////////////////////
  652. //
  653. // CalendarInit
  654. //
  655. ////////////////////////////////////////////////////////////////////////////
  656. TCHAR const c_szCalClass[] = CALENDAR_CLASS;
  657. BOOL CalendarInit(
  658. HANDLE hInstance)
  659. {
  660. WNDCLASS wc;
  661. if (!GetClassInfo(hInstance, c_szCalClass, &wc))
  662. {
  663. wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  664. wc.cbClsExtra = 0;
  665. wc.cbWndExtra = sizeof(PCALINFO);
  666. wc.hCursor = NULL;
  667. wc.hbrBackground = NULL;
  668. wc.hIcon = NULL;
  669. wc.lpszMenuName = NULL;
  670. wc.lpszClassName = c_szCalClass;
  671. wc.hInstance = hInstance;
  672. wc.lpfnWndProc = CalWndProc;
  673. return (RegisterClass(&wc));
  674. }
  675. return (TRUE);
  676. }