OSDN Git Service

Merge7z: Remvoe version number from DLL file name
[winmerge-jp/winmerge-jp.git] / Src / 7zCommon.cpp
index 2ca35cb..123fda8 100644 (file)
@@ -94,30 +94,23 @@ DATE:               BY:                                     DESCRIPTION:
                                                                Change recommended version of 7-Zip to 4.65\r
 */\r
 \r
-// ID line follows -- this is updated by SVN\r
-// $Id: 7zCommon.cpp 7169 2010-05-16 14:44:19Z jtuc $\r
 \r
 #include "stdafx.h"\r
 #include "7zCommon.h"\r
 #include <afxinet.h>\r
-#include <shlwapi.h>\r
 #include "OptionsDef.h"\r
 #include "OptionsMgr.h"\r
-#include "Merge.h"             // DirDocFilter theApp GetOptionsMgr()\r
-#include "resource.h"\r
 #include "DirView.h"\r
 #include "DirDoc.h"\r
 #include "DirActions.h"\r
 //#include "ExternalArchiveFormat.h"\r
-#include "version.h"\r
+#include "VersionInfo.h"\r
 #include "paths.h"\r
 #include "Environment.h"\r
 #include "Merge7zFormatRegister.h"\r
 \r
 #ifdef _DEBUG\r
 #define new DEBUG_NEW\r
