Reputation: 20474
I noticed that the method IShellLinkW::GetPath returns an empty string if the target of a shortcut points to a special folder, like 'My PC', or a Control Panel applet.
Sample code
' CLSID_ShellLink from ShlGuid.h
Dim cShellLink As New CShellLink()
' https://msdn.microsoft.com/en-us/library/windows/desktop/ms687223%28v=vs.85%29.aspx
Dim persistFile As IPersistFile = DirectCast(cShellLink, IPersistFile)
persistFile.Load(lnkFilePath, 0)
Dim target As New StringBuilder(260)
' https://learn.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nn-shobjidl_core-ishelllinkw
Dim lnkW As IShellLinkW = DirectCast(cShellLink, IShellLinkW)
lnkW.GetPath(target, target.Capacity, Nothing, IShellLinkGetPathFlags.RawPath)
( Sorry, are too many P/Invokes to share here, but you can find them in this repository. )
The code above works correctly to retrieve the target of any .lnk file that points to a file or directory. It can't retrieve a target that points to special item / virtual folders.
My questions are:
Is this by design?. If not, what I'm missing or doing wrong? (maybe are my definitions wrong?). And what I have to do in order to retrieve the special target?. Note that I would like to retrieve the target to display it in a PropertyGrid
, and also to create a new target with a clone of the special target.
Please note that the programming language on which I developed this code does not matter, because I'm firstly asking for orientation, and also I accept any solution written in C#.
Upvotes: 2
Views: 664
Reputation: 20474
As mentioned in the comments box of the main post, in order to retrieve the raw target of a shell link that points to a special, non-file system path (eg. 'My PC'), first we need to retrieve the PIDL by calling IShellLinkW::GetIDList()
.
Next, we pass that (absolute)PIDL to SHGetNameFromIDList with the flag SIGDN_DESKTOPABSOLUTEPARSING, and finally this will return a CLSID string that we can specify for the target of a .lnk file with IShellLinkW::SetPath()
. It works as expected.
Note that I'm not sure if there could exist special scenarios (rare targets of a lnk file) on which this could not work as expected. I didn't found that error case.
And if needed, the normal display name can be obtained with the flag SIGDN_NORMALDISPLAY
, or also by calling the SHGetFileInfo function as mentioned too in the comments box of the main post.
Credits for the users that suggested me the PIDL retrieval and its usage, because I was not sure about what to investigate in order to solve this problem.
I also will give credits to Vanara open-source library, that helped me to find the right P/Invokes of every SH* function in their source-code, specially the signature for SHGetNameFromIDList.
Upvotes: 2