Index: src/ch/ch.cpp =================================================================== diff -u -rbeeac49d2e0888993bd231a4e5863c7f0741e154 -r8068e0c351055554340ac9755d1bc846893bf2b8 --- src/ch/ch.cpp (.../ch.cpp) (revision beeac49d2e0888993bd231a4e5863c7f0741e154) +++ src/ch/ch.cpp (.../ch.cpp) (revision 8068e0c351055554340ac9755d1bc846893bf2b8) @@ -22,9 +22,27 @@ #include "CfgProperties.h" #include "MainWnd.h" #include "../common/ipcstructs.h" -#include + +#pragma warning(push) +#pragma warning(disable: 4091) + #include +#pragma warning(pop) + #include "CrashDlg.h" #include "../common/version.h" +#include "TCommandLineParser.h" +#include "../libchcore/TStringSet.h" +#include "../libchcore/TSimpleTimer.h" +#include "../libchcore/SerializerTrace.h" +#include +#include "../libchcore/TSQLiteTaskSchema.h" +#include "../libchcore/TSQLiteSerializer.h" +#include "../libchcore/ISerializerContainer.h" +#include "../libchcore/ISerializerRowData.h" +#include "../libchcore/TFileInfo.h" +#include "TMsgBox.h" +#include "../libchcore/TWin32ErrorFormatter.h" +#include "resource.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -36,18 +54,12 @@ static char THIS_FILE[] = __FILE__; #endif -icpf::config CCopyHandlerApp::m_config = icpf::config::eIni; - ///////////////////////////////////////////////////////////////////////////// // CCopyHandlerApp BEGIN_MESSAGE_MAP(CCopyHandlerApp, CWinApp) - //{{AFX_MSG_MAP(CCopyHandlerApp) - //}}AFX_MSG_MAP END_MESSAGE_MAP() -CSharedConfigStruct* g_pscsShared; - int iCount=98; unsigned short msg[]={ 0x40d1, 0x4dcd, 0x8327, 0x6cdf, 0xb912, 0x017b, 0xac78, 0x1e04, 0x5637, 0x1822, 0x0a69, 0x1b40, 0x4169, 0x504d, 0x80ff, 0x6c2f, 0xa612, 0x017e, @@ -74,45 +86,31 @@ // CCopyHandlerApp construction // main routing function - routes any message that comes from modules -void ResManCallback(uint_t uiMsg) +void ResManCallback(unsigned int uiMsg) { theApp.OnResManNotify(uiMsg); } -void ConfigPropertyChangedCallback(uint_t uiPropID, ptr_t /*pParam*/) +void ConfigPropertyChangedCallback(const chcore::TStringSet& setPropNames, void* /*pParam*/) { - theApp.OnConfigNotify(uiPropID); + theApp.OnConfigNotify(setPropNames); } CCopyHandlerApp::CCopyHandlerApp() : - m_piShellExtControl(NULL), - m_hMapObject(NULL), - m_pMainWindow(NULL) + m_pMainWindow(nullptr) { // this is the one-instance application InitProtection(); } CCopyHandlerApp::~CCopyHandlerApp() { - // Unmap shared memory from the process's address space. - UnmapViewOfFile((LPVOID)g_pscsShared); - - // Close the process's handle to the file-mapping object. - CloseHandle(m_hMapObject); - if (m_pMainWindow) { ((CMainWnd*)m_pMainWindow)->DestroyWindow(); delete m_pMainWindow; - m_pMainWnd=NULL; + m_pMainWnd=nullptr; } - - if(m_piShellExtControl) - { - m_piShellExtControl->Release(); - m_piShellExtControl = NULL; - } } CCopyHandlerApp& GetApp() @@ -125,9 +123,10 @@ return ictranslate::CResourceManager::Acquire(); } -icpf::config& GetConfig() +chcore::TConfig& GetConfig() { - return CCopyHandlerApp::m_config; + static chcore::TConfig tCfg; + return tCfg; } int MsgBox(UINT uiID, UINT nType, UINT nIDHelp) @@ -140,14 +139,12 @@ bool bChanged=false; // flag that'll be returned - if the paths has changed // generate the current filename - uses language from config - TCHAR szBuffer[_MAX_PATH]; - _tcscpy(szBuffer, _T("\\Help\\")); - ExpandPath(szBuffer); - _tcscat(szBuffer, GetResManager().m_ld.GetHelpName()); - if(_tcscmp(szBuffer, m_pszHelpFilePath) != 0) + CString strHelpPath = m_pathProcessor.ExpandPath(_T("\\Help\\")); + strHelpPath += GetResManager().m_ld.GetHelpName(); + if(strHelpPath != m_pszHelpFilePath) { free((void*)m_pszHelpFilePath); - m_pszHelpFilePath = _tcsdup(szBuffer); + m_pszHelpFilePath = _tcsdup(strHelpPath); bChanged=true; } @@ -156,48 +153,47 @@ ///////////////////////////////////////////////////////////////////////////// // CCopyHandlerApp initialization -#include "charvect.h" LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo) { // Step1 - should not fail - prepare some more unique crash name, create under the path where ch data exists TCHAR szPath[_MAX_PATH]; - HRESULT hResult = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, szPath); + HRESULT hResult = SHGetFolderPath(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, szPath); if(FAILED(hResult)) _tcscpy(szPath, _T("c:\\")); CString strPath(szPath); // make sure to create the required directories if they does not exist strPath += _T("\\Copy Handler"); - CreateDirectory(strPath, NULL); + CreateDirectory(strPath, nullptr); strPath += _T("\\Dumps"); - CreateDirectory(strPath, NULL); + CreateDirectory(strPath, nullptr); // current date SYSTEMTIME st; GetLocalTime(&st); TCHAR szName[_MAX_PATH]; - _sntprintf(szName, _MAX_PATH, _T("%s\\ch_crashdump-%s-%I64u-%s.dmp"), (PCTSTR)strPath, _T(PRODUCT_VERSION), (ull_t)_time64(NULL), + _sntprintf(szName, _MAX_PATH, _T("%s\\ch_crashdump-%s-%I64u-%s.dmp"), (PCTSTR)strPath, _T(PRODUCT_VERSION), (unsigned long long)_time64(nullptr), #ifdef _WIN64 _T("64") #else _T("32") #endif ); - szPath[_MAX_PATH - 1] = _T('\0'); + szName[_MAX_PATH - 1] = _T('\0'); // Step 2 - create the crash dump in case anything happens later bool bResult = false; - HANDLE hFile = CreateFile(szName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE hFile = CreateFile(szName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if(hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION mei; mei.ThreadId = GetCurrentThreadId(); mei.ExceptionPointers = ExceptionInfo; mei.ClientPointers = TRUE; - if(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithProcessThreadData, &mei, NULL, NULL)) + if(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithProcessThreadData, &mei, nullptr, nullptr)) bResult = true; } @@ -209,11 +205,79 @@ return EXCEPTION_EXECUTE_HANDLER; } +//#define DO_TEST + BOOL CCopyHandlerApp::InitInstance() { +#ifdef DO_TEST + using namespace chcore; + + DeleteFile(_T("C:\\Users\\ixen\\AppData\\Local\\Copy Handler\\Tasks\\test.sqlite")); + TSQLiteTaskSchemaPtr spTaskSchema(new TSQLiteTaskSchema); + + TSQLiteSerializer serializer(PathFromString(_T("C:\\Users\\ixen\\AppData\\Local\\Copy Handler\\Tasks\\test.sqlite")), spTaskSchema); + //TSQLiteSerializer serializer(PathFromString(_T(":memory:")), spTaskSchema); + + TSimpleTimer timer(true); + + { + ISerializerContainerPtr spContainer = serializer.GetContainer(_T("scanned_files")); + + IColumnsDefinition& rColumns = spContainer->GetColumnsDefinition(); + TFileInfo::InitColumns(rColumns); + + const size_t rel_path = rColumns.GetColumnIndex(_T("rel_path")); + const size_t base_path_id = rColumns.GetColumnIndex(_T("base_path_id")); + const size_t attr = rColumns.GetColumnIndex(_T("attr")); + const size_t size = rColumns.GetColumnIndex(_T("size")); + const size_t time_created = rColumns.GetColumnIndex(_T("time_created")); + const size_t time_last_write = rColumns.GetColumnIndex(_T("time_last_write")); + const size_t time_last_access = rColumns.GetColumnIndex(_T("time_last_access")); + const size_t flags = rColumns.GetColumnIndex(_T("flags")); + + TString strPath(_T("C:\\Users\\ixen\\AppData\\Local\\Copy Handler\\Tasks\\sometask.xxx")); + TSmartPath path(PathFromString(_T("C:\\Users\\ixen\\AppData\\Local\\Copy Handler\\Tasks\\sometask.xxx"))); + + for(object_id_t oidIndex = 0; oidIndex < 200000; ++oidIndex) + { + ISerializerRowData& rRow = spContainer->GetRow(oidIndex, true); + rRow.SetValue(rel_path, path); //C:\\Users\\ixen\\AppData\\Local\\Copy Handler\\Tasks\\sometask.xxx + rRow.SetValue(base_path_id, 24735275ull); + rRow.SetValue(attr, 0x56533234ul); + rRow.SetValue(size, 0x565332340897ff12ull); + rRow.SetValue(time_created, 0x565332340897ff12ull); + rRow.SetValue(time_last_write, 0x565122340897ff12ull); + rRow.SetValue(time_last_access, 0x565517840897ff12ull); + rRow.SetValue(flags, 0x56551114u); + } + + unsigned long long ullFillTime = timer.Checkpoint(); ullFillTime; + GTRACE1(_T("***** [FillTime]: %I64u ms\n"), ullFillTime); + + serializer.Flush(); + unsigned long long ullFlushTime = timer.Checkpoint(); ullFlushTime; + GTRACE1(_T("***** [FlushTime]: %I64u ms\n"), ullFlushTime); + + spContainer.reset(); + unsigned long long ullDeleteContainerTime = timer.Checkpoint(); ullDeleteContainerTime; + GTRACE1(_T("***** [DeleteContainer]: %I64u ms\n"), ullDeleteContainerTime); + } + + unsigned long long ullDestructTime = timer.Checkpoint(); ullDestructTime; + GTRACE1(_T("***** [DestructTime]: %I64u ms\n"), ullDestructTime); + + return FALSE; +#else + // ================================= Crash handling ======================================= SetUnhandledExceptionFilter(&MyUnhandledExceptionFilter); + // ================================= Handle command line ================================== + // parse the command line this early, so we can support as much options as possible in the future + // (i.e. override the defaults used below) + if (!ParseCommandLine()) + return FALSE; + // ================================= Configuration ======================================== CString strPath; CString strCfgPath; @@ -227,36 +291,30 @@ return FALSE; } - strCfgPath = strPath + _T("\\ch.ini"); + strCfgPath = strPath + _T("\\ch.xml"); // initialize configuration file - m_config.set_callback(ConfigPropertyChangedCallback, NULL); + chcore::TConfig& rCfg = GetConfig(); + rCfg.ConnectToNotifier(ConfigPropertyChangedCallback, nullptr); // read the configuration try { - m_config.read(strCfgPath); + GetConfig().Read(strCfgPath); } catch(...) { } - // set working dir for the engine - icpf::config& rConfig = GetConfig(); - -// rConfig.SetBasePath(strPath); - // register all properties - RegisterProperties(&rConfig); - // ================================= Logging ======================================== // initialize the global log file if it is requested by configuration file - strLogPath = strPath + + _T("\\ch.log"); + strLogPath = strPath + _T("\\ch.log"); chcore::TLogger& rLogger = chcore::TLogger::Acquire(); try { - rLogger.init(strLogPath, (int_t)m_config.get_signed_num(PP_LOGMAXSIZE), (int_t)rConfig.get_unsigned_num(PP_LOGLEVEL), false, false); - rLogger.Enable(m_config.get_bool(PP_LOGENABLELOGGING)); + rLogger.init(strLogPath, GetPropValue(rCfg), GetPropValue(rCfg), false, false); + rLogger.Enable(GetPropValue(rCfg)); } catch(...) { @@ -269,7 +327,7 @@ // ================================= COM ======================================== LOG_INFO(_T("Initializing COM")); - HRESULT hResult = CoInitializeEx(NULL, COINIT_MULTITHREADED); + HRESULT hResult = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hResult)) { CString strMsg; @@ -286,16 +344,14 @@ ictranslate::CResourceManager& rResManager = ictranslate::CResourceManager::Acquire(); // set current language - TCHAR szPath[_MAX_PATH]; - rResManager.Init(AfxGetInstanceHandle()); rResManager.SetCallback(ResManCallback); - rConfig.get_string(PP_PLANGUAGE, szPath, _MAX_PATH); - TRACE(_T("Help path=%s\n"), szPath); - if(!rResManager.SetLanguage(ExpandPath(szPath))) + GetPropValue(rCfg, strPath); + TRACE(_T("Help path=%s\n"), strPath); + if(!rResManager.SetLanguage(m_pathProcessor.ExpandPath(strPath))) { TCHAR szData[2048]; - _sntprintf(szData, 2048, _T("Couldn't find the language file specified in configuration file:\n%s\nPlease correct this path to point the language file to use.\nProgram will now exit."), szPath); + _sntprintf(szData, 2048, _T("Couldn't find the language file specified in configuration file:\n%s\nPlease correct this path to point the language file to use.\nProgram will now exit."), (PCTSTR)strPath); LOG_ERROR(szData); AfxMessageBox(szData, MB_ICONSTOP | MB_OK); return FALSE; @@ -308,14 +364,56 @@ EnableHtmlHelp(); + // ================================= Handle early command line options ======================================== + if(m_cmdLineParser.HasCommandLineParams() && m_cmdLineParser.HasSystemStartupOption()) + { + SetPropValue(rCfg, m_cmdLineParser.IsSystemStartupEnabled()); + rCfg.Write(); + + SetAutorun(GetPropValue(rCfg)); + + return FALSE; + } + // ================================= Checking for running instances of CH ======================================== // check instance - return false if it's the second one LOG_INFO(_T("Checking for other running instances of Copy Handler")); if(!IsFirstInstance()) { - LOG_WARNING(_T("Other instance of Copy Handler is already running. Exiting.")); - MsgBox(IDS_ONECOPY_STRING); - return FALSE; + // if there is a command line specified, send it to the existing instance + if(m_cmdLineParser.HasCommandLineParams()) + { + HWND hWnd = ::FindWindow(_T("Copy Handler Wnd Class"), _T("Copy handler")); + if(hWnd == nullptr) + { + // cannot pass command line to running ch + LOG_ERROR(_T("Cannot determine running CH's window. Cannot pass command line there.")); + MsgBox(IDS_COMMAND_LINE_FAILED_STRING, MB_OK | MB_ICONERROR); + return FALSE; + } + + CString strCmdLine = ::GetCommandLine(); + + COPYDATASTRUCT cds; + cds.dwData = eCDType_CommandLineArguments; + cds.cbData = (DWORD)(strCmdLine.GetLength() + 1) * sizeof(wchar_t); + cds.lpData = (void*)(PCTSTR)strCmdLine; + + // send a message to ch + if(::SendMessage(hWnd, WM_COPYDATA, 0, reinterpret_cast(&cds)) == 0) + { + LOG_ERROR(_T("Command line was not processed properly at the running CH's instance.")); + MsgBox(IDS_COMMAND_LINE_FAILED_STRING, MB_OK | MB_ICONERROR); + } + + return FALSE; + } + else + { + LOG_WARNING(_T("Other instance of Copy Handler is already running. Exiting.")); + MsgBox(IDS_ONECOPY_STRING, MB_OK | MB_ICONWARNING); + return FALSE; + } } // ================================= Common controls ======================================== @@ -329,61 +427,35 @@ // Set this to include all the common control classes you want to use // in your application. InitCtrls.dwICC = ICC_WIN95_CLASSES; - InitCommonControlsEx(&InitCtrls); - - // ================================= Shell extension ======================================== - LOG_INFO(_T("Initializing shared memory for communication with shell extension")); - - m_hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(CSharedConfigStruct), _T("CHLMFile")); - if (m_hMapObject == NULL) - return FALSE; - - // Get a pointer to the file-mapped shared memory. - g_pscsShared=(CSharedConfigStruct*)MapViewOfFile(m_hMapObject, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); - if (g_pscsShared == NULL) - return FALSE; - - LOG_INFO(_T("Checking shell extension compatibility")); - - // calculate ch version - long lCHVersion = PRODUCT_VERSION1 << 24 | PRODUCT_VERSION2 << 16 | PRODUCT_VERSION3 << 8 | PRODUCT_VERSION4; - - // check the version of shell extension - LONG lVersion = 0; - BSTR bstrVersion = NULL; - - hResult = CoCreateInstance(CLSID_CShellExtControl, NULL, CLSCTX_ALL, IID_IShellExtControl, (void**)&m_piShellExtControl); - if(SUCCEEDED(hResult) && !m_piShellExtControl) - hResult = E_FAIL; - if(SUCCEEDED(hResult)) - hResult = m_piShellExtControl->GetVersion(&lVersion, &bstrVersion); - if(SUCCEEDED(hResult) && lVersion == lCHVersion) - hResult = m_piShellExtControl->SetFlags(eShellExt_Enabled, eShellExt_Enabled); - if(FAILED(hResult) || lCHVersion != lVersion) + if(!InitCommonControlsEx(&InitCtrls)) { - CString strMsg; - strMsg.Format(_T("Shell extension has different version (0x%lx) than Copy Handler (0x%lx). Shell extension will be disabled."), lVersion, lCHVersion); + LOG_ERROR(_T("Cannot initialize common controls.")); + MsgBox(IDS_ERROR_INITIALIZING_COMMON_CONTROLS, MB_OK | MB_ICONERROR); + return FALSE; + } - LOG_WARNING(strMsg); - MsgBox(IDS_SHELL_EXTENSION_MISMATCH_STRING); - - if(m_piShellExtControl) - m_piShellExtControl->SetFlags(0, eShellExt_Enabled); + if(!AfxInitRichEdit2()) + { + LOG_ERROR(_T("Cannot initialize rich edit control.")); + MsgBox(IDS_ERROR_INITIALIZING_RICH_EDIT_CONTROL, MB_OK | MB_ICONERROR); + return FALSE; } - if(bstrVersion) - ::SysFreeString(bstrVersion); + // ================================= Shell extension ======================================== + LOG_INFO(_T("Checking shell extension compatibility")); + InitShellExtension(); + // ================================= Initial settings ======================================== LOG_INFO(_T("Applying initial settings")); // set this process priority class - HANDLE hProcess=GetCurrentProcess(); - ::SetPriorityClass(hProcess, (DWORD)rConfig.get_signed_num(PP_PPROCESSPRIORITYCLASS)); + HANDLE hProcess = GetCurrentProcess(); + ::SetPriorityClass(hProcess, GetPropValue(rCfg)); #ifndef _DEBUG // for easier writing the program - doesn't collide with std CH // set "run with system" registry settings - SetAutorun(rConfig.get_bool(PP_PRELOADAFTERRESTART)); + SetAutorun(GetPropValue(rCfg)); #endif // ================================= Main window ======================================== @@ -399,70 +471,223 @@ LOG_INFO(_T("Copy Handler initialized successfully")); return TRUE; +#endif } -bool CCopyHandlerApp::IsShellExtEnabled() const +bool CCopyHandlerApp::ParseCommandLine() { - if(m_piShellExtControl) + CString strError; + try { - LONG lFlags = 0; - HRESULT hResult = m_piShellExtControl->GetFlags(&lFlags); - if(SUCCEEDED(hResult) && (lFlags & eShellExt_Enabled)) - return true; + m_cmdLineParser.ParseCommandLine(::GetCommandLine()); } - return false; + catch (const std::exception& e) + { + strError = e.what(); + } + + if (!strError.IsEmpty()) + { + CString strFmt; + strFmt.Format(_T("Error processing command line options. Reason: %s"), (PCTSTR) strError); + AfxMessageBox(strFmt, MB_OK | MB_ICONERROR); + + return false; + } + + return true; } -void CCopyHandlerApp::OnConfigNotify(uint_t uiPropID) +void CCopyHandlerApp::InitShellExtension() { - // is this language - switch(uiPropID) + // validate ch version against extension version + CString strExtensionStringVersion; + long lExtensionVersion = 0; + INT_PTR iDlgResult = IDNO; + + chcore::TConfig& rConfig = GetConfig(); + + int iDoNotShowAgain_Unregistered = GetPropValue(rConfig); + int iDoNotShowAgain_VersionMismatch = GetPropValue(rConfig); + bool bDontShow = false; + + // first try to just enable the extension (assume that it has already been registered) + HRESULT hResult = m_tShellExtClient.EnableExtensionIfCompatible(PRODUCT_VERSION1 << 24 | PRODUCT_VERSION2 << 16 | PRODUCT_VERSION3 << 8 | PRODUCT_VERSION4, lExtensionVersion, strExtensionStringVersion); + if(FAILED(hResult)) { - case PP_PLANGUAGE: + CString strMsg; + strMsg.Format(_T("Shell extension is not registered.")); + LOG_WARNING(strMsg); + + switch(iDoNotShowAgain_Unregistered) { - // update language in resource manager - TCHAR szPath[_MAX_PATH]; - GetConfig().get_string(PP_PLANGUAGE, szPath, _MAX_PATH); - GetResManager().SetLanguage(ExpandPath(szPath)); + case eDNS_HideAndRegister: + iDlgResult = IDYES; break; - } - case PP_LOGENABLELOGGING: - { - chcore::TLogger& rLogger = chcore::TLogger::Acquire(); - rLogger.Enable(GetConfig().get_bool(PP_LOGENABLELOGGING)); + case eDNS_HideAndDontRegister: + iDlgResult = IDNO; break; - } - case PP_LOGLEVEL: - { - chcore::TLogger& rLogger = chcore::TLogger::Acquire(); - rLogger.set_log_level((int_t)GetConfig().get_unsigned_num(PP_LOGLEVEL)); - break; + case eDNS_AlwaysShow: + default: + { + iDlgResult = TMsgBox::MsgBox(IDS_SHELL_EXTENSION_UNREGISTERED_STRING, TMsgBox::eYesNo, TMsgBox::eIcon_Warning, IDS_DO_NOT_SHOW_AGAIN_STRING, &bDontShow); + if(bDontShow) + SetPropValue(rConfig, (iDlgResult == IDYES) ? eDNS_HideAndRegister : eDNS_HideAndDontRegister); + } } - case PP_LOGMAXSIZE: + } + else if(hResult == S_FALSE) + { + CString strMsg; + strMsg.Format(_T("Shell extension has different version (0x%lx) than Copy Handler (0x%lx)."), (unsigned long)lExtensionVersion, (unsigned long)(PRODUCT_VERSION1 << 24 | PRODUCT_VERSION2 << 16 | PRODUCT_VERSION3 << 8 | PRODUCT_VERSION4)); + LOG_WARNING(strMsg); + + switch(iDoNotShowAgain_VersionMismatch) { - chcore::TLogger& rLogger = chcore::TLogger::Acquire(); + case eDNS_HideAndRegister: + iDlgResult = IDYES; + break; - rLogger.set_max_size((int_t)GetConfig().get_signed_num(PP_LOGMAXSIZE)); + case eDNS_HideAndDontRegister: + iDlgResult = IDNO; break; + + case eDNS_AlwaysShow: + default: + { + iDlgResult = TMsgBox::MsgBox(IDS_SHELL_EXTENSION_MISMATCH_STRING, TMsgBox::eYesNo, TMsgBox::eIcon_Warning, IDS_DO_NOT_SHOW_AGAIN_STRING, &bDontShow); + if(bDontShow) + SetPropValue(rConfig, (iDlgResult == IDYES) ? eDNS_HideAndRegister : eDNS_HideAndDontRegister); + } } } + + if(bDontShow) + rConfig.Write(); + + // we didn't succeed, but want to fix this + if(iDlgResult == IDYES) + { + // try to register the extension + RegisterShellExtension(); + } } +void CCopyHandlerApp::RegisterShellExtension() +{ + CString strPath = CString(m_pathProcessor.GetProgramPath()) + _T("\\"); + +#ifdef _WIN64 + strPath += _T("chext64.dll"); +#else + strPath += _T("chext.dll"); +#endif + + long lExtensionVersion = 0; + CString strExtensionVersion; + + HRESULT hResult = m_tShellExtClient.RegisterShellExtDll(strPath, PRODUCT_VERSION1 << 24 | PRODUCT_VERSION2 << 16 | PRODUCT_VERSION3 << 8 | PRODUCT_VERSION4, + lExtensionVersion, strExtensionVersion); + if(FAILED(hResult)) + { + // normal failure + chcore::TString strError = chcore::TWin32ErrorFormatter::FormatWin32ErrorCode(hResult, true); + + ictranslate::CFormat fmt(GetResManager().LoadString(IDS_REGISTERERR_STRING)); + fmt.SetParam(_T("%errno"), (unsigned long)hResult); + fmt.SetParam(_T("%errdesc"), strError.c_str()); + AfxMessageBox(fmt, MB_ICONERROR | MB_OK); + } + else if(hResult == S_FALSE) + { + // registered ok, but incompatible versions - probably restart required + CString strMsg; + strMsg.Format(_T("Registration succeeded, but still the shell extension has different version (0x%lx) than Copy Handler (0x%lx)."), (unsigned long)lExtensionVersion, (unsigned long)(PRODUCT_VERSION1 << 24 | PRODUCT_VERSION2 << 16 | PRODUCT_VERSION3 << 8 | PRODUCT_VERSION4)); + LOG_WARNING(strMsg); + + MsgBox(IDS_SHELL_EXTENSION_REGISTERED_MISMATCH_STRING, MB_ICONWARNING | MB_OK); + } + else if(hResult == S_OK) + MsgBox(IDS_REGISTEROK_STRING, MB_ICONINFORMATION | MB_OK); +} + +void CCopyHandlerApp::UnregisterShellExtension() +{ + CString strPath = CString(m_pathProcessor.GetProgramPath()) + _T("\\"); + +#ifdef _WIN64 + strPath += _T("chext64.dll"); +#else + strPath += _T("chext.dll"); +#endif + + HRESULT hResult = m_tShellExtClient.UnRegisterShellExtDll(strPath); + if(hResult == TYPE_E_REGISTRYACCESS) + { + MsgBox(IDS_CHEXT_ALREADY_UNREGISTERED, MB_ICONINFORMATION | MB_OK); + } + else if(FAILED(hResult)) + { + chcore::TString strError = chcore::TWin32ErrorFormatter::FormatWin32ErrorCode(hResult, true); + + ictranslate::CFormat fmt(GetResManager().LoadString(IDS_UNREGISTERERR_STRING)); + fmt.SetParam(_T("%errno"), (unsigned long)hResult); + fmt.SetParam(_T("%errdesc"), strError.c_str()); + + AfxMessageBox(fmt, MB_ICONERROR | MB_OK); + } + else if(hResult == S_OK) + MsgBox(IDS_UNREGISTEROK_STRING, MB_ICONINFORMATION | MB_OK); +} + +void CCopyHandlerApp::OnConfigNotify(const chcore::TStringSet& setPropNames) +{ + // is this language + if(setPropNames.HasValue(PropData::GetPropertyName())) + { + // update language in resource manager + CString strPath; + GetPropValue(GetConfig(), strPath); + GetResManager().SetLanguage(m_pathProcessor.ExpandPath(strPath)); + } + + if(setPropNames.HasValue(PropData::GetPropertyName())) + { + chcore::TLogger& rLogger = chcore::TLogger::Acquire(); + + rLogger.Enable(GetPropValue(GetConfig())); + } + + if(setPropNames.HasValue(PropData::GetPropertyName())) + { + chcore::TLogger& rLogger = chcore::TLogger::Acquire(); + + rLogger.set_log_level(GetPropValue(GetConfig())); + } + + if(setPropNames.HasValue(PropData::GetPropertyName())) + { + chcore::TLogger& rLogger = chcore::TLogger::Acquire(); + + rLogger.set_max_size(GetPropValue(GetConfig())); + } +} + void CCopyHandlerApp::OnResManNotify(UINT uiType) { if (uiType == RMNT_LANGCHANGE) { // language has been changed - close the current help file if (UpdateHelpPaths()) - HtmlHelp(NULL, HH_CLOSE_ALL); + HtmlHelp(0, HH_CLOSE_ALL); } } HWND CCopyHandlerApp::HHelp(HWND hwndCaller, LPCTSTR pszFile, UINT uCommand, DWORD_PTR dwData) { - PCTSTR pszPath=NULL; + PCTSTR pszPath=nullptr; WIN32_FIND_DATA wfd; HANDLE handle=::FindFirstFile(m_pszHelpFilePath, &wfd); if (handle != INVALID_HANDLE_VALUE) @@ -471,15 +696,14 @@ ::FindClose(handle); } - if (pszPath == NULL) - return NULL; + if (pszPath == nullptr) + return nullptr; - if (pszFile != NULL) + if (pszFile != nullptr) { - TCHAR szAdd[2*_MAX_PATH]; - _tcscpy(szAdd, pszPath); - _tcscat(szAdd, pszFile); - return ::HtmlHelp(hwndCaller, szAdd, uCommand, dwData); + CString strAdd = pszPath; + strAdd += pszFile; + return ::HtmlHelp(hwndCaller, strAdd, uCommand, dwData); } else return ::HtmlHelp(hwndCaller, pszPath, uCommand, dwData); @@ -492,11 +716,11 @@ case HH_DISPLAY_TOPIC: case HH_HELP_CONTEXT: { - HHelp(GetDesktopWindow(), NULL, nCmd, dwData); + HHelp(GetDesktopWindow(), nullptr, nCmd, dwData); break; } case HH_CLOSE_ALL: - ::HtmlHelp(NULL, NULL, HH_CLOSE_ALL, NULL); + ::HtmlHelp(nullptr, nullptr, HH_CLOSE_ALL, 0); break; case HH_DISPLAY_TEXT_POPUP: { @@ -507,9 +731,9 @@ HH_POPUP hhp; hhp.cbStruct=sizeof(HH_POPUP); - hhp.hinst=NULL; + hhp.hinst=nullptr; hhp.idString=(pHelp->dwContextId & 0xffff); - hhp.pszText=NULL; + hhp.pszText=nullptr; hhp.pt=pHelp->MousePos; hhp.pt.y+=::GetSystemMetrics(SM_CYCURSOR)/2; hhp.clrForeground=(COLORREF)-1; @@ -521,8 +745,8 @@ hhp.pszFont=_T("Tahoma, 8, , "); TCHAR szPath[_MAX_PATH]; - _sntprintf(szPath, _MAX_PATH, _T("::/%lu.txt"), (pHelp->dwContextId >> 16) & 0x7fff); - HHelp(GetDesktopWindow(), szPath, HH_DISPLAY_TEXT_POPUP, (DWORD)&hhp); + _sntprintf(szPath, _MAX_PATH, _T("::/%lu.txt"), (DWORD)((pHelp->dwContextId >> 16) & 0x7fff)); + HHelp(GetDesktopWindow(), szPath, HH_DISPLAY_TEXT_POPUP, (DWORD_PTR)&hhp); break; } @@ -532,12 +756,9 @@ int CCopyHandlerApp::ExitInstance() { LOG_INFO(_T("Pre-exit step - releasing shell extension")); - if(m_piShellExtControl) - { - m_piShellExtControl->Release(); - m_piShellExtControl = NULL; - } + m_tShellExtClient.Close(); + LOG_INFO(_T("Pre-exit step - uninitializing COM")); CoUninitialize();