Where did my permission set controls go?
20 May 09 01:00 PM

I’m going to diverge a bit off the VSTO path and talk about a more generic ClickOnce story.  If you have used ClickOnce in VS 2008 or VS 2005 you may be somewhat familiar with partial trust scenarios and the idea of permission sets.  If you do not care about partial trust but instead live in the world of using full-trust (such as VSTO requires) then you can skip this post as it may be irrelevant to you. 

The Setup

If you haven’t heard yet, we are in the midst of shipping the Beta for VS 2010.  You can read more about it here: 

http://blogs.msdn.com/somasegar/archive/2009/05/18/visual-studio-2010-and-net-fx-4-beta-1-ships.aspx

There are many exciting new features and changes occurring in this cycle.  As a product of some of these changes I’ve been seeing a lot of questions about some of the changes being made.  I’d like to answer at least one of them now.

The Question

“I went to customize my zone permissions and noticed that the control that lists the zone permissions is missing!  Is this a bug or is this control moved somewhere else?  I need to know how to customized the internet zone so my application will work.  How do I do this in VS 2010?”

Here is a screenshot of said control in VS 2008 (on Vista):

PermissionPage

Here is a screenshot from VS2010 Beta 1 (on Server 2008):

Permissions2010

The Short Answer

This is not a bug, we intentionally removed this control within VS 2010. 

The Long Answer

So the question itself is just one of the reasons that this control was removed.  As it turns out there is an implied functionality/design in this control that confuses developers about how the security model works.  Conceptually it is easy to look at this control and assume that you can set a “zone” and then customize the permissions that should work within that zone.  But this is not the case and this is where the confusion comes into play.

What this control essentially does is create a Custom Permission Set and compare it to the permission set of a “well known” zone.  If you change the setting element to anything other than Zone Default, you’ve defined a “custom” permission set and that is what your application will request.  In VS 2008 and VS 2010, this same functionality can be achieved by adding the individual permissions to the <TrustInfo> element in the app.manifest file.  In VS 2010, this will be the only way to define a “custom” permission set.  You can find an older MSDN article on how to do this here: http://msdn.microsoft.com/en-us/library/6ad1fshk(VS.80).aspx.

Our belief is that most customers that use this control are under the impression they get some benefit from using the custom sets, but in most cases they are not getting the benefit they believe they are getting.  The misconception comes about because the impact of changing things in this control are non-obvious.  So let’s break this down into 3 scenarios and describe what happens, why, and alternatives that get the same effect.

Target Internet Zone:  Do not change anything.

If your application really does need only the internet permission set, it will work without a trust prompt as long as you run it from the following zones:  Internet, Local Intranet, My Computer.  You do not see a trust prompt (assuming your application is signed with a “known” certificate that chains to a Trusted Root Authority) because you have provided “evidence” (the permissions you requested,where it is run from, and a “known” certificate signature) saying your application will only execute within the confines of the functionality allowed for applications that execute within that zone.  If your application needs any permissions outside of this zone, it will fail with a “trust/security” error.

In VS 2010, we support this scenario with the current UI, the “Zone your application will be install from:” control is what determines the permissions set. 

Target Internet Zone:  Remove a Permission.

You are no longer targeting the “Internet” Permission set but rather a custom set.  If your application is published on the internet, local intranet, or my computer zones, it will function without a trust prompt exactly like targeting the internet zone.  There is a caveat here, but I will come back to it (See Caveat:  Least Permissions).

In VS2010, there are 2 options to achieve this:  You could have simply targeted the internet zone or you can define the custom set your application needs in the app.manifest file manually.  Our general recommendation is to target the well-known-zone that your application runs from rather than defining custom permission sets.

Target Internet Zone:  Add a Permission.

In this scenario, your customers will get the ClickOnce trust prompt.  We believe users of the permission set control fall into this bucket.  The reality of the security model is that at this point once you have incurred a trust prompt of any kind you might as well be targeting “full trust” since your end user will not see a difference.

In VS2010, if you cannot run under the permission set of the zone you are targeting, we recommend that you switch your application to requesting full trust.  Functionally to the end user, this is exactly the same as if you had targeted a custom set that exceeds the permissions of the zone your application is installed or run from.  You can manually configure the custom set using the app.manifest xml file within the project.

Caveat:  Least Permissions

Our team is aware there is a segment of our developer customers that prefers to target the “least” number of permissions required in which to run their application.  While we do understand this UI made it much easier to do this, we believe that this segment is familiar enough with permission sets that they are capable of achieving the appropriate settings using the app.manifest xml file.  Please continue reading if you would like to understand the other justifications for why this UI was removed.

How we came to this final decision (or rather “other aspects involved”):

Generally we don’t remove UI or features without good reasons.  In this case, we discussed at length with the Security Team about this specific piece of UI.  They have indicated to us that they believe the general focus of their customers should be to move away from “custom” permission sets and more to targeting only the well-known permission sets or fully trust.

Beyond the general “this is the direction we want to take this feature,” VS 2010 includes some changes that made removing this UI desirable from a technical perspective.  If you have not noticed yet, VS 2010 allows you to target/build and debug solutions against both CLR 2.0 (.NET version 2.0, 3.0 and 3.5) and CLR 4.0 (.NET version 4.0).  Visual Studio itself runs against CLR 4.0.  In previous cycles, the assumption was that VS would only run against the CLR version it targets, but that assumption is no longer true.  As a result, many elements of VS have had to change because VS cannot always rely on the CLR it is running against to provide the correct information for the project (if it targets a different CLR).  Our permission set control falls under the bucket of things that functioned on this basic assumption.  When we looked at what the cost of changing the design was and how it would impact the overall user story, we determined that it was better for our customers that we removed the UI and focused on improving the other aspects of the product.  We feel that the loss of improved functionality (how easy it is to setup custom permissions) did not outweigh the gains we could apply elsewhere.

Thank You for reading.

Kris

Postedby krimakey | 2 Comments    
Filed under:
Enterprise Level Deployment of VSTO Solutions: Deployment Design
08 April 09 05:00 PM

It's been a while, I'm not really interested in going to the details of why at the moment, lets dig right into the topic.

Generally I focus on more of the technical aspects of what you can do without really talking much about some of the other considerations that should go into make your deployment design decisions.  This post is going to be a little different.  I won't have any nuggets of deployment code or advice on how to achieve specific deployment actions, rather I'm going to cover some of the details that you might want to include into your evaluation before you decide "how" you will deploy your solution.  Essentially this post will be about how to go about designing your deployment (what factors you may have to consider and how they will impact your deployment implementation).

First, some terminology:  I have been known to throw around the following terms and haven't really defined them in any consistent way, so I'm going do so now.

Customer level solution (customer solutions, customer deployments):  Solutions in this class of products that are released to the general public.  Generally as far as deployment goes, Customer solutions are deployed by some kind of opt-in methodology.  Customer solutions have constraints unique to not always having control of the system in which the solution is installed into.

Small Business level solution (smb solutions, smb  deployments) :  Solutions in this class of products that target user bases encompassing 10 - 200 clients.  Deployment and installation state may be controlled by a central organization or individual.  SMB solutions generally have some moderate to low-level infrastructure such as an intranet and UNC servers.

Enterprise level solution (enterprise solutions, enterprise deployments):  Solutions in this class of products will target a set user base of 200-100,000 clients.  Heavy infrastructure is available and both deployment and installation state are controlled by a central organization (IT department) with dedicated resources for management and support.  Constraints on this level are often defined by such issues as infrastructure constraints, machine state preservation and maintenance impact.

I'm going to focus on the enterprise solutions and some of the specific details that an IT department may impose on deployment configuration and maintenance decisions.  Enterprise solutions should have 4 specific phases of a solution's lifetime that should be considered before making deployment design decisions.  These phases are initial rollout, solution maintenance (updating), emergency response and uninstall.  

Initial Rollout:

When considering Initial Rollout, there are a number of factors that should be considered.  One of which is the bandwidth-to-client metric (versus solution size) and the window of opportunity for rollout.  Simply put, how long is it going to take to for every client to download the solution the first time.  Here are some numbers and math.

First, assumptions and caveats:

All numbers here are idealized, actual networking is never as nice as this idealized form.  The assumption for the following graphs is that you are hosting all of the data at 1 machine and the network bandwidth is the idealized out-bandwidth of the publish server.  VSTO solutions may range in size from 100KB to 50MB or more depending on any number of factors involved.  As a reasonable medium point I'm choosing 5MB with the assumption that most solutions will sit somewhere within this upper bound. 

Next, the formula:

Rollout Time = Amount of Data / Speed of Data

Rollout Time (minutes)  = ([number of installs] x [Installation Size]) / ([Bandwdith] x 0.125  x 60)

Bandwidth is generally stated in megabits per second (mb/s), but we need to calculated based on megabytes (MB) and minutes thus the multiplication by 1/8 and by 60.

Finally, Data:

Solution only installation (no prerequisites)
100 megabit network

Client Machines

Network Bandwidth (mb/s)

Installation Size (MB)

Approximate Rollout Time (minutes) 

