Index: src/ch/AppHelper.cpp
===================================================================
diff -u -N -r8dc649003961dad64b92da67426814fb5dd862e0 -rffb46a396ce20cda2e04020cf01c118ae81642b5
--- src/ch/AppHelper.cpp	(.../AppHelper.cpp)	(revision 8dc649003961dad64b92da67426814fb5dd862e0)
+++ src/ch/AppHelper.cpp	(.../AppHelper.cpp)	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -45,192 +45,53 @@
 	if (m_hMutex)
 		ReleaseMutex(m_hMutex);
 
-	delete [] m_pszProgramPath;
 	delete [] m_pszProgramName;
 }
 
-// inits mutex app protection
-void CAppHelper::InitProtection()
-{
-	m_hMutex=CreateMutex(NULL, TRUE, CH_MUTEX_NAME);
-	m_bFirstInstance=(m_hMutex != NULL && GetLastError() != ERROR_ALREADY_EXISTS);
-}
-
-// retrieves application path
 void CAppHelper::RetrievePaths()
 {
 	// try to find '\\' in path to see if this is only exe name or fully qualified path
-#ifdef _UNICODE
-	TCHAR* pszArgv = __wargv[0];
-#else
-	TCHAR* pszArgv = __argv[0];
-#endif
+	TCHAR* pszArgv = __wargv[ 0 ];
 
-	TCHAR* pszName=_tcsrchr(pszArgv, _T('\\'));
-	if (pszName != NULL)
+	TCHAR* pszName = _tcsrchr(pszArgv, _T('\\'));
+	if(pszName != NULL)
 	{
 		// copy name
-		m_pszProgramName=new TCHAR[_tcslen(pszName+1)+1];
-		_tcscpy(m_pszProgramName, pszName+1);
-
-		// path
-		UINT uiSize=(UINT)(pszName-pszArgv);
-		m_pszProgramPath=new TCHAR[uiSize+1];
-		_tcsncpy(m_pszProgramPath, pszArgv, uiSize);
-		m_pszProgramPath[uiSize]=_T('\0');
+		m_pszProgramName = new TCHAR[ _tcslen(pszName + 1) + 1 ];
+		_tcscpy(m_pszProgramName, pszName + 1);
 	}
 	else
 	{
 		// copy name
-		m_pszProgramName=new TCHAR[_tcslen(pszArgv)+1];
+		m_pszProgramName = new TCHAR[ _tcslen(pszArgv) + 1 ];
 		_tcscpy(m_pszProgramName, pszArgv);
-
-		// path
-		TCHAR szPath[_MAX_PATH];
-		UINT uiSize=GetCurrentDirectory(_MAX_PATH, szPath);
-		_tcscat(szPath, _T("\\"));
-		m_pszProgramPath=new TCHAR[uiSize+2];
-		_tcsncpy(m_pszProgramPath, szPath, uiSize+2);
 	}
 }
 
+// inits mutex app protection
+void CAppHelper::InitProtection()
+{
+	m_hMutex=CreateMutex(NULL, TRUE, CH_MUTEX_NAME);
+	m_bFirstInstance=(m_hMutex != NULL && GetLastError() != ERROR_ALREADY_EXISTS);
+}
+
 void CAppHelper::RetrieveAppInfo()
 {
 	m_pszAppName = _T(PRODUCT_NAME);
 	m_pszAppNameVer = PRODUCT_FULL_VERSION_T;
 	m_pszAppVersion = _T(PRODUCT_VERSION);
 }
 
