changeset 5318:8e28c23e482c v7.4.012

updated for version 7.4.012 Problem: MS-Windows: resolving shortcut does not work properly with multi-byte characters. Solution: Use wide system functions. (Ken Takata)
author Bram Moolenaar <bram@vim.org>
date Fri, 30 Aug 2013 16:44:19 +0200
parents 076f115ed30d
children 5f5d9a89de82
files src/os_mswin.c src/version.c
diffstat 2 files changed, 62 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -1761,9 +1761,13 @@ mch_resolve_shortcut(char_u *fname)
     IPersistFile	*ppf = NULL;
     OLECHAR		wsz[MAX_PATH];
     WIN32_FIND_DATA	ffd; // we get those free of charge
-    TCHAR		buf[MAX_PATH]; // could have simply reused 'wsz'...
+    CHAR		buf[MAX_PATH]; // could have simply reused 'wsz'...
     char_u		*rfname = NULL;
     int			len;
+# ifdef FEAT_MBYTE
+    IShellLinkW		*pslw = NULL;
+    WIN32_FIND_DATAW	ffdw; // we get those free of charge
+# endif
 
     /* Check if the file name ends in ".lnk". Avoid calling
      * CoCreateInstance(), it's quite slow. */
@@ -1775,18 +1779,62 @@ mch_resolve_shortcut(char_u *fname)
 
     CoInitialize(NULL);
 
+# ifdef FEAT_MBYTE
+    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+    {
+	// create a link manager object and request its interface
+	hr = CoCreateInstance(
+		&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+		&IID_IShellLinkW, (void**)&pslw);
+	if (hr == S_OK)
+	{
+	    WCHAR	*p = enc_to_utf16(fname, NULL);
+
+	    if (p != NULL)
+	    {
+		// Get a pointer to the IPersistFile interface.
+		hr = pslw->lpVtbl->QueryInterface(
+			pslw, &IID_IPersistFile, (void**)&ppf);
+		if (hr != S_OK)
+		    goto shortcut_errorw;
+
+		// "load" the name and resolve the link
+		hr = ppf->lpVtbl->Load(ppf, p, STGM_READ);
+		if (hr != S_OK)
+		    goto shortcut_errorw;
+#  if 0  // This makes Vim wait a long time if the target does not exist.
+		hr = pslw->lpVtbl->Resolve(pslw, NULL, SLR_NO_UI);
+		if (hr != S_OK)
+		    goto shortcut_errorw;
+#  endif
+
+		// Get the path to the link target.
+		ZeroMemory(wsz, MAX_PATH * sizeof(WCHAR));
+		hr = pslw->lpVtbl->GetPath(pslw, wsz, MAX_PATH, &ffdw, 0);
+		if (hr == S_OK && wsz[0] != NUL)
+		    rfname = utf16_to_enc(wsz, NULL);
+
+shortcut_errorw:
+		vim_free(p);
+		if (hr == S_OK)
+		    goto shortcut_end;
+	    }
+	}
+	/* Retry with non-wide function (for Windows 98). */
+    }
+# endif
     // create a link manager object and request its interface
     hr = CoCreateInstance(
 	    &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
 	    &IID_IShellLink, (void**)&psl);
     if (hr != S_OK)
-	goto shortcut_error;
+	goto shortcut_end;
 
     // Get a pointer to the IPersistFile interface.
     hr = psl->lpVtbl->QueryInterface(
 	    psl, &IID_IPersistFile, (void**)&ppf);
     if (hr != S_OK)
-	goto shortcut_error;
+	goto shortcut_end;
 
     // full path string must be in Unicode.
     MultiByteToWideChar(CP_ACP, 0, fname, -1, wsz, MAX_PATH);
@@ -1794,12 +1842,12 @@ mch_resolve_shortcut(char_u *fname)
     // "load" the name and resolve the link
     hr = ppf->lpVtbl->Load(ppf, wsz, STGM_READ);
     if (hr != S_OK)
-	goto shortcut_error;
-#if 0  // This makes Vim wait a long time if the target doesn't exist.
+	goto shortcut_end;
+# if 0  // This makes Vim wait a long time if the target doesn't exist.
     hr = psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI);
     if (hr != S_OK)
-	goto shortcut_error;
-#endif
+	goto shortcut_end;
+# endif
 
     // Get the path to the link target.
     ZeroMemory(buf, MAX_PATH);
@@ -1807,12 +1855,16 @@ mch_resolve_shortcut(char_u *fname)
     if (hr == S_OK && buf[0] != NUL)
 	rfname = vim_strsave(buf);
 
-shortcut_error:
+shortcut_end:
     // Release all interface pointers (both belong to the same object)
     if (ppf != NULL)
 	ppf->lpVtbl->Release(ppf);
     if (psl != NULL)
 	psl->lpVtbl->Release(psl);
+# ifdef FEAT_MBYTE
+    if (pslw != NULL)
+	pslw->lpVtbl->Release(pslw);
+# endif
 
     CoUninitialize();
     return rfname;
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    12,
+/**/
     11,
 /**/
     10,