# HG changeset patch # User Bram Moolenaar # Date 1685029505 -7200 # Node ID 32c9b7396a75bca70b8717490c965e9f476ba2d6 # Parent 4f54d3384e4823bd06560afbc26699478546fc86 patch 9.0.1577: MS-Windows: context menu translations may be wrong Commit: https://github.com/vim/vim/commit/1271572a35ae215fa023d97db9896c5745591024 Author: K.Takata Date: Thu May 25 16:43:27 2023 +0100 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) diff --git a/src/GvimExt/Make_ming.mak b/src/GvimExt/Make_ming.mak --- a/src/GvimExt/Make_ming.mak +++ b/src/GvimExt/Make_ming.mak @@ -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 diff --git a/src/GvimExt/Make_mvc.mak b/src/GvimExt/Make_mvc.mak --- a/src/GvimExt/Make_mvc.mak +++ b/src/GvimExt/Make_mvc.mak @@ -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 +! include !else cc = cl link = link diff --git a/src/GvimExt/gvimext.cpp b/src/GvimExt/gvimext.cpp --- a/src/GvimExt/gvimext.cpp +++ b/src/GvimExt/gvimext.cpp @@ -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); + 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; +} - DrawIconEx(hMemDC, 0, 0, hIcon, width, height, 0, hBackground, DI_NORMAL); - - hResultBmp = hMemBmp; - hMemBmp = NULL; + 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); - SelectObject(hMemDC, hOrgBMP); - DeleteDC(hMemDC); - ReleaseDC(NULL, hDC); - DestroyIcon(hIcon); - return hResultBmp; + 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 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)(cons 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 * @@ -263,13 +283,19 @@ null_libintl_gettext(const char *msgid) } 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_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 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 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 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 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 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; 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 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 // 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 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 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 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 { diff --git a/src/GvimExt/gvimext.h b/src/GvimExt/gvimext.h --- a/src/GvimExt/gvimext.h +++ b/src/GvimExt/gvimext.h @@ -81,21 +81,20 @@ DEFINE_GUID(CLSID_ShellExtension, 0x51ee 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(); + //IUnknown members + STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); - //IClassFactory members - STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *); - STDMETHODIMP LockServer(BOOL); - + //IClassFactory members + STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *); + STDMETHODIMP LockServer(BOOL); }; typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY; #define MAX_HWND 100 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1577, +/**/ 1576, /**/ 1575,