diff src/os_mswin.c @ 16196:973070a30381 v8.1.1103

patch 8.1.1103: MS-Windows: old API calls are no longer needed commit https://github.com/vim/vim/commit/0eb035c974c47e65d32439b48e5a056b370ad429 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Apr 2 22:15:55 2019 +0200 patch 8.1.1103: MS-Windows: old API calls are no longer needed Problem: MS-Windows: old API calls are no longer needed. Solution: Always use the wide functions. (Ken Takata, closes https://github.com/vim/vim/issues/4199)
author Bram Moolenaar <Bram@vim.org>
date Tue, 02 Apr 2019 22:30:04 +0200
parents cd5c83115ec6
children b3bc3ba07bef
line wrap: on
line diff
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -105,7 +105,7 @@ typedef int LRESULT;
 typedef int MOUSE_EVENT_RECORD;
 typedef int NEWTEXTMETRICW;
 typedef int PACL;
-typedef int PRINTDLG;
+typedef int PRINTDLGW;
 typedef int PSECURITY_DESCRIPTOR;
 typedef int PSID;
 typedef int SECURITY_INFORMATION;
@@ -282,19 +282,14 @@ mch_settitle(
 # else
     if (title != NULL)
     {
-	if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-	{
-	    /* Convert the title from 'encoding' to the active codepage. */
-	    WCHAR	*wp = enc_to_utf16(title, NULL);
-
-	    if (wp != NULL)
-	    {
-		SetConsoleTitleW(wp);
-		vim_free(wp);
-		return;
-	    }
-	}
-	SetConsoleTitle((LPCSTR)title);
+	WCHAR	*wp = enc_to_utf16(title, NULL);
+
+	if (wp == NULL)
+	    return;
+
+	SetConsoleTitleW(wp);
+	vim_free(wp);
+	return;
     }
 # endif
 }
@@ -359,40 +354,22 @@ mch_FullName(
     else
 #endif
     {
-	if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+	WCHAR	*wname;
+	WCHAR	wbuf[MAX_PATH];
+	char_u	*cname = NULL;
+
+	wname = enc_to_utf16(fname, NULL);
+	if (wname != NULL && _wfullpath(wbuf, wname, MAX_PATH) != NULL)
 	{
-	    WCHAR	*wname;
-	    WCHAR	wbuf[MAX_PATH];
-	    char_u	*cname = NULL;
-
-	    /* Use the wide function:
-	     * - convert the fname from 'encoding' to UCS2.
-	     * - invoke _wfullpath()
-	     * - convert the result from UCS2 to 'encoding'.
-	     */
-	    wname = enc_to_utf16(fname, NULL);
-	    if (wname != NULL && _wfullpath(wbuf, wname, MAX_PATH) != NULL)
+	    cname = utf16_to_enc((short_u *)wbuf, NULL);
+	    if (cname != NULL)
 	    {
-		cname = utf16_to_enc((short_u *)wbuf, NULL);
-		if (cname != NULL)
-		{
-		    vim_strncpy(buf, cname, len - 1);
-		    nResult = OK;
-		}
+		vim_strncpy(buf, cname, len - 1);
+		nResult = OK;
 	    }
-	    vim_free(wname);
-	    vim_free(cname);
 	}
-	if (nResult == FAIL)	    /* fall back to non-wide function */
-	{
-	    if (_fullpath((char *)buf, (const char *)fname, len - 1) == NULL)
-	    {
-		/* failed, use relative path name */
-		vim_strncpy(buf, fname, len - 1);
-	    }
-	    else
-		nResult = OK;
-	}
+	vim_free(wname);
+	vim_free(cname);
     }
 
 #ifdef USE_FNAME_CASE
@@ -480,57 +457,6 @@ slash_adjust(char_u *p)
 #endif
 
     static int
-stat_symlink_aware(const char *name, stat_T *stp)
-{
-#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__MINGW32__)
-    /* Work around for VC12 or earlier (and MinGW). stat() can't handle
-     * symlinks properly.
-     * VC9 or earlier: stat() doesn't support a symlink at all. It retrieves
-     * status of a symlink itself.
-     * VC10: stat() supports a symlink to a normal file, but it doesn't support
-     * a symlink to a directory (always returns an error).
-     * VC11 and VC12: stat() doesn't return an error for a symlink to a
-     * directory, but it doesn't set S_IFDIR flag.
-     * MinGW: Same as VC9. */
-    WIN32_FIND_DATA	findData;
-    HANDLE		hFind, h;
-    DWORD		attr = 0;
-    BOOL		is_symlink = FALSE;
-
-    hFind = FindFirstFile(name, &findData);
-    if (hFind != INVALID_HANDLE_VALUE)
-    {
-	attr = findData.dwFileAttributes;
-	if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
-		&& (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
-	    is_symlink = TRUE;
-	FindClose(hFind);
-    }
-    if (is_symlink)
-    {
-	h = CreateFile(name, FILE_READ_ATTRIBUTES,
-		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
-		OPEN_EXISTING,
-		(attr & FILE_ATTRIBUTE_DIRECTORY)
-					    ? FILE_FLAG_BACKUP_SEMANTICS : 0,
-		NULL);
-	if (h != INVALID_HANDLE_VALUE)
-	{
-	    int	    fd, n;
-
-	    fd = _open_osfhandle((OPEN_OH_ARGTYPE)h, _O_RDONLY);
-	    n = _fstat(fd, (struct _stat *)stp);
-	    if ((n == 0) && (attr & FILE_ATTRIBUTE_DIRECTORY))
-		stp->st_mode = (stp->st_mode & ~S_IFREG) | S_IFDIR;
-	    _close(fd);
-	    return n;
-	}
-    }
-#endif
-    return stat(name, stp);
-}
-
-    static int
 wstat_symlink_aware(const WCHAR *name, stat_T *stp)
 {
 #if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__MINGW32__)
@@ -593,6 +519,8 @@ vim_stat(const char *name, stat_T *stp)
      * UTF-8. */
     char_u	buf[_MAX_PATH * 3 + 1];
     char_u	*p;
+    WCHAR	*wp;
+    int		n;
 
     vim_strncpy((char_u *)buf, (char_u *)name, sizeof(buf) - 1);
     p = buf + STRLEN(buf);
@@ -614,19 +542,14 @@ vim_stat(const char *name, stat_T *stp)
 		STRCAT(buf, "\\");
 	}
     }
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-    {
-	WCHAR	*wp = enc_to_utf16(buf, NULL);
-	int	n;
-
-	if (wp != NULL)
-	{
-	    n = wstat_symlink_aware(wp, stp);
-	    vim_free(wp);
-	    return n;
-	}
-    }
-    return stat_symlink_aware((char *)buf, stp);
+
+    wp = enc_to_utf16(buf, NULL);
+    if (wp == NULL)
+	return -1;
+
+    n = wstat_symlink_aware(wp, stp);
+    vim_free(wp);
+    return n;
 }
 
 #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
