How do I get the full path for the target of a shortcut file?

A customer was having trouble obtaining information from a shortcut file. "Here is a sample program that tries to print the target of a shortcut file, but it only gets the file name without a directory. How do I get the full path?"

 IShellLink *psl;
 ... code that loads the IShellLink omitted ...
 hr = psl->GetPath(szPath, MAX_PATH, &wfd, SLGP_UNCPATH);
 if (SUCCEEDED(hr)) {
  _tprintf(TEXT("Got path: %s\n"), wfd.cFileName);

Recall that the WIN32_FIND_DATA structure contains only a file name in the cFile­Name member. It doesn't have any path information. The WIN32_FIND_DATA structure was originally created for the Find­First­File function, and you already know the directory you are searching in because you passed it to Find­First­File.

But we're not using the WIN32_FIND_DATA structure in conjunction with Find­First­File, so where do I get the directory from?

In the customer's excitement over the WIN32_FIND_DATA structure, they forgot about that other parameter: szPath.

 if (SUCCEEDED(hr)) {
  _tprintf(TEXT("Got path: %s\n"), szPath);

The answer was sitting right there in front of them, like an overlooked Christmas present.

(Don't forget, the target of the shortcut might not be a file, in which case the call to Get­Path will return S_FALSE.)

Comments (16)
  1. anonymous says:

    (don't forget SUCCEEDED(S_FALSE) == TRUE)

  2. cron22 says:

    Does this work for .net users?

  3. cron22 says:

    it should so that developers of the framework can enjoy the same benefits.  

  4. Ben Voigt [Visual C++ MVP] says:

    Raymond, looks like your tagline about .NET has gone missing.  And the inevitable questions about using the WinAPI from .NET have already started.

    cron22, developers of the framework do enjoy the benefits of the WinAPI.  Almost every file-related function in the framework calls a Win32 API function to do the real work.  I guess you meant users of the framework, but they can use COM objects too, due to the magic of interop.

  5. cron22 says:

    I guess they are.  I mean, directory access is available from .net, isn't it?  

  6. cron22 says:

    Yes, Interop is good, except in places where it is unsupported for some reason such as in MAPI.  I meant to ask, why on earth is that?  Why aren't things like MAPI supported by Interop?  

  7. xpclient says:

    How to get the full path for the target of a Windows Installer (advertised) shortcut? Why is there no way in Windows to view and edit such a shortcut target (e.g. to modify command line switches etc)?

  8. Does the support include explaining the very first parameter to documented function? (…/bb774944(v=vs.85).aspx)

    pszFile [out]

    Type: LPTSTR

    The address of a buffer that receives the path and file name of the Shell link object.

  9. Joshua says:

    @xpclient, what are you smoking? The full target of an advertised shortcut is not yet defined because the installation directory is defined.

  10. Gabe says:

    I'd like to know what the SLGP_RELATIVEPRIORITY flag is for. The only documentation says "Windows Vista and later." with no indication of what it actually does.

    [You try to infer what it does given that there is an IShellLink::SetRelativePath method. -Raymond]
  11. xpclient says:

    @Joshua, Explorer shows the target of an advertised shortcut as greyed out, doesn't mean the target's the installation directory. The target is stored in a key file, it's just that Windows annoyingly doesn't give the USER the control it should give over changing (or even showing) the target path or even changing the icon. There should be a Group Policy to never create advertised shortcuts. You can't even check "Run as administrator" for the evil advertised shortcut. Its self healing feature is also annoying as hell.

  12. Joshua says:

    Sorry xpclient I appear to have grossly misunderstood your question.

    I'm sure if you want rid of them you can blast them out of existence with a shell plugin, but there's got to be an easier way.

  13. root says:

    @xpclient: Most users don't understand that GPOs are for their own good. A corporate environment must be easy to administer from a central command. And computers are typically not owned by employees, not their property to fiddle with. Try to spend your time on doing the work you have been assigned to do instead.

  14. @root says:

    You don't seem to understand the concept behind Group Policy. Try to read about it more before giving advice.

  15. DWalker says:

    @Raymond, Gabe:  No matter what the odds are that you can infer what a parameter is for, if the only documentation is "Windows Vista and later", that's incredibly poor documentation!

    [Agreed. I'll see what I can do about that. But you can infer in the meantime. -Raymond]
  16. Phil W says:

    @xpclient. See MsiGetShortcutTarget() function. With the returned ProductCode and ComponentCode you can get the target file path with the MsiGetComponentPath() function. No, you can't edit them. That would defeat their purpose (resilience, install on demand).

Comments are closed.