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++

// 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;
}