@@ -758,6 +681,9 @@ mch_has_wildcard(char_u *p)
     int
 mch_chdir(char *path)
 {
+    WCHAR   *p;
+    int	    n;
+
     if (path[0] == NUL)		/* just checking... */
 	return -1;
 
@@ -779,20 +705,13 @@ mch_chdir(char *path)
     if (*path == NUL)		/* drive name only */
 	return 0;
 
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-    {
-	WCHAR	*p = enc_to_utf16((char_u *)path, NULL);
-	int	n;
-
-	if (p != NULL)
-	{
-	    n = _wchdir(p);
-	    vim_free(p);
-	    return n;
-	}
-    }
-
-    return chdir(path);	       /* let the normal chdir() do the rest */
+    p = enc_to_utf16((char_u *)path, NULL);
+    if (p == NULL)
+	return -1;
+
+    n = _wchdir(p);
+    vim_free(p);
+    return n;
 }
 
 
@@ -1097,7 +1016,7 @@ mch_set_winpos(int x, int y)
  */
 
 static HFONT		prt_font_handles[2][2][2];
-static PRINTDLG		prt_dlg;
+static PRINTDLGW	prt_dlg;
 static const int	boldface[2] = {FW_REGULAR, FW_BOLD};
 static TEXTMETRIC	prt_tm;
 static int		prt_line_height;
