OSDN Git Service

Merge with stable
authorsdottaka <none@none>
Sat, 18 Jan 2014 15:05:36 +0000 (00:05 +0900)
committersdottaka <none@none>
Sat, 18 Jan 2014 15:05:36 +0000 (00:05 +0900)
75 files changed:
1  2 
Src/7zCommon.cpp
Src/7zCommon.h
Src/CCPrompt.cpp
Src/ChildFrm.cpp
Src/Common/LanguageSelect.cpp
Src/Common/LanguageSelect.h
Src/Common/PreferencesDlg.cpp
Src/Common/RegKey.cpp
Src/Common/RegOptionsMgr.cpp
Src/Common/RegOptionsMgr.h
Src/Common/ShellFileOperations.h
Src/Common/unicoder.cpp
Src/ConfirmFolderCopyDlg.cpp
Src/DiffViewBar.cpp
Src/DirActions.cpp
Src/DirCmpReportDlg.cpp
Src/DirColsDlg.cpp
Src/DirDoc.cpp
Src/DirFrame.cpp
Src/DirItem.h
Src/DirView.cpp
Src/DirView.h
Src/EditorFilepathBar.cpp
Src/FileActionScript.cpp
Src/FileFiltersDlg.cpp
Src/FileFiltersDlg.h
Src/FileOrFolderSelect.cpp
Src/FileOrFolderSelect.h
Src/FilepathEdit.cpp
Src/HexMergeDoc.cpp
Src/HexMergeDoc.h
Src/HexMergeFrm.cpp
Src/HexMergeView.cpp
Src/LineFiltersDlg.cpp
Src/LoadSaveCodepageDlg.cpp
Src/LocationBar.cpp
Src/LocationView.cpp
Src/MainFrm.cpp
Src/MainFrm.h
Src/Merge.cpp
Src/Merge.h
Src/MergeApp.cpp
Src/MergeApp.h
Src/MergeDoc.cpp
Src/MergeDocLineDiffs.cpp
Src/MergeEditView.cpp
Src/MergeEditView.h
Src/OpenView.cpp
Src/OptionsInit.cpp
Src/PatchDlg.cpp
Src/PatchTool.cpp
Src/PatchTool.h
Src/Plugins.cpp
Src/PluginsListDlg.cpp
Src/ProjectFilePathsDlg.cpp
Src/PropArchive.cpp
Src/PropBackups.cpp
Src/PropCodepage.cpp
Src/PropCompare.cpp
Src/PropCompareFolder.cpp
Src/PropEditor.cpp
Src/PropGeneral.cpp
Src/PropRegistry.cpp
Src/PropShell.cpp
Src/PropTextColors.cpp
Src/PropVss.cpp
Src/SaveClosingDlg.cpp
Src/SelectUnpackerDlg.cpp
Src/SelectUnpackerDlg.h
Src/SharedFilterDlg.cpp
Src/Splash.cpp
Src/TestFilterDlg.cpp
Src/VSSHelper.cpp
Src/WMGotoDlg.cpp
Src/paths.cpp

 -/////////////////////////////////////////////////////////////////////////////
 -//    WinMerge:  an interactive diff/merge utility
 -//    Copyright (C) 1997-2000  Thingamahoochie Software
 -//    Author: Dean Grimm
 -//
 -//    This program is free software; you can redistribute it and/or modify
 -//    it under the terms of the GNU General Public License as published by
 -//    the Free Software Foundation; either version 2 of the License, or
 -//    (at your option) any later version.
 -//
 -//    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 General Public License
 -//    along with this program; if not, write to the Free Software
 -//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 -//
 -/////////////////////////////////////////////////////////////////////////////
 -
 -/* 7zCommon.cpp: Implement 7z related classes and functions
 - * Copyright (c) 2003 Jochen Tucht
 - *
 - * Remarks:   Different versions of 7-Zip are interfaced through specific
 - *                    versions of Merge7z (Merge7z311.dll, Merge7z312.dll, etc.)
 - *                    WinMerge can either use an installed copy of the 7-Zip software,
 - *                    or fallback to a local set of 7-Zip DLLs, which are to be included
 - *                    in the WinMerge binary distribution.
 - *
 - *                    Fallback policies are as follows:
 - *
 - *                    1. Detect 7-Zip version installed (XXX).
 - *                    2. If there is a Merge7zXXX.dll, be happy to use it
 - *                    3. Detect 7-Zip version from WinMerge distribution (YYY).
 - *                    4. If there is a Merge7zYYY.dll, be happy to use it.
 - *                    5. Sorry, no way.
 - *
 - *                    These rules can be customized by setting a registry variable
 - *                    *Merge7z/Enable* of type DWORD to one of the following values:
 - *
 - *                    0 - Entirely disable 7-Zip integration.
 - *                    1 - Use installed 7-Zip if present. Otherwise, use local 7-Zip.
 - *                    2 - Always use local 7-Zip.
 - *
 -
 -Please mind 2. a) of the GNU General Public License, and log your changes below.
 -
 -DATE:         BY:                                     DESCRIPTION:
 -==========    ==================      ================================================
 -2003-12-09    Jochen Tucht            Created
 -2003-12-16    Jochen Tucht            Properly generate .tar.gz and .tar.bz2
 -2003-12-16    Jochen Tucht            Obtain long path to temporary folder
 -2004-01-20    Jochen Tucht            Complain only once if Merge7z*.dll is missing
 -2004-01-25    Jochen Tucht            Fix bad default for OPENFILENAME::nFilterIndex
 -2004-03-15    Jochen Tucht            Fix Visual Studio 2003 build issue
 -2004-04-13    Jochen Tucht            Avoid StrNCat to get away with shlwapi 4.70
 -2004-08-25    Jochen Tucht            More explicit error message
 -2004-10-17    Jochen Tucht            Leave decision whether to recurse into folders
 -                                                              to enumerator (Mask.Recurse)
 -2004-11-03    Jochen Tucht            FIX [1048997] as proposed by Kimmo 2004-11-02
 -2005-01-15    Jochen Tucht            Read 7-Zip version from 7zip_pad.xml
 -                                                              Set Merge7z UI language if DllBuild_Merge7z >= 9
 -2005-01-22    Jochen Tucht            Better explain what's present/missing/outdated
 -2005-02-05    Jochen Tucht            Fall back to IDD_MERGE7ZMISMATCH template from
 -                                                              .exe if .lang file isn't up to date.
 -2005-02-26    Jochen Tucht            Add download link to error message
 -2005-02-26    Jochen Tucht            Use WinAPI to obtain ISO language/region codes
 -2005-02-27    Jochen Tucht            FIX [1152375]
 -2005-04-24    Kimmo Varis                     Don't use DiffContext exported from DirView
 -2005-06-08    Kimmo Varis                     Use DIFFITEM, not reference to it (hopefully only
 -                                                              temporarily, to sort out new directory compare)
 -2005-06-22    Jochen Tucht            Change recommended version of 7-Zip to 4.20
 -                                                              Remove noise from Nagbox
 -2005-07-03    Jochen Tucht            DIFFITEM has changed due to RFE [ 1205516 ]
 -2005-07-04    Jochen Tucht            New global ArchiveGuessFormat() checks for
 -                                                              formats to be handled by external command line
 -                                                              tools. These take precedence over Merge7z
 -                                                              internal handlers.
 -2005-07-05    Jochen Tucht            Move to Merge7z::Format::GetDefaultName() to
 -                                                              build intermediate filenames for multi-step
 -                                                              compression.
 -2005-07-15    Jochen Tucht            Remove external command line tool integration
 -                                                              for now. Rethink about it after 2.4 branch.
 -2005-08-20    Jochen Tucht            Option to guess archive format by signature
 -                                                              Map extensions through ExternalArchiveFormat.ini
 -2005-08-23    Jochen Tucht            Option to entirely disable 7-Zip integration
 -2007-01-04    Kimmo Varis                     Convert using COptionsMgr for options.
 -2007-06-16    Jochen Neubeck          FIX [1723263] "Zip --> Both" operation...
 -2007-12-22    Jochen Neubeck          Fix Merge7z UI lang for new translation system
 -                                                              Change recommended version of 7-Zip to 4.57
 -2010-05-16    Jochen Neubeck          Read 7-Zip version from 7z.dll (which has long
 -                                                              ago replaced the various format and codec DLLs)
 -                                                              Change recommended version of 7-Zip to 4.65
 -*/
 -
 -// ID line follows -- this is updated by SVN
 -// $Id: 7zCommon.cpp 7169 2010-05-16 14:44:19Z jtuc $
 -
 -#include "stdafx.h"
 -#include "7zCommon.h"
 -#include <afxinet.h>
 -#include <shlwapi.h>
 -#include <paths.h>
 -#include "OptionsDef.h"
 -#include "OptionsMgr.h"
 -#include "Merge.h"            // DirDocFilter theApp GetOptionsMgr()
 -#include "resource.h"
 -#include "DirDoc.h"
 -//#include "ExternalArchiveFormat.h"
 -#include "version.h"
 -#include "Environment.h"
 -
 -#ifdef _DEBUG
 -#define new DEBUG_NEW
 -#undef THIS_FILE
 -static char THIS_FILE[] = __FILE__;
 -#endif
 -
 -/**
 - * @brief Proxy for Merge7z
 - */
 -static __declspec(thread) Merge7z::Proxy m_Merge7z =
 -{
 -      { 0, 0, DllBuild_Merge7z, },
 -      "Merge7z%u%02u"DECORATE_U".dll",
 -      "Merge7z",
 -      NULL
 -};
 -
 -bool IsArchiveFile(const String& pszFile)
 -{
 -      try {
 -              Merge7z::Format *piHandler = ArchiveGuessFormat(pszFile);
 -              if (piHandler)
 -                      return TRUE;
 -              else
 -                      return FALSE;
 -      }
 -      catch (CException *e)
 -      {
 -              e->Delete();
 -              return FALSE;
 -      }
 -      return FALSE;
 -}
 -
 -/**
 - * @brief Wrap Merge7z::GuessFormat() to allow for some customizing:
 - * - Check if 7-Zip integration is enabled.
 - * - Check for filename extension mappings.
 - */
 -Merge7z::Format *ArchiveGuessFormat(const String& path)
 -{
 -      if (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE) == 0)
 -              return NULL;
 -      if (paths_IsDirectory(path))
 -              return NULL;
 -      String path2(path);
 -      // Map extensions through ExternalArchiveFormat.ini
 -      static TCHAR null[] = _T("");
 -      static const TCHAR section[] = _T("extensions");
 -      String entry = paths_FindExtension(path);
 -      TCHAR value[20];
 -      static LPCTSTR filename = NULL;
 -      if (filename == NULL)
 -      {
 -              TCHAR cPath[INTERNET_MAX_PATH_LENGTH];
 -              DWORD cchPath = SearchPath(NULL, _T("ExternalArchiveFormat.ini"), NULL,
 -                      INTERNET_MAX_PATH_LENGTH, cPath, NULL);
 -              filename = cchPath && cchPath < INTERNET_MAX_PATH_LENGTH ? StrDup(cPath) : null;
 -      }
 -      if (*filename &&
 -              GetPrivateProfileString(section, entry.c_str(), null, value, 20, filename) &&
 -              *value == '.')
 -      {
 -              // Remove end-of-line comments (in string returned from GetPrivateProfileString)
 -              // that is, remove semicolon & whatever follows it
 -              if (LPTSTR p = StrChr(value, ';'))
 -              {
 -                      *p = '\0';
 -                      StrTrim(value, _T(" \t"));
 -              }
 -              path2 = value;
 -      }
 -
 -      // PATCH [ 1229867 ] RFE [ 1205516 ], RFE [ 887948 ], and other issues
 -      // command line integration portion is not yet applied
 -      // so following code not yet valid, so temporarily commented out
 -      // Look for command line tool first
 -      /*Merge7z::Format *pFormat;
 -      if (CExternalArchiveFormat::GuessFormat(path, pFormat))
 -      {
 -              return pFormat;
 -      }*/
 -      // Default to Merge7z*.dll
 -
 -      return m_Merge7z->GuessFormat(path2.c_str());
 -}
 -
 -/**
 - * @brief Self-initializing raw C character buffer class.
 - */
 -template<class TYPE, size_t SIZE> struct CRawString
 -{
 -      enum { Size = SIZE };
 -      TYPE Data[SIZE];
 -      CRawString()
 -      {
 -              Data[0] = 0;
 -      }
 -};
 -
 -/**
 - * @brief Exception class for more explicit error message.
 - */
 -class C7ZipMismatchException : public CException
 -{
 -public:
 -      C7ZipMismatchException(DWORD dwVer7zInstalled, DWORD dwVer7zLocal, CException *pCause)
 -      {
 -              m_dwVer7zInstalled = dwVer7zInstalled;
 -              m_dwVer7zLocal = dwVer7zLocal;
 -              m_pCause = pCause;
 -      }
 -      ~C7ZipMismatchException()
 -      {
 -              if (m_pCause)
 -                      m_pCause->Delete();
 -      }
 -      virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0);
 -protected:
 -      DWORD m_dwVer7zInstalled;
 -      DWORD m_dwVer7zLocal;
 -      CException *m_pCause;
 -      BOOL m_bShowAllways;
 -      static const DWORD m_dwVer7zRecommended;
 -      static const TCHAR m_strRegistryKey[];
 -      static const TCHAR m_strDownloadURL[];
 -      static INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
 -      static DWORD FormatVersion(LPTSTR, LPTSTR, DWORD);
 -};
 -
 -/**
 - * @brief Recommended version of 7-Zip.
 - */
 -const DWORD C7ZipMismatchException::m_dwVer7zRecommended = DWORD MAKELONG(65,4);
 -
 -/**
 - * @brief Registry key for C7ZipMismatchException's ReportError() popup.
 - */
 -const TCHAR C7ZipMismatchException::m_strRegistryKey[] = _T("7ZipMismatch");
 -
 -/**
 - * @brief Download URL for C7ZipMismatchException's ReportError() popup.
 - */
 -const TCHAR C7ZipMismatchException::m_strDownloadURL[] = _T("https://sourceforge.net/project/showfiles.php?group_id=13216&package_id=143957");
 -
 -/**
 - * @brief Retrieve build number of given DLL.
 - */
 -static DWORD NTAPI GetDllBuild(LPCTSTR cPath)
 -{
 -      HMODULE hModule = LoadLibrary(cPath);
 -      DLLVERSIONINFO dvi;
 -      dvi.cbSize = sizeof dvi;
 -      dvi.dwBuildNumber = ~0UL;
 -      if (hModule)
 -      {
 -              dvi.dwBuildNumber = 0UL;
 -              DLLGETVERSIONPROC DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hModule, "DllGetVersion");
 -              if (DllGetVersion)
 -              {
 -                      DllGetVersion(&dvi);
 -              }
 -              FreeLibrary(hModule);
 -      }
 -      return dvi.dwBuildNumber;
 -}
 -
 -/**
 - * @brief Format Merge7z version number and plugin name, and retrieve DllBuild.
 - */
 -DWORD C7ZipMismatchException::FormatVersion(LPTSTR pcVersion, LPTSTR pcPluginName, DWORD dwVersion)
 -{
 -      *pcVersion = '\0';
 -      *pcPluginName = '\0';
 -      if (dwVersion)
 -      {
 -              wsprintf
 -              (
 -                      pcVersion, _T("%u.%02u"),
 -                      UINT HIWORD(dwVersion),
 -                      UINT LOWORD(dwVersion)
 -              );
 -              wsprintf
 -              (
 -                      pcPluginName,
 -                      sizeof(TCHAR) == 1 ? _T("Merge7z%u%02u.dll") : _T("Merge7z%u%02uU.dll"),
 -                      UINT HIWORD(dwVersion),
 -                      UINT LOWORD(dwVersion)
 -              );
 -      }
 -      return GetDllBuild(pcPluginName);
 -}
 -
 -/**
 - * @brief Populate ListBox with names/revisions of DLLs matching given pattern.
 - */
 -static void NTAPI DlgDirListDLLs(HWND hWnd, LPTSTR cPattern, int nIDListBox)
 -{
 -      HDC hDC = GetDC(hWnd);
 -      HFONT hFont = (HFONT)SendDlgItemMessage(hWnd, nIDListBox, WM_GETFONT, 0, 0);
 -      int cxView = (int)SendDlgItemMessage(hWnd, nIDListBox, LB_GETHORIZONTALEXTENT, 0, 0) - 8;
 -      HGDIOBJ hObject = SelectObject(hDC, hFont);
 -      WIN32_FIND_DATA ff;
 -      HANDLE h = FindFirstFile(cPattern, &ff);
 -      if (h != INVALID_HANDLE_VALUE)
 -      {
 -              do
 -              {
 -                      PathRemoveFileSpec(cPattern);
 -                      PathAppend(cPattern, ff.cFileName);
 -                      wsprintf(ff.cFileName, _T(" (dllbuild %04u)"), GetDllBuild(cPattern));
 -                      lstrcat(cPattern, ff.cFileName);
 -                      int cxText = (int)(WORD)GetTabbedTextExtent(hDC, cPattern, lstrlen(cPattern), 0, 0);
 -                      if (cxView < cxText)
 -                              cxView = cxText;
 -                      SendDlgItemMessage(hWnd, nIDListBox, LB_ADDSTRING, 0, (LPARAM)cPattern);
 -              } while (FindNextFile(h, &ff));
 -              FindClose(h);
 -      }
 -      SelectObject(hDC, hObject);
 -      ReleaseDC(hWnd, hDC);
 -      SendDlgItemMessage(hWnd, nIDListBox, LB_SETHORIZONTALEXTENT, cxView + 8, 0);
 -}
 -
 -/**
 - * @brief OwnerDraw states from recent SDK.
 - */
 -#define ODS_NOACCEL         0x0100
 -#define ODS_NOFOCUSRECT     0x0200
 -
 -/**
 - * @brief WM_DRAWITEM notification handlers.
 - */
 -struct CDrawItemStruct : DRAWITEMSTRUCT
 -{
 -      typedef CDrawItemStruct *From;
 -      void DrawWebLinkButton();
 -};
 -
 -void CDrawItemStruct::DrawWebLinkButton()
 -{
 -      CRawString<TCHAR,INTERNET_MAX_PATH_LENGTH> cText;
 -      int cchText = ::GetWindowText(hwndItem, cText.Data, cText.Size);
 -      COLORREF clrText = RGB(0,0,255);
 -      if (::GetWindowLong(hwndItem, GWL_STYLE) & BS_LEFTTEXT)
 -      {
 -              clrText = RGB(128,0,128);
 -      }
 -      RECT rcText = rcItem;
 -      ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT|DT_CALCRECT);
 -      ::OffsetRect(&rcText, 1, 0);
 -      rcItem.right = rcText.right + 1;
 -      rcItem.bottom = rcText.bottom + 1;
 -      switch (itemAction)
 -      {
 -      case ODA_DRAWENTIRE:
 -              ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcItem, 0, 0, 0);
 -              ::SetBkMode(hDC, TRANSPARENT);
 -              ::SetTextColor(hDC, clrText);
 -              ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT);
 -              rcText.top = rcText.bottom - 1;
 -              ::SetBkColor(hDC, clrText);
 -              ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcText, 0, 0, 0);
 -              if (itemState & ODS_FOCUS)
 -              {
 -              case ODA_FOCUS:
 -                      if (!(itemState & ODS_NOFOCUSRECT))
 -                      {
 -                              ::SetTextColor(hDC, 0);
 -                              ::SetBkColor(hDC, RGB(255,255,255));
 -                              ::SetBkMode(hDC, OPAQUE);
 -                              DrawFocusRect(hDC, &rcItem);
 -                      }
 -              }
 -              break;
 -      }
 -}
 -
 -/**
 - * @brief Load a cursor from COMCTL32.DLL.
 - */
 -HCURSOR NTAPI CommCtrl_LoadCursor(LPCTSTR lpCursorName)
 -{
 -      HMODULE hModule = GetModuleHandle(_T("COMCTL32.DLL"));
 -      return hModule ? LoadCursor(hModule, lpCursorName) : NULL;
 -}
 -
 -/**
 - * @brief DLGPROC for C7ZipMismatchException's ReportError() popup.
 - */
 -INT_PTR CALLBACK C7ZipMismatchException::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 -{
 -      switch (uMsg)
 -      {
 -              case WM_INITDIALOG:
 -              {
 -                      theApp.TranslateDialog(hWnd);
 -                      if (GetDlgItem(hWnd, 9001) == NULL)
 -                      {
 -                              // Dialog template isn't up to date. Give it a second chance.
 -                              EndDialog(hWnd, -1);
 -                              return FALSE;
 -                      }
 -                      C7ZipMismatchException *pThis = (C7ZipMismatchException *)lParam;
 -                      CRawString<TCHAR,2600> cText;
 -                      CRawString<TCHAR,80> cPresent, cMissing, cOutdated, cNone, cPlugin;
 -                      if (pThis->m_pCause)
 -                      {
 -                              pThis->m_pCause->GetErrorMessage(cText.Data, cText.Size);
 -                              SetDlgItemText(hWnd, 107, cText.Data);
 -                      }
 -                      else
 -                      {
 -                              GetDlgItemText(hWnd, 107, cText.Data, cText.Size);
 -                              switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))
 -                              {
 -                              case 0:
 -                                      lstrcat(cText.Data, theApp.LoadString(IDS_MERGE7Z_ENABLE_0).c_str());
 -                                      break;
 -                              case 2:
 -                                      lstrcat(cText.Data, theApp.LoadString(IDS_MERGE7Z_ENABLE_2).c_str());
 -                                      break;
 -                              }
 -                              SetDlgItemText(hWnd, 107, cText.Data);
 -                      }
 -                      GetDlgItemText(hWnd, 112, cPresent.Data, cPresent.Size);
 -                      GetDlgItemText(hWnd, 122, cMissing.Data, cMissing.Size);
 -                      GetDlgItemText(hWnd, 132, cOutdated.Data, cOutdated.Size);
 -                      GetDlgItemText(hWnd, 120, cNone.Data, cNone.Size);
 -                      GetDlgItemText(hWnd, 102, cPlugin.Data, cPlugin.Size);
 -                      wsprintf(cText.Data, cPlugin.Data, DllBuild_Merge7z);
 -                      SetDlgItemText(hWnd, 102, cText.Data);
 -                      SetDlgItemText
 -                      (
 -                              hWnd, 109,
 -                              (
 -                                      pThis->m_dwVer7zRecommended == pThis->m_dwVer7zInstalled
 -                              ||      pThis->m_dwVer7zRecommended == pThis->m_dwVer7zLocal
 -                              ) ? cPresent.Data : cMissing.Data
 -                      );
 -                      DWORD dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zRecommended);
 -                      SetDlgItemText(hWnd, 110, *cText.Data ? cText.Data : cNone.Data);
 -                      SetDlgItemText(hWnd, 111, cPlugin.Data);
 -                      SetDlgItemText(hWnd, 112, *cPlugin.Data == '\0' ? cPlugin.Data :
 -                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);
 -                      dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zInstalled);
 -                      SetDlgItemText(hWnd, 120, *cText.Data ? cText.Data : cNone.Data);
 -                      SetDlgItemText(hWnd, 121, cPlugin.Data);
 -                      SetDlgItemText(hWnd, 122, *cPlugin.Data == '\0' ? cPlugin.Data :
 -                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);
 -                      dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zLocal);
 -                      SetDlgItemText(hWnd, 130, *cText.Data ? cText.Data : cNone.Data);
 -                      SetDlgItemText(hWnd, 131, cPlugin.Data);
 -                      SetDlgItemText(hWnd, 132, *cPlugin.Data == '\0' ? cPlugin.Data :
 -                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);
 -                      GetModuleFileName(0, cText.Data, MAX_PATH);
 -                      PathRemoveFileSpec(cText.Data);
 -                      PathAppend(cText.Data, _T("Merge7z*.dll"));
 -                      DlgDirListDLLs(hWnd, cText.Data, 105);
 -                      if (DWORD cchPath = GetEnvironmentVariable(_T("path"), 0, 0))
 -                      {
 -                              static const TCHAR cSep[] = _T(";");
 -                              LPTSTR pchPath = new TCHAR[cchPath];
 -                              GetEnvironmentVariable(_T("PATH"), pchPath, cchPath);
 -                              LPTSTR pchItem = pchPath;
 -                              while (int cchItem = StrCSpn(pchItem += StrSpn(pchItem, cSep), cSep))
 -                              {
 -                                      if (cchItem < MAX_PATH)
 -                                      {
 -                                              CopyMemory(cText.Data, pchItem, cchItem*sizeof*pchItem);
 -                                              cText.Data[cchItem] = 0;
 -                                              PathAppend(cText.Data, _T("Merge7z*.dll"));
 -                                              DlgDirListDLLs(hWnd, cText.Data, 105);
 -                                      }
 -                                      pchItem += cchItem;
 -                              }
 -                              delete[] pchPath;
 -                      }
 -                      if (SendDlgItemMessage(hWnd, 105, LB_GETCOUNT, 0, 0) == 0)
 -                      {
 -                              SendDlgItemMessage(hWnd, 105, LB_ADDSTRING, 0, (LPARAM) cNone.Data);
 -                      }
 -                      HICON hIcon = LoadIcon(0, IDI_EXCLAMATION);
 -                      SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
 -                      SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
 -                      if (pThis->m_bShowAllways)
 -                      {
 -                              ShowWindow(GetDlgItem(hWnd, 106), SW_HIDE);
 -                      }
 -              } return TRUE;
 -              case WM_DRAWITEM:
 -              {
 -                      switch (wParam)
 -                      {
 -                      case 108:
 -                              CDrawItemStruct::From(lParam)->DrawWebLinkButton();
 -                              break;
 -                      }
 -              } return TRUE;
 -              case WM_SETCURSOR:
 -              {
 -                      HCURSOR hCursor = 0;
 -                      switch (GetDlgCtrlID((HWND)wParam))
 -                      {
 -                      case 108:
 -                              hCursor = CommCtrl_LoadCursor(MAKEINTRESOURCE(108));
 -                              break;
 -                      }
 -                      if (hCursor)
 -                      {
 -                              SetCursor(hCursor);
 -                              SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1);
 -                              return TRUE;
 -                      }
 -              } return FALSE;
 -              case WM_COMMAND:
 -              {
 -                      switch (wParam)
 -                      {
 -                              case IDOK:
 -                              case IDCANCEL:
 -                              {
 -                                      LRESULT nDontShowAgain = SendDlgItemMessage(hWnd, 106, BM_GETCHECK, 0, 0);
 -                                      EndDialog(hWnd, MAKEWORD(IDOK, nDontShowAgain));
 -                              } break;
 -                              case 108:
 -                              {
 -                                      HINSTANCE h = ShellExecute(hWnd, _T("open"), m_strDownloadURL, 0, 0, SW_SHOWNORMAL);
 -                                      if ((UINT)h > 32)
 -                                      {
 -                                              LONG lStyle = ::GetWindowLong((HWND)lParam, GWL_STYLE);
 -                                              ::SetWindowLong((HWND)lParam, GWL_STYLE, lStyle|BS_LEFTTEXT);
 -                                              ::InvalidateRect((HWND)lParam, 0, TRUE);
 -                                      }
 -                                      else
 -                                      {
 -                                              MessageBeep(0);
 -                                      }
 -                              } break;
 -                      }
 -              } return TRUE;
 -      }
 -      return FALSE;
 -}
 -
 -/**
 - * @brief Tell user what went wrong and how she can help.
 - */
 -int C7ZipMismatchException::ReportError(UINT nType, UINT nMessageID)
 -{
 -      UINT_PTR response = -1;
 -      m_bShowAllways = nMessageID;
 -      if (!m_bShowAllways)
 -      {
 -              // Suppress error message in case 7-Zip is not installed.
 -              response =
 -              (
 -                      m_dwVer7zInstalled || m_dwVer7zLocal
 -              ?       theApp.GetProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, -1)
 -              :       IDOK
 -              );
 -      }
 -      if (response == -1)
 -      {
 -              HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();
 -              response = DialogBoxParam(AfxGetResourceHandle(), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);
 -              if (response == -1)
 -              {
 -                      response = DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);
 -                      ASSERT(response != -1);
 -              }
 -              if (HIBYTE(response) == 1)
 -              {
 -                      theApp.WriteProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, response = int LOBYTE(response));
 -              }
 -      }
 -      return response;
 -}
 -
 -/**
 - * @brief Check whether archive support is available.
 - */
 -int NTAPI HasZipSupport()
 -{
 -      static int HasZipSupport = -1;
 -      if (HasZipSupport == -1)
 -      {
 -              try
 -              {
 -                      m_Merge7z.operator->();
 -                      HasZipSupport = 1;
 -              }
 -              catch (CException *e)
 -              {
 -                      e->Delete();
 -                      HasZipSupport = 0;
 -              }
 -      }
 -      return HasZipSupport;
 -}
 -
 -/**
 - * @brief Tell user why archive support is not available.
 - */
 -void NTAPI Recall7ZipMismatchError()
 -{
 -      try
 -      {
 -              m_Merge7z.operator->();
 -      }
 -      catch (CException *e)
 -      {
 -              e->ReportError(MB_ICONEXCLAMATION, TRUE);
 -              e->Delete();
 -      }
 -}
 -
 -/**
 - * @brief Delete head of temp path context list, and return its parent context.
 - */
 -CTempPathContext *CTempPathContext::DeleteHead()
 -{
 -      CTempPathContext *pParent = m_pParent;
 -      delete this;
 -      return pParent;
 -}
 -
 -BOOL NTAPI IsMerge7zEnabled()
 -{
 -      return AfxGetApp()->GetProfileInt(_T("Merge7z"), _T("Enable"), 0);
 -}
 -
 -/**
 - * @brief Return installed or local version of 7-Zip.
 - */
 -DWORD NTAPI VersionOf7z(BOOL bLocal)
 -{
 -      TCHAR path[MAX_PATH];
 -      if (bLocal)
 -      {
 -              GetModuleFileName(0, path, sizeof path/sizeof*path);
 -              PathRemoveFileSpec(path);
 -      }
 -      else
 -      {
 -              static const TCHAR szSubKey[] = _T("Software\\7-Zip");
 -              static const TCHAR szValue[] = _T("Path");
 -              DWORD type = 0;
 -              DWORD size = sizeof path;
 -              SHGetValue(HKEY_LOCAL_MACHINE, szSubKey, szValue, &type, path, &size);
 -      }
 -      PathAppend(path, _T("7z.dll"));
 -      unsigned versionMS = 0;
 -      unsigned versionLS = 0;
 -      CVersionInfo(path).GetFixedFileVersion(versionMS, versionLS);
 -      return versionMS;
 -}
 -
 -/**
 - * @brief Access dll functions through proxy.
 - */
 -interface Merge7z *Merge7z::Proxy::operator->()
 -{
 -      // As long as the Merge7z*.DLL has not yet been loaded, Merge7z
 -      // [0] points to the name of the DLL (with placeholders for 7-
 -      // Zip major and minor version numbers). Once the DLL has been
 -      // loaded successfully, Merge7z[0] is set to NULL, causing the
 -      // if to fail on subsequent calls.
 -
 -      if (const char *format = Merge7z[0])
 -      {
 -              // Merge7z has not yet been loaded
 -
 -              char name[MAX_PATH];
 -              DWORD flags = ~0;
 -              CException *pCause = NULL;
 -              switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))
 -              {
 -              case 1: //Use installed 7-Zip if present. Otherwise, use local 7-Zip.
 -                      if (DWORD ver = VersionOf7z(FALSE))
 -                      {
 -                              flags = Initialize::Default;
 -                              try
 -                              {
 -                                      wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));
 -                                      Merge7z[0] = name;
 -                                      stub.Load();
 -                                      break;
 -                              }
 -                              catch (CException *e)
 -                              {
 -                                      Merge7z[0] = format;
 -                                      pCause = e;
 -                              }
 -                      }
 -              case 2: //Always use local 7-Zip.
 -                      if (DWORD ver = VersionOf7z(TRUE))
 -                      {
 -                              flags = Initialize::Default | Initialize::Local7z;
 -                              try
 -                              {
 -                                      wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));
 -                                      Merge7z[0] = name;
 -                                      stub.Load();
 -                                      break;
 -                              }
 -                              catch (CException *e)
 -                              {
 -                                      Merge7z[0] = format;
 -                                      if (pCause) pCause->Delete();
 -                                      pCause = e;
 -                              }
 -                      }
 -              default:
 -                      throw new C7ZipMismatchException
 -                      (
 -                              VersionOf7z(FALSE),
 -                              VersionOf7z(TRUE),
 -                              pCause
 -                      );
 -              }
 -              LANGID wLangID = (LANGID)GetThreadLocale();
 -              flags |= wLangID << 16;
 -              if (GetOptionsMgr()->GetBool(OPT_ARCHIVE_PROBETYPE))
 -              {
 -                      flags |= Initialize::GuessFormatBySignature | Initialize::GuessFormatByExtension;
 -              }
 -              if (Merge7z[1])
 -                      ((interface Merge7z *)Merge7z[1])->Initialize(flags);
 -      }
 -      return ((interface Merge7z *)Merge7z[1]);
 -}
 -
 -/**
 - * @brief Tell Merge7z we are going to enumerate just 1 item.
 - */
 -UINT SingleItemEnumerator::Open()
 -{
 -      return 1;
 -}
 -
 -/**
 - * @brief Pass information about the item to Merge7z.
 - */
 -Merge7z::Envelope *SingleItemEnumerator::Enum(Item &item)
 -{
 -      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.Recurse;
 -      item.Name = Name;
 -      item.FullPath = FullPath;
 -      return 0;
 -}
 -
 -/**
 - * @brief SingleFileEnumerator constructor.
 - */
 -SingleItemEnumerator::SingleItemEnumerator(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name)
 -: FullPath(FullPath)
 -, Name(Name)
 -{
 -}
 -
 -/**
 - * @brief Construct a CDirView::DirItemEnumerator.
 - *
 - * Argument *nFlags* controls operation as follows:
 - * LVNI_ALL:          Enumerate all items.
 - * LVNI_SELECTED:     Enumerate selected items only.
 - * Original:          Set folder prefix for first iteration to "original"
 - * Altered:                   Set folder prefix for second iteration to "altered"
 - * BalanceFolders:    Ensure that all nonempty folders on either side have a
 - *                                    corresponding folder on the other side, even if it is
 - *                                    empty (DirScan doesn't recurse into folders which
 - *                                    appear only on one side).
 - * DiffsOnly:         Enumerate diffs only.
 - */
 -CDirView::DirItemEnumerator::DirItemEnumerator(CDirView *pView, int nFlags)
 -: m_pView(pView)
 -, m_nFlags(nFlags)
 -{
 -      if (m_nFlags & Original)
 -      {
 -              m_rgFolderPrefix.push_back(_T("original"));
 -      }
 -      if (m_nFlags & Altered)
 -      {
 -              m_rgFolderPrefix.push_back(_T("altered"));
 -      }
 -      if (m_nFlags & BalanceFolders)
 -      {
 -              // Collect implied folders
 -              for (UINT i = Open() ; i-- ; )
 -              {
 -                      const DIFFITEM &di = Next();
 -                      if ((m_nFlags & DiffsOnly) && !m_pView->IsItemNavigableDiff(di))
 -                      {
 -                              continue;
 -                      }
 -                      if (m_bRight) 
 -                      {
 -                              // Enumerating items on right side
 -                              if (!di.diffcode.isSideFirstOnly())
 -                              {
 -                                      // Item is present on right side, i.e. folder is implied
 -                                      m_rgImpliedFoldersRight[di.diffFileInfo[1].path.get()] = PVOID(1);
 -                              }
 -                      }
 -                      else
 -                      {
 -                              // Enumerating items on left side
 -                              if (!di.diffcode.isSideSecondOnly())
 -                              {
 -                                      // Item is present on left side, i.e. folder is implied
 -                                      m_rgImpliedFoldersLeft[di.diffFileInfo[0].path.get()] = PVOID(1);
 -                              }
 -                      }
 -              }
 -      }
 -}
 -
 -/**
 - * @brief Initialize enumerator, return number of items to be enumerated.
 - */
 -UINT CDirView::DirItemEnumerator::Open()
 -{
 -      m_nIndex = -1;
 -      m_curFolderPrefix = m_rgFolderPrefix.begin();
 -      m_bRight = (m_nFlags & Right) != 0;
 -      size_t nrgFolderPrefix = m_rgFolderPrefix.size();
 -      if (nrgFolderPrefix)
 -      {
 -              m_strFolderPrefix = *m_curFolderPrefix++;
 -      }
 -      else
 -      {
 -              nrgFolderPrefix = 1;
 -      }
 -      return
 -      (
 -              m_nFlags & LVNI_SELECTED
 -      ?       pView(m_pView)->GetSelectedCount()
 -      :       pView(m_pView)->GetItemCount()
 -      ) * nrgFolderPrefix;
 -}
 -
 -/**
 - * @brief Return next item.
 - */
 -const DIFFITEM &CDirView::DirItemEnumerator::Next()
 -{
 -      enum {nMask = LVNI_FOCUSED|LVNI_SELECTED|LVNI_CUT|LVNI_DROPHILITED};
 -      while ((m_nIndex = pView(m_pView)->GetNextItem(m_nIndex, m_nFlags & nMask)) == -1)
 -      {
 -              m_strFolderPrefix = *m_curFolderPrefix++;
 -              m_bRight = TRUE;
 -      }
 -      return m_pView->GetDiffItem(m_nIndex);
 -}
 -
 -/**
 - * @brief Pass information about an item to Merge7z.
 - *
 - * Information is passed through struct Merge7z::DirItemEnumerator::Item.
 - * The *mask* member denotes which of the other members contain valid data.
 - * If *mask* is zero upon return, which will be the case if Enum() decides to
 - * leave the struct untouched, Merge7z will ignore the item.
 - * If Enum() allocates temporary storage for string members, it must also
 - * allocate an Envelope, providing a Free() method to free the temporary
 - * storage, along with the Envelope itself. The Envelope pointer is passed to
 - * Merge7z as the return value of the function. It is not meant to be a success
 - * indicator, so if no temporary storage is required, it is perfectly alright
 - * to return NULL.
 - */
 -Merge7z::Envelope *CDirView::DirItemEnumerator::Enum(Item &item)
 -{
 -      CDirDoc * pDoc = m_pView->GetDocument();
 -      const DIFFITEM &di = Next();
 -
 -      if ((m_nFlags & DiffsOnly) && !m_pView->IsItemNavigableDiff(di))
 -      {
 -              return 0;
 -      }
 -
 -      bool isSideFirst = di.diffcode.isSideFirstOnly();
 -      bool isSideSecond = di.diffcode.isSideSecondOnly();
 -
 -      Envelope *envelope = new Envelope;
 -
 -      const String &sFilename = m_bRight ? di.diffFileInfo[1].filename : di.diffFileInfo[0].filename;
 -      const String &sSubdir = m_bRight ? di.diffFileInfo[1].path : di.diffFileInfo[0].path;
 -      envelope->Name = sFilename;
 -      if (sSubdir.length())
 -      {
 -              envelope->Name.insert(0, _T("\\"));
 -              envelope->Name.insert(0, sSubdir);
 -      }
 -      envelope->FullPath = sFilename;
 -      envelope->FullPath.insert(0, _T("\\"));
 -      envelope->FullPath.insert(0, m_bRight ?
 -      di.getFilepath(1, pDoc->GetBasePath(1)) :
 -      di.getFilepath(0, pDoc->GetBasePath(0)));
 -
 -      UINT32 Recurse = item.Mask.Recurse;
 -
 -      if (m_nFlags & BalanceFolders)
 -      {
 -              if (m_bRight)
 -              {
 -                      // Enumerating items on right side
 -                      if (isSideFirst)
 -                      {
 -                              // Item is missing on right side
 -                              PVOID &implied = m_rgImpliedFoldersRight[di.diffFileInfo[0].path.get()];
 -                              if (!implied)
 -                              {
 -                                      // Folder is not implied by some other file, and has
 -                                      // not been enumerated so far, so enumerate it now!
 -                                      envelope->Name = di.diffFileInfo[0].path;
 -                                      envelope->FullPath = di.getFilepath(0, pDoc->GetBasePath(0));
 -                                      implied = PVOID(2); // Don't enumerate same folder twice!
 -                                      isSideFirst = false;
 -                                      Recurse = 0;
 -                              }
 -                      }
 -              }
 -              else
 -              {
 -                      // Enumerating items on left side
 -                      if (isSideSecond)
 -                      {
 -                              // Item is missing on left side
 -                              PVOID &implied = m_rgImpliedFoldersLeft[di.diffFileInfo[1].path.get()];
 -                              if (!implied)
 -                              {
 -                                      // Folder is not implied by some other file, and has
 -                                      // not been enumerated so far, so enumerate it now!
 -                                      envelope->Name = di.diffFileInfo[1].path;
 -                                      envelope->FullPath = di.getFilepath(1, pDoc->GetBasePath(1));
 -                                      implied = PVOID(2); // Don't enumerate same folder twice!
 -                                      isSideSecond = false;
 -                                      Recurse = 0;
 -                              }
 -                      }
 -              }
 -      }
 -
 -      if (m_bRight ? isSideFirst : isSideSecond)
 -      {
 -              return envelope;
 -      }
 -
 -      if (m_strFolderPrefix.length())
 -      {
 -              if (envelope->Name.length())
 -                      envelope->Name.insert(0, _T("\\"));
 -              envelope->Name.insert(0, m_strFolderPrefix);
 -      }
 -
 -      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.CheckIfPresent|Recurse;
 -      item.Name = envelope->Name.c_str();
 -      item.FullPath = envelope->FullPath.c_str();
 -      return envelope;
 -}
 -
 -/**
 - * @brief Apply appropriate handlers from left to right.
 - */
 -bool CDirView::DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path)
 -{
 -      DeleteFile(path);
 -      Merge7z::Format *piHandler = ArchiveGuessFormat(path);
 -      if (piHandler)
 -      {
 -              HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();
 -              CString pathIntermediate;
 -              SysFreeString(Assign(pathIntermediate, piHandler->GetDefaultName(hwndOwner, path)));
 -              String pathPrepend = path;
 -              pathPrepend.resize(pathPrepend.rfind('\\') + 1);
 -              pathIntermediate.Insert(0, pathPrepend.c_str());
 -              bool bDone = MultiStepCompressArchive(pathIntermediate);
 -              if (bDone)
 -              {
 -                      piHandler->CompressArchive(hwndOwner, path,
 -                              &SingleItemEnumerator(path, pathIntermediate));
 -                      DeleteFile(pathIntermediate);
 -              }
 -              else
 -              {
 -                      piHandler->CompressArchive(hwndOwner, path, this);
 -              }
 -              return true;
 -      }
 -      return false;
 -}
 -
 -/**
 - * @brief Generate archive from DirView items.
 - */
 -void CDirView::DirItemEnumerator::CompressArchive(LPCTSTR path)
 -{
 -      String strPath;
 -      if (path == 0)
 -      {
 -              // No path given, so prompt for path!
 -              static const TCHAR _T_Merge7z[] = _T("Merge7z");
 -              static const TCHAR _T_FilterIndex[] = _T("FilterIndex");
 -              // 7z311 can only write 7z, zip, and tar(.gz|.bz2) archives, so don't
 -              // offer other formats here!
 -              static const TCHAR _T_Filter[]
 -              (
 -                      _T("7z|*.7z|")
 -                      //_T("z|*.z|")
 -                      _T("zip|*.zip|")
 -                      _T("jar (zip)|*.jar|")
 -                      _T("ear (zip)|*.ear|")
 -                      _T("war (zip)|*.war|")
 -                      _T("xpi (zip)|*.xpi|")
 -                      //_T("rar|*.rar|")
 -                      _T("tar|*.tar|")
 -                      _T("tar.z|*.tar.z|")
 -                      _T("tar.gz|*.tar.gz|")
 -                      _T("tar.bz2|*.tar.bz2|")
 -                      //_T("tz|*.tz|")
 -                      _T("tgz|*.tgz|")
 -                      _T("tbz2|*.tbz2|")
 -                      //_T("lzh|*.lzh|")
 -                      //_T("cab|*.cab|")
 -                      //_T("arj|*.arj|")
 -                      //_T("deb|*.deb|")
 -                      //_T("rpm|*.rpm|")
 -                      //_T("cpio|*.cpio|")
 -                      //_T("|")
 -              );
 -              String strFilter; // = CExternalArchiveFormat::GetOpenFileFilterString();
 -              strFilter.insert(0, _T_Filter);
 -              strFilter += _T("|");
 -              CFileDialog dlg
 -              (
 -                      FALSE,
 -                      0,
 -                      0,
 -                      OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN,
 -                      strFilter.c_str()
 -              );
 -              dlg.m_ofn.nFilterIndex = AfxGetApp()->GetProfileInt(_T_Merge7z, _T_FilterIndex, 1);
 -              // Use extension from current filter as default extension:
 -              if (int i = dlg.m_ofn.nFilterIndex)
 -              {
 -                      dlg.m_ofn.lpstrDefExt = dlg.m_ofn.lpstrFilter;
 -                      while (*dlg.m_ofn.lpstrDefExt && --i)
 -                      {
 -                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;
 -                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;
 -                      }
 -                      if (*dlg.m_ofn.lpstrDefExt)
 -                      {
 -                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 3;
 -                      }
 -              }
 -              if (dlg.DoModal() == IDOK)
 -              {
 -                      strPath = dlg.GetPathName();
 -                      path = strPath.c_str();
 -                      AfxGetApp()->WriteProfileInt(_T_Merge7z, _T_FilterIndex, dlg.m_ofn.nFilterIndex);
 -              }
 -      }
 -      if (path && !MultiStepCompressArchive(path))
 -      {
 -              LangMessageBox(IDS_UNKNOWN_ARCHIVE_FORMAT, MB_ICONEXCLAMATION);
 -      }
 -}
 -
 -/**
 - * @brief Collect files for SHFileOperation
 - */
 -void CDirView::DirItemEnumerator::CollectFiles(String &strBuffer)
 -{
 -      CDirDoc *pDoc = m_pView->GetDocument();
 -      const String sLeftRootPath = pDoc->GetBasePath(0);
 -      const String sRightRootPath = pDoc->GetBasePath(1);
 -      UINT i;
 -      int cchBuffer = 0;
 -      for (i = Open() ; i-- ; )
 -      {
 -              const DIFFITEM &di = Next();
 -              if (m_bRight ? m_pView->IsItemOpenableOnRightWith(di) : m_pView->IsItemOpenableOnLeftWith(di))
 -              {
 -                      cchBuffer +=
 -                      (
 -                              m_bRight ? di.getFilepath(1, sLeftRootPath) : di.getFilepath(0, sRightRootPath)
 -                      ).length() + (m_bRight ? di.diffFileInfo[1].filename : di.diffFileInfo[0].filename).get().length() + 2;
 -              }
 -      }
 -      strBuffer.resize(cchBuffer + 1);
 -      LPTSTR pchBuffer = &strBuffer[0];
 -      for (i = Open() ; i-- ; )
 -      {
 -              const DIFFITEM &di = Next();
 -              if (m_bRight ? m_pView->IsItemOpenableOnRightWith(di) : m_pView->IsItemOpenableOnLeftWith(di))
 -              {
 -                      pchBuffer += wsprintf
 -                      (
 -                              pchBuffer,
 -                              _T("%s\\%s"),
 -                              m_bRight ? di.getFilepath(1, sLeftRootPath).c_str() : di.getFilepath(0, sRightRootPath).c_str(),
 -                              m_bRight ? di.diffFileInfo[1].filename.get().c_str() : di.diffFileInfo[0].filename.get().c_str()
 -                      ) + 1;
 -              }
 -      }
 -      ASSERT(pchBuffer - &strBuffer[0] == cchBuffer);
 -}
 +/////////////////////////////////////////////////////////////////////////////\r
 +//    WinMerge:  an interactive diff/merge utility\r
 +//    Copyright (C) 1997-2000  Thingamahoochie Software\r
 +//    Author: Dean Grimm\r
 +//\r
 +//    This program is free software; you can redistribute it and/or modify\r
 +//    it under the terms of the GNU General Public License as published by\r
 +//    the Free Software Foundation; either version 2 of the License, or\r
 +//    (at your option) any later version.\r
 +//\r
 +//    This program is distributed in the hope that it will be useful,\r
 +//    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
 +//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
 +//    GNU General Public License for more details.\r
 +//\r
 +//    You should have received a copy of the GNU General Public License\r
 +//    along with this program; if not, write to the Free Software\r
 +//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
 +//\r
 +/////////////////////////////////////////////////////////////////////////////\r
 +\r
 +/* 7zCommon.cpp: Implement 7z related classes and functions\r
 + * Copyright (c) 2003 Jochen Tucht\r
 + *\r
 + * Remarks:   Different versions of 7-Zip are interfaced through specific\r
 + *                    versions of Merge7z (Merge7z311.dll, Merge7z312.dll, etc.)\r
 + *                    WinMerge can either use an installed copy of the 7-Zip software,\r
 + *                    or fallback to a local set of 7-Zip DLLs, which are to be included\r
 + *                    in the WinMerge binary distribution.\r
 + *\r
 + *                    Fallback policies are as follows:\r
 + *\r
 + *                    1. Detect 7-Zip version installed (XXX).\r
 + *                    2. If there is a Merge7zXXX.dll, be happy to use it\r
 + *                    3. Detect 7-Zip version from WinMerge distribution (YYY).\r
 + *                    4. If there is a Merge7zYYY.dll, be happy to use it.\r
 + *                    5. Sorry, no way.\r
 + *\r
 + *                    These rules can be customized by setting a registry variable\r
 + *                    *Merge7z/Enable* of type DWORD to one of the following values:\r
 + *\r
 + *                    0 - Entirely disable 7-Zip integration.\r
 + *                    1 - Use installed 7-Zip if present. Otherwise, use local 7-Zip.\r
 + *                    2 - Always use local 7-Zip.\r
 + *\r
 +\r
 +Please mind 2. a) of the GNU General Public License, and log your changes below.\r
 +\r
 +DATE:         BY:                                     DESCRIPTION:\r
 +==========    ==================      ================================================\r
 +2003-12-09    Jochen Tucht            Created\r
 +2003-12-16    Jochen Tucht            Properly generate .tar.gz and .tar.bz2\r
 +2003-12-16    Jochen Tucht            Obtain long path to temporary folder\r
 +2004-01-20    Jochen Tucht            Complain only once if Merge7z*.dll is missing\r
 +2004-01-25    Jochen Tucht            Fix bad default for OPENFILENAME::nFilterIndex\r
 +2004-03-15    Jochen Tucht            Fix Visual Studio 2003 build issue\r
 +2004-04-13    Jochen Tucht            Avoid StrNCat to get away with shlwapi 4.70\r
 +2004-08-25    Jochen Tucht            More explicit error message\r
 +2004-10-17    Jochen Tucht            Leave decision whether to recurse into folders\r
 +                                                              to enumerator (Mask.Recurse)\r
 +2004-11-03    Jochen Tucht            FIX [1048997] as proposed by Kimmo 2004-11-02\r
 +2005-01-15    Jochen Tucht            Read 7-Zip version from 7zip_pad.xml\r
 +                                                              Set Merge7z UI language if DllBuild_Merge7z >= 9\r
 +2005-01-22    Jochen Tucht            Better explain what's present/missing/outdated\r
 +2005-02-05    Jochen Tucht            Fall back to IDD_MERGE7ZMISMATCH template from\r
 +                                                              .exe if .lang file isn't up to date.\r
 +2005-02-26    Jochen Tucht            Add download link to error message\r
 +2005-02-26    Jochen Tucht            Use WinAPI to obtain ISO language/region codes\r
 +2005-02-27    Jochen Tucht            FIX [1152375]\r
 +2005-04-24    Kimmo Varis                     Don't use DiffContext exported from DirView\r
 +2005-06-08    Kimmo Varis                     Use DIFFITEM, not reference to it (hopefully only\r
 +                                                              temporarily, to sort out new directory compare)\r
 +2005-06-22    Jochen Tucht            Change recommended version of 7-Zip to 4.20\r
 +                                                              Remove noise from Nagbox\r
 +2005-07-03    Jochen Tucht            DIFFITEM has changed due to RFE [ 1205516 ]\r
 +2005-07-04    Jochen Tucht            New global ArchiveGuessFormat() checks for\r
 +                                                              formats to be handled by external command line\r
 +                                                              tools. These take precedence over Merge7z\r
 +                                                              internal handlers.\r
 +2005-07-05    Jochen Tucht            Move to Merge7z::Format::GetDefaultName() to\r
 +                                                              build intermediate filenames for multi-step\r
 +                                                              compression.\r
 +2005-07-15    Jochen Tucht            Remove external command line tool integration\r
 +                                                              for now. Rethink about it after 2.4 branch.\r
 +2005-08-20    Jochen Tucht            Option to guess archive format by signature\r
 +                                                              Map extensions through ExternalArchiveFormat.ini\r
 +2005-08-23    Jochen Tucht            Option to entirely disable 7-Zip integration\r
 +2007-01-04    Kimmo Varis                     Convert using COptionsMgr for options.\r
 +2007-06-16    Jochen Neubeck          FIX [1723263] "Zip --> Both" operation...\r
 +2007-12-22    Jochen Neubeck          Fix Merge7z UI lang for new translation system\r
 +                                                              Change recommended version of 7-Zip to 4.57\r
 +2010-05-16    Jochen Neubeck          Read 7-Zip version from 7z.dll (which has long\r
 +                                                              ago replaced the various format and codec DLLs)\r
 +                                                              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 "DirDoc.h"\r
- #include "MainFrm.h"\r
 +#include "DirView.h"\r
- #include "7zCommon.h"\r
++#include "DirDoc.h"\r
 +#include "DirActions.h"\r
 +//#include "ExternalArchiveFormat.h"\r
 +#include "version.h"\r
- #include <afxinet.h>\r
- #include <shlwapi.h>\r
- #include <paths.h>\r
++#include "paths.h"\r
 +#include "Environment.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
 + * @brief Proxy for Merge7z\r
 + */\r
 +static __declspec(thread) Merge7z::Proxy m_Merge7z =\r
 +{\r
 +      { 0, 0, DllBuild_Merge7z, },\r
 +      "Merge7z%u%02u"DECORATE_U".dll",\r
 +      "Merge7z",\r
 +      NULL\r
 +};\r
 +\r
 +/**\r
 + * @brief assign BSTR to String, and return BSTR for optional SysFreeString()\r
 + */\r
 +inline BSTR Assign(CString &dst, BSTR src)\r
 +{\r
 +      dst = src;\r
 +      return src;\r
 +}\r
 +\r
 +bool IsArchiveFile(const String& pszFile)\r
 +{\r
 +      try {\r
 +              Merge7z::Format *piHandler = ArchiveGuessFormat(pszFile);\r
 +              if (piHandler)\r
 +                      return TRUE;\r
 +              else\r
 +                      return FALSE;\r
 +      }\r
 +      catch (CException *e)\r
 +      {\r
 +              e->Delete();\r
 +              return FALSE;\r
 +      }\r
 +      return FALSE;\r
 +}\r
 +\r
 +/**\r
 + * @brief Wrap Merge7z::GuessFormat() to allow for some customizing:\r
 + * - Check if 7-Zip integration is enabled.\r
 + * - Check for filename extension mappings.\r
 + */\r
 +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
 +      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
 +      TCHAR value[20];\r
 +      static LPCTSTR filename = NULL;\r
 +      if (filename == NULL)\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
 +      }\r
 +      if (*filename &&\r
 +              GetPrivateProfileString(section, entry.c_str(), null, value, 20, filename) &&\r
 +              *value == '.')\r
 +      {\r
 +              // Remove end-of-line comments (in string returned from GetPrivateProfileString)\r
 +              // that is, remove semicolon & whatever follows it\r
 +              if (LPTSTR p = StrChr(value, ';'))\r
 +              {\r
 +                      *p = '\0';\r
 +                      StrTrim(value, _T(" \t"));\r
 +              }\r
 +              path2 = value;\r
 +      }\r
 +\r
 +      // PATCH [ 1229867 ] RFE [ 1205516 ], RFE [ 887948 ], and other issues\r
 +      // command line integration portion is not yet applied\r
 +      // so following code not yet valid, so temporarily commented out\r
 +      // Look for command line tool first\r
 +      /*Merge7z::Format *pFormat;\r
 +      if (CExternalArchiveFormat::GuessFormat(path, pFormat))\r
 +      {\r
 +              return pFormat;\r
 +      }*/\r
 +      // Default to Merge7z*.dll\r
 +\r
 +      return m_Merge7z->GuessFormat(path2.c_str());\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
 +              ?       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
 +{\r
 +      static int HasZipSupport = -1;\r
 +      if (HasZipSupport == -1)\r
 +      {\r
 +              try\r
 +              {\r
 +                      m_Merge7z.operator->();\r
 +                      HasZipSupport = 1;\r
 +              }\r
 +              catch (CException *e)\r
 +              {\r
 +                      e->Delete();\r
 +                      HasZipSupport = 0;\r
 +              }\r
 +      }\r
 +      return HasZipSupport;\r
 +}\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
 +{\r
 +      CTempPathContext *pParent = m_pParent;\r
 +      delete this;\r
 +      return pParent;\r
 +}\r
 +\r
 +BOOL NTAPI IsMerge7zEnabled()\r
 +{\r
 +      return AfxGetApp()->GetProfileInt(_T("Merge7z"), _T("Enable"), 0);\r
 +}\r
 +\r
 +/**\r
 + * @brief Return installed or local version of 7-Zip.\r
 + */\r
 +DWORD NTAPI VersionOf7z(BOOL bLocal)\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
 +      unsigned versionMS = 0;\r
 +      unsigned versionLS = 0;\r
 +      CVersionInfo(path).GetFixedFileVersion(versionMS, versionLS);\r
 +      return versionMS;\r
 +}\r
 +\r
 +/**\r
 + * @brief Access dll functions through proxy.\r
 + */\r
 +interface Merge7z *Merge7z::Proxy::operator->()\r
 +{\r
 +      // 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
 +      // 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
 +              {\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
 +              }\r
 +              LANGID wLangID = (LANGID)GetThreadLocale();\r
 +              flags |= wLangID << 16;\r
 +              if (GetOptionsMgr()->GetBool(OPT_ARCHIVE_PROBETYPE))\r
 +              {\r
 +                      flags |= Initialize::GuessFormatBySignature | Initialize::GuessFormatByExtension;\r
 +              }\r
 +              if (Merge7z[1])\r
 +                      ((interface Merge7z *)Merge7z[1])->Initialize(flags);\r
 +      }\r
 +      return ((interface Merge7z *)Merge7z[1]);\r
 +}\r
 +\r
 +/**\r
 + * @brief Tell Merge7z we are going to enumerate just 1 item.\r
 + */\r
 +UINT SingleItemEnumerator::Open()\r
 +{\r
 +      return 1;\r
 +}\r
 +\r
 +/**\r
 + * @brief Pass information about the item to Merge7z.\r
 + */\r
 +Merge7z::Envelope *SingleItemEnumerator::Enum(Item &item)\r
 +{\r
 +      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.Recurse;\r
 +      item.Name = Name;\r
 +      item.FullPath = FullPath;\r
 +      return 0;\r
 +}\r
 +\r
 +/**\r
 + * @brief SingleFileEnumerator constructor.\r
 + */\r
 +SingleItemEnumerator::SingleItemEnumerator(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name)\r
 +: FullPath(FullPath)\r
 +, Name(Name)\r
 +{\r
 +}\r
 +\r
 +/**\r
 + * @brief Construct a DirItemEnumerator.\r
 + *\r
 + * Argument *nFlags* controls operation as follows:\r
 + * LVNI_ALL:          Enumerate all items.\r
 + * LVNI_SELECTED:     Enumerate selected items only.\r
 + * Original:          Set folder prefix for first iteration to "original"\r
 + * Altered:                   Set folder prefix for second iteration to "altered"\r
 + * BalanceFolders:    Ensure that all nonempty folders on either side have a\r
 + *                                    corresponding folder on the other side, even if it is\r
 + *                                    empty (DirScan doesn't recurse into folders which\r
 + *                                    appear only on one side).\r
 + * DiffsOnly:         Enumerate diffs only.\r
 + */\r
 +DirItemEnumerator::DirItemEnumerator(CDirView *pView, int nFlags)\r
 +: m_pView(pView)\r
 +, m_nFlags(nFlags)\r
 +{\r
 +      if (m_nFlags & Original)\r
 +      {\r
 +              m_rgFolderPrefix.push_back(_T("original"));\r
 +      }\r
 +      if (m_nFlags & Altered)\r
 +      {\r
 +              m_rgFolderPrefix.push_back(_T("altered"));\r
 +      }\r
 +      if (m_nFlags & BalanceFolders)\r
 +      {\r
 +              const CDiffContext& ctxt = pView->GetDiffContext();\r
 +              // Collect implied folders\r
 +              for (UINT i = Open() ; i-- ; )\r
 +              {\r
 +                      const DIFFITEM &di = Next();\r
 +                      if ((m_nFlags & DiffsOnly) && !IsItemNavigableDiff(ctxt, di))\r
 +                      {\r
 +                              continue;\r
 +                      }\r
 +                      // Enumerating items\r
 +                      if (di.diffcode.isExists(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
 +                      }\r
 +              }\r
 +      }\r
 +}\r
 +\r
 +/**\r
 + * @brief Initialize enumerator, return number of items to be enumerated.\r
 + */\r
 +UINT DirItemEnumerator::Open()\r
 +{\r
 +      m_nIndex = -1;\r
 +      m_curFolderPrefix = m_rgFolderPrefix.begin();\r
 +      m_index = (m_nFlags & Right) != 0 ? 1 : 0;\r
 +      size_t nrgFolderPrefix = m_rgFolderPrefix.size();\r
 +      if (nrgFolderPrefix)\r
 +      {\r
 +              m_strFolderPrefix = *m_curFolderPrefix++;\r
 +      }\r
 +      else\r
 +      {\r
 +              nrgFolderPrefix = 1;\r
 +      }\r
 +      return\r
 +      (\r
 +              m_nFlags & LVNI_SELECTED\r
 +      ?       pView(m_pView)->GetSelectedCount()\r
 +      :       pView(m_pView)->GetItemCount()\r
 +      ) * nrgFolderPrefix;\r
 +}\r
 +\r
 +/**\r
 + * @brief Return next item.\r
 + */\r
 +const DIFFITEM &DirItemEnumerator::Next()\r
 +{\r
 +      enum {nMask = LVNI_FOCUSED|LVNI_SELECTED|LVNI_CUT|LVNI_DROPHILITED};\r
 +      while ((m_nIndex = pView(m_pView)->GetNextItem(m_nIndex, m_nFlags & nMask)) == -1)\r
 +      {\r
 +              m_strFolderPrefix = *m_curFolderPrefix++;\r
 +              m_index = 1;\r
 +      }\r
 +      return m_pView->GetDiffItem(m_nIndex);\r
 +}\r
 +\r
 +/**\r
 + * @brief Pass information about an item to Merge7z.\r
 + *\r
 + * Information is passed through struct Merge7z::DirItemEnumerator::Item.\r
 + * The *mask* member denotes which of the other members contain valid data.\r
 + * If *mask* is zero upon return, which will be the case if Enum() decides to\r
 + * leave the struct untouched, Merge7z will ignore the item.\r
 + * If Enum() allocates temporary storage for string members, it must also\r
 + * allocate an Envelope, providing a Free() method to free the temporary\r
 + * 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
 + */\r
 +Merge7z::Envelope *DirItemEnumerator::Enum(Item &item)\r
 +{\r
 +      const CDiffContext& ctxt = m_pView->GetDiffContext();\r
 +      const DIFFITEM &di = Next();\r
 +\r
 +      if ((m_nFlags & DiffsOnly) && !IsItemNavigableDiff(ctxt, di))\r
 +      {\r
 +              return 0;\r
 +      }\r
 +\r
 +      bool isSideOnly = !di.diffcode.isExists(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
 +      else\r
 +              envelope->Name = sFilename;\r
 +      envelope->FullPath = paths_ConcatPath(\r
 +                      di.getFilepath(m_index, ctxt.GetNormalizedPath(m_index)),\r
 +                      sFilename);\r
 +\r
 +      UINT32 Recurse = item.Mask.Recurse;\r
 +\r
 +      if (m_nFlags & BalanceFolders)\r
 +      {\r
 +              // Enumerating items on right side\r
 +              if (isSideOnly)\r
 +              {\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
 +                      {\r
 +                              // Folder is not implied by some other file, and has\r
 +                              // not been enumerated so far, so enumerate it now!\r
 +                              envelope->Name = di.diffFileInfo[1-m_index].path;\r
 +                              envelope->FullPath = di.getFilepath(1-m_index, ctxt.GetNormalizedPath(1-m_index));\r
 +                              implied = PVOID(2); // Don't enumerate same folder twice!\r
 +                              isSideOnly = false;\r
 +                              Recurse = 0;\r
 +                      }\r
 +              }\r
 +      }\r
 +\r
 +      if (isSideOnly)\r
 +      {\r
 +              return envelope;\r
 +      }\r
 +\r
 +      if (m_strFolderPrefix.length())\r
 +      {\r
 +              if (envelope->Name.length())\r
 +                      envelope->Name.insert(0, _T("\\"));\r
 +              envelope->Name.insert(0, m_strFolderPrefix);\r
 +      }\r
 +\r
 +      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.CheckIfPresent|Recurse;\r
 +      item.Name = envelope->Name.c_str();\r
 +      item.FullPath = envelope->FullPath.c_str();\r
 +      return envelope;\r
 +}\r
 +\r
 +/**\r
 + * @brief Apply appropriate handlers from left to right.\r
 + */\r
 +bool DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path)\r
 +{\r
 +      DeleteFile(path);\r
 +      Merge7z::Format *piHandler = ArchiveGuessFormat(path);\r
 +      if (piHandler)\r
 +      {\r
 +              HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();\r
 +              CString pathIntermediate;\r
 +              SysFreeString(Assign(pathIntermediate, piHandler->GetDefaultName(hwndOwner, path)));\r
 +              String pathPrepend = path;\r
 +              pathPrepend.resize(pathPrepend.rfind('\\') + 1);\r
 +              pathIntermediate.Insert(0, pathPrepend.c_str());\r
 +              bool bDone = MultiStepCompressArchive(pathIntermediate);\r
 +              if (bDone)\r
 +              {\r
 +                      piHandler->CompressArchive(hwndOwner, path,\r
 +                              &SingleItemEnumerator(path, pathIntermediate));\r
 +                      DeleteFile(pathIntermediate);\r
 +              }\r
 +              else\r
 +              {\r
 +                      piHandler->CompressArchive(hwndOwner, path, this);\r
 +              }\r
 +              return true;\r
 +      }\r
 +      return false;\r
 +}\r
 +\r
 +/**\r
 + * @brief Generate archive from DirView items.\r
 + */\r
 +void DirItemEnumerator::CompressArchive(LPCTSTR path)\r
 +{\r
 +      String strPath;\r
 +      if (path == 0)\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
 +              (\r
 +                      _T("7z|*.7z|")\r
 +                      //_T("z|*.z|")\r
 +                      _T("zip|*.zip|")\r
 +                      _T("jar (zip)|*.jar|")\r
 +                      _T("ear (zip)|*.ear|")\r
 +                      _T("war (zip)|*.war|")\r
 +                      _T("xpi (zip)|*.xpi|")\r
 +                      //_T("rar|*.rar|")\r
 +                      _T("tar|*.tar|")\r
 +                      _T("tar.z|*.tar.z|")\r
 +                      _T("tar.gz|*.tar.gz|")\r
 +                      _T("tar.bz2|*.tar.bz2|")\r
 +                      //_T("tz|*.tz|")\r
 +                      _T("tgz|*.tgz|")\r
 +                      _T("tbz2|*.tbz2|")\r
 +                      //_T("lzh|*.lzh|")\r
 +                      //_T("cab|*.cab|")\r
 +                      //_T("arj|*.arj|")\r
 +                      //_T("deb|*.deb|")\r
 +                      //_T("rpm|*.rpm|")\r
 +                      //_T("cpio|*.cpio|")\r
 +                      //_T("|")\r
 +              );\r
 +              String strFilter; // = CExternalArchiveFormat::GetOpenFileFilterString();\r
 +              strFilter.insert(0, _T_Filter);\r
 +              strFilter += _T("|");\r
 +              CFileDialog dlg\r
 +              (\r
 +                      FALSE,\r
 +                      0,\r
 +                      0,\r
 +                      OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN,\r
 +                      strFilter.c_str()\r
 +              );\r
 +              dlg.m_ofn.nFilterIndex = AfxGetApp()->GetProfileInt(_T_Merge7z, _T_FilterIndex, 1);\r
 +              // Use extension from current filter as default extension:\r
 +              if (int i = dlg.m_ofn.nFilterIndex)\r
 +              {\r
 +                      dlg.m_ofn.lpstrDefExt = dlg.m_ofn.lpstrFilter;\r
 +                      while (*dlg.m_ofn.lpstrDefExt && --i)\r
 +                      {\r
 +                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;\r
 +                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;\r
 +                      }\r
 +                      if (*dlg.m_ofn.lpstrDefExt)\r
 +                      {\r
 +                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 3;\r
 +                      }\r
 +              }\r
 +              if (dlg.DoModal() == IDOK)\r
 +              {\r
 +                      strPath = dlg.GetPathName();\r
 +                      path = strPath.c_str();\r
 +                      AfxGetApp()->WriteProfileInt(_T_Merge7z, _T_FilterIndex, dlg.m_ofn.nFilterIndex);\r
 +              }\r
 +      }\r
 +      if (path && !MultiStepCompressArchive(path))\r
 +      {\r
 +              LangMessageBox(IDS_UNKNOWN_ARCHIVE_FORMAT, MB_ICONEXCLAMATION);\r
 +      }\r
 +}\r
