Patch 9.0.1577

5 views
Skip to first unread message

Bram Moolenaar

unread,
May 25, 2023, 11:43:58 AM5/25/23
to vim...@googlegroups.com

Patch 9.0.1577
Problem: MS-Windows: context menu translations may be wrong.
Solution: Set the encoding before using gettext(). (Ken Takata,
closes #12441, closes #12431)
Files: src/GvimExt/Make_ming.mak, src/GvimExt/Make_mvc.mak,
src/GvimExt/gvimext.cpp, src/GvimExt/gvimext.h


*** ../vim-9.0.1576/src/GvimExt/Make_ming.mak 2022-11-02 13:30:37.526314510 +0000
--- src/GvimExt/Make_ming.mak 2023-05-25 16:39:16.898728119 +0100
***************
*** 43,51 ****
DEL = del
endif
endif
! # Set the default $(WINVER) to make it work with WinXP.
ifndef WINVER
! WINVER = 0x0501
endif
CXX := $(CROSS_COMPILE)g++
WINDRES := $(CROSS_COMPILE)windres
--- 43,51 ----
DEL = del
endif
endif
! # Set the default $(WINVER) to make it work with Windows 7.
ifndef WINVER
! WINVER = 0x0601
endif
CXX := $(CROSS_COMPILE)g++
WINDRES := $(CROSS_COMPILE)windres
*** ../vim-9.0.1576/src/GvimExt/Make_mvc.mak 2022-09-09 10:51:14.415772399 +0100
--- src/GvimExt/Make_mvc.mak 2023-05-25 16:39:16.898728119 +0100
***************
*** 8,17 ****
TARGETOS = WINNT

!ifndef APPVER
! APPVER = 5.01
!endif
!ifndef WINVER
! WINVER = 0x0501
!endif

!if "$(DEBUG)" != "yes"
--- 8,18 ----
TARGETOS = WINNT

!ifndef APPVER
! APPVER = 6.01
!endif
+ # Set the default $(WINVER) to make it work with Windows 7.
!ifndef WINVER
! WINVER = 0x0601
!endif

!if "$(DEBUG)" != "yes"
***************
*** 40,48 ****
!endif

!ifdef SDK_INCLUDE_DIR
! !include $(SDK_INCLUDE_DIR)\Win32.mak
!elseif "$(USE_WIN32MAK)"=="yes"
! !include <Win32.mak>
!else
cc = cl
link = link
--- 41,49 ----
!endif

!ifdef SDK_INCLUDE_DIR
! ! include $(SDK_INCLUDE_DIR)\Win32.mak
!elseif "$(USE_WIN32MAK)"=="yes"
! ! include <Win32.mak>
!else
cc = cl
link = link
*** ../vim-9.0.1576/src/GvimExt/gvimext.cpp 2021-12-22 15:12:38.000000000 +0000
--- src/GvimExt/gvimext.cpp 2023-05-25 16:39:16.898728119 +0100
***************
*** 130,162 ****
}
}

! 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
//
#ifndef FEAT_GETTEXT
! # define _(x) x
#else
! # define _(x) (*dyn_libintl_gettext)(x)
# define VIMPACKAGE "vim"
# ifndef GETTEXT_DLL
# define GETTEXT_DLL "libintl.dll"
--- 130,177 ----
}
}

! WCHAR *
! utf8_to_utf16(const char *s)
{
! int size = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
! WCHAR *buf = (WCHAR *)malloc(size * sizeof(WCHAR));
! MultiByteToWideChar(CP_UTF8, 0, s, -1, buf, size);
! return 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
//
#ifndef FEAT_GETTEXT
! # define _(x) x
! # define W_impl(x) _wcsdup(L##x)
! # define W(x) W_impl(x)
! # define set_gettext_codeset() NULL
! # define restore_gettext_codeset(x)
#else
! # define _(x) (*dyn_libintl_gettext)(x)
! # define W(x) utf8_to_utf16(x)
# define VIMPACKAGE "vim"
# ifndef GETTEXT_DLL
# define GETTEXT_DLL "libintl.dll"
***************
*** 167,172 ****
--- 182,188 ----
static char *null_libintl_gettext(const char *);
static char *null_libintl_textdomain(const char *);
static char *null_libintl_bindtextdomain(const char *, const char *);
+ static char *null_libintl_bind_textdomain_codeset(const char *, const char *);
static int dyn_libintl_init(char *dir);
static void dyn_libintl_end(void);

***************
*** 175,180 ****
--- 191,198 ----
static char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain;
static char *(*dyn_libintl_bindtextdomain)(const char *, const char *)
= null_libintl_bindtextdomain;
+ static char *(*dyn_libintl_bind_textdomain_codeset)(const char *, const char *)
+ = null_libintl_bind_textdomain_codeset;

//
// Attempt to load libintl.dll. If it doesn't work, use dummy functions.
***************
*** 194,199 ****
--- 212,218 ----
{(char *)"gettext", (FARPROC*)&dyn_libintl_gettext},
{(char *)"textdomain", (FARPROC*)&dyn_libintl_textdomain},
{(char *)"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain},
+ {(char *)"bind_textdomain_codeset", (FARPROC*)&dyn_libintl_bind_textdomain_codeset},
{NULL, NULL}
};
DWORD len, len2;
***************
*** 254,259 ****
--- 273,279 ----
dyn_libintl_gettext = null_libintl_gettext;
dyn_libintl_textdomain = null_libintl_textdomain;
dyn_libintl_bindtextdomain = null_libintl_bindtextdomain;
+ dyn_libintl_bind_textdomain_codeset = null_libintl_bind_textdomain_codeset;
}

