Index: src/ch/ch.cpp =================================================================== diff -u -rb165add706c4fab9d783f0564b1dd398492da491 -r58de8d7360813537b384eff808c031f9e63db4de --- src/ch/ch.cpp (.../ch.cpp) (revision b165add706c4fab9d783f0564b1dd398492da491) +++ src/ch/ch.cpp (.../ch.cpp) (revision 58de8d7360813537b384eff808c031f9e63db4de) @@ -31,19 +31,13 @@ #include "CrashDlg.h" #include "../common/version.h" #include "TCommandLineParser.h" -#include "../libchcore/TStringSet.h" -#include "../libchcore/TSimpleTimer.h" -#include "../libchcore/SerializerTrace.h" -#include "../libchcore/TSQLiteTaskSchema.h" -#include "../libchcore/TSQLiteSerializer.h" -#include "../libchcore/ISerializerContainer.h" -#include "../libchcore/ISerializerRowData.h" -#include "../libchcore/TFileInfo.h" +#include "../libstring/TStringSet.h" #include "TMsgBox.h" -#include "../libchcore/TWin32ErrorFormatter.h" #include "resource.h" #include "../liblogger/TLogger.h" #include "../liblogger/TAsyncMultiLogger.h" +#include "TWindowMessageFilterHelper.h" +#include "../libchengine/TConfigSerializers.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -75,7 +69,7 @@ 0xac6e, 0x1e4c, 0x5667, 0x1942, 0x0a47, 0x1f80, 0x4191, 0x4f8d }; int iOffCount=12; -unsigned char off[]={ 2, 6, 3, 4, 8, 0, 1, 3, 2, 4, 1, 6 }; +unsigned char _off[]={ 2, 6, 3, 4, 8, 0, 1, 3, 2, 4, 1, 6 }; unsigned short _hash[]={ 0x3fad, 0x34cd, 0x7fff, 0x65ff, 0x4512, 0x0112, 0xabac, 0x1abc, 0x54ab, 0x1212, 0x0981, 0x0100 }; ///////////////////////////////////////////////////////////////////////////// @@ -92,16 +86,20 @@ theApp.OnResManNotify(uiMsg); } -void ConfigPropertyChangedCallback(const chcore::TStringSet& setPropNames, void* /*pParam*/) +void ConfigPropertyChangedCallback(const string::TStringSet& setPropNames, void* /*pParam*/) { theApp.OnConfigNotify(setPropNames); } CCopyHandlerApp::CCopyHandlerApp() : - m_pMainWindow(nullptr), m_spAppLoggerConfig(std::make_shared()), - m_spEngineLoggerConfig(std::make_shared()) + m_spEngineLoggerConfig(std::make_shared()), + m_pMainWindow(nullptr) { +#ifdef _DEBUG + AfxEnableMemoryLeakDump(FALSE); +#endif + // this is the one-instance application InitProtection(); } @@ -126,13 +124,13 @@ return ictranslate::CResourceManager::Acquire(); } -chcore::TConfig& CCopyHandlerApp::GetConfig() +chengine::TConfig& CCopyHandlerApp::GetConfig() { - static chcore::TConfig tCfg; + static chengine::TConfig tCfg; return tCfg; } -int MsgBox(UINT uiID, UINT nType, UINT nIDHelp) +int CCopyHandlerApp::MsgBox(UINT uiID, UINT nType, UINT nIDHelp) { return AfxMessageBox(GetResManager().LoadString(uiID), nType, nIDHelp); } @@ -212,66 +210,6 @@ 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); @@ -296,7 +234,7 @@ strCfgPath = strPath + _T("\\ch.xml"); // initialize configuration file - chcore::TConfig& rCfg = GetConfig(); + chengine::TConfig& rCfg = GetConfig(); rCfg.ConnectToNotifier(ConfigPropertyChangedCallback, nullptr); // read the configuration @@ -316,33 +254,50 @@ m_spEngineLoggerConfig->SetLogLevel(L"default", (logger::ESeverityLevel)GetPropValue(rCfg)); m_spEngineLoggerConfig->SetLogLevel(L"Filesystem", (logger::ESeverityLevel)GetPropValue(rCfg)); m_spEngineLoggerConfig->SetLogLevel(L"Filesystem-File", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"DataBuffer", (logger::ESeverityLevel)GetPropValue(rCfg)); m_spEngineLoggerConfig->SetLogLevel(L"Task", (logger::ESeverityLevel)GetPropValue(rCfg)); m_spEngineLoggerConfig->SetLogLevel(L"ST-FastMove", (logger::ESeverityLevel)GetPropValue(rCfg)); m_spEngineLoggerConfig->SetLogLevel(L"ST-CopyMove", (logger::ESeverityLevel)GetPropValue(rCfg)); m_spEngineLoggerConfig->SetLogLevel(L"ST-Delete", (logger::ESeverityLevel)GetPropValue(rCfg)); m_spEngineLoggerConfig->SetLogLevel(L"ST-ScanDirs", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"Serializer", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"Serializer-RowReader", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"Serializer-RowData", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"Serializer-Container", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"TaskManager", (logger::ESeverityLevel)GetPropValue(rCfg)); + // also update CCopyHandlerApp::OnConfigNotify() with new channels // initialize the global log file if it is requested by configuration file CString strLogPath = strPath + _T("\\ch.log"); m_spLog = logger::MakeLogger(logger::TAsyncMultiLogger::GetInstance()->CreateLoggerData(strLogPath, m_spAppLoggerConfig), L"App"); LOG_INFO(m_spLog) << _T("============================ Initializing Copy Handler ============================"); - LOG_INFO(m_spLog) << _T(""); // ================================= COM ======================================== LOG_INFO(m_spLog) << _T("Initializing COM"); HRESULT hResult = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hResult)) { - CString strMsg; - strMsg.Format(_T("Cannot initialize COM, the application will now exit (result = 0x%lx)"), hResult); + // NOTE: with CH code (including external libraries directly referenced by it) the RPC_E_CHANGED_MODE error code + // should not occur. One of the users reported such problem - it is unclear whether there is something being injected + // into CH process or there is some other problem. It seems that RPC_E_CHANGED_MODE error is not a blocker to CH use, + // so we're allowing the initialization to continue. + if(hResult != RPC_E_CHANGED_MODE) + { + CString strMsg; + strMsg.Format(_T("Cannot initialize COM, the application will now exit (result = 0x%lx)"), hResult); - LOG_ERROR(m_spLog) << strMsg; - AfxMessageBox(strMsg, MB_ICONERROR | MB_OK); - return FALSE; + LOG_ERROR(m_spLog) << strMsg; + AfxMessageBox(strMsg, MB_ICONERROR | MB_OK); + return FALSE; + } + + LOG_WARNING(m_spLog) << L"COM already initialized (CoInitializeEx returned RPC_E_CHANGED_MODE)"; } + else + m_bComInitialized = true; // ================================= Resource manager ======================================== LOG_INFO(m_spLog) << _T("Initializing resource manager..."); @@ -353,7 +308,7 @@ rResManager.Init(AfxGetInstanceHandle()); rResManager.SetCallback(ResManCallback); GetPropValue(rCfg, strPath); - TRACE(_T("Help path=%s\n"), strPath); + TRACE(_T("Help path=%s\n"), (PCTSTR)strPath); if(!rResManager.SetLanguage(m_pathProcessor.ExpandPath(strPath))) { TCHAR szData[2048]; @@ -370,17 +325,6 @@ 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(m_spLog) << _T("Checking for other running instances of Copy Handler"); @@ -414,12 +358,10 @@ return FALSE; } - else - { - LOG_WARNING(m_spLog) << _T("Other instance of Copy Handler is already running. Exiting."); - MsgBox(IDS_ONECOPY_STRING, MB_OK | MB_ICONWARNING); - return FALSE; - } + + LOG_WARNING(m_spLog) << _T("Other instance of Copy Handler is already running. Exiting."); + MsgBox(IDS_ONECOPY_STRING, MB_OK | MB_ICONWARNING); + return FALSE; } // ================================= Common controls ======================================== @@ -464,6 +406,23 @@ SetAutorun(GetPropValue(rCfg)); #endif + // ================================= Shell extension config ============================= + LOG_INFO(m_spLog) << _T("Initializing shell extension configuration"); + try + { + m_shellExtConfig = std::make_unique(m_spLog->GetLogFileData()); + m_shellExtConfig->PrepareConfig(); + } + catch(const std::exception& e) + { + LOG_ERROR(m_spLog) << L"Failed to initialize shell extension configuration. Shell extension will be inactive. Error: " << e.what(); + } + + // ================================= User Interface Privilege Isolation ================= + LOG_INFO(m_spLog) << _T("Enabling communication between non-admin explorer and admin Copy Handler"); + if(!TWindowMessageHelper::AllowToReceiveCopyDataMessages()) + LOG_WARNING(m_spLog) << _T("Failed to enable communication between non-admin explorer and admin Copy Handler"); + // ================================= Main window ======================================== LOG_INFO(m_spLog) << _T("Creating main application window"); // create main window @@ -477,7 +436,6 @@ LOG_INFO(m_spLog) << _T("Copy Handler initialized successfully"); return TRUE; -#endif } bool CCopyHandlerApp::ParseCommandLine() @@ -506,7 +464,7 @@ void CCopyHandlerApp::InitLoggers() { - chcore::TConfig& rConfig = GetConfig(); + chengine::TConfig& rConfig = GetConfig(); logger::TAsyncMultiLogger::GetInstance()->SetMaxLogSize(GetPropValue(rConfig)); logger::TAsyncMultiLogger::GetInstance()->SetMaxRotatedCount(GetPropValue(rConfig)); @@ -519,7 +477,7 @@ long lExtensionVersion = 0; INT_PTR iDlgResult = IDNO; - chcore::TConfig& rConfig = GetConfig(); + chengine::TConfig& rConfig = GetConfig(); int iDoNotShowAgain_Unregistered = GetPropValue(rConfig); int iDoNotShowAgain_VersionMismatch = GetPropValue(rConfig); @@ -599,76 +557,73 @@ return m_spEngineLoggerConfig; } -void CCopyHandlerApp::RegisterShellExtension() +TShellExtensionConfigPtr CCopyHandlerApp::GetShellExtensionConfig() const { - CString strPath = CString(m_pathProcessor.GetProgramPath()) + _T("\\"); + return m_shellExtConfig; +} -#ifdef _WIN64 - strPath += _T("chext64.dll"); -#else - strPath += _T("chext.dll"); -#endif - +void CCopyHandlerApp::RegisterShellExtension() +{ long lExtensionVersion = 0; CString strExtensionVersion; - HRESULT hResult = m_tShellExtClient.RegisterShellExtDll(strPath, PRODUCT_VERSION1 << 24 | PRODUCT_VERSION2 << 16 | PRODUCT_VERSION3 << 8 | PRODUCT_VERSION4, + ERegistrationResult eResult = m_tShellExtClient.RegisterShellExtDll(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) + switch(eResult) { - // 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(m_spLog) << strMsg; + case eFailure: + MsgBox(IDS_REGISTERERR_STRING, MB_ICONERROR | MB_OK); + break; - MsgBox(IDS_SHELL_EXTENSION_REGISTERED_MISMATCH_STRING, MB_ICONWARNING | MB_OK); - } - else if(hResult == S_OK) + case eSuccessNative: + MsgBox(IDS_REGISTERED_ONLYNATIVE, MB_ICONWARNING | MB_OK); + break; + + case eSuccess32Bit: + MsgBox(IDS_REGISTERED_ONLY32BIT, MB_ICONWARNING | MB_OK); + break; + + case eSuccessNeedRestart: + { + // 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(m_spLog) << strMsg; + + MsgBox(IDS_SHELL_EXTENSION_REGISTERED_MISMATCH_STRING, MB_ICONWARNING | MB_OK); + break; + } + + case eSuccess: MsgBox(IDS_REGISTEROK_STRING, MB_ICONINFORMATION | MB_OK); + break; + } } 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) + ERegistrationResult eResult = m_tShellExtClient.UnRegisterShellExtDll(); + switch(eResult) { - MsgBox(IDS_CHEXT_ALREADY_UNREGISTERED, MB_ICONINFORMATION | MB_OK); - } - else if(FAILED(hResult)) - { - chcore::TString strError = chcore::TWin32ErrorFormatter::FormatWin32ErrorCode(hResult, true); + case eSuccess: + case eSuccessNative: + case eSuccess32Bit: + MsgBox(IDS_UNREGISTEROK_STRING, MB_ICONINFORMATION | MB_OK); + break; - 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); + case eFailure: + MsgBox(IDS_UNREGISTERERR_STRING, MB_ICONERROR | MB_OK); + break; + case eSuccessNeedRestart: + default: + break; } - else if(hResult == S_OK) - MsgBox(IDS_UNREGISTEROK_STRING, MB_ICONINFORMATION | MB_OK); } -void CCopyHandlerApp::OnConfigNotify(const chcore::TStringSet& setPropNames) +void CCopyHandlerApp::OnConfigNotify(const string::TStringSet& setPropNames) { - chcore::TConfig& rCfg = GetConfig(); + chengine::TConfig& rCfg = GetConfig(); // is this language if(setPropNames.HasValue(PropData::GetPropertyName())) @@ -688,11 +643,16 @@ m_spLog->GetLogFileData()->GetMultiLoggerConfig()->SetLogLevel(L"default", (logger::ESeverityLevel)GetPropValue(rCfg)); if(setPropNames.HasValue(PropData::GetPropertyName())) + { m_spEngineLoggerConfig->SetLogLevel(L"default", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"TaskManager", (logger::ESeverityLevel)GetPropValue(rCfg)); + } if(setPropNames.HasValue(PropData::GetPropertyName())) + { m_spEngineLoggerConfig->SetLogLevel(L"Filesystem", (logger::ESeverityLevel)GetPropValue(rCfg)); - if(setPropNames.HasValue(PropData::GetPropertyName())) m_spEngineLoggerConfig->SetLogLevel(L"Filesystem-File", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"DataBuffer", (logger::ESeverityLevel)GetPropValue(rCfg)); + } if(setPropNames.HasValue(PropData::GetPropertyName())) m_spEngineLoggerConfig->SetLogLevel(L"Task", (logger::ESeverityLevel)GetPropValue(rCfg)); if(setPropNames.HasValue(PropData::GetPropertyName())) @@ -703,6 +663,14 @@ m_spEngineLoggerConfig->SetLogLevel(L"ST-Delete", (logger::ESeverityLevel)GetPropValue(rCfg)); if(setPropNames.HasValue(PropData::GetPropertyName())) m_spEngineLoggerConfig->SetLogLevel(L"ST-ScanDirs", (logger::ESeverityLevel)GetPropValue(rCfg)); + + if(setPropNames.HasValue(PropData::GetPropertyName())) + { + m_spEngineLoggerConfig->SetLogLevel(L"Serializer", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"Serializer-RowReader", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"Serializer-RowData", (logger::ESeverityLevel)GetPropValue(rCfg)); + m_spEngineLoggerConfig->SetLogLevel(L"Serializer-Container", (logger::ESeverityLevel)GetPropValue(rCfg)); + } } void CCopyHandlerApp::OnResManNotify(UINT uiType) @@ -735,8 +703,8 @@ strAdd += pszFile; return ::HtmlHelp(hwndCaller, strAdd, uCommand, dwData); } - else - return ::HtmlHelp(hwndCaller, pszPath, uCommand, dwData); + + return ::HtmlHelp(hwndCaller, pszPath, uCommand, dwData); } void CCopyHandlerApp::HtmlHelp(DWORD_PTR dwData, UINT nCmd) @@ -789,8 +757,13 @@ m_tShellExtClient.Close(); - LOG_INFO(m_spLog) << _T("Pre-exit step - uninitializing COM"); - CoUninitialize(); + if(m_bComInitialized) + { + LOG_INFO(m_spLog) << _T("Pre-exit step - uninitializing COM"); + CoUninitialize(); + } + else + LOG_WARNING(m_spLog) << _T("COM was not initialized by CH. Leaving uninit to original caller."); LOG_INFO(m_spLog) << _T("============================ Leaving Copy Handler ============================");