diff --cc Src/7zCommon.h
@@@ -2,15 -2,13 +2,15 @@@
  
  // We include dllpstub.h for Merge7z.h
  // Merge7z::Proxy embeds a DLLPSTUB
- #include "dllpstub.h"
++#include <list>
++#include <map>
 +#include <PropIdl.h>
+ #include "dllpstub.h"
  #include "../ArchiveSupport/Merge7z/Merge7z.h"
  
- #include "DiffContext.h"
 -#include "DirView.h"
--#include <list>
--
 -class DirView;
 +class CDirView;
 +class CListCtrl;
++struct DIFFITEM;
  
  extern __declspec(thread) Merge7z::Proxy Merge7z;
  
@@@ -23,9 -23,8 +23,9 @@@
  // $Id$
  
  #include "stdafx.h"
- #include "merge.h"
  #include "CCPrompt.h"
+ #include "Merge.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
Simple merge
@@@ -19,8 -22,6 +22,7 @@@
  #include "DirFrame.h"
  #include "paths.h"
  #include "Environment.h"
- #include <locale.h>
- #include <sstream>
++#include "unicoder.h"
  
  // Escaped character constants in range 0x80-0xFF are interpreted in current codepage
  // Using C locale gets us direct mapping to Unicode codepoints
@@@ -9,10 -9,10 +9,10 @@@
  #if !defined(AFX_LANGUAGESELECT_H__4395A84F_E8DF_11D1_BBCB_00A024706EDC__INCLUDED_)
  #define AFX_LANGUAGESELECT_H__4395A84F_E8DF_11D1_BBCB_00A024706EDC__INCLUDED_
  