-#undef THIS_FILE\r
-static char THIS_FILE[] = __FILE__;\r
 #endif\r
 \r
 /**\r
@@ -126,9 +119,9 @@ static char THIS_FILE[] = __FILE__;
 static __declspec(thread) Merge7z::Proxy m_Merge7z =\r
 {\r
        { 0, 0, DllBuild_Merge7z, },\r
-       "Merge7z%u%02u"DECORATE_U".dll",\r
+       "Merge7z\\Merge7z.dll",\r
        "Merge7z",\r
-       NULL\r
+       nullptr\r
 };\r
 \r
 std::vector<Merge7z::Format *(*)(const String& path)> Merge7zFormatRegister::optionalFormats;\r
@@ -146,17 +139,16 @@ bool IsArchiveFile(const String& pszFile)
 {\r
        try {\r
                Merge7z::Format *piHandler = ArchiveGuessFormat(pszFile);\r
-               if (piHandler)\r
-                       return TRUE;\r
+               if (piHandler != nullptr)\r
+                       return true;\r
                else\r
-                       return FALSE;\r
+                       return false;\r
        }\r
        catch (CException *e)\r
        {\r
                e->Delete();\r
-               return FALSE;\r
+               return false;\r
        }\r
-       return FALSE;\r
 }\r
 \r
 /**\r
@@ -167,22 +159,22 @@ bool IsArchiveFile(const String& pszFile)
 Merge7z::Format *ArchiveGuessFormat(const String& path)\r
 {\r
        if (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE) == 0)\r
-               return NULL;\r
-       if (paths_IsDirectory(path))\r
-               return NULL;\r
+               return nullptr;\r
+       if (paths::IsDirectory(path))\r
+               return nullptr;\r
        String path2(path);\r
        // Map extensions through ExternalArchiveFormat.ini\r
        static TCHAR null[] = _T("");\r
        static const TCHAR section[] = _T("extensions");\r
-       String entry = paths_FindExtension(path);\r
+       String entry = paths::FindExtension(path);\r
        TCHAR value[20];\r
-       static LPCTSTR filename = NULL;\r
-       if (filename == NULL)\r
+       static LPCTSTR filename = nullptr;\r
+       if (filename == nullptr)\r
        {\r
                TCHAR cPath[INTERNET_MAX_PATH_LENGTH];\r
-               DWORD cchPath = SearchPath(NULL, _T("ExternalArchiveFormat.ini"), NULL,\r
-                       INTERNET_MAX_PATH_LENGTH, cPath, NULL);\r
-               filename = cchPath && cchPath < INTERNET_MAX_PATH_LENGTH ? StrDup(cPath) : null;\r
+               DWORD cchPath = SearchPath(nullptr, _T("ExternalArchiveFormat.ini"), nullptr,\r
+                       INTERNET_MAX_PATH_LENGTH, cPath, nullptr);\r
+               filename = cchPath && cchPath < INTERNET_MAX_PATH_LENGTH ? _tcsdup(cPath) : null;\r
        }\r
        if (*filename &&\r
                GetPrivateProfileString(section, entry.c_str(), null, value, 20, filename) &&\r
@@ -212,412 +204,20 @@ Merge7z::Format *ArchiveGuessFormat(const String& path)
        try\r
        {\r
                Merge7z::Format *pFormat = m_Merge7z->GuessFormat(path2.c_str());\r
-               if (!pFormat)\r
+               if (pFormat == nullptr)\r
                        pFormat = Merge7zFormatRegister::GuessFormat(path2);\r
                return pFormat;\r
        }\r
        catch (...)\r
        {\r
                Merge7z::Format *pFormat = Merge7zFormatRegister::GuessFormat(path2);\r
-               if (pFormat)\r
+               if (pFormat != nullptr)\r
                        return pFormat;\r
                throw;\r
        }\r
 }\r
 \r
 /**\r
- * @brief Self-initializing raw C character buffer class.\r
- */\r
-template<class TYPE, size_t SIZE> struct CRawString\r
-{\r
-       enum { Size = SIZE };\r
-       TYPE Data[SIZE];\r
-       CRawString()\r
-       {\r
-               Data[0] = 0;\r
-       }\r
-};\r
-\r
-/**\r
- * @brief Exception class for more explicit error message.\r
- */\r
-class C7ZipMismatchException : public CException\r
-{\r
-public:\r
-       C7ZipMismatchException(DWORD dwVer7zInstalled, DWORD dwVer7zLocal, CException *pCause)\r
-       {\r
-               m_dwVer7zInstalled = dwVer7zInstalled;\r
-               m_dwVer7zLocal = dwVer7zLocal;\r
-               m_pCause = pCause;\r
-       }\r
-       ~C7ZipMismatchException()\r
-       {\r
-               if (m_pCause)\r
-                       m_pCause->Delete();\r
-       }\r
-       virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0);\r
-protected:\r
-       DWORD m_dwVer7zInstalled;\r
-       DWORD m_dwVer7zLocal;\r
-       CException *m_pCause;\r
-       BOOL m_bShowAllways;\r
-       static const DWORD m_dwVer7zRecommended;\r
-       static const TCHAR m_strRegistryKey[];\r
-       static const TCHAR m_strDownloadURL[];\r
-       static INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);\r
-       static DWORD FormatVersion(LPTSTR, LPTSTR, DWORD);\r
-};\r
-\r
-/**\r
- * @brief Recommended version of 7-Zip.\r
- */\r
-const DWORD C7ZipMismatchException::m_dwVer7zRecommended = DWORD MAKELONG(65,4);\r
-\r
-/**\r
- * @brief Registry key for C7ZipMismatchException's ReportError() popup.\r
- */\r
-const TCHAR C7ZipMismatchException::m_strRegistryKey[] = _T("7ZipMismatch");\r
-\r
-/**\r
- * @brief Download URL for C7ZipMismatchException's ReportError() popup.\r
- */\r
-const TCHAR C7ZipMismatchException::m_strDownloadURL[] = _T("https://sourceforge.net/project/showfiles.php?group_id=13216&package_id=143957");\r
-\r
-/**\r
- * @brief Retrieve build number of given DLL.\r
- */\r
-static DWORD NTAPI GetDllBuild(LPCTSTR cPath)\r
-{\r
-       HMODULE hModule = LoadLibrary(cPath);\r
-       DLLVERSIONINFO dvi;\r
-       dvi.cbSize = sizeof dvi;\r
-       dvi.dwBuildNumber = ~0UL;\r
-       if (hModule)\r
-       {\r
-               dvi.dwBuildNumber = 0UL;\r
-               DLLGETVERSIONPROC DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hModule, "DllGetVersion");\r
-               if (DllGetVersion)\r
-               {\r
-                       DllGetVersion(&dvi);\r
-               }\r
-               FreeLibrary(hModule);\r
-       }\r
-       return dvi.dwBuildNumber;\r
-}\r
-\r
-/**\r
- * @brief Format Merge7z version number and plugin name, and retrieve DllBuild.\r
- */\r
-DWORD C7ZipMismatchException::FormatVersion(LPTSTR pcVersion, LPTSTR pcPluginName, DWORD dwVersion)\r
-{\r
-       *pcVersion = '\0';\r
-       *pcPluginName = '\0';\r
-       if (dwVersion)\r
-       {\r
-               wsprintf\r
-               (\r
-                       pcVersion, _T("%u.%02u"),\r
-                       UINT HIWORD(dwVersion),\r
-                       UINT LOWORD(dwVersion)\r
-               );\r
-               wsprintf\r
-               (\r
-                       pcPluginName,\r
-                       sizeof(TCHAR) == 1 ? _T("Merge7z%u%02u.dll") : _T("Merge7z%u%02uU.dll"),\r
-                       UINT HIWORD(dwVersion),\r
-                       UINT LOWORD(dwVersion)\r
-               );\r
-       }\r
-       return GetDllBuild(pcPluginName);\r
-}\r
-\r
-/**\r
- * @brief Populate ListBox with names/revisions of DLLs matching given pattern.\r
- */\r
-static void NTAPI DlgDirListDLLs(HWND hWnd, LPTSTR cPattern, int nIDListBox)\r
-{\r
-       HDC hDC = GetDC(hWnd);\r
-       HFONT hFont = (HFONT)SendDlgItemMessage(hWnd, nIDListBox, WM_GETFONT, 0, 0);\r
-       int cxView = (int)SendDlgItemMessage(hWnd, nIDListBox, LB_GETHORIZONTALEXTENT, 0, 0) - 8;\r
-       HGDIOBJ hObject = SelectObject(hDC, hFont);\r
-       WIN32_FIND_DATA ff;\r
-       HANDLE h = FindFirstFile(cPattern, &ff);\r
-       if (h != INVALID_HANDLE_VALUE)\r
-       {\r
-               do\r
-               {\r
-                       PathRemoveFileSpec(cPattern);\r
-                       PathAppend(cPattern, ff.cFileName);\r
-                       wsprintf(ff.cFileName, _T(" (dllbuild %04u)"), GetDllBuild(cPattern));\r
-                       lstrcat(cPattern, ff.cFileName);\r
-                       int cxText = (int)(WORD)GetTabbedTextExtent(hDC, cPattern, lstrlen(cPattern), 0, 0);\r
-                       if (cxView < cxText)\r
-                               cxView = cxText;\r
-                       SendDlgItemMessage(hWnd, nIDListBox, LB_ADDSTRING, 0, (LPARAM)cPattern);\r
-               } while (FindNextFile(h, &ff));\r
-               FindClose(h);\r
-       }\r
-       SelectObject(hDC, hObject);\r
-       ReleaseDC(hWnd, hDC);\r
-       SendDlgItemMessage(hWnd, nIDListBox, LB_SETHORIZONTALEXTENT, cxView + 8, 0);\r
-}\r
-\r
-/**\r
- * @brief OwnerDraw states from recent SDK.\r
- */\r
-#define ODS_NOACCEL         0x0100\r
-#define ODS_NOFOCUSRECT     0x0200\r
-\r
-/**\r
- * @brief WM_DRAWITEM notification handlers.\r
- */\r
-struct CDrawItemStruct : DRAWITEMSTRUCT\r
-{\r
-       typedef CDrawItemStruct *From;\r
-       void DrawWebLinkButton();\r
-};\r
-\r
-void CDrawItemStruct::DrawWebLinkButton()\r
-{\r
-       CRawString<TCHAR,INTERNET_MAX_PATH_LENGTH> cText;\r
-       int cchText = ::GetWindowText(hwndItem, cText.Data, cText.Size);\r
-       COLORREF clrText = RGB(0,0,255);\r
-       if (::GetWindowLong(hwndItem, GWL_STYLE) & BS_LEFTTEXT)\r
-       {\r
-               clrText = RGB(128,0,128);\r
-       }\r
-       RECT rcText = rcItem;\r
-       ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT|DT_CALCRECT);\r
-       ::OffsetRect(&rcText, 1, 0);\r
-       rcItem.right = rcText.right + 1;\r
-       rcItem.bottom = rcText.bottom + 1;\r
-       switch (itemAction)\r
-       {\r
-       case ODA_DRAWENTIRE:\r
-               ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcItem, 0, 0, 0);\r
-               ::SetBkMode(hDC, TRANSPARENT);\r
-               ::SetTextColor(hDC, clrText);\r
-               ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT);\r
-               rcText.top = rcText.bottom - 1;\r
-               ::SetBkColor(hDC, clrText);\r
-               ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcText, 0, 0, 0);\r
-               if (itemState & ODS_FOCUS)\r
-               {\r
-               case ODA_FOCUS:\r
-                       if (!(itemState & ODS_NOFOCUSRECT))\r
-                       {\r
-                               ::SetTextColor(hDC, 0);\r
-                               ::SetBkColor(hDC, RGB(255,255,255));\r
-                               ::SetBkMode(hDC, OPAQUE);\r
-                               DrawFocusRect(hDC, &rcItem);\r
-                       }\r
-               }\r
-               break;\r
-       }\r
-}\r
-\r
-/**\r
- * @brief Load a cursor from COMCTL32.DLL.\r
- */\r
-HCURSOR NTAPI CommCtrl_LoadCursor(LPCTSTR lpCursorName)\r
-{\r
-       HMODULE hModule = GetModuleHandle(_T("COMCTL32.DLL"));\r
-       return hModule ? LoadCursor(hModule, lpCursorName) : NULL;\r
-}\r
-\r
-/**\r
- * @brief DLGPROC for C7ZipMismatchException's ReportError() popup.\r
- */\r
-INT_PTR CALLBACK C7ZipMismatchException::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
-{\r
-       switch (uMsg)\r
-       {\r
-               case WM_INITDIALOG:\r
-               {\r
-                       theApp.TranslateDialog(hWnd);\r
-                       if (GetDlgItem(hWnd, 9001) == NULL)\r
-                       {\r
-                               // Dialog template isn't up to date. Give it a second chance.\r
-                               EndDialog(hWnd, -1);\r
-                               return FALSE;\r
-                       }\r
-                       C7ZipMismatchException *pThis = (C7ZipMismatchException *)lParam;\r
-                       CRawString<TCHAR,2600> cText;\r
-                       CRawString<TCHAR,80> cPresent, cMissing, cOutdated, cNone, cPlugin;\r
-                       if (pThis->m_pCause)\r
-                       {\r
-                               pThis->m_pCause->GetErrorMessage(cText.Data, cText.Size);\r
-                               SetDlgItemText(hWnd, 107, cText.Data);\r
-                       }\r
-                       else\r
-                       {\r
-                               GetDlgItemText(hWnd, 107, cText.Data, cText.Size);\r
-                               switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))\r
-                               {\r
-                               case 0:\r
-                                       lstrcat(cText.Data, _("\nNote: 7-Zip integration is disabled in WinMerge settings.").c_str());\r
-                                       break;\r
-                               case 2:\r
-                                       lstrcat(cText.Data, _("\nNote: 7-Zip integration is restricted to standalone operation in WinMerge settings.").c_str());\r
-                                       break;\r
-                               }\r
-                               SetDlgItemText(hWnd, 107, cText.Data);\r
-                       }\r
-                       GetDlgItemText(hWnd, 112, cPresent.Data, cPresent.Size);\r
-                       GetDlgItemText(hWnd, 122, cMissing.Data, cMissing.Size);\r
-                       GetDlgItemText(hWnd, 132, cOutdated.Data, cOutdated.Size);\r
-                       GetDlgItemText(hWnd, 120, cNone.Data, cNone.Size);\r
-                       GetDlgItemText(hWnd, 102, cPlugin.Data, cPlugin.Size);\r
-                       wsprintf(cText.Data, cPlugin.Data, DllBuild_Merge7z);\r
-                       SetDlgItemText(hWnd, 102, cText.Data);\r
-                       SetDlgItemText\r
-                       (\r
-                               hWnd, 109,\r
-                               (\r
-                                       pThis->m_dwVer7zRecommended == pThis->m_dwVer7zInstalled\r
-                               ||      pThis->m_dwVer7zRecommended == pThis->m_dwVer7zLocal\r
-                               ) ? cPresent.Data : cMissing.Data\r
-                       );\r
-                       DWORD dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zRecommended);\r
-                       SetDlgItemText(hWnd, 110, *cText.Data ? cText.Data : cNone.Data);\r
-                       SetDlgItemText(hWnd, 111, cPlugin.Data);\r
-                       SetDlgItemText(hWnd, 112, *cPlugin.Data == '\0' ? cPlugin.Data :\r
-                               dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);\r
-                       dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zInstalled);\r
-                       SetDlgItemText(hWnd, 120, *cText.Data ? cText.Data : cNone.Data);\r
-                       SetDlgItemText(hWnd, 121, cPlugin.Data);\r
-                       SetDlgItemText(hWnd, 122, *cPlugin.Data == '\0' ? cPlugin.Data :\r
-                               dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);\r
-                       dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zLocal);\r
-                       SetDlgItemText(hWnd, 130, *cText.Data ? cText.Data : cNone.Data);\r
-                       SetDlgItemText(hWnd, 131, cPlugin.Data);\r
-                       SetDlgItemText(hWnd, 132, *cPlugin.Data == '\0' ? cPlugin.Data :\r
-                               dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);\r
-                       GetModuleFileName(0, cText.Data, MAX_PATH);\r
-                       PathRemoveFileSpec(cText.Data);\r
-                       PathAppend(cText.Data, _T("Merge7z*.dll"));\r
-                       DlgDirListDLLs(hWnd, cText.Data, 105);\r
-                       if (DWORD cchPath = GetEnvironmentVariable(_T("path"), 0, 0))\r
-                       {\r
-                               static const TCHAR cSep[] = _T(";");\r
-                               LPTSTR pchPath = new TCHAR[cchPath];\r
-                               GetEnvironmentVariable(_T("PATH"), pchPath, cchPath);\r
-                               LPTSTR pchItem = pchPath;\r
-                               while (int cchItem = StrCSpn(pchItem += StrSpn(pchItem, cSep), cSep))\r
-                               {\r
-                                       if (cchItem < MAX_PATH)\r
-                                       {\r
-                                               CopyMemory(cText.Data, pchItem, cchItem*sizeof*pchItem);\r
-                                               cText.Data[cchItem] = 0;\r
-                                               PathAppend(cText.Data, _T("Merge7z*.dll"));\r
-                                               DlgDirListDLLs(hWnd, cText.Data, 105);\r
-                                       }\r
-                                       pchItem += cchItem;\r
-                               }\r
-                               delete[] pchPath;\r
-                       }\r
-                       if (SendDlgItemMessage(hWnd, 105, LB_GETCOUNT, 0, 0) == 0)\r
-                       {\r
-                               SendDlgItemMessage(hWnd, 105, LB_ADDSTRING, 0, (LPARAM) cNone.Data);\r
-                       }\r
-                       HICON hIcon = LoadIcon(0, IDI_EXCLAMATION);\r
-                       SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon);\r
-                       SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);\r
-                       if (pThis->m_bShowAllways)\r
-                       {\r
-                               ShowWindow(GetDlgItem(hWnd, 106), SW_HIDE);\r
-                       }\r
-               } return TRUE;\r
-               case WM_DRAWITEM:\r
-               {\r
-                       switch (wParam)\r
-                       {\r
-                       case 108:\r
-                               CDrawItemStruct::From(lParam)->DrawWebLinkButton();\r
-                               break;\r
-                       }\r
-               } return TRUE;\r
-               case WM_SETCURSOR:\r
-               {\r
-                       HCURSOR hCursor = 0;\r
-                       switch (GetDlgCtrlID((HWND)wParam))\r
-                       {\r
-                       case 108:\r
-                               hCursor = CommCtrl_LoadCursor(MAKEINTRESOURCE(108));\r
-                               break;\r
-                       }\r
-                       if (hCursor)\r
-                       {\r
-                               SetCursor(hCursor);\r
-                               SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1);\r
-                               return TRUE;\r
-                       }\r
-               } return FALSE;\r
-               case WM_COMMAND:\r
-               {\r
-                       switch (wParam)\r
-                       {\r
-                               case IDOK:\r
-                               case IDCANCEL:\r
-                               {\r
-                                       LRESULT nDontShowAgain = SendDlgItemMessage(hWnd, 106, BM_GETCHECK, 0, 0);\r
-                                       EndDialog(hWnd, MAKEWORD(IDOK, nDontShowAgain));\r
-                               } break;\r
-                               case 108:\r
-                               {\r
-                                       HINSTANCE h = ShellExecute(hWnd, _T("open"), m_strDownloadURL, 0, 0, SW_SHOWNORMAL);\r
-                                       if ((UINT)h > 32)\r
-                                       {\r
-                                               LONG lStyle = ::GetWindowLong((HWND)lParam, GWL_STYLE);\r
-                                               ::SetWindowLong((HWND)lParam, GWL_STYLE, lStyle|BS_LEFTTEXT);\r
-                                               ::InvalidateRect((HWND)lParam, 0, TRUE);\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               MessageBeep(0);\r
-                                       }\r
-                               } break;\r
-                       }\r
-               } return TRUE;\r
-       }\r
-       return FALSE;\r
-}\r
-\r
-/**\r
- * @brief Tell user what went wrong and how she can help.\r
- */\r
-int C7ZipMismatchException::ReportError(UINT nType, UINT nMessageID)\r
-{\r
-       UINT_PTR response = -1;\r
-       m_bShowAllways = nMessageID;\r
-       if (!m_bShowAllways)\r
-       {\r
-               // Suppress error message in case 7-Zip is not installed.\r
-               response =\r
-               (\r
-                       m_dwVer7zInstalled || m_dwVer7zLocal\r
-               ?       (INT_PTR)(int)theApp.GetProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, -1)\r
-               :       IDOK\r
-               );\r
-       }\r
-       if (response == -1)\r
-       {\r
-               HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();\r
-               response = DialogBoxParam(AfxGetResourceHandle(), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);\r
-               if (response == -1)\r
-               {\r
-                       response = DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);\r
-                       ASSERT(response != -1);\r
-               }\r
-               if (HIBYTE(response) == 1)\r
-               {\r
-                       theApp.WriteProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, response = int LOBYTE(response));\r
-               }\r
-       }\r
-       return response;\r
-}\r
-\r
-/**\r
  * @brief Check whether archive support is available.\r
  */\r
 int NTAPI HasZipSupport()\r
