Tuesday, May 13, 2008

Update: This article is not limited to deploying applications to Vista, but also when changing files that are only writeable by administrators (e.g. files in the Program Files directory).

If you have not made specific changes to your installation to support UAC in Vista, this is for you. I hope this will help others to not spend many days of confusion, desperation and sleepless nights like I have.

Lately I've been getting reports from some of my coworkers running Windows Vista that the app.config file in our application was not updated after installation. I've also experienced this myself. We've solved them without knowing exactly how (which I hate). Typically "I uninstalled the application and installed to a different location, and it worked!" Well, this is a workaround that are not particulary popular to any of our customers, so I dived into the problem to find the exact reason.

To save you some reading I'll just say that the reason and solution is to provide your application with a manifest file to handle UAC in Vista as described in this article: Create and Embed an Application Manifest (UAC) I haven't actually tried this out yet, but I trust the article to be correct :-)

Virtualization
But that's not the interesting part. The interesting part is what happens (or what can happen) if you don't have an application manifest for this purpose? If your superstitious you might think that something weird is going on with your computer. If you're like me you KNOW that something weird is going on with your computer, and you need to find it and fix it. The weird thing is Vista virtualization.

"File virtualization addresses the situation where an application relies on the ability to store a file, such as a configuration file, in a system location typically writeable only by administrators"

"Virtualization is implemented to improve application compatibility problems for applications running as a standard user on Windows Vista."

As I write this I have exactly this problem on my computer. I've installed our application (Contiki ECM) to this location: C:\Program Files\CMA Contiki AS\Contiki ECM\. This is where I've always install our app. So today I installed and checked that the app.config was updated with all my changes done during installation. And it hadn't. Actually it was updated, but not with my changes. It looked like an old file that I had some time ago. How could this happen?

Textpad .vs. Notepad
To make this even more confusing, I discovered this reading the file in TextPad, but when opening the file in Notepad it was fine. All my changes was there! So I thought that this was a TextPad problem. I started our application, but it turns out that when .Net tries to read the config file, it reads the same old stuff as TextPad did, resulting in old config to be loaded into our app. Why does Notepad get the right file? I don't know. Please tell me if you do.

The solution
So after Googling for a while I found this article on MSDN, and things started to make sense. But first let me show you what it looks like on my computer. The file causing my headaches are Contiki.Windows.Application.exe.config.

VistaUNCImg1 
Do you see when it's modified? 08:56 this morning, but the file that is being opened is from 13th of April! How do I know? Well, if you have a look at the virtualized files which you'll find in C:\Users\Username\AppData\Local\VirtualStore\[Your path], it might help out. So I looked at C:\Users\1jontor\AppData\Local\VirtualStore\Program Files\CMA Contiki AS\Contiki ECM and found this:

VistaUNCImg2 
Modified back in April. I opened this file and it was exactly what I saw in TextPad. But this file is the same both in TextPad and Notepad! :-)

Explorer gives you a shortcut to the Virtual Store folder if any files are virtualized, and will show this button in Explorer:

VistaUNCImg3

The end
A couple of notes from the MSDN article:

"When you enumerate resources in folders and in the registry, Windows Vista will merge global file/folder and registry keys into a single list. In this merged view, the global (protected) resource is listed along with the virtualized resource."

"The virtual copy will always be present to the application first.... even if [some file] is updated"

Even if the file is updated!? Who though of that? Was that really such a good idea? I can see what they where thinking, but it would have saved me a lot of work getting an error message saying "Access denied"...

To end this off I picked another good quote from the article:

"Microsoft intends to remove virtualization from future versions of the Windows operating system as more applications are migrated to Windows Vista."

I appreciate that... :-)

Tuesday, May 13, 2008 10:08:42 PM (W. Europe Daylight Time, UTC+02:00)
 Wednesday, May 07, 2008

Today I was struggling to figure out why I kept getting this error message when downloading a ClickOnce app:

The file 'C:\Documents and Settings\[user]\Local Settings\Temp\2\Deployment\RCAX3K4W.T8E\GRY27V4Q.GBE\SomeDll.dll' already exists.

First, let me just say that I don't use Visual Studio to create the ClickOnce deployment, but the Mage.exe utility. If you use Visual Studio this problem will be solved on Publish in Visual Studio.

I knew there was only one of this dll present on the server where ClickOnce downloads its files, but still it insisted that it was already downloaded. I checked my application manifest and there where only one entry for my dll. The dll causing this problem is a COM dll with generated manifest files (Reg-Free COM) as described here.

I started to inspect the Reg-Free COM manifest file generated by Visual Studio. It turns out that this manifest file use the same syntax as ClickOnce, or actually ClickOnce use the existing manifest schema that was introduced with Windows XP and Reg-Free COM. So in my ClickOnce manifest I had this:

...
<file name="My.dll" size="1121280">
  <hash>
    <dsig:Transforms>
      <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
    </dsig:Transforms>
    <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
    <dsig:DigestValue>UwpS1EpkD7aJk3uWdOtX+3BHiOA=</dsig:DigestValue>
  </hash>
</file>
...

...and in my Reg-Free COM manifest I had this:

...
<file name="My.dll" asmv2:size="1121280">
    <hash xmlns="urn:schemas-microsoft-com:asm.v2">
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <dsig:DigestValue>UwpS1EpkD7aJk3uWdOtX+3BHiOA=</dsig:DigestValue>
    </hash>
    <typelib tlbid="{2d5e2d34-bed5-4b9f-9793-a31e26e6806e}" version="4.1" helpdir="" resourceid="0" flags="HASDISKIMAGE" />
    ...COM Registry Entries...
</file>
...

It's exactly the same as ClickOnce except from the <typelib> part which is used by Reg-Free COM. ClickOnce treated this as any other ClickOnce manifest, and correctly stated that the file is about to be downloaded twice. The surprising part for me though was that the Reg-Free COM manifest was read at all. Since the deployment manifest is only linked to the application manifest...

So what's the solution? Just delete the file entry in the ClickOnce manifest and re-sign it! Deleting can be done like this:

ApplicationManifest manifest = (ApplicationManifest) ManifestReader.ReadManifest("ApplicationManifest", @"My.exe.manifest", false);
FileReference fileRef = manifest.FileReferences.FindTargetPath("My.dll");
manifest.FileReferences.Remove(fileRef);
ManifestWriter.WriteManifest(manifest);

Curious about how Visual Studio solves this? It merges all the manifest files into the application manifest and use the imported manifest entries instead (or something like that). At least that happened when I created a sample program to test this.

Wednesday, May 07, 2008 12:05:41 AM (W. Europe Daylight Time, UTC+02:00)