views:

500

answers:

6

I am working on a program which includes a general purpose engine, some program specific content, and a custom automatic updater to handle updating the many gigabytes worth of media in our content as efficiently as possible. In a recent release of the engine, we have reorganized our directory structure, such that instead of the executable installing to (for example) c:\Program Files\Program\Engine.exe, it is now in c:\Program Files\Program\engine\win32\NewEngine.exe (note that the name of the engine changed as well in this process).

The problem is that in order to launch the program, the user needs to use a shortcut, which we install in their start menu and (optionally) on their desktop. The move of the engine after an update breaks those shortcuts, though. So now I need to figure out a way to fix all of the shortcuts that the user has in order to launch the program.

Coming from a Unix/Mac OS X background, my inclination would be to just create a symlink from the old executable name to the new one. As far as I know though, there isn't really an equivalent of a symlink on Windows (from Googling, I see that there are symlinks on Vista and later, but this needs to work on XP). Am I wrong in my assumption? Is there any equivalent on Windows to a symlink to an executable?

Some other possible solutions that come to mind are:

  1. Creating a small executable at the old location that launches the real one in the new location. Is there any quick and easy way to create a simple, headless executable, that just launches another program? Again, on Unix, I'd simply create a shell script, but as far as I know I can't name a .bat file .exe and have it run, so this needs to be a way to actually generate an .exe.
  2. Upon the update, search for all shortcuts that point to the executable and edit them. Is there any (efficient and reliable) way to find all shortcuts on the system that point to a given location and update them?
  3. A combination of the above, with a small executable that detects that it's being launched from a shortcut, and edits that shortcut before launching the real program. Is there any way to detect that a program is being launched from a shortcut, and thus be able to edit that shortcut?

Would any of these options work, and if so how? What is the best way to do this sort of thing on Windows? Am I missing any other ways of redirecting a shortcut from one location to another?

edit to add: Some additional requirements we have:

  1. Many of our users are non-technical. Any solution requiring user intervention is out of the question.
  2. This should be as seamless as possible. Having any extra windows pop up every time the user clicks the shortcut is unacceptable.
  3. This should be robust in the face of most things the user could have done, such as rearranging their start menu or moving a shortcut to the quick launch bar.
  4. Our shortcuts are absolutely necessary to the functioning of the program, as they pass in arguments necessary for the engine to load the content (yes, this is less than ideal; I would prefer to fix this, but cannot at this point)
  5. I'm looking for something that is relatively quick and easy to implement and extremely reliable.
+1  A: 

Why can't you overwrite the shortcuts during installation of updates?

You should overwrite only the default shortcuts, not every shortcut the user might have created. Still, for this second case you can use option 1, but yes, it should have to be a real executable.

(I think you can safely assume that if the user has created a third shortcut in a non standard location, he knows what it means or where to look for information when the copied shortcut doesn't work. Heck, you could even put a warning somewhere in the updater noting the changes.)

If you really truly want to do what you've stated (updating every shortcut), you can do it with an extension of the method of the accepted answer here. Just search for any .lnk file, see if TargetPath is the old engine location, and update it if it is.

Vinko Vrsalovic
There are two problems. One is how to find the shortcuts, even for the default install; the installer (Inno Setup) allows the user to select the name of the directory in the Start Menu to install into. We'd have to figure out how to extract information about where Inno Setup put its shortcuts, probably from the uninstall log, and that may be fragile. The second is that users may copy or move shortcuts without having any idea of how to fix the problem if it comes up (and having long forgotten about any dialog boxes they may have seen). I'd like to make this process as seamless as possible.
Brian Campbell
See the final paragraph... it links to a WSH way of finding and updating shortcuts.
Vinko Vrsalovic
Well, not true, it links to a method to update a shortcut and to another method to find files, you have to do the mix :)
Vinko Vrsalovic
Yeah. Actually searching the whole disk for all shortcuts and updating the relevant ones seems like a pretty losing proposition; pretty damn slow, and too many opportunities for some corner case failing horribly. I was hoping there might be some kind of built in index of them to make this process easier.
Brian Campbell
I would do as I said, update installed shortcuts only, and have an executable at the old location launching the new engine.
Vinko Vrsalovic
(because, as far as I know, there is no such index)
Vinko Vrsalovic
A: 

This sounds like an installer issue to me. During an upgrade, why not just uninstall the old version and install the new version? I am not familiar with Inno Setup, but this is how we do our InstallShield installer for an upgrade. Granted this doesn't handle the case when the user manually creates a shortcut; however, the user could just recreate it. As for a simple search and replace, I don't think it's worth the effort.

Luke
Our program includes several gigabytes worth of media, which have all moved to a different path as well. As far as I know, Inno Setup has no features for producing an incremental update for this type of situation, that would not involve downloading all of the media all over again. Requiring the user to update his shortcuts manually is more trouble than you may think. We'd either have to re-create shortcuts that the user has moved out of the way, or the user would have to dig around deep in our program file hierarchy to find an engine that has a name unrelated to the name of the program.
Brian Campbell
+1  A: 

Well, the solution we've decided on is just doing the small little executable that launches our real engine. It took a bit more futzing with Visual Studio to get the project set up than I would have preferred, but it seems to be working out.

#include "stdafx.h"
#include <shellapi.h>

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
  HINSTANCE result = ShellExecute(NULL, _T("open"), 
                                  _T("engine\\win32\\NewEngine.exe"),
                                  lpCmdLine, NULL, 1);
  // ... handle errors ...
  return 0;
}

edit: Nope. This seems to work on XP, but not Windows 7 or Vista. Any ideas for why this would fail on Windows 7 or Vista would be much appreciated. If I can't figure this out soon, I may break this out into a separate question.

edit 2: Ah. On XP, forward slashes in the pathname work just fine. On Vista or newer, you need backslashes.

Brian Campbell
A: 

Instead of ShellExecute, try CreateProcess or spawn equivalents. I would bet on CreateProcess.

hackworks
What benefit would this give over ShellExecute?
Brian Campbell
+1  A: 

From the MSDN documentation for ShellExecute(), I notice you might need to initialize COM. Also, you need to provide full path to the executable (not relative). Alternatively, you could use ENVIRONMENT variables in the shortcuts instead of full paths. You can modify the ENVIRONMENT variables during new installations to reflect the new paths.

hackworks
+1  A: 

Strangely enough, no one mentioned NTFS Hard Links.

Some references:

MaD70
Hmm, interesting idea. That might have worked, but I've deployed the situation with the stub executable already. Thanks!
Brian Campbell
You are welcome. This is for future reference, I know you solved the problem months ago.. I read the entire thread. ;-)
MaD70