@@ -1119,18 +1038,16 @@ static char_u		*prt_name = NULL;
     static BOOL
 vimSetDlgItemText(HWND hDlg, int nIDDlgItem, char_u *s)
 {
-    WCHAR   *wp = NULL;
+    WCHAR   *wp;
     BOOL    ret;
 
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-	wp = enc_to_utf16(s, NULL);
-    if (wp != NULL)
-    {
-	ret = SetDlgItemTextW(hDlg, nIDDlgItem, wp);
-	vim_free(wp);
-	return ret;
-    }
-    return SetDlgItemText(hDlg, nIDDlgItem, (LPCSTR)s);
+    wp = enc_to_utf16(s, NULL);
+    if (wp == NULL)
+	return FALSE;
+
+    ret = SetDlgItemTextW(hDlg, nIDDlgItem, wp);
+    vim_free(wp);
+    return ret;
 }
 
 /*
@@ -1248,7 +1165,7 @@ PrintHookProc(
 {
     HWND	hwndOwner;
     RECT	rc, rcDlg, rcOwner;
-    PRINTDLG	*pPD;
+    PRINTDLGW	*pPD;
 
     if (uiMsg == WM_INITDIALOG)
     {
@@ -1280,7 +1197,7 @@ PrintHookProc(
 		SWP_NOSIZE);
 
 	/*  tackle the printdlg copiesctrl problem */
-	pPD = (PRINTDLG *)lParam;
+	pPD = (PRINTDLGW *)lParam;
 	pPD->nCopies = (WORD)pPD->lCustData;
 	SetDlgItemInt( hDlg, edt3, pPD->nCopies, FALSE );
 	/*  Bring the window to top */