200 100 5 2
500 100 5 4
1000 100 5 7
5000 100 5 34
10000 100 5 67
1 gigabit network

Client Machines

Network Bandwidth (mb/s)

Installation Size (MB)

Approximate Rollout Time (minutes) 

5000 1000 5 4
10000 1000 5 7
50000 1000 5 34
100000 1000 5 67

However these are the "best case" roll out scenarios give that you may not have all of the prerequisites.  Consider that the following are common prerequisites that you may have to also install:

Office 2007 PIA redist:  6.82 Mb

VSTOR 3.0 SP1 redist: 3.27 Mb

Solution, Runtime and PIAs
100 megabit network

Client Machines

Network Bandwidth (mb/s)

Installation Size (MB)

Approximate Rollout Time (minutes) 

200 100 15 4
500 100 15 10
1000 100 15 20
5000 100 15 100
10000 100 15 200
1 gigabit network

Client Machines

Network Bandwidth (mb/s)

Installation Size (MB)

Approximate Rollout Time (minutes) 

5000 1000 15 10
10000 1000 15 20
50000 1000 15 100
100000 1000 15 200

What we can draw from these numbers? Nothing specific, these values are based on idealized networking and don't take into consideration a lot of factors that may have a greater impact on your deployment design.  What they do give us though is a basic framework to use as a basis for further discussion.

Specifically, as your organization is bigger or has less infrastructure, there may be value in breaking up the initial roll out into waves or separate deployment sites.  If you have an organization of 10k or more employees, there is a pretty high chance you can use geographic based division to save a lot of pain and allow you to handle the initial rollout in a controlled manner.

Let's move on and talk about some of the other factors that should influence the rollout.  One things that comes to mind in particular is the prerequisites.  By default VSTO publishes a Setup.exe file that is meant to be used to pull prerequisites down to client machines that don't have them installed.  If the prerequisites are not present you may want to roll them out first and possibly even rollout a "dummy" solution that allows you to track the number of successful prerequisite setups.  When you then push out the "real" solution, you only need to worry about the solution itself and not the problems that would be caused by failures in the prerequisites. 

Work habits is another factor you have to consider for initial rollout.  You may consider pre-registration of an Add-in as possible Rollout mechanism, but if you do you should be aware of the impact this specific factor may incur.  Specifically if your clients all connect at the same time or if it is staggered over a period of time there may be a much higher bandwidth cost.  An example graph below compares relative network usage versus Initial connection of clients (the data is made up but it demonstrates the basic idea).

In this example:

In this example we have a case where the bandwidth usage of installing the solution on all clients exceeds the capacity of the network infrastructure.  In both "scenarios"  the bandwidth speed and data served is the same, but the final results (and subsequent customer impact)  differ because of usage patterns. 

Scenario A is where a natural Bell curve occurs between 8:00 and 8:30.  Initially only a couple of clients start the installation process at 8:00, at 8:05 more connect, at 8:10 the highest number of clients are connecting (about 50% of the total) and then as time progress fewer clients are connecting. 

Scenario B is where All clients connect at the same moment (at 8:00)

image

The key take-away from this example should be the effect that spreading out the install step can have.  In both cases the network usage peaking is causing a delay, but in one case the delay is at least 15 minutes in length for some clients.  If you're in a situation where your clients have common peak times (specifically around startup) you will want to reduce the amount of potential impact your rollout will have.

Now that we've established some of the factors, lets talk about some specific design choices you might make based on how these factors impact your specific deployment story. If you're in an enterprise that is just beginning to rollout .NET 3.5 (or 3.5 SP1) and the VSTO prerequisites, you probably specifically want to roll out the prerequisites ahead of time to ensure that when you finally do roll out your specific solution code there are fewer kinks to work out in both steps.  Using a "test" add-in (specifically on the Application you plan to customize) may help flush out any issues related to initial prerequisite installations.

There are 2 basic paths you might take to propagate the solution out to your clients. 

The ClickOnce method may be used by forcibly installing the prerequisites (which are machine level and require administrative access) and then pushing a ClickOnce registration (of and Add-in) to all user accounts  (for documents, simply making the documents available is the same as registering the add-in).  The first time your solution consumers login on a client machine and start the customized application (or open a customized document) Clickonce will pull down the solution (from the location you specific in the registration) and store in the cache on that machine.  Depending on your user statistics this can result in a installation really bad peaks.  If you find that you might have this kind of peaking behavior there are some specific options you might employ to reduce the rollout impact.  One option is to stagger the registration step.  By introducing the registration in waves you can reduce the "height" of the peaks to something that doesn't significantly impact your user base.  Another option with particularly large rollouts might be to host the solution on different servers.  Doing this breaks up the load but keep in Mind VSTO ClickOnce doesn't really have a good mechanism to allow you to load balance these solution.  Once an installation points to a specific deployment (publish) server, it will always point to that server.  An uninstall and reinstall (on each client) would be necessary to migrate client installations.

The vstolocal method would be the alternative.  Similar to (or possibly using) MSI installations you would copy the customization contents to a specific location on the machine and then push down a registration with the |vstolocal tag.  Using this method would allow you to be more specific about "when" the solution is installed.  With the vstolocal method, the "hard" work is all in getting the client computer properly configured once you've achieved that, the subsequent rollout should just be a matter of "when".

On trusting the solution:

In both cases, you may want to use certificate trust since it allows you to trust the solution for all users on that machine.  If you do not use a trusted publisher certificate approach, each of your users will incur a trust prompt on the initial execution of the solution on each client (example: Joe would see it on Client A and Client B but Bill who only uses Client B for the customized app only sees the prompt on Client B (though both will see it on Client B)).

Solution Maintenance:

Depending on the nature of your solution you may be planning regular updates, infrequent updates or no updates at all.  When considering the design of your deployment story, you should consider how updating is going to impact your usage scenarios.

When using "vstolocal", updates are entirely based on a push model where you have to push a new version of the manifests and  executable files to each client machine.  Every update in this model will pretty much have the same impact as incurring a solution only initial rollout.

If you use ClickOnce, there are several options for managing updating.  ClickOnce itself allows for determining the frequency of update checks but there are scenarios with this that you may want to consider.  Generally the cost of checking shouldn't be significant issue, when a check is made, only the deployment manifest is downloaded to the client.  Most manifests should be in the 6k - 10k size which means even with a 100 mb/s connection, a 7 second delay would only occur if around 9000 clients attempted to check at the same moment.  It's not really the update check that is likely to cause problems, its those times when an update actually exists to be downloaded (the amount of data and subsequently bandwidth is a magnitude larger).  The same basic network metrics and usage patterns in the initial rollout may have similar impacts on your usage experience so it's a factor you should consider in your design.

One possible method of reducing spiking on "update days" is to stagger when the update checks occur.  This prevents spiking but it also delays when all clients will have the update and can be problematic if older clients can cause problems with newer clients when they share data sources (ex:  your solution access a Database and an update includes a Database Schema change that causes issues when older clients attempt to manipulate data). 

Another potential flaw with staggering updates is relating to a natural tendency for "bunching".  This is best explained as an example: tets just assume for the sake of this example, profiling indicated that having every client download updates on the same day would over-tax the resources available.  So to mitigate the problem the initial rollout occurred over the course of a week (5 days) and the each client was set to check for updates every 7 days.  So each day of the week, 20% of your clients check for updates first thing in the morning (an assumption that every client opens the application at least 1 time every  (work)day is made here).

The problem occurs whenever vacations or Holidays occur.  Each day that users are not logged into client machines the scheduled checks (for the missed day) to check on the next day.  What this ends up doing is causing bunching up (most likely around the middle of the week).  Here is little example graphic to demonstrate what this might look like:

image

Initially in the first week all clients are checking in a consistent pattern and no spike in usage occurs.  However on the second week, Monday and Friday are both Holidays.  On Tuesday 40% of the clients are checking for updates since the 20% from Monday were unable to check on their "designated" day.  Additionally on the third week, due to Monday and the previous Friday being holidays, now 60% of the users are checking for updates on Tuesday (and 0% are checking on Friday and Monday).

One mitigation for this is to delay checking for updates by a larger chunk of time (3 weeks for example) and providing a bigger buffer between each "wave" of updates.  There are other methods you might work around this behavior (rather than using automatic checking, using the ClickOnce API and controlling when update checks occur similar to an earlier blog post I had about creating a "check for updates" button).

Emergency Response:

While no one wants to ship a bug or have cases when a solution has been compromised by a virus or hacker, it is important to be aware of what you can do to mitigate the impact when these things occur.  By having a clearly designed response ahead of time, it may be possible to reduce the severity of the impact on your business operations by reducing the response time and window of opportunity for damage.

If you use vstolocal there are 2 specific methods you can take to mitigate a bad customization.  The first option is to disable the solution.  There are 2 methods:  force an uninstall on user startup or an alternative is to simply push the solution certificate into the Untrusted Certificates Store.  One of the subtle behaviors of vstolocal is that trust of the solution is always evaluated at startup.  This works from an administrative (machine) level and doesn't require pushing out any action to specific users.