static char *
***************
*** 263,275 ****
}

static char *
null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */)
{
return NULL;
}

static char *
! null_libintl_textdomain(const char* /* domainname */)
{
return NULL;
}
--- 283,301 ----
}

static char *
+ null_libintl_textdomain(const char * /* domainname */)
+ {
+ return NULL;
+ }
+
+ static char *
null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */)
{
return NULL;
}

static char *
! null_libintl_bind_textdomain_codeset(const char * /* domainname */, const char * /* codeset */)
{
return NULL;
}
***************
*** 304,309 ****
--- 330,358 ----
{
dyn_libintl_end();
}
+
+ //
+ // Use UTF-8 for gettext. Returns previous codeset.
+ //
+ static char *
+ set_gettext_codeset(void)
+ {
+ char *prev = dyn_libintl_bind_textdomain_codeset(VIMPACKAGE, NULL);
+ prev = _strdup((prev != NULL) ? prev : "char");
+ dyn_libintl_bind_textdomain_codeset(VIMPACKAGE, "utf-8");
+
+ return prev;
+ }
+
+ //
+ // Restore previous codeset for gettext.
+ //
+ static void
+ restore_gettext_codeset(char *prev)
+ {
+ dyn_libintl_bind_textdomain_codeset(VIMPACKAGE, prev);
+ free(prev);
+ }
#endif // FEAT_GETTEXT

//
***************
*** 583,589 ****

hres = m_pDataObj->GetData(&fmte, &medium);
if (medium.hGlobal)
! cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0);

// InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

--- 632,638 ----

hres = m_pDataObj->GetData(&fmte, &medium);
if (medium.hGlobal)
! cbFiles = DragQueryFileW((HDROP)medium.hGlobal, (UINT)-1, 0, 0);

// InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

***************
*** 607,617 ****
RegCloseKey(keyhandle);
}

// Retrieve all the vim instances, unless disabled.
if (showExisting)
EnumWindows(EnumWindowsProc, (LPARAM)this);

! MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
mii.fMask = MIIM_STRING | MIIM_ID;
if (showIcons)
{
--- 656,669 ----
RegCloseKey(keyhandle);
}

+ // Use UTF-8 for gettext.
+ char *prev = set_gettext_codeset();
+
// Retrieve all the vim instances, unless disabled.
if (showExisting)
EnumWindows(EnumWindowsProc, (LPARAM)this);

