Upgrading Custom Projects
If you change the information persisted in the project file between different Visual Studio versions of your product, then you need to support upgrading your project file from the old to the new version. To support upgrading that allows you to participate in the Visual Studio Conversion Wizard, implement the IVsProjectUpgradeViaFactory interface. This interface contains the only mechanism available for copy upgrading. The upgrading of the project happens as a part of the solution opens. The IVsProjectUpgradeViaFactory interface is implemented by the project factory, or should at least be obtainable from the project factory.
The old mechanism that uses the IVsProjectUpgrade interface is still supported, but conceptually upgrades the project system as a part of the project open. The IVsProjectUpgrade interface is therefore called by the Visual Studio environment even if the IVsProjectUpgradeViaFactory interface is called or implemented. This approach allows you to use IVsProjectUpgradeViaFactory to implement the copy and project only portions of the upgrade, and delegate the rest of the work to be done in-place (possibly at the new location) by the IVsProjectUpgrade interface.
For a sample implementation of IVsProjectUpgrade, see VSSDK Samples.
The following scenarios arise with project upgrades:
If the file is of a newer format than the project can support, then it must return an error stating this. This assumes that the older version of your product — for example, Visual Studio .NET 2003 — includes code to check for the version.
If the __VSPPROJECTUPGRADEVIAFACTORYFLAGS flag is specified in the UpgradeProject method, the upgrade is going to be implemented as an in-place upgrade prior to the opening of the project.
If the __VSPPROJECTUPGRADEVIAFACTORYFLAGS flag is specified in the UpgradeProject method, the upgrade is implemented as a copy upgrade.
If the __VSUPGRADEPROJFLAGS flag is specified in the UpgradeProject call, then the user has been prompted by the environment to upgrade the project file as an in-place upgrade, after the project is opened. For example, the environment prompts the user to upgrade when the user opens an older version of the solution.
If the __VSUPGRADEPROJFLAGS flag is not specified in the UpgradeProject call, then you must prompt the user to upgrade the project file.
The following is an example upgrade prompt message:
"The project '%1' was created with an older version of Visual Studio. If you open it with this version of Visual Studio, you may not be able to open it with older versions of Visual Studio. Do you want to continue and open this project?"
To implement IVsProjectUpgradeViaFactory
Implement the method of the IVsProjectUpgradeViaFactory interface, specifically the UpgradeProject method in your project factory implementation, or make the implementations callable from your project factory implementation.
If you want to do an in-place upgrade as a part of the solution opening, supply the flag __VSPPROJECTUPGRADEVIAFACTORYFLAGS as the
VSPUVF_FLAGS
parameter in your UpgradeProject implementation.If you want to do an in-place upgrade as a part of the solution opening, supply the flag __VSPPROJECTUPGRADEVIAFACTORYFLAGS as the
VSPUVF_FLAGS
parameter in your UpgradeProject implementation.For both the steps 2 and 3, the actual file upgrade steps, using IVsQueryEditQuerySave2, can be implemented as described in the "Implementing
IVsProjectUpgade
" section below, or you can delegate the actual file upgrade to IVsProjectUpgrade.Use the methods of IVsUpgradeLogger to post upgrade related messages for the user using Visual Studio Migration Wizard.
IVsFileUpgrade interface is used to implement any kind of file upgrade that needs to happen as part of project upgrade. This interface is not called from IVsProjectUpgradeViaFactory, but is supplied as a mechanism to upgrade files that are part of the project system, but the main project system might not be directly aware of. For example, this situation could arise if the compiler related files and properties are not handled by the same development team that handles the rest of the project system.
IVsProjectUpgrade Implementation
If your project system implements IVsProjectUpgrade only, it can not participate in the Visual Studio Conversion Wizard. However, even if you implement the IVsProjectUpgradeViaFactory interface, you can still delegate the file upgrade to IVsProjectUpgrade implementation.
To implement IVsProjectUpgrade
When a user attempts to open a project, the UpgradeProject method is called by the environment after the project is opened and before any other user action can be taken on the project. If the user had already been prompted to upgrade the solution, then the __VSUPGRADEPROJFLAGS flag is passed in the
grfUpgradeFlags
parameter. If the user opens a project directly, such as by using the Add Existing Project command, then the __VSUPGRADEPROJFLAGS flag is not passed and the project needs to prompt the user to upgrade.In response to the UpgradeProject call, the project must evaluate whether the project file is upgraded. If the project does not need to upgrade the project type to a new version, then it can simply return the S_OK flag.
If the project needs to upgrade the project type to a new version, then it must determine whether the project file can be modified by calling the QueryEditFiles method and passing in a value of tagVSQueryEditFlags for the
rgfQueryEdit
parameter. The project then needs to do the following:If the
VSQueryEditResult
value returned in thepfEditCanceled
parameter is tagVSQueryEditResult, then the upgrade can proceed because the project file can be written.If the
VSQueryEditResult
value returned in thepfEditCanceled
parameter is tagVSQueryEditResult and theVSQueryEditResult
value has the tagVSQueryEditResultFlags bit set, then UpgradeProject must return failure, because users should resolve the permissions issue themselves. The project should then do the following:Report the error to the user by calling ReportErrorInfo. and return the VSErrorCodes error code to IVsProjectUpgrade.
If the
VSQueryEditResult
value is tagVSQueryEditResult and theVSQueryEditResultFlags
value has the tagVSQueryEditResultFlags bit set, then the project file should be checked out by calling QueryEditFiles (tagVSQueryEditFlags, tagVSQueryEditFlags,...).
If the QueryEditFiles call on the project file causes the file to be checked out, and the latest version to be retrieved, then the project is unloaded and reloaded. The UpgradeProject method is called again once another instance of the project is created. On this second call, the project file can be written to disk; it is recommended that the project save a copy of the project file in the previous format with an .OLD extension, make its necessary upgrade changes, and save the project file in the new format. Again, if any part of the upgrade process fails, the method must indicate failure by returning VSErrorCodes. This causes the project to be unloaded in Solution Explorer.
It is important to understand the complete process that occurs in the environment for the case in which the call to the QueryEditFiles method (specifying a value of ReportOnly) returns the tagVSQueryEditResult and the tagVSQueryEditResultFlags flags.
The user attempts to open the project file.
The environment calls your CanCreateProject implementation.
If CanCreateProject returns
true
, then the environment calls your CanCreateProject implementation.The environment calls your Load implementation to open the file and initialize the project object, for example, Project1.
The environment calls your
IVsProjectUpgrade::UpgradeProject
implementation to determine whether the project file needs to be upgraded.You call QueryEditFiles and pass in a value of tagVSQueryEditFlags for the
rgfQueryEdit
parameter.The environment returns tagVSQueryEditResult for
VSQueryEditResult
and the tagVSQueryEditResultFlags bit is set inVSQueryEditResultFlags
.Your IVsProjectUpgrade implementation calls
IVsQueryEditQuerySave::QueryEditFiles
(tagVSQueryEditFlags, tagVSQueryEditFlags).This call may cause a new copy of your project file to be checked out and the latest version retrieved, as well as a need to reload your project file. At this point, one of two things happen:
If you handle your own project reload, then the environment calls your ReloadItem (VSITEMID_ROOT) implementation. When you receive this call, reload the first instance of your project (Project1) and continue upgrading your project file. The environment knows that you handle your own project reload if you return
true
for GetProperty (__VSHPROPID).If you do not handle your own project reload, then you return
false
for GetProperty (__VSHPROPID). In this case, before QueryEditFiles(QEF_ForceEdit_NoPrompting, QEF_DisallowInMemoryEdits,) returns, the environment creates another new, instance of your project, for example, Project2, as follows:The environment calls Close on your first project object, Project1, thus placing this object in the inactive state.
The environment calls your
IVsProjectFactory::CreateProject
implementation to create a second instance of your project, Project2.The environment calls your
IPersistFileFormat::Load
implementation to open the file and initialize the second project object, Project2.The environment calls
IVsProjectUpgrade::UpgradeProject
for a second time to determine whether the project object should be upgraded. However, this call is made on a new, second, instance of the project, Project2. This is the project that is opened in the solution.Note
In the instance that your first project, Project1, is placed in the inactive state, then you must return S_OK from the first call to your UpgradeProject implementation. See Basic Project for an implementation of
IVsProjectUpgrade::UpgradeProject
.You call QueryEditFiles and pass in a value of tagVSQueryEditFlags for the
rgfQueryEdit
parameter.The environment returns tagVSQueryEditResult and the upgrade can proceed because the project file can be written.
If you fail to upgrade, return VSErrorCodes from
IVsProjectUpgrade::UpgradeProject
. If no upgrade is necessary or you choose not to upgrade, treat theIVsProjectUpgrade::UpgradeProject
call as a no-op. If you return VSErrorCodes, a placeholder node is added to the solution for your project.
See Also
Visual Studio Conversion Wizard
Upgrading Project Items
Projects