Say you have a shortcut file and you want to see what its target is. The natural thing to do is to call IShellLink::GetPath, which returns S_FALSE if the shortcut does not target a path, or returns S_OK and a path to the target. But for some shortcuts, it returns S_OK but produces a weird path to a file inside the C:\Windows\Installer directory that is definitely not the shortcut target. So what is it?

You’re seeing a backward compatibility consequence of shortcuts to MSI applications.

The Microsoft Windows Installer (MSI) was introduced in Windows 2000. It supports various types of installation functionality, but the interesting one here is install-on-demand. A shortcut to an MSI-installed application is not a shortcut to an executable, but rather it is a shortcut that encodes the MSI information to identify an MSI application. When the user double-clicks the shortcut, the shortcut file asks MSI to get the application ready to run, which involves installing the application and all its dependencies (if they aren’t already installed), and possibly verifying that the files are not corrupted and performing self-repair. Only after everything is ready to go does the shortcut actually launch the program. This install-on-demand behavior means that if the program hasn’t been installed, there is no target to execute.

The initial implementation of MSI shortcuts had the Get­Path method ask MSI for the application’s executable, and MSI would go off and say, “Hang on, I need to install it first,” and that might display some installation UI, possibly asking the user to reinsert the original install media if the package is not cached. We discovered during testing that lots of programs ask for the application’s executable path without any intent to launch the resulting application. As a result, you would find that your system would suddenly go bonkers installing every program on the Start menu just because some program wanted to enumerate the contents of the Start menu and get information about all of the shortcuts. These sorts of program are popular in managed environments where the system administrator wrote a tool to take an inventory of all the programs that have been installed across their organization. This also means that Get­Path can’t return S_FALSE to say “This does not refer to a file,” because those inventory programs insisted that they get a file path back so they can determine, say, how many of their users have CONTOSO.EXE installed.

The IShellLink::GetPath and IShellLink::Resolve methods were modified so that they didn’t actually give you the path to the executable (which would trigger an on-demand install) but rather gave you the path to a placeholder file.¹ This placeholder file usually had just enough information to keep most programs happy with what they found. The executable name matched that of the final program, like WINWORD.EXE, which tended to satisfy a lot of system inventory-type programs. And that placeholder also contained the icon for the final program, so that programs that tried to be fancy and show an icon for the program got the icon they wanted (even if not from the file they thought they were getting it from).

You can detect that you are being lied to by checking the shortcut flags returned by IShell­Link­Data­List::Get­Flags for the SLDF_HAS_DARWIN­ID flag. Darwin was the code name for what became the Microsoft Windows Installer.

Once you realize that you have an MSI shortcut, you can obtain more information about them by calling Msi­Get­Shortcut­Target, which will give you the MSI product code, feature ID, and component code that the shortcut refers to. You can pass the product code and component code to Msi­Get­Component­Path to get the path to the component if it is installed.²

If you are a real glutton for punishment, you can get the raw MSI descriptor by calling IShell­Link­Data­List::Copy­Data­Block and asking for the EXP_DARWIN_ID_SIG data block. The descriptor is returned in the EXP_DARWIN_LINK‘s szDarwinID and szwDarwinID members. What can you do with that descriptor? I have no idea, but you did ask for it.

¹ The Resolve method lets you override this by passing the SLR_INVOKE_MSI flag, which means “No really, I want you to install the shortcut target.” Use with extreme caution or you will be one of those programs that causes the user’s machine to go berzerk installing every program on the Start menu.

² Note that the component path is not the same as what the shortcut will launch when you double-click it. The shortcut includes command line arguments that the MSI package specified when it defined the shortcut.

The post A shortcut gives me a weird path for a program shortcut that doesn’t point to the executable, so what is it? appeared first on The Old New Thing.


From The Old New Thing via this RSS feed