@@ -1423,13 +1340,13 @@ mch_print_init(prt_settings_T *psettings
     int			pifBold;
     int			pifUnderline;
 
-    DEVMODE		*mem;
+    DEVMODEW		*mem;
     DEVNAMES		*devname;
     int			i;
 
     bUserAbort = &(psettings->user_abort);
-    vim_memset(&prt_dlg, 0, sizeof(PRINTDLG));
-    prt_dlg.lStructSize = sizeof(PRINTDLG);
+    vim_memset(&prt_dlg, 0, sizeof(PRINTDLGW));
+    prt_dlg.lStructSize = sizeof(PRINTDLGW);
 #ifndef FEAT_GUI
     GetConsoleHwnd();	    /* get value of s_hwnd */
 #endif
@@ -1470,11 +1387,11 @@ mch_print_init(prt_settings_T *psettings
 	else
 	{
 	    prt_dlg.Flags |= PD_RETURNDEFAULT;
-	    if (PrintDlg(&prt_dlg) == 0)
+	    if (PrintDlgW(&prt_dlg) == 0)
 		goto init_fail_dlg;
 	}
     }
-    else if (PrintDlg(&prt_dlg) == 0)
+    else if (PrintDlgW(&prt_dlg) == 0)
 	goto init_fail_dlg;
     else
     {
@@ -1510,7 +1427,7 @@ mch_print_init(prt_settings_T *psettings
      * passed back correctly. It must be retrieved from the
      * hDevMode struct.
      */
-    mem = (DEVMODE *)GlobalLock(prt_dlg.hDevMode);
+    mem = (DEVMODEW *)GlobalLock(prt_dlg.hDevMode);
     if (mem != NULL)
     {
 	if (mem->dmCopies != 1)
@@ -1525,34 +1442,20 @@ mch_print_init(prt_settings_T *psettings
     devname = (DEVNAMES *)GlobalLock(prt_dlg.hDevNames);
     if (devname != 0)
     {
-	char_u	*printer_name = (char_u *)devname + devname->wDeviceOffset;
-	char_u	*port_name = (char_u *)devname +devname->wOutputOffset;
+	WCHAR	*wprinter_name = (WCHAR *)devname + devname->wDeviceOffset;
+	WCHAR	*wport_name = (WCHAR *)devname + devname->wOutputOffset;
 	char_u	*text = (char_u *)_("to %s on %s");
-	char_u  *printer_name_orig = printer_name;
-	char_u	*port_name_orig = port_name;
-
-	if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-	{
-	    char_u  *to_free = NULL;
-	    int     maxlen;
-
-	    acp_to_enc(printer_name, (int)STRLEN(printer_name), &to_free,
-								    &maxlen);
-	    if (to_free != NULL)
-		printer_name = to_free;
-	    acp_to_enc(port_name, (int)STRLEN(port_name), &to_free, &maxlen);
-	    if (to_free != NULL)
-		port_name = to_free;
-	}
-	prt_name = alloc((unsigned)(STRLEN(printer_name) + STRLEN(port_name)
-							     + STRLEN(text)));
+	char_u  *printer_name = utf16_to_enc(wprinter_name, NULL);
+	char_u	*port_name = utf16_to_enc(wport_name, NULL);
+
+	if (printer_name != NULL && port_name != NULL)
+	    prt_name = alloc((unsigned)(STRLEN(printer_name)
+					+ STRLEN(port_name) + STRLEN(text)));
 	if (prt_name != NULL)
 	    wsprintf((char *)prt_name, (const char *)text,
 		    printer_name, port_name);
-	if (printer_name != printer_name_orig)
-	    vim_free(printer_name);
-	if (port_name != port_name_orig)
-	    vim_free(port_name);
+	vim_free(printer_name);
+	vim_free(port_name);
     }
     GlobalUnlock(prt_dlg.hDevNames);
 
@@ -1639,9 +1542,9 @@ init_fail_dlg:
     int
 mch_print_begin(prt_settings_T *psettings)
 {
-    int			ret;
+    int			ret = 0;
     char		szBuffer[300];
-    WCHAR		*wp = NULL;
+    WCHAR		*wp;
 
     hDlgPrint = CreateDialog(GetModuleHandle(NULL), TEXT("PrintDlgBox"),
 					     prt_dlg.hwndOwner, PrintDlgProc);
@@ -1649,8 +1552,7 @@ mch_print_begin(prt_settings_T *psetting
     wsprintf(szBuffer, _("Printing '%s'"), gettail(psettings->jobname));
     vimSetDlgItemText(hDlgPrint, IDC_PRINTTEXT1, (char_u *)szBuffer);
 
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-	wp = enc_to_utf16(psettings->jobname, NULL);
+    wp = enc_to_utf16(psettings->jobname, NULL);
     if (wp != NULL)
     {
 	DOCINFOW	di;
@@ -1661,15 +1563,6 @@ mch_print_begin(prt_settings_T *psetting
 	ret = StartDocW(prt_dlg.hDC, &di);
 	vim_free(wp);
     }
-    else
-    {
-	DOCINFO		di;
-
-	vim_memset(&di, 0, sizeof(di));
-	di.cbSize = sizeof(di);
-	di.lpszDocName = (LPCSTR)psettings->jobname;
-	ret = StartDoc(prt_dlg.hDC, &di);
-    }
 
 #ifdef FEAT_GUI
     /* Give focus back to main window (when using MDI). */
@@ -1725,50 +1618,32 @@ mch_print_start_line(int margin, int pag
 mch_print_text_out(char_u *p, int len)
 {
     SIZE	sz;
-    WCHAR	*wp = NULL;
+    WCHAR	*wp;
     int		wlen = len;
-
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-	wp = enc_to_utf16(p, &wlen);
-    if (wp != NULL)
-    {
-	int ret = FALSE;
-
-	TextOutW(prt_dlg.hDC, prt_pos_x + prt_left_margin,
-					 prt_pos_y + prt_top_margin, wp, wlen);
-	GetTextExtentPoint32W(prt_dlg.hDC, wp, wlen, &sz);
-	vim_free(wp);
-	prt_pos_x += (sz.cx - prt_tm.tmOverhang);
-	/* This is wrong when printing spaces for a TAB. */
-	if (p[len] != NUL)
-	{
-	    wlen = MB_PTR2LEN(p + len);
-	    wp = enc_to_utf16(p + len, &wlen);
-	    if (wp != NULL)
-	    {
-		GetTextExtentPoint32W(prt_dlg.hDC, wp, 1, &sz);
-		ret = (prt_pos_x + prt_left_margin + sz.cx > prt_right_margin);
-		vim_free(wp);
-	    }
-	}
-	return ret;
-    }
-    TextOut(prt_dlg.hDC, prt_pos_x + prt_left_margin,
-					  prt_pos_y + prt_top_margin,
-					  (LPCSTR)p, len);
-#ifndef FEAT_PROPORTIONAL_FONTS
-    prt_pos_x += len * prt_tm.tmAveCharWidth;
-    return (prt_pos_x + prt_left_margin + prt_tm.tmAveCharWidth
-				     + prt_tm.tmOverhang > prt_right_margin);
-#else
-    GetTextExtentPoint32(prt_dlg.hDC, (LPCSTR)p, len, &sz);
+    int		ret = FALSE;
+
+    wp = enc_to_utf16(p, &wlen);
+    if (wp == NULL)
+	return FALSE;
+
+    TextOutW(prt_dlg.hDC, prt_pos_x + prt_left_margin,
+	    prt_pos_y + prt_top_margin, wp, wlen);
+    GetTextExtentPoint32W(prt_dlg.hDC, wp, wlen, &sz);
+    vim_free(wp);
     prt_pos_x += (sz.cx - prt_tm.tmOverhang);
     /* This is wrong when printing spaces for a TAB. */
-    if (p[len] == NUL)
-	return FALSE;
-    GetTextExtentPoint32(prt_dlg.hDC, p + len, 1, &sz);
-    return (prt_pos_x + prt_left_margin + sz.cx > prt_right_margin);
-#endif
+    if (p[len] != NUL)
+    {
+	wlen = MB_PTR2LEN(p + len);
+	wp = enc_to_utf16(p + len, &wlen);
+	if (wp != NULL)
+	{
+	    GetTextExtentPoint32W(prt_dlg.hDC, wp, 1, &sz);
+	    ret = (prt_pos_x + prt_left_margin + sz.cx > prt_right_margin);
+	    vim_free(wp);
+	}
+    }
+    return ret;
 }
 
     void
@@ -1863,6 +1738,7 @@ resolve_reparse_point(char_u *fname)
 {
     HANDLE	    h = INVALID_HANDLE_VALUE;
     DWORD	    size;
+    WCHAR	    *p;
     char_u	    *rfname = NULL;
     FILE_NAME_INFO_ *nameinfo = NULL;
     WCHAR	    buff[MAX_PATH], *volnames = NULL;
@@ -1887,33 +1763,19 @@ resolve_reparse_point(char_u *fname)
 	    return NULL;
     }
 
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+    p = enc_to_utf16(fname, NULL);
+    if (p == NULL)
+	goto fail;
+
+    if ((GetFileAttributesW(p) & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
     {
-	WCHAR	*p;
-
-	p = enc_to_utf16(fname, NULL);
-	if (p == NULL)
-	    goto fail;
-
-	if ((GetFileAttributesW(p) & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
-	{
-	    vim_free(p);
-	    goto fail;
-	}
-
-	h = CreateFileW(p, 0, 0, NULL, OPEN_EXISTING,
-		FILE_FLAG_BACKUP_SEMANTICS, NULL);
 	vim_free(p);
+	goto fail;
     }
-    else
-    {
-	if ((GetFileAttributes((char*) fname) &
-		    FILE_ATTRIBUTE_REPARSE_POINT) == 0)
-	    goto fail;
-
-	h = CreateFile((char*) fname, 0, 0, NULL, OPEN_EXISTING,
-		FILE_FLAG_BACKUP_SEMANTICS, NULL);
-    }
+
+    h = CreateFileW(p, 0, 0, NULL, OPEN_EXISTING,
+	    FILE_FLAG_BACKUP_SEMANTICS, NULL);
+    vim_free(p);
 
     if (h == INVALID_HANDLE_VALUE)
 	goto fail;
@@ -1988,8 +1850,6 @@ resolve_shortcut(char_u *fname)
     IShellLink		*psl = NULL;
     IPersistFile	*ppf = NULL;
     OLECHAR		wsz[MAX_PATH];
-    WIN32_FIND_DATA	ffd; // we get those free of charge
-    CHAR		buf[MAX_PATH]; // could have simply reused 'wsz'...
     char_u		*rfname = NULL;
     int			len;
     IShellLinkW		*pslw = NULL;
@@ -2005,80 +1865,43 @@ resolve_shortcut(char_u *fname)
 
     CoInitialize(NULL);
 
-    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);
-		goto shortcut_end;
-	    }
-	}
-	goto shortcut_end;
-    }
     // 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_end;
-
-    // Get a pointer to the IPersistFile interface.
-    hr = psl->lpVtbl->QueryInterface(
-	    psl, &IID_IPersistFile, (void**)&ppf);
-    if (hr != S_OK)
-	goto shortcut_end;
-
-    // full path string must be in Unicode.
-    MultiByteToWideChar(CP_ACP, 0, (LPCSTR)fname, -1, wsz, MAX_PATH);
-
-    // "load" the name and resolve the link
-    hr = ppf->lpVtbl->Load(ppf, wsz, STGM_READ);
-    if (hr != S_OK)
-	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_end;
+	    &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(buf, MAX_PATH);
-    hr = psl->lpVtbl->GetPath(psl, buf, MAX_PATH, &ffd, 0);
-    if (hr == S_OK && buf[0] != NUL)
-	rfname = vim_strsave((char_u *)buf);
-
-shortcut_end:
+	    // 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);
+	}
+    }
+
     // Release all interface pointers (both belong to the same object)
     if (ppf != NULL)
 	ppf->lpVtbl->Release(ppf);