@@ -640,22 +240,6 @@ int NTAPI HasZipSupport()
 }\r
 \r
 /**\r
- * @brief Tell user why archive support is not available.\r
- */\r
-void NTAPI Recall7ZipMismatchError()\r
-{\r
-       try\r
-       {\r
-               m_Merge7z.operator->();\r
-       }\r
-       catch (CException *e)\r
-       {\r
-               e->ReportError(MB_ICONEXCLAMATION, TRUE);\r
-               e->Delete();\r
-       }\r
-}\r
-\r
-/**\r
  * @brief Delete head of temp path context list, and return its parent context.\r
  */\r
 CTempPathContext *CTempPathContext::DeleteHead()\r
@@ -665,34 +249,23 @@ CTempPathContext *CTempPathContext::DeleteHead()
        return pParent;\r
 }\r
 \r
-BOOL NTAPI IsMerge7zEnabled()\r
+void CTempPathContext::Swap(int idx1, int idx2)\r
 {\r
-       return AfxGetApp()->GetProfileInt(_T("Merge7z"), _T("Enable"), 0);\r
+       std::swap(m_strDisplayRoot[idx1], m_strDisplayRoot[idx2]);\r
+       std::swap(m_strRoot[idx1], m_strRoot[idx2]);\r
+       if (m_pParent != nullptr)\r
+               m_pParent->Swap(idx1, idx2);\r
 }\r
 \r
 /**\r
  * @brief Return installed or local version of 7-Zip.\r
  */\r