! MENUITEMINFOW mii = { sizeof(MENUITEMINFOW) };
mii.fMask = MIIM_STRING | MIIM_ID;
if (showIcons)
{
***************
*** 622,643 ****
if (cbFiles > 1)
{
mii.wID = idCmd++;
! mii.dwTypeData = _("Edit with Vim using &tabpages");
! mii.cch = lstrlen(mii.dwTypeData);
! InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);

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
mii.wID = idCmd++;
! mii.dwTypeData = _("Diff with Vim");
! mii.cch = lstrlen(mii.dwTypeData);
! InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
m_edit_existing_off = 3;
}
else
--- 674,698 ----
if (cbFiles > 1)
{
mii.wID = idCmd++;
! mii.dwTypeData = W(_("Edit with Vim using &tabpages"));
! mii.cch = wcslen(mii.dwTypeData);
! InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
! free(mii.dwTypeData);

mii.wID = idCmd++;
! mii.dwTypeData = W(_("Edit with single &Vim"));
! mii.cch = wcslen(mii.dwTypeData);
! InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
! free(mii.dwTypeData);

if (cbFiles <= 4)
{
// Can edit up to 4 files in diff mode
mii.wID = idCmd++;
! mii.dwTypeData = W(_("Diff with Vim"));
! mii.cch = wcslen(mii.dwTypeData);
! InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
! free(mii.dwTypeData);
m_edit_existing_off = 3;
}
else
***************
*** 647,655 ****
else
{
mii.wID = idCmd++;
! mii.dwTypeData = _("Edit with &Vim");
! mii.cch = lstrlen(mii.dwTypeData);
! InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
m_edit_existing_off = 1;
}

--- 702,711 ----
else
{
mii.wID = idCmd++;
! mii.dwTypeData = W(_("Edit with &Vim"));
! mii.cch = wcslen(mii.dwTypeData);
! InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
! free(mii.dwTypeData);
m_edit_existing_off = 1;
}

***************
*** 659,704 ****
hSubMenu = CreatePopupMenu();
mii.fMask |= MIIM_SUBMENU;
mii.wID = idCmd;
! mii.dwTypeData = _("Edit with existing Vim");
! mii.cch = lstrlen(mii.dwTypeData);
mii.hSubMenu = hSubMenu;
! InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
mii.fMask = mii.fMask & ~MIIM_SUBMENU;
mii.hSubMenu = NULL;
}
// Now display all the vim instances
for (int i = 0; i < m_cntOfHWnd; i++)
{
! char title[BUFSIZE];
! char temp[BUFSIZE];
int index;
HMENU hmenu;

// Obtain window title, continue if can not
! if (GetWindowText(m_hWnd[i], title, BUFSIZE - 1) == 0)
continue;
// Truncate the title before the path, keep the file name
! char *pos = strchr(title, '(');
if (pos != NULL)
{
! if (pos > title && pos[-1] == ' ')
--pos;
*pos = 0;
}
// Now concatenate
if (m_cntOfHWnd > 1)
! temp[0] = '\0';
else
{
! strncpy(temp, _("Edit with existing Vim - "), BUFSIZE - 1);
! temp[BUFSIZE - 1] = '\0';
}
! strncat(temp, title, BUFSIZE - 1 - strlen(temp));
! temp[BUFSIZE - 1] = '\0';

mii.wID = idCmd++;
mii.dwTypeData = temp;
! mii.cch = lstrlen(mii.dwTypeData);
if (m_cntOfHWnd > 1)
{
hmenu = hSubMenu;
--- 715,763 ----
hSubMenu = CreatePopupMenu();
mii.fMask |= MIIM_SUBMENU;
mii.wID = idCmd;
! mii.dwTypeData = W(_("Edit with existing Vim"));
! mii.cch = wcslen(mii.dwTypeData);
mii.hSubMenu = hSubMenu;
! InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
! free(mii.dwTypeData);
mii.fMask = mii.fMask & ~MIIM_SUBMENU;
mii.hSubMenu = NULL;
}
// Now display all the vim instances
for (int i = 0; i < m_cntOfHWnd; i++)
{
! WCHAR title[BUFSIZE];
! WCHAR temp[BUFSIZE];
int index;
HMENU hmenu;

// Obtain window title, continue if can not
! if (GetWindowTextW(m_hWnd[i], title, BUFSIZE - 1) == 0)
continue;
// Truncate the title before the path, keep the file name
! WCHAR *pos = wcschr(title, L'(');
if (pos != NULL)
{
! if (pos > title && pos[-1] == L' ')
--pos;
*pos = 0;
}
// Now concatenate
if (m_cntOfHWnd > 1)
! temp[0] = L'\0';
else
{
! WCHAR *s = W(_("Edit with existing Vim - "));
! wcsncpy(temp, s, BUFSIZE - 1);
! temp[BUFSIZE - 1] = L'\0';
! free(s);
}
! wcsncat(temp, title, BUFSIZE - 1 - wcslen(temp));
! temp[BUFSIZE - 1] = L'\0';

mii.wID = idCmd++;
mii.dwTypeData = temp;
! mii.cch = wcslen(mii.dwTypeData);
if (m_cntOfHWnd > 1)
{
hmenu = hSubMenu;
***************
*** 709,718 ****
hmenu = hMenu;
index = indexMenu++;
}
! InsertMenuItem(hmenu, index, TRUE, &mii);
}
// InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

// Must return number of menu items we added.
return ResultFromShort(idCmd-idCmdFirst);
}
--- 768,780 ----
hmenu = hMenu;
index = indexMenu++;
}
! InsertMenuItemW(hmenu, index, TRUE, &mii);
}
// InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