The other option is to for a registry disable of the customization (set the load behavior to 2).  This works to shut down the solution from automatically starting up and causing further harm but it doesn't prevent users from re-enabling the solution via the com-add-ins dialog in office.  Additionally, disabling the add-in in this method requires pushing the change to every user on every client. 

The second method for vstolocal solutions you might take is to simply force an uninstall of the solution, this prevents the solution from being re-enabled by the user but again incurs a user level action.  This depends on good authoring of your deployment mechanism (I'm assuming this to be an MSI).

If you deployed using ClickOnce, you can't use the Untrusted Certificates store to block/disable existing installs (of the bad update) since security for ClickOnce solutions is only evaluated when we copy the solution contents into the cache.  However you can push out commands to VSTOInstaller to force an install or alter the user level registry to disable the solution (same as described for vstolocal). 

If your solution checks for updates on every run though, you can push out a rollback by simply replacing the "bad" version with the version published previous to it.  Any users who had not updates will not see any effect (they will not have pulled down the "bad" update) and any users who installed the bad version will be rolled back to a working version.

The last option may be to write some code in the initialization of the customization to check for a "halt" registry key in the hklm registry hive.  This allows you to push out a single key to every client machine disabling the solution for every user on that machine...but it does require designing this functionality into the solution immediately. 

Uninstall:

Preparing for the end of life for your solution is part of proper deployment design.  When you are looking at Enterprise level solutions, you need to determine how responsive you want the uninstall process to be.  If you use vstolocal deployment, the work for uninstall is achieved by removing the solution files and then further forcing an deletion of the registration of the add-in for each and every user.  

With ClickOnce Installation, there isn't a specific mechanism built-in for pushing an uninstall out to every user, however VSTOInstaller does support a command line only uninstall.  The command would be something of the format:

%commonprogramfiles%\microsoft shared\VSTO\9.0\VSTOInstaller.exe /Silent /U "{publishlocation...Addin.vsto}"

You probably want to use the silent flag specifically to prevent your users from blocking the uninstall process.

Similar to handling an "emergency response" situation, you may simply want to bake a registry check to cause the solution to uninstall itself.  The problem with this method though is the registry key is left around (assuming it is in the hklm registry hive).

Another possible method for handling the final uninstall:  publish an update that calls VSTOInstaller to uninstall at add-in shutdown.  This this should work because fusion copies the solution executables into a shadow cache during execution (although you may want to ensure no references to (data) files exist at the moment (in execution) you call uninstall).

Thanks for Reading (and being patient enough to stay with me over a long break)

Kris

Postedby krimakey | 0 Comments    
Filed under: ,
VS 2008 SP1 and VSTO, why you should be seriously considering installation.
03 October 08 05:15 PM

I'm not going to go into detail about everything in the VS 2008 SP1 package, but what I would like to point out some key deployment features that were added and why you would want to consider installing even if you have a large user base using a base VS 2008 customization.  In this discussion I will refer to things as being RTM (meaning VS 2008 and VSTOR 3.0 Pre SP1) and SP1.

Adding VSTOR 3.0 and .NET 3.5 SP1 Patch Redistributable's: 

We've added some additional functionality to the base VSTOR 3.0 Runtime that you can actually take advantage with RTM Applications.  As such, if you install the SP1 patch on your development machine, you should be able to include the SP1 patches for both .NET 3.5 and VSTO Runtime 3.0. Adding these patches to the bootstrapper will not upgrade your existing customers but any new customers you have will be able to take advantage of the new functionality without any changes on your end.  Any previously existing customers could re-run the Setup.exe file to receive the upgraded functionality. 

One thing to keep in mind for these changes I'm describing is that the customization itself is not being upgraded, just the runtime it runs on is.  If you have to recompile your customization against the SP1 Runtime to take advantage of a new feature, your customization will not work for your customers who don't install the SP1 patches.

Additional Redistributable Package, the Office 2007 PIAS:

We've authored an Office 2007 PIA installer for general consumption.  In general, Office 2007 will install the PIAs by default, specifically it will install them if you have a .NET Framework installed on your machine at the time you install Office.  The problem with this is that it turns out a lot of you out there still use XP and clean installs of XP do not come with .NET installed.  As such we've included a PIA redist package that you should be able to include.  This package looks for a previous instance of an Office PIA existing on the machine before it does anything that might require elevation. 

Event Logging:

Specifically any deployment errors that occur on your client machines will by default log the error directly into the windows event log.  The functionality here isn't particularly rich, we've basically taken the same information that we display in the "alert dialog" that turning off VSTO_SUPPRESSDISPLAYALERTS enables.  The key here is that you should now be able to excavate what the actual cause of error was even if the issue is resolved before you get a chance to investigate.

Update Cancellation:

In RTM the timeframe in which an update can be "successfully" canceled is very small.  If the user cancels the updated outside of that particular window the VSTO Runtime sees it as an error case and blocks further execution of the customization.  Based on your feedback, we changed this behavior in SP1 such that you should now be able to cancel an update and continue running the previously installed version.   There are still cases where an error will occur (an example would be if you are installing the customization for the first time) but in general this should be a lot closer to what you guys told us you wanted.

 

Thank You for Reading.

Kris.

Postedby krimakey | 0 Comments    
Filed under: ,
A day at the movies.
02 September 08 07:00 PM

It's been quiet.  I've been super busy with a lot of things.  Some things I can talk about and mostly things I can't.  What I can talk about:  I went to PAX this last weekend.  PAX (also known as Penny Arcade Expo) is a big convention for us "gaming" enthusiasts.  When I say "gaming" I mean computer games, board games and of course the run of the old school pen and paper role-playing games (ala Dungeons and Dragons).

PAX is one of those things that helps me recharge once a year, get a bit of a look into what is coming down the pipeline and occasionally just see what other interesting things are going on in the entertainment industries of my choice.  At PAX I tend to focus more on seeing things rather than playing (I usually try a couple of game) there were some very interesting videos of the new stuff coming up and some very compelling demos also.  One thing in particular leapt out at me:  Popfly might be a very inspiring way of easing some of those non-programmer folks into understanding how things are put together.  I completely recommend taking a moment to look at this, especially if you have children you want to get interesting into the whole software industry.  At one point a 12 year old (I think he was 12, may have been younger) was demonstrating his game "apple eater".  Pretty much a Pac-man clone that he put together. 

So enough with the games, I know most of you are probably more interested in VSTO.  So here is something related to VSTO.   I have to admit that for me this is kind of an ego boost.  I don't generally put together videos since I feel like I don't have anything worth saving to a camera but when given the opportunity to create one focused on some of the VS 2008 Sp1 features, I couldn't pass it up.  It's pretty short, but there you go.

Thanks for Reading

Kris

Postedby krimakey | 0 Comments    
Filed under:
In the Before of the Beginning: Custom Prerequisites for VSTO ClickOnce (part II).
30 July 08 03:00 PM

In my last post I talked about the first steps to building my Customer Prerequisite.  In it, I built an MSI that would display a message box during the install phase. Here is what Setup1looks like when you run it:

Setup1inAction

It's nothing too ingenious but it gets the job done.

So...here we are with an MSI but I want to be able to somehow integrate this into the setup.exe file that gets created for my VSTO customization.  The first step to doing this is to author some bootstrapper manifests.  Specifically a package.xml file and a product.xml (for each supported language) needs to be created.  Thankfully the is a powertool that will help you do this. 

David Guyer has produced an exellent simple to use UI Tool to help with creating the bootstrapper manifest.  You can get the VS 2008 version of the tool here: http://www.codeplex.com/bmg/Release/ProjectReleases.aspx?ReleaseId=10652 .  This tool is currently listed as being in Beta and I still had to do some manual work to get everything lined up.  Here are the steps I took:

  • Open BMG for VS 2008 (installed it should show up under the Visual Studio 2008 folder).
  • Create a new "Package Manifest" Project.
  • Right Click on the left pane and select [Add Install File]
  • Select the MSI file via the [Browse] button
  • Set the Display Name (this will show up in VS)
  • You can include a text License Agreement file (this will be displayed before the MSI is ran).
  • Make sure to include a "Success" Exit Code on the Exit Codes tab.
  • By Default the Hashing method is used under the Security, I did not change this, but you should be aware of it since it means that any changes to MSI after creating the Package Manifests may cause errors.
  • Click Build.

BMG2008

As you can see, I get this warning about the Product Code.  I talked to David Guyer about this and here was his comment:

I think once you enter a display name, I try to autogenerate a product code.  Just to help clarify, the bootstrapper’s product code is not the same as the MSI’s product code… so you don’t need to enter the MSI’s product code…  a bootstrapper product code is something typically like “Microsoft.VisualBasic.Powertoys.1.0”

You can manually add this to the files.  If you go to the build output folder you will see all of the files

So the Product.xml file should look something like this:

<?xml version="1.0" encoding="utf-8"?>
<Product ProductCode="" xmlns="http://schemas.microsoft.com/developer/2004/01/bootstrapper">
  <PackageFiles CopyAllPackageFiles="false">
    <PackageFile Name="setup1.msi" Hash="DD8BF9497F8447128E4F6C72C8D30D8E2871E9BE" />
  </PackageFiles>
  <Commands Reboot="Defer">
    <Command PackageFile="setup1.msi">
      <ExitCodes>
        <ExitCode Value="0" Result="Success" />
        <DefaultExitCode Result="Fail" String="Anunexpectedexitcodewasr" FormatMessageFromSystem="true" />
      </ExitCodes>
    </Command>
  </Commands>
</Product>

 

The last steps are to add a Product code to this file and then copy the files in the Build Output folder to the prerequisites directory.

PreReqFolderView

The path shown here would be: C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\My Custom Prerequisite\

Once you've done that you should be able to include your custom prerequisite step as if it was just another standard part of your setup.

CustomPreReqDialog

I'm going to end with that, it should be enough to get you started on deploying even more powerful and interesting VSTO solutions.

Thank You for reading.

Kris

Postedby krimakey | 0 Comments    
Filed under: , ,
In the Before of the Beginning: Custom Prerequisites for VSTO ClickOnce (part I).
18 July 08 09:06 PM

In January I talked about using Custom Prerequisites to add a little more specialization to the VSTO ClickOnce experience.  I didn't go too much in depth into this and I've since seen a few comments crop up about them in some of the VSTO community spaces I watch.  So I'm going to go through a basic walk through of how you might go about doing this. 

So first you need to create your custom prerequisite installer.  I believe any executable can be used but for this post I'm going to cover a method where instead of using an "executable" I'm going to build an MSI (Windows Installer).  I might come back to the executable option in another post, but with that lets move on. 

Creating a Custom Prerequisite MSI that does something:

For my first try I actually created a custom .NET DLL that did my prerequisite step (in which I just to display an Message Box to ensure it was working).  To do this I created a C# class library project and added a new "Installer Class" to the solution.   Here's what the code for that class looks like:

namespace CustomAction1
{
    [RunInstaller(true)]
    public partial class Installer1 : Installer
    {
        public Installer1()
        {
            InitializeComponent();
        }

        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
                        
            string messageString = "Message Strings: \n";

            messageString = messageString + "Message:";
            messageString = messageString + this.Context.Parameters["Message"];
            messageString = messageString + "\n" + "OtherMessage:";
            messageString = messageString + this.Context.Parameters["OtherMessage"];
            System.Windows.Forms.MessageBox.Show(messageString);
        }
    }
}

