Index: src/ch/CfgProperties.cpp =================================================================== diff -u -r0373359eff650e8cf04a5992711ef9f20347536f -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/CfgProperties.cpp (.../CfgProperties.cpp) (revision 0373359eff650e8cf04a5992711ef9f20347536f) +++ src/ch/CfgProperties.cpp (.../CfgProperties.cpp) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -33,6 +33,9 @@ pManager->register_bool(_t("Program/Enabled clipboard monitoring"), false); pManager->register_signed_num(_t("Program/Monitor scan interval"), 1000, 0, llHour); pManager->register_bool(_t("Program/Reload after restart"), false); + pManager->register_bool(_t("Program/Check for updates at startup"), true); + pManager->register_bool(_t("Program/Updater checks for beta"), true); + pManager->register_bool(_t("Program/Shutdown system after finished"), false); pManager->register_signed_num(_t("Program/Time before shutdown"), 10000, 0, 24*llHour); pManager->register_bool(_t("Program/Force shutdown"), false); Index: src/ch/CfgProperties.h =================================================================== diff -u -r0373359eff650e8cf04a5992711ef9f20347536f -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/CfgProperties.h (.../CfgProperties.h) (revision 0373359eff650e8cf04a5992711ef9f20347536f) +++ src/ch/CfgProperties.h (.../CfgProperties.h) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -29,6 +29,8 @@ PP_PCLIPBOARDMONITORING = 0, PP_PMONITORSCANINTERVAL, PP_PRELOADAFTERRESTART, + PP_PCHECK_FOR_UPDATES_AT_STARTUP, + PP_PUPDATE_CHECK_FOR_BETA, PP_PSHUTDOWNAFTREFINISHED, PP_PTIMEBEFORESHUTDOWN, PP_PFORCESHUTDOWN, Index: src/ch/MainWnd.cpp =================================================================== diff -u -r0373359eff650e8cf04a5992711ef9f20347536f -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision 0373359eff650e8cf04a5992711ef9f20347536f) +++ src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -177,6 +177,14 @@ // start clipboard monitoring CClipboardMonitor::StartMonitor(&m_tasks); + if(GetConfig().get_bool(PP_PCHECK_FOR_UPDATES_AT_STARTUP)) + { + CUpdaterDlg* pDlg = new CUpdaterDlg(true); + pDlg->m_bAutoDelete = true; + + pDlg->Create(); + } + // start saving timer SetTimer(1023, (UINT)GetConfig().get_signed_num(PP_PAUTOSAVEINTERVAL), NULL); @@ -900,7 +908,7 @@ void CMainWnd::OnPopupCheckForUpdates() { - CUpdaterDlg* pDlg = new CUpdaterDlg; + CUpdaterDlg* pDlg = new CUpdaterDlg(false); pDlg->m_bAutoDelete = true; pDlg->Create(); Index: src/ch/OptionsDlg.cpp =================================================================== diff -u -r0373359eff650e8cf04a5992711ef9f20347536f -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/OptionsDlg.cpp (.../OptionsDlg.cpp) (revision 0373359eff650e8cf04a5992711ef9f20347536f) +++ src/ch/OptionsDlg.cpp (.../OptionsDlg.cpp) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -228,6 +228,8 @@ PROP_BOOL(IDS_CLIPBOARDMONITORING_STRING, GetConfig().get_bool(PP_PCLIPBOARDMONITORING)) PROP_UINT(IDS_CLIPBOARDINTERVAL_STRING, GetConfig().get_signed_num(PP_PMONITORSCANINTERVAL)) PROP_BOOL(IDS_AUTORUNPROGRAM_STRING, GetConfig().get_bool(PP_PRELOADAFTERRESTART)) + PROP_BOOL(IDS_CFG_CHECK_FOR_UPDATES_AT_STARTUP, GetConfig().get_bool(PP_PCHECK_FOR_UPDATES_AT_STARTUP)) + PROP_BOOL(IDS_CFG_UPDATE_CHECK_FOR_BETA, GetConfig().get_bool(PP_PUPDATE_CHECK_FOR_BETA)) PROP_BOOL(IDS_AUTOSHUTDOWN_STRING, GetConfig().get_bool(PP_PSHUTDOWNAFTREFINISHED)) PROP_UINT(IDS_SHUTDOWNTIME_STRING, GetConfig().get_signed_num(PP_PTIMEBEFORESHUTDOWN)) PROP_COMBO(IDS_FORCESHUTDOWN_STRING, IDS_FORCESHUTDOWNVALUES_STRING, GetConfig().get_bool(PP_PFORCESHUTDOWN)) @@ -349,6 +351,8 @@ rConfig.set_bool(PP_PCLIPBOARDMONITORING, GetBoolProp(iPosition++)); rConfig.set_signed_num(PP_PMONITORSCANINTERVAL, GetUintProp(iPosition++)); rConfig.set_bool(PP_PRELOADAFTERRESTART, GetBoolProp(iPosition++)); + rConfig.set_bool(PP_PCHECK_FOR_UPDATES_AT_STARTUP, GetBoolProp(iPosition++)); + rConfig.set_bool(PP_PUPDATE_CHECK_FOR_BETA, GetBoolProp(iPosition++)); rConfig.set_bool(PP_PSHUTDOWNAFTREFINISHED, GetBoolProp(iPosition++)); rConfig.set_signed_num(PP_PTIMEBEFORESHUTDOWN, GetUintProp(iPosition++)); rConfig.set_bool(PP_PFORCESHUTDOWN, GetBoolProp(iPosition++)); Index: src/ch/Stdafx.h =================================================================== diff -u -rf6706e71721e6828e4e3be894caec6808e27630b -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/Stdafx.h (.../Stdafx.h) (revision f6706e71721e6828e4e3be894caec6808e27630b) +++ src/ch/Stdafx.h (.../Stdafx.h) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -31,6 +31,8 @@ #include #include +#include + #pragma warning (disable: 4711) #include "debug.h" #include "../libicpf/file.h" Index: src/ch/UpdateChecker.cpp =================================================================== diff -u -rd5c3edd0d167db9b5d47d04248820fda49499a5e -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/UpdateChecker.cpp (.../UpdateChecker.cpp) (revision d5c3edd0d167db9b5d47d04248820fda49499a5e) +++ src/ch/UpdateChecker.cpp (.../UpdateChecker.cpp) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -1,112 +1,755 @@ +// ============================================================================ +// Copyright (C) 2001-2009 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library 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. +// ============================================================================ +/// @file UpdateChecker.cpp +/// @date 2009/04/18 +/// @brief Contains an implementation of update checker class. +// ============================================================================ #include "stdafx.h" #include "UpdateChecker.h" #include #include #include "../common/version.h" #include "../libicpf/cfg.h" #include "../libicpf/exception.h" +#include "../libicpf/circ_buffer.h" -CUpdateChecker::ECheckResult CUpdateChecker::CheckForUpdates(const tchar_t* pszSite, bool bCheckBeta) +// timeout used with waiting for events (avoiding hangs) +#define FORCE_TIMEOUT 60000 + +// ============================================================================ +/// CAsyncHttpFile::CAsyncHttpFile +/// @date 2009/04/18 +/// +/// @brief Constructs the CAsyncHttpFile object. +// ============================================================================ +CAsyncHttpFile::CAsyncHttpFile() : + m_hInternet(NULL), + m_hOpenUrl(NULL), + m_dwExpectedState(0), + m_hFinishedEvent(NULL), + m_dwError(0) { - try + memset(&m_internetBuffers, 0, sizeof(INTERNET_BUFFERS)); +} + +// ============================================================================ +/// CAsyncHttpFile::~CAsyncHttpFile +/// @date 2009/04/18 +/// +/// @brief Destructs the CASyncHttpFile object. +// ============================================================================ +CAsyncHttpFile::~CAsyncHttpFile() +{ + Close(); +} + +// ============================================================================ +/// CAsyncHttpFile::Open +/// @date 2009/04/18 +/// +/// @brief Opens the specified internet address (starts those operations). +/// @param[in] pszPath Url to be opened (full path to file). +/// @return S_OK if opened, S_FALSE if wait for result is needed, E_* for errors. +// ============================================================================ +HRESULT CAsyncHttpFile::Open(const tchar_t* pszPath) +{ + if(!pszPath) + return E_INVALIDARG; + + if(m_hInternet || m_hFinishedEvent) + return E_FAIL; + + // create event + m_hFinishedEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + if(!m_hFinishedEvent) + return E_FAIL; + + m_hInternet = ::InternetOpen(_T(PRODUCT_NAME), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC); + if(!m_hInternet) { - CString strSite(pszSite); - strSite.Replace(_T("http://"), _T("")); + ::CloseHandle(m_hFinishedEvent); + m_hFinishedEvent = NULL; - CInternetSession inetSession; - CHttpConnection* pHttpConnection = inetSession.GetHttpConnection(strSite, INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 80); - if(!pHttpConnection) - { - m_eResult = eResult_Error; - return m_eResult; - } + m_dwError = GetLastError(); + return E_FAIL; + } - CString strAddr = _T("chver.ini"); - CHttpFile* pHttpFile = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_GET, strAddr); - if(!pHttpFile) + if(::InternetSetStatusCallback(m_hInternet, (INTERNET_STATUS_CALLBACK)&CAsyncHttpFile::InternetStatusCallback) == INTERNET_INVALID_STATUS_CALLBACK) + { + m_dwError = GetLastError(); + ::InternetCloseHandle(m_hInternet); + ::CloseHandle(m_hFinishedEvent); + + m_hFinishedEvent = NULL; + return E_FAIL; + } + + m_dwExpectedState = INTERNET_STATUS_REQUEST_COMPLETE; + m_hOpenUrl = ::InternetOpenUrl(m_hInternet, pszPath, NULL, 0, INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, (DWORD_PTR)this); + if(!m_hOpenUrl) + { + m_dwError = ::GetLastError(); + if(m_dwError != ERROR_IO_PENDING) { - m_eResult = eResult_Error; - return m_eResult; + ::InternetSetStatusCallback(m_hInternet, NULL); + ::InternetCloseHandle(m_hInternet); + ::CloseHandle(m_hFinishedEvent); + m_hInternet = NULL; + m_hFinishedEvent = NULL; + m_dwExpectedState = 0; + + return E_FAIL; } + } + else + m_dwExpectedState = 0; // everything has been completed - if(!pHttpFile->SendRequest()) + if(m_hOpenUrl) + ::SetEvent(m_hFinishedEvent); + + return m_hOpenUrl ? S_OK : S_FALSE; +} + +// ============================================================================ +/// CAsyncHttpFile::GetFileSize +/// @date 2009/04/18 +/// +/// @brief Retrieves the size of file opened with CAsyncHttpFile::Open() +// (if such information exists in http headers). +/// @param[out] stSize Receives the size of file (receives 65536 if http headers +/// did not contain the information). +/// @return Result of the operation. +// ============================================================================ +HRESULT CAsyncHttpFile::GetFileSize(size_t& stSize) +{ + if(!m_hInternet || !m_hOpenUrl) + return E_FAIL; + + DWORD dwContentLengthSize = sizeof(DWORD); + if(!HttpQueryInfo(m_hOpenUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &stSize, &dwContentLengthSize, NULL) || stSize == 0 || stSize > 1*1024UL*1024UL) + { + stSize = 65536; // safe fallback + return S_FALSE; + } + + return S_OK; +} + +// ============================================================================ +/// CAsyncHttpFile::RequestData +/// @date 2009/04/18 +/// +/// @brief Requests the data from already opened url. +/// @param[in] pBuffer Buffer for the data. +/// @param[in] stSize Buffer size. +/// @return S_OK if completed, S_FALSE if needs waiting, E_* on error. +// ============================================================================ +HRESULT CAsyncHttpFile::RequestData(void* pBuffer, size_t stSize) +{ + if(!pBuffer) + return E_INVALIDARG; + if(!m_hInternet || !m_hOpenUrl || !m_hFinishedEvent) + return E_FAIL; + + if(!::ResetEvent(m_hFinishedEvent)) + return E_FAIL; + + memset(&m_internetBuffers, 0, sizeof(INTERNET_BUFFERS)); + m_internetBuffers.dwStructSize = sizeof(INTERNET_BUFFERS); + m_internetBuffers.dwBufferLength = stSize; + m_internetBuffers.dwBufferTotal = stSize; + m_internetBuffers.lpvBuffer = pBuffer; + + m_dwExpectedState = INTERNET_STATUS_REQUEST_COMPLETE; + if(!::InternetReadFileEx(m_hOpenUrl, &m_internetBuffers, IRF_NO_WAIT, (DWORD_PTR)this)) + { + if((m_dwError = ::GetLastError()) == ERROR_IO_PENDING) + return S_FALSE; + else + return E_FAIL; + } + + if(!::SetEvent(m_hFinishedEvent)) + return E_FAIL; + + return S_OK; +} + +// ============================================================================ +/// CAsyncHttpFile::RetrieveRequestedData +/// @date 2009/04/18 +/// +/// @brief Retrieves the size of data retrieved. +/// @param[out] stSize Receives the size of data read from file. +/// @return Result of the operation. +// ============================================================================ +HRESULT CAsyncHttpFile::GetRetrievedDataSize(size_t& stSize) +{ + if(!m_hInternet) + return E_FAIL; + + stSize = m_internetBuffers.dwBufferLength; + + return S_OK; +} + +// ============================================================================ +/// CAsyncHttpFile::Close +/// @date 2009/04/18 +/// +/// @brief Closes the file. +/// @return Result of the operation. +// ============================================================================ +HRESULT CAsyncHttpFile::Close() +{ + if(m_hOpenUrl) + { + m_dwExpectedState = INTERNET_STATUS_CLOSING_CONNECTION; + if(!::InternetCloseHandle(m_hOpenUrl)) { - m_eResult = eResult_Error; - return m_eResult; + if(::GetLastError() == ERROR_IO_PENDING) + return S_FALSE; + else + return E_FAIL; } - const size_t stBufferSize(65536); - tchar_t* pszBuf = new tchar_t[stBufferSize]; - UINT uiRD = pHttpFile->Read(pszBuf, stBufferSize - 1); - if(uiRD > 0) - pszBuf[uiRD] = _T('\0'); + // if closing url handle succeeded, we close internet here, if not + // then a separate call to close need to be performed. + m_dwExpectedState = 0; + m_hOpenUrl = NULL; + ::InternetCloseHandle(m_hInternet); + } - // convert text to unicode - icpf::config cfg(icpf::config::eIni); - const uint_t uiVersionNumeric = cfg.register_string(_t("Version/Numeric"), _t("")); - const uint_t uiVersionReadable = cfg.register_string(_t("Version/Human Readable"), _t("")); - const uint_t uiDownloadAddress = cfg.register_string(_t("Version/Download Address"), pszSite); - const uint_t uiBetaVersionNumeric = cfg.register_string(_t("Version/Numeric Beta"), _t("")); - const uint_t uiBetaVersionReadable = cfg.register_string(_t("Version/Human Readable Beta"), _t("")); - const uint_t uiBetaDownloadAddress = cfg.register_string(_t("Version/Download Address Beta"), pszSite); - try + if(m_hFinishedEvent) + { + ::CloseHandle(m_hFinishedEvent); + m_hFinishedEvent = NULL; + } + + + return S_OK; +} + +// ============================================================================ +/// CAsyncHttpFile::GetResult +/// @date 2009/04/18 +/// +/// @brief Retrieves the last call result (blocking call). +/// @return Result of the last call. +// ============================================================================ +CAsyncHttpFile::EWaitResult CAsyncHttpFile::GetResult() +{ + HANDLE hHandles[] = { m_hFinishedEvent }; + DWORD dwEffect = WaitForMultipleObjects(1, hHandles, FALSE, 0); + if(dwEffect == WAIT_OBJECT_0 + 0 || dwEffect == WAIT_ABANDONED_0 + 0) + return m_dwError == ERROR_SUCCESS ? CAsyncHttpFile::eFinished : CAsyncHttpFile::eError; + else + return CAsyncHttpFile::ePending; +} + +// ============================================================================ +/// CAsyncHttpFile::WaitForResult +/// @date 2009/04/18 +/// +/// @brief Waits for the result with additional 'kill' event. +/// @param[in] hKillEvent Event handle that would break waiting for result. +/// @return Result of waiting. +// ============================================================================ +CAsyncHttpFile::EWaitResult CAsyncHttpFile::WaitForResult(HANDLE hKillEvent) +{ + HANDLE hHandles[] = { hKillEvent, m_hFinishedEvent }; + DWORD dwEffect = WaitForMultipleObjects(2, hHandles, FALSE, FORCE_TIMEOUT); + if(dwEffect == 0xffffffff) + { + TRACE(_T("[CAsyncHttpFile::WaitForResult()] Wait failed with system error %lu\n"), ::GetLastError()); + return CAsyncHttpFile::eError; + } + else if(dwEffect == WAIT_OBJECT_0 + 0 || dwEffect == WAIT_ABANDONED_0 + 0) + return CAsyncHttpFile::eKilled; + else if(dwEffect == WAIT_OBJECT_0 + 1 || dwEffect == WAIT_ABANDONED_0 + 1) + return m_dwError == ERROR_SUCCESS ? CAsyncHttpFile::eFinished : CAsyncHttpFile::eError; + else + return CAsyncHttpFile::eTimeout; +} + +// ============================================================================ +/// CAsyncHttpFile::InternetStatusCallback +/// @date 2009/04/18 +/// +/// @brief Callback for use with internet API. +/// @param[in] hInternet Internet handle. +/// @param[in] dwContext Context value. +/// @param[in] dwInternetStatus Internet status. +/// @param[in] lpvStatusInformation Additional status information. +/// @param[in] dwStatusInformationLength Length of lpvStatusInformation. +// ============================================================================ +void CAsyncHttpFile::InternetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD /*dwStatusInformationLength*/) +{ + TRACE(_T("[InternetStatusCallback] hInternet: %p, dwInternetStatus: %lu\n"), hInternet, dwInternetStatus); + CAsyncHttpFile* pAsyncHttpFile = (CAsyncHttpFile*)dwContext; + BOOST_ASSERT(pAsyncHttpFile); + if(!pAsyncHttpFile) + return; + + DWORD dwError = ERROR_SUCCESS; + switch(dwInternetStatus) + { + case INTERNET_STATUS_HANDLE_CREATED: { - cfg.read_from_buffer(pszBuf, uiRD); + INTERNET_ASYNC_RESULT* res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation; + pAsyncHttpFile->SetUrlHandle((HINTERNET)(res->dwResult)); + break; } - catch(icpf::exception& e) + case INTERNET_STATUS_REQUEST_COMPLETE: { - m_strLastError = e.get_desc(); - - delete [] pszBuf; - m_eResult = eResult_Error; - return m_eResult; + INTERNET_ASYNC_RESULT* pResult = (INTERNET_ASYNC_RESULT*)lpvStatusInformation; + dwError = pResult->dwError; + break; } - delete [] pszBuf; + case INTERNET_STATUS_CLOSING_CONNECTION: + { + pAsyncHttpFile->SetUrlHandle(NULL); + break; + } + case INTERNET_STATUS_CONNECTION_CLOSED: + { + break; + } + default: + TRACE(_T("[CAsyncHttpFile::InternetStatusCallback()] Unhandled status: %lu\n"), dwInternetStatus); + } - if(bCheckBeta) + pAsyncHttpFile->SetErrorCode(dwError); + pAsyncHttpFile->SetCompletionStatus(dwInternetStatus); +} + + +// ============================================================================ +/// CAsyncHttpFile::SetUrlHandle +/// @date 2009/04/18 +/// +/// @brief Sets the url handle. +/// @param[in] hOpenUrl Handle to be set. +// ============================================================================ +void CAsyncHttpFile::SetUrlHandle(HANDLE hOpenUrl) +{ + m_hOpenUrl = hOpenUrl; +} + +// ============================================================================ +/// CAsyncHttpFile::SetErrorCode +/// @date 2009/04/18 +/// +/// @brief Sets the error code. +/// @param[in] dwError Error code to be set. +// ============================================================================ +void CAsyncHttpFile::SetErrorCode(DWORD dwError) +{ + m_dwError = dwError; +} + +// ============================================================================ +/// CAsyncHttpFile::SetCompletionStatus +/// @date 2009/04/18 +/// +/// @brief Sets the completion status. +/// @param[in] dwCurrentState State to be set. +/// @return Result of the operation. +// ============================================================================ +HRESULT CAsyncHttpFile::SetCompletionStatus(DWORD dwCurrentState) +{ + if(!m_hFinishedEvent) + return E_FAIL; + + if(dwCurrentState == m_dwExpectedState || dwCurrentState == INTERNET_STATUS_CLOSING_CONNECTION) + return ::SetEvent(m_hFinishedEvent) ? S_OK : E_FAIL; + return S_FALSE; +} + +// ============================================================================ +/// CUpdateChecker::CUpdateChecker +/// @date 2009/04/18 +/// +/// @brief Constructs the update checker object. +// ============================================================================ +CUpdateChecker::CUpdateChecker() : + m_hThread(NULL), + m_hKillEvent(NULL), + m_eResult(eResult_Undefined), + m_bCheckForBeta(false) +{ + m_hKillEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + BOOST_ASSERT(m_hKillEvent); + ::InitializeCriticalSection(&m_cs); +} + +// ============================================================================ +/// CUpdateChecker::~CUpdateChecker +/// @date 2009/04/18 +/// +/// @brief Destroys the update checker object. +// ============================================================================ +CUpdateChecker::~CUpdateChecker() +{ + Cleanup(); + + ::DeleteCriticalSection(&m_cs); +} + +// ============================================================================ +/// CUpdateChecker::AsyncCheckForUpdates +/// @date 2009/04/18 +/// +/// @brief Starts the asynchronous checking for updates. +/// @param[in] pszSite Site where to search for updates (without file name). +/// @param[in] bCheckBeta States if we are interested in beta products. +/// @return True if operation started, false otherwise. +// ============================================================================ +bool CUpdateChecker::AsyncCheckForUpdates(const tchar_t* pszSite, bool bCheckBeta, bool bOnlyIfConnected) +{ + if(!pszSite) + return false; + + DWORD dwConnectionFlags = 0; + + if(bOnlyIfConnected && !InternetGetConnectedState(&dwConnectionFlags, 0)) + return false; + + m_strSite = pszSite; + m_eResult = eResult_Undefined; + m_bCheckForBeta = bCheckBeta; + + ::ResetEvent(m_hKillEvent); + + m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&CUpdateChecker::UpdateCheckThread, (void*)this, 0, NULL); + if(!m_hThread) + { + m_strSite.Empty(); + m_eResult = eResult_Undefined; + m_bCheckForBeta = false; + return false; + } + + return true; +} + +// ============================================================================ +/// CUpdateChecker::Cleanup +/// @date 2009/04/18 +/// +/// @brief Stops scanning for updates and clears the object. +// ============================================================================ +void CUpdateChecker::Cleanup() +{ + if(m_hThread) + { + if(m_hKillEvent) + ::SetEvent(m_hKillEvent); + WaitForSingleObject(m_hThread, 5000); + if(m_hKillEvent) + ::CloseHandle(m_hKillEvent); + } + + m_httpFile.Close(); + + ::EnterCriticalSection(&m_cs); + m_hThread = NULL; + m_hKillEvent = NULL; + m_strSite.Empty(); + m_bCheckForBeta = false; + m_strLastError.Empty(); + m_strNumericVersion.Empty(); + m_strReadableVersion.Empty(); + m_strDownloadAddress.Empty(); + m_eResult = CUpdateChecker::eResult_Undefined; + ::LeaveCriticalSection(&m_cs); +} + +// ============================================================================ +/// CUpdateChecker::SetResult +/// @date 2009/04/18 +/// +/// @brief Sets the result of checking. +/// @param[in] eCheckResult Result to be set. +/// @param[in] dwError Error code (if any). +// ============================================================================ +void CUpdateChecker::SetResult(ECheckResult eCheckResult, DWORD dwError) +{ + CString strError; + + if(eCheckResult == eResult_Error && dwError != 0) + { + PTSTR pszBuffer = strError.GetBufferSetLength(_MAX_PATH); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pszBuffer, _MAX_PATH, NULL); + strError.ReleaseBuffer(); + + if(strError.IsEmpty()) { - m_strReadableVersion = cfg.get_string(uiBetaVersionReadable); - m_strNumericVersion = cfg.get_string(uiBetaVersionNumeric); - m_strDownloadAddress = cfg.get_string(uiBetaDownloadAddress); + pszBuffer = strError.GetBufferSetLength(_MAX_PATH); + FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(_T("wininet.dll")), dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pszBuffer, _MAX_PATH, NULL); + strError.ReleaseBuffer(); } - if(!bCheckBeta || m_strNumericVersion.IsEmpty()) + if(strError.IsEmpty()) + strError.Format(_T("0x%lx"), dwError); + } + + strError.TrimRight(_T("\r\n \t")); + + ::EnterCriticalSection(&m_cs); + + m_eResult = eCheckResult; + m_strLastError = strError; + + ::LeaveCriticalSection(&m_cs); +} + +// ============================================================================ +/// CUpdateChecker::SetLastError +/// @date 2009/04/18 +/// +/// @brief Sets last error. +/// @param[in] pszError String containing the last error description. +// ============================================================================ +void CUpdateChecker::SetLastError(PCTSTR pszError) +{ + ::EnterCriticalSection(&m_cs); + m_strLastError = pszError; + ::LeaveCriticalSection(&m_cs); +} + +// ============================================================================ +/// CUpdateChecker::SetVersionsAndAddress +/// @date 2009/04/18 +/// +/// @brief Sets the download address and version information. +/// @param[in] pszAddress Download address. +/// @param[in] pszNumericVersion Numeric version number. +/// @param[in] pszReadableVersion Human readable version number. +// ============================================================================ +void CUpdateChecker::SetVersionsAndAddress(PCTSTR pszAddress, PCTSTR pszNumericVersion, PCTSTR pszReadableVersion) +{ + ::EnterCriticalSection(&m_cs); + m_strDownloadAddress = pszAddress; + m_strNumericVersion = pszNumericVersion; + m_strReadableVersion = pszReadableVersion; + ::LeaveCriticalSection(&m_cs); +} + +// ============================================================================ +/// CUpdateChecker::GetSiteAddress +/// @date 2009/04/18 +/// +/// @brief Retrieves the address of a site to check the updates at. +/// @param[out] rstrAddress Receives the address. +// ============================================================================ +void CUpdateChecker::GetSiteAddress(CString& rstrAddress) const +{ + ::EnterCriticalSection(&m_cs); + rstrAddress = m_strSite; + ::LeaveCriticalSection(&m_cs); +} + +// ============================================================================ +/// CUpdateChecker::CheckForBeta +/// @date 2009/04/18 +/// +/// @brief Returns information, if update should check for beta versions. +/// @return True if beta versions should be processed, false otherwise. +// ============================================================================ +bool CUpdateChecker::CheckForBeta() +{ + ::EnterCriticalSection(&m_cs); + bool bCheckForBeta = m_bCheckForBeta; + ::LeaveCriticalSection(&m_cs); + + return bCheckForBeta; +} + +// ============================================================================ +/// CUpdateChecker::GetResult +/// @date 2009/04/18 +/// +/// @brief Retrieves the result of checking for updates. +/// @return Check for updates result. +// ============================================================================ +CUpdateChecker::ECheckResult CUpdateChecker::GetResult() const +{ + ::EnterCriticalSection(&m_cs); + ECheckResult eResult = m_eResult; + ::LeaveCriticalSection(&m_cs); + return eResult; +} + +// ============================================================================ +/// CUpdateChecker::UpdateCheckThread +/// @date 2009/04/18 +/// +/// @brief Main thread function. +/// @param[in] pParam Pointer to the thread parameter (pointer to the CUpdateChecker object). +/// @return Thread execution status. +// ============================================================================ +DWORD CUpdateChecker::UpdateCheckThread(LPVOID pParam) +{ + CUpdateChecker* pUpdateChecker = (CUpdateChecker*)pParam; + + // mark as started + pUpdateChecker->SetResult(eResult_Pending, 0); + + // get the real address of file to download + CString strSite; + pUpdateChecker->GetSiteAddress(strSite); + strSite += _T("/chver.ini"); + + CAsyncHttpFile::EWaitResult eWaitResult = CAsyncHttpFile::ePending; + size_t stFileSize = 0; + byte_t* pbyBuffer = NULL; + icpf::circular_buffer circBuffer; + + // open the connection and try to get to the file + HRESULT hResult = pUpdateChecker->m_httpFile.Open(strSite); + if(SUCCEEDED(hResult)) + { + eWaitResult = pUpdateChecker->m_httpFile.WaitForResult(pUpdateChecker->m_hKillEvent); + switch(eWaitResult) { - m_strNumericVersion = cfg.get_string(uiVersionNumeric); - m_strReadableVersion = cfg.get_string(uiVersionReadable); - m_strDownloadAddress = cfg.get_string(uiDownloadAddress); + case CAsyncHttpFile::eFinished: + break; + case CAsyncHttpFile::eKilled: + pUpdateChecker->SetResult(eResult_Killed, 0); + return 1; + break; + case CAsyncHttpFile::eError: + pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); + return 1; + case CAsyncHttpFile::eTimeout: + case CAsyncHttpFile::ePending: + default: + pUpdateChecker->SetResult(eResult_Error, 0); + return 1; } + } + if(SUCCEEDED(hResult)) + hResult = pUpdateChecker->m_httpFile.GetFileSize(stFileSize); - // and compare to current version - ushort_t usVer[4]; - if(_stscanf(m_strNumericVersion, _t("%hu.%hu.%hu.%hu"), &usVer[0], &usVer[1], &usVer[2], &usVer[3]) != 4) + if(SUCCEEDED(hResult)) + { + bool bIsClosed = false; + pbyBuffer = new byte_t[stFileSize]; + do { - TRACE(_T("Error parsing retrieved version number.")); - m_eResult = eResult_Error; - return m_eResult; + hResult = pUpdateChecker->m_httpFile.RequestData(pbyBuffer, stFileSize); + if(SUCCEEDED(hResult)) + { + eWaitResult = pUpdateChecker->m_httpFile.WaitForResult(pUpdateChecker->m_hKillEvent); + switch(eWaitResult) + { + case CAsyncHttpFile::eFinished: + break; + case CAsyncHttpFile::eKilled: + pUpdateChecker->SetResult(eResult_Killed, 0); + return 1; + break; + case CAsyncHttpFile::eError: + pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); + return 1; + case CAsyncHttpFile::eTimeout: + case CAsyncHttpFile::ePending: + default: + pUpdateChecker->SetResult(eResult_Error, 0); + return 1; + } + } + + if(SUCCEEDED(hResult)) + hResult = pUpdateChecker->m_httpFile.GetRetrievedDataSize(stFileSize); + + if(SUCCEEDED(hResult) && stFileSize) + circBuffer.push_data(pbyBuffer, stFileSize); + + bIsClosed = pUpdateChecker->m_httpFile.IsClosed(); } + while(stFileSize && !bIsClosed && SUCCEEDED(hResult)); - ull_t ullCurrentVersion = ((ull_t)PRODUCT_VERSION1) << 48 | ((ull_t)PRODUCT_VERSION2) << 32 | ((ull_t)PRODUCT_VERSION3) << 16 | ((ull_t)PRODUCT_VERSION4); - ull_t ullSiteVersion = ((ull_t)usVer[0]) << 48 | ((ull_t)usVer[1]) << 32 | ((ull_t)usVer[2]) << 16 | ((ull_t)usVer[3]); + delete [] pbyBuffer; + } - if(ullCurrentVersion < ullSiteVersion) - m_eResult = eResult_VersionNewer; - else if(ullCurrentVersion == ullSiteVersion) - m_eResult = eResult_VersionCurrent; - else - m_eResult = eResult_VersionOlder; + if(FAILED(hResult)) + { + pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); + return 1; + } - return m_eResult; + pUpdateChecker->m_httpFile.Close(); + + // convert text to unicode + icpf::config cfg(icpf::config::eIni); + const uint_t uiVersionNumeric = cfg.register_string(_t("Version/Numeric"), _t("")); + const uint_t uiVersionReadable = cfg.register_string(_t("Version/Human Readable"), _t("")); + const uint_t uiDownloadAddress = cfg.register_string(_t("Version/Download Address"), strSite); + const uint_t uiBetaVersionNumeric = cfg.register_string(_t("Version/Numeric Beta"), _t("")); + const uint_t uiBetaVersionReadable = cfg.register_string(_t("Version/Human Readable Beta"), _t("")); + const uint_t uiBetaDownloadAddress = cfg.register_string(_t("Version/Download Address Beta"), strSite); + try + { + cfg.read_from_buffer((TCHAR*)circBuffer.get_buffer(), (circBuffer.get_datasize() + 1) / 2); } - catch(CInternetException* e) + catch(icpf::exception& e) { - TCHAR* pszBuffer = m_strLastError.GetBufferSetLength(1024); - e->GetErrorMessage(pszBuffer, 1023); - pszBuffer[1023] = _T('\0'); - m_strLastError.ReleaseBuffer(); - m_strLastError.TrimRight(); + pUpdateChecker->SetResult(eResult_Error, 0); + pUpdateChecker->SetLastError(e.get_desc()); - m_eResult = eResult_Error; - return m_eResult; + return 0xffffffff; } + + CString strVersionNumeric; + bool bCheckForBeta = pUpdateChecker->CheckForBeta(); + if(bCheckForBeta) + { + strVersionNumeric = cfg.get_string(uiBetaVersionNumeric); + pUpdateChecker->SetVersionsAndAddress(cfg.get_string(uiBetaDownloadAddress), strVersionNumeric, cfg.get_string(uiBetaVersionReadable)); + } + + if(!bCheckForBeta || strVersionNumeric.IsEmpty()) + { + strVersionNumeric = cfg.get_string(uiVersionNumeric); + pUpdateChecker->SetVersionsAndAddress(cfg.get_string(uiDownloadAddress), strVersionNumeric, cfg.get_string(uiVersionReadable)); + } + + // and compare to current version + ushort_t usVer[4]; + if(_stscanf(strVersionNumeric, _t("%hu.%hu.%hu.%hu"), &usVer[0], &usVer[1], &usVer[2], &usVer[3]) != 4) + { + TRACE(_T("Error parsing retrieved version number.")); + pUpdateChecker->SetResult(eResult_Error, 0); + return 0xffffffff; + } + + ull_t ullCurrentVersion = ((ull_t)PRODUCT_VERSION1) << 48 | ((ull_t)PRODUCT_VERSION2) << 32 | ((ull_t)PRODUCT_VERSION3) << 16 | ((ull_t)PRODUCT_VERSION4); + ull_t ullSiteVersion = ((ull_t)usVer[0]) << 48 | ((ull_t)usVer[1]) << 32 | ((ull_t)usVer[2]) << 16 | ((ull_t)usVer[3]); + + if(ullCurrentVersion < ullSiteVersion) + pUpdateChecker->SetResult(eResult_RemoteVersionNewer, 0); + else if(ullCurrentVersion == ullSiteVersion) + pUpdateChecker->SetResult(eResult_VersionCurrent, 0); + else + pUpdateChecker->SetResult(eResult_RemoteVersionOlder, 0); + + return 0; } Index: src/ch/UpdateChecker.h =================================================================== diff -u -rd5c3edd0d167db9b5d47d04248820fda49499a5e -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/UpdateChecker.h (.../UpdateChecker.h) (revision d5c3edd0d167db9b5d47d04248820fda49499a5e) +++ src/ch/UpdateChecker.h (.../UpdateChecker.h) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -1,37 +1,145 @@ +// ============================================================================ +// Copyright (C) 2001-2009 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library 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. +// ============================================================================ +/// @file UpdateChecker.h +/// @date 2009/04/18 +/// @brief Contains declaration of update checker class. +// ============================================================================ #ifndef __UPDATECHECKER_H__ #define __UPDATECHECKER_H__ -class CUpdateChecker +class CAsyncHttpFile { public: + enum EWaitResult + { + eKilled, + eFinished, + eTimeout, + ePending, + eError + }; + +public: + CAsyncHttpFile(); + ~CAsyncHttpFile(); + + HRESULT Open(const tchar_t* pszPath); + HRESULT GetFileSize(size_t& stSize); + + HRESULT RequestData(void* pBuffer, size_t stSize); + HRESULT GetRetrievedDataSize(size_t& stSize); + + HRESULT Close(); + + EWaitResult GetResult(); + DWORD GetErrorCode() { return m_dwError; } + + EWaitResult WaitForResult(HANDLE hKillEvent); + + bool IsClosed() const { return m_hOpenUrl == NULL; } + +protected: + static void InternetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength); + + void SetUrlHandle(HANDLE hOpenUrl); + void SetErrorCode(DWORD dwError); + + /// Sets the completion event + HRESULT SetCompletionStatus(DWORD dwCurrentState); + +protected: + HINTERNET m_hInternet; + HINTERNET m_hOpenUrl; + + DWORD m_dwExpectedState; ///< State we are expecting + HANDLE m_hFinishedEvent; + + INTERNET_BUFFERS m_internetBuffers; + + DWORD m_dwError; +}; + +class CUpdateChecker : protected CInternetSession +{ +public: enum ECheckResult { eResult_Undefined, - eResult_VersionOlder, + eResult_Pending, + eResult_Killed, + eResult_Error, + eResult_RemoteVersionOlder, eResult_VersionCurrent, - eResult_VersionNewer, - eResult_Error + eResult_RemoteVersionNewer }; + public: - CUpdateChecker() : m_eResult(eResult_Undefined) { }; - ~CUpdateChecker() { }; + /// Constructs the update checker object + CUpdateChecker(); + /// Destructs the update checker object + ~CUpdateChecker(); - ECheckResult CheckForUpdates(const tchar_t* pszSite, bool bCheckBeta); + /// Starts the 'check for updates' thread + bool AsyncCheckForUpdates(const tchar_t* pszSite, bool bCheckBeta, bool bOnlyIfConnected); + /// Stops checking and cleanups the object + void Cleanup(); + + /// Retrieves the update result + ECheckResult GetResult() const; + + // methods for retrieving state const tchar_t* GetNumericVersion() const { return (const tchar_t*)m_strNumericVersion; } const tchar_t* GetReadableVersion() const { return (const tchar_t*)m_strReadableVersion; } const tchar_t* GetLastError() const { return (const tchar_t*)m_strLastError; } const tchar_t* GetDownloadAddress() const { return m_strDownloadAddress; } - ECheckResult GetResult() const { return m_eResult; } +protected: + /// Thread function (handles most of the internet connection operation) + static DWORD WINAPI UpdateCheckThread(LPVOID pParam); + /// Sets the result in mt-safe way + void SetResult(ECheckResult eCheckResult, DWORD dwError); + /// Sets the last error + void SetLastError(PCTSTR pszError); + /// Sets the versions and download address + void SetVersionsAndAddress(PCTSTR pszAddress, PCTSTR pszNumericVersion, PCTSTR pszReadableVersion); + /// Retrieves the site address + void GetSiteAddress(CString& rstrAddress) const; + + /// Returns information if we're interested in beta versions + bool CheckForBeta(); + protected: CString m_strSite; + bool m_bCheckForBeta; CString m_strLastError; CString m_strNumericVersion; CString m_strReadableVersion; CString m_strDownloadAddress; + ECheckResult m_eResult; + + CAsyncHttpFile m_httpFile; + HANDLE m_hThread; + HANDLE m_hKillEvent; + mutable CRITICAL_SECTION m_cs; }; #endif Index: src/ch/UpdaterDlg.cpp =================================================================== diff -u -r449a5b399ab21ca0d06050b47b264f2f704af966 -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision 449a5b399ab21ca0d06050b47b264f2f704af966) +++ src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -19,13 +19,16 @@ IMPLEMENT_DYNAMIC(CUpdaterDlg, ictranslate::CLanguageDialog) -CUpdaterDlg::CUpdaterDlg(CWnd* pParent /*=NULL*/) -: ictranslate::CLanguageDialog(CUpdaterDlg::IDD, pParent) +CUpdaterDlg::CUpdaterDlg(bool bBackgroundMode, CWnd* pParent /*=NULL*/) : + ictranslate::CLanguageDialog(CUpdaterDlg::IDD, pParent), + m_eLastState(CUpdateChecker::eResult_Undefined), + m_bBackgroundMode(bBackgroundMode) { } CUpdaterDlg::~CUpdaterDlg() { + m_ucChecker.Cleanup(); } void CUpdaterDlg::DoDataExchange(CDataExchange* pDX) @@ -42,44 +45,19 @@ fmt.SetParam(_t("%site"), _T(PRODUCT_SITE)); m_ctlText.SetWindowText(fmt); + if(!m_bBackgroundMode) + ShowWindow(SW_SHOW); + + // start the updater + m_ucChecker.AsyncCheckForUpdates(_T(PRODUCT_SITE), GetConfig().get_bool(PP_PUPDATE_CHECK_FOR_BETA), m_bBackgroundMode); + + // start a timer to display progress SetTimer(UPDATER_TIMER, 10, NULL); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } -void CUpdaterDlg::StartChecking() -{ - m_ucChecker.CheckForUpdates(_T(PRODUCT_SITE), false); - - ictranslate::CResourceManager& rResManager = GetResManager(); - ictranslate::CFormat fmt; - - CString strFmt; - switch(m_ucChecker.GetResult()) - { - case CUpdateChecker::eResult_Error: - strFmt = rResManager.LoadString(IDS_UPDATER_ERROR_STRING); - break; - case CUpdateChecker::eResult_VersionNewer: - strFmt = rResManager.LoadString(IDS_UPDATER_NEW_VERSION_STRING); - break; - case CUpdateChecker::eResult_VersionCurrent: - strFmt = rResManager.LoadString(IDS_UPDATER_EQUAL_VERSION_STRING); - break; - case CUpdateChecker::eResult_VersionOlder: - strFmt = rResManager.LoadString(IDS_UPDATER_OLD_VERSION_STRING); - break; - } - - fmt.SetFormat(strFmt); - fmt.SetParam(_t("%errdesc"), m_ucChecker.GetLastError()); - fmt.SetParam(_t("%thisver"), _T(PRODUCT_VERSION)); - fmt.SetParam(_t("%officialver"), m_ucChecker.GetReadableVersion()); - - m_ctlText.SetWindowText(fmt); -} - void CUpdaterDlg::OnBnClickedOpenWebpageButton() { ShellExecute(NULL, _T("open"), m_ucChecker.GetDownloadAddress(), NULL, NULL, SW_SHOW); @@ -89,8 +67,86 @@ { if(nIDEvent == UPDATER_TIMER) { - KillTimer(UPDATER_TIMER); - StartChecking(); + ictranslate::CResourceManager& rResManager = GetResManager(); + ictranslate::CFormat fmt; + CUpdateChecker::ECheckResult eResult = m_ucChecker.GetResult(); + CString strFmt; + EBkModeResult eBkMode = eRes_None; + + if(eResult != m_eLastState) + { + switch(m_ucChecker.GetResult()) + { + case CUpdateChecker::eResult_Undefined: + TRACE(_T("CUpdateChecker::eResult_Undefined\n")); + eBkMode = eRes_Exit; + strFmt = rResManager.LoadString(IDS_UPDATER_WAITING_STRING); + break; + case CUpdateChecker::eResult_Pending: + TRACE(_T("CUpdateChecker::eResult_Pending\n")); + strFmt = rResManager.LoadString(IDS_UPDATER_WAITING_STRING); + break; + case CUpdateChecker::eResult_Killed: + TRACE(_T("CUpdateChecker::eResult_Killed\n")); + eBkMode = eRes_Exit; + strFmt = rResManager.LoadString(IDS_UPDATER_ERROR_STRING); + break; + case CUpdateChecker::eResult_Error: + TRACE(_T("CUpdateChecker::eResult_Error\n")); + eBkMode = eRes_Exit; + strFmt = rResManager.LoadString(IDS_UPDATER_ERROR_STRING); + break; + case CUpdateChecker::eResult_RemoteVersionOlder: + TRACE(_T("CUpdateChecker::eResult_RemoteVersionOlder\n")); +// eBkMode = eRes_Exit; + eBkMode = eRes_Show; // for debugging purposes only + strFmt = rResManager.LoadString(IDS_UPDATER_OLD_VERSION_STRING); + break; + case CUpdateChecker::eResult_VersionCurrent: + TRACE(_T("CUpdateChecker::eResult_VersionCurrent\n")); + eBkMode = eRes_Exit; + strFmt = rResManager.LoadString(IDS_UPDATER_EQUAL_VERSION_STRING); + break; + case CUpdateChecker::eResult_RemoteVersionNewer: + TRACE(_T("CUpdateChecker::eResult_RemoteVersionNewer\n")); + eBkMode = eRes_Show; + strFmt = rResManager.LoadString(IDS_UPDATER_NEW_VERSION_STRING); + break; + default: + _ASSERTE(FALSE); + eBkMode = eRes_Exit; + return; + } + + fmt.SetFormat(strFmt); + fmt.SetParam(_t("%site"), _t(PRODUCT_SITE)); + fmt.SetParam(_t("%errdesc"), m_ucChecker.GetLastError()); + fmt.SetParam(_t("%thisver"), _T(PRODUCT_VERSION)); + fmt.SetParam(_t("%officialver"), m_ucChecker.GetReadableVersion()); + + m_ctlText.SetWindowText(fmt); + + m_eLastState = eResult; + + // handle background mode + if(m_bBackgroundMode) + { + switch(eBkMode) + { + case eRes_None: + break; + case eRes_Exit: + KillTimer(UPDATER_TIMER); + EndDialog(IDCANCEL); + return; + case eRes_Show: + ShowWindow(SW_SHOW); + break; + default: + BOOST_ASSERT(FALSE); + } + } + } } CLanguageDialog::OnTimer(nIDEvent); Index: src/ch/UpdaterDlg.h =================================================================== diff -u -r449a5b399ab21ca0d06050b47b264f2f704af966 -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/UpdaterDlg.h (.../UpdaterDlg.h) (revision 449a5b399ab21ca0d06050b47b264f2f704af966) +++ src/ch/UpdaterDlg.h (.../UpdaterDlg.h) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -7,15 +7,20 @@ { DECLARE_DYNAMIC(CUpdaterDlg) + enum EBkModeResult + { + eRes_None, + eRes_Exit, + eRes_Show + }; public: - CUpdaterDlg(CWnd* pParent = NULL); // standard constructor + CUpdaterDlg(bool bBackgroundMode, CWnd* pParent = NULL); // standard constructor virtual ~CUpdaterDlg(); // Dialog Data enum { IDD = IDD_UPDATER_DIALOG }; virtual BOOL OnInitDialog(); - void StartChecking(); afx_msg void OnBnClickedOpenWebpageButton(); afx_msg void OnTimer(UINT_PTR nIDEvent); @@ -28,5 +33,6 @@ protected: CStatic m_ctlText; CUpdateChecker m_ucChecker; - + CUpdateChecker::ECheckResult m_eLastState; + bool m_bBackgroundMode; ///< Do we operate in standard mode (false), or in background mode (true) }; Index: src/ch/ch.rc =================================================================== diff -u -r0373359eff650e8cf04a5992711ef9f20347536f -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/ch.rc (.../ch.rc) (revision 0373359eff650e8cf04a5992711ef9f20347536f) +++ src/ch/ch.rc (.../ch.rc) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -461,8 +461,8 @@ END IDD_UPDATER_DIALOG DIALOGEX 0, 0, 259, 83 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Version information" +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Copy Handler Update Information" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "&Close",IDOK,202,62,50,14 @@ -754,8 +754,8 @@ IDS_CFGSHELL_STRING "Shell" IDS_CFGSCCOUNT_STRING "Defined shortcuts' count" IDS_CFGRPCOUNT_STRING "Count of recent paths" - IDS_CFGINTERCEPTKEYACTION_STRING "Intercept shell keyboard actions (experimental)" - IDS_CFGINTERCEPTCONTEXTMENU_STRING "Intercept standard Windows operations (experimental/not recommended)" + IDS_CFGINTERCEPTKEYACTION_STRING + "Intercept shell keyboard actions (experimental)" IDS_CFGPRIORITYCLASS_STRING "Application's priority class" IDS_CFGDISABLEPRIORITYBOOST_STRING "Disable priority boosting" IDS_BOOLTEXT_STRING "No!Yes" @@ -767,6 +767,15 @@ STRINGTABLE BEGIN + IDS_CFGINTERCEPTCONTEXTMENU_STRING + "Intercept standard Windows operations (experimental/not recommended)" + IDS_CFG_CHECK_FOR_UPDATES_AT_STARTUP + "Automatically check for program updates at startup" + IDS_CFG_UPDATE_CHECK_FOR_BETA "Check for updates - include beta versions" +END + +STRINGTABLE +BEGIN IDS_MINIVIEWAUTOHIDE_STRING "Hide when empty" IDS_PROCESSINGTHREAD_STRING "Copying/moving thread" IDS_AUTOCOPYREST_STRING "Auto ""copy-rest"" of files" Index: src/ch/resource.h =================================================================== diff -u -r0373359eff650e8cf04a5992711ef9f20347536f -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 --- src/ch/resource.h (.../resource.h) (revision 0373359eff650e8cf04a5992711ef9f20347536f) +++ src/ch/resource.h (.../resource.h) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) @@ -424,6 +424,8 @@ #define IDS_LANGSFOLDERCHOOSE_STRING 8094 #define IDS_ABOUT_LANGUAGE_STRING 8095 #define IDS_CFGINTERCEPTCONTEXTMENU_STRING 8096 +#define IDS_CFG_CHECK_FOR_UPDATES_AT_STARTUP 8097 +#define IDS_CFG_UPDATE_CHECK_FOR_BETA 8098 #define IDS_MENUCOPY_STRING 9000 #define IDS_MENUMOVE_STRING 9001 #define IDS_MENUCOPYMOVESPECIAL_STRING 9002