]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1577: MS-Windows: context menu translations may be wrong v9.0.1577
authorK.Takata <kentkt@csc.jp>
Thu, 25 May 2023 15:43:27 +0000 (16:43 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 25 May 2023 15:43:27 +0000 (16:43 +0100)
Problem:    MS-Windows: context menu translations may be wrong.
Solution:   Set the encoding before using gettext(). (Ken Takata,
            closes #12441, closes #12431)

src/GvimExt/Make_ming.mak
src/GvimExt/Make_mvc.mak
src/GvimExt/gvimext.cpp
src/GvimExt/gvimext.h
src/version.c

index 0ebe08a4e5fd3c4dc821539564e49d53ea5be5a2..85017d89f79a466c01e3d4158d06d7d7500ba940 100644 (file)
@@ -43,9 +43,9 @@ else
 DEL = del
 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
-WINVER = 0x0501
+WINVER = 0x0601
 endif
 CXX := $(CROSS_COMPILE)g++
 WINDRES := $(CROSS_COMPILE)windres
index 4b83f52dd5e4e7c9967166eeb663ffee9e6ed4ea..7068d8f70e3dd715473a1358c21f897ab1ba8134 100644 (file)
@@ -8,10 +8,11 @@
 TARGETOS = WINNT
 
 !ifndef APPVER
-APPVER = 5.01
+APPVER = 6.01
 !endif
+# Set the default $(WINVER) to make it work with Windows 7.
 !ifndef WINVER
-WINVER = 0x0501
+WINVER = 0x0601
 !endif
 
 !if "$(DEBUG)" != "yes"
@@ -40,9 +41,9 @@ CPU = i386
 !endif
 
 !ifdef SDK_INCLUDE_DIR
-!include $(SDK_INCLUDE_DIR)\Win32.mak
+! include $(SDK_INCLUDE_DIR)\Win32.mak
 !elseif "$(USE_WIN32MAK)"=="yes"
-!include <Win32.mak>
+! include <Win32.mak>
 !else
 cc = cl
 link = link
index dd26eb1b694b3b248a125ae4939420c0343d95fb..e58b142555c57153105d0ac1adc846fc0136874d 100644 (file)
@@ -130,33 +130,48 @@ getRuntimeDir(char *buf)
     }
 }
 
-HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height)
+    WCHAR *
+utf8_to_utf16(const char *s)
 {
-       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;
+    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;
+}
 
-       SelectObject(hMemDC, hOrgBMP);
-       DeleteDC(hMemDC);
-       ReleaseDC(NULL, hDC);
-       DestroyIcon(hIcon);
-       return hResultBmp;
+    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 _(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 _(x)      (*dyn_libintl_gettext)(x)
+# define W(x)      utf8_to_utf16(x)
 # define VIMPACKAGE "vim"
 # ifndef GETTEXT_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_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,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_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,6 +212,7 @@ dyn_libintl_init(char *dir)
        {(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,6 +273,7 @@ dyn_libintl_end(void)
     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 *
@@ -262,6 +282,12 @@ null_libintl_gettext(const char *msgid)
     return (char *)msgid;
 }
 
+    static char *
+null_libintl_textdomain(const char * /* domainname */)
+{
+    return NULL;
+}
+
     static char *
 null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */)
 {
@@ -269,7 +295,7 @@ null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirna
 }
 
     static char *
-null_libintl_textdomain(const char*  /* domainname */)
+null_libintl_bind_textdomain_codeset(const char * /* domainname */, const char * /* codeset */)
 {
     return NULL;
 }
@@ -304,6 +330,29 @@ dyn_gettext_free(void)
 {
     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,7 +632,7 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
 
     hres = m_pDataObj->GetData(&fmte, &medium);
     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);
 
@@ -607,11 +656,14 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
        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);
 