-DWORD NTAPI VersionOf7z(BOOL bLocal)\r
+DWORD NTAPI VersionOf7z()\r
 {\r
-       TCHAR path[MAX_PATH];\r
-       if (bLocal)\r
-       {\r
-               GetModuleFileName(0, path, sizeof path/sizeof*path);\r
-               PathRemoveFileSpec(path);\r
-       }\r
-       else\r
-       {\r
-               static const TCHAR szSubKey[] = _T("Software\\7-Zip");\r
-               static const TCHAR szValue[] = _T("Path");\r
-               DWORD type = 0;\r
-               DWORD size = sizeof path;\r
-               SHGetValue(HKEY_LOCAL_MACHINE, szSubKey, szValue, &type, path, &size);\r
-       }\r
-       PathAppend(path, _T("7z.dll"));\r
+       String path = paths::ConcatPath(env::GetProgPath(), _T("Merge7z\\7z.dll"));\r
        unsigned versionMS = 0;\r
        unsigned versionLS = 0;\r
-       CVersionInfo(path).GetFixedFileVersion(versionMS, versionLS);\r
+       CVersionInfo(path.c_str()).GetFixedFileVersion(versionMS, versionLS);\r
        return versionMS;\r
 }\r
 \r
@@ -704,63 +277,26 @@ interface Merge7z *Merge7z::Proxy::operator->()
        // As long as the Merge7z*.DLL has not yet been loaded, Merge7z\r
        // [0] points to the name of the DLL (with placeholders for 7-\r
        // Zip major and minor version numbers). Once the DLL has been\r
