Providing upgrade support for Project systems targeting Visual Studio 2005

(This article applies strictly to Visual Studio 2005)

Project Upgrade Architecture

The project systems can either choose to support upgrade or not support it at all. If the project system chooses to support upgrade then the project system implementation needs to define/implement an upgrade strategy for it to behave consistently for single and multi project solutions with disparate project types. Most Microsoft projects support upgrade. Projects that support upgrade can choose to either support side-by-side (SxS) or Copy Backup or support both.

What is Copy Backup?

Project systems copy *ALL* the files to a user-provided location. Upgrade the relevant files needing upgrade at the original project location. Backup location is user-specified.

What is Side by Side (SxS) Backup?

Project systems copy *ONLY* those files that need upgrade with a suitable file name suffix like ".old" in the same location as the original project. The key differences between this and Copy Backup is that only the relevant files are backed up (not *ALL*), and the backup location is always the same path as the original project.

 Upgrade Strategy

For solutions containing projects that need upgrade, the following algorithm is used to pick upgrade type. When a solution that contains projects needing upgrade is loaded, each contained project is queried for its upgrade capabilities. Based on the capabilities returned by the project factories, the solution either picks the least common denominator if all the capabilities have common capabilities. In cases where the capabilities are mutually exclusive (for example C++ projects only support SxS and Web projects only support Copy Backup) the choice of picking the right upgrade path is delegated to the project factory. However there is one special case when a Web project is in the solution with a C++ project. Web projects need a backup location. Consequently, the upgrade wizard always provides a backup location in the wizard. However, the location is applicable only to Web projects. The C++ projects are still backed up in the same location as the original project. In these situations the solution passes an ORed value of the distinct upgrade flags to the project factories. Hence the project factory may get passed a combination of VSPUVF_FLAGS that it does not support. Therefore, the project factories should always be wary of the unsupported flags and behave accordingly. The Upgrade process happens in two phases.

The first phase revolves around project factories and adopting an upgrade strategy. The solution queries each project factory for IVsProjectUpgradeViaFactory. It then calls IVsProjectUpgradeViaFactory::UpgradeProject_CheckOnly to see if the project needs upgrade and to determine the supported upgrade strategies. Each project factory should provide appropriate VSPUVF_FLAGS to disclose it’s supported backup strategies. The solution then processes the capabilities returned by each project and presents the upgrade wizard UI compatible with the supported capabilities. The only visible change to the Wizard UI is the backup location choice on the second page of the wizard. After the user clicks Finish on the wizard, IVsProjectUpgradeViaFactory::UpgradeProject is called for each project factory to do the actual upgrade. The project factories determine, based on the flags passed, their preferred upgrade mechanism. For example the C#/VB/J# projects always favor Copy Backup to SxS backup. C++ projects only support SxS backup. In this phase the recommendation is to back up the files as appropriate and upgrade the project file only leaving the project item upgrade for the second phase. However this is not a requirement. To participate in the upgrade log you can use the Upgrade logging service, SVsUpgradeLogger. During this phase of upgrade the service interface is handed to you by IVsProjectUpgradeViaFactory methods. The logging service is available only while the upgrade process lasts. Attempting to cache and reuse this service later might have unpredictable behavior and hence should never be done.

The second pass happens after the project factory has been created and the project has been instantiated. The project implementation needs to support IVsProjectUpgrade. The project is queried for this interface and IVsProjectUpgrade::UpgradeProject implementation is called. This call happens after the project is opened but before any action by a user can be taken on the project. This is the time when you can upgrade the project items. It also provides a second chance to apply further changes to the project itself. However modifying the project file is purely optional. If the project or the project items have no need to upgrade, it can simply return S_OK. One thing to note is that when shell calls UpgradeProject, it does not pass you the Upgrade logging service as it did in the first phase. However, the service is still queriable and can be obtained by a call to QueryService.

In both the phases, as a best practice the implementation should never assume the state of file(s) that it can potentially modify. It is advisable that you use the SVsQueryEditQuerySave service to determine if you can edit the file before editing it and to determine if you can save it before you save it. This will help your project systems deal appropriately with situations when the project files are under source control or do not have appropriate permissions, and so on. Pseudo code for this appears below:

  • Query if you can edit the file
  • If true then Edit the file
  • Query if you can save the file
  • If true then save the file.

You can also refer to comments for IVsProjectUpgrade in vsshell2.idl.

Thanks

Dr. eX