#include <sys/types.h>
#include <sys/stat.h>
+OBJECT_ENTRY_AUTO(CLSID_WinMergeShell, CWinMergeShell)
+
/**
* @brief Flags for enabling and other settings of context menu.
*/
EXT_ADVANCED = 0x02, /**< Advanced menuitems enabled/disabled. */
};
+enum
+{
+ CMD_COMPARE = 0,
+ CMD_COMPARE_ELLIPSE,
+ CMD_SELECT_LEFT,
+ CMD_SELECT_MIDDLE,
+ CMD_RESELECT_LEFT,
+ CMD_LAST = CMD_RESELECT_LEFT,
+};
+
/// Max. filecount to select
static const int MaxFileCount = 3;
/// Registry path to WinMerge
static const TCHAR f_RegValueEnabled[] = _T("ContextMenuEnabled");
/** 'Saved' path in advanced mode */
static const TCHAR f_FirstSelection[] = _T("FirstSelection");
-/** Path to WinMerge[U].exe */
+/** 'Saved' path in advanced mode */
+static const TCHAR f_SecondSelection[] = _T("SecondSelection");
+/** Path to WinMergeU.exe */
static const TCHAR f_RegValuePath[] = _T("Executable");
-/** Path to WinMerge[U].exe, overwrites f_RegValuePath if present. */
+/** Path to WinMergeU.exe, overwrites f_RegValuePath if present. */
static const TCHAR f_RegValuePriPath[] = _T("PriExecutable");
/** LanguageId */
static const TCHAR f_LanguageId[] = _T("LanguageId");
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_ONESEL_TWO_PREV, /**< One item selected, two previous selections exist. */
MENU_TWOSEL, /**< Two items are selected. */
MENU_THREESEL
};
-#define USES_WINMERGELOCALE CWinMergeTempLocale __wmtl__
-
-static String GetResourceString(UINT resourceID);
-
-class CWinMergeTempLocale
+// GreyMerlin (03 Sept 2017) - The following Version Info checking code is a
+// short extract from the Microsoft <versionhelpers.h> file. Unfortunatly,
+// that file is not available for WinXP-compatible Platform Toolsets (e.g.
+// v141_xp for VS2017). Fortunatly, all the actual API interfaces do exist
+// in WinXP (actually, in all Windows products since Win2000). Use of this
+// <versionhelpers.h> code avoids the unpleasant deprecation of the GetVersionEx()
+// API begining with Win 8.1. This Version Info checking code is also fully
+// compatible with all non-XP-compatible Toolsets as well (e.g. v141).
+
+#ifndef _WIN32_WINNT_VISTA
+#define _WIN32_WINNT_VISTA 0x0600
+#endif
+#ifndef _WIN32_WINNT_WIN8
+#define _WIN32_WINNT_WIN8 0x0602
+#endif
+
+#ifndef VERSIONHELPERAPI
+#define VERSIONHELPERAPI inline bool
+
+VERSIONHELPERAPI
+IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
-private:
- LCID m_lcidOld;
-public:
- CWinMergeTempLocale()
- {
- CRegKeyEx reg;
- if (reg.Open(HKEY_CURRENT_USER, f_RegLocaleDir) != ERROR_SUCCESS)
- return;
-
- m_lcidOld = GetThreadLocale();
+ OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
+ DWORDLONG const dwlConditionMask = VerSetConditionMask(
+ VerSetConditionMask(
+ VerSetConditionMask(
+ 0, VER_MAJORVERSION, VER_GREATER_EQUAL),
+ VER_MINORVERSION, VER_GREATER_EQUAL),
+ VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
+
+ osvi.dwMajorVersion = wMajorVersion;
+ osvi.dwMinorVersion = wMinorVersion;
+ osvi.wServicePackMajor = wServicePackMajor;
+
+ return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
+}
- int iLangId = reg.ReadDword(f_LanguageId, (DWORD)-1);
- if (iLangId != -1)
- {
- SetThreadLocale(MAKELCID(iLangId, SORT_DEFAULT));
- SetThreadUILanguage(iLangId);
- }
- }
- ~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)
+VERSIONHELPERAPI
+IsWindows8OrGreater()
{
- TCHAR resStr[1024] = {0};
- int res = LoadString(_Module.GetModuleInstance(), resourceID, resStr, 1024);
- ATLASSERT(res != 0);
- String strResource = resStr;
- return strResource;
+ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
}
+#endif // VERSIONHELPERAPI
-static HBITMAP MakeBitmapBackColorTransparent(HBITMAP hbmSrc)
+HBITMAP ConvertHICONtoHBITMAP(HICON hIcon, int cx, int cy)
{
- 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)
+ LPVOID lpBits;
+ BITMAPINFO bmi = { { sizeof(BITMAPINFOHEADER), cx, cy, 1, IsWindows8OrGreater() ? 32u : 24u } };
+ HDC hdcMem = CreateCompatibleDC(NULL);
+ HBITMAP hbmp = CreateDIBSection(NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &lpBits, NULL, 0);
+ if (hbmp)
{
- COLORREF clrTP = GetPixel(hdcSrc, 0, 0);
- int bR = GetRValue(clrTP), bG = GetGValue(clrTP), bB = GetBValue(clrTP);
-
- for (int y = 0; y < bm.bmHeight; ++y)
+ HBITMAP hbmpPrev = (HBITMAP)SelectObject(hdcMem, hbmp);
+ RECT rc = { 0, 0, cx, cy };
+ if (bmi.bmiHeader.biBitCount <= 24)
{
- 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;
- }
- }
+ SetBkColor(hdcMem, GetSysColor(COLOR_MENU));
+ ExtTextOut(hdcMem, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
}
+ DrawIconEx(hdcMem, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);
+ SelectObject(hdcMem, hbmpPrev);
}
-
- SelectObject(hdcSrc, hbmSrcOld);
- DeleteDC(hdcSrc);
-
- return hbmNew;
+ DeleteDC(hdcMem);
+ return hbmp;
}
-
/////////////////////////////////////////////////////////////////////////////
// CWinMergeShell
/// Default constructor, loads icon bitmap
CWinMergeShell::CWinMergeShell()
+ : m_dwContextMenuEnabled(false)
+ , m_nSelectedItems(0)
+ , m_dwMenuState(0)
+ , m_langID(GetUserDefaultUILanguage())
{
- m_dwMenuState = 0;
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);
+ HICON hMergeIcon = (HICON)LoadImage(_AtlComModule.m_hInstTypeLib, MAKEINTRESOURCE(IDI_WINMERGE), IMAGE_ICON,
+ cx, cy, LR_DEFAULTCOLOR);
+ HICON hMergeDirIcon = (HICON)LoadImage(_AtlComModule.m_hInstTypeLib, MAKEINTRESOURCE(IDI_WINMERGEDIR), IMAGE_ICON,
+ cx, cy, LR_DEFAULTCOLOR);
+
+ m_MergeBmp = ConvertHICONtoHBITMAP(hMergeIcon, cx, cy);
+ m_MergeDirBmp = ConvertHICONtoHBITMAP(hMergeDirIcon, cx, cy);
+
+ DestroyIcon(hMergeIcon);
+ DestroyIcon(hMergeDirIcon);
+
+ CRegKeyEx reg;
+ if (reg.Open(HKEY_CURRENT_USER, f_RegLocaleDir) == ERROR_SUCCESS)
+ m_langID = static_cast<LANGID>(reg.ReadDword(f_LanguageId, m_langID));
- m_MergeDirBmp = MakeBitmapBackColorTransparent(hMergeDirBmp);
- DeleteObject(hMergeDirBmp);
- }
- else
- {
- m_MergeBmp = hMergeBmp;
- m_MergeDirBmp = hMergeDirBmp;
- }
}
/// Default destructor, unloads bitmap
HRESULT CWinMergeShell::Initialize(LPCITEMIDLIST pidlFolder,
LPDATAOBJECT pDataObj, HKEY hProgID)
{
- USES_WINMERGELOCALE;
HRESULT hr = E_INVALIDARG;
+ for (auto& path: m_strPaths)
+ path.erase();
+
// Files/folders selected normally from the explorer
if (pDataObj)
{
HRESULT CWinMergeShell::QueryContextMenu(HMENU hmenu, UINT uMenuIndex,
UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags)
{
- int nItemsAdded = 0;
- USES_WINMERGELOCALE;
+ // check whether menu items are already added
+ if (hmenu == s_hMenuLastAdded)
+ {
+ MENUITEMINFO mii{ sizeof mii };
+ mii.fMask = MIIM_DATA;
+ if (GetMenuItemInfo(hmenu, s_uidCmdLastAdded, FALSE, &mii))
+ {
+ if (mii.dwItemData >= IDS_COMPARE && mii.dwItemData <= IDS_RESELECT_LEFT)
+ return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
+ }
+ }
+
+ s_hMenuLastAdded = hmenu;
+ s_uidCmdLastAdded = uidFirstCmd;
+
+ int uidUserLastCmd = 0;
// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
if (uFlags & CMF_DEFAULTONLY)
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
m_dwContextMenuEnabled = reg.ReadDword(f_RegValueEnabled, 0);
- m_strPreviousPath = reg.ReadString(f_FirstSelection, _T("")).c_str();
+ m_strPreviousPath[0] = reg.ReadString(f_FirstSelection, _T("")).c_str();
+ m_strPreviousPath[1] = reg.ReadString(f_SecondSelection, _T("")).c_str();
if (m_dwContextMenuEnabled & EXT_ENABLED) // Context menu enabled
{
if ((m_dwContextMenuEnabled & EXT_ADVANCED) == 0)
{
m_dwMenuState = MENU_SIMPLE;
- nItemsAdded = DrawSimpleMenu(hmenu, uMenuIndex, uidFirstCmd);
+ uidUserLastCmd = DrawSimpleMenu(hmenu, uMenuIndex, uidFirstCmd);
}
else
{
- if (m_nSelectedItems == 1 && m_strPreviousPath.empty())
+ if (m_nSelectedItems == 1 && m_strPreviousPath[0].empty())
m_dwMenuState = MENU_ONESEL_NOPREV;
- else if (m_nSelectedItems == 1 && !m_strPreviousPath.empty())
+ else if (m_nSelectedItems == 1 && !m_strPreviousPath[0].empty() && m_strPreviousPath[1].empty())
m_dwMenuState = MENU_ONESEL_PREV;
+ else if (m_nSelectedItems == 1 && !m_strPreviousPath[0].empty() && !m_strPreviousPath[1].empty())
+ m_dwMenuState = MENU_ONESEL_TWO_PREV;
else if (m_nSelectedItems == 2)
m_dwMenuState = MENU_TWOSEL;
else if (m_nSelectedItems == 3)
m_dwMenuState = MENU_THREESEL;
- nItemsAdded = DrawAdvancedMenu(hmenu, uMenuIndex, uidFirstCmd);
+ uidUserLastCmd = DrawAdvancedMenu(hmenu, uMenuIndex, uidFirstCmd);
}
- return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, nItemsAdded);
+ return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, (uidUserLastCmd - uidFirstCmd) + 1);
}
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
}
UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
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)
// supplied buffer.
if (uFlags & GCS_HELPTEXT)
{
- String strHelp;
-
- strHelp = GetHelpText(idCmd);
+ String strHelp = GetHelpText(idCmd);
if (uFlags & GCS_UNICODE)
// We need to cast pszName to a Unicode string, and then use the
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 (HIWORD(pCmdInfo->lpVerb) != 0)
if (!PathFileExists(strWinMergePath.c_str()))
return S_FALSE;
- if (LOWORD(pCmdInfo->lpVerb) == 0)
+ if (LOWORD(pCmdInfo->lpVerb) == CMD_COMPARE)
{
switch (m_dwMenuState)
{
bCompare = TRUE;
break;
- case MENU_ONESEL_NOPREV:
- m_strPreviousPath = m_strPaths[0];
+ case MENU_ONESEL_PREV:
+ m_strPaths[1] = m_strPaths[0];
+ m_strPaths[0] = m_strPreviousPath[0];
+ bCompare = TRUE;
+
+ // Forget previous selection
if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
- reg.WriteString(f_FirstSelection, m_strPreviousPath.c_str());
+ {
+ reg.WriteString(f_FirstSelection, _T(""));
+ reg.WriteString(f_SecondSelection, _T(""));
+ }
break;
- case MENU_ONESEL_PREV:
- m_strPaths[1] = m_strPaths[0];
- m_strPaths[0] = m_strPreviousPath;
+ case MENU_ONESEL_TWO_PREV:
+ m_strPaths[2] = m_strPaths[0];
+ m_strPaths[0] = m_strPreviousPath[0];
+ m_strPaths[1] = m_strPreviousPath[1];
bCompare = TRUE;
// Forget previous selection
if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
+ {
reg.WriteString(f_FirstSelection, _T(""));
+ reg.WriteString(f_SecondSelection, _T(""));
+ }
break;
case MENU_TWOSEL:
case MENU_THREESEL:
// "Compare" - compare paths
bCompare = TRUE;
- m_strPreviousPath.erase();
+ m_strPreviousPath[0].erase();
+ m_strPreviousPath[1].erase();
break;
}
}
- else if (LOWORD(pCmdInfo->lpVerb) == 1)
+ else if (LOWORD(pCmdInfo->lpVerb) == CMD_COMPARE_ELLIPSE)
{
- switch (m_dwMenuState)
+ // "Compare..." - user wants to compare this single item and open WinMerge
+ m_strPaths[1].erase();
+ m_strPaths[2].erase();
+ bCompare = TRUE;
+ }
+ else if (LOWORD(pCmdInfo->lpVerb) == CMD_SELECT_LEFT)
+ {
+ // Select Left
+ m_strPreviousPath[0] = m_strPaths[0];
+ if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
+ reg.WriteString(f_FirstSelection, m_strPreviousPath[0].c_str());
+ }
+ else if (LOWORD(pCmdInfo->lpVerb) == CMD_SELECT_MIDDLE)
+ {
+ // Select Middle
+ m_strPreviousPath[1] = m_strPaths[0];
+ if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
+ reg.WriteString(f_SecondSelection, m_strPreviousPath[1].c_str());
+ }
+ else if (LOWORD(pCmdInfo->lpVerb) == CMD_RESELECT_LEFT)
+ {
+ // Re-select Left
+ m_strPreviousPath[0] = m_strPaths[0];
+ m_strPreviousPath[1].clear();
+ if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS)
{
- 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.c_str());
- bCompare = FALSE;
- break;
- default:
- // "Compare..." - user wants to compare this single item and open WinMerge
- m_strPaths[1].erase();
- bCompare = TRUE;
- break;
+ reg.WriteString(f_FirstSelection, m_strPreviousPath[0].c_str());
+ reg.WriteString(f_SecondSelection, _T(""));
}
}
else
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("\"");
+ String strCommandLine = FormatCmdLine(strWinMergePath,
+ m_strPaths[0], m_strPaths[1], m_strPaths[2], bAlterSubFolders);
// Finally start a new WinMerge process
BOOL retVal = FALSE;
NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL,
&stInfo, &processInfo);
- if (!retVal)
+ if (retVal)
+ {
+ CloseHandle(processInfo.hThread);
+ CloseHandle(processInfo.hProcess);
+ }
+ else if (GetLastError() == ERROR_ELEVATION_REQUIRED)
+ {
+ String strCommandLine = FormatCmdLine(_T(""),
+ m_strPaths[0], m_strPaths[1], m_strPaths[2], bAlterSubFolders);
+ HINSTANCE hInstance = ShellExecute(nullptr, _T("runas"), strWinMergePath.c_str(), strCommandLine.c_str(), 0, SW_SHOWNORMAL);
+ if (reinterpret_cast<intptr_t>(hInstance) < 32)
+ return S_FALSE;
+ }
+ else
+ {
return S_FALSE;
+ }
- CloseHandle(processInfo.hThread);
- CloseHandle(processInfo.hProcess);
return S_OK;
}
+/**
+ * @brief Load a string from resource.
+ * @param [in] Resource string ID.
+ * @return String loaded from resource.
+ */
+String CWinMergeShell::GetResourceString(UINT resourceID)
+{
+ if (!s_pLang)
+ s_pLang = new CLanguageSelect();
+ if (s_pLang->GetLangId() != m_langID)
+ {
+ TCHAR szFileName[1024] = {0};
+ GetModuleFileName(_AtlComModule.m_hInstTypeLib, szFileName, sizeof(szFileName) / sizeof(TCHAR));
+ PathRemoveFileSpec(szFileName);
+ String languagesFolder = String(szFileName) + _T("\\Languages\\ShellExtension");
+ s_pLang->LoadLanguageFile(m_langID, languagesFolder);
+ }
+ TCHAR resStr[1024] = {0};
+ int res = LoadString(_AtlComModule.m_hInstTypeLib, resourceID, resStr, 1024);
+ ATLASSERT(res != 0);
+ String strResource;
+ s_pLang->TranslateString(resStr, strResource);
+ return strResource;
+}
+
+BOOL CWinMergeShell::InsertMenuString(HMENU hMenu, UINT uPosition, UINT uIDNewItem, UINT uStringId)
+{
+ String str = GetResourceString(uStringId);
+ MENUITEMINFO mii{sizeof mii};
+ mii.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
+ mii.wID = uIDNewItem;
+ mii.dwTypeData = const_cast<LPTSTR>(str.c_str());
+ mii.dwItemData = uStringId;
+ return InsertMenuItem(hMenu, uPosition, TRUE, &mii);
+}
+
/// Reads WinMerge path from registry
BOOL CWinMergeShell::GetWinMergeDir(String &strDir)
{
int CWinMergeShell::DrawSimpleMenu(HMENU hmenu, UINT uMenuIndex,
UINT uidFirstCmd)
{
- String strMenu = GetResourceString(IDS_CONTEXT_MENU);
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, strMenu.c_str());
+ InsertMenuString(hmenu, uMenuIndex, uidFirstCmd, IDS_CONTEXT_MENU);
// Add bitmap
HBITMAP hBitmap = PathIsDirectory(m_strPaths[0].c_str()) ? m_MergeDirBmp : m_MergeBmp;
if (m_nSelectedItems > MaxFileCount)
EnableMenuItem(hmenu, uMenuIndex, MF_BYPOSITION | MF_GRAYED);
- return 1;
+ return uidFirstCmd + CMD_LAST;
}
/// Create menu for advanced mode
int CWinMergeShell::DrawAdvancedMenu(HMENU hmenu, UINT uMenuIndex,
UINT uidFirstCmd)
{
- 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;
switch (m_dwMenuState)
// No items selected earlier
// Select item as first item to compare
case MENU_ONESEL_NOPREV:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
- strCompareTo.c_str());
- uMenuIndex++;
- uidFirstCmd++;
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
- strCompareEllipsis.c_str());
+ InsertMenuString(hmenu, uMenuIndex++, uidFirstCmd + CMD_SELECT_LEFT, IDS_SELECT_LEFT);
+ InsertMenuString(hmenu, uMenuIndex, uidFirstCmd + CMD_COMPARE_ELLIPSE, IDS_COMPARE_ELLIPSIS);
nItemsAdded = 2;
break;
// One item selected earlier:
// Allow re-selecting first item or selecting second item
case MENU_ONESEL_PREV:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
- strCompare.c_str());
- uMenuIndex++;
- uidFirstCmd++;
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
- strReselect.c_str());
+ InsertMenuString(hmenu, uMenuIndex++, uidFirstCmd + CMD_COMPARE, IDS_COMPARE);
+ InsertMenuString(hmenu, uMenuIndex++, uidFirstCmd + CMD_SELECT_MIDDLE, IDS_SELECT_MIDDLE);
+ InsertMenuString(hmenu, uMenuIndex, uidFirstCmd + CMD_RESELECT_LEFT, IDS_RESELECT_LEFT);
+ nItemsAdded = 3;
+ break;
+
+ // Two items are selected earlier:
+ // Allow re-selecting first item or selecting second item
+ case MENU_ONESEL_TWO_PREV:
+ InsertMenuString(hmenu, uMenuIndex++, uidFirstCmd + CMD_COMPARE, IDS_COMPARE);
+ InsertMenuString(hmenu, uMenuIndex, uidFirstCmd + CMD_RESELECT_LEFT, IDS_RESELECT_LEFT);
nItemsAdded = 2;
break;
// Select both items for compare
case MENU_TWOSEL:
case MENU_THREESEL:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
- strCompare.c_str());
+ InsertMenuString(hmenu, uMenuIndex, uidFirstCmd + CMD_COMPARE, IDS_COMPARE);
nItemsAdded = 1;
break;
default:
- InsertMenu(hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd,
- strCompare.c_str());
+ InsertMenuString(hmenu, uMenuIndex, uidFirstCmd + CMD_COMPARE, IDS_COMPARE);
nItemsAdded = 1;
break;
}
HBITMAP hBitmap = PathIsDirectory(m_strPaths[0].c_str()) ? m_MergeDirBmp : m_MergeBmp;
if (hBitmap != NULL)
{
- if (nItemsAdded == 2)
- SetMenuItemBitmaps(hmenu, uMenuIndex - 1, MF_BYPOSITION, hBitmap, NULL);
- SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION, hBitmap, NULL);
+ for (int i = 0; i < nItemsAdded; i++)
+ SetMenuItemBitmaps(hmenu, uMenuIndex - (nItemsAdded - 1 - i), MF_BYPOSITION, hBitmap, NULL);
}
// Show menu item as grayed if more than two items selected
if (m_nSelectedItems > MaxFileCount)
{
- if (nItemsAdded == 2)
- EnableMenuItem(hmenu, uMenuIndex - 1, MF_BYPOSITION | MF_GRAYED);
- EnableMenuItem(hmenu, uMenuIndex, MF_BYPOSITION | MF_GRAYED);
+ for (int i = 0; i < nItemsAdded; i++)
+ EnableMenuItem(hmenu, uMenuIndex - (nItemsAdded - 1 - i), MF_BYPOSITION | MF_GRAYED);
}
- return nItemsAdded;
+ return uidFirstCmd + CMD_LAST;
}
/// Determine help text shown in explorer's statusbar
return strHelp;
}
- if (idCmd == 0)
+ if (idCmd == CMD_COMPARE)
{
switch (m_dwMenuState)
{
- case MENU_SIMPLE:
- strHelp = GetResourceString(IDS_CONTEXT_HELP);;
- break;
-
- case MENU_ONESEL_NOPREV:
- strHelp = GetResourceString(IDS_HELP_SAVETHIS);
- break;
-
case MENU_ONESEL_PREV:
strHelp = GetResourceString(IDS_HELP_COMPARESAVED);
- string_replace(strHelp, _T("%1"), m_strPreviousPath);
+ strutils::replace(strHelp, _T("%1"), m_strPreviousPath[0]);
break;
- case MENU_TWOSEL:
- case MENU_THREESEL:
- strHelp = GetResourceString(IDS_CONTEXT_HELP);
- break;
- }
- }
- else if (idCmd == 1)
- {
- switch (m_dwMenuState)
- {
- case MENU_ONESEL_PREV:
- strHelp = GetResourceString(IDS_HELP_SAVETHIS);
+ case MENU_ONESEL_TWO_PREV:
+ strHelp = GetResourceString(IDS_HELP_COMPARESAVED);
+ strutils::replace(strHelp, _T("%1"), m_strPreviousPath[0] + _T(" - ") + m_strPreviousPath[1]);
break;
default:
strHelp = GetResourceString(IDS_CONTEXT_HELP);
break;
}
}
+ else if (idCmd == CMD_COMPARE_ELLIPSE)
+ {
+ strHelp = GetResourceString(IDS_CONTEXT_HELP);
+ }
+ else if (idCmd == CMD_SELECT_LEFT)
+ {
+ strHelp = GetResourceString(IDS_HELP_SAVETHIS);
+ }
+ else if (idCmd == CMD_SELECT_MIDDLE)
+ {
+ strHelp = GetResourceString(IDS_HELP_SAVETHIS);
+ }
+ else if (idCmd == CMD_RESELECT_LEFT)
+ {
+ strHelp = GetResourceString(IDS_HELP_SAVETHIS);
+ }
return strHelp;
}
/// Format commandline used to start WinMerge
String CWinMergeShell::FormatCmdLine(const String &winmergePath,
- const String &path1, const String &path2, BOOL bAlterSubFolders)
+ const String &path1, const String &path2, const String &path3, BOOL bAlterSubFolders)
{
- String strCommandline = _T("\"") + winmergePath + _T("\"");
+ String strCommandline = winmergePath.empty() ? _T("") : _T("\"") + winmergePath + _T("\"");
// Check if user wants to use context menu
BOOL bSubfoldersByDefault = FALSE;
if (!m_strPaths[1].empty())
strCommandline += _T(" \"") + path2 + _T("\"");
+ if (!m_strPaths[2].empty())
+ strCommandline += _T(" \"") + path3 + _T("\"");
+
return strCommandline;
}