Page 1 of 1

FileCreateShortcut bug

Posted: 17 Dec 2018, 14:52
by gwarble
noticed what I think is a bug:

Code: Select all

FileCreateShortcut, "S:\IT - Software\Tools\AppName.exe", %A_ProgramsCommon%\AppName\Update now.lnk
S:\ is a mapped network drive. Non-admin user needs elevation to create the shortcut, which means S:\ mapped drive no longer exists.

Created shortcut path is:
with quotes removed and spaces changes into underscores

When S:\ drive exists, shortcut is created as expected, including quotes

Help files says:
The file does not have to exist at the time the shortcut is created; in other words, shortcuts to invalid targets can be created.
but maybe the folder does??

Re: FileCreateShortcut bug

Posted: 06 Jan 2019, 12:36
by Helgef
The folder where you want to create the link needs to exist, and you need permission to write there.


Re: FileCreateShortcut bug

Posted: 07 Jan 2019, 09:03
by joefiesta
this definitely appears worthy of a documentation update. This is too subtle to be gleaned from "The file does not have to exist at the time the shortcut is created; in other words, shortcuts to invalid targets can be created."

Re: FileCreateShortcut bug

Posted: 07 Jan 2019, 09:56
by safetycar
It also happens with some others like FileMove. In case it's decided to update one, it could be done with others.

Re: FileCreateShortcut bug

Posted: 02 Apr 2019, 04:18
by lexikos
What's the bug? gwarble says that the shortcut is created (success is good; no bug) when S: drive exists, but did not say that the shortcut is not created when S drive does not exist.

It does not matter whether S: drive exists. FileCreateShortcut, "S:\IT - Software\Tools\AppName.exe", test.lnk works for me and I do not have S: drive. Even FileCreateShortcut |foo|, test.lnk will create a shortcut, although it doesn't actually set the target since this isn't a valid path or URL.

By contrast, FileCreateShortcut, "S:\IT - Software\Tools\AppName.exe", %A_ProgramsCommon%\AppName\Update now.lnk does not work for me because %A_ProgramsCommon%\AppName does not exist. This is what Helgef was referring to.

Commands which create directories should always indicate that they do so.
FileCopyDir wrote:Copies a folder along with all its sub-folders and files (similar to xcopy).
FileCreateDir wrote:This command will also create all parent directories given in DirName if they do not already exist.
The OS does not create directories automatically, and in general, neither does AutoHotkey.

Code: Select all

C:\>echo test > foo\bar
The system cannot find the path specified.

Re: FileCreateShortcut bug

Posted: 02 Apr 2019, 21:42
by gwarble
Edit: This isn't about the destination/LinkFile, rather the "target" parameter of FileCreateShortcut

gwarble wrote:
17 Dec 2018, 14:52
When S:\ drive exists, shortcut is created as expected, including quotes
When S:\ drive doesn't exist:
shortcut pathtarget is:
with quotes removed and spaces changes into underscores

The "bug" (in my opinion) is that last sentence. If creating the shortcut succeeds, then its target should always match the parameter sent to FileCreateShortcut. The quotes may or may not matter, but "C:\this location\" is definitely not the same file path as "C:\this_location\"

That is, of course, unless those underscores (and stripped quotes) are coming from windows' own api when creating non-existent-target shortcuts, in which case my bad, Microsoft should fix it (and ahk should fail to create maybe?)

Re: FileCreateShortcut bug

Posted: 03 Apr 2019, 03:24
by lexikos
I read it backwards and assumed the underscores were to show where the spaces were and not actually part of the path. Now I understand why you think there is a bug. However, as I said, I cannot reproduce the behaviour you describe. Using FileCreateShortcut, "S:\IT - Software\Tools\AppName.exe", test.lnk, the shortcut's target is exactly "S:\IT - Software\Tools\AppName.exe" (copy-pasted from the properties dialog). S drive does not exist. If I map S drive, the result is the same. If I also create the folders and put AppName.exe in, the result is the same.

AutoHotkey doesn't do any processing of the target path. It merely passes the parameter value exactly as is to IShellLink::SetPath. Why do anything more?

Code: Select all

If you open the lnk file in a text or hex editor, is the path the same as it appears in the properties dialog?

The properties dialog sometimes lies about the target of the shortcut - probably due to link resolution.

You may also try this, which I would expect to produce a shortcut file with the same properties.

Code: Select all

