Creating Application Shortcuts for Click-Once Applications

Posted by & filed under Code Mode, Technology.

Category: Code ModeWhile writing my latest C# .NET software application, the need came to be able to allow users to enable and disable an “auto-start” feature. Users wanted to control whether the app would start automatically when they start their workstation, or log into their accounts, or whether they had to start it manually. The challenge came out the fact that this was a very small application and was being created using VS C# Express and Click-Once deployment. My options were to either manipulate the registry run keys, or create a method to create/delete an application shortcut in the startup folder. I opted for the shortcut solution figuring it was probably the safest and easiest solution (VS express editions have limited access to registry manipulation, not to mention that any keys created through the use of the application would be orphaned after uninstall).

The first problem we have with the shortcut solution is that Click-Once deployments do not install (in the traditional sense) on the target system. The applications do not install in the Program Files directory and there is no control over setting or selecting a preferred location to install them. Instead, Click-Once applications are “installed” on a per-user basis to the active users profile > […Documents and Settings\user_account\Local Settings\Apps\…\…] and when deployed in “off line” mode, Click_once also adds a sudo shortcut to the Start > All Programs menu. I say “Sudo” shortcut because it is not a traditional shortcut (.lnk) file, but instead an application reference file with an extension of .appref-ms

The directories below the “Apps” directory containing the executable files are not easily readable and appear to be dynamically generated by the Click-once deployment process [please correct me if I’m wrong]. This makes it impossible to include shortcuts in the project to access the executable without first knowing the absolute path to the executable after installation. If it is possible, I am not aware of how to go about doing it. Normally, I would have control over the installation path and directory structure so that I could include shortcut files with the project and copy/move them to the directories I need (programs folder – startup folder – etc) but we don’t have that ability with click_once deployments.

Another major problem is that the .NET framework does not provide a native class or method for creating shortcuts. Are you kidding me? With everything that the framework includes, I can’t easily create a (what should be) simple shortcut? PFFT!! Whatever… Help on the web was scarce and all the suggestions seemed to point to the same reference that showed how to create them using COM add-ins. I don’t want to go there.

I nearly pulled all my hair out trying to figure out how to overcome these problems and create a shortcut in the startup folder. Then it hit me..wait a minute..the click-once deployment already created an application reference (shortcut) in the All Programs folder. Why can’t I just use that? I was so caught up in “how to create the shortcut” that I almost overlooked the fact that it was already done.

My Solution (a simplified explaination):
This is Tray Icon Application that monitors an XML file and alerts users to updates and changes made to it.

  1. Provide a MenuItem in the Tray Icon context menu to enable/disable the “auto-start” feature.
  2. Include a method to copy the application reference created in the “All Programs” folder to the “Startup” folder – enable auto-start.
  3. Include a method to delete the application reference (copy) from the “Startup” folder – disable auto-start.
  4. Install using click-once deployment.
  5. Test

How I did it [Code Samples]:

tsmiAutoStart_CheckChanged method:
This Method is called when the tsmiAutoStart menu item checked state changes

private void tsmiAutoStart_CheckedChanged(object sender, EventArgs e){
 if (tsmiAutoStart.Checked) manage_startupAutoRun("copy");
 else manage_startupAutoRun("delete");
}

manage_startupAutoRun method:
This method is triggered by the tsmiAutoStart_CheckedChanged method and creates or deletes an application reference shortcut in the users programs > startup menu enables the ability for users to control when/how the application runs (during startup, or manually)

“Action” parameter must be a string value of either “copy” or “delete”

