patch 9.0.1577: MS-Windows: context menu translations may be wrong

Problem:    MS-Windows: context menu translations may be wrong.
Solution:   Set the encoding before using gettext(). (Ken Takata,
            closes #12441, closes #12431)
This commit is contained in:
K.Takata
2023-05-25 16:43:27 +01:00
committed by Bram Moolenaar
parent 097c5370ea
commit 1271572a35
5 changed files with 167 additions and 85 deletions

View File

@ -43,9 +43,9 @@ else
DEL = del DEL = del
endif endif
endif endif
# Set the default $(WINVER) to make it work with WinXP. # Set the default $(WINVER) to make it work with Windows 7.
ifndef WINVER ifndef WINVER
WINVER = 0x0501 WINVER = 0x0601
endif endif
CXX := $(CROSS_COMPILE)g++ CXX := $(CROSS_COMPILE)g++
WINDRES := $(CROSS_COMPILE)windres WINDRES := $(CROSS_COMPILE)windres

View File

@ -8,10 +8,11 @@
TARGETOS = WINNT TARGETOS = WINNT
!ifndef APPVER !ifndef APPVER
APPVER = 5.01 APPVER = 6.01
!endif !endif
# Set the default $(WINVER) to make it work with Windows 7.
!ifndef WINVER !ifndef WINVER
WINVER = 0x0501 WINVER = 0x0601
!endif !endif
!if "$(DEBUG)" != "yes" !if "$(DEBUG)" != "yes"
@ -40,9 +41,9 @@ CPU = i386
!endif !endif
!ifdef SDK_INCLUDE_DIR !ifdef SDK_INCLUDE_DIR
!include $(SDK_INCLUDE_DIR)\Win32.mak ! include $(SDK_INCLUDE_DIR)\Win32.mak
!elseif "$(USE_WIN32MAK)"=="yes" !elseif "$(USE_WIN32MAK)"=="yes"
!include <Win32.mak> ! include <Win32.mak>
!else !else
cc = cl cc = cl
link = link link = link

View File

@ -130,7 +130,17 @@ getRuntimeDir(char *buf)
} }
} }
HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height) 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 hDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hDC); HDC hMemDC = CreateCompatibleDC(hDC);
@ -155,8 +165,13 @@ HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height)
// //
#ifndef FEAT_GETTEXT #ifndef FEAT_GETTEXT
# define _(x) x # 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 #else
# define _(x) (*dyn_libintl_gettext)(x) # define _(x) (*dyn_libintl_gettext)(x)
# define W(x) utf8_to_utf16(x)
# define VIMPACKAGE "vim" # define VIMPACKAGE "vim"
# ifndef GETTEXT_DLL # ifndef GETTEXT_DLL
# define GETTEXT_DLL "libintl.dll" # define GETTEXT_DLL "libintl.dll"
@ -167,6 +182,7 @@ HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height)
static char *null_libintl_gettext(const char *); static char *null_libintl_gettext(const char *);
static char *null_libintl_textdomain(const char *); static char *null_libintl_textdomain(const char *);
static char *null_libintl_bindtextdomain(const char *, 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 int dyn_libintl_init(char *dir);
static void dyn_libintl_end(void); static void dyn_libintl_end(void);
@ -175,6 +191,8 @@ static char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext;
static char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain; static char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain;
static char *(*dyn_libintl_bindtextdomain)(const char *, const char *) static char *(*dyn_libintl_bindtextdomain)(const char *, const char *)
= null_libintl_bindtextdomain; = 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. // Attempt to load libintl.dll. If it doesn't work, use dummy functions.
@ -194,6 +212,7 @@ dyn_libintl_init(char *dir)
{(char *)"gettext", (FARPROC*)&dyn_libintl_gettext}, {(char *)"gettext", (FARPROC*)&dyn_libintl_gettext},
{(char *)"textdomain", (FARPROC*)&dyn_libintl_textdomain}, {(char *)"textdomain", (FARPROC*)&dyn_libintl_textdomain},
{(char *)"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain}, {(char *)"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain},
{(char *)"bind_textdomain_codeset", (FARPROC*)&dyn_libintl_bind_textdomain_codeset},
{NULL, NULL} {NULL, NULL}
}; };
DWORD len, len2; DWORD len, len2;
@ -254,6 +273,7 @@ dyn_libintl_end(void)
dyn_libintl_gettext = null_libintl_gettext; dyn_libintl_gettext = null_libintl_gettext;
dyn_libintl_textdomain = null_libintl_textdomain; dyn_libintl_textdomain = null_libintl_textdomain;
dyn_libintl_bindtextdomain = null_libintl_bindtextdomain; dyn_libintl_bindtextdomain = null_libintl_bindtextdomain;
dyn_libintl_bind_textdomain_codeset = null_libintl_bind_textdomain_codeset;
} }
static char * static char *
@ -262,6 +282,12 @@ null_libintl_gettext(const char *msgid)
return (char *)msgid; return (char *)msgid;
} }
static char *
null_libintl_textdomain(const char * /* domainname */)
{
return NULL;
}
static char * static char *
null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */) null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */)
{ {
@ -269,7 +295,7 @@ null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirna
} }
static char * static char *
null_libintl_textdomain(const char* /* domainname */) null_libintl_bind_textdomain_codeset(const char * /* domainname */, const char * /* codeset */)
{ {
return NULL; return NULL;
} }
@ -304,6 +330,29 @@ dyn_gettext_free(void)
{ {
dyn_libintl_end(); 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 #endif // FEAT_GETTEXT
// //
@ -583,7 +632,7 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
hres = m_pDataObj->GetData(&fmte, &medium); hres = m_pDataObj->GetData(&fmte, &medium);
if (medium.hGlobal) if (medium.hGlobal)
cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0); cbFiles = DragQueryFileW((HDROP)medium.hGlobal, (UINT)-1, 0, 0);
// InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
@ -607,11 +656,14 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
RegCloseKey(keyhandle); RegCloseKey(keyhandle);
} }
// Use UTF-8 for gettext.
char *prev = set_gettext_codeset();
// Retrieve all the vim instances, unless disabled. // Retrieve all the vim instances, unless disabled.
if (showExisting) if (showExisting)
EnumWindows(EnumWindowsProc, (LPARAM)this); EnumWindows(EnumWindowsProc, (LPARAM)this);
MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; MENUITEMINFOW mii = { sizeof(MENUITEMINFOW) };
mii.fMask = MIIM_STRING | MIIM_ID; mii.fMask = MIIM_STRING | MIIM_ID;
if (showIcons) if (showIcons)
{ {
@ -622,22 +674,25 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
if (cbFiles > 1) if (cbFiles > 1)
{ {
mii.wID = idCmd++; mii.wID = idCmd++;
mii.dwTypeData = _("Edit with Vim using &tabpages"); mii.dwTypeData = W(_("Edit with Vim using &tabpages"));
mii.cch = lstrlen(mii.dwTypeData); mii.cch = wcslen(mii.dwTypeData);
InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
free(mii.dwTypeData);
mii.wID = idCmd++; mii.wID = idCmd++;
mii.dwTypeData = _("Edit with single &Vim"); mii.dwTypeData = W(_("Edit with single &Vim"));
mii.cch = lstrlen(mii.dwTypeData); mii.cch = wcslen(mii.dwTypeData);
InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
free(mii.dwTypeData);
if (cbFiles <= 4) if (cbFiles <= 4)
{ {
// Can edit up to 4 files in diff mode // Can edit up to 4 files in diff mode
mii.wID = idCmd++; mii.wID = idCmd++;
mii.dwTypeData = _("Diff with Vim"); mii.dwTypeData = W(_("Diff with Vim"));
mii.cch = lstrlen(mii.dwTypeData); mii.cch = wcslen(mii.dwTypeData);
InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
free(mii.dwTypeData);
m_edit_existing_off = 3; m_edit_existing_off = 3;
} }
else else
@ -647,9 +702,10 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
else else
{ {
mii.wID = idCmd++; mii.wID = idCmd++;
mii.dwTypeData = _("Edit with &Vim"); mii.dwTypeData = W(_("Edit with &Vim"));
mii.cch = lstrlen(mii.dwTypeData); mii.cch = wcslen(mii.dwTypeData);
InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
free(mii.dwTypeData);
m_edit_existing_off = 1; m_edit_existing_off = 1;
} }
@ -659,46 +715,49 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
hSubMenu = CreatePopupMenu(); hSubMenu = CreatePopupMenu();
mii.fMask |= MIIM_SUBMENU; mii.fMask |= MIIM_SUBMENU;
mii.wID = idCmd; mii.wID = idCmd;
mii.dwTypeData = _("Edit with existing Vim"); mii.dwTypeData = W(_("Edit with existing Vim"));
mii.cch = lstrlen(mii.dwTypeData); mii.cch = wcslen(mii.dwTypeData);
mii.hSubMenu = hSubMenu; mii.hSubMenu = hSubMenu;
InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
free(mii.dwTypeData);
mii.fMask = mii.fMask & ~MIIM_SUBMENU; mii.fMask = mii.fMask & ~MIIM_SUBMENU;
mii.hSubMenu = NULL; mii.hSubMenu = NULL;
} }
// Now display all the vim instances // Now display all the vim instances
for (int i = 0; i < m_cntOfHWnd; i++) for (int i = 0; i < m_cntOfHWnd; i++)
{ {
char title[BUFSIZE]; WCHAR title[BUFSIZE];
char temp[BUFSIZE]; WCHAR temp[BUFSIZE];
int index; int index;
HMENU hmenu; HMENU hmenu;
// Obtain window title, continue if can not // Obtain window title, continue if can not
if (GetWindowText(m_hWnd[i], title, BUFSIZE - 1) == 0) if (GetWindowTextW(m_hWnd[i], title, BUFSIZE - 1) == 0)
continue; continue;
// Truncate the title before the path, keep the file name // Truncate the title before the path, keep the file name
char *pos = strchr(title, '('); WCHAR *pos = wcschr(title, L'(');
if (pos != NULL) if (pos != NULL)
{ {
if (pos > title && pos[-1] == ' ') if (pos > title && pos[-1] == L' ')
--pos; --pos;
*pos = 0; *pos = 0;
} }
// Now concatenate // Now concatenate
if (m_cntOfHWnd > 1) if (m_cntOfHWnd > 1)
temp[0] = '\0'; temp[0] = L'\0';
else else
{ {
strncpy(temp, _("Edit with existing Vim - "), BUFSIZE - 1); WCHAR *s = W(_("Edit with existing Vim - "));
temp[BUFSIZE - 1] = '\0'; wcsncpy(temp, s, BUFSIZE - 1);
temp[BUFSIZE - 1] = L'\0';
free(s);
} }
strncat(temp, title, BUFSIZE - 1 - strlen(temp)); wcsncat(temp, title, BUFSIZE - 1 - wcslen(temp));
temp[BUFSIZE - 1] = '\0'; temp[BUFSIZE - 1] = L'\0';
mii.wID = idCmd++; mii.wID = idCmd++;
mii.dwTypeData = temp; mii.dwTypeData = temp;
mii.cch = lstrlen(mii.dwTypeData); mii.cch = wcslen(mii.dwTypeData);
if (m_cntOfHWnd > 1) if (m_cntOfHWnd > 1)
{ {
hmenu = hSubMenu; hmenu = hSubMenu;
@ -709,10 +768,13 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
hmenu = hMenu; hmenu = hMenu;
index = indexMenu++; index = indexMenu++;
} }
InsertMenuItem(hmenu, index, TRUE, &mii); InsertMenuItemW(hmenu, index, TRUE, &mii);
} }
// InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
// Restore previous codeset.
restore_gettext_codeset(prev);
// Must return number of menu items we added. // Must return number of menu items we added.
return ResultFromShort(idCmd-idCmdFirst); return ResultFromShort(idCmd-idCmdFirst);
} }
@ -819,8 +881,16 @@ STDMETHODIMP CShellExt::GetCommandString(UINT_PTR /* idCmd */,
LPSTR pszName, LPSTR pszName,
UINT cchMax) UINT cchMax)
{ {
if (uFlags == GCS_HELPTEXT && cchMax > 35) // Use UTF-8 for gettext.
lstrcpy(pszName, _("Edits the selected file(s) with Vim")); 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; return NOERROR;
} }
@ -831,7 +901,8 @@ BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam)
// First do a bunch of check // First do a bunch of check
// No invisible window // No invisible window
if (!IsWindowVisible(hWnd)) return TRUE; if (!IsWindowVisible(hWnd))
return TRUE;
// No child window ??? // No child window ???
// if (GetParent(hWnd)) return TRUE; // if (GetParent(hWnd)) return TRUE;
// Class name should be Vim, if failed to get class name, return // Class name should be Vim, if failed to get class name, return
@ -842,7 +913,8 @@ BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam)
return TRUE; return TRUE;
// First check if the number of vim instance exceeds MAX_HWND // First check if the number of vim instance exceeds MAX_HWND
CShellExt *cs = (CShellExt*) lParam; CShellExt *cs = (CShellExt*) lParam;
if (cs->m_cntOfHWnd >= MAX_HWND) return TRUE; if (cs->m_cntOfHWnd >= MAX_HWND)
return FALSE; // stop enumeration
// Now we get the vim window, put it into some kind of array // Now we get the vim window, put it into some kind of array
cs->m_hWnd[cs->m_cntOfHWnd] = hWnd; cs->m_hWnd[cs->m_cntOfHWnd] = hWnd;
cs->m_cntOfHWnd ++; cs->m_cntOfHWnd ++;
@ -953,11 +1025,19 @@ STDMETHODIMP CShellExt::InvokeSingleGvim(HWND hParent,
&pi) // Pointer to PROCESS_INFORMATION structure. &pi) // Pointer to PROCESS_INFORMATION structure.
) )
{ {
MessageBox( // Use UTF-8 for gettext.
hParent, char *prev = set_gettext_codeset();
_("Error creating process: Check if gvim is in your path!"),
_("gvimext.dll error"), WCHAR *msg = W(_("Error creating process: Check if gvim is in your path!"));
MB_OK); WCHAR *title = W(_("gvimext.dll error"));
MessageBoxW(hParent, msg, title, MB_OK);
free(msg);
free(title);
// Restore previous codeset.
restore_gettext_codeset(prev);
} }
else else
{ {

View File

@ -95,7 +95,6 @@ public:
//IClassFactory members //IClassFactory members
STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *); STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
STDMETHODIMP LockServer(BOOL); STDMETHODIMP LockServer(BOOL);
}; };
typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY; typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY;
#define MAX_HWND 100 #define MAX_HWND 100

View File

@ -695,6 +695,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1577,
/**/ /**/
1576, 1576,
/**/ /**/