-       // loaded successfully, Merge7z[0] is set to NULL, causing the\r
+       // loaded successfully, Merge7z[0] is set to nullptr, causing the\r
        // if to fail on subsequent calls.\r
 \r
        if (const char *format = Merge7z[0])\r
        {\r
                // Merge7z has not yet been loaded\r
 \r
-               char name[MAX_PATH];\r
-               DWORD flags = ~0;\r
-               CException *pCause = NULL;\r
-               switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))\r
+               if (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE) == 0)\r
+                       throw new CResourceException();\r
+               if (DWORD ver = VersionOf7z())\r
                {\r
-               case 1: //Use installed 7-Zip if present. Otherwise, use local 7-Zip.\r
-                       if (DWORD ver = VersionOf7z(FALSE))\r
-                       {\r
-                               flags = Initialize::Default;\r
-                               try\r
-                               {\r
-                                       wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));\r
-                                       Merge7z[0] = name;\r
-                                       stub.Load();\r
-                                       break;\r
-                               }\r
-                               catch (CException *e)\r
-                               {\r
-                                       Merge7z[0] = format;\r
-                                       pCause = e;\r
-                               }\r
-                       }\r
-               case 2: //Always use local 7-Zip.\r
-                       if (DWORD ver = VersionOf7z(TRUE))\r
-                       {\r
-                               flags = Initialize::Default | Initialize::Local7z;\r
-                               try\r
-                               {\r
-                                       wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));\r
-                                       Merge7z[0] = name;\r
-                                       stub.Load();\r
-                                       break;\r
-                               }\r
-                               catch (CException *e)\r
-                               {\r
-                                       Merge7z[0] = format;\r
-                                       if (pCause) pCause->Delete();\r
-                                       pCause = e;\r
-                               }\r
-                       }\r
-               default:\r
-                       throw new C7ZipMismatchException\r
-                       (\r
-                               VersionOf7z(FALSE),\r
-                               VersionOf7z(TRUE),\r
-                               pCause\r
-                       );\r
+                       Merge7z[0] = format;\r
+                       stub.Load();\r
+               }\r
+               else\r
+               {\r
+                       throw new CResourceException();\r
                }\r
                LANGID wLangID = (LANGID)GetThreadLocale();\r