-// internal func - safe getting special folder locations
-UINT CAppHelper::GetFolderLocation(int iFolder, PTSTR pszBuffer)
-{
-	LPITEMIDLIST piid;
-	HRESULT h=SHGetSpecialFolderLocation(NULL, iFolder, &piid);
-	if (!SUCCEEDED(h))
-		return false;
-
-	// get path
-	BOOL bRes=SHGetPathFromIDList(piid, pszBuffer);
-
-	// free piid
-	LPMALLOC lpm;
-	if (!SUCCEEDED(SHGetMalloc(&lpm)))
-		return 0;
-
-	lpm->Free((void*)piid);
-	lpm->Release();
-
-	// check for error
-	if (!bRes)
-		return 0;
-
-	// strip the last '\\'
-	UINT uiLen=(UINT)_tcslen(pszBuffer);
-	if (pszBuffer[uiLen-1] == _T('\\'))
-	{
-		pszBuffer[uiLen-1]=_T('\0');
-		return uiLen-1;
-	}
-	else
-		return uiLen;
-}
-
-// expands given path
-CString CAppHelper::ExpandPath(CString strPath)
-{
-	// check if there is need to perform all these checkings
-	if (strPath[0] != _T('<'))
-		return strPath;
-
-	TCHAR szStr[ _MAX_PATH ];
-	szStr[ 0 ] = _T('\0');
-
-	// search for string to replace
-	// _T("<WINDOWS>"), _T("<TEMP>"), _T("<SYSTEM>"), _T("<APPDATA>"), _T("<DESKTOP>"), 
-	// _T("<PERSONAL>"), _T("<PROGRAM>")
-	if (_tcsnicmp(strPath, _T("<PROGRAM>"), 9) == 0)
-	{
-		// get windows path
-		_tcsncpy(szStr, m_pszProgramPath ? m_pszProgramPath : _T(""), _MAX_PATH);
-		szStr[_MAX_PATH - 1] = _T('\0');
-		_tcsncat(szStr, strPath.Mid(9), _MAX_PATH - _tcslen(szStr));
-		szStr[_MAX_PATH - 1] = _T('\0');
-	}
-	else if (_tcsnicmp(strPath, _T("<WINDOWS>"), 9) == 0)
-	{
-		// get windows path
-		UINT uiSize=GetWindowsDirectory(szStr, _MAX_PATH);
-		if (szStr[uiSize-1] == _T('\\'))
-			szStr[uiSize-1]=_T('\0');
-		_tcsncat(szStr, strPath.Mid(9), _MAX_PATH - uiSize);
-		szStr[_MAX_PATH - 1] = _T('\0');
-	}
-	else if (_tcsnicmp(strPath, _T("<TEMP>"), 6) == 0)	// temp dir
-	{
-		// get windows path
-		UINT uiSize=GetTempPath(_MAX_PATH, szStr);
-		if (szStr[uiSize-1] == _T('\\'))
-			szStr[uiSize-1]=_T('\0');
-		_tcsncat(szStr, strPath.Mid(6), _MAX_PATH - uiSize);
-		szStr[_MAX_PATH - 1] = _T('\0');
-	}
-	else if (_tcsnicmp(strPath, _T("<SYSTEM>"), 8) == 0)	// system
-	{
-		// get windows path
-		UINT uiSize=GetSystemDirectory(szStr, _MAX_PATH);
-		if (szStr[uiSize-1] == _T('\\'))
-			szStr[uiSize-1]=_T('\0');
-		_tcsncat(szStr, strPath.Mid(8), _MAX_PATH - uiSize);
-		szStr[_MAX_PATH - 1] = _T('\0');
-	}
-	else if (_tcsnicmp(strPath, _T("<APPDATA>"), 9) == 0)	// app data
-	{
-		// get windows path
-		UINT uiSize=GetFolderLocation(CSIDL_LOCAL_APPDATA, szStr);
-		if (szStr[uiSize-1] == _T('\\'))
-			szStr[uiSize-1]=_T('\0');
-		_tcsncat(szStr, strPath.Mid(9), _MAX_PATH - uiSize);
-		szStr[_MAX_PATH - 1] = _T('\0');
-	}
-	else if (_tcsnicmp(strPath, _T("<DESKTOP>"), 9) == 0)	// desktop
-	{
-		// get windows path
-		UINT uiSize=GetFolderLocation(CSIDL_DESKTOPDIRECTORY, szStr);
-		if (szStr[uiSize-1] == _T('\\'))
-			szStr[uiSize-1]=_T('\0');
-		_tcsncat(szStr, strPath.Mid(9), _MAX_PATH - uiSize);
-		szStr[_MAX_PATH - 1] = _T('\0');
-	}
-	else if (_tcsnicmp(strPath, _T("<PERSONAL>"), 10) == 0)	// personal...
-	{
-		// get windows path
-		UINT uiSize=GetFolderLocation(CSIDL_PERSONAL, szStr);
-		if (szStr[uiSize-1] == _T('\\'))
-			szStr[uiSize-1]=_T('\0');
-		_tcsncat(szStr, strPath.Mid(10), _MAX_PATH - uiSize);
-		szStr[_MAX_PATH - 1] = _T('\0');
-	}
-
-	// copy to src string
-	return szStr;
-}
-
 bool CAppHelper::GetProgramDataPath(CString& rStrPath)
 {
 	if(IsInPortableMode())
-		rStrPath = GetProgramPath();
+		rStrPath = m_pathProcessor.GetProgramPath();
 	else
 	{
-		HRESULT hResult = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, rStrPath.GetBufferSetLength(_MAX_PATH));
-		rStrPath.ReleaseBuffer();
-		if(FAILED(hResult))
-			return false;
+		rStrPath = m_pathProcessor.GetAppDataPath();
+		rStrPath += L"\\Copy Handler";
 
-		if(rStrPath.Right(1) != _T('\\'))
-			rStrPath += _T('\\');
-
 		// make sure to create the required directories if they does not exist
-		rStrPath += _T("Copy Handler");
 		if(!CreateDirectory(rStrPath, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
 			return false;
 	}
@@ -242,12 +103,22 @@
 	return true;
 }
 
+CString CAppHelper::ExpandPath(CString strPath)
+{
+	return m_pathProcessor.ExpandPath(strPath);
+}
+
+CString CAppHelper::GetProgramPath() const
+{
+	return m_pathProcessor.GetProgramPath();
+}
+
 bool CAppHelper::IsInPortableMode()
 {
 	if(!m_optPortableMode.is_initialized())
 	{
 		// check if the ch.ini exists in the program's directory - it is the only way we can determine portable mode
-		CString strPortableCfgPath = CString(GetProgramPath()) + _T("\\ch.xml");
+		CString strPortableCfgPath = CString(m_pathProcessor.GetProgramPath()) + _T("\\ch.xml");
 		if(GetFileAttributes(strPortableCfgPath) == INVALID_FILE_ATTRIBUTES)
 			m_optPortableMode = false;
 		else
@@ -287,7 +158,7 @@
 			return true;
 
 		// format the data to be written to registry
-		strKey.Format(_T("%s\\%s"), m_pszProgramPath, m_pszProgramName);
+		strKey.Format(_T("%s\\%s"), (PCTSTR)m_pathProcessor.GetProgramPath(), m_pszProgramName);
 	}
 	else
 	{
@@ -297,7 +168,7 @@
 		if(bEnable)
 		{
 			// key exists in registry, check if the value is correct
-			strKey.Format(_T("%s\\%s"), m_pszProgramPath, m_pszProgramName);
+			strKey.Format(_T("%s\\%s"), (PCTSTR)m_pathProcessor.GetProgramPath(), m_pszProgramName);
 
 			if(strValue.CompareNoCase(strKey) == 0)
 				return true;
Index: src/ch/AppHelper.h
===================================================================
diff -u -N -r44a2ec5f1eb0a435b56daef42ef5fe3b7a91da0d -rffb46a396ce20cda2e04020cf01c118ae81642b5
--- src/ch/AppHelper.h	(.../AppHelper.h)	(revision 44a2ec5f1eb0a435b56daef42ef5fe3b7a91da0d)
+++ src/ch/AppHelper.h	(.../AppHelper.h)	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -20,6 +20,7 @@
 #define __APPHELPER_H__
 
 #include <boost/optional.hpp>
+#include "TPathProcessor.h"
 
 class CAppHelper
 {
@@ -28,33 +29,32 @@
 	virtual ~CAppHelper();
 
 	bool SetAutorun(bool bState);		// changes state of "run with system" option
-	CString ExpandPath(CString strPath);	// expands path string - ie. <windows> into c:\windows
 
 	bool IsFirstInstance() const { return m_bFirstInstance; };
 
 	PCTSTR GetAppName() const { return m_pszAppName; };
 	PCTSTR GetAppNameVer() const { return m_pszAppNameVer; };
 	PCTSTR GetAppVersion() const { return m_pszAppVersion; };
 
-	PCTSTR GetProgramPath() const { return m_pszProgramPath; };
 	PCTSTR GetProgramName() const { return m_pszProgramName; };
 
 	bool GetProgramDataPath(CString& rStrPath);
+	CString ExpandPath(CString strPath);
+	CString GetProgramPath() const;
 
 	bool IsInPortableMode();
 
 protected:
 	void InitProtection();		// optional call - protects from running multiple instance
 	void RetrievePaths();							// reads program's path and name
 	void RetrieveAppInfo();							// reads app name and version from VERSION resource
-	UINT GetFolderLocation(int iFolder, PTSTR pszBuffer);
 
 protected:
 	HANDLE m_hMutex;
 	bool m_bFirstInstance;		// tells if it is first instance(true) or second(or third, ...)
 
 	// program placement
-	TCHAR* m_pszProgramPath;	// path from which this program was run
+	TPathProcessor m_pathProcessor;
 	TCHAR* m_pszProgramName;	// name of this program (ie. CH.exe)
 
 	TCHAR* m_pszAppName;		// app-name string of this app
Index: src/ch/OptionsDlg.cpp
===================================================================
diff -u -N -r045540c818c374806d09742ef3d7a984d8d757d3 -rffb46a396ce20cda2e04020cf01c118ae81642b5
--- src/ch/OptionsDlg.cpp	(.../OptionsDlg.cpp)	(revision 045540c818c374806d09742ef3d7a984d8d757d3)
+++ src/ch/OptionsDlg.cpp	(.../OptionsDlg.cpp)	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -343,17 +343,19 @@
 	SetPropValue<PP_PFORCESHUTDOWN>(rConfig, GetBoolProp(iPosition++));
 	SetPropValue<PP_PAUTOSAVEINTERVAL>(rConfig, GetUintProp(iPosition++));
 	SetPropValue<PP_PPROCESSPRIORITYCLASS>(rConfig, IndexToPriorityClass(GetIndexProp(iPosition++)));
+
 	// language
-	PCTSTR pszSrc=m_vld.at(GetIndexProp(iPosition++)).GetFilename(true);
-	if (_tcsnicmp(pszSrc, GetApp().GetProgramPath(), _tcslen(GetApp().GetProgramPath())) == 0)
+	CString strSrc = m_vld.at(GetIndexProp(iPosition++)).GetFilename(true);
+	CString strProgramPath = GetApp().GetProgramPath();
+	if (_tcsnicmp(strSrc, GetApp().GetProgramPath(), GetApp().GetProgramPath().GetLength()) == 0)
 	{
 		// replace the first part of path with <PROGRAM>
 		TCHAR szData[_MAX_PATH];
-		_sntprintf(szData, _MAX_PATH, _T("<PROGRAM>%s"), pszSrc+_tcslen(GetApp().GetProgramPath()));
+		_sntprintf(szData, _MAX_PATH, _T("<PROGRAM>%s"), strSrc.Mid(strProgramPath.GetLength()));
 		SetPropValue<PP_PLANGUAGE>(rConfig, szData);
 	}
 	else
-		SetPropValue<PP_PLANGUAGE>(rConfig, pszSrc);
+		SetPropValue<PP_PLANGUAGE>(rConfig, strSrc);
 
 	SKIP_SEPARATOR(iPosition);
 	SetPropValue<PP_STATUSREFRESHINTERVAL>(rConfig, GetUintProp(iPosition++));
Index: src/ch/TPathProcessor.cpp
===================================================================
diff -u -N
--- src/ch/TPathProcessor.cpp	(revision 0)
+++ src/ch/TPathProcessor.cpp	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -0,0 +1,166 @@
+// ============================================================================
+//  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.
+// ============================================================================
+#include "stdafx.h"
+#include "TPathProcessor.h"
+
+TPathProcessor::TPathProcessor()
+{
+	RetrievePaths();
+}
+
+CString TPathProcessor::ExpandPath(CString strPath)
+{
+	if(strPath[ 0 ] != _T('<'))
+		return strPath;
+
+	// search for string to replace
+	// _T("<WINDOWS>"), _T("<TEMP>"), _T("<SYSTEM>"), _T("<APPDATA>"), _T("<DESKTOP>"), 
+	// _T("<PERSONAL>"), _T("<PROGRAM>")
+	if(StartsWith(strPath, _T("<PROGRAM>")))
+		strPath.Replace(_T("<PROGRAM>"), m_strProgramPath);
+	else if(StartsWith(strPath, _T("<WINDOWS>")))
+		strPath.Replace(_T("<WINDOWS>"), GetWindowsPath());
+	else if(StartsWith(strPath, _T("<TEMP>")))	// temp dir
+		strPath.Replace(_T("<TEMP>"), GetTempPath());
+	else if(StartsWith(strPath, _T("<SYSTEM>")))	// system
+		strPath.Replace(_T("<SYSTEM>"), GetSystemPath());
+	else if(StartsWith(strPath, _T("<APPDATA>")))	// app data
+		strPath.Replace(_T("<APPDATA>"), GetFolderLocation(CSIDL_LOCAL_APPDATA));
+	else if(StartsWith(strPath, _T("<DESKTOP>")))	// desktop
+		strPath.Replace(_T("<DESKTOP>"), GetFolderLocation(CSIDL_DESKTOPDIRECTORY));
+	else if(StartsWith(strPath, _T("<PERSONAL>")))	// personal...
+		strPath.Replace(_T("<DESKTOP>"), GetFolderLocation(CSIDL_PERSONAL));
+
+	return strPath;
+}
+
+CString TPathProcessor::GetProgramPath() const
+{
+	return m_strProgramPath;
+}
+
+CString TPathProcessor::GetAppDataPath() const
+{
+	return GetFolderLocation(CSIDL_LOCAL_APPDATA);
+}
+
+bool TPathProcessor::StartsWith(const CString& strWhere, const CString& strWhat)
+{
+	int iLen = strWhat.GetLength();
+	if(iLen <= 0)
+		return false;
+
+	return (strWhere.Left(iLen) == strWhat);
+}
+
+CString TPathProcessor::GetWindowsPath()
+{
+	// get windows path
+	wchar_t szData[ _MAX_PATH + 1 ];
+	UINT uiSize = GetWindowsDirectory(szData, _MAX_PATH);
+	if(uiSize == 0 || uiSize > _MAX_PATH)
+		return CString();
+
+	if(szData[ uiSize - 1 ] == _T('\\'))
+		szData[ uiSize - 1 ] = _T('\0');
+
+	return szData;
+}
+
+CString TPathProcessor::GetTempPath()
+{
+	// get windows path
+	wchar_t szData[ _MAX_PATH + 1 ];
+	UINT uiSize = ::GetTempPath(_MAX_PATH, szData);
+	if(uiSize == 0 || uiSize > _MAX_PATH)
+		return CString();
+
+	if(szData[ uiSize - 1 ] == _T('\\'))
+		szData[ uiSize - 1 ] = _T('\0');
+
+	return szData;
+}
+
+CString TPathProcessor::GetSystemPath()
+{
+	// get windows path
+	wchar_t szData[ _MAX_PATH + 1 ];
+	UINT uiSize = GetSystemDirectory(szData, _MAX_PATH);
+	if(uiSize == 0 || uiSize > _MAX_PATH)
+		return CString();
+
+	if(szData[ uiSize - 1 ] == _T('\\'))
+		szData[ uiSize - 1 ] = _T('\0');
+
+	return szData;
+}
+
+CString TPathProcessor::GetFolderLocation(int iFolder)
+{
+	LPITEMIDLIST piid = nullptr;
+	HRESULT hResult = SHGetSpecialFolderLocation(NULL, iFolder, &piid);
+	if(!SUCCEEDED(hResult))
+		return CString();
+
+	// get path
+	wchar_t szData[ _MAX_PATH ];
+	BOOL bRes = SHGetPathFromIDList(piid, szData);
+
+	// free piid
+	LPMALLOC lpm = nullptr;
+	if(!SUCCEEDED(SHGetMalloc(&lpm)))
+		return CString();
+
+	lpm->Free((void*)piid);
+	lpm->Release();
+
+	// check for error
+	if(!bRes)
+		return CString();
+
+	// strip the last '\\'
+	CString strPath = szData;
+	strPath.TrimRight(L'\\');
+
+	return strPath;
+}
+
+void TPathProcessor::RetrievePaths()
+{
+	// try to find '\\' in path to see if this is only exe name or fully qualified path
+	TCHAR* pszArgv = __wargv[ 0 ];
+
+	CString strName = pszArgv;
+	int iPos = strName.ReverseFind(_T('\\'));
+
+	if(iPos != -1)
+		m_strProgramPath = strName.Left(iPos + 1);
+	else
+	{
+		// path
+		TCHAR szPath[ _MAX_PATH ];
+		UINT uiSize = GetCurrentDirectory(_MAX_PATH, szPath);
+		if(uiSize == 0)
+			m_strProgramPath.Empty();
+		else
+			m_strProgramPath = szPath;
+	}
+
+	m_strProgramPath.TrimRight(L'\\');
+}
Index: src/ch/TPathProcessor.h
===================================================================
diff -u -N
--- src/ch/TPathProcessor.h	(revision 0)
+++ src/ch/TPathProcessor.h	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -0,0 +1,46 @@
+// ============================================================================
+//  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 __TPATHPROCESSOR_H__
+#define __TPATHPROCESSOR_H__
+
+class TPathProcessor
+{
+public:
+	TPathProcessor();
+
+	CString ExpandPath(CString strPath);
+
+	CString GetProgramPath() const;
+	CString GetAppDataPath() const;
+
+private:
+	void RetrievePaths();
+
+	static CString GetFolderLocation(int iFolder);
+	static CString GetWindowsPath();
+	static CString GetTempPath();
+	static CString GetSystemPath();
+
+	bool StartsWith(const CString& strWhere, const CString& strWhat);
+
+private:
+	CString m_strProgramPath;	// path from which this program was run
+};
+
+#endif
Index: src/ch/ch.cpp
===================================================================
diff -u -N -r694e362bf3ce049a7bbba8b4cf442d07e6741901 -rffb46a396ce20cda2e04020cf01c118ae81642b5
--- src/ch/ch.cpp	(.../ch.cpp)	(revision 694e362bf3ce049a7bbba8b4cf442d07e6741901)
+++ src/ch/ch.cpp	(.../ch.cpp)	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -138,7 +138,7 @@
 	bool bChanged=false;		// flag that'll be returned - if the paths has changed
 
 	// generate the current filename - uses language from config
-	CString strHelpPath = ExpandPath(_T("<PROGRAM>\\Help\\"));
+	CString strHelpPath = m_pathProcessor.ExpandPath(_T("<PROGRAM>\\Help\\"));
 	strHelpPath += GetResManager().m_ld.GetHelpName();
 	if(strHelpPath != m_pszHelpFilePath)
 	{
@@ -347,7 +347,7 @@
 	rResManager.SetCallback(ResManCallback);
 	GetPropValue<PP_PLANGUAGE>(rCfg, strPath);
 	TRACE(_T("Help path=%s\n"), strPath);
-	if(!rResManager.SetLanguage(ExpandPath(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."), (PCTSTR)strPath);
@@ -576,7 +576,7 @@
 
 void CCopyHandlerApp::RegisterShellExtension() 
 {
-	CString strPath = CString(GetProgramPath()) + _T("\\");
+	CString strPath = CString(m_pathProcessor.GetProgramPath()) + _T("\\");
 
 #ifdef _WIN64
 	strPath += _T("chext64.dll");
@@ -614,7 +614,7 @@
 
 void CCopyHandlerApp::UnregisterShellExtension() 
 {
-	CString strPath = CString(GetProgramPath()) + _T("\\");
+	CString strPath = CString(m_pathProcessor.GetProgramPath()) + _T("\\");
 
 #ifdef _WIN64
 	strPath += _T("chext64.dll");
@@ -649,7 +649,7 @@
 		// update language in resource manager
 		CString strPath;
 		GetPropValue<PP_PLANGUAGE>(GetConfig(), strPath);
-		GetResManager().SetLanguage(ExpandPath(strPath));
+		GetResManager().SetLanguage(m_pathProcessor.ExpandPath(strPath));
 	}
 
 	if(setPropNames.HasValue(PropData<PP_LOGENABLELOGGING>::GetPropertyName()))
Index: src/ch/ch.vc140.vcxproj
===================================================================
diff -u -N -rc4b596d905262841724ae7b091c11a8c9d5b4a5f -rffb46a396ce20cda2e04020cf01c118ae81642b5
--- src/ch/ch.vc140.vcxproj	(.../ch.vc140.vcxproj)	(revision c4b596d905262841724ae7b091c11a8c9d5b4a5f)
+++ src/ch/ch.vc140.vcxproj	(.../ch.vc140.vcxproj)	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -522,6 +522,7 @@
     <ClInclude Include="shortcuts.h" />
     <ClInclude Include="StringHelpers.h" />
     <ClInclude Include="TMsgBox.h" />
+    <ClInclude Include="TPathProcessor.h" />
     <ClInclude Include="TProgressCtrlEx.h" />
     <ClInclude Include="TRecentPathsTools.h" />
     <ClInclude Include="TRegistry.h" />
@@ -770,6 +771,7 @@
     <ClCompile Include="shortcuts.cpp" />
     <ClCompile Include="StringHelpers.cpp" />
     <ClCompile Include="TMsgBox.cpp" />
+    <ClCompile Include="TPathProcessor.cpp" />
     <ClCompile Include="TProgressCtrlEx.cpp" />
     <ClCompile Include="TRecentPathsTools.cpp" />
     <ClCompile Include="TRegistry.cpp" />
Index: src/ch/ch.vc140.vcxproj.filters
===================================================================
diff -u -N -r926b1177cffa2face218fabb3d8af71910d1b8e5 -rffb46a396ce20cda2e04020cf01c118ae81642b5
--- src/ch/ch.vc140.vcxproj.filters	(.../ch.vc140.vcxproj.filters)	(revision 926b1177cffa2face218fabb3d8af71910d1b8e5)
+++ src/ch/ch.vc140.vcxproj.filters	(.../ch.vc140.vcxproj.filters)	(revision ffb46a396ce20cda2e04020cf01c118ae81642b5)
@@ -239,6 +239,9 @@
     <ClInclude Include="CDragDropComboEx.h">
       <Filter>Source Files\GUI\Controls</Filter>
     </ClInclude>
+    <ClInclude Include="TPathProcessor.h">
+      <Filter>Source Files\Tools</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\common\TShellExtMenuConfig.cpp">
@@ -406,6 +409,9 @@
     <ClCompile Include="CDragDropComboEx.cpp">
       <Filter>Source Files\GUI\Controls</Filter>
     </ClCompile>
+    <ClCompile Include="TPathProcessor.cpp">
+      <Filter>Source Files\Tools</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\ch.rc2">