I built this action and then created a "standard" Windows Installer Project.  I ripped out all of the steps from the MSI project and then added Custom action.  To do this, I added the "Primary Output" of the dll project to the project and then go to the Custom Actions pane via the view option in Setup Project. 

CustomActionPaneDialogOption

Once there I was able to add the "Primary output from CustomAction1" (the dll) as an install custom action.  In the properties window for the custom action (you have to select it) I set the following values: 

CustomActionData = /Message="Message1" /OtherMessage="This is the other Message"

InstallerClass = True

And with that I had my CustomAction MSI (I left it labelled "Setup1" in my example).  This is about as simple as it gets and it doesn't nearly cover everything (I didn't implement Uninstall or Update steps).  I believe the "power" in the MSI method is that you can hook into a standardized setup framework and it handles a lot of details you would otherwise need to implement.  This goes a little outside my particular area of expertise and I haven't had time to do the full degree of experimentation to give a definite reasons beyond that yet though.  If anyone is interested in educating me or clarifying anything on this stuff, please feel free to leave a comment.

In the next installment I'll cover how I authored the package manifest files so VS can include this at publish time.  

My post frequency has been a down a bit lately due to being busy with a lot of things but I am responsive to feedback (I've gotten a littler here and there, please feel free to post any comments or questions here so others may also get the benefit of it).  And with that I'm going to wrap up this post.

Thank You for reading.

Kris

Postedby krimakey | 0 Comments    
Filed under: , ,
MSI VSTO Deployment revealed
09 June 08 03:30 PM

For the past couple of months I have been avoiding talking too much on this blog about about creating "Windows Installer" deployments of VSTO.  I've been avoiding it because we've been working on writing a well-formed paper on how to do this and I wanted to wait for it to come out.  So here's the link to the announcement (includes links to the paper):

http://blogs.msdn.com/vsto/archive/2008/05/29/deploying-office-solutions-with-a-setup-project.aspx

If you're not convinced the ClickOnce deployment model is for you, this is the method you should consider and I recommend reading this paper and looking at the example before proceeding.

That's all I have for the moment, I'm looking for any interesting stories or questions to answer though, so please feel free to send me some feedback.

Thank You for reading. 

-Kris-

Postedby krimakey | 0 Comments    
Filed under: ,
Two years of lessons learned.
23 May 08 05:00 PM

It's been a while since I've posted here, I'm not quite ready to jump back into pushing deployment stuff again, I have had other things on my plate (vacation being one of them) and am finding less time to tackle the interesting questions that are coming through.

That said, I do want to keep up the habit of posting, so I'm going to switch gears a bit and talk about something a little more general than VSTO Deployment.  Yesterday marks 2 years working for Microsoft, working in the software industry and working in the testing field.  Here are some of the things I have learned in those two years that I think may interest you:

On Chocolate:

Having a candy dish full of chocolate is a great way to learn a lot of interesting things with very little effort.  I maintain my candy dish religiously and it's turned out to be very fortuitous.  Every time someone comes to "snatch" a piece I can often engage them long enough to learn something interesting from them.  Sometimes it is programming tips and other times it is just basic information about what they're working on. 

Another lesson with this:  don't eat the chocolate yourself, it's just not as good if it's not provided by someone else.

On Testing in General:

When I started working my belief was that a tester's goal was to find bugs.  In some cases this is true, but here at Microsoft, my job is to make the product better.  With this in mind a lot of what I focus on is not so much "finding bugs" but at "understanding" the product (and writing bugs when the understanding reveals deficiencies from what the product does and what we say it does or want it do ).  Part of this understanding is knowing what customers need which is why I am here writing this, hoping that should you be reading you'll drop me feedback on how you're using "my product". 

On Automation:

I believe software testing as an industry and automation in particular are still in an infant stage.  What I have seen internally and what I have heard about what happens outside of Microsoft indicates to me there is still a lot of work to be done and learned in this space.  With that in mind, I believe the goals of Automation are often counter to what automation actually provides.  Automation doesn't find bugs during development but rather forms a sort of rigid documented (in code) expectation of what the product is that is easily evaluated and repeated.   I'm not saying that Automation isn't important (quite the opposite) but rather often its value is not fully understood.

Automation is important especially if you want your product to work outside of the context in which it is initially written.  (We will sometimes find bugs around things like localization/globalization, though automation is only one step.)

The more "customer scenario" focused your automation is, the more likely it is to move forward and be understandable.  It is very easy for me to write automation that checks that the value within a file is the same as the value specified in a text box within the product, but the value of that test is much harder to express and the test is more likely to be broken as the product changes. However, if I tell you my test installs an add-in that was published to a web server, it's clear to see how the test is "relevant" to how the product works and it also is more likely to move forward as the product does.

Automation writers may know more about complex problems than product developers:  Automation often must be product, context and language resilient.   If your product is potentially going to have backwards and forwards version resiliency, you might ask your automation writers if they've tackled the problem before and what they've specifically learned about it.

On Development:

Be intentional.  When you are writing something new:  draw a picture or at least tell someone about your design.   Designing something before writing it will always result in something better then something you simply "piece together".

Use intellisense comments when available.

Use comments to give context and meaning to your code.

Avoid using TODO:,  TODO is a form of procrastination that can often cost you more than simply doing the work initially.  If you absolutely can't implement something at that moment, instead of just a "TODO:",  leave a (large) block comment at the entry point for what needs to be done and throw a not-implemented exception (preferably with something to help indicate what needs to be implemented).

Own your code but expect that you may be hit by a bus tomorrow.  This means that when you check code into source control you expect that someone will be able to pick up where you left off and achieve your same (end) goals.

On working in general:

Be open to other people's interests.  It's a lot easier to get cooperation from someone who you've helped than to ask for help from someone with a promise of future help.

Never eat lunch alone.

Be fearless even in the face of failure:  failing is an opportunity to learn and improve (don't forget to grasp it).

 

Thanks for reading.

Kris

 

[edited 5/27/08:  Minor typos and sentence clarification]

Postedby krimakey | 0 Comments    
Filed under: ,
Correction!
30 April 08 02:18 AM

I got ahead of myself and thought it was one week later than it really is (sort of good because I was beginning to think I was a lot further behind than I was).  I will be out next week.   Unfortunately this week has been super crazy.  I'm going to skip a full post this week but I will point out some posts of interest for those who may be looking at an "All-user" administrative installation.  Misha Shneerson has written some very good posts all about all-user installation in VSTO on his blog. 

The posts are here:

http://blogs.msdn.com/mshneer/archive/2007/09/04/deploying-your-vsto-add-in-to-all-users-part-i.aspx

http://blogs.msdn.com/mshneer/archive/2007/09/05/deploying-your-vsto-add-in-to-all-users-part-ii.aspx

http://blogs.msdn.com/mshneer/archive/2008/04/24/deploying-your-vsto-add-in-to-all-users-part-iii.aspx

You should pay specific attention to the third article as it covers VSTO 3.0 specifically.

With that, I'm going to go back to being super-busy until I wrap up this week and then take a week off (there definitely will be no post next week).

Thank You for reading.

Kris

Postedby krimakey | 0 Comments    
Filed under:
One-Shot customizations, but we're not VBA.
22 April 08 02:45 PM

Last week I had the pleasure of getting some very interesting feedback from some of the Microsoft Office development audience (people who develop against office through VSTO/VSTA/VBA/Shared Add-ins/etc ).  If you were at said event and are now reading here because of it, I welcome you and hope you enjoy the time you spend.

One of the more interesting things of note I heard was that VSTO just wasn't as easy and simple to deploy for those one-shot customizations that might be created to solve a small problem, save some time or simply just do something repetitious quicker.

Certainly this is entirely true under the older Security model, CASPOL is not something you just "simply do" and move on, it takes a fairly significant degree of initial investment and understanding of .NET to get to the "working" state.  Click-Once can also seem like it's a little too heavy-weight for a similar reason, there's all this extra stuff to consider:  prerequisites, updating, a publishing location, certificates. 

This is why I'm going to talk about the "tricks" you can use for that simple once-off git 'er done solution.  These methods are supported they are not considered our prime scenarios used in this particular context.

First Let's talk about publishing versus building.  If you are creating a customized document, you might consider bypassing publishing, although if you're creating application level customization (something that will impact multiple documents) then I fully recommend publishing even for these quick and dirty solutions.  There are still some things you can do to make things simple and quick with the publishing experience in add-ins.  I will come back to add-ins and publishing after I cover documents.

Documents!

What the Developer needs to do:

  1. Copy (or email) the entire contents of the bin/release folder over to the "user", Zipping the folder is perfectly acceptable.
  2. Inform your user about the "Trust Prompt" (see below)
  3. Inform your user about that moving the document around without moving the customization files can cause the customization to stop working.

What your user needs to do:

  1. Keep folder contents together (document must be in the same folder as .vsto, .dll.manifest and .dll file)
  2. Click the "Install" prompt when the document is opened.  (This is just asking for Trust)VSTOLocalTrustPrompt
    (note:  The right part of image just shows "vstolocal" the user doesn't need to be aware it)
  3. "Un-install" can be achieved by deleting the document and customization files, though you should know that it does leave the trust decision behind (a single registry key).

Incremental improvements towards more "professional" level solutions that you can do:

  1. (Developer Action) Acquire a proper (verifiable by Certificate Authority) code-signing Certificate from a well-known Trusted Root Authority and Sign you manifests with it instead of using VS generated Self-Certificates.  This changes the information in the "Trust Prompt" from 'unknown publisher" to "<YourName on certificate>":
    CertificatePage
  2. Have your user install your "proper" certificate into their trusted publisher list. By having your user trust you as a publisher, they will no longer be prompted to install the solutions you sign with your certificate.
    1. (Developer Action) Export your Signing Certificate without the Private key (I use Certmgr.msc in windows vista here in this example)
      CertMgr
    2. (Developer Action) Send your public-key-containing exported certificate file to your Customer. 
    3. (User Action) Double-click the Certificate file to start the install process.
    4. (User Action) Click "Install Certificate"
    5. (User Action) Select "Place all certificates in the following store" and Choose "Trusted Publishers"
  3. Re-Customize the Document to look for the manifest file in a specific location.  If you do this, then the document can be moved around but the .vsto/.dll.manifest/.dll files must stay in one (specific) location.  You can do this with Office my manually editing the custom properties as shown in this image:
    ReCustomizeDoc

Add-ins.

Inherently there is a more work to do since you need to somehow "hook-up" the add-in to the hosting (Office) application.  Fortunately for you, we've thought through this scenario.  Here are the steps to the quickest "simple" setup.

What the developer needs to do:

  1. Set the Publish Location to "publish", this will put the final add-in files in the project/publish folder.
  2. Set the Updates to Never, because you will not be providing and update framework.
  3. Click Publish
    NeverUpdate
  4. Copy the publish folder contents to a zip folder or disk.
  5. Inform your user about the "Trust Prompt" (see document example).
  6. Inform your user that they must un-install using Add-Remove Programs, but can delete the "setup" files after installation.

What the user needs to do:

  1. Run Setup.exe (if you think they may not have the .NET runtime or VSTO Runtime) OR you can have them double-click the vsto file from their end (CD,un-zip folder, etc)
  2. Click the "Install" prompt when it comes up.
  3. Use Add-Remove-Programs if they need to un-install.

Incremental improvements towards more "professional" level solutions that you can do:

  1. (Developer Action) Acquire a "proper" code-signing Certificate from a well-known Trusted Root Authority  and Sign you manifests with it instead.  This changes the information in the "Trust Prompt" from 'unknown publisher" to "<YourName on certificate>" (See the document example of this)
  2. (User Action) Install your "proper" certificate into their trusted publisher list. By having your user trust you as a publisher, they will no longer be prompted to install the solutions you sign with your certificate.  (See the document example of this)
  3. (Developer Action) Deploy the Add-in via CD and as long as it is run from the same drive as the original install on that computer, updates can be achieved in the same manner as a "normal" install.

These are the easiest 2 "throw-away" solution deployment methods that I can think of.  There are so many advantages to using VSTO you shouldn't feel blocked by the belief that deployment must always be Click-Once with large amounts of infrastructure.  There are ways to wrangle it to manage scenarios beyond the initial "deploy via server and provide constant updates" model that Click-Once specifically targets well.

With that I'll wrap this up with a final side-note.  I wrote the bulk of this post a week early because next week I will be on a boat most likely not thinking about anything other than having fun and looking at scenery.  I may or may not have a post due to this trip, but it's possible I might have just enough of a backlog to work something out.

Thank You for Reading.

Kris

 

[note:  Edited 5-19-2008, Attempting to clarify what is done by user versus developer]

Postedby krimakey | 0 Comments    
Filed under: ,
Click-Once forced updates in VSTO II: A fuller solution
18 April 08 02:00 PM

 

Last Week I talked about user-generated updates and the Click-Once Deployment Management API's.  Based on some internal feedback and a large degree of personal interest, I'm going to come right back around to the same topic, but with a cleaner solution that does the whole kit and caboodle and does it nicely.  While certainly I have put a lot more investigation into this method, the disclaimer still stands. 

This scenario is not fully tested and strictly speaking is not supported.

That said, here are the features I am implementing:

A customized document that...

  • Checks to see if there is and update on the Server
  • Reports the Current Version
  • Reports the Version on the Server
  • Specifies the Click-Once Cache Path (for debugging purposes, I needed to verify information)
  • Specifies the Document Path (for debugging purposes I needed to see the string result, you'll see why later)
  • Updates the Solution "on demand"
  • Restarts the Application and Re-Opens the Document to ensure the most recently installed update is being executed.
  • Maintains a certain degree of "safety" around debugging (occasionally I forget and hit F5).

So there's the list, pretty lengthy, but I wanted to be clear about what my goals were.  I spent about 6 or so hours working through this, mostly because I wanted to do something a little more robust then my usual fare.  As a result I ran into some issues that are worth noting:

In last week's example, the solution I used I was deploying to a local UNC share; in this example I deploy to a local path.  One of the more "interesting" results was that I ended up dealing with paths that had spaces in it.  This is particularly interesting because... application arguments are split on the space character.  The basic lesson here should be:  If you are dealing with paths in a scenario like this it is probably better to use URI's and enforce absolute URI's so you don't have some of the issues that come from special characters.

I also had to spend to much time determining what using statements I needed to enable the API enabling trust code.  As a result, I will post those statements:

using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Deployment.Application;

Finally:  Reporting is important, I generally use Message Box because I'm lazy and don't want to write real error-handling code for these investigations.  What I'm finding though is the more complicated stuff I write, the more information I end up packing into the messages to aid in debugging.  I fully recommend if you do any these things out in the wild you ensure you're using really good reporting tools.  The more information you can shove into logging when things go wrong, the more likely you'll be able to figure out what happens.  This is particularly important when you do stuff like spinning out separate processes to do things, those processes are particularly hard to capture during debugging so verbose reporting is likely to save you a lot of time.

That said, let's get back to the actual project, or actually in this case 2 projects.  Last week I mentioned the need of restarting the customization after the update finishes.  I don't personally know of any inherent support for doing so, but that doesn't make it impossible to do.  It is possible there is a better way, but this is what I came up with based upon a week of mulling it over while also being very very busy.  This solution achieves the restart by shipping a executable that handles the re-opening the document.  I call this this tool "Word Restarter" because amazingly enough it restarts word.

Word Restarter

What I did was create a Managed Console app, and then set it to be a Windows Application.  This creates a program that runs very lightweight with no UI (at least not any that I don't explicitly supply) that I can now pass just enough information to be very useful.

Here's the code for this console app:

//used in exception cases and debugging.
foreach (string s in args)
    argAsString = argAsString + "[" + s + "]"; 

try
{
    
    //Missing is used because C# does not have optional parameters
    Object missing = System.Type.Missing;

    //Check to see if any existing Word Processes exist
    System.Diagnostics.Process[] currentWordProcesses = 
        System.Diagnostics.Process.GetProcessesByName("WINWORD");

    //Empty Case gets ignored, lazy but effective enough
    foreach (System.Diagnostics.Process p in currentWordProcesses) p.WaitForExit();

    //Could be more, but I'm being restrictive because I want to 
    //make sure it fails quickly
    if (args.Length != 1) throw new Exception("You must Specify a full path to a" + 
      " valid Word Document to use this program.");

    string path = args[0] as string;

    //Path Doesn't handle URI's.
    //if (System.IO.Path.IsPathRooted(path) == false)
    //    throw new Exception("You must Specify a full path to a " +
    //    "valid Word Document to use this program.");

    Word.ApplicationClass wordApp = new Microsoft.Office.Interop.Word.ApplicationClass();
    wordApp.Visible = true;

    //cast the path to an object (Office PIA's operate on Objects)
    object docpath = (object)path;
    wordApp.Documents.Open(ref docpath, ref missing, ref missing,
                           ref missing, ref missing, ref missing,
                           ref missing, ref missing, ref missing,
                           ref missing, ref missing, ref missing,
                           ref missing, ref missing, ref missing,
                           ref missing);
}
catch (Exception e)
{
    System.Windows.Forms.MessageBox.Show(
        "The following Exception Occured " +
        "when trying to restart the Word Process: " + 
        e.Message + "\n\n Stack: \n" + e.StackTrace + 
        "Args("+args.Length+"): \n" + argAsString);
}

It could certainly be better, it's not super robust, but it should be just enough to give you an idea on what is necessary to accomplish the task.  There are some pretty serious flaws in this specific implementation, I am basically assuming that all Word Processes will go away, but the code I call in the customization does not explicitly close-all documents.  It's possible to kill all version of the word process but.  I leave it to you to think  about this further I just want to point out that this still isn't production quality.

Once I was fairly confident I had this working I built a retail build of this exe and moved on to the document.

Self Updating Doc

Really this should be "User Updating Document" but it doesn't really matter too much, it's a name.   Anyway, this project is fairly simple and is very similar to the one I created last week.  The key piece of this project is, I'm only using one method to update the document, but I'm doing it in the way I felt last week would be ideal.

So here are some (path obfuscated) images of the Document in action:

"Initial" Run:

UpdatingDoc

Published a "new" update and then Clicked "Check For Update".  The document was still running from the Desktop this entire time:

UpdatingDocAfterCheck

Clicked Update, watched Word disappear (clicking through my debugging information dialogs) and finally word comes back up with:

UpdatingDocAfterUpdate

While I do obscure the paths for security reasons, I did want to point out that the Cache Path changes.  This is particularly of note because it should help explain why an update can happen while the customization is still executing.  That said, I haven't spent a lot of time investigating the data caching behavior that occurs, so make sure you fully test any side-by-side / error conditions / resource handling scenarios that might occur if you decide to implement this in production code.

So what does the code look like?

Well...during start-up I setup the trust so I can access Click-Once API features.  I would recommend isolating these calls to those times this functionality is called by the user to simply reduce the work that happens during startup, but in my case startup time is effective enough.  Then I check some initial values and fill the information in the labels:

if(ApplicationDeployment.IsNetworkDeployed)
{
    Assembly addinAssembly= Assembly.GetExecutingAssembly();
    CachePath = addinAssembly.CodeBase.Substring(0, addinAssembly.CodeBase.Length - 
        System.IO.Path.GetFileName(addinAssembly.CodeBase).Length);

    CurrentDep = ApplicationDeployment.CurrentDeployment;
    string deploymentFullName = CurrentDep.UpdatedApplicationFullName;
    ApplicationIdentity appID = new ApplicationIdentity(deploymentFullName);
    PermissionSet everything = new PermissionSet(PermissionState.Unrestricted);

    ApplicationTrust trust = new ApplicationTrust(appID);
    trust.DefaultGrantSet = new PolicyStatement(everything);
    trust.IsApplicationTrustedToRun = true;
    trust.Persist = true;

    ApplicationSecurityManager.UserApplicationTrusts.Add(trust);

}

Here's the "Helper" Function I call after setting the trust statement to check the deployment location.

private void CheckForUpdate()
{
    if (ApplicationDeployment.IsNetworkDeployed)
    {

        if (CurrentDep.CheckForUpdate())
        {
            UpdateCheckInfo updateInfo = CurrentDep.CheckForDetailedUpdate();
            ClickOnceVersion = updateInfo.AvailableVersion;
        }
        else
        {
            ClickOnceVersion = CurrentDep.CurrentVersion;
        }

        label1.Text = "Current Version: " + CurrentDep.CurrentVersion.ToString();
        label2.Text = "Deployed Version: " + ClickOnceVersion.ToString();
        label3.Text = "CachePath = " + CachePath;
        label4.Text = "DocumentPath = " + Globals.ThisDocument.Path + 
            "\\" + Globals.ThisDocument.Name;

    }
    else
    {
        string notClickOnce = "This Customization is not ClickOnce Installed.";

        label1.Text = "Current Version: " + notClickOnce;
        label2.Text = "Deployed Version: " + notClickOnce;
        label3.Text = "CachePath = " + notClickOnce;
        label4.Text = "DocumentPath = " + notClickOnce;
    }
}

In "real" Solution I would just have a single button that you click to check for the update and that proceed to download the update only if the version is a new version (You simply need to call "CheckForUpdate" unless you want to report Version info).  In the case of my document, I just call the CheckForUpdate helper function when the Check for Update button as way of helping me validate the state appropriately.

And Finally the updating code:

if (ApplicationDeployment.IsNetworkDeployed)
{

    Uri DocPath = new Uri(Globals.ThisDocument.Path + "\\" + Globals.ThisDocument.Name);
    Uri InstallerPath = new Uri("C:\\Program Files\\Common Files\\microsoft shared\\VSTO\\9.0\\VSTOINSTALLER.exe");
    Uri RestarterPath = new Uri(CachePath + "WordRestarter.exe");
    Uri Updatelocation = new Uri(CurrentDep.UpdateLocation.ToString());

    DialogResult dResult = MessageBox.Show(
        "Are you sure you want to continue?\n" +
        "Updating will require a Restart of Word,\n" +
        "Cancel now or forever hold your peace",
        "Update Requested", MessageBoxButtons.OKCancel);

    if (DialogResult.OK == dResult)
    {
        //Call VSTOInstaller Explicitely in "Silent Mode"
        Process VstoInstallerProc = new System.Diagnostics.Process();
        VstoInstallerProc.StartInfo.Arguments = " /S /I " + Updatelocation.AbsoluteUri;
        VstoInstallerProc.StartInfo.FileName = InstallerPath.AbsoluteUri;
        VstoInstallerProc.Start();

        //Call VSTOInstaller Explicitely in "Silent Mode"
        Process RestarterProc = new System.Diagnostics.Process();
        RestarterProc.StartInfo.Arguments = DocPath.AbsoluteUri;
        RestarterProc.StartInfo.FileName = RestarterPath.AbsoluteUri;
        RestarterProc.Start();

        VstoInstallerProc.WaitForExit();
        if (VstoInstallerProc.ExitCode == 0)
            MessageBox.Show("Update was succesfull, restarting..");
        else
            MessageBox.Show("Update failed: Exit Code (" + VstoInstallerProc.ExitCode.ToString() + ")");

        object save = (object)false;
        this.Application.Quit(ref save, ref missing, ref missing);
    }
}

Ideally you would determine the Installer Path using Environment Variables or some other more robust method, I just wanted to get this working so I've hard-coded the path.  You'll notice that I am using the Uri class here to handle the paths, this turns out to be a much more robust method for ensuring the paths are well-formed when you pass them off to the Process Class.

Let's go back to the WordRestarter for a second.  You'll notice that I'm using reflection to figure out the location of the cache and then subsequently using that path to get to the executable.  You're probably wondering how it got into the cache.  To put it simply, I shipped it as part of the Click-Once package.  To do this I added the executable file as a content file that is always copied.  Here's what it looks like in VS:

UpdatingDocRestarterVSSettings

If you are worried about the security implication of using this method, I want to point out a couple of very relevant facts:

  • The executable hash is injected into the Click-Once Deployment Manifest.
  • Tampering of the Executable on the server would cause the update to be rejected.
  • The manifest is signed with a Certificate that helps guarantee that the user trusts either the specific publisher or the user trusts the specific solution at a specific location. 

With that I'm going to finish this particular post (that's 2 long ones in 2 weeks). 

Thank You for reading.

Kris

Postedby krimakey | 0 Comments    
Filed under: , ,
Click-Once forced updates in VSTO: Some things we don't recommend using, that you might consider anyway.
10 April 08 02:17 PM

Before I go any further in this post I'm going to put a huge disclaimer: 

You should be warned what I'm about to cover has not been fully tested, is clearly not supported or recommended and may have significant impact on your application's ability to work.  Additionally there is no guarantee that we will support these scenarios or methods in future versions or patches.  The scenarios I cover are to answer specific questions and should be considered an academic exercise in how VSTO behaves.  Your mileage may vary.

Okay so disclaimer said,  I'm going to talk about is something you can do with a win-forms Click-Once application that you might try to do in VSTO (albeit with some large caveats).  The basic scenario is this:  You develop a customization that periodically checks for updates which contains a button that the user can "force" an update check with.  Click Once provides an API for this that works very well, and you can use this same API with VSTO though you travel from the realm of "it works and we've fully tested it" into the realm of "it might work but will very likely 'break' you anyway".

So lets' get to the point, in previous posts I've mentioned that you can reference System.Deployment and with a little work get access to the "CurrentDeployment" object.  I've used this in the past to demonstrate how to detect if your customization is running from local disk or from the Click-Once Cache.  We're going to use the same API, but now we're going to "force" an update check and install it.  The second method is going to use our friend the "VSTO Installer" executable that ships as part of the VSTO Runtime 3.0.  

Here's an example of a customized document in which I have create that demonstrates both methods:

Forced Updating Doc example ImageI've dropped some Controls onto this document to demonstrate 2 basic scenarios and additional options for the first scenario.

The basic flow is this, the user clicks the button and the 2 labels beneath it will give some information about the update/version.  The first label will display the current running version and the second will display the version after it the update has run.  As you can see in the example image the version is the same.  I show this now to demonstrate the next point I'm about to make.

When the customer updates the solution in this manner (either through the API or via VSTO Installer) the current running version will not change.  To fully update to the new version the running version of the customization would have to be shut down and the new version loaded up.  Currently neither Office or VSTO have support for doing this at the moment.  I imagine there are ways to do this but I'll leave that for a later time.

So let's talk a little more about the API itself.  I'm going to cover it first because I personally feel it's not the best solution for several reasons and then I'll move to what I feel is in a better direction. 

The first issue that comes up is a matter of trust.  In order to use the API to update the customization the developer needs to grant specific permissions to the code in the Click-Once Cache.  My understanding based on the feedback from the developer who provided me with the trust code that this is a case where the differences between the Click-Once Trust Model and the VSTO Trust Model differ.  What happens under the hood here is this:  ultimately in VSTO the VSTO Runtime is what determines the trust for the Addin.  When it creates the Add-in it evaluates everything against the VSTO trust model and (given the Add-in is actually trusted) executes the Add-in code under full trust.  Since the trust is evaluated and stored by the VSTO Runtime the Add-in must set the trust/permissions for the code in the Click-Once cache in order to execute the update, but it is able to do this since VSTO Add-ins always run under the "Full-Trust" Context. 

So here's the the trust code for enabling the API:

//Create the appropriate Trust settings so the Application can do 
//Click-Once Related updating

ApplicationDeployment CurrentDep = ApplicationDeployment.CurrentDeployment;
String deploymentFullName = CurrentDep.UpdatedApplicationFullName;
ApplicationIdentity appID = new ApplicationIdentity(deploymentFullName);
PermissionSet everything = new PermissionSet(PermissionState.Unrestricted);

ApplicationTrust trust = new ApplicationTrust(appID);
trust.DefaultGrantSet = new PolicyStatement(everything);
trust.IsApplicationTrustedToRun = true;
trust.Persist = true;

ApplicationSecurityManager.UserApplicationTrusts.Add(trust);
 

The reason why I would not use the API for updating is that there are steps that the VSTO runtime must do as a result of the add-in existing within an Add-in Model versus a Stand-alone Executable Model.  Essentially the add-in model is a little more complex than a "standard" Click-Once scenario since not only does the execution code have to be moved onto the user's machine, but also there is a chunk of meta-data that needs to be communicated to the Host-Application for the Customization so that the host process can properly plug-in the customization.

What this turns out to mean is: when the update is done using the API, not every part involved in the customizatoin is correctly updated.  The behavior that I see when I tried this scenario is that the ApplicationDeployment object behaves strangely after the update occurred.  My initial investigation indicates that the solution information store is out of date after the update which then causes the customization to be running in an unexpected context. 

I won't show you the code for updating because I can't personally recommend it for your application.  What you might do though is use CurrentDeployment.CheckForDetailedUpdate() which will tell you if an update is available at least.

Anyway.

Let's move on to using VSTOInstaller...

In a previous post I talked about VSTOInstaller, but as a quick rehash, basically it's an thin executable that uses the same functionality in the runtime to update/install the customization.  What it means in this scenario is that we can use System.Diagnostic.Process to call it and force an update.  In the example code that I'm going to post I call it in 2 ways to demonstrate 2 alternative methods to consider.

In the first method you call VSTOInstaller directly (and silently).  The advantage in using this method is that the user does not see any UI.  The VSTOInstaller will return a negative value if the "update" failed.  Unfortunately the return value of 0 is the only "positive" value you will get back and it is not informative of whether or not an update occurred or if the current version is up to date.

Here's the Code for using VSTOInstaller Directly:

label1.Text = "Current Version: " + 
    ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString();

//Call VSTOInstaller Explicitely in "Silent Mode"
string installerArgs = " /S /I \\\\GenericServer\\WordDocument2.vsto";
string installerPath = "C:\\Program Files\\Common Files\\microsoft shared\\VSTO\\9.0\\VSTOINSTALLER.exe";

System.Diagnostics.Process VstoInstallerProc = new System.Diagnostics.Process();
VstoInstallerProc.StartInfo.Arguments = installerArgs;
VstoInstallerProc.StartInfo.FileName = installerPath;
VstoInstallerProc.Start();

VstoInstallerProc.WaitForExit();
//Report Exit Code
MessageBox.Show("Exit Code: " + VstoInstallerProc.ExitCode.ToString());                  
//End "Silent Mode" Scenario  

If you want UI the easier method is to simply "shell out" the path to the .vsto file.  Doing so would invoke the mime handler which under the covers calls VSTOInstaller.  This method is less likely to fall prey to issues that come of running on future versions of the runtime(not that I'm saying we support you doing this exactly and I'm not going to go into specifics currently).  The UI will inform the user if the update actually happened or if the version was up-to-date but I don't know what would happen if the path is not available and there may be additional UI that occurs (I have seen specific cases in non-customization managed code where specific security settings on the OS would cause a blocking dialog to occur when the shell handler is invoked in this method).  So your mileage may still vary.

And here's the code for installing using the Shell Handler:

//Call VSTOInstaller Via the Shell (will show UI) assumes the Mime handler works
string manifestPath = "\\\\GenericServer\\WordDocument2.vsto";

System.Diagnostics.Process ExplorerInstallProc = new System.Diagnostics.Process();
ExplorerInstallProc.StartInfo.Arguments = manifestPath;
ExplorerInstallProc.StartInfo.FileName = "explorer.exe";
ExplorerInstallProc.Start();

label2.Text = "\"NEW\" Current Version: " + 
    ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString();            

Here are some items to keep in mind if you are considering this at all:

  • VSTO Installer is less likely to put you in bad state then calling the API's directly.
  • Cached Data (in the Click-Once Data Cache) may be impacted (I would recommend thorough  testing/investigation).
  • You might consider shelling out a process that 'sleeps' until the Office app is closed and then causes the Update.
  • You might consider forcing a restart of the office application after the update occurred.
  • Warn your users that they may want to save their data before you start the update process.
  • Thoroughly Test anything before fully integrating it into any solutions.  Make sure you try it under extreme security situations (IE Protected mode on while running as a normal user).

If you do end up using any of this or have come up with a better solution, feel free to comment, I love open discussion about this stuff.

Thank You for reading.

Kris Makey

Postedby krimakey | 2 Comments    
Filed under: , ,
Late but live!
31 March 08 02:30 PM

I was planning to post something about 3 days ago but things have been a little crazy on the home front (lets just say that 'the games' have been playing me these days) and a lot crazy on the work front (can't talk about it exactly, but it's been good busy mostly). 

I have no VSTO tips today, sorry.

However I had a chance to receive some general advice on blogging, display styles etc.  So this should almost be "See What I See Version 2-beta".  On recommendation I've installed Windows Live Writer, and to be honest so far it has been a pretty okay experience.  I had a lot of trouble connecting up the piping initially but it seems to be more of a factor of bits-in-the-piping issues (restrictive network settings) than anything wrong with the software.  Firewalls can be tricky things sometimes. 

Anyway, I got everything up and running and with a bit of customization I can now paste "nice" code instead of the ugly black boring notepad code I have been pasting in the past.  An example:  here's some "C++" "Code" that I _may_ have written recently to do a bit of a "refresher" since it's been almost 2 years since I've done anything serious with C++.    Oh how the time flies and the tools rust.

// MyCppIsRusty.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Widget.h"

int _tmain(int argc, _TCHAR* argv[])
{
    int result = (int)*argv[1];
    printf("The Result is: %i \n", result);

    RustRemoval::Widget *Foo = new RustRemoval::Widget();
    result = Foo->SomeFunction(result);
    printf("The result after manipulation is: %i \n", result);

    return 0;
}

Yes that is real code, it  doesn't do anything interesting and has bugs, I was exploring building static library building and the actual content didn't matter so long as I was getting results from code that wasn't in the project itself.  I do have to say though, going back to C++ after being spoiled by C# for so long, There are some things that .NET just does better.  Building multi-component software using dll's is nicer.  In .NET there are no header files I have to copy around, if you want to use my dll, simply create a reference to it and everything is golden.

One last thing, Here's a random picture to see what Live Writer can do:

kris2

If you can see the image, then Live Writer gets 2 thumbs and a pinky up from me.

As always Thank You for reading,

K.

Postedby krimakey | 0 Comments    
Filed under: ,
VSTO 3.0 and .NET 3.5
21 March 08 02:26 AM

From time to time I will come across (via various channels) a question of why VSTO 3.0 requires the 3.5 framework.  Usually these questions are prefaced or suffixed with a “in VSTO 2005 SE I was able to use 2.0, why are you making me use 3.5 now?”

Just to clarify, when I talk about VSTO 3.0 I mean only the addins that are build in VS 2008 and are labelled "Office 2007".   Office 2003 addins in VS 2008 are essentially the same as addins build in VSTO 2005 SE (which can be loaded in both 2003 and 2007).

The answer is both short and long and simple and complicated.  The short and simple answer is that VSTO 3.0 requires .Net 3.5.  If I left it at that I imagine I would get a lot more questions so I’ll go into the long answer:

In the VS 2008 timeframe we rebuilt the loading model for VSTO.  This new loading model consists of 2 major parts, the first being that the VSTO runtime now uses the System.Addin Framework.  You can read about the System.Addin framework here: http://msdn2.microsoft.com/en-us/library/bb384200.aspx.  I don’t know as much about this, but I’m told that it is a good thing all around. 

The second major part, the one that I do know about is around “deployment” (ClickOnce).  In VS 2008 we integrated the ClickOnce model of trust, installation and loading into the Runtime.  The benefits have been that the model is much easier to use for the end user.   The associated cost has been that in order to integrate this functionality properly, additional changes to the ClickOnce framework had to be made (some of which is only a part of the 3.5 framework).  These changes not only include publishing and installation but it includes the basic security model that the VSTO runtime uses.

So even if you don’t use ClickOnce with VSTO 3.0 solutions, the runtime itself relies on functionality that exists only within the 3.5 framework.   Hopefully that clarifies the reasoning behind why we require the 3.5 framework.  

Until next time, thank you for reading.

Postedby krimakey | 0 Comments    
Filed under: ,
If memory serves me correctly...
08 March 08 04:43 AM

Memory is king and he who remembers the most rules will rule the most (not a real quote but it sounds interesting).  Anyway, it is very easy to create "widget" apps with VSTO that "do" something, but often where the really interesting projects come into play is when the app can "do" something and then save state.  Sometimes state can be minor feature like keeping the previous values used in a control or something large like storing associations and actions to allow data manipulation. 

In this post I'm only going to cover an example of lightweight state caching and I will leave it up to you to imagine some of the more interesting scenarios this can be applied to.  So in this little project I'm working on I have a drop down control on Ribbon Control of a Customized Document.  This control contains a list of "Emotive States" that I might want to associate with blocks of text.  In typical lazy fashion I could just set the initial on startup and not worry about it from moment to moment but lets say I know that likely the user of the document is most likely going to use one state more often than the others.  As a nice "micro-feature" I want to save the state between instances of opening the document.  Because this state is more of a "program state" rather then "document state" ideally I will want to store the state with customization and not with the document itself.

So lets consider some of the Data features in VSTO:

Manually created Data Files out to disk on the user's machine but there is a lot of work around things like "where" and potentially permissions issues that might come up.  Ideally I don't want to have to think about these things myself.

Binding to a Database seems like overkill.  Really all I want is to know what the last stored value for the current user is, I don't want to have to have them deal with databases, etc.

Custom XML in the document is a possible option but this is better for saving state specific to the document rather than things like control settings.  Also this feature takes a lot of work to really understand how to hook into the Office Files nicely so I'm not really going to use this approach this time.

VSTO Data Store is also associated with the Document and really is a much nice way of achieving the same results of Custom XML without the pain of the Office object model so while a possibility I still am going to bypass this feature also.

ClickOnce Data Directory is the feature that I really want to use.  I can associate Data with the customization code rather than a specific instance of the document.  This gives me a nicely protected User space for allowing user specific settings and data. 

Okay so that seemed a little forced even to me...basically if you want to store things like application settings and users settings, I think this is the route to take since it provides a "safe" method for producing files and it eliminates a lot of the details of file management that might have to otherwise be create by the developer (or myself in this case).

So lets talk about the ClickOnce Data Directory.  Basically it is a folder "somewhere" that code executing under the user's credentials can write to.  Additionally since the data folder is managed by ClickOnce, the headache of worrying about things like "un-installation" are simply not something you have to worry about.  The data directory is obfuscated just like any other part of the cache.  If you add a reference to System.Deployment you can use the ClickOnce API to access the Data Directory.

VSTO supports using the data directory but currently in VS 2008 there isn't any UI around it specifically.  If you have much experience with Window Forms you may know that you can set many files as data files.  You may can do the same with VSTO but you would have to do so manually in the manifest files (and then you would have to re-sign them).  By default though if you include an xml file (must be of the .xml extension) we assume it is a data file and should be copied into the Data Directory on installation.  In VS you must set the xml file as a content file that is always copied. Once you have done this step you're already well on your way to having application data settings.

So let us assume you've created an XML settings files, something that might just contain a root node like: <data></data> 

The first thing you will want to do is hook it up using the deployment API's and open the file to show you can in fact access the data file.  Unfortunately if you do this and hook up to the API then hit F5, you will get an exception.  The reason is fairly straight forward, until you install the solution into the Cache it isn't a "real" ClickOnce Solution and there isn't a data directory to get to.  So here's a code example on how to hook up to the API such that the data directory is used when the solution is "installed" into the cache and simply expects the file to be side-by-side with the customization dll when it is run in the "local" (|vstolocal) context. If you wrap any calls to the data files in this way you should be able to F5 your solution, create an MSI installer or use ClickOnce without changing the code.

So here's the code i used in my project:

[code]

private EmotiveState LoadEmotiveState()
{
  string xmlfile = "";
  XDocument CachedDoc;

  if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
     xmlfile = System.Deployment.Application.ApplicationDeployment.CurrentDeployment.DataDirectory + "\\EmoTesterSettings.xml";
  else
     xmlfile = ".\\EmoTesterSettings.xml";

  CachedDoc = XDocument.Load(xmlfile);
  XAttribute Oldstate = CachedDoc.Root.Attribute("EmotiveState");

  if (Oldstate == null)
     return EmotiveState.Neutral;
  else
     return EmotiveStateHelper.EmotiveStateFromString(Oldstate.Value);
}

private void SaveEmotiveState(EmotiveState state)
{
  string xmlfile = "";
  XDocument CachedDoc;
  XAttribute Oldstate;
  XAttribute NewState = new XAttribute("EmotiveState", state.ToString());
 
 if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
    xmlfile = System.Deployment.Application.ApplicationDeployment.CurrentDeployment.DataDirectory + "\\EmoTesterSettings.xml";
 else
    xmlfile = ".\\EmoTesterSettings.xml";

 CachedDoc = XDocument.Load(xmlfile);
 Oldstate = CachedDoc.Root.Attribute(NewState.Name);

 if (Oldstate == null)
    CachedDoc.Root.Add(NewState);
 else
    Oldstate.Value = NewState.Value;

 CachedDoc.Save(xmlfile);

}

[code]

As you can see, by keying off the "isNetworkDeployed" property I can choose to use the Data directory or (in the case of F5) the bin folder the dll's are in.

In my example above you can see that I expect there to be a root node, in this case the file contains <data></data>.  After running the solution the xml looks something like: <data EmotiveState="Happy"></data>.  There is no reason why the files have to be published and installed before the first run, it is possible to add files to the directory, but if you do want to have default settings, using a pre-built data file instead of hard-coded values is a much better way to implement it.

So with that said there are some caveats about the Data Directory.  If the solution is rolled back the data may or may not be preserved, generally if you store stuff in the data directory it is important to be aware that you shouldn't be putting mission critical information in it.  If the user takes an update (usually) the data they have stored into the data directory is kept which means you also have to consider backwards compatibility.  Unfortunately I don't know for certain if there is a reliable way to flush the data directory outside of un-installing the solution, I haven't had time to investigate it yet. Certainly there is a lot more documentation on this feature on MSDN under the general ClickOnce stuff and I fully recommend doing a little more investigation before diving any deeper than I have.

Thank You for reading.

Kris

Postedby krimakey | 0 Comments    
Filed under: , ,
More Posts Next page »

This Blog

Syndication

Page view tracker