-               flags |= wLangID << 16;\r
+               DWORD flags = Initialize::Default | Initialize::Local7z | (wLangID << 16);\r
                if (GetOptionsMgr()->GetBool(OPT_ARCHIVE_PROBETYPE))\r
                {\r
                        flags |= Initialize::GuessFormatBySignature | Initialize::GuessFormatByExtension;\r
@@ -837,7 +373,7 @@ DirItemEnumerator::DirItemEnumerator(CDirView *pView, int nFlags)
                                continue;\r
                        }\r
                        // Enumerating items\r
-                       if (di.diffcode.isExists(m_index))\r
+                       if (di.diffcode.exists(m_index))\r
                        {\r
                                // Item is present on right side, i.e. folder is implied\r
                                m_rgImpliedFolders[m_index][di.diffFileInfo[m_index].path.get()] = PVOID(1);\r
@@ -853,7 +389,10 @@ UINT DirItemEnumerator::Open()
 {\r
        m_nIndex = -1;\r
        m_curFolderPrefix = m_rgFolderPrefix.begin();\r
-       m_index = (m_nFlags & Right) != 0 ? 1 : 0;\r
+       if (m_pView->GetDocument()->m_nDirs < 3)\r
+               m_index = (m_nFlags & Right) != 0 ? 1 : 0;\r
+       else\r
+               m_index = ((m_nFlags & Right) != 0) ? 2 : ((m_nFlags & Middle) != 0 ? 1 : 0);\r
        size_t nrgFolderPrefix = m_rgFolderPrefix.size();\r
        if (nrgFolderPrefix)\r
        {\r
@@ -864,11 +403,11 @@ UINT DirItemEnumerator::Open()
                nrgFolderPrefix = 1;\r
        }\r
        return\r
-       (\r
-               m_nFlags & LVNI_SELECTED\r
+       static_cast<UINT>((\r
+               (m_nFlags & LVNI_SELECTED)\r
        ?       pView(m_pView)->GetSelectedCount()\r
        :       pView(m_pView)->GetItemCount()\r
-       ) * nrgFolderPrefix;\r
+       ) * nrgFolderPrefix);\r
 }\r
 \r
 /**\r
@@ -897,7 +436,7 @@ const DIFFITEM &DirItemEnumerator::Next()
  * storage, along with the Envelope itself. The Envelope pointer is passed to\r
  * Merge7z as the return value of the function. It is not meant to be a success\r
  * indicator, so if no temporary storage is required, it is perfectly alright\r
- * to return NULL.\r
+ * to return `nullptr`.\r
  */\r
 Merge7z::Envelope *DirItemEnumerator::Enum(Item &item)\r
 {\r
@@ -909,17 +448,17 @@ Merge7z::Envelope *DirItemEnumerator::Enum(Item &item)
                return 0;\r
        }\r
 \r
-       bool isSideOnly = !di.diffcode.isExists(m_index);\r
+       bool isSideOnly = !di.diffcode.exists(m_index);\r
 \r
        Envelope *envelope = new Envelope;\r
 \r
        const String &sFilename = di.diffFileInfo[m_index].filename;\r
        const String &sSubdir = di.diffFileInfo[m_index].path;\r
        if (sSubdir.length())\r
-               envelope->Name = paths_ConcatPath(sSubdir, sFilename);\r
+               envelope->Name = paths::ConcatPath(sSubdir, sFilename);\r
        else\r
                envelope->Name = sFilename;\r
-       envelope->FullPath = paths_ConcatPath(\r
+       envelope->FullPath = paths::ConcatPath(\r
                        di.getFilepath(m_index, ctxt.GetNormalizedPath(m_index)),\r
                        sFilename);\r
 \r
@@ -932,7 +471,7 @@ Merge7z::Envelope *DirItemEnumerator::Enum(Item &item)
                {\r
                        // Item is missing on right side\r
                        PVOID &implied = m_rgImpliedFolders[m_index][di.diffFileInfo[1-m_index].path.get()];\r
-                       if (!implied)\r
+                       if (implied == nullptr)\r
                        {\r
                                // Folder is not implied by some other file, and has\r
                                // not been enumerated so far, so enumerate it now!\r
@@ -970,7 +509,7 @@ bool DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path)
 {\r
        DeleteFile(path);\r
        Merge7z::Format *piHandler = ArchiveGuessFormat(path);\r
-       if (piHandler)\r
+       if (piHandler != nullptr)\r
        {\r
                HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();\r
                CString pathIntermediate;\r
@@ -981,8 +520,8 @@ bool DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path)
                bool bDone = MultiStepCompressArchive(pathIntermediate);\r
                if (bDone)\r
                {\r
-                       piHandler->CompressArchive(hwndOwner, path,\r
-                               &SingleItemEnumerator(path, pathIntermediate));\r
+                       SingleItemEnumerator tmpEnumerator(path, pathIntermediate);\r
+                       piHandler->CompressArchive(hwndOwner, path, &tmpEnumerator);\r
                        DeleteFile(pathIntermediate);\r
                }\r
                else\r
@@ -1000,11 +539,8 @@ bool DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path)
 void DirItemEnumerator::CompressArchive(LPCTSTR path)\r
 {\r
        String strPath;\r
-       if (path == 0)\r
+       if (path == nullptr)\r
        {\r
-               // No path given, so prompt for path!\r
-               static const TCHAR _T_Merge7z[] = _T("Merge7z");\r
-               static const TCHAR _T_FilterIndex[] = _T("FilterIndex");\r
                // 7z311 can only write 7z, zip, and tar(.gz|.bz2) archives, so don't\r
                // offer other formats here!\r
                static const TCHAR _T_Filter[]\r
@@ -1043,7 +579,7 @@ void DirItemEnumerator::CompressArchive(LPCTSTR path)
                        OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN,\r
                        strFilter.c_str()\r
                );\r
-               dlg.m_ofn.nFilterIndex = AfxGetApp()->GetProfileInt(_T_Merge7z, _T_FilterIndex, 1);\r
+               dlg.m_ofn.nFilterIndex = GetOptionsMgr()->GetInt(OPT_ARCHIVE_FILTER_INDEX);\r
                // Use extension from current filter as default extension:\r
                if (int i = dlg.m_ofn.nFilterIndex)\r
                {\r
@@ -1062,7 +598,7 @@ void DirItemEnumerator::CompressArchive(LPCTSTR path)
                {\r
                        strPath = dlg.GetPathName();\r
                        path = strPath.c_str();\r
-                       AfxGetApp()->WriteProfileInt(_T_Merge7z, _T_FilterIndex, dlg.m_ofn.nFilterIndex);\r
+                       GetOptionsMgr()->SaveOption(OPT_ARCHIVE_FILTER_INDEX, static_cast<int>(dlg.m_ofn.nFilterIndex));\r
                }\r
        }\r
        if (path && !MultiStepCompressArchive(path))\r
@@ -1074,17 +610,18 @@ void DirItemEnumerator::CompressArchive(LPCTSTR path)
 \r
 DecompressResult DecompressArchive(HWND hWnd, const PathContext& files)\r
 {\r
-       DecompressResult res(files, NULL, IS_EXISTING_DIR);\r
+       DecompressResult res(files, nullptr, paths::IS_EXISTING_DIR);\r
        try\r
        {\r
                String path;\r
                USES_CONVERSION;\r
                // Handle archives using 7-zip\r
                Merge7z::Format *piHandler;\r
-               if (piHandler = ArchiveGuessFormat(res.files[0].c_str()))\r
+               piHandler = ArchiveGuessFormat(res.files[0]);\r
+               if (piHandler  != nullptr)\r
                {\r
                        res.pTempPathContext = new CTempPathContext;\r
-                       path = env_GetTempChildPath();\r
+                       path = env::GetTempChildPath();\r
                        for (int index = 0; index < res.files.GetSize(); index++)\r
                                res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];\r
                        if (res.files.GetSize() == 2 && res.files[0] == res.files[1])\r
@@ -1095,64 +632,70 @@ DecompressResult DecompressArchive(HWND hWnd, const PathContext& files)
                                        break;\r
                                if (res.files[0].find(path) == 0)\r
                                {\r
-                                       VERIFY(::DeleteFile(res.files[0].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[0].c_str())), false));\r
+                                       VERIFY(::DeleteFile(res.files[0].c_str()) || (LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), res.files[0].c_str())), false));\r
                                }\r
                                BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[0].c_str());\r
                                res.files[0] = OLE2T(pTmp);\r
                                SysFreeString(pTmp);\r
                                res.files[0].insert(0, _T("\\"));\r
                                res.files[0].insert(0, path);\r
