/** FILE: date.c *********** Module Header ******************************** * * Control panel applet for Date/Time configuration. This file holds * everything to do with the "DateTime" dialog box in the Control * Panel. * * History: * 12:30 on Tues 23 Apr 1991 -by- Steve Cathcart [stevecat] * Took base code from Win 3.1 source * 10:30 on Tues 04 Feb 1992 -by- Steve Cathcart [stevecat] * Updated code to latest Win 3.1 sources * 12:30 on Tues 27 Oct 1992 -by- Steve Cathcart [stevecat] * Added TimeZone extensions * 22:00 on Wed 17 Nov 1993 -by- Steve Cathcart [stevecat] * Time Zone resources in registry * * Copyright (C) 1990-1993 Microsoft Corporation * *************************************************************************/ //========================================================================== // Include files //========================================================================== // C Runtime #include #include // Application specific #include "main.h" //========================================================================== // Local Definitions //========================================================================== // #define TZMAP //========================================================================== // External Declarations //========================================================================== //========================================================================== // Local Data Declarations //========================================================================== short wDeltaDateTime[6]; /* Amount of time change */ #ifdef JAPAN /* V-KeijiY June.29.1992 */ // need more space to hold strings // At least "GoZen" and "GoGo" TCHAR sz1159[TIMESUF_LEN]; TCHAR sz2359[TIMESUF_LEN]; #else TCHAR sz1159[4]; TCHAR sz2359[4]; #endif BOOL bAMPM; BOOL bPM; BOOL bPrefix; BOOL bDisplayMessage = FALSE; WORD wTimerOn; BOOL bLZero[6] = {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE}; ARROWVSCROLL avs[6] = { { 1, -1, 5, -5, 23, 0, 12, 12 }, { 1, -1, 5, -5, 59, 0, 30, 30 }, { 1, -1, 5, -5, 59, 0, 30, 30 }, { 1, -1, 4, -4, 12, 1, 0, 0 }, { 1, -1, 5, -5, 31, 1, 0, 0 }, { 1, -1, 10, -10, 2099, 1980, 1990, 1990 } }; #ifdef TZMAP // "World" memory bitmap variables HPALETTE hpalTZmap = NULL; HBITMAP hbmTZmap = NULL; HBITMAP hbmTZDefault = NULL; HBITMAP hbmBitmaps = NULL; HBITMAP hbmDefault = NULL; HDC hdcMem = NULL; HDC hdcTZmap = NULL; int iWidth, iHeight; // World bitmap width and height #endif // TZMAP LONG NumTimeZones = 0; PAPPLET_TIME_ZONE_INFORMATION Tzi; LPTIME_ZONE_INFORMATION SelectedTimeZone = NULL; TIME_ZONE_INFORMATION TimeZone; PAPPLET_TIME_ZONE_INFORMATION ptziOriginal; int iOriginalTimeZone; int iOrigButtonChecked; // Registry location for Time Zone information TCHAR *pszTimezones = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"); // Time Zone data value keys TCHAR *pszTZDisplayName = TEXT("Display"); TCHAR *pszTZDaylightName = TEXT("Dlt"); TCHAR *pszTZI = TEXT("TZI"); //========================================================================== // Local Function Prototypes //========================================================================== void DateTimeInit(HWND hDlg, WORD nBaseID, WORD nSepID, TCHAR *pszSep, int nMaxDigitWidth, BOOL bDate); VOID CentreWindow(HWND hwnd); LPVOID GetResPtr (int iResType); BOOL InitTimeZone (HWND hDlg); LONG PaintWorld (HWND hwndWorld, HDC hdcWorld); BOOL SetupWorld (HWND hWnd); VOID SetTheVirtualTimezone (HWND hDlg, int DaylightOption, PAPPLET_TIME_ZONE_INFORMATION ptzi); void UpdateItem (HWND hDlg, short i); //========================================================================== // Functions //========================================================================== /* ParseDateElement assumes that the character pointed to by pszElement is a 'M', 'd', or 'y', and checks if the string indicates a leading zero or century. The return value is a pointer to the next character, which should be a separator or NULL. A return value of NULL indicates an error. */ TCHAR *ParseDateElement (TCHAR *pszElement, BOOL *pbLZero) { switch (*pszElement) /* Check for valid character */ { case TEXT('y'): case TEXT('M'): case TEXT('d'): /* case TEXT('h'): case TEXT('m'): case TEXT('s'): */ break; default: return (NULL); } ++pszElement; if (*pszElement != *(pszElement - 1)) *pbLZero = 0; else { *pbLZero = 1; if (*pszElement++ == TEXT('y')) { if (!(*pszElement == TEXT('y'))) *pbLZero = 0; else if (!(*++pszElement == TEXT('y'))) return (NULL); /* Found 3 y's, invalid format */ else ++pszElement; } } return (pszElement); } /* AdjustDelta() alters the variables in wDeltaDateTime, allowing a CANCEL button to perform its job by resetting the time as if it had never been touched. GetTime() & GetDate() should already have been called. */ void AdjustDelta (HWND hDlg, short nIndex) { short nDelta; BOOL bOK; nDelta = (short) GetDlgItemInt (hDlg, DATETIME_HOUR + nIndex, (BOOL * ) &bOK, FALSE); GetDateTime (); if (nIndex == HOUR) { if (!bAMPM) { if (nDelta == 12) { if (!bPM) nDelta = 0; } else if (bPM) nDelta += 12; } } else if ((nIndex == YEAR) && !bLZero[YEAR]) { if (nDelta < 80) nDelta += 2000; else nDelta += 1900; // nDelta += wDateTime[YEAR] - wDateTime[YEAR] % 100; } else if ((nIndex == MONTH) || (nIndex == DAY)) { // // Check for invalid DAY or MONTH value // if (nDelta == 0) { // // Set it to current date value // UpdateItem (hDlg, nIndex); nDelta = wDateTime[nIndex]; } } if (wDateTime[nIndex] != nDelta) { wDeltaDateTime[nIndex] += nDelta - wDateTime[nIndex]; wPrevDateTime[nIndex] = wDateTime[nIndex] = nDelta; if (nIndex < 3) SetTime (); else SetDate (); } } short ReadShortDate (TCHAR *pszDate, BOOL *pbMonth, BOOL *pbDay, BOOL *pbYear) { short i, nOrder; BOOL *pbOrder[3]; TCHAR cHope[3]; switch (cHope[0] = *pszDate) { case TEXT('M'): nOrder = 0; pbOrder[0] = pbMonth; break; case TEXT('d'): nOrder = 1; pbOrder[0] = pbDay; break; case TEXT('y'): nOrder = 2; pbOrder[0] = pbYear; break; default: return (FALSE); } if (nOrder) { cHope[1] = TEXT('M'); pbOrder[1] = pbMonth; } else { cHope[1] = TEXT('d'); pbOrder[1] = pbDay; } if (nOrder == 2) { cHope[2] = TEXT('d'); pbOrder[2] = pbDay; } else { cHope[2] = TEXT('y'); pbOrder[2] = pbYear; } for (i = 0; i < 3; i++, pszDate++) { if (*pszDate != cHope[i]) return ((short) (-1 - nOrder)); if (!(pszDate = ParseDateElement (pszDate, pbOrder[i]))) return ((short) (-1 - nOrder)); } return (nOrder); /* Success. Return MDY, DMY or YMD index */ } /* Determine the widest digit (safety against variable pitch fonts) */ int GetMaxCharWidth (HDC hDC) { int *pNumWidth; int nNumWidth[10]; int nMaxNumWidth; GetCharWidth (hDC, (DWORD)TEXT('0'), (DWORD)TEXT('9'), (LPINT) nNumWidth); pNumWidth = nNumWidth + 1; for (nMaxNumWidth = nNumWidth[0]; pNumWidth < (int *) (nNumWidth + 10); pNumWidth++) { if (*pNumWidth > nMaxNumWidth) nMaxNumWidth = *pNumWidth; } return (nMaxNumWidth); } void DateTimeInit (hDlg, nBaseID, nSepID, pszSep, nMaxDigitWidth, bDate) HWND hDlg; WORD nBaseID; WORD nSepID; TCHAR *pszSep; int nMaxDigitWidth; BOOL bDate; { HWND hAMPMList, hwndTemp; HWND hDay, hMonth, hYear; // also used as hHour, hMinute, & hSecond HWND hOrder[5]; HDC hDC; short nWidth, nHeight, X; RECT Rect; int i; short nAMPMlength; BOOL bSuccess; SIZE TxtSize; TCHAR szMessage[256]; TCHAR szTemp[128]; short nSaveXpos; hMonth = GetDlgItem (hDlg, nBaseID); hDay = GetDlgItem (hDlg, nBaseID + 1); hYear = GetDlgItem (hDlg, nBaseID + 2); hOrder[1] = GetDlgItem (hDlg, nSepID); hOrder[3] = GetDlgItem (hDlg, nSepID + 1); if (bDate) { i = GetLocaleValue (0, LOCALE_IDATE, szTemp, CharSizeOf(szTemp), TEXT("0")); } else { if (!(bAMPM = (BOOL) GetLocaleValue (0, LOCALE_ITIME, szTemp, CharSizeOf(szTemp), TEXT("0")))) { bPrefix = GetLocaleValue (0, LOCALE_ITIMEMARKPOSN, szTemp, CharSizeOf(szTemp), TEXT("0")); GetLocaleValue (0, LOCALE_S1159, sz1159, CharSizeOf(sz1159), IntlDef.s1159); GetLocaleValue (0, LOCALE_S2359, sz2359, CharSizeOf(sz2359), IntlDef.s2359); } i = 0; } switch (i) { case 1: hOrder[0] = hDay; hOrder[2] = hMonth; hOrder[4] = hYear; break; case 2: hOrder[0] = hYear; hOrder[2] = hMonth; hOrder[4] = hDay; break; case 0: default: hOrder[0] = hMonth; hOrder[2] = hDay; hOrder[4] = hYear; break; } // Find the correct window for proper order for date controls and // for window positioning switch (nBaseID) { case DATETIME_HOUR: hwndTemp = GetDlgItem (hDlg, IDD_TZ_TIME); break; case DATETIME_MONTH: hwndTemp = GetDlgItem (hDlg, IDD_TZ_DATE); break; case IDD_TZ_SD_MONTH: hwndTemp = GetDlgItem (hDlg, IDD_TZ_SDATE); break; case IDD_TZ_ED_MONTH: hwndTemp = GetDlgItem (hDlg, IDD_TZ_EDATE); break; default: hwndTemp = hDlg; break; } if (bDate) { SetWindowPos (hOrder[0], hwndTemp, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW); SetWindowPos (hOrder[2], hOrder[0], 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW); SetWindowPos (hOrder[4], hOrder[2], 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW); } hDC = GetDC (hDlg); if (!bDate) { bSuccess = GetTextExtentPoint (hDC, sz2359, lstrlen (sz2359), &TxtSize); nAMPMlength = (short) TxtSize.cx; bSuccess = GetTextExtentPoint (hDC, sz1159, lstrlen (sz1159), &TxtSize); if (nAMPMlength < (short) TxtSize.cx) nAMPMlength = (short) TxtSize.cx; } #ifdef JAPAN //We need to add the borders of ListBox. // Bug#231 1992.10.27 by yutakas nAMPMlength += 2; #endif bSuccess = GetTextExtentPoint (hDC, pszSep, lstrlen (pszSep), &TxtSize); ReleaseDC (hDlg, hDC); GetWindowRect (hYear, (LPRECT) &Rect); ScreenToClient (hDlg, (LPPOINT) &Rect.left); ScreenToClient (hDlg, (LPPOINT) &Rect.right); nHeight = (short) (Rect.bottom - Rect.top); nWidth = (short) Rect.top; GetWindowRect (hwndTemp, (LPRECT) &Rect); ScreenToClient (hDlg, (LPPOINT) &Rect.left); ScreenToClient (hDlg, (LPPOINT) &Rect.right); Rect.top = (long) nWidth; X = (short) ((Rect.left + Rect.right - 6 * nMaxDigitWidth - 2 * TxtSize.cx) / 2); if (bDate) { if (bLZero[YEAR]) X -= (short) nMaxDigitWidth; } else if (!bAMPM) { if (bPrefix) { nSaveXpos = X - nAMPMlength / 2; X = nSaveXpos + nAMPMlength; } else X -= nAMPMlength / 2; } for (i = 0; i < 5; i++) { nWidth = (short) ((i % 2) ? TxtSize.cx : 2 * nMaxDigitWidth); if ((hOrder[i] == hYear) && bDate && bLZero[YEAR]) nWidth *= 2; nWidth += 2; /* allow for centering in edit control*/ MoveWindow (hOrder[i], X, Rect.top, nWidth, nHeight, FALSE); X += nWidth; } hAMPMList = GetDlgItem (hDlg, DATETIME_AMPM); if (!bDate && !bAMPM) { if (bPrefix) X = nSaveXpos; MoveWindow (hAMPMList, X, Rect.top, nAMPMlength, nHeight, FALSE); SendMessage (hAMPMList, LB_INSERTSTRING, (WPARAM)(LONG) -1, (LPARAM)sz1159); SendMessage (hAMPMList, LB_INSERTSTRING, (WPARAM)(LONG)-1, (LPARAM)sz2359); SendMessage (hAMPMList, LB_SETCURSEL, (WPARAM)(LONG)-1, 0); } EnableWindow (hAMPMList, !bAMPM); SendMessage (hYear, EM_LIMITTEXT, (bDate && bLZero[YEAR]) ? 4 : 2, 0L); SendMessage (hMonth, EM_LIMITTEXT, 2, 0L); SendMessage (hDay, EM_LIMITTEXT, 2, 0L); SetDlgItemText (hDlg, nSepID, pszSep); SetDlgItemText (hDlg, nSepID + 1, pszSep); // If running under "Setup" display helpful message // and disable "Cancel" if (bDisplayMessage) { if (LoadString (hModule, DATE+9, szMessage, CharSizeOf(szMessage)-2)) { SetDlgItemText (hDlg, DATETIME_MSG, szMessage); } EnableWindow (GetDlgItem (hDlg, PUSH_CANCEL), FALSE); } } BOOL CheckNum (HWND hDlg, WORD nID) { short i; TCHAR szNum[5]; BOOL bReturn; INT iVal; bReturn = TRUE; GetDlgItemText (hDlg, nID, szNum, CharSizeOf(szNum)); for (i = 0; szNum[i]; i++) if (!_istdigit (szNum[i])) return (FALSE); iVal = MyAtoi(szNum); switch (nID) { case DATETIME_HOUR: if (iVal > 23) bReturn = FALSE; break; case DATETIME_MINUTE: case DATETIME_SECOND: if (iVal > 59) bReturn = FALSE; break; case DATETIME_MONTH: if (iVal > 12) bReturn = FALSE; break; case DATETIME_DAY: if (iVal > 31) bReturn = FALSE; break; } return (bReturn); } short MonthUpperBound (short nMonth, short nYear) { switch (nMonth) { case 2: /* The following line accounts for leap years every 400 years and * every 4 years, except every 100 years. */ return ((short) (!(nYear % 400) || ((nYear % 100) && !(nYear % 4)) ? 29 : 28)); break; case 4: case 6: case 9: case 11: return (30); break; } return (31); } void UpdateItem (HWND hDlg, short i) { TCHAR szNum[5]; short nNum = wDateTime[i]; if (i == YEAR) { if (!bLZero[i]) nNum %= 100; } else if ((i == HOUR) && !bAMPM) { bPM = (nNum >= 12) ? 1 : 0; SendDlgItemMessage (hDlg, DATETIME_AMPM, LB_SETTOPINDEX, bPM, 0L); if (bPM) nNum -= 12; if (!nNum) nNum = 12; } if ((nNum < 10) && (bLZero[i] || (i == YEAR))) { szNum[0] = TEXT('0'); szNum[1] = (TCHAR)(TEXT('0') + nNum); szNum[2] = TEXT('\0'); } else MyItoa (nNum, szNum, 10); SetDlgItemText (hDlg, DATETIME_HOUR + i, szNum); SendDlgItemMessage (hDlg, DATETIME_HOUR + i, EM_SETSEL, 0, 32767); if (i == MONTH || i == YEAR) avs[DAY].top = MonthUpperBound (wDateTime[MONTH], wDateTime[YEAR]); } BOOL DateTimeDlg (HWND hDlg, UINT message, DWORD wParam, LONG lParam) { int nNewNum; /* Temporary */ int nMaxDigitWidth; int j; short i; short nDelta; TCHAR szNum[5]; TCHAR szShortDate[12]; HDC hDC; HFONT hFont; BOOL bOK; HWND hwndCB; int iTimeZone, iButtonChecked; PAPPLET_TIME_ZONE_INFORMATION ptzi; TCHAR szTemp[128]; switch (message) { case WM_INITDIALOG: HourGlass (TRUE); // Center dialog on screen, both since it is large and for setup CentreWindow(hDlg); // // TEMPORARY FIX FOR BUG 10170 - Time screw-up if User attempts // to change Timezone and Date/Time at same time. This forces // applet to work the same way as it does under Setup, except it // does not display message. // bDisplayMessage = bSetup; bSetup = TRUE; // // BUG 10170 - When user tries to set tz and date/time at same time in applet // the date/time will get fouled up. This is because when the tz is changed // we set the global "SelectedTimezone" to point to a TZINFO struct. That is // used in "SystemTimeToTimezoneSpecificLocalTime" api call to get what the // local time would be in that timezone if it were selected. // // If a user then tries to change the date or time, a call is made to SetTime // which uses the displayed time in a call to SetLocalTime(). That call in // turn changes the SystemTime. Then the next call to GetDate/Time will use // the now erroneous SystemTime in its next call to SystemTimeToTZSpecific // LocalTime" api and get a bogus time. // // // We want to preserve the behavoir of the Date/Time applet to show the current // local time for the user's new TZ selection, while still allowing them to // change the date or time. // // The temporary fix for this is to force applet to act the same way it does // under Setup, where current date and time are preserved across a TZ selection // and the user must explicitly set the desired Date and Time. // SelectedTimeZone = NULL; InitTimeZone (hDlg); // Setup date and time fields in correct order bLZero[HOUR] = bLZero[MONTH] = bLZero[DAY] = bLZero[YEAR] = FALSE; bLZero[MINUTE] = bLZero[SECOND] = TRUE; hDC = GetDC (hDlg); if (hFont = (HFONT) SendMessage (hDlg, WM_GETFONT, 0, 0L)) hFont = SelectObject (hDC, hFont); nMaxDigitWidth = GetMaxCharWidth (hDC); if (hFont) SelectObject (hDC, hFont); ReleaseDC (hDlg, hDC); bLZero[HOUR] = GetLocaleValue (0, LOCALE_ITLZERO, szTemp, CharSizeOf(szTemp), TEXT("0")); GetLocaleValue (0, LOCALE_SSHORTDATE, szShortDate, CharSizeOf(szShortDate), IntlDef.sShortDate); ReadShortDate (szShortDate, bLZero + MONTH, bLZero + DAY, bLZero + YEAR); GetLocaleValue (0, LOCALE_SDATE, szNum, CharSizeOf(szNum), IntlDef.sDateSep); DateTimeInit (hDlg, DATETIME_MONTH, DATETIME_DSEP1, szNum, nMaxDigitWidth, TRUE); #ifdef LATER // Setup timezone date fields DateTimeInit (hDlg, IDD_TZ_SD_MONTH, IDD_TZ_SD_SEP1, szNum, nMaxDigitWidth, TRUE); DateTimeInit (hDlg, IDD_TZ_ED_MONTH, IDD_TZ_ED_SEP1, szNum, nMaxDigitWidth, TRUE); #endif // LATER GetLocaleValue (0, LOCALE_STIME, szNum, CharSizeOf(szNum), IntlDef.sTime); DateTimeInit (hDlg, DATETIME_HOUR, DATETIME_TSEP1, szNum, nMaxDigitWidth, FALSE); OddArrowWindow (GetDlgItem (hDlg, DATETIME_DARROW)); OddArrowWindow (GetDlgItem (hDlg, DATETIME_TARROW)); GetDateTime (); avs[DAY].top = MonthUpperBound (wDateTime[MONTH], wDateTime[YEAR]); if (!bLZero[YEAR]) { wDateTime[YEAR] %= 100; avs[YEAR].top = 99; avs[YEAR].bottom = 0; avs[YEAR].thumbpos = avs[YEAR].thumbtrack = 93; } else { avs[YEAR].top = 9999; avs[YEAR].bottom = 1980; avs[YEAR].thumbpos = avs[YEAR].thumbtrack = 1993; } for (i = 0; i < 6; i++) { wPrevDateTime[i] = -1; wDeltaDateTime[i] = 0; } wTimerOn = TRUE; SendMessage (hDlg, WM_TIMER, SECOND, 0L); wTimerOn = (WORD) SetTimer (hDlg, SECOND, 950, (WNDPROC) NULL); HourGlass (FALSE); break; case WM_VSCROLL: switch (nDelta = (short) GetWindowLong(GetFocus(), GWL_ID)) { case DATETIME_AMPM: case DATETIME_HOUR: case DATETIME_MINUTE: case DATETIME_SECOND: if (HIWORD(wParam) != DATETIME_TARROW) return (FALSE); break; case DATETIME_MONTH: case DATETIME_DAY: case DATETIME_YEAR: if (HIWORD(wParam) != DATETIME_DARROW) return (FALSE); break; default: return (FALSE); } i = (short) (nDelta - DATETIME_HOUR); GetDateTime (); switch (LOWORD(wParam)) { case SB_THUMBTRACK: case SB_ENDSCROLL: return (TRUE); break; default: if (nDelta == DATETIME_AMPM) { HWND hWndAMPM; hWndAMPM = GetFocus (); SendMessage (hWndAMPM, LB_SETCURSEL, 1 - (WORD)SendMessage (hWndAMPM, LB_GETCURSEL, 0, 0L), 0L); return (TRUE); } else { nNewNum = GetDlgItemInt (hDlg, nDelta, &bOK, FALSE); if ((i == HOUR) && !bAMPM) { if (bPM) nNewNum += 12; if (!(nNewNum % 12)) nNewNum -= 12; } wDateTime[i] = ArrowVScrollProc (LOWORD(wParam), (short)nNewNum, (LPARROWVSCROLL) (avs + i)); /* Wrap around if exceeded limit */ if (avs[i].flags & UNDERFLOW) wDateTime[i] = avs[i].top; else if (avs[i].flags & OVERFLOW) wDateTime[i] = avs[i].bottom; if (i == HOUR) { bPM = (wDateTime[i] >= 12); } } break; } /* set system var */ UpdateItem (hDlg, i); break; case WM_TIMER: if (wTimerOn && (wParam == SECOND)) { GetDateTime (); if (!bLZero[YEAR]) wDateTime[YEAR] %= 100; for (i = 0; i < 6; i++) { if ((wDateTime[i] != wPrevDateTime[i]) && (GetFocus () != GetDlgItem (hDlg, DATETIME_HOUR + i))) { // // Update prev date-time // wPrevDateTime[i] = wDateTime[i]; UpdateItem (hDlg, i); } } } break; #ifdef TZMAP // case WM_PAINT: // return PaintWorld (hDlg); case WM_CTLCOLORSTATIC: if ((HWND) lParam == GetDlgItem (hDlg, IDD_TZ_WORLD)) { return PaintWorld ((HWND) lParam, (HDC) wParam); } break; #endif // TZMAP case WM_COMMAND: switch (LOWORD(wParam)) { case IDD_HELP: goto DoHelp; case DATETIME_AMPM: { switch (HIWORD(wParam)) { case LBN_SETFOCUS: SendMessage ((HWND) lParam, LB_SETCURSEL, (WORD)SendMessage ((HWND) lParam, LB_GETTOPINDEX, 0, 0L), 0L); break; case LBN_KILLFOCUS: SendMessage ((HWND)lParam, LB_SETCURSEL, (WPARAM)(LONG)-1, 0L); bPM = (BOOL)SendMessage ((HWND)lParam, LB_GETTOPINDEX, 0, 0L); AdjustDelta (hDlg, HOUR); break; } break; } case DATETIME_HOUR: case DATETIME_MINUTE: case DATETIME_SECOND: case DATETIME_YEAR: case DATETIME_MONTH: case DATETIME_DAY: if (HIWORD(wParam) == EN_UPDATE) { if (!CheckNum (hDlg, LOWORD(wParam))) SendMessage ((HWND) lParam, EM_UNDO, 0, 0L); } else if (HIWORD(wParam) == EN_KILLFOCUS) { AdjustDelta (hDlg, (short) (LOWORD(wParam) - DATETIME_HOUR)); } break; #ifdef SHOW_NEW_TIME case IDD_TZ_DAYLIGHT: { // If we get a BN_CLICKED message on Checkbox, treat it as // though User made another Timezone selection - this forces // the system to recalc date/time if (HIWORD(wParam) != BN_CLICKED) break; hwndCB = GetDlgItem (hDlg, IDD_TZ_TIMEZONES); iTimeZone = SendMessage (hwndCB, CB_GETCURSEL, 0, 0L); // Get DST selection iButtonChecked = IsDlgButtonChecked (hDlg, IDD_TZ_DAYLIGHT); // A disabled checkbox is same as "No DST" selection if (iButtonChecked != 1) iButtonChecked = 0; if (iTimeZone != CB_ERR) { ptzi = (PAPPLET_TIME_ZONE_INFORMATION) SendMessage ( hwndCB, CB_GETITEMDATA, (WPARAM)iTimeZone, 0L); if (bSetup) SetTheTimezone (hDlg, iButtonChecked, ptzi); else SetTheVirtualTimezone (hDlg, iButtonChecked, ptzi); } break; } #endif // SHOW_NEW_TIME case IDD_TZ_TIMEZONES: { if (HIWORD(wParam) != CBN_SELCHANGE) break; hwndCB = GetDlgItem (hDlg, IDD_TZ_TIMEZONES); iTimeZone = SendMessage (hwndCB, CB_GETCURSEL, 0, 0L); if (iTimeZone != CB_ERR) { ptzi = (PAPPLET_TIME_ZONE_INFORMATION) SendMessage ( hwndCB, CB_GETITEMDATA, (WPARAM)iTimeZone, 0L); hwndCB = GetDlgItem (hDlg, IDD_TZ_DAYLIGHT); // Gray Checkbox if this TimeZone doesn't allow // Daylight Saving Time if (ptzi->StandardDate.wMonth == 0) { CheckDlgButton (hDlg, IDD_TZ_DAYLIGHT, 0); EnableWindow (hwndCB, FALSE); iButtonChecked = 0; } else { EnableWindow (hwndCB, TRUE); CheckDlgButton (hDlg, IDD_TZ_DAYLIGHT, 1); iButtonChecked = 1; } #ifdef SHOW_NEW_TIME if (bSetup) SetTheTimezone (hDlg, iButtonChecked, ptzi); else SetTheVirtualTimezone (hDlg, iButtonChecked, ptzi); #endif // SHOW_NEW_TIME } break; } case PUSH_CANCEL: SelectedTimeZone = NULL; SetFocus (GetDlgItem (hDlg, LOWORD(wParam))); hwndCB = GetDlgItem (hDlg, IDD_TZ_TIMEZONES); GetDateTime (); for (i = 0; i < 6; i++) wDateTime[i] -= wDeltaDateTime[i]; SetDateTime (); #ifdef SHOW_NEW_TIME // // Restore the original TimeZone and DST state. // SetTheTimezone (hDlg, iOrigButtonChecked, ptziOriginal); #endif // SHOW_NEW_TIME goto KillTheTimer; case PUSH_OK: HourGlass (TRUE); SelectedTimeZone = NULL; hwndCB = GetDlgItem (hDlg, IDD_TZ_TIMEZONES); // Get DST selection iButtonChecked = IsDlgButtonChecked (hDlg, IDD_TZ_DAYLIGHT); // A disabled checkbox is same as "No DST" selection if (iButtonChecked != 1) iButtonChecked = 0; // Find out which listbox item was selected iTimeZone = SendMessage (hwndCB, CB_GETCURSEL, 0, 0L); if (iTimeZone != CB_ERR) { ptzi = (PAPPLET_TIME_ZONE_INFORMATION) SendMessage ( hwndCB, CB_GETITEMDATA, (WPARAM)iTimeZone, 0L); } else { ptzi = NULL; } SetTheTimezone (hDlg, iButtonChecked, ptzi); SendMessage ((HWND) -1, WM_TIMECHANGE, 0L, 0L); KillTheTimer: // No more updates to local time - use what we have KillTimer (hDlg, SECOND); ////////////////////////////////////////////////////////////////// // Free TimeZone structs and all strings associated with them ////////////////////////////////////////////////////////////////// for (j = 0; j < NumTimeZones; j++) { ptzi = (PAPPLET_TIME_ZONE_INFORMATION) SendMessage ( hwndCB, CB_GETITEMDATA, (WPARAM)j, 0L); if (ptzi) FreeMem (ptzi, sizeof(APPLET_TIME_ZONE_INFORMATION)); } #ifdef TZMAP if (hpalTZmap) DeleteObject (hpalTZmap); #endif // TZMAP HourGlass (FALSE); EndDialog (hDlg, 0L); break; } break; default: if (message == wHelpMessage) { DoHelp: CPHelp (hDlg); return TRUE; } else return FALSE; break; } return (TRUE); } ////////////////////////////////////////////////////////////////////////////// // // InitTimeZone // // This function initializes everything to do with the Timezones // ////////////////////////////////////////////////////////////////////////////// BOOL InitTimeZone (HWND hDlg) { TIME_ZONE_INFORMATION CurrentTzi; int j; DWORD TimeZoneId; int CurrentTziIndex; HWND hwndCB; PAPPLET_TIME_ZONE_INFORMATION ptzi; #ifdef TZMAP // Initilize drawing of world bitmap and timezones SetupWorld (hDlg); #endif // TZMAP ////////////////////////////////////////////////////////////////////////// // Init "Auto Adjust for DST" checkbox ////////////////////////////////////////////////////////////////////////// TimeZoneId = GetTimeZoneInformation (&CurrentTzi); // Assume "Auto Adjust for DST" CheckDlgButton (hDlg, IDD_TZ_DAYLIGHT, 1); // If wMonth is 0, then this TimeZone does not support DST // else if all fields between StandardDate and DaylightDate are equal // then we assume that there is no "Daylight Saving Time" selected if ((CurrentTzi.StandardDate.wMonth == 0) || (CurrentTzi.DaylightDate.wMonth == 0)) { CheckDlgButton (hDlg, IDD_TZ_DAYLIGHT, 0); EnableWindow (GetDlgItem (hDlg, IDD_TZ_DAYLIGHT), FALSE); } else if ((CurrentTzi.StandardDate.wYear == CurrentTzi.DaylightDate.wYear) && (CurrentTzi.StandardDate.wMonth == CurrentTzi.DaylightDate.wMonth) && (CurrentTzi.StandardDate.wDayOfWeek == CurrentTzi.DaylightDate.wDayOfWeek) && (CurrentTzi.StandardDate.wDay == CurrentTzi.DaylightDate.wDay) && (CurrentTzi.StandardDate.wHour == CurrentTzi.DaylightDate.wHour) && (CurrentTzi.StandardDate.wMinute == CurrentTzi.DaylightDate.wMinute) && (CurrentTzi.StandardDate.wSecond == CurrentTzi.DaylightDate.wSecond) && (CurrentTzi.StandardDate.wMilliseconds == CurrentTzi.DaylightDate.wMilliseconds)) CheckDlgButton (hDlg, IDD_TZ_DAYLIGHT, 0); ////////////////////////////////////////////////////////////////////////// // Get the TimeZones from registry ////////////////////////////////////////////////////////////////////////// if (!GetTimeZoneRes (hDlg)) { MyMessageBox(hDlg, DATE+12, INITS+1, MB_OK|MB_ICONINFORMATION); return FALSE; } ////////////////////////////////////////////////////////////////////////// // Find the current one ////////////////////////////////////////////////////////////////////////// hwndCB = GetDlgItem(hDlg, IDD_TZ_TIMEZONES); if (TimeZoneId != 0xffffffff) { CurrentTziIndex = NumTimeZones; } else { CurrentTziIndex = 0; goto QuickOut; } for (j = 0; j < NumTimeZones; j++) { ptzi = (PAPPLET_TIME_ZONE_INFORMATION) SendMessage (hwndCB, CB_GETITEMDATA, (WPARAM)j, 0L); if (!wcscmp (ptzi->szStandardName, CurrentTzi.StandardName)) { CurrentTziIndex = j; break; } } ////////////////////////////////////////////////////////////////////////// // hilight the current one ////////////////////////////////////////////////////////////////////////// if (CurrentTziIndex == NumTimeZones) { for (j = 0; j < NumTimeZones; j++) { ptzi = (PAPPLET_TIME_ZONE_INFORMATION) SendMessage (hwndCB, CB_GETITEMDATA, (WPARAM)j, 0L); if (!wcscmp(ptzi->szDaylightName, CurrentTzi.DaylightName)) { CurrentTziIndex = j; } } } if (CurrentTziIndex == NumTimeZones) { CurrentTziIndex = 0; } QuickOut: SendMessage (hwndCB, CB_SETCURSEL, CurrentTziIndex, (LPARAM)NULL); SetFocus (hwndCB); // // Save the original values // iOriginalTimeZone = CurrentTziIndex; ptziOriginal = (PAPPLET_TIME_ZONE_INFORMATION) SendMessage (hwndCB, CB_GETITEMDATA, (WPARAM)iOriginalTimeZone, 0L); // // Save initial DST selection // iOrigButtonChecked = IsDlgButtonChecked (hDlg, IDD_TZ_DAYLIGHT); // // A disabled checkbox is same as "No DST" selection // if (iOrigButtonChecked != 1) iOrigButtonChecked = 0; return TRUE; } ////////////////////////////////////////////////////////////////////////////// // // GetTimeZoneRes - REGISTRY VERSION // // Retrieve Time Zone information from registry // ////////////////////////////////////////////////////////////////////////////// BOOL GetTimeZoneRes (HWND hDlg) { int i, j, k, nEntries = 0; DWORD dwSize, dwBufz; DWORD dwType; HKEY hkey, hkeySub; TCHAR szTimeZone[80]; DWORD dwValue; FILETIME ftReg; PAPPLET_TIME_ZONE_INFORMATION ptzi; Tzi = NULL; ////////////////////////////////////////////////////////////////////////// // // Enumerate the subkeys under the Time Zone key and read data from // each subkey to fill in APPLET_TIME_ZONE_INFO structs // ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Get Time Zones from registry ////////////////////////////////////////////////////////////////////// hkey = NULL; if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, // Root key pszTimezones, // Subkey to open 0L, // Reserved KEY_READ, // SAM &hkey) // return handle != ERROR_SUCCESS) { return FALSE; } ////////////////////////////////////////////////////////////////////// // Special Case for when this routine is called from DllInitialize // to do and "/Install=SomeTimeZoneName" // // In this case I return an array of Time Zone structs, which we // allocate here. ////////////////////////////////////////////////////////////////////// if (hDlg == NULL) { // Number of subkeys is best estimate of number of Time Zones dwValue = 0; dwBufz = CharSizeOf(szTimeZone); // Get number of subkeys if (RegQueryInfoKey (hkey, // handle of key to query szTimeZone, // ptr class string &dwBufz, // ptr size class string buffer NULL, // reserved &dwValue, // ptr number of subkeys &dwBufz, // ptr longest subkey name length &dwBufz, // ptr longest class string length &dwBufz, // ptr number of value entries &dwBufz, // ptr longest value name length &dwBufz, // ptr longest value data length &dwBufz, // ptr security descriptor length &ftReg) // ptr last write time != ERROR_SUCCESS) { RegCloseKey (hkey); return FALSE; } k = dwValue * sizeof(APPLET_TIME_ZONE_INFORMATION); if (!(Tzi = (PAPPLET_TIME_ZONE_INFORMATION) AllocMem (k))) return FALSE; ptzi = Tzi; } else { k = sizeof(APPLET_TIME_ZONE_INFORMATION); ptzi = NULL; } ////////////////////////////////////////////////////////////////////// // Enumerate all keys under Time Zones ////////////////////////////////////////////////////////////////////// i = 0; while (RegEnumKey (hkey, i++, szTimeZone, CharSizeOf(szTimeZone)) != ERROR_NO_MORE_ITEMS) { hkeySub = NULL; if (RegOpenKeyEx (hkey, // Root key szTimeZone, // Subkey to open 0L, // Reserved KEY_READ, // SAM &hkeySub) // return handle == ERROR_SUCCESS) { /////////////////////////////////////////////////////////// // Allocate memory for this Time Zone struct /////////////////////////////////////////////////////////// if (hDlg) ptzi = (APPLET_TIME_ZONE_INFORMATION *) AllocMem (k); lstrcpy(ptzi->szRegKey, szTimeZone); /////////////////////////////////////////////////////////// // Get Time Zone strings /////////////////////////////////////////////////////////// // Get Time Zone Display Name dwSize = TZDISPLAYZ * sizeof(TCHAR); if ((RegQueryValueEx (hkeySub, pszTZDisplayName, 0L, &dwType, (LPBYTE) ptzi->szDisplayName, &dwSize)) != ERROR_SUCCESS) { goto TryNextSubKey; } if (dwType != REG_SZ) goto TryNextSubKey; // Get Time Zone Standard Name // NOTE: Each subkey under the "Time Zones" key is the // Standard Time Zone name so just copy it _tcsncpy (ptzi->szStandardName, szTimeZone, TZNAME_SIZE); // OPTIONAL - Get Time Zone Daylight Name dwSize = TZNAME_SIZE * sizeof(TCHAR); if ((RegQueryValueEx (hkeySub, pszTZDaylightName, 0L, &dwType, (LPBYTE) ptzi->szDaylightName, &dwSize)) != ERROR_SUCCESS) { // Set it to null string ptzi->szDaylightName[0] = TEXT('\0'); } /////////////////////////////////////////////////////////// // Get Binary information - Bias values, SYSTEMTIME structs // // NOTE: The binary information is stored in the same // format as the last 5 values in our structure // APPLET_TIME_ZONE_INFORMATION. // /////////////////////////////////////////////////////////// dwSize = 3 * sizeof(LONG) + 2 * sizeof(SYSTEMTIME); if ((RegQueryValueEx (hkeySub, pszTZI, 0L, &dwType, (LPBYTE) &ptzi->Bias, &dwSize)) != ERROR_SUCCESS) { goto TryNextSubKey; } /////////////////////////////////////////////////////////// // Put Time Zone into Combobox /////////////////////////////////////////////////////////// if (hDlg) { if ((j = (int)SendDlgItemMessage (hDlg, IDD_TZ_TIMEZONES, CB_ADDSTRING, (WPARAM) 0, (LPARAM) ptzi->szDisplayName)) >= 0) { SendDlgItemMessage (hDlg, IDD_TZ_TIMEZONES, CB_SETITEMDATA, j, (LPARAM) ptzi); } } else { // Simply create an array of Time Zones ptzi++; } nEntries++; } else { TryNextSubKey: if (hDlg && ptzi) FreeMem (ptzi, sizeof(APPLET_TIME_ZONE_INFORMATION)); } RegCloseKey (hkeySub); } RegCloseKey (hkey); NumTimeZones = nEntries; return TRUE; } #ifdef SHOW_NEW_TIME ////////////////////////////////////////////////////////////////////////////// // // SetTheVirtualTimezone // // Apply the User's timezone selection based on Daylight Saving option. Sets // up global TimeZone struct to be used by GetDateTime() routine. This TZ is // used by the SystemTimeToTZspecificLocalTime() api to get what the time // would be, if the user actually hit OK in the Date/Time dialog box. It // does not actually change the System TimeZone or time settings. // ////////////////////////////////////////////////////////////////////////////// VOID SetTheVirtualTimezone (HWND hDlg, int DaylightOption, PAPPLET_TIME_ZONE_INFORMATION tzi) { if (tzi == NULL) { SelectedTimeZone = NULL; return; } TimeZone.Bias = tzi->Bias; // Automatically turn off Daylight Option if this TimeZone doesn't allow it if (tzi->StandardDate.wMonth == 0) DaylightOption = 0; if (DaylightOption == 0) { // STANDARDONLY: TimeZone.StandardBias = tzi->StandardBias; TimeZone.DaylightBias = tzi->StandardBias; TimeZone.StandardDate = tzi->StandardDate; TimeZone.DaylightDate = tzi->StandardDate; lstrcpy(TimeZone.StandardName, tzi->szStandardName); lstrcpy(TimeZone.DaylightName, tzi->szStandardName); } else { // Automatically adjust for Daylight Saving Time TimeZone.StandardBias = tzi->StandardBias; TimeZone.DaylightBias = tzi->DaylightBias; TimeZone.StandardDate = tzi->StandardDate; TimeZone.DaylightDate = tzi->DaylightDate; lstrcpy(TimeZone.StandardName, tzi->szStandardName); lstrcpy(TimeZone.DaylightName, tzi->szDaylightName); } SelectedTimeZone = &TimeZone; } #endif // SHOW_NEW_TIME ////////////////////////////////////////////////////////////////////////////// // // SetTheTimezone // // Apply the User's timezone selection based on Daylight Saving option // ////////////////////////////////////////////////////////////////////////////// VOID SetTheTimezone (HWND hDlg, int DaylightOption, PAPPLET_TIME_ZONE_INFORMATION ptzi) { TIME_ZONE_INFORMATION Info; if (!ptzi) return; Info.Bias = ptzi->Bias; // Automatically turn off Daylight Option if this TimeZone doesn't allow it if (ptzi->StandardDate.wMonth == 0) DaylightOption = 0; if (DaylightOption == 0) { // STANDARDONLY: Info.StandardBias = ptzi->StandardBias; Info.DaylightBias = ptzi->StandardBias; Info.StandardDate = ptzi->StandardDate; Info.DaylightDate = ptzi->StandardDate; lstrcpy(Info.StandardName, ptzi->szStandardName); lstrcpy(Info.DaylightName, ptzi->szStandardName); } else { // Automatically adjust for Daylight Saving Time Info.StandardBias = ptzi->StandardBias; Info.DaylightBias = ptzi->DaylightBias; Info.StandardDate = ptzi->StandardDate; Info.DaylightDate = ptzi->DaylightDate; lstrcpy(Info.StandardName, ptzi->szStandardName); lstrcpy(Info.DaylightName, ptzi->szDaylightName); } // If running under "Setup", setting Timezone info is not allowed // to change system date and time if (bSetup) GetDateTime(); if (!SetTimeZoneInformation (&Info)) { if (hDlg) MyMessageBox(hDlg, ERRORS+15, INITS+1, MB_OK|MB_ICONINFORMATION); } if (bSetup) SetDateTime(); } ////////////////////////////////////////////////////////////////////////////// // // CentreWindow // // Purpose : Positions a window so that it is centred in its parent // // History: // 12-09-91 Davidc Created. // ////////////////////////////////////////////////////////////////////////////// VOID CentreWindow(HWND hwnd) { RECT rect; RECT rectParent; HWND hwndParent; LONG dx, dy; LONG dxParent, dyParent; LONG Style; // Get window rect GetWindowRect(hwnd, &rect); dx = rect.right - rect.left; dy = rect.bottom - rect.top; // Get parent rect Style = GetWindowLong(hwnd, GWL_STYLE); if ((Style & WS_CHILD) == 0) { hwndParent = GetDesktopWindow(); } else { hwndParent = GetParent(hwnd); if (hwndParent == NULL) { hwndParent = GetDesktopWindow(); } } GetWindowRect(hwndParent, &rectParent); dxParent = rectParent.right - rectParent.left; dyParent = rectParent.bottom - rectParent.top; // Centre the child in the parent rect.left = (dxParent - dx) / 2; rect.top = (dyParent - dy) / 3; // Move the child into position SetWindowPos(hwnd, NULL, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); SetForegroundWindow(hwnd); } #ifdef TZMAP ////////////////////////////////////////////////////////////////////////////// // // SetupWorld // // This function retrieves the world bitmap from the resources, draws it // with stretchblt and halftoning into the dialog frame area, scales the // Timezone polygon region coordinates to match the bitmaps stretched size // and sets up the gross "hit test accelerator x-coordinate array" for use // in fast hit-testing to determine user selection. // // NOTE: This function must also create an offscreen bitmap the same size // as the on-screen STATIC area that holds the world. We should // just do the HALF-TONE of the source bitmap into it once at INIT // time, and then just BITBLT from this memory bitmap to the screen // and then highlight the selected region // ////////////////////////////////////////////////////////////////////////////// BOOL SetupWorld (HWND hWnd) { HDC hdc; HANDLE h, hRes; LPBYTE lpBits; int i; RECT rc; LPBITMAPINFOHEADER lpBitmapInfo; h = FindResource (hModule, MAKEINTRESOURCE(WORLD), RT_BITMAP); hRes = LoadResource (hModule, h); /* Lock the bitmap and get a pointer to the color table. */ lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes); if (!lpBitmapInfo) return FALSE; // UnlockResource(hRes); /* First skip over the header structure */ lpBits = (LPBYTE)(lpBitmapInfo + 1); /* Skip the color table entries, if any */ lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD); /* Create a color bitmap compatible with the display device */ hdc = GetDC(NULL); /////////////////////////////////////////////////////////////////////////// // Create another hDC compatible with the screen and make a bitmap // the size of the static control - WORLD // Then halftone the WORLD bitmap into it /////////////////////////////////////////////////////////////////////////// // Stretchblt with halftoning, the source bitmap from our resources // into a local (display compatible) memory bitmap // // This is a speed hack to allow faster redrawing of display GetClientRect (GetDlgItem (hWnd, IDD_TZ_WORLD), &rc); if (hdcTZmap = CreateCompatibleDC (hdc)) { #ifdef USE_HALFTONE // Create a halftone palette for screen compatible memory dc hpalTZmap = CreateHalftonePalette (hdcTZmap); SelectPalette (hdcTZmap, hpalTZmap, FALSE); RealizePalette (hdcTZmap); #endif // USE_HALFTONE if (hbmTZmap = CreateCompatibleBitmap (hdc, rc.right, rc.bottom)) { #ifdef USE_HALFTONE SetStretchBltMode (hdcTZmap, HALFTONE); #else // USE_HALFTONE SetStretchBltMode (hdcTZmap, COLORONCOLOR); #endif // USE_HALFTONE hbmTZDefault = SelectObject (hdcTZmap, hbmTZmap); StretchDIBits (hdcTZmap, 0, 0, rc.right, rc.bottom, 0, 0, lpBitmapInfo->biWidth, lpBitmapInfo->biHeight, lpBits, lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY); } else return FALSE; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Discard bitmap and DC from resources - not needed now!! /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// ReleaseDC (NULL, hdc); GlobalUnlock (hRes); FreeResource (hRes); return TRUE; } ////////////////////////////////////////////////////////////////////////////// // // PaintWorld // // This function paints the World bitmap and any highlighted timezone // regions using stretchblt and halftoning into the dialog frame area // from the memory bitmap. // ////////////////////////////////////////////////////////////////////////////// LONG PaintWorld (HWND hwndWorld, HDC hdcWorld) { RECT rect; GetClientRect (hwndWorld, &rect); // Performance hack??? - Check the paint rect against our hwndWorld client // rect to see if we need to do any painting at all #ifdef USE_HALFTONE SelectPalette (hdcWorld, hpalTZmap, FALSE); RealizePalette (hdcWorld); #endif // USE_HALFTONE BitBlt (hdcWorld, 0, 0, rect.right, rect.bottom, hdcTZmap, 0, 0, SRCCOPY); // FIX FIX FIX - determine which timezone REGION is selected based on current // user TimeZone selection and invert it // Clean up return 0L; } #ifdef WORLDPAINT ////////////////////////////////////////////////////////////////////////////// // // SetupWorld // // This function retrieves the world bitmap from the resources, draws it // with stretchblt and halftoning into the dialog frame area, scales the // Timezone polygon region coordinates to match the bitmaps stretched size // and sets up the gross "hit test accelerator x-coordinate array" for use // in fast hit-testing to determine user selection. // // NOTE: This function must also create an offscreen bitmap the same size // as the on-screen STATIC area that holds the world. We should // just do the HALF-TONE of the source bitmap into it once at INIT // time, and then just BITBLT from this memory bitmap to the screen // and then highlight the selected region // ////////////////////////////////////////////////////////////////////////////// BOOL SetupWorld (HWND hWnd) { HDC hdc; HANDLE h, hRes; LPBYTE lpBits; int i; RECT rc; LPBITMAPINFOHEADER lpBitmapInfo; h = FindResource (hModule, (LPTSTR) MAKEINTRESOURCE(WORLD), RT_BITMAP); hRes = LoadResource (hModule, h); /* Lock the bitmap and get a pointer to the color table. */ lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes); if (!lpBitmapInfo) return FALSE; // UnlockResource(hRes); /* First skip over the header structure */ lpBits = (LPBYTE)(lpBitmapInfo + 1); /* Skip the color table entries, if any */ lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD); /* Create a color bitmap compatible with the display device */ hdc = GetDC(NULL); if (hdcMem = CreateCompatibleDC (hdc)) { if (hbmBitmaps = CreateDIBitmap (hdc, lpBitmapInfo, (DWORD)CBM_INIT, lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS)) hbmDefault = SelectObject (hdcMem, hbmBitmaps); } // Save the size of the source "World" bitmap iWidth = lpBitmapInfo->biWidth; iHeight = lpBitmapInfo->biHeight; /////////////////////////////////////////////////////////////////////////// // Create another hDC compatible with the screen and make a bitmap // the size of the static control - WORLD // Then halftone the WORLD bitmap into it /////////////////////////////////////////////////////////////////////////// // Stretchblt with halftoning, the source bitmap from our resources // into a local (display compatible) memory bitmap // // This is a speed hack to allow faster redrawing of display GetClientRect (GetDlgItem (hWnd, IDD_TZ_WORLD), &rc); if (hdcTZmap = CreateCompatibleDC (hdc)) { if (hbmTZmap = CreateCompatibleBitmap (hdc, rc.right, rc.bottom)) hbmTZDefault = SelectObject (hdcTZmap, hbmTZmap); } SetStretchBltMode (hdcTZmap, HALFTONE); StretchBlt (hdcTZmap, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, iWidth, iHeight, SRCCOPY); /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Discard bitmap and DC from resources - not needed now!! /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// ReleaseDC (NULL, hdc); GlobalUnlock (hRes); FreeResource (hRes); return TRUE; } LONG PaintWorld (HWND hwndWorld, HDC hdcWorld) { RECT rect; GetClientRect (hwndWorld, &rect); // Performance hack??? - Check the paint rect against our hwndWorld client // rect to see if we need to do any painting at all SetStretchBltMode (hdcWorld, HALFTONE); StretchBlt (hdcWorld, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, iWidth, iHeight, SRCCOPY); // FIX FIX FIX - determine which timezone REGION is selected based on current // user TimeZone selection and invert it // Clean up return 0L; } LONG PaintWorld (HWND hWnd) { HDC hDC, hdcWorld; HWND hwndWorld; int i; PAINTSTRUCT ps; RECT rect; hDC = BeginPaint (hWnd, &ps); hwndWorld = GetDlgItem (hWnd, IDD_TZ_WORLD); hdcWorld = GetDC (hwndWorld); GetClientRect (hwndWorld, &rect); // Performance hack??? - Check the paint rect against our hwndWorld client // rect to see if we need to do any painting at all SetStretchBltMode (hdcWorld, HALFTONE); StretchBlt (hdcWorld, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, iWidth, iHeight, SRCCOPY); // FIX FIX FIX - determine which timezone REGION is selected based on current // user TimeZone selection and invert it ReleaseDC(hwndWorld, hdcWorld); // Clean up return EndPaint(hWnd, &ps); } #endif // WORLDPAINT #endif // TZMAP