l := FileGetShellLink(A_ProgramsCommon "\AppName\Update now.lnk")
l.Path := """S:\IT - Software\Tools\AppName.exe"""

FileGetShellLink(lnkpath) {
    if !FileExist(lnkpath)
        FileOpen(lnkpath, "w")
    Loop Files, % lnkpath
        lnkpath := A_LoopFileLongPath
    SplitPath lnkpath, name, dir
    if !(sl := ComObjCreate("Shell.Application").NameSpace(dir).ParseName(name).GetLink())
    return sl

Re: FileCreateShortcut bug

Posted: 03 Apr 2019, 11:09
by gwarble
Thanks for the explanation.

Its definitely consistent for me in Win7 using Ahk1.1.30.01 U32: When the target doesn't exist, the spaces are changed to underscores. Its not just as its displayed in the properties either, the target is actually wrong. Even more odd, in WinXP I get spaces changes to underscores AND truncated to 8 characters when the target doesn't exist, ie target becomes "S:\IT_-_Sof"

So my guess is that this is actually a Windows bug, or that windows API doesn't technically "allow" creating shortcuts that don't resolve, and that AHK is somehow doing it anyway exposing this bug. And maybe they fixed it in newer windows (don't have one handy now, but if you can't recreate it and are on Win10 that would make sense.)

Edit: I guess its not a Microsoft bug:
According to Raymond:
Instead of using IShell­Link::Set­Path, use IShell­Link::Set­ID­List with a simple pidl.
Apparently SetPath should only be used when the target exists.

Re: FileCreateShortcut bug

Posted: 04 Apr 2019, 05:26
by lexikos
It seems to me that understanding how this can be the intended behaviour of SetPath would require a very specific and uncommon point of view. Raymond's explanation doesn't change the fact that the behaviour is at least undocumented, if not contrary to the documentation. I would also say it is counter-intuitive in multiple ways, but I suppose that is more opinion than fact (and ranting about it in further detail seems futile, so I'll stop there).

I will implement this workaround. Thanks.

Edit: Maybe not. The initial article makes the workaround look trivial: create a "simple PIDL" and call SetIDList. However, a "simple PIDL" seems to be something Raymond invented, implemented by the program (not the system) through several helper functions and a class which implements a COM interface. I just want to take this string, and shove it into a lnk file...

Re: FileCreateShortcut bug

Posted: 05 Apr 2019, 10:57
by gwarble
You're welcome, and thanks for looking into it.

I'm not sure a fix needs to be implemented, but at the very least maybe a note added to the documentation since its a known issue that contradicts the current documentation.

Edit: On ancient versions of windows:
For the easy and undocumented way, Shell32.dll contains a rather neat little undocumented function that essentially duplicates what GetPIDLFromPath does (calls ParseDisplayName with the path passed to it converted to Unicode and returns the path's pidl) called SHSimpleIDListFromPath. Here's the declare:

Declare Function SHSimpleIDListFromPath Lib "shell32" Alias "#162" _
(ByVal szPath As String) As Long
I don't know if this undocumented function survived over the years...
Prior to Windows 7, this function was declared in Shlobj.h. In Windows 7 and later versions, it is declared in Shobjidl.h.

Note This function is available through Windows 7 and Windows Server 2003. It is possible that it will not be present in future versions of Windows.

An alternative to this function is as follows:
Call SHGetDesktopFolder to obtain IShellFolder for the desktop folder.
Get the IShellFolder's bind context (IBindCtx).
Call IShellFolder::ParseDisplayName with the IBindCtx and the path.

Re: FileCreateShortcut bug

Posted: 29 Jun 2019, 05:58
by lexikos
SHSimpleIDListFromPath appears to work on Windows 10.0.18362 (v1903).

Having said that, it appears that it cannot be used to create a shortcut to a folder, at least on this version of Windows. The shortcut's properties show the target file type as "File folder", but the icon is blank. The shortcut's default action is "Open with", but it does nothing. "Open File Location" from the shortcut's properties does nothing, but from the context menu it opens the folder containing the shortcut (not target).

This is also what happens if I create a shortcut to a file (even manually) or non-existent target and then create a directory at that location (replacing the file if there was one). Related: FileCreateShortcut not working for folder.

From what I recall reading, the "simple ID list" implements interface functions that return information about the object that the ID list identifies. I suppose that this implementation identifies as a file, not a folder, so maybe it is possible to create a "folder shortcut" to a non-existent/inaccessible target using a custom ID list implementation, but that would require knowing that it should be a folder shortcut first.