private void manage_startupAutoRun(string action){
 if (string.IsNullOrEmpty(startMenu_FolderName)) startMenu_FolderName = "Publisher Name"; //NOTE: startMenu_FolderName must be set to the value of Project Properties > Publish Tab > Options button > Publisher Name field
  string app_program_file = Environment.GetFolderPath(System.Environment.SpecialFolder.Programs) + "\" + startMenu_FolderName + "\" + Application.ProductName + ".appref-ms";
  bool app_program_file_exists = System.IO.File.Exists(app_program_file);
  string startup_file = Environment.GetFolderPath(System.Environment.SpecialFolder.Startup) + "\" + Application.ProductName + ".appref-ms";
  bool startup_file_exists = File.Exists(startup_file);
  startMenu_FolderName = string.Empty;
  switch (action)
  {
   case "delete":
    //remove application reference shortcut
    if (startup_file_exists) File.Delete(startup_file);
    break;
   case "copy":
    if ((app_program_file_exists) && (!startup_file_exists)) File.Copy(app_program_file, startup_file);
    //copy application reference shortcut
   break;
   default:
    throw new Exception("An invalid paramater [" + action + "] was passed to the manage_startupAutoRun method: accepts \"copy\" or \"delete\"");
   break;
  }
}

autostart_enabled method:

Method is called during application load and returns a boolian value (true/false) based on the existance of an application reference shorcut located in the users programs > startup folder.

This method returns a boolean true/false value used to set the checked state of the MenuItem that calls the manage_startupAutoRun method. If the startup folder icon for the app exists, the MenuItem is set to checked and unchecked if it is not. This method is called only once during the application load.

private bool autostart_enabled(){
//check for shortcut in startup folder
//if exists, set "checked" state for menu item
//if not, set "unchecked" state for menu item.
 if (string.IsNullOrEmpty(startMenu_FolderName)) startMenu_FolderName = "Publisher Name"; //NOTE: startMenu_FolderName must be set to the value of Project Properties > Publish Tab > Options button > Publisher Name field
 string app_StartupFolderpath = Environment.GetFolderPath(System.Environment.SpecialFolder.Startup) + "\"  + Application.ProductName + ".appref-ms";
 startMenu_FolderName = string.Empty;
 return File.Exists(app_StartupFolderpath)?  true : false;
}

In the end, this process allows the user to control an “auto_start” feature by using the existing application reference file created in the “All Programs” menu and copying it to or deleting it from the Startup Menu programmatically from within the application.

9 Responses to “Creating Application Shortcuts for Click-Once Applications”

  1. Alex Taylor

    The same appref-ms file will work on any computer. It’s ok if you include it in the project I think.

    Maybe this is specific to vista or maybe just me, but I can’t get windows to execute my appref-ms file in the startup folder. Maybe it only looks for .LNKs or something?

  2. Ed Stafford

    Alex,

    The appref-ms file is provided by the click-once install so you do not include it with your project.

    I don’t have a Vista system to test this on, but if you are having trouble getting this to work, I’d start by making sure you have all your Project Properties set correctly, (see notes in the code samples), and you are referencing your paths correctly. I would love to hear back from you if you are able to sort it out.

  3. David Karlin

    This worked very well for me (there were a couple of trivial errors cutting and pasting the code, but nothing to worry about; I can give details if you want), so thanks very much for the clear and detailed post. Haven’t tried Vista yet.

    A question about a possible additional feature: I would like to run the main window of my app minimised to the system tray when starting from boot, but opened normally if started manually. This requires the app to know whether or not it has been launched from the startup link. Do you have any idea on how to do this?

    Thanks

  4. Ed Stafford

    David,
    Thanks for your comment. I’m happy you found the info here to be helpful.
    That’s an interesting idea about detecting how the app is launched. To be honest, I’m not sure if there is a way to do that, but it may be worth looking in to. Thanks for the suggestion.

    I am curious about the “trivial” errors you were seeing. The samples were cut directly from my working application. Could possibly be specific to the design differences between your application and the samples here, or maybe a different .NET version? This was created for the 2.0 framework.

    Anyway, thanks again for you input.

  5. Richard

    This does not currently work on Vista, XP however works great. I’ve even tried making a separate launcher exe as i have read others successfully used but with no luck.

  6. James

    this article helped me resolved my problem that has occupied me for the last 3 days , trying to get a simple vb application with a reference application file to run thru schedule tasks , the answer was in this article thank you

  7. admin

    So glad the information here was able to help you. Thanks for your comment.