-                       } while (piHandler = ArchiveGuessFormat(res.files[0].c_str()));\r
+                               piHandler = ArchiveGuessFormat(res.files[0]);\r
+                       } while (piHandler != nullptr);\r
                        res.files[0] = path;\r
                }\r
-               if (!res.files[1].empty() && (piHandler = ArchiveGuessFormat(res.files[1].c_str())))\r
+               piHandler = res.files[1].empty() ? nullptr\r
+                                                                                : ArchiveGuessFormat(res.files[1]);\r
+               if (piHandler != nullptr)\r
                {\r
-                       if (!res.pTempPathContext)\r
+                       if (res.pTempPathContext == nullptr)\r
                        {\r
                                res.pTempPathContext = new CTempPathContext;\r
                                for (int index = 0; index < res.files.GetSize(); index++)\r
                                        res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];\r
                        }\r
-                       path = env_GetTempChildPath();\r
+                       path = env::GetTempChildPath();\r
                        do\r
                        {\r
                                if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[1].c_str(), path.c_str())))\r
                                        break;;\r
                                if (res.files[1].find(path) == 0)\r
                                {\r
-                                       VERIFY(::DeleteFile(res.files[1].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[1].c_str())), false));\r
+                                       VERIFY(::DeleteFile(res.files[1].c_str()) || (LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), res.files[1].c_str())), false));\r
                                }\r
                                BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[1].c_str());\r
                                res.files[1] = OLE2T(pTmp);\r
                                SysFreeString(pTmp);\r
                                res.files[1].insert(0, _T("\\"));\r
                                res.files[1].insert(0, path);\r
