Index: src/ch/TShellExtensionClient.cpp =================================================================== diff -u -N -rb2102d724fda96a2533b866dbf1efca9f499713b -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/ch/TShellExtensionClient.cpp (.../TShellExtensionClient.cpp) (revision b2102d724fda96a2533b866dbf1efca9f499713b) +++ src/ch/TShellExtensionClient.cpp (.../TShellExtensionClient.cpp) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -19,6 +19,7 @@ #include "stdafx.h" #include "TShellExtensionClient.h" #include "objbase.h" +#include "../chext/Logger.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -59,145 +60,199 @@ } } -HRESULT TShellExtensionClient::RegisterShellExtDll(const CString& strPath, long lClientVersion, long& rlExtensionVersion, CString& rstrExtensionStringVersion) +bool TShellExtensionClient::DetectRegExe() { - if(strPath.IsEmpty()) - return E_INVALIDARG; + const DWORD dwSize = 32768; + wchar_t szData[dwSize]; + DWORD dwResult = ::GetModuleFileName(nullptr, szData, dwSize); + if (dwResult == 0) + return false; + szData[dwResult] = L'\0'; - HRESULT hResult = S_OK; + std::wstring wstrDir = szData; - if(SUCCEEDED(hResult)) - hResult = InitializeCOM(); + size_t stPos = wstrDir.find_last_of(L'\\'); + if (stPos != std::wstring::npos) + wstrDir.erase(wstrDir.begin() + stPos + 1, wstrDir.end()); - // get rid of the interface, so we can at least try to re-register - if(SUCCEEDED(hResult)) - FreeControlInterface(); +#ifdef _WIN64 + wstrDir += _T("regchext64.exe"); +#else + wstrDir += _T("regchext.exe"); +#endif - // first try - load dll and register it manually. - // if failed - try by loading extension manually (would fail on vista when running as user) - if(SUCCEEDED(hResult)) + m_strRegExe = wstrDir; + + return true; +} + +logger::TLoggerPtr& TShellExtensionClient::GetLogger() +{ + if(!m_spLog) + m_spLog = logger::MakeLogger(GetLogFileData(), L"ShellExtClient"); + + return m_spLog; +} + +ERegistrationResult TShellExtensionClient::RegisterShellExtDll(long lClientVersion, long& rlExtensionVersion, CString& rstrExtensionStringVersion) +{ + LOG_INFO(GetLogger()) << L"Registering shell extension"; + + HRESULT hResult = InitializeCOM(); + if(FAILED(hResult)) { - HRESULT (STDAPICALLTYPE *pfn)(void) = nullptr; - HINSTANCE hMod = LoadLibrary(strPath); // load the dll - if(hMod == nullptr) - hResult = HRESULT_FROM_WIN32(GetLastError()); - if(SUCCEEDED(hResult) && !hMod) - hResult = E_FAIL; - if(SUCCEEDED(hResult)) - { - (FARPROC&)pfn = GetProcAddress(hMod, "DllRegisterServer"); - if(pfn == nullptr) - hResult = E_FAIL; - if(SUCCEEDED(hResult)) - hResult = (*pfn)(); + LOG_ERROR(GetLogger()) << L"Failed to initialize COM. Error: " << hResult; + return eFailure; + } - FreeLibrary(hMod); - } + // get rid of the interface, so we can at least try to re-register + LOG_DEBUG(GetLogger()) << L"Freeing control interface"; + FreeControlInterface(); + + LOG_DEBUG(GetLogger()) << L"Detecting regchext binary"; + if(!DetectRegExe()) + { + LOG_ERROR(GetLogger()) << L"Failed to detect regchext binary"; + return eFailure; } + LOG_DEBUG(GetLogger()) << L"Executing regchext binary"; // if previous operation failed (ie. vista system) - try running regsvr32 with elevated privileges - if(SCODE_CODE(hResult) == ERROR_ACCESS_DENIED) + // try with regsvr32 + SHELLEXECUTEINFO sei; + memset(&sei, 0, sizeof(sei)); + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS; + sei.lpVerb = _T("runas"); + sei.lpFile = m_strRegExe.c_str(); + sei.lpParameters = _T(""); + sei.nShow = SW_SHOW; + + if(!ShellExecuteEx(&sei)) { - // try with regsvr32 - SHELLEXECUTEINFO sei; - memset(&sei, 0, sizeof(sei)); - sei.cbSize = sizeof(sei); - sei.fMask = SEE_MASK_UNICODE; - sei.lpVerb = _T("runas"); - sei.lpFile = _T("regsvr32.exe"); - CString strParams = CString(_T("/s \"")) + strPath + CString(_T("\"")); - sei.lpParameters = strParams; - sei.nShow = SW_SHOW; + DWORD dwLastError = GetLastError(); + LOG_ERROR(GetLogger()) << L"Failed to execute regchext binary. Error: " << dwLastError; + return eFailure; + } - if(!ShellExecuteEx(&sei)) - hResult = E_FAIL; - else - hResult = S_OK; + LOG_DEBUG(GetLogger()) << L"Waiting for registration process to finish"; + if(SUCCEEDED(hResult) && WaitForSingleObject(sei.hProcess, 10000) != WAIT_OBJECT_0) + { + DWORD dwLastError = GetLastError(); + LOG_ERROR(GetLogger()) << L"Waiting failed. Last error: " << dwLastError; + CloseHandle(sei.hProcess); + + return eFailure; } - if(SUCCEEDED(hResult)) + DWORD dwExitCode = 0; + if (!GetExitCodeProcess(sei.hProcess, &dwExitCode)) { - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + DWORD dwLastError = GetLastError(); + LOG_ERROR(GetLogger()) << L"Failed to retrieve process exit code. Last error: " << dwLastError; + CloseHandle(sei.hProcess); + return eFailure; + } + CloseHandle(sei.hProcess); + + LOG_INFO(GetLogger()) << L"Registration result: " << dwExitCode; + + ERegistrationResult eResult = (ERegistrationResult)dwExitCode; + + if(eResult == eSuccess || eResult == eSuccessNative) + { // NOTE: we are re-trying to enable the shell extension through our notification interface // in case of class-not-registered error because (it seems) system needs some time to process // DLL's self registration and usually the first call fails. int iTries = 3; do { + LOG_DEBUG(GetLogger()) << L"Trying to enable native shell extension";; hResult = EnableExtensionIfCompatible(lClientVersion, rlExtensionVersion, rstrExtensionStringVersion); if(hResult == REGDB_E_CLASSNOTREG) { - ATLTRACE(_T("Class CLSID_CShellExtControl still not registered...\r\n")); + LOG_ERROR(GetLogger()) << L"Class CLSID_CShellExtControl still not registered"; Sleep(500); } } while(--iTries && hResult == REGDB_E_CLASSNOTREG); + + if(FAILED(hResult)) + { + LOG_INFO(GetLogger()) << L"Shell Extension requires system restart";; + eResult = eSuccessNeedRestart; + } } - return hResult; + return eResult; } -HRESULT TShellExtensionClient::UnRegisterShellExtDll(const CString& strPath) +ERegistrationResult TShellExtensionClient::UnRegisterShellExtDll() { - if(strPath.IsEmpty()) - return E_INVALIDARG; + LOG_INFO(GetLogger()) << L"Unregistering shell extension"; - HRESULT hResult = S_OK; + HRESULT hResult = InitializeCOM(); + if(FAILED(hResult)) + { + LOG_ERROR(GetLogger()) << L"Failed to initialize COM. Error: " << hResult; + return eFailure; + } - if(SUCCEEDED(hResult)) - hResult = InitializeCOM(); + // get rid of the interface, so we can at least try to re-register + LOG_DEBUG(GetLogger()) << L"Freeing control interface"; + FreeControlInterface(); - // get rid of the interface if unregistering - if(SUCCEEDED(hResult)) - FreeControlInterface(); + LOG_DEBUG(GetLogger()) << L"Detecting regchext binary"; + if(!DetectRegExe()) + { + LOG_ERROR(GetLogger()) << L"Failed to detect regchext binary"; + return eFailure; + } - // first try - load dll and register it manually. - // if failed - try by loading extension manually (would fail on vista when running as user) - if(SUCCEEDED(hResult)) + LOG_DEBUG(GetLogger()) << L"Executing regchext binary"; + // if previous operation failed (ie. vista system) - try running regsvr32 with elevated privileges + // try with regsvr32 + SHELLEXECUTEINFO sei; + memset(&sei, 0, sizeof(sei)); + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS; + sei.lpVerb = _T("runas"); + sei.lpFile = m_strRegExe.c_str(); + sei.lpParameters = _T("/u"); + sei.nShow = SW_SHOW; + + if(!ShellExecuteEx(&sei)) { - HRESULT (STDAPICALLTYPE *pfn)(void) = nullptr; - HINSTANCE hMod = LoadLibrary(strPath); // load the dll - if(hMod == nullptr) - hResult = HRESULT_FROM_WIN32(GetLastError()); - if(SUCCEEDED(hResult) && !hMod) - hResult = E_FAIL; - if(SUCCEEDED(hResult)) - { - (FARPROC&)pfn = GetProcAddress(hMod, "DllUnregisterServer"); - if(pfn == nullptr) - hResult = E_FAIL; - if(SUCCEEDED(hResult)) - hResult = (*pfn)(); + DWORD dwLastError = GetLastError(); + LOG_ERROR(GetLogger()) << L"Failed to execute regchext binary. Error: " << dwLastError; + return eFailure; + } - FreeLibrary(hMod); - } + LOG_DEBUG(GetLogger()) << L"Waiting for deregistration process to finish"; + if(SUCCEEDED(hResult) && WaitForSingleObject(sei.hProcess, 10000) != WAIT_OBJECT_0) + { + DWORD dwLastError = GetLastError(); + LOG_ERROR(GetLogger()) << L"Waiting failed. Last error: " << dwLastError; + CloseHandle(sei.hProcess); + + return eFailure; } - // if previous operation failed (ie. vista system) - try running regsvr32 with elevated privileges - if(SCODE_CODE(hResult) == ERROR_ACCESS_DENIED) + DWORD dwExitCode = 0; + if(!GetExitCodeProcess(sei.hProcess, &dwExitCode)) { - // try with regsvr32 - SHELLEXECUTEINFO sei; - memset(&sei, 0, sizeof(sei)); - sei.cbSize = sizeof(sei); - sei.fMask = SEE_MASK_UNICODE; - sei.lpVerb = _T("runas"); - sei.lpFile = _T("regsvr32.exe"); - CString strParams = CString(_T("/u /s \"")) + strPath + CString(_T("\"")); - sei.lpParameters = strParams; - sei.nShow = SW_SHOW; + DWORD dwLastError = GetLastError(); + LOG_ERROR(GetLogger()) << L"Failed to retrieve process exit code. Last error: " << dwLastError; + CloseHandle(sei.hProcess); - if(!ShellExecuteEx(&sei)) - hResult = E_FAIL; - else - hResult = S_OK; + return eFailure; } + CloseHandle(sei.hProcess); - if(SUCCEEDED(hResult)) - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + LOG_INFO(GetLogger()) << L"Deregistration result: " << dwExitCode; - return hResult; + return (ERegistrationResult)dwExitCode; } HRESULT TShellExtensionClient::EnableExtensionIfCompatible(long lClientVersion, long& rlExtensionVersion, CString& rstrExtensionStringVersion) Index: src/ch/TShellExtensionClient.h =================================================================== diff -u -N -rbfa621d15810c821a147b2499926996b158b6444 -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/ch/TShellExtensionClient.h (.../TShellExtensionClient.h) (revision bfa621d15810c821a147b2499926996b158b6444) +++ src/ch/TShellExtensionClient.h (.../TShellExtensionClient.h) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -20,6 +20,8 @@ #define __TSHELLEXTENSIONCLIENT_H__ #include "../chext/chext.h" +#include "../liblogger/TLogger.h" +#include "../common/ERegistrationResult.h" class TShellExtensionClient { @@ -28,8 +30,8 @@ ~TShellExtensionClient(); // registers or unregisters shell extension - HRESULT RegisterShellExtDll(const CString& strPath, long lClientVersion, long& rlExtensionVersion, CString& rstrExtensionStringVersion); - HRESULT UnRegisterShellExtDll(const CString& strPath); + ERegistrationResult RegisterShellExtDll(long lClientVersion, long& rlExtensionVersion, CString& rstrExtensionStringVersion); + ERegistrationResult UnRegisterShellExtDll(); // enables the extension if compatible with the client (CH) version // returns S_OK if enabled, S_FALSE if not @@ -42,10 +44,15 @@ void FreeControlInterface(); HRESULT InitializeCOM(); void UninitializeCOM(); + bool DetectRegExe(); + logger::TLoggerPtr& GetLogger(); + private: + logger::TLoggerPtr m_spLog; bool m_bInitialized; IShellExtControl* m_piShellExtControl; + std::wstring m_strRegExe; }; #endif \ No newline at end of file Index: src/ch/ch.cpp =================================================================== diff -u -N -r09cedb80782a75d4b4896a1f3d2dd535688bf840 -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/ch/ch.cpp (.../ch.cpp) (revision 09cedb80782a75d4b4896a1f3d2dd535688bf840) +++ src/ch/ch.cpp (.../ch.cpp) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -635,69 +635,57 @@ 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, + 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); + } + + 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; } - else if(hResult == S_OK) - MsgBox(IDS_UNREGISTEROK_STRING, MB_ICONINFORMATION | MB_OK); } void CCopyHandlerApp::OnConfigNotify(const chcore::TStringSet& setPropNames) Index: src/ch/ch.h =================================================================== diff -u -N -r306fbe693c70290af9de9a5779084a697de22d75 -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/ch/ch.h (.../ch.h) (revision 306fbe693c70290af9de9a5779084a697de22d75) +++ src/ch/ch.h (.../ch.h) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -67,15 +67,17 @@ bool ParseCommandLine(); protected: - TShellExtensionClient m_tShellExtClient; + logger::TMultiLoggerConfigPtr m_spAppLoggerConfig; + logger::TMultiLoggerConfigPtr m_spEngineLoggerConfig; + + logger::TLoggerPtr m_spLog; + TCommandLineParser m_cmdLineParser; chcore::TCoreEngine m_chEngine; - logger::TLoggerPtr m_spLog; - logger::TMultiLoggerConfigPtr m_spAppLoggerConfig; - logger::TMultiLoggerConfigPtr m_spEngineLoggerConfig; TShellExtensionConfigPtr m_shellExtConfig; + TShellExtensionClient m_tShellExtClient; CWnd *m_pMainWindow; bool m_bComInitialized = false; Index: src/ch/ch.rc =================================================================== diff -u -N -rffbc773697bd08220163bf1e4491a34376b0f61c -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/ch/ch.rc (.../ch.rc) (revision ffbc773697bd08220163bf1e4491a34376b0f61c) +++ src/ch/ch.rc (.../ch.rc) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -748,14 +748,14 @@ BEGIN IDS_ONECOPY_STRING "Cannot run the second instance of this program" IDS_REGISTEROK_STRING "Integration with system enabled successfully." - IDS_REGISTERERR_STRING "Encountered an error while trying to enable integration with system.\nError #%errno (%errdesc)." + IDS_REGISTERERR_STRING "Failed to enable integration with system." + IDS_REGISTERED_ONLYNATIVE "Successfully enabled 64bit integration.\nFailed to enable 32bit integration." + IDS_REGISTERED_ONLY32BIT "Failed to enable 64bit integration.\nSuccessfully enabled 32bit integration." IDS_UNREGISTEROK_STRING "Integration with system disabled successfully." - IDS_UNREGISTERERR_STRING - "Encountered an error while trying to disable integration with system.\nError #%errno (%errdesc)." + IDS_UNREGISTERERR_STRING "Failed to disable integration with system." IDS_CRASH_STRING "Copy Handler encountered an internal problem and will be closed.\n\nIf you want to help correct this problem in the future releases of program you can send the crash information to the author of this program." IDS_COMMAND_LINE_FAILED_STRING "Cannot process command line arguments passed to Copy Handler." - IDS_CHEXT_ALREADY_UNREGISTERED "Integration with system already disabled." END STRINGTABLE Index: src/ch/langs/polish.lng =================================================================== diff -u -N -rdcc6234ed612a75910b8900704c9d564096a037a -rb556d023b748dfea230575959b6513acf29fd7b3 Binary files differ Index: src/ch/resource.h =================================================================== diff -u -N -rffbc773697bd08220163bf1e4491a34376b0f61c -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/ch/resource.h (.../resource.h) (revision ffbc773697bd08220163bf1e4491a34376b0f61c) +++ src/ch/resource.h (.../resource.h) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -430,7 +430,8 @@ #define IDS_UNREGISTERERR_STRING 6004 #define IDS_CRASH_STRING 6006 #define IDS_COMMAND_LINE_FAILED_STRING 6007 -#define IDS_CHEXT_ALREADY_UNREGISTERED 6008 +#define IDS_REGISTERED_ONLYNATIVE 6009 +#define IDS_REGISTERED_ONLY32BIT 6010 #define IDS_PROGRAM_STRING 8000 #define IDS_CLIPBOARDMONITORING_STRING 8001 #define IDS_CLIPBOARDINTERVAL_STRING 8002 Index: src/common/ERegistrationResult.h =================================================================== diff -u -N --- src/common/ERegistrationResult.h (revision 0) +++ src/common/ERegistrationResult.h (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -0,0 +1,31 @@ +// ============================================================================ +// Copyright (C) 2001-2016 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. +// ============================================================================ +#ifndef __EREGISTRATIONRESULT_H__ +#define __EREGISTRATIONRESULT_H__ + +enum ERegistrationResult +{ + eSuccess, + eSuccessNative, + eSuccess32Bit, + eSuccessNeedRestart, + eFailure, +}; + +#endif Index: src/regchext/TComRegistrar.cpp =================================================================== diff -u -N -re2054db3fa2be3652ca376a318d49dbaba8539ed -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/regchext/TComRegistrar.cpp (.../TComRegistrar.cpp) (revision e2054db3fa2be3652ca376a318d49dbaba8539ed) +++ src/regchext/TComRegistrar.cpp (.../TComRegistrar.cpp) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -25,38 +25,38 @@ DetectRegsvrPaths(); } -void TComRegistrar::RegisterNative(const wchar_t* pszPath, const wchar_t* pszDir) +bool TComRegistrar::RegisterNative(const wchar_t* pszPath, const wchar_t* pszDir) { if(!PathFileExists(pszPath)) throw std::runtime_error("File does not exist"); - Register(pszPath, pszDir, m_strNativeRegsvrPath.c_str()); + return Register(pszPath, pszDir, m_strNativeRegsvrPath.c_str()); } -void TComRegistrar::UnregisterNative(const wchar_t* pszPath, const wchar_t* pszDir) +bool TComRegistrar::UnregisterNative(const wchar_t* pszPath, const wchar_t* pszDir) { if(!PathFileExists(pszPath)) throw std::runtime_error("File does not exist"); - Unregister(pszPath, pszDir, m_strNativeRegsvrPath.c_str()); + return Unregister(pszPath, pszDir, m_strNativeRegsvrPath.c_str()); } #ifdef _WIN64 -void TComRegistrar::Register32bit(const wchar_t* pszPath, const wchar_t* pszDir) +bool TComRegistrar::Register32bit(const wchar_t* pszPath, const wchar_t* pszDir) { if(!PathFileExists(pszPath)) throw std::runtime_error("File does not exist"); - Register(pszPath, pszDir, m_str32bitRegsvr.c_str()); + return Register(pszPath, pszDir, m_str32bitRegsvr.c_str()); } -void TComRegistrar::Unregister32bit(const wchar_t* pszPath, const wchar_t* pszDir) +bool TComRegistrar::Unregister32bit(const wchar_t* pszPath, const wchar_t* pszDir) { if(!PathFileExists(pszPath)) throw std::runtime_error("File does not exist"); - Unregister(pszPath, pszDir, m_str32bitRegsvr.c_str()); + return Unregister(pszPath, pszDir, m_str32bitRegsvr.c_str()); } #endif @@ -66,31 +66,67 @@ // try with regsvr32 SHELLEXECUTEINFO sei = { 0 }; sei.cbSize = sizeof(sei); - sei.fMask = SEE_MASK_UNICODE; + sei.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = L"runas"; sei.lpFile = pszRegsvrPath; sei.lpDirectory = pszDir; std::wstring strParams = std::wstring(L"/s \"") + pszPath + L"\""; sei.lpParameters = strParams.c_str(); sei.nShow = SW_SHOW; - return ShellExecuteEx(&sei) != FALSE; + if (!ShellExecuteEx(&sei)) + return false; + + if (WaitForSingleObject(sei.hProcess, 10000) != WAIT_OBJECT_0) + { + CloseHandle(sei.hProcess); + return false; + } + + DWORD dwExitCode = 0; + if (!GetExitCodeProcess(sei.hProcess, &dwExitCode)) + { + CloseHandle(sei.hProcess); + return false; + } + + CloseHandle(sei.hProcess); + + return dwExitCode == 0; } bool TComRegistrar::Unregister(const wchar_t* pszPath, const wchar_t* pszDir, const wchar_t* pszRegsvrPath) { // try with regsvr32 SHELLEXECUTEINFO sei = { 0 }; sei.cbSize = sizeof(sei); - sei.fMask = SEE_MASK_UNICODE; + sei.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = L"runas"; sei.lpFile = pszRegsvrPath; sei.lpDirectory = pszDir; std::wstring strParams = std::wstring(L"/u /s \"") + pszPath + L"\""; sei.lpParameters = strParams.c_str(); sei.nShow = SW_SHOW; - return ShellExecuteEx(&sei) != FALSE; + if (!ShellExecuteEx(&sei)) + return false; + + if (WaitForSingleObject(sei.hProcess, 10000) != WAIT_OBJECT_0) + { + CloseHandle(sei.hProcess); + return false; + } + + DWORD dwExitCode = 0; + if (!GetExitCodeProcess(sei.hProcess, &dwExitCode)) + { + CloseHandle(sei.hProcess); + return false; + } + + CloseHandle(sei.hProcess); + + return dwExitCode == 0; } void TComRegistrar::DetectRegsvrPaths() Index: src/regchext/TComRegistrar.h =================================================================== diff -u -N -re2054db3fa2be3652ca376a318d49dbaba8539ed -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/regchext/TComRegistrar.h (.../TComRegistrar.h) (revision e2054db3fa2be3652ca376a318d49dbaba8539ed) +++ src/regchext/TComRegistrar.h (.../TComRegistrar.h) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -26,11 +26,11 @@ public: TComRegistrar(); - void RegisterNative(const wchar_t* pszPath, const wchar_t* pszDir); - void UnregisterNative(const wchar_t* pszPath, const wchar_t* pszDir); + bool RegisterNative(const wchar_t* pszPath, const wchar_t* pszDir); + bool UnregisterNative(const wchar_t* pszPath, const wchar_t* pszDir); #ifdef _WIN64 - void Register32bit(const wchar_t* pszPath, const wchar_t* pszDir); - void Unregister32bit(const wchar_t* pszPath, const wchar_t* pszDir); + bool Register32bit(const wchar_t* pszPath, const wchar_t* pszDir); + bool Unregister32bit(const wchar_t* pszPath, const wchar_t* pszDir); #endif private: Index: src/regchext/TExtensionDetector.cpp =================================================================== diff -u -N -re2054db3fa2be3652ca376a318d49dbaba8539ed -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/regchext/TExtensionDetector.cpp (.../TExtensionDetector.cpp) (revision e2054db3fa2be3652ca376a318d49dbaba8539ed) +++ src/regchext/TExtensionDetector.cpp (.../TExtensionDetector.cpp) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -32,6 +32,19 @@ DetectPaths(); } + +bool TExtensionDetector::HasNativePath() const +{ + return !m_strNativeBasePath.empty() && !m_strNativeExtension.empty(); +} + +#ifdef _WIN64 +bool TExtensionDetector::Has32bitPath() const +{ + return !m_str32bitBasePath.empty() && !m_str32bitExtension.empty(); +} +#endif + void TExtensionDetector::DetectPaths() { // get path of this file @@ -52,19 +65,25 @@ // find chext.dll/chext64.dll m_strNativeExtension = wstrThisPath + DLL_NATIVE; m_strNativeBasePath = wstrThisPath; - if(!PathFileExists(m_strNativeExtension.c_str())) - throw std::runtime_error("Native extension does not exist"); + if (!PathFileExists(m_strNativeExtension.c_str())) + { + m_strNativeExtension.clear(); + m_strNativeBasePath.clear(); + } #ifdef _WIN64 m_str32bitExtension = wstrThisPath + DLL_32BIT; m_str32bitBasePath = wstrThisPath; - if(!PathFileExists(m_strNativeExtension.c_str())) + if(!PathFileExists(m_str32bitExtension.c_str())) { m_str32bitExtension = wstrThisPath + L"ShellExt32\\" + DLL_32BIT; m_str32bitBasePath = wstrThisPath + L"ShellExt32\\"; - if(!PathFileExists(m_strNativeExtension.c_str())) - throw std::runtime_error("32bit extension does not exist"); + if(!PathFileExists(m_str32bitExtension.c_str())) + { + m_str32bitExtension.clear(); + m_str32bitBasePath.clear(); + } } #endif } Index: src/regchext/TExtensionDetector.h =================================================================== diff -u -N -re2054db3fa2be3652ca376a318d49dbaba8539ed -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/regchext/TExtensionDetector.h (.../TExtensionDetector.h) (revision e2054db3fa2be3652ca376a318d49dbaba8539ed) +++ src/regchext/TExtensionDetector.h (.../TExtensionDetector.h) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -28,9 +28,13 @@ const std::wstring& GetNativeExtension() const { return m_strNativeExtension; } const std::wstring& GetNativeBasePath() const { return m_strNativeBasePath; } + bool HasNativePath() const; + #ifdef _WIN64 const std::wstring& Get32bitExtension() const { return m_str32bitExtension; } const std::wstring& Get32bitBasePath() const { return m_str32bitBasePath; } + + bool Has32bitPath() const; #endif private: Index: src/regchext/regchext.cpp =================================================================== diff -u -N -re2054db3fa2be3652ca376a318d49dbaba8539ed -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/regchext/regchext.cpp (.../regchext.cpp) (revision e2054db3fa2be3652ca376a318d49dbaba8539ed) +++ src/regchext/regchext.cpp (.../regchext.cpp) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -20,6 +20,7 @@ #include #include "TExtensionDetector.h" #include "TComRegistrar.h" +#include "../common/ERegistrationResult.h" int APIENTRY wWinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInstance*/, @@ -42,25 +43,48 @@ TExtensionDetector extensions; TComRegistrar registrar; + bool bNativeSucceeded = extensions.HasNativePath(); +#ifdef _WIN64 + bool b32BitSucceeded = extensions.Has32bitPath(); +#endif if(bRegister) { + if(extensions.HasNativePath()) + bNativeSucceeded = registrar.RegisterNative(extensions.GetNativeExtension().c_str(), extensions.GetNativeBasePath().c_str()); #ifdef _WIN64 - registrar.Register32bit(extensions.Get32bitExtension().c_str(), extensions.Get32bitBasePath().c_str()); + if (extensions.Has32bitPath()) + b32BitSucceeded = registrar.Register32bit(extensions.Get32bitExtension().c_str(), extensions.Get32bitBasePath().c_str()); #endif - registrar.RegisterNative(extensions.GetNativeExtension().c_str(), extensions.GetNativeBasePath().c_str()); } else { + if (extensions.HasNativePath()) + bNativeSucceeded = registrar.UnregisterNative(extensions.GetNativeExtension().c_str(), extensions.GetNativeBasePath().c_str()); #ifdef _WIN64 - registrar.Unregister32bit(extensions.Get32bitExtension().c_str(), extensions.Get32bitBasePath().c_str()); + if (extensions.Has32bitPath()) + b32BitSucceeded = registrar.Unregister32bit(extensions.Get32bitExtension().c_str(), extensions.Get32bitBasePath().c_str()); #endif - registrar.UnregisterNative(extensions.GetNativeExtension().c_str(), extensions.GetNativeBasePath().c_str()); } + + // return 0 for success + // return 1 for partial success + // return 2 for failure +#ifdef _WIN64 + if(bNativeSucceeded && b32BitSucceeded) + return eSuccess; + if(bNativeSucceeded) + return eSuccessNative; + if(b32BitSucceeded) + return eSuccess32Bit; + return eFailure; +#else + if(bNativeSucceeded) + return eSuccess; + return eFailure; +#endif } catch(const std::exception&) { - return 1; + return eFailure; } - - return 0; } Index: src/regchext/regchext.vcxproj =================================================================== diff -u -N -r742602f5dfdd0f08397e1a0e24c3eb13a030bae1 -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/regchext/regchext.vcxproj (.../regchext.vcxproj) (revision 742602f5dfdd0f08397e1a0e24c3eb13a030bae1) +++ src/regchext/regchext.vcxproj (.../regchext.vcxproj) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -520,6 +520,7 @@ + Index: src/regchext/regchext.vcxproj.filters =================================================================== diff -u -N -re2054db3fa2be3652ca376a318d49dbaba8539ed -rb556d023b748dfea230575959b6513acf29fd7b3 --- src/regchext/regchext.vcxproj.filters (.../regchext.vcxproj.filters) (revision e2054db3fa2be3652ca376a318d49dbaba8539ed) +++ src/regchext/regchext.vcxproj.filters (.../regchext.vcxproj.filters) (revision b556d023b748dfea230575959b6513acf29fd7b3) @@ -59,5 +59,8 @@ Resource Files + + Source Files + \ No newline at end of file