The Golden Egg: Desktop Shortcuts
One of the side benefits of ClickOnce is that I don't have to worry about end users who wouldn't know what to do with a new DLL if I e-mailed it to them and told them to copy it into the c:\program files\the app
folder. The fact that ClickOnce does not have the ability to automatically install desktop shortcuts to the application becomes a problem with this same group of users.
If you do your initial installation with an MSI file, this isn't a problem. But if your users install from a Web site with the manifests, then it definitely is.
Once Again, Know the Risks
I'm about to delve into another hack, which means you better know why ClickOnce does not put shortcuts on the user's desktop. One reason is that it requires your application to have full trust. By default, applications deployed with ClickOnce only have partial trust and you should set them to full trust only with a good understanding of what you are doing. Check out Patrick Darragh's ClickOnce article
for more info on that.
In his book "Smart Client Deployment with ClickOnce
," Brian Noyes reminds us that Microsoft created ClickOnce with specific rules so that it could be trusted not to muck with the end user's machine. Putting a desktop shortcut on the user's desktop falls into this bucket, but I'm doing it anyway, because my client specifically requested that I create a desktop shortcut as part of their installation and frankly, they trust me even more than they trust ClickOnce. To create a desktop shortcut you must tap into the Win32 API's Windows Script Host object model.
Adding the desktop shortcut is not part of the ClickOnce deployment. It is a function of the application that you are deploying.
shows my DesktopShortcut class with two methods. One determines if the shortcut already exists. The other creates it. The methods are shared, so the class does not need to be instantiated. The basis for this class came from an article by Les Smith.
Call these methods from your application's startup code.
If Not DesktopShortcut.Exists("MyApp") Then
This is a rude solution that just slams the shortcut on the desktop without asking if the user wants it or not. If the user deletes the shortcut, the application will just re-create it on next startup. That's what my client requested.
A more polite approach would be to check for the existence of the shortcut and then ask the user if they want it installed or not.
You could also choose to leverage the IsFirstRun
property of the System.Deployment.Application class. Check the Remarks
section of the IsFirstRun
property to learn more about how the Deployment API determines if this property returns True or False. This way you only create the shortcut the first time the user runs the application. If the user deletes the shortcut, it will not get re-created by the application.
Troubleshooting ClickOnce Deployments: The Docs
Don't overlook the pages of the MSDN documentation called "Troubleshooting ClickOnce Deployments." In fact, don't even wait until you have a problem to check it out. Go print it out and staple it to the end of this article and read it when you are finished here. Here's the online link to that document: http://msdn2.microsoft.com/en-us/fb94w1t5(VS.80).aspx
Points of Confusion
I struggled with a number of things before I had a better understanding how ClickOnce works. So these are my own personal FAQs, or POCs, if you prefer.
Where Does ClickOnce Install?
ClickOnce installs my custom application in the ClickOnce application cache (buried deep in the user's Local Settings) for the user that is logged in when the application is installed. If you take a look at the path of the file that the shortcut is pointing to, you may have a small fainting spell as one my clients did. The versions of my custom application are also maintained in the cache as updates are downloaded.
What if More than One User Shares the Computer? Can I Create a Desktop Shortcut for All Users?
|Figure 6: Finding the starting point in the installed MSDN Library for Visual Studio 2005 was a little tricky. Here's a road map. I prefer using the online docs as they are updated and are much easier to search anyway!|
Because the application is installed in the user's application cache, each user (with separate Windows logins) on a shared computer needs to install the application for their own login. The .NET Framework and other common pieces such as third-party tools or your own custom APIs that get shared across applications, only need to be installed once and will be available to all users. But the application itself requires per-user installation and a shared shortcut won't work.
Hey! I Updated Only One DLL but the Progress Bar Is Saying the Entire App Is Being Downloaded Again!
This issue really bugged me, but, in fact, the progress bar does not tell the whole story! ClickOnce needs to create a completely new version folder for each update. ClickOnce will determine which files are new and copy only those files down from the Web server. It then copies the rest over from the previous version folder in the user's assembly cache. So ClickOnce is, in fact, copying all of the files, but since most of those files are coming from a local source it's not really wasting time downloading anything more than it has to from the Web server.
Where Is that ClickOnce Documentation, Anyway?
If you have the MSDN Library installed, the ClickOnce documentation is buried deeply and not so easy to find. Figure 6
shows you where it is in my version. Online you can start looking at http://msdn2.microsoft.com/en-us/library/wh45kb66(VS.80).aspx
A Special Scenario: Intranet Users, ISA Server and Internet Explorer Proxy Issues
|Figure 7: Intranet problems required me to enter the IP address and DNS for the installation/update site into the LAN settings as exceptions.|
My client's application is used in-house and out in the wild by remote workers. The internal people hit the Web server through the local network while the remote people are coming in over the Web through an ISA Server. They had a proxy problem (identified by the Show Details link in the ClickOnce error dialog) that prevented them from getting at the manifests. I found that I had to do one extra switch to the local users' IE proxy settings. Although "Bypass proxy server for local addresses" was checked, entering the IP address and/or domain name (whichever the local users are using) into the proxy exceptions list fixed the problem. Figure 7
shows this dialog box.
After years of publicly documented frustration with early iterations of technologies that evolved into ClickOnce, I have finally found ClickOnce to be the tool I needed. It doesn't answer all of my needs, but with the little hacks that I've figured out (implemented in ways that I don't feel put my client's data or intellectual property, nor the end user's PCs at risk) I've finally accomplished what I set out to do to simplify the deployment and updating of this application (see the sidebar "Tricks and Traps
" for more information). The ClickOnce Publishing wizard will suffice as a perfect solution for many applications, but don't ignore the possibilities that exist to go much deeper with the Deployment API (System.Deployment). The fact that people are writing entire books on the topic says a lot about the depth of this technology.