You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
573 lines
13 KiB
C++
573 lines
13 KiB
C++
// XTPCalendarTimeZoneHelper.cpp: implementation of Time Zone Helper classes.
|
|
//
|
|
// This file is a part of the XTREME CALENDAR MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Common/XTPVC80Helpers.h"
|
|
#include "Common/XTPSystemHelpers.h"
|
|
#include "Common/XTPSmartPtrInternalT.h"
|
|
|
|
#include "XTPCalendarPtrCollectionT.h"
|
|
#include "XTPCalendarUtils.h"
|
|
#include "XTPCalendarTimeZoneHelper.h"
|
|
#include "XTPCalendarDefines.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
|
|
IMPLEMENT_DYNAMIC(CXTPCalendarTimeZone, CCmdTarget)
|
|
IMPLEMENT_DYNAMIC(CXTPCalendarTimeZones, CCmdTarget)
|
|
|
|
|
|
CXTPCalendarTimeZone::CXTPCalendarTimeZone(const TIME_ZONE_INFORMATION* pTZInfo)
|
|
{
|
|
if (pTZInfo)
|
|
{
|
|
*((TIME_ZONE_INFORMATION*)this) = *pTZInfo;
|
|
}
|
|
else
|
|
{
|
|
::ZeroMemory((void*)((TIME_ZONE_INFORMATION*)this), sizeof(TIME_ZONE_INFORMATION));
|
|
}
|
|
|
|
m_dwIndex = 0;
|
|
|
|
}
|
|
|
|
CXTPCalendarTimeZone::CXTPCalendarTimeZone(const CXTPCalendarTimeZone* pTZInfoEx)
|
|
{
|
|
*this = *pTZInfoEx;
|
|
|
|
}
|
|
|
|
CXTPCalendarTimeZone::~CXTPCalendarTimeZone()
|
|
{
|
|
}
|
|
|
|
const CXTPCalendarTimeZone&
|
|
CXTPCalendarTimeZone::operator=(const CXTPCalendarTimeZone& rTZInfo)
|
|
{
|
|
*((TIME_ZONE_INFORMATION*)this) = *((TIME_ZONE_INFORMATION*)&rTZInfo);
|
|
|
|
m_strDisplayString = rTZInfo.GetDisplayString();
|
|
m_dwIndex = rTZInfo.GetIndex();
|
|
|
|
return *this;
|
|
}
|
|
|
|
CString CXTPCalendarTimeZone::GetDisplayString() const
|
|
{
|
|
return m_strDisplayString;
|
|
}
|
|
|
|
DWORD CXTPCalendarTimeZone::GetIndex() const
|
|
{
|
|
return m_dwIndex;
|
|
}
|
|
|
|
BOOL CXTPCalendarTimeZone::IsEqual(const TIME_ZONE_INFORMATION* pTZI2) const
|
|
{
|
|
if (!pTZI2)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
const int cnChSize_name = _countof(StandardName);
|
|
|
|
if (_wcsnicmp(StandardName, pTZI2->StandardName, cnChSize_name) == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
CXTPCalendarTimeZonePtr CXTPCalendarTimeZone::GetTimeZoneInfo(
|
|
const TIME_ZONE_INFORMATION* pTZIdata)
|
|
{
|
|
if (!pTZIdata)
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
CXTPCalendarTimeZones arXTP_TZI;
|
|
|
|
if (!arXTP_TZI.InitFromRegistry())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
CXTPCalendarTimeZone* pTZI2Info = arXTP_TZI.Find(pTZIdata);
|
|
if (pTZI2Info)
|
|
{
|
|
CXTPCalendarTimeZone* pTZI2;
|
|
pTZI2 = new CXTPCalendarTimeZone(pTZI2Info);
|
|
//to update "biases" and names values
|
|
if (pTZI2)
|
|
{
|
|
*((TIME_ZONE_INFORMATION*)pTZI2) = *pTZIdata;
|
|
}
|
|
CXTPCalendarTimeZonePtr ptrTZI2(pTZI2, FALSE);
|
|
return ptrTZI2;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//class CXTPCalendarTimeZones : public CCmdTarget
|
|
CXTPCalendarTimeZones::CXTPCalendarTimeZones()
|
|
{
|
|
}
|
|
|
|
CXTPCalendarTimeZones::~CXTPCalendarTimeZones()
|
|
{
|
|
}
|
|
|
|
BOOL CXTPCalendarTimeZones::GetRegBSTR(HKEY hKey, LPCWSTR pcszValueNameW, BSTR& rbstrValue)
|
|
{
|
|
if (rbstrValue)
|
|
{
|
|
::SysFreeString(rbstrValue);
|
|
rbstrValue = NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
if (CXTPCalendarUtils::IsWin9x())
|
|
{
|
|
CString strValueName(pcszValueNameW);
|
|
CString strValue;
|
|
if (GetRegStr(hKey, strValueName, strValue))
|
|
{
|
|
rbstrValue = strValue.AllocSysString();
|
|
}
|
|
return rbstrValue != NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
const DWORD cdwDataSize = 4 * 1024;
|
|
BYTE arData[cdwDataSize];
|
|
::ZeroMemory(arData, sizeof(arData));
|
|
DWORD dwType = 0, dwDataSize = sizeof(arData)-2;
|
|
|
|
LONG lRes = ::RegQueryValueExW(hKey, pcszValueNameW, NULL, &dwType,
|
|
arData, &dwDataSize);
|
|
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ)
|
|
{
|
|
ASSERT(dwType != REG_MULTI_SZ); // WARMING!
|
|
|
|
rbstrValue = ::SysAllocString((LPCWSTR)arData);
|
|
return rbstrValue != NULL;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTPCalendarTimeZones::GetRegStr(HKEY hKey, LPCTSTR pcszValueName, CString& rstrValue)
|
|
{
|
|
rstrValue.Empty();
|
|
|
|
const DWORD cdwDataSize = 4 * 1024;
|
|
BYTE arData[cdwDataSize];
|
|
::ZeroMemory(arData, sizeof(arData));
|
|
DWORD dwType = 0, dwDataSize = sizeof(arData)-2;
|
|
|
|
LONG lRes = ::RegQueryValueEx(hKey, pcszValueName, NULL, &dwType,
|
|
arData, &dwDataSize);
|
|
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ)
|
|
{
|
|
ASSERT(dwType != REG_MULTI_SZ); // WARMING!
|
|
|
|
rstrValue = (LPCTSTR)arData;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTPCalendarTimeZones::GetRegDWORD(HKEY hKey, LPCTSTR pcszValueName, DWORD& rdwValue)
|
|
{
|
|
rdwValue = 0;
|
|
|
|
const DWORD cdwDataSize = 16;
|
|
BYTE arData[cdwDataSize];
|
|
::ZeroMemory(arData, sizeof(arData));
|
|
DWORD dwType = 0, dwDataSize = sizeof(arData);
|
|
|
|
LONG lRes = ::RegQueryValueEx(hKey, pcszValueName, NULL, &dwType,
|
|
arData, &dwDataSize);
|
|
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwType == REG_DWORD || dwType == REG_DWORD_BIG_ENDIAN || dwType == REG_BINARY)
|
|
{
|
|
rdwValue = *((DWORD*)arData);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTPCalendarTimeZones::GetRegTZI(HKEY hKey, LPCTSTR pcszValueName,
|
|
CXTPCalendarTimeZones::REGISTRY_TIMEZONE_INFORMATION& rRegTZI)
|
|
{
|
|
::ZeroMemory(&rRegTZI, sizeof(rRegTZI));
|
|
|
|
const DWORD cdwDataSize = sizeof(rRegTZI)*2;
|
|
BYTE arData[cdwDataSize];
|
|
::ZeroMemory(arData, sizeof(arData));
|
|
DWORD dwType = 0, dwDataSize = sizeof(arData);
|
|
|
|
LONG lRes = ::RegQueryValueEx(hKey, pcszValueName, NULL, &dwType,
|
|
arData, &dwDataSize);
|
|
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwType == REG_BINARY && dwDataSize == sizeof(rRegTZI))
|
|
{
|
|
rRegTZI = *((REGISTRY_TIMEZONE_INFORMATION*)arData);
|
|
return TRUE;
|
|
}
|
|
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTPCalendarTimeZones::InitFromRegistry()
|
|
{
|
|
m_arTZInfo.RemoveAll();
|
|
|
|
CString strTZIRootKey = XTP_CALENDAR_TIMEZONESKEY_NT;
|
|
|
|
HKEY hkTZIRoot = NULL;
|
|
BOOL bUseIndex = !XTPSystemVersion()->IsWinXPOrGreater();
|
|
|
|
// Try NT information first
|
|
LONG lRes = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, strTZIRootKey, 0, KEY_READ, &hkTZIRoot);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
// try Win9x information
|
|
strTZIRootKey = XTP_CALENDAR_TIMEZONESKEY_9X;
|
|
bUseIndex = FALSE;
|
|
|
|
lRes = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, strTZIRootKey, 0, KEY_READ, &hkTZIRoot);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
TRACE(_T("Cannot open Time Zones information registry key. err = %d \n"), lRes);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
const DWORD cdwKeyBufSize = 1024;
|
|
TCHAR szTZIKey[cdwKeyBufSize + 1];
|
|
|
|
BSTR bstrStandardName = NULL;
|
|
BSTR bstrDaylightName = NULL;
|
|
|
|
lRes = ERROR_SUCCESS;
|
|
for (DWORD dwEnumKey = 0; lRes == ERROR_SUCCESS; dwEnumKey++)
|
|
{
|
|
::ZeroMemory(szTZIKey, sizeof(szTZIKey));
|
|
|
|
lRes = ::RegEnumKey (hkTZIRoot, dwEnumKey, szTZIKey, cdwKeyBufSize);
|
|
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
ASSERT(lRes == ERROR_NO_MORE_ITEMS);
|
|
break;
|
|
}
|
|
|
|
//===================================================================
|
|
CString strTZIKey = strTZIRootKey + _T("\\") + szTZIKey;
|
|
|
|
HKEY hkTZIdata = NULL;
|
|
LONG lRes2 = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, strTZIKey, 0, KEY_READ, &hkTZIdata);
|
|
if (lRes2 != ERROR_SUCCESS)
|
|
{
|
|
TRACE(_T("Cannot open registry key 'HKEY_LOCAL_MACHINE\\%s'. err = %d \n"), (LPCTSTR)strTZIKey, lRes2);
|
|
continue;
|
|
}
|
|
|
|
CString strDisplayStr, strStandardName, strDaylightName;
|
|
DWORD dwIndex;
|
|
REGISTRY_TIMEZONE_INFORMATION regTZI;
|
|
|
|
if (!GetRegStr(hkTZIdata, XTP_CALENDAR_TZIRegValName_DisplayStr, strDisplayStr))
|
|
{
|
|
TRACE(_T("Cannot get value from registry: 'HKEY_LOCAL_MACHINE\\%s\\%s'\n"), (LPCTSTR)strTZIKey, XTP_CALENDAR_TZIRegValName_DisplayStr);
|
|
continue;
|
|
}
|
|
if (!GetRegBSTR(hkTZIdata, XTP_CALENDAR_TZIRegValName_StandardNameW, bstrStandardName))
|
|
{
|
|
TRACE(_T("Cannot get value from registry: 'HKEY_LOCAL_MACHINE\\%s\\%s'\n"), (LPCTSTR)strTZIKey, XTP_CALENDAR_TZIRegValName_StandardName);
|
|
continue;
|
|
}
|
|
if (!GetRegBSTR(hkTZIdata, XTP_CALENDAR_TZIRegValName_DaylightNameW, bstrDaylightName))
|
|
{
|
|
TRACE(_T("Cannot get value from registry: 'HKEY_LOCAL_MACHINE\\%s\\%s'\n"), (LPCTSTR)strTZIKey, XTP_CALENDAR_TZIRegValName_DaylightName);
|
|
continue;
|
|
}
|
|
|
|
if (!GetRegTZI(hkTZIdata, XTP_CALENDAR_TZIRegValName_DATA, regTZI))
|
|
{
|
|
TRACE(_T("Cannot get value from registry: 'HKEY_LOCAL_MACHINE\\%s\\%s'\n"), (LPCTSTR)strTZIKey, XTP_CALENDAR_TZIRegValName_DATA);
|
|
continue;
|
|
}
|
|
|
|
if (!GetRegDWORD(hkTZIdata, XTP_CALENDAR_TZIRegValName_Index, dwIndex))
|
|
{
|
|
if (bUseIndex)
|
|
{
|
|
TRACE(_T("Cannot get value from registry: 'HKEY_LOCAL_MACHINE\\%s\\%s'\n"), (LPCTSTR)strTZIKey, XTP_CALENDAR_TZIRegValName_Index);
|
|
}
|
|
dwIndex = 0;
|
|
}
|
|
|
|
//=================================================
|
|
CXTPCalendarTimeZone* pXTP_TZI;
|
|
pXTP_TZI = new CXTPCalendarTimeZone();
|
|
if (!pXTP_TZI)
|
|
{
|
|
AfxThrowOleException(E_OUTOFMEMORY);
|
|
}
|
|
|
|
pXTP_TZI->Bias = regTZI.Bias;
|
|
|
|
WCSNCPY_S(pXTP_TZI->StandardName, 32, bstrStandardName, 32);
|
|
pXTP_TZI->StandardName[_countof(pXTP_TZI->StandardName)-1] = L'\0';
|
|
|
|
pXTP_TZI->StandardDate = regTZI.StandardDate;
|
|
pXTP_TZI->StandardBias = regTZI.StandardBias;
|
|
|
|
WCSNCPY_S(pXTP_TZI->DaylightName, 32, bstrDaylightName, 32);
|
|
pXTP_TZI->DaylightName[_countof(pXTP_TZI->DaylightName)-1] = L'\0';
|
|
|
|
pXTP_TZI->DaylightDate = regTZI.DaylightDate;
|
|
pXTP_TZI->DaylightBias = regTZI.DaylightBias;
|
|
|
|
pXTP_TZI->m_strDisplayString = strDisplayStr;
|
|
pXTP_TZI->m_dwIndex = dwIndex;
|
|
|
|
m_arTZInfo.Add(pXTP_TZI, FALSE);
|
|
|
|
RegCloseKey(hkTZIdata);
|
|
}
|
|
|
|
RegCloseKey(hkTZIRoot);
|
|
|
|
//-----------------------------------------------
|
|
if (bstrStandardName)
|
|
{
|
|
::SysFreeString(bstrStandardName);
|
|
}
|
|
if (bstrDaylightName)
|
|
{
|
|
::SysFreeString(bstrDaylightName);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
int nCount = m_arTZInfo.GetCount();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
for (int j = i + 1; j < nCount; j++)
|
|
{
|
|
CXTPCalendarTimeZonePtr ptrElem1, ptrElem2;
|
|
ptrElem1 = m_arTZInfo.GetAt(i, TRUE);
|
|
ptrElem2 = m_arTZInfo.GetAt(j, TRUE);
|
|
|
|
if (CompareTZI(ptrElem1, ptrElem2, bUseIndex) > 0)
|
|
{
|
|
m_arTZInfo.SetAt(i, ptrElem2.Detach());
|
|
m_arTZInfo.SetAt(j, ptrElem1.Detach());
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int CXTPCalendarTimeZones::GetDigit(TCHAR ch) const
|
|
{
|
|
int nD = ch - _T('0');
|
|
return (nD >= 0 && nD <= 9) ? nD : -1;
|
|
}
|
|
|
|
void CXTPCalendarTimeZones::ParseDisplayStr(LPCTSTR str, int& rnOffset, CString& rstrPlace) const
|
|
{
|
|
// (GMT + 02:00) Athens, ...
|
|
// (GMT-02:00) place, ...
|
|
//----------------------------------------------
|
|
// (GMT - 02 : 00) place, ...
|
|
//0 1 2 3 4 5
|
|
//----------------------------------------------
|
|
|
|
rnOffset = 0;
|
|
rstrPlace.Empty();
|
|
|
|
int nSign = 0, nHr = 0, nMin = 0;
|
|
int nState = 0;
|
|
|
|
for (const TCHAR* pCh = (LPCTSTR)str; pCh && *pCh != 0; pCh = _tcsinc(pCh))
|
|
{
|
|
if (nState == 0 && *pCh == _T('('))
|
|
{
|
|
nState = 1;
|
|
}
|
|
else if (nState == 1)
|
|
{
|
|
if (*pCh == _T('+'))
|
|
{
|
|
nSign = 1;
|
|
nState = 2;
|
|
}
|
|
else if (*pCh == _T('-'))
|
|
{
|
|
nSign = -1;
|
|
nState = 2;
|
|
}
|
|
}
|
|
else if (nState == 2)
|
|
{
|
|
if (GetDigit(*pCh) >= 0)
|
|
{
|
|
nHr *= 10;
|
|
nHr += GetDigit(*pCh);
|
|
}
|
|
else if (*pCh == _T(':'))
|
|
{
|
|
nState = 3;
|
|
}
|
|
}
|
|
else if (nState == 3)
|
|
{
|
|
if (GetDigit(*pCh) >= 0)
|
|
{
|
|
nMin *= 10;
|
|
nMin += GetDigit(*pCh);
|
|
}
|
|
else if (*pCh == _T(')'))
|
|
{
|
|
nState = 4;
|
|
}
|
|
}
|
|
else if (nState == 4)
|
|
{
|
|
if (*pCh != _T(' '))
|
|
{
|
|
rstrPlace = pCh;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------
|
|
rnOffset = nSign * (nHr * 60 + nMin);
|
|
}
|
|
|
|
int CXTPCalendarTimeZones::CompareTZI(const CXTPCalendarTimeZone* pTZI1,
|
|
const CXTPCalendarTimeZone* pTZI2, BOOL bUseIndex) const
|
|
{
|
|
if (bUseIndex)
|
|
{
|
|
return XTPCompare(pTZI1->m_dwIndex, pTZI2->m_dwIndex);
|
|
}
|
|
|
|
int nOffset1, nOffset2;
|
|
CString strPlace1, strPlace2;
|
|
|
|
ParseDisplayStr(pTZI1->GetDisplayString(), nOffset1, strPlace1);
|
|
ParseDisplayStr(pTZI2->GetDisplayString(), nOffset2, strPlace2);
|
|
|
|
int nCmpRes = XTPCompare(nOffset1, nOffset2);
|
|
if (nCmpRes)
|
|
{
|
|
return nCmpRes;
|
|
}
|
|
|
|
return XTPCompare(strPlace1, strPlace2);
|
|
}
|
|
|
|
int CXTPCalendarTimeZones::GetCount() const
|
|
{
|
|
return m_arTZInfo.GetCount();
|
|
}
|
|
|
|
CXTPCalendarTimeZone* CXTPCalendarTimeZones::GetAt(long nIndex) const
|
|
{
|
|
if (nIndex < 0 || nIndex >= m_arTZInfo.GetCount())
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
CXTPCalendarTimeZone* pTZI = m_arTZInfo.GetAt(nIndex, FALSE);
|
|
return pTZI;
|
|
}
|
|
|
|
CXTPCalendarTimeZone* CXTPCalendarTimeZones::Find(const TIME_ZONE_INFORMATION* pTZI2) const
|
|
{
|
|
if (!pTZI2)
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
int nCount = GetCount();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
CXTPCalendarTimeZone* pTZI = GetAt(i);
|
|
if (!pTZI)
|
|
{
|
|
ASSERT(FALSE);
|
|
continue;
|
|
}
|
|
if (pTZI->IsEqual(pTZI2))
|
|
{
|
|
return pTZI;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|