-                       } while (piHandler = ArchiveGuessFormat(res.files[1].c_str()));\r
+                               piHandler = ArchiveGuessFormat(res.files[1]);\r
+                       } while (piHandler != nullptr);\r
                        res.files[1] = path;\r
                }\r
-               if (res.files.GetSize() > 2 && (piHandler = ArchiveGuessFormat(res.files[2].c_str())))\r
+               piHandler = (res.files.GetSize() <= 2) ? nullptr : ArchiveGuessFormat(res.files[2]);\r
+               if (piHandler != nullptr)\r
                {\r
-                       if (!res.pTempPathContext)\r
+                       if (res.pTempPathContext == nullptr)\r
                        {\r
                                res.pTempPathContext = new CTempPathContext;\r
                                for (int index = 0; index < res.files.GetSize(); index++)\r
                                        res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];\r
                        }\r
-                       path = env_GetTempChildPath();\r
+                       path = env::GetTempChildPath();\r
                        do\r
                        {\r
                                if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[2].c_str(), path.c_str())))\r
                                        break;;\r
                                if (res.files[2].find(path) == 0)\r
                                {\r
-                                       VERIFY(::DeleteFile(res.files[2].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[2].c_str())), false));\r
+                                       VERIFY(::DeleteFile(res.files[2].c_str()) || (LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), res.files[2].c_str())), false));\r
                                }\r
                                BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[1].c_str());\r
                                res.files[2] = OLE2T(pTmp);\r
                                SysFreeString(pTmp);\r
                                res.files[2].insert(0, _T("\\"));\r
                                res.files[2].insert(0, path);\r
-                       } while (piHandler = ArchiveGuessFormat(res.files[2].c_str()));\r
+                               piHandler = ArchiveGuessFormat(res.files[2]);\r
+                       } while (piHandler != nullptr);\r
                        res.files[2] = path;\r
                }\r
                if (res.files[1].empty())\r
@@ -1175,7 +718,6 @@ DecompressResult DecompressArchive(HWND hWnd, const PathContext& files)
        }\r
        catch (CException *e)\r
        {\r
-               e->ReportError(MB_ICONSTOP);\r
                e->Delete();\r
        }\r
        return res;\r