summaryrefslogtreecommitdiff
path: root/src/modules/utils/timezones.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/utils/timezones.cpp')
-rw-r--r--src/modules/utils/timezones.cpp662
1 files changed, 662 insertions, 0 deletions
diff --git a/src/modules/utils/timezones.cpp b/src/modules/utils/timezones.cpp
new file mode 100644
index 0000000000..7d22cbec1e
--- /dev/null
+++ b/src/modules/utils/timezones.cpp
@@ -0,0 +1,662 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+implements services to handle location - based timezones, instead of
+simple UTC offsets.
+*/
+
+#include <commonheaders.h>
+
+TIME_API tmi;
+
+#if _MSC_VER < 1500
+ typedef struct _TIME_DYNAMIC_ZONE_INFORMATION_T {
+ LONG Bias;
+ WCHAR StandardName[ 32 ];
+ SYSTEMTIME StandardDate;
+ LONG StandardBias;
+ WCHAR DaylightName[ 32 ];
+ SYSTEMTIME DaylightDate;
+ LONG DaylightBias;
+ WCHAR TimeZoneKeyName[ 128 ];
+ BOOLEAN DynamicDaylightTimeDisabled;
+ } DYNAMIC_TIME_ZONE_INFORMATION;
+#endif
+
+typedef DWORD (WINAPI *pfnGetDynamicTimeZoneInformation_t)(DYNAMIC_TIME_ZONE_INFORMATION *pdtzi);
+static pfnGetDynamicTimeZoneInformation_t pfnGetDynamicTimeZoneInformation;
+
+typedef HRESULT (WINAPI *pfnSHLoadIndirectString_t)(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, void **ppvReserved);
+static pfnSHLoadIndirectString_t pfnSHLoadIndirectString;
+
+typedef LANGID (WINAPI *pfnGetUserDefaultUILanguage_t)(void);
+static pfnGetUserDefaultUILanguage_t pfnGetUserDefaultUILanguage;
+
+typedef LANGID (WINAPI *pfnGetSystemDefaultUILanguage_t)(void);
+static pfnGetSystemDefaultUILanguage_t pfnGetSystemDefaultUILanguage;
+
+typedef LPARAM (WINAPI *pfnSendMessageW_t)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+static pfnSendMessageW_t pfnSendMessageW;
+
+typedef struct _REG_TZI_FORMAT
+{
+ LONG Bias;
+ LONG StandardBias;
+ LONG DaylightBias;
+ SYSTEMTIME StandardDate;
+ SYSTEMTIME DaylightDate;
+} REG_TZI_FORMAT;
+
+#define MIM_TZ_DISPLAYLEN 128
+
+struct MIM_TIMEZONE
+{
+ unsigned hash;
+ int offset;
+
+ TCHAR tszName[MIM_TZ_NAMELEN]; // windows name for the time zone
+ wchar_t szDisplay[MIM_TZ_DISPLAYLEN]; // more descriptive display name (that's what usually appears in dialogs)
+ // every hour should be sufficient.
+ TIME_ZONE_INFORMATION tzi;
+
+ static int compareBias(const MIM_TIMEZONE* p1, const MIM_TIMEZONE* p2)
+ { return p2->tzi.Bias - p1->tzi.Bias; }
+};
+
+typedef struct
+{
+ DWORD timestamp; // last time updated
+ MIM_TIMEZONE myTZ; // set to my own timezone
+} TZ_INT_INFO;
+
+static TZ_INT_INFO myInfo;
+bool muiInstalled;
+
+static OBJLIST<MIM_TIMEZONE> g_timezones(55, NumericKeySortT);
+static LIST<MIM_TIMEZONE> g_timezonesBias(55, MIM_TIMEZONE::compareBias);
+
+void FormatTime (const SYSTEMTIME *st, const TCHAR *szFormat, TCHAR *szDest, int cbDest);
+void UnixTimeToFileTime(time_t ts, LPFILETIME pft);
+time_t FileTimeToUnixTime(LPFILETIME pft);
+
+#ifdef _UNICODE
+#define fnSystemTimeToTzSpecificLocalTime SystemTimeToTzSpecificLocalTime
+#else
+BOOL MySystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION ptzi, LPSYSTEMTIME pstUtc, LPSYSTEMTIME pstLoc);
+#define fnSystemTimeToTzSpecificLocalTime MySystemTimeToTzSpecificLocalTime
+#endif
+
+
+static int timeapiGetTimeZoneTime(HANDLE hTZ, SYSTEMTIME *st)
+{
+ if (st == NULL) return 1;
+
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == UTC_TIME_HANDLE)
+ GetSystemTime(st);
+ else if (tz && tz != &myInfo.myTZ)
+ {
+ SYSTEMTIME sto;
+ GetSystemTime(&sto);
+ return !fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &sto, st);
+ }
+ else
+ GetLocalTime(st);
+
+ return 0;
+}
+
+static LPCTSTR timeapiGetTzName(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL)
+ return myInfo.myTZ.tszName;
+ else if (tz == UTC_TIME_HANDLE)
+ return _T("UTC");
+
+ return tz->tszName;
+}
+
+static void CalcTsOffset(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+ GetSystemTime(&st);
+
+ FILETIME ft;
+ SystemTimeToFileTime(&st, &ft);
+ time_t ts1 = FileTimeToUnixTime(&ft);
+
+ if (!fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &st, &stl))
+ return;
+
+ SystemTimeToFileTime(&stl, &ft);
+ time_t ts2 = FileTimeToUnixTime(&ft);
+
+ tz->offset = ts2 - ts1;
+}
+
+static bool IsSameTime(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+
+ if (tz == &myInfo.myTZ)
+ return true;
+
+ timeapiGetTimeZoneTime(tz, &stl);
+ timeapiGetTimeZoneTime(NULL, &st);
+
+ return st.wHour == stl.wHour && st.wMinute == stl.wMinute;
+}
+
+static HANDLE timeapiGetInfoByName(LPCTSTR tszName, DWORD dwFlags)
+{
+ if (tszName == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (_tcscmp(myInfo.myTZ.tszName, tszName) == 0)
+ return (dwFlags & TZF_DIFONLY) ? NULL : &myInfo.myTZ;
+
+ MIM_TIMEZONE tzsearch;
+ tzsearch.hash = hashstr(tszName);
+
+ MIM_TIMEZONE *tz = g_timezones.find(&tzsearch);
+ if (tz == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (dwFlags & TZF_DIFONLY)
+ return IsSameTime(tz) ? NULL : tz;
+
+ return tz;
+}
+
+static HANDLE timeapiGetInfoByContact(HANDLE hContact, DWORD dwFlags)
+{
+ if (hContact == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, "UserInfo", "TzName", &dbv))
+ {
+ HANDLE res = timeapiGetInfoByName(dbv.ptszVal, dwFlags);
+ DBFreeVariant(&dbv);
+ if (res) return res;
+ }
+
+ signed char timezone = (signed char)DBGetContactSettingByte(hContact, "UserInfo", "Timezone", -1);
+ if (timezone == -1)
+ {
+ char* szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (!DBGetContactSettingTString(hContact, szProto, "TzName", &dbv))
+ {
+ HANDLE res = timeapiGetInfoByName(dbv.ptszVal, dwFlags);
+ DBFreeVariant(&dbv);
+ if (res) return res;
+ }
+ timezone = (signed char)DBGetContactSettingByte(hContact, szProto, "Timezone", -1);
+ }
+
+ if (timezone != -1)
+ {
+ MIM_TIMEZONE tzsearch;
+ tzsearch.tzi.Bias = timezone * 30;
+ if (myInfo.myTZ.tzi.Bias == tzsearch.tzi.Bias)
+ {
+ if (dwFlags & TZF_DIFONLY) return NULL;
+ return &myInfo.myTZ;
+ }
+
+ int i = g_timezonesBias.getIndex(&tzsearch);
+ while (i >= 0 && g_timezonesBias[i]->tzi.Bias == tzsearch.tzi.Bias) --i;
+
+ int delta = LONG_MAX;
+ for (int j = ++i; j < g_timezonesBias.getCount() && g_timezonesBias[j]->tzi.Bias == tzsearch.tzi.Bias; ++j)
+ {
+ int delta1 = abs(g_timezonesBias[j]->tzi.DaylightDate.wMonth - myInfo.myTZ.tzi.DaylightDate.wMonth);
+ if (delta1 <= delta)
+ {
+ delta = delta1;
+ i = j;
+ }
+ }
+
+ if (i >= 0)
+ {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+ return ((dwFlags & TZF_DIFONLY) && IsSameTime(tz)) ? NULL : tz;
+ }
+ }
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+}
+
+static void timeapiSetInfoByContact(HANDLE hContact, HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+
+ if (hContact == NULL) return;
+
+ if (tz)
+ {
+ DBWriteContactSettingTString(hContact, "UserInfo", "TzName", tz->tszName);
+ DBWriteContactSettingByte(hContact, "UserInfo", "Timezone", (char)((tz->tzi.Bias + tz->tzi.StandardBias) / 30));
+ }
+ else
+ {
+ DBDeleteContactSetting(hContact, "UserInfo", "TzName");
+ DBDeleteContactSetting(hContact, "UserInfo", "Timezone");
+ }
+}
+
+static int timeapiPrintDateTime(HANDLE hTZ, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ SYSTEMTIME st;
+ if (timeapiGetTimeZoneTime(tz, &st))
+ return 1;
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+
+ return 0;
+}
+
+static int timeapiPrintTimeStamp(HANDLE hTZ, time_t ts, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ FILETIME ft;
+
+ if (tz == NULL) tz = &myInfo.myTZ;
+ if (tz == NULL)
+ {
+ FILETIME lft;
+
+ UnixTimeToFileTime(ts, &lft);
+ FileTimeToLocalFileTime(&lft, &ft);
+ }
+ else if (tz == UTC_TIME_HANDLE)
+ UnixTimeToFileTime(ts, &ft);
+ else
+ {
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ UnixTimeToFileTime(ts + tz->offset, &ft);
+ }
+
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&ft, &st);
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+
+ return 0;
+}
+
+static LPTIME_ZONE_INFORMATION timeapiGetTzi(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ return tz ? &tz->tzi : &myInfo.myTZ.tzi;
+}
+
+
+static time_t timeapiTimeStampToTimeZoneTimeStamp(HANDLE hTZ, time_t ts)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+
+ if (tz == NULL) tz = &myInfo.myTZ;
+ if (tz == NULL)
+ {
+ FILETIME ft, lft;
+
+ UnixTimeToFileTime(ts, &ft);
+ FileTimeToLocalFileTime(&ft, &lft);
+ return FileTimeToUnixTime(&lft);
+ }
+ else if (tz == UTC_TIME_HANDLE)
+ return ts;
+
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ return ts + tz->offset;
+}
+
+typedef struct
+{
+ UINT addStr, getSel, setSel, getData, setData;
+} ListMessages;
+
+static const ListMessages lbMessages =
+{ LB_ADDSTRING, LB_GETCURSEL, LB_SETCURSEL, LB_GETITEMDATA, LB_SETITEMDATA };
+
+static const ListMessages cbMessages =
+{ CB_ADDSTRING, CB_GETCURSEL, CB_SETCURSEL, CB_GETITEMDATA, CB_SETITEMDATA };
+
+static const ListMessages *GetListMessages(HWND hWnd, DWORD dwFlags)
+{
+ if (!(dwFlags & (TZF_PLF_CB | TZF_PLF_LB)))
+ {
+ TCHAR tszClassName[128];
+ GetClassName(hWnd, tszClassName, SIZEOF(tszClassName));
+ if (!_tcsicmp(tszClassName, _T("COMBOBOX")))
+ dwFlags |= TZF_PLF_CB;
+ else if(!_tcsicmp(tszClassName, _T("LISTBOX")))
+ dwFlags |= TZF_PLF_LB;
+ }
+ if (dwFlags & TZF_PLF_CB)
+ return & cbMessages;
+ else if(dwFlags & TZF_PLF_LB)
+ return & lbMessages;
+ else
+ return NULL;
+}
+
+
+static int timeapiSelectListItem(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ if (hWnd == NULL) // nothing to do
+ return -1;
+
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return -1;
+
+ int iSelection = 0;
+ if (hContact)
+ {
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, "UserInfo", "TzName", &dbv))
+ {
+ unsigned hash = hashstr(dbv.ptszVal);
+ for (int i = 0; i < g_timezonesBias.getCount(); ++i)
+ {
+ if (hash == g_timezonesBias[i]->hash)
+ {
+ iSelection = i + 1;
+ break;
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ SendMessage(hWnd, lstMsg->setSel, iSelection, 0);
+ return iSelection;
+}
+
+
+static int timeapiPrepareList(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ if (hWnd == NULL) // nothing to do
+ return 0;
+
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return 0;
+
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)TranslateT("<unspecified>"));
+
+ for (int i = 0; i < g_timezonesBias.getCount(); ++i)
+ {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+
+ if (pfnSendMessageW)
+ pfnSendMessageW(hWnd, lstMsg->addStr, 0, (LPARAM)tz->szDisplay);
+ else
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)StrConvTu(tz->szDisplay));
+
+ SendMessage(hWnd, lstMsg->setData, i + 1, (LPARAM)tz);
+ }
+
+ return timeapiSelectListItem(hContact, hWnd, dwFlags);
+}
+
+
+static void timeapiStoreListResult(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return;
+
+ LRESULT offset = SendMessage(hWnd, lstMsg->getSel, 0, 0);
+ if (offset > 0)
+ {
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)SendMessage(hWnd, lstMsg->getData, offset, 0);
+ if ((INT_PTR)tz != CB_ERR && tz != NULL)
+ timeapiSetInfoByContact(hContact, tz);
+ }
+ else
+ timeapiSetInfoByContact(hContact, NULL);
+}
+
+
+static INT_PTR GetTimeApi( WPARAM, LPARAM lParam )
+{
+ TIME_API* tmi = (TIME_API*)lParam;
+ if (tmi == NULL)
+ return FALSE;
+
+ if (tmi->cbSize != sizeof(TIME_API))
+ return FALSE;
+
+ tmi->createByName = timeapiGetInfoByName;
+ tmi->createByContact = timeapiGetInfoByContact;
+ tmi->storeByContact = timeapiSetInfoByContact;
+
+ tmi->printDateTime = timeapiPrintDateTime;
+ tmi->printTimeStamp = timeapiPrintTimeStamp;
+
+ tmi->prepareList = timeapiPrepareList;
+ tmi->selectListItem = timeapiSelectListItem;
+ tmi->storeListResults = timeapiStoreListResult;
+
+ tmi->getTimeZoneTime = timeapiGetTimeZoneTime;
+ tmi->timeStampToTimeZoneTimeStamp = timeapiTimeStampToTimeZoneTimeStamp;
+ tmi->getTzi = timeapiGetTzi;
+ tmi->getTzName = timeapiGetTzName;
+
+ return TRUE;
+}
+
+static INT_PTR TimestampToLocal(WPARAM wParam, LPARAM)
+{
+ return timeapiTimeStampToTimeZoneTimeStamp(NULL, (time_t)wParam);
+}
+
+static INT_PTR TimestampToStringT(WPARAM wParam, LPARAM lParam)
+{
+ DBTIMETOSTRINGT *tts = (DBTIMETOSTRINGT*)lParam;
+ if (tts == NULL) return 0;
+
+ timeapiPrintTimeStamp(NULL, (time_t)wParam, tts->szFormat, tts->szDest, tts->cbDest, 0);
+ return 0;
+}
+
+#ifdef _UNICODE
+static INT_PTR TimestampToStringA(WPARAM wParam, LPARAM lParam)
+{
+ DBTIMETOSTRING *tts = (DBTIMETOSTRING*)lParam;
+ if (tts == NULL) return 0;
+
+ TCHAR *szDest = (TCHAR*)alloca(tts->cbDest);
+ timeapiPrintTimeStamp(NULL, (time_t)wParam, StrConvT(tts->szFormat), szDest, tts->cbDest, 0);
+ WideCharToMultiByte(CP_ACP, 0, szDest, -1, tts->szDest, tts->cbDest, NULL, NULL);
+ return 0;
+}
+#endif
+
+void GetLocalizedString(HKEY hSubKey, const TCHAR *szName, wchar_t *szBuf, DWORD cbLen)
+{
+ szBuf[0] = 0;
+ if (muiInstalled)
+ {
+ TCHAR tszTempBuf[MIM_TZ_NAMELEN], tszName[30];
+ mir_sntprintf(tszName, SIZEOF(tszName), _T("MUI_%s"), szName);
+ DWORD dwLength = cbLen * sizeof(TCHAR);
+ if (ERROR_SUCCESS == RegQueryValueEx(hSubKey, tszName, NULL, NULL, (unsigned char *)tszTempBuf, &dwLength))
+ {
+ tszTempBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+ if (pfnSHLoadIndirectString)
+ pfnSHLoadIndirectString(StrConvU(tszTempBuf), szBuf, cbLen, NULL);
+ }
+ }
+ if (szBuf[0] == 0)
+ {
+ DWORD dwLength = cbLen * sizeof(wchar_t);
+
+#ifdef _UNICODE
+ RegQueryValueEx(hSubKey, szName, NULL, NULL, (unsigned char *)szBuf, &dwLength);
+ szBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+#else
+ char* szBufP = (char*)alloca(dwLength);
+ RegQueryValueEx(hSubKey, szName, NULL, NULL, (unsigned char *)szBufP, &dwLength);
+ szBufP[min(dwLength, cbLen * sizeof(wchar_t) - 1)] = 0;
+ MultiByteToWideChar(CP_ACP, 0, szBufP, -1, szBuf, cbLen);
+#endif
+ }
+}
+
+void RecalculateTime(void)
+{
+ GetTimeZoneInformation(&myInfo.myTZ.tzi);
+ myInfo.timestamp = time(NULL);
+ myInfo.myTZ.offset = INT_MIN;
+
+ bool found = false;
+ DYNAMIC_TIME_ZONE_INFORMATION dtzi;
+
+ if (pfnGetDynamicTimeZoneInformation && pfnGetDynamicTimeZoneInformation(&dtzi) != TIME_ZONE_ID_INVALID)
+ {
+ TCHAR *myTzKey = mir_u2t(dtzi.TimeZoneKeyName);
+ _tcscpy(myInfo.myTZ.tszName, myTzKey);
+ mir_free(myTzKey);
+ found = true;
+ }
+
+ for (int i = 0; i < g_timezones.getCount(); ++i)
+ {
+ MIM_TIMEZONE &tz = g_timezones[i];
+ if (tz.offset != INT_MIN) tz.offset = INT_MIN;
+
+ if (!found)
+ {
+ if (!wcscmp(tz.tzi.StandardName, myInfo.myTZ.tzi.StandardName) ||
+ !wcscmp(tz.tzi.DaylightName, myInfo.myTZ.tzi.DaylightName))
+ {
+ _tcscpy(myInfo.myTZ.tszName, tz.tszName);
+ found = true;
+ }
+ }
+ }
+}
+
+void InitTimeZones(void)
+{
+ REG_TZI_FORMAT tzi;
+ HKEY hKey;
+
+ const TCHAR *tszKey = IsWinVerNT() ?
+ _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones") :
+ _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones");
+
+ /*
+ * use GetDynamicTimeZoneInformation() on Vista+ - this will return a structure with
+ * the registry key name, so finding our own time zone later will be MUCH easier for
+ * localized systems or systems with a MUI pack installed
+ */
+ if (IsWinVerVistaPlus())
+ pfnGetDynamicTimeZoneInformation = (pfnGetDynamicTimeZoneInformation_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetDynamicTimeZoneInformation");
+
+ if (IsWinVer2000Plus())
+ {
+ pfnSHLoadIndirectString = (pfnSHLoadIndirectString_t)GetProcAddress(GetModuleHandle(_T("shlwapi")), "SHLoadIndirectString");
+ pfnGetSystemDefaultUILanguage = (pfnGetSystemDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetSystemDefaultUILanguage");
+ pfnGetUserDefaultUILanguage = (pfnGetUserDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetUserDefaultUILanguage");
+ muiInstalled = pfnSHLoadIndirectString && pfnGetSystemDefaultUILanguage() != pfnGetUserDefaultUILanguage();
+ }
+
+ pfnSendMessageW = (pfnSendMessageW_t)GetProcAddress(GetModuleHandle(_T("user32")), "SendMessageW");
+
+ if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, tszKey, 0, KEY_ENUMERATE_SUB_KEYS, &hKey))
+ {
+ DWORD dwIndex = 0;
+ HKEY hSubKey;
+ TCHAR tszName[MIM_TZ_NAMELEN];
+
+ DWORD dwSize = SIZEOF(tszName);
+ while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hKey, dwIndex++, tszName, &dwSize, NULL, NULL, 0, NULL))
+ {
+ if (ERROR_SUCCESS == RegOpenKeyEx(hKey, tszName, 0, KEY_QUERY_VALUE, &hSubKey))
+ {
+ dwSize = sizeof(tszName);
+
+ DWORD dwLength = sizeof(tzi);
+ if (ERROR_SUCCESS != RegQueryValueEx(hSubKey, _T("TZI"), NULL, NULL, (unsigned char *)&tzi, &dwLength))
+ continue;
+
+ MIM_TIMEZONE *tz = new MIM_TIMEZONE;
+
+ tz->tzi.Bias = tzi.Bias;
+ tz->tzi.StandardDate = tzi.StandardDate;
+ tz->tzi.StandardBias = tzi.StandardBias;
+ tz->tzi.DaylightDate = tzi.DaylightDate;
+ tz->tzi.DaylightBias = tzi.DaylightBias;
+
+ _tcscpy(tz->tszName, tszName);
+ tz->hash = hashstr(tszName);
+ tz->offset = INT_MIN;
+
+ GetLocalizedString(hSubKey, _T("Display"), tz->szDisplay, SIZEOF(tz->szDisplay));
+ GetLocalizedString(hSubKey, _T("Std"), tz->tzi.StandardName, SIZEOF(tz->tzi.StandardName));
+ GetLocalizedString(hSubKey, _T("Dlt"), tz->tzi.DaylightName, SIZEOF(tz->tzi.DaylightName));
+
+ g_timezones.insert(tz);
+ g_timezonesBias.insert(tz);
+
+ RegCloseKey(hSubKey);
+ }
+ dwSize = SIZEOF(tszName);
+ }
+ RegCloseKey(hKey);
+ }
+
+ RecalculateTime();
+
+ CreateServiceFunction(MS_SYSTEM_GET_TMI, GetTimeApi);
+
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOLOCAL, TimestampToLocal);
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRINGT, TimestampToStringT);
+#ifdef _UNICODE
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToStringA);
+#else
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToStringT);
+#endif
+
+
+ tmi.cbSize = sizeof(tmi);
+ GetTimeApi(0, (LPARAM)&tmi);
+}
+
+void UninitTimeZones(void)
+{
+ g_timezonesBias.destroy();
+ g_timezones.destroy();
+}