To: vim_dev@googlegroups.com Subject: Patch 9.0.1577 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 !else cc = cl link = link --- 41,49 ---- !endif !ifdef SDK_INCLUDE_DIR ! ! include $(SDK_INCLUDE_DIR)\Win32.mak !elseif "$(USE_WIN32MAK)"=="yes" ! ! include !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 -- Bram@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 ///