-    MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
+    MENUITEMINFOW mii = { sizeof(MENUITEMINFOW) };
     mii.fMask = MIIM_STRING | MIIM_ID;
     if (showIcons)
     {
@@ -622,22 +674,25 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
     if (cbFiles > 1)
     {
        mii.wID = idCmd++;
-       mii.dwTypeData = _("Edit with Vim using &tabpages");
-       mii.cch = lstrlen(mii.dwTypeData);
-       InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+       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 = _("Edit with single &Vim");
-       mii.cch = lstrlen(mii.dwTypeData);
-       InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+       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 = _("Diff with Vim");
-           mii.cch = lstrlen(mii.dwTypeData);
-           InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+           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,9 +702,10 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
     else
     {
        mii.wID = idCmd++;
-       mii.dwTypeData = _("Edit with &Vim");
-       mii.cch = lstrlen(mii.dwTypeData);
-       InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+       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,46 +715,49 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
        hSubMenu = CreatePopupMenu();
        mii.fMask |= MIIM_SUBMENU;
        mii.wID = idCmd;
-       mii.dwTypeData = _("Edit with existing Vim");
-       mii.cch = lstrlen(mii.dwTypeData);
+       mii.dwTypeData = W(_("Edit with existing Vim"));
+       mii.cch = wcslen(mii.dwTypeData);
        mii.hSubMenu = hSubMenu;
-       InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+       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++)
     {
-       char title[BUFSIZE];
-       char temp[BUFSIZE];
+       WCHAR title[BUFSIZE];
+       WCHAR temp[BUFSIZE];
        int index;
        HMENU hmenu;
 
        // 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;
        // Truncate the title before the path, keep the file name
-       char *pos = strchr(title, '(');
+       WCHAR *pos = wcschr(title, L'(');
        if (pos != NULL)
        {
-           if (pos > title && pos[-1] == ' ')
+           if (pos > title && pos[-1] == L' ')
                --pos;
            *pos = 0;
        }
        // Now concatenate
        if (m_cntOfHWnd > 1)
-           temp[0] = '\0';
+           temp[0] = L'\0';
        else
        {
-           strncpy(temp, _("Edit with existing Vim - "), BUFSIZE - 1);
-           temp[BUFSIZE - 1] = '\0';
+           WCHAR *s = W(_("Edit with existing Vim - "));
+           wcsncpy(temp, s, BUFSIZE - 1);
+           temp[BUFSIZE - 1] = L'\0';
+           free(s);
        }
-       strncat(temp, title, BUFSIZE - 1 - strlen(temp));
-       temp[BUFSIZE - 1] = '\0';
+       wcsncat(temp, title, BUFSIZE - 1 - wcslen(temp));
+       temp[BUFSIZE - 1] = L'\0';
 
        mii.wID = idCmd++;
        mii.dwTypeData = temp;
-       mii.cch = lstrlen(mii.dwTypeData);
+       mii.cch = wcslen(mii.dwTypeData);
        if (m_cntOfHWnd > 1)
        {
            hmenu = hSubMenu;
@@ -709,10 +768,13 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
            hmenu = hMenu;
            index = indexMenu++;
        }
-       InsertMenuItem(hmenu, index, TRUE, &mii);
+       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,8 +881,16 @@ STDMETHODIMP CShellExt::GetCommandString(UINT_PTR  /* idCmd */,
                                         LPSTR pszName,
                                         UINT cchMax)
 {
-    if (uFlags == GCS_HELPTEXT && cchMax > 35)
-       lstrcpy(pszName, _("Edits the selected file(s) with Vim"));
+    // 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,7 +901,8 @@ BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam)
 
     // First do a bunch of check
     // No invisible window
-    if (!IsWindowVisible(hWnd)) return TRUE;
+    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,7 +913,8 @@ BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam)
        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;
+    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,18 +924,18 @@ BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam)
 
 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;
+    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,16 +1020,24 @@ STDMETHODIMP CShellExt::InvokeSingleGvim(HWND hParent,
                FALSE,          // Set handle inheritance to FALSE.
                0,              // No creation flags.
                NULL,           // Use parent's environment block.
-               workingDir,  // Use parent's starting directory.
+               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);
+       // 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
     {
index b85f32e2046083e1480d7d1cd4364da2fd201741..e7bcfb84f0627bc0656d169175c1aa8442cf1da9 100644 (file)
@@ -81,21 +81,20 @@ DEFINE_GUID(CLSID_ShellExtension, 0x51eee242, 0xad87, 0x11d3, 0x9c, 0x1e, 0x0, 0
 class CShellExtClassFactory : public IClassFactory
 {
 protected:
-       ULONG   m_cRef;
+    ULONG      m_cRef;
 
 public:
-       CShellExtClassFactory();
-       ~CShellExtClassFactory();
+    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);
+    //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
index d9ce3d1a96352500c85c33d5258e868321055d55..02be5bf57dc9027f251ecde609eee8b886b85121 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1577,
 /**/
     1576,
 /**/