// 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
/////////////////////////////////////////////////////////////////////////////
// Look at http://www.codeproject.com/shell/ for excellent guide
// to Windows Shell programming by Michael Dunn.
-//
+//
// This extension needs two registry values to be defined:
// HKEY_CURRENT_USER\Software\Thingamahoochie\WinMerge\ContextMenuEnabled
// defines if context menu is shown (extension enabled) and if
// overwrites 'Executable' if defined. Useful to overwrite
// option set from UI when debugging/testing.
/////////////////////////////////////////////////////////////////////////////
-/**
+/**
* @file WinMergeShell.cpp
*
* @brief Implementation of the ShellExtension class
*/
-// RCS ID line follows -- this is updated by CVS
-// $Id$
+// ID line follows -- this is updated by SVN
+// $Id: WinMergeShell.cpp 6933 2009-07-26 14:07:03Z kimmov $
#include "stdafx.h"
#include "ShellExtension.h"
#include "WinMergeShell.h"
+#include "UnicodeString.h"
#include "RegKey.h"
-#include "coretools.h"
#include <sys/types.h>
#include <sys/stat.h>
-/// Flags for enabling and mode of extension
-#define EXT_ENABLED 0x01
-#define EXT_ADVANCED 0x02
+/**
+ * @brief Flags for enabling and other settings of context menu.
+ */
+enum ExtensionFlags
+{
+ EXT_ENABLED = 0x01, /**< ShellExtension enabled/disabled. */
+ EXT_ADVANCED = 0x02, /**< Advanced menuitems enabled/disabled. */
+};
/// Max. filecount to select
-static const int MaxFileCount = 2;
-/// Registry path to WinMerge
+static const int MaxFileCount = 3;
+/// Registry path to WinMerge
#define REGDIR _T("Software\\Thingamahoochie\\WinMerge")
static const TCHAR f_RegDir[] = REGDIR;
static const TCHAR f_RegLocaleDir[] = REGDIR _T("\\Locale");
+static const TCHAR f_RegSettingsDir[] = REGDIR _T("\\Settings");
/**
* @name Registry valuenames.
*/
-/*@{*/
+/*@{*/
/** Shell context menuitem enabled/disabled */
static const TCHAR f_RegValueEnabled[] = _T("ContextMenuEnabled");
/** 'Saved' path in advanced mode */
static const TCHAR f_RegValuePriPath[] = _T("PriExecutable");
/** LanguageId */
static const TCHAR f_LanguageId[] = _T("LanguageId");
+/** Recurse */
+static const TCHAR f_Recurse[] = _T("Recurse");
/*@}*/
-/// Shown menustate
+/**
+ * @brief The states in which the menu can be.
+ * These states define what items are added to the menu and how those
+ * items work.
+ */
enum
{
- MENU_SIMPLE = 0,
- MENU_ONESEL_NOPREV,
- MENU_ONESEL_PREV,
- MENU_TWOSEL,
+ MENU_SIMPLE = 0, /**< Simple menu, only "Compare item" is shown. */
+ MENU_ONESEL_NOPREV, /**< One item selected, no previous selections. */
+ MENU_ONESEL_PREV, /**< One item selected, previous selection exists. */
+ MENU_TWOSEL, /**< Two items are selected. */
+ MENU_THREESEL
};
#define USES_WINMERGELOCALE CWinMergeTempLocale __wmtl__
+static String GetResourceString(UINT resourceID);
+
class CWinMergeTempLocale
{
private:
LCID m_lcidOld;
public:
- CWinMergeTempLocale() {
+ CWinMergeTempLocale()
+ {
CRegKeyEx reg;
if (reg.Open(HKEY_CURRENT_USER, f_RegLocaleDir) != ERROR_SUCCESS)
return;
int iLangId = reg.ReadDword(f_LanguageId, (DWORD)-1);
if (iLangId != -1)
+ {
SetThreadLocale(MAKELCID(iLangId, SORT_DEFAULT));
+ SetThreadUILanguage(iLangId);
+ }
}
- ~CWinMergeTempLocale() {
+ ~CWinMergeTempLocale()
+ {
SetThreadLocale(m_lcidOld);
+ SetThreadUILanguage(LANGIDFROMLCID(m_lcidOld));
}
};
+/**
+ * @brief Load a string from resource.
+ * @param [in] Resource string ID.
+ * @return String loaded from resource.
+ */
+static String GetResourceString(UINT resourceID)
+{
+ TCHAR resStr[1024] = {0};
+ int res = LoadString(_Module.GetModuleInstance(), resourceID, resStr, 1024);
+ ATLASSERT(res != 0);
+ String strResource = resStr;
+ return strResource;
+}
+
+static HBITMAP MakeBitmapBackColorTransparent(HBITMAP hbmSrc)
+{
+ HDC hdcSrc = CreateCompatibleDC(NULL);
+ BITMAP bm;
+ GetObject(hbmSrc, sizeof(bm), &bm);
+ HBITMAP hbmSrcOld = (HBITMAP)SelectObject(hdcSrc, hbmSrc);
+ BITMAPINFO bi = {0};
+ bi.bmiHeader.biSize = sizeof BITMAPINFOHEADER;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = 32;
+ bi.bmiHeader.biCompression = BI_RGB;
+ bi.bmiHeader.biWidth = bm.bmWidth;
+ bi.bmiHeader.biHeight = -bm.bmHeight;
+ DWORD *pBits = NULL;
+ HBITMAP hbmNew = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
+ if (pBits)
+ {
+ COLORREF clrTP = GetPixel(hdcSrc, 0, 0);
+ int bR = GetRValue(clrTP), bG = GetGValue(clrTP), bB = GetBValue(clrTP);
+
+ for (int y = 0; y < bm.bmHeight; ++y)
+ {
+ for (int x = 0; x < bm.bmWidth; ++x)
+ {
+ COLORREF clrCur = GetPixel(hdcSrc, x, y);
+ int cR = GetRValue(clrCur), cG = GetGValue(clrCur), cB = GetBValue(clrCur);
+ if (!(abs(cR - bR) <= 1 && abs(cG - bG) <= 1 && abs(cB - bB) <= 1))
+ {
+ pBits[y * bm.bmWidth + x] = cB | (cG << 8) | (cR << 16) | 0xFF000000;
+ }
+ }
+ }
+ }
+
+ SelectObject(hdcSrc, hbmSrcOld);
+ DeleteDC(hdcSrc);
+
+ return hbmNew;
+}
+
+
/////////////////////////////////////////////////////////////////////////////
// CWinMergeShell
CWinMergeShell::CWinMergeShell()
{
m_dwMenuState = 0;
- m_hMergeBmp = LoadBitmap(_Module.GetModuleInstance(),
- MAKEINTRESOURCE(IDB_WINMERGE));
+ int cx = GetSystemMetrics(SM_CXMENUCHECK);
+ int cy = GetSystemMetrics(SM_CYMENUCHECK);
+ int id_fileicon = cx > 16 ? IDB_WINMERGE32 : IDB_WINMERGE;
+ int id_diricon = cx > 16 ? IDB_WINMERGEDIR32 : IDB_WINMERGEDIR;
+
+ // compress or stretch icon bitmap according to menu item height
+ HBITMAP hMergeBmp = (HBITMAP)LoadImage(_Module.GetModuleInstance(), MAKEINTRESOURCE(id_fileicon), IMAGE_BITMAP,
+ cx, cy, LR_DEFAULTCOLOR);
+ HBITMAP hMergeDirBmp = (HBITMAP)LoadImage(_Module.GetModuleInstance(), MAKEINTRESOURCE(id_diricon), IMAGE_BITMAP,
+ cx, cy, LR_DEFAULTCOLOR);
+
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof OSVERSIONINFO;
+ GetVersionEx(&osvi);
+ if (osvi.dwMajorVersion >= 6)
+ {
+ m_MergeBmp = MakeBitmapBackColorTransparent(hMergeBmp);
+ DeleteObject(hMergeBmp);
+
+ m_MergeDirBmp = MakeBitmapBackColorTransparent(hMergeDirBmp);
+ DeleteObject(hMergeDirBmp);
+ }
+ else
+ {
+ m_MergeBmp = hMergeBmp;
+ m_MergeDirBmp = hMergeDirBmp;
+ }
+}
+
+/// Default destructor, unloads bitmap
+CWinMergeShell::~CWinMergeShell()
+{
+ DeleteObject(m_MergeDirBmp);
+ DeleteObject(m_MergeBmp);
}
/// Reads selected paths
HRESULT CWinMergeShell::Initialize(LPCITEMIDLIST pidlFolder,
LPDATAOBJECT pDataObj, HKEY hProgID)
{
- FORMATETC fmt = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
- STGMEDIUM stg = {TYMED_HGLOBAL};
- HDROP hDropInfo;
USES_WINMERGELOCALE;
+ HRESULT hr = E_INVALIDARG;
- // Look for CF_HDROP data in the data object.
- if (FAILED(pDataObj->GetData(&fmt, &stg)))
- // Nope! Return an "invalid argument" error back to Explorer.
- return E_INVALIDARG;
+ // Files/folders selected normally from the explorer
+ if (pDataObj)
+ {
+ FORMATETC fmt = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ STGMEDIUM stg = {TYMED_HGLOBAL};
+ HDROP hDropInfo;
- // Get a pointer to the actual data.
- hDropInfo = (HDROP) GlobalLock(stg.hGlobal);
+ // Look for CF_HDROP data in the data object.
+ if (FAILED(pDataObj->GetData(&fmt, &stg)))
+ // Nope! Return an "invalid argument" error back to Explorer.
+ return E_INVALIDARG;
- // Make sure it worked.
- if (NULL == hDropInfo)
- return E_INVALIDARG;
+ // Get a pointer to the actual data.
+ hDropInfo = (HDROP) GlobalLock(stg.hGlobal);
- // Sanity check & make sure there is at least one filename.
- UINT uNumFilesDropped = DragQueryFile (hDropInfo, 0xFFFFFFFF, NULL, 0);
- m_nSelectedItems = uNumFilesDropped;
+ // Make sure it worked.
+ if (NULL == hDropInfo)
+ return E_INVALIDARG;
- if (uNumFilesDropped == 0)
- {
- GlobalUnlock(stg.hGlobal);
- ReleaseStgMedium(&stg);
- return E_INVALIDARG;
- }
+ // Sanity check & make sure there is at least one filename.
+ UINT uNumFilesDropped = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0);
+ m_nSelectedItems = uNumFilesDropped;
- HRESULT hr = S_OK;
+ if (uNumFilesDropped == 0)
+ {
+ GlobalUnlock(stg.hGlobal);
+ ReleaseStgMedium(&stg);
+ return E_INVALIDARG;
+ }
- // Get all file names.
- for (WORD x = 0 ; x < uNumFilesDropped; x++)
- {
- // Get the number of bytes required by the file's full pathname
- UINT wPathnameSize = DragQueryFile(hDropInfo, x, NULL, 0);
+ hr = S_OK;
+
+ // Get all file names.
+ for (WORD x = 0 ; x < uNumFilesDropped; x++)
+ {
+ // Get the number of bytes required by the file's full pathname
+ UINT wPathnameSize = DragQueryFile(hDropInfo, x, NULL, 0);
- // Allocate memory to contain full pathname & zero byte
- wPathnameSize += 1;
- LPTSTR npszFile = (TCHAR *) new TCHAR[wPathnameSize];
+ // Allocate memory to contain full pathname & zero byte
+ wPathnameSize += 1;
+ LPTSTR npszFile = (TCHAR *) new TCHAR[wPathnameSize];
- // If not enough memory, skip this one
- if (npszFile == NULL)
- continue;
+ // If not enough memory, skip this one
+ if (npszFile == NULL)
+ continue;
- // Copy the pathname into the buffer
- DragQueryFile(hDropInfo, x, npszFile, wPathnameSize);
+ // Copy the pathname into the buffer
+ DragQueryFile(hDropInfo, x, npszFile, wPathnameSize);
- if (x < MaxFileCount)
- m_strPaths[x] = npszFile;
+ if (x < MaxFileCount)
+ m_strPaths[x] = npszFile;
- delete[] npszFile;
+ delete[] npszFile;
+ }
+ GlobalUnlock(stg.hGlobal);
+ ReleaseStgMedium(&stg);
}
- GlobalUnlock(stg.hGlobal);
- ReleaseStgMedium(&stg);
+ else
+ {
+ m_nSelectedItems = 0;
+ }
+
+ // No item selected - selection is the folder background
+ if (pidlFolder)
+ {
+ TCHAR szPath[MAX_PATH] = {0};
- return hr;
+ if (SHGetPathFromIDList(pidlFolder, szPath))
+ {
+ if (m_nSelectedItems < MaxFileCount)
+ m_strPaths[m_nSelectedItems++] = szPath;
+ hr = S_OK;
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ return hr;
}
/// Adds context menu item
HRESULT CWinMergeShell::QueryContextMenu(HMENU hmenu, UINT uMenuIndex,
UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags)
{
- AFX_MANAGE_STATE(AfxGetStaticModuleState())
int nItemsAdded = 0;
USES_WINMERGELOCALE;
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
m_dwContextMenuEnabled = reg.ReadDword(f_RegValueEnabled, 0);
- m_strPreviousPath = reg.ReadString(f_FirstSelection, _T(""));
+ m_strPreviousPath = reg.ReadString(f_FirstSelection, _T("")).c_str();
if (m_dwContextMenuEnabled & EXT_ENABLED) // Context menu enabled
{
}
else
{
- if (m_nSelectedItems == 1 && m_strPreviousPath.IsEmpty())
+ if (m_nSelectedItems == 1 && m_strPreviousPath.empty())
m_dwMenuState = MENU_ONESEL_NOPREV;
- else if (m_nSelectedItems == 1 && !m_strPreviousPath.IsEmpty())
+ else if (m_nSelectedItems == 1 && !m_strPreviousPath.empty())
m_dwMenuState = MENU_ONESEL_PREV;
else if (m_nSelectedItems == 2)
m_dwMenuState = MENU_TWOSEL;
+ else if (m_nSelectedItems == 3)
+ m_dwMenuState = MENU_THREESEL;
nItemsAdded = DrawAdvancedMenu(hmenu, uMenuIndex, uidFirstCmd);
}
}
/// Gets string shown explorer's status bar when menuitem selected
-HRESULT CWinMergeShell::GetCommandString(UINT idCmd, UINT uFlags,
+HRESULT CWinMergeShell::GetCommandString(UINT_PTR idCmd, UINT uFlags,
UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
- AFX_MANAGE_STATE(AfxGetStaticModuleState())
USES_CONVERSION;
USES_WINMERGELOCALE;
// Check idCmd, it must be 0 in simple mode and 0 or 1 in advanced mode.
- if (m_dwMenuState & EXT_ADVANCED == 0)
+ if ((m_dwMenuState & EXT_ADVANCED) == 0)
{
if (idCmd > 0)
return E_INVALIDARG;
}
else
{
- if (idCmd > 1)
+ if (idCmd > 2)
return E_INVALIDARG;
}
// supplied buffer.
if (uFlags & GCS_HELPTEXT)
{
- CString strHelp;
+ String strHelp;
strHelp = GetHelpText(idCmd);
if (uFlags & GCS_UNICODE)
// We need to cast pszName to a Unicode string, and then use the
// Unicode string copy API.
- lstrcpynW((LPWSTR) pszName, T2CW(strHelp), cchMax);
+ lstrcpynW((LPWSTR) pszName, T2CW(strHelp.c_str()), cchMax);
else
// Use the ANSI string copy API to return the help string.
- lstrcpynA(pszName, T2CA(strHelp), cchMax);
+ lstrcpynA(pszName, T2CA(strHelp.c_str()), cchMax);
return S_OK;
}
/// Runs WinMerge with given paths
HRESULT CWinMergeShell::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo)
{
- AFX_MANAGE_STATE(AfxGetStaticModuleState())
CRegKeyEx reg;
- CString strWinMergePath;
+ String strWinMergePath;
BOOL bCompare = FALSE;
+ BOOL bAlterSubFolders = FALSE;
USES_WINMERGELOCALE;
// If lpVerb really points to a string, ignore this function call and bail out.
if (!GetWinMergeDir(strWinMergePath))
return S_FALSE;
- // Check that file we are trying to execute exists and is executable
- if (!CheckExecutable(strWinMergePath))
+ // Check that file we are trying to execute exists
+ if (!PathFileExists(strWinMergePath.c_str()))
return S_FALSE;
if (LOWORD(pCmdInfo->lpVerb) == 0)
case MENU_ONESEL_NOPREV:
m_strPreviousPath = m_strPaths[0];
if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
- reg.WriteString(f_FirstSelection, m_strPreviousPath);
+ reg.WriteString(f_FirstSelection, m_strPreviousPath.c_str());
break;
case MENU_ONESEL_PREV:
m_strPaths[1] = m_strPaths[0];
m_strPaths[0] = m_strPreviousPath;
bCompare = TRUE;
-
+
// Forget previous selection
if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
reg.WriteString(f_FirstSelection, _T(""));
break;
case MENU_TWOSEL:
+ case MENU_THREESEL:
// "Compare" - compare paths
bCompare = TRUE;
- m_strPreviousPath.Empty();
+ m_strPreviousPath.erase();
break;
}
}
case MENU_ONESEL_PREV:
m_strPreviousPath = m_strPaths[0];
if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
- reg.WriteString(f_FirstSelection, m_strPreviousPath);
+ reg.WriteString(f_FirstSelection, m_strPreviousPath.c_str());
bCompare = FALSE;
break;
default:
// "Compare..." - user wants to compare this single item and open WinMerge
- m_strPaths[1].Empty();
+ m_strPaths[1].erase();
bCompare = TRUE;
break;
}
if (bCompare == FALSE)
return S_FALSE;
- CString strCommandLine = FormatCmdLine(strWinMergePath, m_strPaths[0],
- m_strPaths[1]);
+ if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0)
+ bAlterSubFolders = TRUE;
+
+ String strCommandLine = FormatCmdLine(strWinMergePath, m_strPaths[0],
+ m_strPaths[1], bAlterSubFolders);
+
+ if (!m_strPaths[2].empty())
+ strCommandLine += _T(" \"") + m_strPaths[2] + _T("\"");
// Finally start a new WinMerge process
BOOL retVal = FALSE;
STARTUPINFO stInfo = {0};
stInfo.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION processInfo = {0};
-
- retVal = CreateProcess(NULL, (LPTSTR)(LPCTSTR)strCommandLine,
- NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL,
- &stInfo, &processInfo);
- if (retVal)
- return S_OK;
- else
+ retVal = CreateProcess(NULL, (LPTSTR)strCommandLine.c_str(),
+ NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL,
+ &stInfo, &processInfo);
+
+ if (!retVal)
return S_FALSE;
+
+ CloseHandle(processInfo.hThread);
+ CloseHandle(processInfo.hProcess);
+ return S_OK;
}
/// Reads WinMerge path from registry
-BOOL CWinMergeShell::GetWinMergeDir(CString &strDir)
+BOOL CWinMergeShell::GetWinMergeDir(String &strDir)
{
CRegKeyEx reg;
if (!reg.QueryRegUser(f_RegDir))
return FALSE;
-
+
// Try first reading debug/test value
strDir = reg.ReadString(f_RegValuePriPath, _T(""));
- if (strDir.IsEmpty())
+ if (strDir.empty())
{
strDir = reg.ReadString(f_RegValuePath, _T(""));
- if (strDir.IsEmpty())
+ if (strDir.empty())
return FALSE;
- }
+ }
return TRUE;
}
-/// Checks if given file exists and is executable
-BOOL CWinMergeShell::CheckExecutable(CString path)
-{
- CString ext;
- SplitFilename(path, NULL, NULL, &ext);
-
- // Check extension
- ext.MakeLower();
- if (ext == _T("exe") || ext == _T("cmd") || ext == ("bat"))
- {
- // Check if file exists
- struct _stati64 statBuffer;
- int nRetVal = _tstati64(path, &statBuffer);
- if (nRetVal > -1)
- return TRUE;
- }
- return FALSE;
-}
-
/// Create menu for simple mode
int CWinMergeShell::DrawSimpleMenu(HMENU hmenu, UINT uMenuIndex,
UINT uidFirstCmd)
{
- CString strMenu;
- VERIFY(strMenu.LoadString(IDS_CONTEXT_MENU));
+ String strMenu = GetResourceString(IDS_CONTEXT_MENU);
+ InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strMenu.c_str());
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strMenu);
-
// Add bitmap
- if (m_hMergeBmp != NULL)
- SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION, m_hMergeBmp, NULL);
-
+ HBITMAP hBitmap = PathIsDirectory(m_strPaths[0].c_str()) ? m_MergeDirBmp : m_MergeBmp;
+ if (hBitmap != NULL)
+ SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION, hBitmap, NULL);
+
// Show menu item as grayed if more than two items selected
if (m_nSelectedItems > MaxFileCount)
EnableMenuItem(hmenu, uMenuIndex, MF_BYPOSITION | MF_GRAYED);
-
+
return 1;
}
int CWinMergeShell::DrawAdvancedMenu(HMENU hmenu, UINT uMenuIndex,
UINT uidFirstCmd)
{
- CString strCompare;
- CString strCompareEllipsis;
- CString strCompareTo;
- CString strReselect;
+ String strCompare = GetResourceString(IDS_COMPARE);
+ String strCompareEllipsis = GetResourceString(IDS_COMPARE_ELLIPSIS);
+ String strCompareTo = GetResourceString(IDS_COMPARE_TO);
+ String strReselect = GetResourceString(IDS_RESELECT_FIRST);
int nItemsAdded = 0;
- VERIFY(strCompare.LoadString(IDS_COMPARE));
- VERIFY(strCompareEllipsis.LoadString(IDS_COMPARE_ELLIPSIS));
- VERIFY(strCompareTo.LoadString(IDS_COMPARE_TO));
- VERIFY(strReselect.LoadString(IDS_RESELECT_FIRST));
-
switch (m_dwMenuState)
{
- // No items selected earlier
- // Select item as first item to compare
+ // No items selected earlier
+ // Select item as first item to compare
case MENU_ONESEL_NOPREV:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strCompareTo);
+ InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
+ strCompareTo.c_str());
uMenuIndex++;
uidFirstCmd++;
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strCompareEllipsis);
+ InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
+ strCompareEllipsis.c_str());
nItemsAdded = 2;
break;
- // One item selected earlier:
- // Allow re-selecting first item or selecting second item
+ // One item selected earlier:
+ // Allow re-selecting first item or selecting second item
case MENU_ONESEL_PREV:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strCompare);
+ InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
+ strCompare.c_str());
uMenuIndex++;
uidFirstCmd++;
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strReselect);
+ InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
+ strReselect.c_str());
nItemsAdded = 2;
break;
- // Two items selected
- // Select both items for compare
+ // Two items selected
+ // Select both items for compare
case MENU_TWOSEL:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strCompare);
+ case MENU_THREESEL:
+ InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
+ strCompare.c_str());
nItemsAdded = 1;
break;
default:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strCompare);
+ InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
+ strCompare.c_str());
nItemsAdded = 1;
break;
}
-
+
// Add bitmap
- if (m_hMergeBmp != NULL)
+ HBITMAP hBitmap = PathIsDirectory(m_strPaths[0].c_str()) ? m_MergeDirBmp : m_MergeBmp;
+ if (hBitmap != NULL)
{
if (nItemsAdded == 2)
- SetMenuItemBitmaps(hmenu, uMenuIndex - 1, MF_BYPOSITION, m_hMergeBmp, NULL);
- SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION, m_hMergeBmp, NULL);
+ SetMenuItemBitmaps(hmenu, uMenuIndex - 1, MF_BYPOSITION, hBitmap, NULL);
+ SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION, hBitmap, NULL);
}
-
+
// Show menu item as grayed if more than two items selected
if (m_nSelectedItems > MaxFileCount)
{
}
/// Determine help text shown in explorer's statusbar
-CString CWinMergeShell::GetHelpText(int idCmd)
+String CWinMergeShell::GetHelpText(UINT_PTR idCmd)
{
- CString strHelp;
+ String strHelp;
// More than two items selected, advice user
if (m_nSelectedItems > MaxFileCount)
{
- VERIFY(strHelp.LoadString(IDS_CONTEXT_HELP_MANYITEMS));
+ strHelp = GetResourceString(IDS_CONTEXT_HELP_MANYITEMS);
return strHelp;
}
switch (m_dwMenuState)
{
case MENU_SIMPLE:
- VERIFY(strHelp.LoadString(IDS_CONTEXT_HELP));
+ strHelp = GetResourceString(IDS_CONTEXT_HELP);;
break;
case MENU_ONESEL_NOPREV:
- VERIFY(strHelp.LoadString(IDS_HELP_SAVETHIS));
+ strHelp = GetResourceString(IDS_HELP_SAVETHIS);
break;
-
+
case MENU_ONESEL_PREV:
- AfxFormatString1(strHelp, IDS_HELP_COMPARESAVED, m_strPreviousPath);
+ strHelp = GetResourceString(IDS_HELP_COMPARESAVED);
+ string_replace(strHelp, _T("%1"), m_strPreviousPath);
break;
-
+
case MENU_TWOSEL:
- VERIFY(strHelp.LoadString(IDS_CONTEXT_HELP));
+ case MENU_THREESEL:
+ strHelp = GetResourceString(IDS_CONTEXT_HELP);
break;
}
}
switch (m_dwMenuState)
{
case MENU_ONESEL_PREV:
- VERIFY(strHelp.LoadString(IDS_HELP_SAVETHIS));
+ strHelp = GetResourceString(IDS_HELP_SAVETHIS);
break;
default:
- VERIFY(strHelp.LoadString(IDS_CONTEXT_HELP));
+ strHelp = GetResourceString(IDS_CONTEXT_HELP);
break;
}
}
}
/// Format commandline used to start WinMerge
-CString CWinMergeShell::FormatCmdLine(const CString &winmergePath,
- const CString &path1, const CString &path2)
+String CWinMergeShell::FormatCmdLine(const String &winmergePath,
+ const String &path1, const String &path2, BOOL bAlterSubFolders)
{
- CString strCommandline = winmergePath;
- BOOL bOnlyFiles = FALSE;
-
- if (!path1.IsEmpty() && !path2.IsEmpty())
- {
- CFileStatus status;
- CFileStatus status2;
- if (CFile::GetStatus(path1, status) &&
- CFile::GetStatus(path2, status2))
- {
- // Check if both paths are files
- if ((status.m_attribute & CFile::Attribute::directory) == 0 &&
- (status2.m_attribute & CFile::Attribute::directory) == 0)
- {
- bOnlyFiles = TRUE;
- }
- }
- }
+ String strCommandline = _T("\"") + winmergePath + _T("\"");
- strCommandline += _T(" \"") +
- path1 + _T("\"");
-
- if (!m_strPaths[1].IsEmpty())
+ // Check if user wants to use context menu
+ BOOL bSubfoldersByDefault = FALSE;
+ CRegKeyEx reg;
+ if (reg.Open(HKEY_CURRENT_USER, f_RegSettingsDir) == ERROR_SUCCESS)
+ bSubfoldersByDefault = reg.ReadBool(f_Recurse, FALSE);
+
+ if (bAlterSubFolders && !bSubfoldersByDefault)
+ strCommandline += _T(" /r");
+ else if (!bAlterSubFolders && bSubfoldersByDefault)
+ strCommandline += _T(" /r");
+
+ strCommandline += _T(" \"") + path1 + _T("\"");
+
+ if (!m_strPaths[1].empty())
strCommandline += _T(" \"") + path2 + _T("\"");
return strCommandline;