--#include "CMoveConstraint.h"
--
  #include <vector>
  #include <string>
++#include <map>
++#include "CMoveConstraint.h"
  
  /////////////////////////////////////////////////////////////////////////////
  // CLanguageSelect dialog
  #include "OptionsDef.h"
  #include "OptionsMgr.h"
  #include "SyntaxColors.h"
- #include "PreferencesDlg.h"
- #include "MainFrm.h"
  #include "Merge.h"
 -#include "paths.h" //paths_SplitFilename()
 +#include "paths.h"
  #include "FileOrFolderSelect.h"
  
  #ifdef _DEBUG
Simple merge
Simple merge
Simple merge
@@@ -26,7 -26,8 +26,9 @@@
  #define _SHELL_FILE_OPERATIONS_H_
  
  #include <vector>
+ #include <Windows.h>
 +#include <ShellAPI.h>
+ #include "UnicodeString.h"
  
  /**
   * @brief A wrapper class for SHFileOperation().
Simple merge
@@@ -23,9 -23,8 +23,9 @@@
  // $Id$
  
  #include "stdafx.h"
- #include "Merge.h"
  #include "ConfirmFolderCopyDlg.h"
+ #include "Merge.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
Simple merge
  // One idea would be to provide an iterator over them.
  //
  
 -#include "stdafx.h"
 -#include "Merge.h"
 +#include "DirActions.h"
 +#include "MergeApp.h"
  #include "UnicodeString.h"
 -#include "DirView.h"
 -#include "DirDoc.h"
 -#include "coretools.h"
 -#include "paths.h"
  #include "7zCommon.h"
  #include "ShellFileOperations.h"
 -#include "OptionsDef.h"
 -#include "WaitStatusCursor.h"
  #include "DiffItem.h"
  #include "FileActionScript.h"
 -#include "LoadSaveCodepageDlg.h"
 -#include "IntToIntMap.h"
 -#include "FileOrFolderSelect.h"
 -#include "ConfirmFolderCopyDlg.h"
 +#include "locality.h"
 +#include "FileFilterHelper.h"
 +#include "coretools.h"
+ #include "OptionsMgr.h"
  
 -#ifdef _DEBUG
 -#define new DEBUG_NEW
 -#undef THIS_FILE
 -static char THIS_FILE[] = __FILE__;
 -#endif
 -
 -// Flags for checking compare items:
 -// Don't check for existence
 -#define ALLOW_DONT_CARE 0
 -// Allow it being folder
 -#define ALLOW_FOLDER 1
 -// Allow it being file
 -#define ALLOW_FILE 2
 -// Allow all types (currently file and folder)
 -#define ALLOW_ALL (ALLOW_FOLDER | ALLOW_FILE)
 -
 -static bool ConfirmCopy(int origin, int destination, int count,
 +using Poco::UIntPtr;
 +
 +static void ThrowConfirmCopy(const CDiffContext& ctxt, int origin, int destination, int count,
                const String& src, const String& dest, bool destIsSide);
 -static bool ConfirmMove(int origin, int destination, int count,
 +static void ThrowConfirmMove(const CDiffContext& ctxt, int origin, int destination, int count,
                const String& src, const String& dest, bool destIsSide);
 -static bool ConfirmDialog(const String &caption, const String &question,
 -              int origin, int destination, int count,
 +static void ThrowConfirmationNeededException(const CDiffContext& ctxt, const String &caption, const String &question,
 +              int origin, int destination, size_t count,
                const String& src, const String& dest, bool destIsSide);
  
 -static bool CheckPathsExist(const String &orig, const String& dest, int allowOrig,
 -              int allowDest, String & failedPath);
 -
 +ContentsChangedException::ContentsChangedException(const String& failpath)
 +{
 +      m_msg = string_format_string1(
 +      _("Operation aborted!\n\nFolder contents at disks has changed, path\n%1\nwas not found.\n\nPlease refresh the compare."),
 +      failpath);
 +}
  
  /**
   * @brief Ask user a confirmation for copying item(s).
@@@ -15,8 -15,6 +15,7 @@@
  #include "paths.h"
  #include "FileOrFolderSelect.h"
  #include "Merge.h"
- #include "DirCmpReportDlg.h"
 +#include "DDXHelper.h"
  
  IMPLEMENT_DYNAMIC(DirCmpReportDlg, CDialog)
  
Simple merge
diff --cc Src/DirDoc.cpp
  //
  
  #include "StdAfx.h"
 -#include <shlwapi.h>          // PathFindFileName()
+ #include "DirDoc.h"
  #include <Poco/StringTokenizer.h>
  #include "Merge.h"
+ #include "MergeDoc.h"
  #include "HexMergeDoc.h"
  #include "UnicodeString.h"
  #include "CompareStats.h"
  #include "FilterList.h"
  #include "DirView.h"
- #include "DirDoc.h"
  #include "DirFrame.h"
 +#include "MainFrm.h"
  #include "coretools.h"
  #include "paths.h"
 -#include "WaitStatusCursor.h"
 +#include "CustomStatusCursor.h"
  #include "7zCommon.h"
  #include "OptionsDef.h"
+ #include "OptionsMgr.h"
  #include "OptionsDiffOptions.h"
  #include "FileActionScript.h"
  #include "LineFiltersList.h"
+ #include "FileFilterHelper.h"
  #include "unicoder.h"
 +#include "DirActions.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
Simple merge
diff --cc Src/DirItem.h
@@@ -25,9 -25,8 +25,7 @@@
  #ifndef _DIR_ITEM_H_INCLUDED
  #define _DIR_ITEM_H_INCLUDED
  
- #include "UnicodeString.h"
- #include "FileVersion.h"
  #define POCO_NO_UNWINDOWS 1
 -#include <Poco/Types.h>
  #include <Poco/File.h>
  #include <Poco/Timestamp.h>
  #include <boost/flyweight.hpp>
diff --cc Src/DirView.cpp
  #include "Constants.h"
  #include "Merge.h"
  #include "ClipBoard.h"
- #include "DirView.h"
 +#include "DirActions.h"
 +#include "SourceControl.h"
 +#include "DirViewColItems.h"
  #include "DirFrame.h"  // StatePane
  #include "DirDoc.h"
+ #include "MergeDoc.h"
  #include "HexMergeFrm.h"
  #include "HexMergeDoc.h"
  #include "MainFrm.h"
@@@ -767,176 -968,93 +769,176 @@@ void CDirView::OnCtxtDirCopy(
  }
  
  /// User chose (context menu) Copy left to...
 -void CDirView::OnCtxtDirCopyLeftTo()
 +template<SIDE_TYPE stype>
 +void CDirView::OnCtxtDirCopyTo()
  {
 -      DoCopyLeftTo();
 +      DoDirActionTo(stype, &DirActions::CopyTo<stype>, _("Copying files..."));
  }
  
 -/// User chose (context menu) Copy from right to...
 -void CDirView::OnCtxtDirCopyRightTo()
 +/// Update context menu Copy Right to Left item
 +template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
 +void CDirView::OnUpdateCtxtDirCopy(CCmdUI* pCmdUI)
  {
 -      DoCopyRightTo();
 +      DoUpdateDirCopy<srctype, dsttype>(pCmdUI, eContext);
  }
  
 -/// Update context menu Copy Right to Left item
 -void CDirView::OnUpdateCtxtDirCopyRightToLeft(CCmdUI* pCmdUI)
 +/// Update main menu Copy Right to Left item
 +template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
 +void CDirView::OnUpdateDirCopy(CCmdUI* pCmdUI)
  {
 -      DoUpdateDirCopyRightToLeft(pCmdUI, eContext);
 +      DoUpdateDirCopy<srctype, dsttype>(pCmdUI, eMain);
  }
 -/// Update context menu Copy Left to Right item
 -void CDirView::OnUpdateCtxtDirCopyLeftToRight(CCmdUI* pCmdUI)
 +
 +void CDirView::DoDirAction(DirActions::method_type func, const String& status_message)
  {
 -      DoUpdateDirCopyLeftToRight(pCmdUI, eContext);
 +      WaitStatusCursor waitstatus(status_message);
 +
 +      try {
 +              // First we build a list of desired actions
 +              FileActionScript actionScript;
 +              DirItemWithIndexIterator begin(m_pIList.get(), -1, true);
 +              DirItemWithIndexIterator end;
 +              std::accumulate(begin, end, &actionScript, MakeDirActions(func));
 +              // Now we prompt, and execute actions
 +              ConfirmAndPerformActions(actionScript);
 +      } catch (ContentsChangedException& e) {
 +              AfxMessageBox(e.m_msg.c_str(), MB_ICONWARNING);
 +      }
  }
  
 -/// Update main menu Copy Right to Left item
 -void CDirView::OnUpdateDirCopyRightToLeft(CCmdUI* pCmdUI)
 +void CDirView::DoDirActionTo(SIDE_TYPE stype, DirActions::method_type func, const String& status_message)
  {
 -      DoUpdateDirCopyRightToLeft(pCmdUI, eMain);
 +      String destPath;
 +      String startPath(m_lastCopyFolder);
 +      String selectfolder_title;
 +
 +      if (stype == SIDE_LEFT)
 +              selectfolder_title = _("Left side - select destination folder:");
 +      else if (stype == SIDE_MIDDLE)
 +              selectfolder_title = _("Middle side - select destination folder:");
 +      else if (stype == SIDE_RIGHT)
 +              selectfolder_title = _("Right side - select destination folder:");
 +
 +      if (!SelectFolder(destPath, startPath.c_str(), selectfolder_title))
 +              return;
 +
 +      m_lastCopyFolder = destPath;
 +      WaitStatusCursor waitstatus(status_message);
 +
 +      try {
 +              // First we build a list of desired actions
 +              FileActionScript actionScript;
 +              actionScript.m_destBase = destPath;
 +              DirItemWithIndexIterator begin(m_pIList.get(), -1, true);
 +              DirItemWithIndexIterator end;
 +              std::accumulate(begin, end, &actionScript, MakeDirActions(func));
 +              // Now we prompt, and execute actions
 +              ConfirmAndPerformActions(actionScript);
 +      } catch (ContentsChangedException& e) {
 +              AfxMessageBox(e.m_msg.c_str(), MB_ICONWARNING);
 +      }
  }
 -/// Update main menu Copy Left to Right item
 -void CDirView::OnUpdateDirCopyLeftToRight(CCmdUI* pCmdUI)
 +
 +// Confirm with user, then perform the action list
 +void CDirView::ConfirmAndPerformActions(FileActionScript & actionList)
  {
 -      DoUpdateDirCopyLeftToRight(pCmdUI, eMain);
 +      if (actionList.GetActionItemCount() == 0) // Not sure it is possible to get right-click menu without
 +              return;    // any selected items, but may as well be safe
 +
 +      ASSERT(actionList.GetActionItemCount()>0); // Or else the update handler got it wrong
 +
 +      // Set parent window so modality is correct and correct window gets focus
 +      // after dialogs.
 +      actionList.SetParentWindow(this->GetSafeHwnd());
 +      
 +      try {
 +              ConfirmActionList(GetDiffContext(), actionList);
 +      } catch (ConfirmationNeededException& e) {
 +              ConfirmFolderCopyDlg dlg;
 +              dlg.m_caption = e.m_caption;
 +              dlg.m_question = e.m_question;
 +              dlg.m_fromText = e.m_fromText;
 +              dlg.m_toText = e.m_toText;
 +              dlg.m_fromPath = e.m_fromPath;
 +              dlg.m_toPath = e.m_toPath;
 +              if (dlg.DoModal() != IDOK)
 +                      return;
 +      }
 +      PerformActionList(actionList);
  }
  
 -/// Should Copy to Left be enabled or disabled ? (both main menu & context menu use this)
 -void CDirView::DoUpdateDirCopyRightToLeft(CCmdUI* pCmdUI, eMenuType menuType)
 +/**
 + * @brief Perform an array of actions
 + * @note There can be only COPY or DELETE actions, not both!
 + * @sa SourceControl::SaveToVersionControl()
 + * @sa SourceControl::SyncFilesToVCS()
 + */
 +void CDirView::PerformActionList(FileActionScript & actionScript)
  {
 -      if (GetDocument()->GetReadOnly(0))
 -              pCmdUI->Enable(FALSE);
 +      // Reset suppressing VSS dialog for multiple files.
 +      // Set in SourceControl::SaveToVersionControl().
-       GetMainFrame()->m_pSourceControl->m_CheckOutMulti = false;
-       GetMainFrame()->m_pSourceControl->m_bVssSuppressPathCheck = false;
++      theApp.m_pSourceControl->m_CheckOutMulti = false;
++      theApp.m_pSourceControl->m_bVssSuppressPathCheck = false;
 +
 +      // Check option and enable putting deleted items to Recycle Bin
 +      if (GetOptionsMgr()->GetBool(OPT_USE_RECYCLE_BIN))
 +              actionScript.UseRecycleBin(true);
        else
 +              actionScript.UseRecycleBin(false);
 +
 +      actionScript.SetParentWindow(GetMainFrame()->GetSafeHwnd());
 +
 +      theApp.AddOperation();
 +      if (actionScript.Run())
 +              UpdateAfterFileScript(actionScript);
 +      theApp.RemoveOperation();
 +}
 +
 +/**
 + * @brief Update results after running FileActionScript.
 + * This functions is called after script is finished to update
 + * results (including UI).
 + * @param [in] actionlist Script that was run.
 + */
 +void CDirView::UpdateAfterFileScript(FileActionScript & actionList)
 +{
 +      bool bItemsRemoved = false;
 +      int curSel = GetFirstSelectedInd();
 +      CDiffContext& ctxt = GetDiffContext();
 +      while (actionList.GetActionItemCount()>0)
        {
 -              int sel = -1;
 -              int legalcount = 0, selcount = 0;
 -              while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
 +              // Start handling from tail of list, so removing items
 +              // doesn't invalidate our item indexes.
 +              FileActionItem act = actionList.RemoveTailActionItem();
 +
 +              // Synchronized items may need VCS operations
 +              if (act.UIResult == FileActionItem::UI_SYNC)
                {
-                       if (GetMainFrame()->m_pSourceControl->m_bCheckinVCS)
-                               GetMainFrame()->m_pSourceControl->CheckinToClearCase(act.dest);
 -                      const DIFFITEM& di = GetDiffItem(sel);
 -                      if (di.diffcode.diffcode != 0 && IsItemCopyableToLeft(di))
 -                              ++legalcount;
 -                      ++selcount;
++                      if (theApp.m_pSourceControl->m_bCheckinVCS)
++                              theApp.m_pSourceControl->CheckinToClearCase(act.dest);
                }
 -              pCmdUI->Enable(legalcount > 0);
 -              if (menuType == eContext)
 +
 +              // Update doc (difflist)
 +              UPDATEITEM_TYPE updatetype = UpdateDiffAfterOperation(act, ctxt, GetDiffItem(act.context));
 +              if (updatetype == UPDATEITEM_REMOVE)
                {
 -                      String s;
 -                      if (legalcount == selcount)
 -                              s = LangFormatString1(IDS_COPY_TO_LEFT, NumToStr(selcount).c_str());
 -                      else
 -                              s = LangFormatString2(IDS_COPY_TO_LEFT2, NumToStr(legalcount).c_str(), NumToStr(selcount).c_str());
 -                      pCmdUI->SetText(s.c_str());
 +                      DeleteItem(act.context);
 +                      bItemsRemoved = true;
                }
 +              else if (updatetype == UPDATEITEM_UPDATE)
 +                      UpdateDiffItemStatus(act.context);
        }
 -}
 -
 -/// Should Copy to Right be enabled or disabled ? (both main menu & context menu use this)
 -void CDirView::DoUpdateDirCopyLeftToRight(CCmdUI* pCmdUI, eMenuType menuType)
 -{
 -      if (GetDocument()->GetReadOnly(GetDocument()->m_nDirs - 1))
 -              pCmdUI->Enable(FALSE);
 -      else
 +      
 +      // Make sure selection is at sensible place if all selected items
 +      // were removed.
 +      if (bItemsRemoved == true)
        {
 -              int sel = -1;
 -              int legalcount = 0, selcount = 0;
 -              while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
 -              {
 -                      const DIFFITEM& di = GetDiffItem(sel);
 -                      if (di.diffcode.diffcode != 0 && IsItemCopyableToRight(di))
 -                              ++legalcount;
 -                      ++selcount;
 -              }
 -              pCmdUI->Enable(legalcount > 0);
 -              if (menuType == eContext)
 +              UINT selected = GetSelectedCount();
 +              if (selected == 0)
                {
 -                      String s;
 -                      if (legalcount == selcount)
 -                              s = LangFormatString1(IDS_COPY_TO_RIGHT, NumToStr(selcount).c_str());
 -                      else
 -                              s = LangFormatString2(IDS_COPY_TO_RIGHT2, NumToStr(legalcount).c_str(), NumToStr(selcount).c_str());
 -                      pCmdUI->SetText(s.c_str());
 +                      if (curSel < 1)
 +                              ++curSel;
 +                      MoveFocus(0, curSel - 1, selected);
                }
        }
  }
@@@ -1335,12 -1813,12 +1337,12 @@@ void CDirView::OpenSelection(SELECTIONT
                        if (di1 == di2 && !di1->diffcode.isExists(0))
                        {
                                paths[0] = _T("");
-                               GetMainFrame()->m_strDescriptions[0] = _("Untitled left");
 -                              theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE);
++                              theApp.m_strDescriptions[0] = _("Untitled left");
                        }
                        if (di1 == di2 && !di1->diffcode.isExists(1))
                        {
                                paths[1] = _T("");
-                               GetMainFrame()->m_strDescriptions[1] = _("Untitled right");
 -                              theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE);
++                              theApp.m_strDescriptions[1] = _("Untitled right");
                        }
                }
                else
                        if (di1 == di2 && di1 == di3 && !di1->diffcode.isExists(0))
                        {
                                paths[0] = _T("");
-                               GetMainFrame()->m_strDescriptions[0] = _("Untitled left");
 -                              theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE);
++                              theApp.m_strDescriptions[0] = _("Untitled left");
                        }
                        if (di1 == di2 && di1 == di3 && !di1->diffcode.isExists(1))
                        {
                                paths[1] = _T("");
-                               GetMainFrame()->m_strDescriptions[1] = _("Untitled middle");
 -                              theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_MIDDLE_FILE);
++                              theApp.m_strDescriptions[1] = _("Untitled middle");
                        }
                        if (di1 == di2 && di1 == di3 && !di1->diffcode.isExists(2))
                        {
                                paths[2] = _T("");
-                               GetMainFrame()->m_strDescriptions[2] = _("Untitled right");
 -                              theApp.m_strDescriptions[2] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE);
++                              theApp.m_strDescriptions[2] = _("Untitled right");
                        }
                }
  
@@@ -1549,103 -2212,39 +1551,103 @@@ int CDirView::GetItemIndex(UIntPtr key
        return m_pList->FindItem(&findInfo);
  }
  
 -/// User chose (context menu) open left
 -void CDirView::OnCtxtDirOpenLeft()
 +/**
 + * @brief Get the file names on both sides for specified item.
 + * @note Return empty strings if item is special item.
 + */
 +void CDirView::GetItemFileNames(int sel, String& strLeft, String& strRight) const
  {
 -      DoOpen(SIDE_LEFT);
 +      UINT_PTR diffpos = GetItemKey(sel);
 +      if (diffpos == (UINT_PTR)SPECIAL_ITEM_POS)
 +      {
 +              strLeft.erase();
 +              strRight.erase();
 +      }
 +      else
 +      {
 +              const CDiffContext& ctxt = GetDiffContext();
 +              ::GetItemFileNames(ctxt, ctxt.GetDiffAt(diffpos), strLeft, strRight);
 +      }
  }
 -/// User chose (context menu) open right
 -void CDirView::OnCtxtDirOpenRight()
 +
 +/**
 + * @brief Get the file names on both sides for specified item.
 + * @note Return empty strings if item is special item.
 + */
 +void CDirView::GetItemFileNames(int sel, PathContext * paths) const
  {
 -      DoOpen(SIDE_RIGHT);
 +      String strPath[3];
 +      UINT_PTR diffpos = GetItemKey(sel);
 +      if (diffpos == SPECIAL_ITEM_POS)
 +      {
 +              for (int nIndex = 0; nIndex < GetDocument()->m_nDirs; nIndex++)
 +                      paths->SetPath(nIndex, _T(""));
 +      }
 +      else
 +      {
 +              const CDiffContext& ctxt = GetDiffContext();
 +              *paths = ::GetItemFileNames(ctxt, ctxt.GetDiffAt(diffpos));
 +      }
  }
  
 -/// User chose (context menu) open left with
 -void CDirView::OnCtxtDirOpenLeftWith()
 +/**
 + * @brief Open selected file with registered application.
 + * Uses shell file associations to open file with registered
 + * application. We first try to use "Edit" action which should
 + * open file to editor, since we are more interested editing
 + * files than running them (scripts).
 + * @param [in] stype Side of file to open.
 + */
 +void CDirView::DoOpen(SIDE_TYPE stype)
  {
 -      DoOpenWith(SIDE_LEFT);
 +      int sel = GetSingleSelectedItem();
 +      if (sel == -1) return;
 +      String file = GetSelectedFileName(SelBegin(), stype, GetDiffContext());
 +      if (file.empty()) return;
 +      int rtn = (int)ShellExecute(::GetDesktopWindow(), _T("edit"), file.c_str(), 0, 0, SW_SHOWNORMAL);
 +      if (rtn==SE_ERR_NOASSOC)
 +              rtn = (int)ShellExecute(::GetDesktopWindow(), _T("open"), file.c_str(), 0, 0, SW_SHOWNORMAL);
 +      if (rtn==SE_ERR_NOASSOC)
 +              DoOpenWith(stype);
  }
  
 -/// User chose (context menu) open right with
 -void CDirView::OnCtxtDirOpenRightWith()
 +/// Open with dialog for file on selected side
 +void CDirView::DoOpenWith(SIDE_TYPE stype)
  {
 -      DoOpenWith(SIDE_RIGHT);
 +      int sel = GetSingleSelectedItem();
 +      if (sel == -1) return;
 +      String file = GetSelectedFileName(SelBegin(), stype, GetDiffContext());
 +      if (file.empty()) return;
 +      CString sysdir;
 +      if (!GetSystemDirectory(sysdir.GetBuffer(MAX_PATH), MAX_PATH)) return;
 +      sysdir.ReleaseBuffer();
 +      CString arg = (CString)_T("shell32.dll,OpenAs_RunDLL ") + file.c_str();
 +      ShellExecute(::GetDesktopWindow(), 0, _T("RUNDLL32.EXE"), arg, sysdir, SW_SHOWNORMAL);
  }
  
 -/// User chose (context menu) open right with editor
 -void CDirView::OnCtxtDirOpenRightWithEditor()
 +/// Open selected file  on specified side to external editor
 +void CDirView::DoOpenWithEditor(SIDE_TYPE stype)
  {
 -      DoOpenWithEditor(SIDE_RIGHT);
 +      int sel = GetSingleSelectedItem();
 +      if (sel == -1) return;
 +      String file = GetSelectedFileName(SelBegin(), stype, GetDiffContext());
 +      if (file.empty()) return;
 +
-       GetMainFrame()->OpenFileToExternalEditor(file);
++      theApp.OpenFileToExternalEditor(file);
 +}
 +
 +/// User chose (context menu) open left
 +template<SIDE_TYPE stype>
 +void CDirView::OnCtxtDirOpen()
 +{
 +      DoOpen(stype);
  }
  
 -/// Update context menuitem "Open right | with editor"
 -void CDirView::OnUpdateCtxtDirOpenRightWithEditor(CCmdUI* pCmdUI)
 +/// User chose (context menu) open left with
 +template<SIDE_TYPE stype>
 +void CDirView::OnCtxtDirOpenWith()
  {
 -      DoUpdateOpenRightWith(pCmdUI);
 +      DoOpenWith(stype);
  }
  
  /// User chose (context menu) open left with editor
diff --cc Src/DirView.h
Simple merge
Simple merge
  #include "UnicodeString.h"
  #include "Merge.h"
  #include "OptionsDef.h"
+ #include "OptionsMgr.h"
  #include "MainFrm.h"
- #include "FileActionScript.h"
  #include "ShellFileOperations.h"
  #include "paths.h"
 +#include "SourceControl.h"
  
  using std::vector;
  
@@@ -175,9 -173,9 +176,9 @@@ int FileActionScript::CreateOperationsS
  
                        if (bContinue)
                        {
-                               if (!GetMainFrame()->CreateBackup(TRUE, (*iter).dest.c_str()))
+                               if (!theApp.CreateBackup(TRUE, (*iter).dest.c_str()))
                                {
 -                                      String strErr = theApp.LoadString(IDS_ERROR_BACKUP);
 +                                      String strErr = _("Error backing up file");
                                        AfxMessageBox(strErr.c_str(), MB_OK | MB_ICONERROR);
                                        bContinue = FALSE;
                                }
@@@ -246,9 -246,9 +246,9 @@@ void FileFiltersDlg::OnFiltersEditbtn(
   * @brief Edit file filter in external editor.
   * @param [in] path Full path to file filter to edit.
   */
 -void FileFiltersDlg::EditFileFilter(LPCTSTR path)
 +void FileFiltersDlg::EditFileFilter(const String& path)
  {
-       CMainFrame::OpenFileToExternalEditor(path);
+       theApp.OpenFileToExternalEditor(path);
  }
  
  /**
@@@ -455,14 -457,11 +455,14 @@@ void FileFiltersDlg::OnBnClickedFilterf
                // user has already allowed it.
                if (!CopyFile(templatePath.c_str(), s.c_str(), FALSE))
                {
 -                      ResMsgBox1(IDS_FILEFILTER_TMPL_COPY, templatePath.c_str(), MB_ICONERROR);
 +                      String msg = string_format_string1(
 +                              _( "Cannot copy filter template file to filter folder:\n%1\n\nPlease make sure the folder exists and is writable."),
 +                              templatePath);
 +                      AfxMessageBox(msg.c_str(), MB_ICONERROR);
                        return;
                }
 -              EditFileFilter(s.c_str());
 +              EditFileFilter(s);
-               FileFilterMgr *pMgr = theApp.m_globalFileFilter.GetManager();
+               FileFilterMgr *pMgr = theApp.m_pGlobalFileFilter->GetManager();
                int retval = pMgr->AddFilter(s.c_str());
                if (retval == FILTER_OK)
                {
@@@ -496,10 -496,10 +496,10 @@@ void FileFiltersDlg::OnBnClickedFilterf
                int res = AfxMessageBox(sConfirm.c_str(), MB_ICONWARNING | MB_YESNO);
                if (res == IDYES)
                {
 -                      if (DeleteFile(path))
 +                      if (DeleteFile(path.c_str()))
                        {
-                               FileFilterMgr *pMgr = theApp.m_globalFileFilter.GetManager();
+                               FileFilterMgr *pMgr = theApp.m_pGlobalFileFilter->GetManager();
 -                              pMgr->RemoveFilter((LPCTSTR)path);
 +                              pMgr->RemoveFilter(path);
                                
                                // Remove all from filterslist and re-add so we can update UI
                                String selected;
@@@ -559,12 -556,17 +559,12 @@@ void FileFiltersDlg::OnBnClickedFilterf
  {
        String s;
        String path;
-       String userPath = theApp.m_globalFileFilter.GetUserFilterPathWithCreate();
+       String userPath = theApp.m_pGlobalFileFilter->GetUserFilterPathWithCreate();
  
 -      if (SelectFile(GetSafeHwnd(), s, path.c_str(), IDS_FILEFILTER_INSTALL, IDS_FILEFILTER_FILEMASK,
 +      if (SelectFile(GetSafeHwnd(), s, path.c_str(), _("Locate filter file to install"), _("File Filters (*.flt)|*.flt|All Files (*.*)|*.*||"),
                TRUE))
        {
 -              String sfile, sext;
 -              paths_SplitFilename(s, NULL, &sfile, &sext);
 -              String filename = sfile;
 -              filename += _T(".");
 -              filename += sext;
 -              userPath = paths_ConcatPath(userPath, filename);
 +              userPath = paths_ConcatPath(userPath, paths_FindFileName(s));
                if (!CopyFile(s.c_str(), userPath.c_str(), TRUE))
                {
                        // If file already exists, ask from user
Simple merge
Simple merge
  #ifndef _FILE_OR_FOLDER_SELECTION_H_
  #define _FILE_OR_FOLDER_SELECTION_H_
  
+ #include "UnicodeString.h"
  
  BOOL SelectFile(HWND parent, String& path, LPCTSTR initialPath = NULL, 
 -                       UINT titleid = 0, UINT filterid = 0,
 +                       const String& stitle = _T(""), const String& sfilter = _T(""),
                         BOOL is_open =TRUE, LPCTSTR defaultExtension = NULL);
  
  BOOL SelectFolder(String& path, LPCTSTR root_path = NULL, 
  // $Id: FilepathEdit.cpp 6500 2009-02-25 13:36:26Z kimmov $
  
  #include "stdafx.h"
+ #include "FilepathEdit.h"
  #include "Merge.h"
  #include "BCMenu.h"
- #include "FilepathEdit.h"
  #include "ClipBoard.h"
  #include "Shlwapi.h"
 +#include "paths.h"
 +#include <algorithm>
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
  #include "HexMergeView.h"
  #include "DiffItem.h"
  #include "FolderCmp.h"
- #include "MainFrm.h"
  #include "Environment.h"
 -#include "diffcontext.h"      // FILE_SAME
 -#include "dirdoc.h"
 +#include "DiffContext.h"      // FILE_SAME
 +#include "DirDoc.h"
 +#include "DirActions.h"
  #include "OptionsDef.h"
  #include "DiffFileInfo.h"
  #include "SaveClosingDlg.h"
@@@ -366,14 -365,14 +366,14 @@@ void CHexMergeDoc::DoFileSaveAs(int nBu
  {
        const String &path = m_filePaths.GetPath(nBuffer);
        String strPath;
 -      int id;
 +      String title;
        if (nBuffer == 0)
 -              id = IDS_SAVE_LEFT_AS;
 +              title = _("Save Left File As");
        else if (nBuffer == m_nBuffers - 1)
 -              id = IDS_SAVE_RIGHT_AS;
 +              title = _("Save Right File As");
        else
 -              id = IDS_SAVE_MIDDLE_AS;
 -      if (SelectFile(AfxGetMainWnd()->GetSafeHwnd(), strPath, path.c_str(), id, NULL, FALSE))
 +              title = _("Save Middle File As");
-       if (SelectFile(GetMainFrame()->GetSafeHwnd(), strPath, path.c_str(), title, _T(""), FALSE))
++      if (SelectFile(AfxGetMainWnd()->GetSafeHwnd(), strPath, path.c_str(), title, _T(""), FALSE))
        {
                if (Try(m_pView[nBuffer]->SaveFile(strPath.c_str())) == IDCANCEL)
                        return;
Simple merge
Simple merge
Simple merge
@@@ -7,11 -7,9 +7,10 @@@
  // $Id$
  
  #include "stdafx.h"
- #include "merge.h"
  #include "LineFiltersList.h"
- #include "MainFrm.h"
+ #include "Merge.h"
  #include "LineFiltersDlg.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
@@@ -7,13 -7,11 +7,12 @@@
  // $Id: LoadSaveCodepageDlg.cpp 5394 2008-05-29 09:47:36Z kimmov $
  
  #include "stdafx.h"
+ #include "LoadSaveCodepageDlg.h"
  #include "Merge.h"
- #include "MainFrm.h"
  #include "resource.h"
- #include "LoadSaveCodepageDlg.h"
  #include "unicoder.h"
  #include "ExConverter.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
@@@ -131,11 -127,11 +128,11 @@@ BOOL CLoadSaveCodepageDlg::OnInitDialog
                combo.Detach();
        }
  
-       CMainFrame::CenterToMainFrame(this);
+       AfxGetMainWnd()->CenterWindow(this);
  
 -      SetDlgItemText(IDC_LEFT_FILES_LABEL, m_sAffectsLeftString);
 -      SetDlgItemText(IDC_MIDDLE_FILES_LABEL, m_sAffectsMiddleString);
 -      SetDlgItemText(IDC_RIGHT_FILES_LABEL, m_sAffectsRightString);
 +      SetDlgItemText(IDC_LEFT_FILES_LABEL, m_sAffectsLeftString.c_str());
 +      SetDlgItemText(IDC_MIDDLE_FILES_LABEL, m_sAffectsMiddleString.c_str());
 +      SetDlgItemText(IDC_RIGHT_FILES_LABEL, m_sAffectsRightString.c_str());
  
        UpdateSaveGroup();
  
Simple merge
Simple merge
diff --cc Src/MainFrm.cpp
  // $Id: MainFrm.cpp 7063 2009-12-27 15:28:16Z kimmov $
  
  #include "StdAfx.h"
+ #include "MainFrm.h"
  #include <vector>
- #include <htmlhelp.h>  // From HTMLHelp Workshop (incl. in Platform SDK)
++#include <Poco/Exception.h>
  #include <shlwapi.h>
+ #include <Poco/Exception.h>
  #include "Constants.h"
  #include "Merge.h"
+ #include "FileFilterHelper.h"
  #include "UnicodeString.h"
  #include "BCMenu.h"
- #include "MainFrm.h"
  #include "OpenFrm.h"
  #include "DirFrame.h"         // Include type information
  #include "ChildFrm.h"
@@@ -891,122 -840,8 +841,8 @@@ void CMainFrame::OnUpdateOptionsShowSki
   */
  void CMainFrame::OnHelpGnulicense() 
  {
 -      const String spath = env_GetProgPath() + LicenseFile;
 +      const String spath = paths_ConcatPath(env_GetProgPath(), LicenseFile);
-       OpenFileOrUrl(spath.c_str(), LicenceUrl);
- }
- /**
-  * @brief Checks if path (file/folder) is read-only and asks overwriting it.
-  *
-  * @param strSavePath [in,out] Path where to save (file or folder)
-  * @param bMultiFile [in] Single file or multiple files/folder
-  * @param bApplyToAll [in,out] Apply last user selection for all items?
-  * @return Users selection:
-  * - IDOK: Item was not readonly, no actions
-  * - IDYES/IDYESTOALL: Overwrite readonly item
-  * - IDNO: User selected new filename (single file) or user wants to skip
-  * - IDCANCEL: Cancel operation
-  * @sa CMainFrame::SyncFileToVCS()
-  * @sa CMergeDoc::DoSave()
-  */
- int CMainFrame::HandleReadonlySave(String& strSavePath, BOOL bMultiFile,
-               BOOL &bApplyToAll)
- {
-       CFileStatus status;
-       UINT userChoice = 0;
-       int nRetVal = IDOK;
-       BOOL bFileRO = FALSE;
-       BOOL bFileExists = FALSE;
-       String s;
-       String str;
-       CString title;
-       int nVerSys = 0;
-       try
-       {
-               TFile file(strSavePath);
-               bFileExists = file.exists();
-               if (bFileExists)
-                       bFileRO = !file.canWrite();
-       }
-       catch (...)
-       {
-       }
-       nVerSys = GetOptionsMgr()->GetInt(OPT_VCS_SYSTEM);
-       
-       if (bFileExists && bFileRO)
-       {
-               // Version control system used?
-               // Checkout file from VCS and modify, don't ask about overwriting
-               // RO files etc.
-               if (nVerSys != SourceControl::VCS_NONE)
-               {
-                       bool bRetVal = m_pSourceControl->SaveToVersionControl(strSavePath);
-                       if (bRetVal)
-                               return IDYES;
-                       else
-                               return IDCANCEL;
-               }
-               
-               // Don't ask again if its already asked
-               if (bApplyToAll)
-                       userChoice = IDYES;
-               else
-               {
-                       // Prompt for user choice
-                       if (bMultiFile)
-                       {
-                               // Multiple files or folder
-                               str = string_format_string1(_("%1\nis marked read-only. Would you like to override the read-only item?"), strSavePath);
-                               userChoice = AfxMessageBox(str.c_str(), MB_YESNOCANCEL |
-                                               MB_ICONWARNING | MB_DEFBUTTON3 | MB_DONT_ASK_AGAIN |
-                                               MB_YES_TO_ALL, IDS_SAVEREADONLY_MULTI);
-                       }
-                       else
-                       {
-                               // Single file
-                               str = string_format_string1(_("%1 is marked read-only. Would you like to override the read-only file ? (No to save as new filename.)"), strSavePath);
-                               userChoice = AfxMessageBox(str.c_str(), MB_YESNOCANCEL |
-                                               MB_ICONWARNING | MB_DEFBUTTON2 | MB_DONT_ASK_AGAIN,
-                                               IDS_SAVEREADONLY_FMT);
-                       }
-               }
-               switch (userChoice)
-               {
-               // Overwrite read-only file
-               case IDYESTOALL:
-                       bApplyToAll = TRUE;  // Don't ask again (no break here)
-               case IDYES:
-                       CFile::GetStatus(strSavePath.c_str(), status);
-                       status.m_mtime = 0;             // Avoid unwanted changes
-                       status.m_attribute &= ~CFile::readOnly;
-                       CFile::SetStatus(strSavePath.c_str(), status);
-                       nRetVal = IDYES;
-                       break;
-               
-               // Save to new filename (single) /skip this item (multiple)
-               case IDNO:
-                       if (!bMultiFile)
-                       {
-                               if (SelectFile(GetSafeHwnd(), s, strSavePath.c_str(), _("Save As"), _T(""), FALSE))
-                               {
-                                       strSavePath = s;
-                                       nRetVal = IDNO;
-                               }
-                               else
-                                       nRetVal = IDCANCEL;
-                       }
-                       else
-                               nRetVal = IDNO;
-                       break;
-               // Cancel saving
-               case IDCANCEL:
-                       nRetVal = IDCANCEL;
-                       break;
-               }
-       }
-       return nRetVal;
+       theApp.OpenFileOrUrl(spath.c_str(), LicenceUrl);
  }
  
  /// Wrapper to set the global option 'm_bAllowMixedEol'
@@@ -2330,17 -1974,17 +1953,17 @@@ void CMainFrame::FileNew(int nPanes
        FileLocation fileloc[3];
        if (nPanes == 2)
        {
-               m_strDescriptions[0] = _("Untitled left");
-               m_strDescriptions[1] = _("Untitled right");
 -              theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE);
 -              theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE);
++              theApp.m_strDescriptions[0] = _("Untitled left");
++              theApp.m_strDescriptions[1] = _("Untitled right");
                fileloc[0].encoding.SetCodepage(ucr::getDefaultCodepage());
                fileloc[1].encoding.SetCodepage(ucr::getDefaultCodepage());
                ShowMergeDoc(pDirDoc, 2, fileloc, dwFlags);
        }
        else
        {
-               m_strDescriptions[0] = _("Untitled left");
-               m_strDescriptions[1] = _("Untitled middle");
-               m_strDescriptions[2] = _("Untitled right");
 -              theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE);
 -              theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_MIDDLE_FILE);
 -              theApp.m_strDescriptions[2] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE);
++              theApp.m_strDescriptions[0] = _("Untitled left");
++              theApp.m_strDescriptions[1] = _("Untitled middle");
++              theApp.m_strDescriptions[2] = _("Untitled right");
                fileloc[0].encoding.SetCodepage(ucr::getDefaultCodepage());
                fileloc[1].encoding.SetCodepage(ucr::getDefaultCodepage());
                fileloc[2].encoding.SetCodepage(ucr::getDefaultCodepage());
@@@ -2391,15 -2035,15 +2014,15 @@@ void CMainFrame::OnToolsFilters(
        sht.m_psh.dwFlags |= PSH_NOAPPLYNOW; // Hide 'Apply' button since we don't need it
  
        // Make sure all filters are up-to-date
-       theApp.m_globalFileFilter.ReloadUpdatedFilters();
+       theApp.m_pGlobalFileFilter->ReloadUpdatedFilters();
  
-       theApp.m_globalFileFilter.GetFileFilters(&fileFilters, selectedFilter);
+       theApp.m_pGlobalFileFilter->GetFileFilters(&fileFilters, selectedFilter);
        fileFiltersDlg.SetFilterArray(&fileFilters);
        fileFiltersDlg.SetSelected(selectedFilter);
 -      const BOOL lineFiltersEnabledOrig = GetOptionsMgr()->GetBool(OPT_LINEFILTER_ENABLED);
 +      const bool lineFiltersEnabledOrig = GetOptionsMgr()->GetBool(OPT_LINEFILTER_ENABLED);
        lineFiltersDlg.m_bIgnoreRegExp = lineFiltersEnabledOrig;
  
-       lineFilters->CloneFrom(m_pLineFilters.get());
+       lineFilters->CloneFrom(theApp.m_pLineFilters.get());
        lineFiltersDlg.SetList(lineFilters.get());
  
        if (sht.DoModal() == IDOK)
                }
                else
                {
-                       theApp.m_globalFileFilter.SetFileFilterPath(path);
-                       theApp.m_globalFileFilter.UseMask(FALSE);
-                       String sFilter = theApp.m_globalFileFilter.GetFilterNameOrMask();
+                       theApp.m_pGlobalFileFilter->SetFileFilterPath(path);
+                       theApp.m_pGlobalFileFilter->UseMask(FALSE);
+                       String sFilter = theApp.m_pGlobalFileFilter->GetFilterNameOrMask();
                        GetOptionsMgr()->SaveOption(OPT_FILEFILTER_CURRENT, sFilter);
                }
 -              BOOL linefiltersEnabled = lineFiltersDlg.m_bIgnoreRegExp;
 -              GetOptionsMgr()->SaveOption(OPT_LINEFILTER_ENABLED, linefiltersEnabled == TRUE);
 +              bool linefiltersEnabled = lineFiltersDlg.m_bIgnoreRegExp;
 +              GetOptionsMgr()->SaveOption(OPT_LINEFILTER_ENABLED, linefiltersEnabled);
  
                // Check if compare documents need rescanning
                BOOL bFileCompareRescan = FALSE;
@@@ -2772,65 -2380,7 +2359,7 @@@ CMainFrame * GetMainFrame(
        return pMainframe;
  }
  
 -/** 
 +/**
-  * @brief Access to the singleton set of syntax colors
-  */
- SyntaxColors * GetMainSyntaxColors()
- {
-       return GetMainFrame()->GetMainSyntaxColors();
- }
- /** 
-  * @brief Move dialog to center of MainFrame
-  */
- void CMainFrame::CenterToMainFrame(CDialog * dlg)
- {
-       CRect rectFrame;
-       CRect rectBar;
-       AfxGetMainWnd()->GetWindowRect(&rectFrame);
-       dlg->GetClientRect(&rectBar);
-       // Middlepoint of MainFrame
-       int x = rectFrame.left + (rectFrame.right - rectFrame.left) / 2;
-       int y = rectFrame.top + (rectFrame.bottom - rectFrame.top) / 2;
-       // Reduce by half of dialog's size
-       x -= rectBar.right / 2;
-       y -= rectBar.bottom / 2;
-       // This refreshes dialog size after m_constraint rezizing dialog so we get
-       // correct dialog positioning
-       dlg->CenterWindow();
-       // Calculate real desktop coordinates (if we have multiple monitors or
-       // virtual desktops
-       CRect dsk_rc;
-       dsk_rc.left = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
-       dsk_rc.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
-       dsk_rc.right = dsk_rc.left + ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
-       dsk_rc.bottom = dsk_rc.top + ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
-       // Only move Open-dialog if its fully visible in new position
-       CPoint ptLeftTop(x, y);
-       CPoint ptRightBottom(x + rectBar.right, y + rectBar.bottom);
-       if (dsk_rc.PtInRect(ptLeftTop) && dsk_rc.PtInRect(ptRightBottom))
-       {
-               dlg->SetWindowPos(&CWnd::wndTop, x, y, rectBar.right,
-                       rectBar.bottom, SWP_NOOWNERZORDER | SWP_NOSIZE );
-       }
- }
- /**
-  * @brief Assign the main WinMerge 16x16 icon to dialog
-  */
- void CMainFrame::SetMainIcon(CDialog * dlg)
- {
-       // Note: LoadImage gets shared icon, don't need to destroy
-       HICON hMergeIcon = (HICON) LoadImage(AfxGetInstanceHandle(),
-                       MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 16, 16,
-                       LR_DEFAULTSIZE | LR_SHARED);
-       dlg->SetIcon(hMergeIcon, TRUE);
- }
- /** 
   * @brief Opens dialog for user to Load, edit and save project files.
   * This dialog gets current compare paths and filter (+other properties
   * possible in project files) and initializes the dialog with them.
@@@ -2872,7 -2425,8 +2401,7 @@@ void CMainFrame::OnSaveProject(
                pathsDlg.m_bRightPathReadOnly = pDoc->GetReadOnly(pDoc->m_nDirs - 1);
        }
  
-       pathsDlg.m_sFilter = theApp.m_globalFileFilter.GetFilterNameOrMask();
 -      String filterNameOrMask = theApp.m_pGlobalFileFilter->GetFilterNameOrMask();
 -      pathsDlg.m_sFilter = filterNameOrMask.c_str();
++      pathsDlg.m_sFilter = theApp.m_pGlobalFileFilter->GetFilterNameOrMask();
        sht.DoModal();
  }
  
@@@ -3262,11 -2816,11 +2791,11 @@@ BOOL CMainFrame::DoOpenConflict(const S
        {
                // Open two parsed files to WinMerge, telling WinMerge to
                // save over original file (given as third filename).
-               m_strSaveAsPath = conflictFile.c_str();
+               theApp.m_strSaveAsPath = conflictFile.c_str();
 -              String theirs = LoadResString(IDS_CONFLICT_THEIRS_FILE);
 -              String my = LoadResString(IDS_CONFLICT_MINE_FILE);
 +              String theirs = _("Theirs File");
 +              String my = _("Mine File");
-               m_strDescriptions[0] = theirs;
-               m_strDescriptions[1] = my;
+               theApp.m_strDescriptions[0] = theirs;
+               theApp.m_strDescriptions[1] = my;
  
                DWORD dwFlags[2] = {FFILEOPEN_READONLY | FFILEOPEN_NOMRU, FFILEOPEN_NOMRU | FFILEOPEN_MODIFIED};
                conflictCompared = DoFileOpen(&PathContext(revFile, workFile), 
diff --cc Src/MainFrm.h
@@@ -108,10 -104,8 +105,8 @@@ public
        int ShowMergeDoc(CDirDoc * pDirDoc, int nFiles, const FileLocation fileloc[],
                DWORD dwFlags[], PackingInfo * infoUnpacker = NULL);
        void ShowHexMergeDoc(CDirDoc * pDirDoc,
 -              const PathContext &paths, bool bRO[]);
 +              const PathContext &paths, const bool bRO[]);
        void UpdateResources();
-       BOOL CreateBackup(BOOL bFolder, const String& pszPath);
-       int HandleReadonlySave(String& strSavePath, BOOL bMultiFile, BOOL &bApplyToAll);
        CString SetStatus(LPCTSTR status);
        void ClearStatusbarItemCount();
        void ApplyViewWhitespace();
diff --cc Src/Merge.cpp
  #include "ConflictFileParser.h"
  #include "codepage.h"
  #include "JumpList.h"
 -#include "VSSHelper.h"
+ #include "stringdiffs.h"
+ #include "TFile.h"
++#include "SourceControl.h"
 +#include "paths.h"
 +#include "Constants.h"
  
  // For shutdown cleanup
  #include "charsets.h"
@@@ -187,8 -200,18 +202,15 @@@ CMergeApp::CMergeApp() 
  , m_nLastCompareResult(0)
  , m_bNonInteractive(false)
  , m_pOptions(new CRegOptionsMgr())
+ , m_pGlobalFileFilter(new FileFilterHelper())
  , m_nActiveOperations(0)
  , m_pLangDlg(new CLanguageSelect(IDR_MAINFRAME, IDR_MAINFRAME))
 -, m_pVssHelper(new VSSHelper())
 -, m_CheckOutMulti(FALSE)
 -, m_bVCProjSync(FALSE)
 -, m_bVssSuppressPathCheck(FALSE)
+ , m_bEscShutdown(FALSE)
+ , m_bClearCaseTool(FALSE)
+ , m_bExitIfNoDiff(MergeCmdLineInfo::Disabled)
+ , m_pLineFilters(new LineFiltersList())
+ , m_pSyntaxColors(new SyntaxColors())
++, m_pSourceControl(new SourceControl())
  {
        // add construction code here,
        // Place all significant initialization in InitInstance
@@@ -346,6 -370,40 +369,42 @@@ BOOL CMergeApp::InitInstance(
                m_pOptions->SaveOption(OPT_FILEFILTER_CURRENT, filter);
        }
  
 -      InitializeSourceControlMembers();
+       UpdateCodepageModule();
++      if (m_pSourceControl)
++              m_pSourceControl->InitializeSourceControlMembers();
++
+       g_bUnpackerMode = theApp.GetProfileInt(_T("Settings"), _T("UnpackerMode"), PLUGIN_MANUAL);
+       g_bPredifferMode = theApp.GetProfileInt(_T("Settings"), _T("PredifferMode"), PLUGIN_MANUAL);
+       if (m_pSyntaxColors)
+               Options::SyntaxColors::Load(m_pSyntaxColors.get());
+       if (m_pLineFilters)
+               m_pLineFilters->Initialize(GetOptionsMgr());
+       // If there are no filters loaded, and there is filter string in previous
+       // option string, import old filters to new place.
+       if (m_pLineFilters->GetCount() == 0)
+       {
+               String oldFilter = theApp.GetProfileString(_T("Settings"), _T("RegExps"));
+               if (!oldFilter.empty())
+                       m_pLineFilters->Import(oldFilter);
+       }
+       // Check if filter folder is set, and create it if not
+       String pathMyFolders = GetOptionsMgr()->GetString(OPT_FILTER_USERPATH);
+       if (pathMyFolders.empty())
+       {
+               // No filter path, set it to default and make sure it exists.
+               String pathFilters = GetDefaultFilterUserPath(TRUE);
+               GetOptionsMgr()->SaveOption(OPT_FILTER_USERPATH, pathFilters);
+               theApp.m_pGlobalFileFilter->SetFileFilterPath(pathFilters.c_str());
+       }
+       sd_Init(); // String diff init
+       sd_SetBreakChars(GetOptionsMgr()->GetString(OPT_BREAK_SEPARATORS).c_str());
        CSplashWnd::EnableSplashScreen(!bDisableSplash && !bCommandLineInvoke);
  
        // Initialize i18n (multiple language) support
        return bContinue;
  }
  
-       GetMainFrame()->OpenFileToExternalEditor(paths_ConcatPath(env_GetProgPath(), ContributorsPath));
 +static void OpenContributersFile(int&)
 +{
++      theApp.OpenFileToExternalEditor(paths_ConcatPath(env_GetProgPath(), ContributorsPath));
 +}
 +
  // App command to run the dialog
  void CMergeApp::OnAppAbout()
  {
@@@ -742,7 -802,385 +810,385 @@@ void CMergeApp::UpdateCodepageModule(
  /** @brief Open help from mainframe when user presses F1*/
  void CMergeApp::OnHelp()
  {
-       GetMainFrame()->ShowHelp();
+       ShowHelp();
+ }
+ /**
+  * @brief Open given file to external editor specified in options.
+  * @param [in] file Full path to file to open.
+  *
+  * Opens file to defined (in Options/system), Notepad by default,
+  * external editor. Path is decorated with quotation marks if needed
+  * (contains spaces). Also '$file' in editor path is replaced by
+  * filename to open.
+  * @param [in] file Full path to file to open.
+  * @param [in] nLineNumber Line number to go to.
+  */
+ void CMergeApp::OpenFileToExternalEditor(const String& file, int nLineNumber/* = 1*/)
+ {
+       String sCmd = GetOptionsMgr()->GetString(OPT_EXT_EDITOR_CMD);
+       String sFile(file);
 -      string_replace(sCmd, _T("$linenum"), string_format(_T("%d"), nLineNumber));
++      string_replace(sCmd, _T("$linenum"), string_to_str(nLineNumber));
+       int nIndex = sCmd.find(_T("$file"));
+       if (nIndex > -1)
+       {
+               sFile.insert(0, _T("\""));
+               string_replace(sCmd, _T("$file"), sFile);
+               nIndex = sCmd.find(' ', nIndex + sFile.length());
+               if (nIndex > -1)
+                       sCmd.insert(nIndex, _T("\""));
+               else
+                       sCmd += '"';
+       }
+       else
+       {
+               sCmd += _T(" \"");
+               sCmd += sFile;
+               sCmd += _T("\"");
+       }
+       BOOL retVal = FALSE;
+       STARTUPINFO stInfo = {0};
+       stInfo.cb = sizeof(STARTUPINFO);
+       PROCESS_INFORMATION processInfo;
+       retVal = CreateProcess(NULL, (LPTSTR)sCmd.c_str(),
+               NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL,
+               &stInfo, &processInfo);
+       if (!retVal)
+       {
+               // Error invoking external editor
 -              ResMsgBox1(IDS_ERROR_EXECUTE_FILE, sCmd.c_str(), MB_ICONSTOP);
++              String msg = string_format_string1(_("Failed to execute external editor: %1"), sCmd);
++              AfxMessageBox(msg.c_str(), MB_ICONSTOP);
+       }
+       else
+       {
+               CloseHandle(processInfo.hThread);
+               CloseHandle(processInfo.hProcess);
+       }
+ }
+ /**
+  * @brief Open file, if it exists, else open url
+  */
+ void CMergeApp::OpenFileOrUrl(LPCTSTR szFile, LPCTSTR szUrl)
+ {
+       if (paths_DoesPathExist(szFile) == IS_EXISTING_FILE)
+               ShellExecute(NULL, _T("open"), _T("notepad.exe"), szFile, NULL, SW_SHOWNORMAL);
+       else
+               ShellExecute(NULL, _T("open"), szUrl, NULL, NULL, SW_SHOWNORMAL);
+ }
+ /**
+  * @brief Show Help - this is for opening help from outside mainframe.
+  * @param [in] helpLocation Location inside help, if NULL main help is opened.
+  */
+ void CMergeApp::ShowHelp(LPCTSTR helpLocation /*= NULL*/)
+ {
+       String sPath = env_GetProgPath();
+       LANGID LangId = GetLangId();
+       if (PRIMARYLANGID(LangId) == LANG_JAPANESE)
 -              sPath += DocsPath_ja;
++              sPath = paths_ConcatPath(sPath, DocsPath_ja);
+       else
 -              sPath += DocsPath;
++              sPath = paths_ConcatPath(sPath, DocsPath);
+       if (helpLocation == NULL)
+       {
+               if (paths_DoesPathExist(sPath) == IS_EXISTING_FILE)
+                       ::HtmlHelp(NULL, sPath.c_str(), HH_DISPLAY_TOC, NULL);
+               else
+                       ShellExecute(NULL, _T("open"), DocsURL, NULL, NULL, SW_SHOWNORMAL);
+       }
+       else
+       {
+               if (paths_DoesPathExist(sPath) == IS_EXISTING_FILE)
+               {
+                       sPath += helpLocation;
+                       ::HtmlHelp(NULL, sPath.c_str(), HH_DISPLAY_TOPIC, NULL);
+               }
+       }
+ }
+ /**
+  * @brief Creates backup before file is saved or copied over.
+  * This function handles formatting correct path and filename for
+  * backup file. Formatting is done based on several options available
+  * for users in Options/Backups dialog. After path is formatted, file
+  * is simply just copied. Not much error checking, just if copying
+  * succeeded or failed.
+  * @param [in] bFolder Are we creating backup in folder compare?
+  * @param [in] pszPath Full path to file to backup.
+  * @return TRUE if backup succeeds, or isn't just done.
+  */
+ BOOL CMergeApp::CreateBackup(BOOL bFolder, const String& pszPath)
+ {
+       // If user doesn't want to backups in folder compare, return
+       // success so operations don't abort.
+       if (bFolder && !(GetOptionsMgr()->GetBool(OPT_BACKUP_FOLDERCMP)))
+               return TRUE;
+       // Likewise if user doesn't want backups in file compare
+       else if (!bFolder && !(GetOptionsMgr()->GetBool(OPT_BACKUP_FILECMP)))
+               return TRUE;
+       // create backup copy of file if destination file exists
+       if (paths_DoesPathExist(pszPath) == IS_EXISTING_FILE)
+       {
+               String bakPath;
+               String path;
+               String filename;
+               String ext;
+       
+               paths_SplitFilename(pszPath, &path, &filename, &ext);
+               // Determine backup folder
+               if (GetOptionsMgr()->GetInt(OPT_BACKUP_LOCATION) ==
+                       PropBackups::FOLDER_ORIGINAL)
+               {
+                       // Put backups to same folder than original file
+                       bakPath = path;
+               }
+               else if (GetOptionsMgr()->GetInt(OPT_BACKUP_LOCATION) ==
+                       PropBackups::FOLDER_GLOBAL)
+               {
+                       // Put backups to global folder defined in options
+                       bakPath = GetOptionsMgr()->GetString(OPT_BACKUP_GLOBALFOLDER);
+                       if (bakPath.empty())
+                               bakPath = path;
+                       else
+                               bakPath = paths_GetLongPath(bakPath);
+               }
+               else
+               {
+                       _RPTF0(_CRT_ERROR, "Unknown backup location!");
+               }
+               BOOL success = FALSE;
+               if (GetOptionsMgr()->GetBool(OPT_BACKUP_ADD_BAK))
+               {
+                       // Don't add dot if there is no existing extension
+                       if (ext.size() > 0)
+                               ext += _T(".");
+                       ext += BACKUP_FILE_EXT;
+               }
+               // Append time to filename if wanted so
+               // NOTE just adds timestamp at the moment as I couldn't figure out
+               // nice way to add a real time (invalid chars etc).
+               if (GetOptionsMgr()->GetBool(OPT_BACKUP_ADD_TIME))
+               {
+                       struct tm *tm;
+                       time_t curtime = 0;
+                       time(&curtime);
+                       tm = localtime(&curtime);
+                       CString timestr;
+                       timestr.Format(_T("%04d%02d%02d%02d%02d%02d"), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+                       filename += _T("-");
+                       filename += timestr;
+               }
+               // Append filename and extension (+ optional .bak) to path
+               if ((bakPath.length() + filename.length() + ext.length())
+                       < MAX_PATH)
+               {
+                       success = TRUE;
 -                      if (!paths_EndsWithSlash(bakPath))
 -                              bakPath += _T("\\");
+                       bakPath = paths_ConcatPath(bakPath, filename);
+                       bakPath += _T(".");
+                       bakPath += ext;
+               }
+               if (success)
+                       success = CopyFile(pszPath.c_str(), bakPath.c_str(), FALSE);
+               
+               if (!success)
+               {
 -                      if (ResMsgBox1(IDS_BACKUP_FAILED_PROMPT, pszPath.c_str(),
 -                                      MB_YESNO | MB_ICONWARNING | MB_DONT_ASK_AGAIN, 
 -                                      IDS_BACKUP_FAILED_PROMPT) != IDYES)
++                      String msg = string_format_string1(
++                              _("Unable to backup original file:\n%1\n\nContinue anyway?"),
++                              pszPath);
++                      if (AfxMessageBox(msg.c_str(), MB_YESNO | MB_ICONWARNING | MB_DONT_ASK_AGAIN) != IDYES)
+                               return FALSE;
+               }
+               return TRUE;
+       }
+       // we got here because we're either not backing up of there was nothing to backup
+       return TRUE;
+ }
+ /**
+  * @brief Sync file to Version Control System
+  * @param pszDest [in] Where to copy (incl. filename)
+  * @param bApplyToAll [in,out] Apply user selection to all items
+  * @param psError [out] Error string that can be shown to user in caller func
+  * @return User selection or -1 if error happened
+  * @sa CMainFrame::HandleReadonlySave()
+  * @sa CDirView::PerformActionList()
+  */
+ int CMergeApp::SyncFileToVCS(const String& pszDest, BOOL &bApplyToAll,
+       String& sError)
+ {
+       String sActionError;
+       String strSavePath(pszDest);
+       int nVerSys = 0;
+       nVerSys = GetOptionsMgr()->GetInt(OPT_VCS_SYSTEM);
+       
+       int nRetVal = HandleReadonlySave(strSavePath, TRUE, bApplyToAll);
+       if (nRetVal == IDCANCEL || nRetVal == IDNO)
+               return nRetVal;
+       
+       // If VC project opened from VSS sync and version control used
 -      if ((nVerSys == VCS_VSS4 || nVerSys == VCS_VSS5) && m_bVCProjSync)
++      if ((nVerSys == SourceControl::VCS_VSS4 || nVerSys == SourceControl::VCS_VSS5) && m_pSourceControl->m_bVCProjSync)
+       {
 -              if (!m_pVssHelper->ReLinkVCProj(strSavePath, sError))
++              if (!m_pSourceControl->m_vssHelper.ReLinkVCProj(strSavePath, sError))
+                       nRetVal = -1;
+       }
+       return nRetVal;
+ }
+ /**
+  * @brief Checks if path (file/folder) is read-only and asks overwriting it.
+  *
+  * @param strSavePath [in,out] Path where to save (file or folder)
+  * @param bMultiFile [in] Single file or multiple files/folder
+  * @param bApplyToAll [in,out] Apply last user selection for all items?
+  * @return Users selection:
+  * - IDOK: Item was not readonly, no actions
+  * - IDYES/IDYESTOALL: Overwrite readonly item
+  * - IDNO: User selected new filename (single file) or user wants to skip
+  * - IDCANCEL: Cancel operation
+  * @sa CMainFrame::SyncFileToVCS()
+  * @sa CMergeDoc::DoSave()
+  */
+ int CMergeApp::HandleReadonlySave(String& strSavePath, BOOL bMultiFile,
+               BOOL &bApplyToAll)
+ {
+       CFileStatus status;
+       UINT userChoice = 0;
+       int nRetVal = IDOK;
+       BOOL bFileRO = FALSE;
+       BOOL bFileExists = FALSE;
+       String s;
+       String str;
+       CString title;
+       int nVerSys = 0;
+       try
+       {
+               TFile file(strSavePath);
+               bFileExists = file.exists();
+               if (bFileExists)
+                       bFileRO = !file.canWrite();
+       }
+       catch (...)
+       {
+       }
+       nVerSys = GetOptionsMgr()->GetInt(OPT_VCS_SYSTEM);
+       
+       if (bFileExists && bFileRO)
+       {
+               // Version control system used?
+               // Checkout file from VCS and modify, don't ask about overwriting
+               // RO files etc.
 -              if (nVerSys != VCS_NONE)
++              if (nVerSys != SourceControl::VCS_NONE)
+               {
 -                      BOOL bRetVal = SaveToVersionControl(strSavePath);
++                      bool bRetVal = m_pSourceControl->SaveToVersionControl(strSavePath);
+                       if (bRetVal)
+                               return IDYES;
+                       else
+                               return IDCANCEL;
+               }
+               
+               // Don't ask again if its already asked
+               if (bApplyToAll)
+                       userChoice = IDYES;
+               else
+               {
+                       // Prompt for user choice
+                       if (bMultiFile)
+                       {
+                               // Multiple files or folder
 -                              str = LangFormatString1(IDS_SAVEREADONLY_MULTI, strSavePath.c_str());
++                              str = string_format_string1(_("%1\nis marked read-only. Would you like to override the read-only item?"), strSavePath);
+                               userChoice = AfxMessageBox(str.c_str(), MB_YESNOCANCEL |
+                                               MB_ICONWARNING | MB_DEFBUTTON3 | MB_DONT_ASK_AGAIN |
+                                               MB_YES_TO_ALL, IDS_SAVEREADONLY_MULTI);
+                       }
+                       else
+                       {
+                               // Single file
 -                              str = LangFormatString1(IDS_SAVEREADONLY_FMT, strSavePath.c_str());
++                              str = string_format_string1(_("%1 is marked read-only. Would you like to override the read-only file ? (No to save as new filename.)"), strSavePath);
+                               userChoice = AfxMessageBox(str.c_str(), MB_YESNOCANCEL |
+                                               MB_ICONWARNING | MB_DEFBUTTON2 | MB_DONT_ASK_AGAIN,
+                                               IDS_SAVEREADONLY_FMT);
+                       }
+               }
+               switch (userChoice)
+               {
+               // Overwrite read-only file
+               case IDYESTOALL:
+                       bApplyToAll = TRUE;  // Don't ask again (no break here)
+               case IDYES:
+                       CFile::GetStatus(strSavePath.c_str(), status);
+                       status.m_mtime = 0;             // Avoid unwanted changes
+                       status.m_attribute &= ~CFile::readOnly;
+                       CFile::SetStatus(strSavePath.c_str(), status);
+                       nRetVal = IDYES;
+                       break;
+               
+               // Save to new filename (single) /skip this item (multiple)
+               case IDNO:
+                       if (!bMultiFile)
+                       {
 -                              if (SelectFile(AfxGetMainWnd()->GetSafeHwnd(), s, strSavePath.c_str(), IDS_SAVE_AS_TITLE, NULL, FALSE))
++                              if (SelectFile(AfxGetMainWnd()->GetSafeHwnd(), s, strSavePath.c_str(), _("Save As"), _T(""), FALSE))
+                               {
+                                       strSavePath = s;
+                                       nRetVal = IDNO;
+                               }
+                               else
+                                       nRetVal = IDCANCEL;
+                       }
+                       else
+                               nRetVal = IDNO;
+                       break;
+               // Cancel saving
+               case IDCANCEL:
+                       nRetVal = IDCANCEL;
+                       break;
+               }
+       }
+       return nRetVal;
+ }
+ /**
+  * @brief Shows VSS error from exception and writes log.
+  */
+ void CMergeApp::ShowVSSError(CException *e, const String& strItem)
+ {
+       TCHAR errStr[1024] = {0};
+       if (e->GetErrorMessage(errStr, 1024))
+       {
+               String errMsg = theApp.LoadString(IDS_VSS_ERRORFROM);
+               String logMsg = errMsg;
+               errMsg += _T("\n");
+               errMsg += errStr;
+               logMsg += _T(" ");
+               logMsg += errStr;
+               if (!strItem.empty())
+               {
+                       errMsg += _T("\n\n");
+                       errMsg += strItem;
+                       logMsg += _T(": ");
+                       logMsg += strItem;
+               }
+               LogErrorString(logMsg);
+               AfxMessageBox(errMsg.c_str(), MB_ICONSTOP);
+       }
+       else
+       {
+               LogErrorString(_T("VSSError (unable to GetErrorMessage)"));
+               e->ReportError(MB_ICONSTOP, IDS_VSS_RUN_ERROR);
+       }
  }
  
  /**
diff --cc Src/Merge.h
@@@ -47,6 -44,10 +44,10 @@@ class CMainFrame
  class CLanguageSelect;
  class MergeCmdLineInfo;
  class ProjectFile;
 -class VSSHelper;
+ class COptionsMgr;
+ class LineFiltersList;
+ class SyntaxColors;
++class SourceControl;
  
  /////////////////////////////////////////////////////////////////////////////
  // CMergeApp:
  
  enum { IDLE_TIMER = 9754 };
  
- /** 
+ /**
 - * @brief Supported versioncontrol systems.
 - */
 -enum
 -{
 -      VCS_NONE = 0,
 -      VCS_VSS4,
 -      VCS_VSS5,
 -      VCS_CLEARCASE,
 -};
 -
 -/** 
   * @brief WinMerge application class
   */
  class CMergeApp : public CWinApp
@@@ -67,7 -79,42 +68,26 @@@ public
        CMultiDocTemplate* m_pHexMergeTemplate;
        CMultiDocTemplate* m_pDirTemplate;
        boost::scoped_ptr<CLanguageSelect> m_pLangDlg;
-       FileFilterHelper m_globalFileFilter;
+       boost::scoped_ptr<FileFilterHelper> m_pGlobalFileFilter;
+       boost::scoped_ptr<SyntaxColors> m_pSyntaxColors; /**< Syntax color container */
 -      boost::scoped_ptr<VSSHelper> m_pVssHelper; /**< Helper class for VSS integration */
++      boost::scoped_ptr<SourceControl> m_pSourceControl;
+       CString m_strSaveAsPath; /**< "3rd path" where output saved if given */
+       BOOL m_bEscShutdown; /**< If commandline switch -e given ESC closes appliction */
+       SyntaxColors * GetMainSyntaxColors() { return m_pSyntaxColors.get(); }
+       BOOL m_bClearCaseTool; /**< WinMerge is executed as an external Rational ClearCase compare/merge tool. */
+       MergeCmdLineInfo::ExitNoDiff m_bExitIfNoDiff; /**< Exit if files are identical? */
+       boost::scoped_ptr<LineFiltersList> m_pLineFilters; /**< List of linefilters */
+       /**
 -       * @name Version Control System (VCS) integration.
 -       */
 -      /*@{*/ 
 -protected:
 -      CString m_strVssUser; /**< Visual Source Safe User ID */
 -      CString m_strVssPassword; /**< Visual Source Safe Password */
 -      CString m_strVssDatabase; /**< Visual Source Safe database */
 -      CString m_strCCComment; /**< ClearCase comment */
 -public:
 -      BOOL m_bCheckinVCS;     /**< TRUE if files should be checked in after checkout */
 -      BOOL m_CheckOutMulti; /**< Suppresses VSS int. code asking checkout for every file */
 -      BOOL m_bVCProjSync; /**< VC project opened from VSS sync? */
 -      BOOL m_bVssSuppressPathCheck; /**< Suppresses VSS int code asking about different path */
 -      /*@}*/
 -
 -      /**
+        * @name Textual labels/descriptors
+        * These descriptors overwrite dir/filename usually shown in headerbar
+        * and can be given from command-line. For example version control
+        * system can set these to "WinMerge v2.1.2.0" and "WinMerge 2.1.4.0"
+        * which is more pleasant and informative than temporary paths.
+        */
+       /*@{*/ 
+       String m_strDescriptions[3];
+       /*@}*/
  
        WORD GetLangId() const;
        void SetIndicators(CStatusBar &, const UINT *, int) const;
@@@ -91,6 -138,18 +112,14 @@@ public
        void OptionsInit();
        void ResetOptions() { OptionsInit(); }
        void SetFontDefaults();
 -// Implementation in SourceControl.cpp
 -      void InitializeSourceControlMembers();
 -      BOOL SaveToVersionControl(const String& strSavePath);
 -// End SourceControl.cpp
+       void ShowHelp(LPCTSTR helpLocation = NULL);
+       void OpenFileToExternalEditor(const String& file, int nLineNumber = 1);
+       void OpenFileOrUrl(LPCTSTR szFile, LPCTSTR szUrl);
+       void ShowVSSError(CException *e, const String& strItem);
+       void CheckinToClearCase(const String& strDestinationPath);
+       BOOL CreateBackup(BOOL bFolder, const String& pszPath);
+       int HandleReadonlySave(String& strSavePath, BOOL bMultiFile, BOOL &bApplyToAll);
+       BOOL SyncFileToVCS(const String& pszDest,       BOOL &bApplyToAll, String& psError);
  
  // Implementation
  protected:
@@@ -1,10 -1,7 +1,11 @@@
  #include "StdAfx.h"
  #include "MergeApp.h"
  #include "Merge.h"
 +#include "version.h"
 +#include "paths.h"
 +#include "Environment.h"
 +#include "Constants.h"
+ #include "unicoder.h"
  
  // Get user language description of error, if available
  String GetSysError(int nerr /* =-1 */)
diff --cc Src/MergeApp.h
@@@ -3,20 -3,9 +3,21 @@@
  
  #include "UnicodeString.h"
  
 +#define _(x) tr(x)
 +#define N_(x) (x)
 +
  class COptionsMgr;
+ class FileFilterHelper;
  
 +struct AboutInfo
 +{
 +      AboutInfo();
 +      String copyright;
 +      String version;
 +      String private_build;
 +      String website;
 +};
 +
  /** @brief Retrieve error description from Windows; uses FormatMessage */
  String GetSysError(int nerr = -1);
  
  // $Id: MergeDoc.cpp 7107 2010-01-14 21:43:14Z kimmov $
  
  #include "StdAfx.h"
+ #include "MergeDoc.h"
  #include <shlwapi.h>          // PathCompactPathEx()
  #include <io.h>
++#include <boost/cstdint.hpp>
  #include <Poco/Timestamp.h>
+ #include <Poco/Exception.h>
  #include "UnicodeString.h"
  #include "Merge.h"
  #include "MainFrm.h"
@@@ -1357,14 -1349,16 +1358,14 @@@ bool CMergeDoc::DoSave(LPCTSTR szPath, 
                        // third arg was a directory, so get append the filename
                        String sname;
                        paths_SplitFilename(szPath, 0, &sname, 0);
-                       strSavePath = GetMainFrame()->m_strSaveAsPath;
+                       strSavePath = theApp.m_strSaveAsPath;
 -                      if (theApp.m_strSaveAsPath.Right(1) != _T('\\'))
 -                              strSavePath += _T('\\');
 -                      strSavePath += sname;
 +                      strSavePath = paths_ConcatPath(strSavePath, sname);
                }
                else
-                       strSavePath = GetMainFrame()->m_strSaveAsPath;  
+                       strSavePath = theApp.m_strSaveAsPath;   
        }
  
-       nRetVal = GetMainFrame()->HandleReadonlySave(strSavePath, false, bApplyToAll);
+       nRetVal = theApp.HandleReadonlySave(strSavePath, false, bApplyToAll);
        if (nRetVal == IDCANCEL)
                return false;
  
@@@ -2194,34 -2188,34 +2195,34 @@@ bool CMergeDoc::PromptAndSaveIfNeeded(b
                dlg.m_bDisableCancel = true;
        if (!m_filePaths.GetLeft().empty())
        {
-               if (GetMainFrame()->m_strSaveAsPath.IsEmpty())
+               if (theApp.m_strSaveAsPath.IsEmpty())
 -                      dlg.m_sLeftFile = m_filePaths.GetLeft().c_str();
 +                      dlg.m_sLeftFile = m_filePaths.GetLeft();
                else
-                       dlg.m_sLeftFile = GetMainFrame()->m_strSaveAsPath;
+                       dlg.m_sLeftFile = theApp.m_strSaveAsPath;
        }
        else
 -              dlg.m_sLeftFile = m_strDesc[0].c_str();
 +              dlg.m_sLeftFile = m_strDesc[0];
        if (m_nBuffers == 3)
        {
                if (!m_filePaths.GetMiddle().empty())
                {
-                       if (GetMainFrame()->m_strSaveAsPath.IsEmpty())
+                       if (theApp.m_strSaveAsPath.IsEmpty())
 -                              dlg.m_sMiddleFile = m_filePaths.GetMiddle().c_str();
 +                              dlg.m_sMiddleFile = m_filePaths.GetMiddle();
                        else
-                               dlg.m_sMiddleFile = GetMainFrame()->m_strSaveAsPath;
+                               dlg.m_sMiddleFile = theApp.m_strSaveAsPath;
                }
                else
 -                      dlg.m_sMiddleFile = m_strDesc[1].c_str();
 +                      dlg.m_sMiddleFile = m_strDesc[1];
        }
        if (!m_filePaths.GetRight().empty())
        {
-               if (GetMainFrame()->m_strSaveAsPath.IsEmpty())
+               if (theApp.m_strSaveAsPath.IsEmpty())
 -                      dlg.m_sRightFile = m_filePaths.GetRight().c_str();
 +                      dlg.m_sRightFile = m_filePaths.GetRight();
                else
-                       dlg.m_sRightFile = GetMainFrame()->m_strSaveAsPath;
+                       dlg.m_sRightFile = theApp.m_strSaveAsPath;
        }
        else
 -              dlg.m_sRightFile = m_strDesc[m_nBuffers - 1].c_str();
 +              dlg.m_sRightFile = m_strDesc[m_nBuffers - 1];
  
        if (dlg.DoModal() == IDOK)
        {
@@@ -3276,7 -3311,7 +3277,7 @@@ void CMergeDoc::OnToolsGenerateReport(
        String s;
        CString folder;
  
-       if (!SelectFile(GetMainFrame()->GetSafeHwnd(), s, folder, _("Save As"), _("HTML Files (*.htm,*.html)|*.htm;*.html|All Files (*.*)|*.*||"), false, _T("htm")))
 -      if (!SelectFile(AfxGetMainWnd()->GetSafeHwnd(), s, folder, IDS_SAVE_AS_TITLE, IDS_HTML_REPORT_FILES, false, _T("htm")))
++      if (!SelectFile(AfxGetMainWnd()->GetSafeHwnd(), s, folder, _("Save As"), _("HTML Files (*.htm,*.html)|*.htm;*.html|All Files (*.*)|*.*||"), false, _T("htm")))
                return;
  
        GenerateReport(s.c_str());
Simple merge
Simple merge
Simple merge
@@@ -847,10 -851,10 +848,10 @@@ void COpenView::SetUnpackerStatus(UINT 
   */
  void COpenView::OnSelectFilter()
  {
 -      String filterPrefix = theApp.LoadString(IDS_FILTER_PREFIX);
 +      String filterPrefix = _("[F] ");
        CString curFilter;
  
-       const BOOL bUseMask = theApp.m_globalFileFilter.IsUsingMask();
+       const BOOL bUseMask = theApp.m_pGlobalFileFilter->IsUsingMask();
        GetDlgItemText(IDC_EXT_COMBO, curFilter);
        curFilter.TrimLeft();
        curFilter.TrimRight();
Simple merge
Simple merge
Simple merge
diff --cc Src/PatchTool.h
Simple merge
diff --cc Src/Plugins.cpp
Simple merge
Simple merge
  #include "MainFrm.h"
  #include "paths.h"
  #include "OptionsDef.h"
+ #include "OptionsMgr.h"
  #include "ProjectFile.h"
- #include "ProjectFilePathsDlg.h"
  #include "FileOrFolderSelect.h"
+ #include "FileFilterHelper.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
@@@ -107,10 -108,10 +109,10 @@@ void ProjectFilePathsDlg::OnBnClickedPr
   */
  void ProjectFilePathsDlg::OnBnClickedProjFilterSelect()
  {
 -      String filterPrefix = theApp.LoadString(IDS_FILTER_PREFIX);
 +      String filterPrefix = _("[F] ");
        CString curFilter;
  
-       const BOOL bUseMask = theApp.m_globalFileFilter.IsUsingMask();
+       const BOOL bUseMask = theApp.m_pGlobalFileFilter->IsUsingMask();
        GetDlgItemText(IDC_PROJ_FILTER_EDIT, curFilter);
        curFilter.TrimLeft();
        curFilter.TrimRight();
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc Src/PropVss.cpp
Simple merge
@@@ -23,9 -23,8 +23,9 @@@
  // $Id: SaveClosingDlg.cpp 4704 2007-11-03 12:10:48Z jtuc $
  
  #include "stdafx.h"
- #include "Merge.h"
  #include "SaveClosingDlg.h"
+ #include "Merge.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
  //
  
  #include "stdafx.h"
- #include "merge.h"
  #include "SelectUnpackerDlg.h"
+ #include "Merge.h"
  #include "Plugins.h"
  #include "FileTransform.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
@@@ -30,7 -30,7 +30,8 @@@
  #define AFX_SELECTUNPACKERDLG_H__C8FD4C3A_5ED5_43D3_ADAE_A2378369705C__INCLUDED_
  
  #include <vector>
 +#include "UnicodeString.h"
+ #include <boost/scoped_ptr.hpp>
  
  /////////////////////////////////////////////////////////////////////////////
  // CSelectUnpackerDlgDlg dialog
Simple merge
diff --cc Src/Splash.cpp
Simple merge
@@@ -10,9 -11,7 +11,8 @@@
  #include "Merge.h"
  #include "resource.h"
  #include "UnicodeString.h"
- #include "TestFilterDlg.h"
  #include "FileFilterMgr.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
Simple merge
@@@ -24,8 -24,7 +24,8 @@@
  
  #include "stdafx.h"
  #include "WMGotoDlg.h"
- #include "merge.h"
+ #include "Merge.h"
 +#include "DDXHelper.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
diff --cc Src/paths.cpp
Simple merge