changeset 6805:81cb471657e0 v7.4.724

patch 7.4.724 Problem: Vim icon does not show in Windows context menu. (issue 249) Solution: Load the icon in GvimExt.
author Bram Moolenaar <bram@vim.org>
date Mon, 04 May 2015 18:27:36 +0200
parents 0d87f7311e5b
children 0d413bf8e288
files src/GvimExt/gvimext.cpp src/GvimExt/gvimext.h src/version.c
diffstat 3 files changed, 94 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/src/GvimExt/gvimext.cpp
+++ b/src/GvimExt/gvimext.cpp
@@ -79,19 +79,24 @@ getGvimName(char *name, int runtime)
 	    strcpy(name, searchpath((char *)"gvim.bat"));
 	if (name[0] == 0)
 	    strcpy(name, "gvim");	// finds gvim.bat or gvim.exe
-
-	// avoid that Vim tries to expand wildcards in the file names
-	strcat(name, " --literal");
     }
 }
 
     static void
-getGvimNameW(wchar_t *nameW)
+getGvimInvocation(char *name, int runtime)
+{
+    getGvimName(name, runtime);
+    // avoid that Vim tries to expand wildcards in the file names
+    strcat(name, " --literal");
+}
+
+    static void
+getGvimInvocationW(wchar_t *nameW)
 {
     char *name;
 
     name = (char *)malloc(BUFSIZE);
-    getGvimName(name, 0);
+    getGvimInvocation(name, 0);
     mbstowcs(nameW, name, BUFSIZE);
     free(name);
 }
@@ -123,6 +128,26 @@ getRuntimeDir(char *buf)
     }
 }
 
+HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height)
+{
+	HDC hDC = GetDC(NULL);
+	HDC hMemDC = CreateCompatibleDC(hDC);
+	HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, width, height);
+	HBITMAP hResultBmp = NULL;
+	HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);
+
+	DrawIconEx(hMemDC, 0, 0, hIcon, width, height, 0, hBackground, DI_NORMAL);
+
+	hResultBmp = hMemBmp;
+	hMemBmp = NULL;
+
+	SelectObject(hMemDC, hOrgBMP);
+	DeleteDC(hMemDC);
+	ReleaseDC(NULL, hDC);
+	DestroyIcon(hIcon);
+	return hResultBmp;
+}
+
 //
 // GETTEXT: translated messages and menu entries
 //
@@ -404,7 +429,7 @@ STDMETHODIMP CShellExtClassFactory::Quer
 {
     *ppv = NULL;
 
-    // Any interface on this object is the object pointer
+    // any interface on this object is the object pointer
 
     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
     {
@@ -448,7 +473,7 @@ STDMETHODIMP CShellExtClassFactory::Crea
     // QueryInterface with IID_IShellExtInit--this is how shell extensions are
     // initialized.
 
-    LPCSHELLEXT pShellExt = new CShellExt();  //Create the CShellExt object
+    LPCSHELLEXT pShellExt = new CShellExt();  // create the CShellExt object
 
     if (NULL == pShellExt)
 	return E_OUTOFMEMORY;
@@ -469,6 +494,8 @@ CShellExt::CShellExt()
     m_pDataObj = NULL;
 
     inc_cRefThisDLL();
+
+    LoadMenuIcon();
 }
 
 CShellExt::~CShellExt()
@@ -477,6 +504,9 @@ CShellExt::~CShellExt()
 	m_pDataObj->Release();
 
     dec_cRefThisDLL();
+
+    if (m_hVimIconBitmap)
+	DeleteObject(m_hVimIconBitmap);
 }
 
 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
@@ -597,6 +627,7 @@ STDMETHODIMP CShellExt::QueryContextMenu
 
     HKEY keyhandle;
     bool showExisting = true;
+    bool showIcons = true;
 
     // Check whether "Edit with existing Vim" entries are disabled.
     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
@@ -605,6 +636,9 @@ STDMETHODIMP CShellExt::QueryContextMenu
 	if (RegQueryValueEx(keyhandle, "DisableEditWithExisting", 0, NULL,
 						 NULL, NULL) == ERROR_SUCCESS)
 	    showExisting = false;
+	if (RegQueryValueEx(keyhandle, "DisableContextMenuIcons", 0, NULL,
+						 NULL, NULL) == ERROR_SUCCESS)
+	    showIcons = false;
 	RegCloseKey(keyhandle);
     }
 
@@ -612,28 +646,33 @@ STDMETHODIMP CShellExt::QueryContextMenu
     if (showExisting)
 	EnumWindows(EnumWindowsProc, (LPARAM)this);
 
+    MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
+    mii.fMask = MIIM_STRING | MIIM_ID;
+    if (showIcons)
+    {
+	mii.fMask |= MIIM_BITMAP;
+	mii.hbmpItem = m_hVimIconBitmap;
+    }
+
     if (cbFiles > 1)
     {
-	InsertMenu(hMenu,
-		indexMenu++,
-		MF_STRING|MF_BYPOSITION,
-		idCmd++,
-		_("Edit with &multiple Vims"));
+	mii.wID = idCmd++;
+	mii.dwTypeData = _("Edit with &multiple Vims");
+	mii.cch = lstrlen(mii.dwTypeData);
+	InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
 
-	InsertMenu(hMenu,
-		indexMenu++,
-		MF_STRING|MF_BYPOSITION,
-		idCmd++,
-		_("Edit with single &Vim"));
+	mii.wID = idCmd++;
+	mii.dwTypeData = _("Edit with single &Vim");
+	mii.cch = lstrlen(mii.dwTypeData);
+	InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
 
 	if (cbFiles <= 4)
 	{
 	    // Can edit up to 4 files in diff mode
-	    InsertMenu(hMenu,
-		    indexMenu++,
-		    MF_STRING|MF_BYPOSITION,
-		    idCmd++,
-		    _("Diff with Vim"));
+	    mii.wID = idCmd++;
+	    mii.dwTypeData = _("Diff with Vim");
+	    mii.cch = lstrlen(mii.dwTypeData);
+	    InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
 	    m_edit_existing_off = 3;
 	}
 	else
@@ -642,11 +681,10 @@ STDMETHODIMP CShellExt::QueryContextMenu
     }
     else
     {
-	InsertMenu(hMenu,
-		indexMenu++,
-		MF_STRING|MF_BYPOSITION,
-		idCmd++,
-		_("Edit with &Vim"));
+	mii.wID = idCmd++;
+	mii.dwTypeData = _("Edit with &Vim");
+	mii.cch = lstrlen(mii.dwTypeData);
+	InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
 	m_edit_existing_off = 1;
     }
 
@@ -672,11 +710,11 @@ STDMETHODIMP CShellExt::QueryContextMenu
 	temp[BUFSIZE - 1] = '\0';
 	strncat(temp, title, BUFSIZE - 1 - strlen(temp));
 	temp[BUFSIZE - 1] = '\0';
-	InsertMenu(hMenu,
-		indexMenu++,
-		MF_STRING|MF_BYPOSITION,
-		idCmd++,
-		temp);
+
+	mii.wID = idCmd++;
+	mii.dwTypeData = temp;
+	mii.cch = lstrlen(mii.dwTypeData);
+	InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
     }
     // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
 
@@ -813,6 +851,22 @@ BOOL CALLBACK CShellExt::EnumWindowsProc
     return TRUE; // continue enumeration (otherwise this would be false)
 }
 
+BOOL CShellExt::LoadMenuIcon()
+{
+	char vimExeFile[BUFSIZE];
+	getGvimName(vimExeFile, 1);
+	if (vimExeFile[0] == '\0')
+		return FALSE;
+	HICON hVimIcon;
+	if (ExtractIconEx(vimExeFile, 0, NULL, &hVimIcon, 1) == 0)
+		return FALSE;
+	m_hVimIconBitmap = IconToBitmap(hVimIcon,
+		GetSysColorBrush(COLOR_MENU),
+		GetSystemMetrics(SM_CXSMICON),
+		GetSystemMetrics(SM_CYSMICON));
+	return TRUE;
+}
+
 #ifdef WIN32
 // This symbol is not defined in older versions of the SDK or Visual C++.
 
@@ -893,7 +947,7 @@ STDMETHODIMP CShellExt::InvokeGvim(HWND 
 		m_szFileUserClickedOn,
 		sizeof(m_szFileUserClickedOn));
 
-	getGvimNameW(cmdStrW);
+	getGvimInvocationW(cmdStrW);
 	wcscat(cmdStrW, L" \"");
 
 	if ((wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 2) < BUFSIZE)
@@ -961,7 +1015,7 @@ STDMETHODIMP CShellExt::InvokeSingleGvim
 
     cmdlen = BUFSIZE;
     cmdStrW  = (wchar_t *) malloc(cmdlen * sizeof(wchar_t));
-    getGvimNameW(cmdStrW);
+    getGvimInvocationW(cmdStrW);
 
     if (useDiff)
 	wcscat(cmdStrW, L" -d");
--- a/src/GvimExt/gvimext.h
+++ b/src/GvimExt/gvimext.h
@@ -110,10 +110,14 @@ typedef CShellExtClassFactory *LPCSHELLE
 class CShellExt : public IContextMenu,
 			 IShellExtInit
 {
+private:
+    BOOL LoadMenuIcon();
+
 protected:
     ULONG	 m_cRef;
     LPDATAOBJECT m_pDataObj;
     UINT	 m_edit_existing_off;
+    HBITMAP	 m_hVimIconBitmap;
 
     // For some reason, this callback must be static
     static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam);
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    724,
+/**/
     723,
 /**/
     722,