+ // Restore previous codeset.
+ restore_gettext_codeset(prev);
+
// Must return number of menu items we added.
return ResultFromShort(idCmd-idCmdFirst);
}
***************
*** 819,826 ****
LPSTR pszName,
UINT cchMax)
{
! if (uFlags == GCS_HELPTEXT && cchMax > 35)
! lstrcpy(pszName, _("Edits the selected file(s) with Vim"));

return NOERROR;
}
--- 881,896 ----
LPSTR pszName,
UINT cchMax)
{
! // Use UTF-8 for gettext.
! char *prev = set_gettext_codeset();
!
! WCHAR *s = W(_("Edits the selected file(s) with Vim"));
! if (uFlags == GCS_HELPTEXTW && cchMax > wcslen(s))
! wcscpy((WCHAR *)pszName, s);
! free(s);
!
! // Restore previous codeset.
! restore_gettext_codeset(prev);

return NOERROR;
}
***************
*** 831,837 ****

// First do a bunch of check
// No invisible window
! if (!IsWindowVisible(hWnd)) return TRUE;
// No child window ???
// if (GetParent(hWnd)) return TRUE;
// Class name should be Vim, if failed to get class name, return
--- 901,908 ----

// First do a bunch of check
// No invisible window
! if (!IsWindowVisible(hWnd))
! return TRUE;
// No child window ???
// if (GetParent(hWnd)) return TRUE;
// Class name should be Vim, if failed to get class name, return
***************
*** 842,848 ****
return TRUE;
// First check if the number of vim instance exceeds MAX_HWND
CShellExt *cs = (CShellExt*) lParam;
! if (cs->m_cntOfHWnd >= MAX_HWND) return TRUE;
// Now we get the vim window, put it into some kind of array
cs->m_hWnd[cs->m_cntOfHWnd] = hWnd;
cs->m_cntOfHWnd ++;
--- 913,920 ----
return TRUE;
// First check if the number of vim instance exceeds MAX_HWND
CShellExt *cs = (CShellExt*) lParam;
! if (cs->m_cntOfHWnd >= MAX_HWND)
! return FALSE; // stop enumeration
// Now we get the vim window, put it into some kind of array
cs->m_hWnd[cs->m_cntOfHWnd] = hWnd;
cs->m_cntOfHWnd ++;
***************
*** 852,869 ****

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;
}

static char *
--- 924,941 ----

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;
}

static char *
***************
*** 948,963 ****
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
! workingDir, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi) // Pointer to PROCESS_INFORMATION structure.
)
{
! MessageBox(
! hParent,
! _("Error creating process: Check if gvim is in your path!"),
! _("gvimext.dll error"),
! MB_OK);
}
else
{
--- 1020,1043 ----
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
! workingDir, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi) // Pointer to PROCESS_INFORMATION structure.
)
{
! // Use UTF-8 for gettext.
! char *prev = set_gettext_codeset();
!
! WCHAR *msg = W(_("Error creating process: Check if gvim is in your path!"));
! WCHAR *title = W(_("gvimext.dll error"));
!
! MessageBoxW(hParent, msg, title, MB_OK);
!
! free(msg);
! free(title);
!
! // Restore previous codeset.
! restore_gettext_codeset(prev);
}
else
{
*** ../vim-9.0.1576/src/GvimExt/gvimext.h 2022-01-24 11:12:27.000000000 +0000
--- src/GvimExt/gvimext.h 2023-05-25 16:39:16.898728119 +0100
***************
*** 81,101 ****
class CShellExtClassFactory : public IClassFactory
{
protected:
! ULONG m_cRef;

public:
! CShellExtClassFactory();
! ~CShellExtClassFactory();

! //IUnknown members
! STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
! STDMETHODIMP_(ULONG) AddRef();
! STDMETHODIMP_(ULONG) Release();
!
! //IClassFactory members
! STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
! STDMETHODIMP LockServer(BOOL);

};
typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY;
#define MAX_HWND 100
--- 81,100 ----
class CShellExtClassFactory : public IClassFactory
{
protected:
! ULONG m_cRef;

public:
! CShellExtClassFactory();
! ~CShellExtClassFactory();

! //IUnknown members
! STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
! STDMETHODIMP_(ULONG) AddRef();
! STDMETHODIMP_(ULONG) Release();

+ //IClassFactory members
+ STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
+ STDMETHODIMP LockServer(BOOL);
};
typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY;
#define MAX_HWND 100
*** ../vim-9.0.1576/src/version.c 2023-05-24 21:02:20.489162125 +0100
--- src/version.c 2023-05-25 16:41:22.770738804 +0100
***************
*** 697,698 ****
--- 697,700 ----
{ /* Add new patch number below this line */
+ /**/
+ 1577,
/**/

--
hundred-and-one symptoms of being an internet addict:
75. You start wondering whether you could actually upgrade your brain
with a Pentium Pro microprocessor 80. The upgrade works just fine.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages