プロジェクトのアップグレード

あるバージョンの Visual Studio から次のバージョンへのプロジェクト モデルの変更では、新しいバージョンで実行できるようにプロジェクトとソリューションをアップグレードする必要がある場合があります。 Visual Studio SDK には、独自のプロジェクトでアップグレード サポートを実装するために使用できるインターフェイスが用意されています。

アップグレード戦略

アップグレードをサポートするには、プロジェクト システムの実装でアップグレード戦略を定義して実装する必要があります。 戦略を決定する際に、サイド バイ サイド (SxS) バックアップ、コピー バックアップ、またはその両方をサポートすることを選択できます。

  • SxS バックアップとは、アップグレードが必要なファイルのみをコピーし、適切なファイル名サフィックス ("old" など) を追加することを意味します。

  • バックアップのコピーとは、プロジェクトがユーザー指定のバックアップ場所にすべてのプロジェクト項目をコピーすることを意味します。 その後、元のプロジェクトの場所にある関連ファイルがアップグレードされます。

アップグレードのしくみ

以前のバージョンの Visual Studio で作成されたソリューションが新しいバージョンで開かれると、IDE はソリューション ファイルをチェックして、アップグレードが必要かどうかを判断します。 アップグレードが必要な場合は、 アップグレード ウィザード が自動的に起動され、アップグレード プロセスがユーザーに表示されます。

ソリューションでアップグレードが必要な場合は、各プロジェクト ファクトリに対してアップグレード戦略のクエリを実行します。 この戦略では、プロジェクト ファクトリがコピー バックアップと SxS バックアップのどちらをサポートしているかを決定します。 この情報は アップグレード ウィザードに送信され、バックアップに必要な情報が収集され、該当するオプションがユーザーに表示されます。

マルチプロジェクト ソリューション

ソリューションに複数のプロジェクトが含まれており、アップグレード戦略が異なる場合 (SxS バックアップのみをサポートする C++ プロジェクトと、コピー バックアップのみをサポートする Web プロジェクトがある場合など)、プロジェクト ファクトリはアップグレード戦略をネゴシエートする必要があります。

ソリューションは、各プロジェクト ファクトリに対して IVsProjectUpgradeViaFactoryのクエリを実行します。 その後、 UpgradeProject_CheckOnly を呼び出して、グローバル プロジェクト ファイルのアップグレードが必要かどうかを確認し、サポートされているアップグレード戦略を決定します。 その後、 アップグレード ウィザード が呼び出されます。

ユーザーがウィザードを完了すると、各プロジェクト ファクトリで UpgradeProject が呼び出され、実際のアップグレードが実行されます。 バックアップを容易にするために、IVsProjectUpgradeViaFactory メソッドは、アップグレード プロセスの詳細をログに記録する SVsUpgradeLogger サービスを提供します。 このサービスはキャッシュできません。

関連するすべてのグローバル ファイルを更新した後、各プロジェクト ファクトリはプロジェクトのインスタンス化を選択できます。 プロジェクトの実装では、 IVsProjectUpgradeをサポートする必要があります。 その後、 UpgradeProject メソッドが呼び出され、関連するすべてのプロジェクト項目がアップグレードされます。

注

UpgradeProject メソッドは、SVsUpgradeLogger サービスを提供しません。 このサービスは、 QueryServiceを呼び出すことによって取得できます。

ベスト プラクティス

SVsQueryEditQuerySave サービスを使用して、ファイルを編集する前に編集できるかどうかを確認し、保存する前に保存できます。 これにより、バックアップとアップグレードの実装では、ソース管理下のプロジェクト ファイル、アクセス許可が不十分なファイルなどを処理できます。

バックアップとアップグレードのすべてのフェーズで SVsUpgradeLogger サービスを使用して、アップグレード プロセスの成功または失敗に関する情報を提供します。

プロジェクトのバックアップとアップグレードの詳細については、vsshell2.idl の IVsProjectUpgrade のコメントを参照してください。

カスタム プロジェクトのアップグレード

製品の異なる Visual Studio バージョン間でプロジェクト ファイルに保存されている情報を変更する場合は、プロジェクト ファイルを古いバージョンから新しいバージョンにアップグレードするサポートが必要です。 Visual Studio 変換ウィザードに参加できるアップグレードをサポートするには、IVsProjectUpgradeViaFactory インターフェイスを実装します。 このインターフェイスには、コピーのアップグレードに使用できる唯一のメカニズムが含まれています。 プロジェクトのアップグレードは、ソリューションの一部が開くと発生します。 IVsProjectUpgradeViaFactory インターフェイスはプロジェクト ファクトリによって実装されるか、少なくともプロジェクト ファクトリから取得できる必要があります。

IVsProjectUpgrade インターフェイスを使用する古いメカニズムは引き続きサポートされていますが、概念的にはプロジェクト システムが開いているプロジェクトの一部としてアップグレードされます。 そのため、 IVsProjectUpgrade インターフェイスは、 IVsProjectUpgradeViaFactory インターフェイスが呼び出されたり実装されたりした場合でも、Visual Studio 環境によって呼び出されます。 このアプローチでは、IVsProjectUpgradeViaFactory を使用してアップグレードの一部であるコピーとプロジェクトを実装し、残りの作業を IVsProjectUpgrade インターフェイスに委任して、その場で(場合によっては新しい場所で)実行させることができます。

IVsProjectUpgradeの実装例については、VSSDK サンプルを参照してください。

プロジェクトのアップグレードでは、次のシナリオが発生します。

  • プロジェクトがサポートできるより新しい形式のファイルの場合は、これを示すエラーを返す必要があります。 これは、製品の古いバージョンにバージョンを確認するコードが含まれていることを前提としています。

  • PUVFF_SXSBACKUP フラグが UpgradeProject メソッドで指定されている場合、アップグレードはプロジェクトを開く前にインプレース アップグレードとして実装されます。

  • PUVFF_COPYBACKUP メソッドで UpgradeProject フラグが指定されている場合、アップグレードはコピー アップグレードとして実装されます。

  • UPF_SILENTMIGRATE呼び出しで UpgradeProject フラグが指定されている場合、ユーザーは、プロジェクトを開いた後、プロジェクト ファイルをインプレース アップグレードとしてアップグレードするように環境から求められます。 たとえば、環境では、ユーザーが古いバージョンのソリューションを開いたときに、ユーザーにアップグレードを求めるメッセージが表示されます。

  • UPF_SILENTMIGRATE呼び出しでUpgradeProject フラグが指定されていない場合は、プロジェクト ファイルをアップグレードするようにユーザーに求める必要があります。

    アップグレード プロンプト メッセージの例を次に示します。

    "プロジェクト '%1' は、以前のバージョンの Visual Studio で作成されました。 このバージョンの Visual Studio で開くと、古いバージョンの Visual Studio で開くことができない場合があります。 このプロジェクトを続行して開いてみませんか?

IVsProjectUpgradeViaFactory を実装するには

  1. IVsProjectUpgradeViaFactory インターフェイスのメソッド 、特にプロジェクト ファクトリの実装で UpgradeProject メソッドを実装するか、プロジェクト ファクトリの実装から実装を呼び出し可能にします。

  2. ソリューションオープンの一部としてインプレース アップグレードを実行する場合は、PUVFF_SXSBACKUP実装のVSPUVF_FLAGS パラメーターとしてフラグ UpgradeProjectを指定します。

  3. ソリューションオープンの一部としてインプレース アップグレードを実行する場合は、PUVFF_COPYBACKUP実装のVSPUVF_FLAGS パラメーターとしてフラグ UpgradeProjectを指定します。

  4. 手順 2 と 3 の両方で、 IVsQueryEditQuerySave2を使用した実際のファイル アップグレード手順は、以下の「 IVsProjectUpgadeの実装」セクションの説明に従って実装することも、実際のファイル アップグレードを IVsProjectUpgradeに委任することもできます。

  5. IVsUpgradeLoggerのメソッドを使用して、Visual Studio 移行ウィザードを使用してユーザーのアップグレード関連メッセージを投稿します。

  6. IVsFileUpgrade インターフェイスは、プロジェクトアップグレードの一環として行う必要があるあらゆる種類のファイルアップグレードを実装するために使用されます。 このインターフェイスは IVsProjectUpgradeViaFactoryから呼び出されませんが、プロジェクト システムの一部であるファイルをアップグレードするためのメカニズムとして提供されますが、メイン プロジェクト システムが直接認識していない可能性があります。 たとえば、この状況は、コンパイラ関連のファイルとプロパティが、プロジェクト システムの残りの部分を処理する同じ開発チームによって処理されない場合に発生する可能性があります。

IVsProjectUpgrade の実装

プロジェクト システムが IVsProjectUpgrade のみを実装している場合、 Visual Studio 変換ウィザードには参加できません。 ただし、 IVsProjectUpgradeViaFactory インターフェイスを実装した場合でも、ファイルのアップグレードを IVsProjectUpgrade 実装に委任できます。

IVsProjectUpgrade を実装するには

  1. ユーザーがプロジェクトを開こうとすると、 UpgradeProject メソッドは、プロジェクトを開いた後、およびプロジェクトに対して他のユーザー アクションを実行する前に、環境によって呼び出されます。 ユーザーが既にソリューションのアップグレードを求められた場合は、 UPF_SILENTMIGRATE フラグが grfUpgradeFlags パラメーターに渡されます。 ユーザーが [既存のプロジェクトの 追加 ] コマンドを使用するなどしてプロジェクトを直接開いた場合、 UPF_SILENTMIGRATE フラグは渡されず、プロジェクトはユーザーにアップグレードを求める必要があります。

  2. UpgradeProject呼び出しに応答して、プロジェクト ファイルがアップグレードされているかどうかを評価する必要があります。 プロジェクトの種類を新しいバージョンにアップグレードする必要がない場合は、 S_OK フラグを返すだけです。

  3. プロジェクトの種類を新しいバージョンにアップグレードする必要がある場合は、QueryEditFiles メソッドを呼び出し、tagVSQueryEditFlags パラメーターにrgfQueryEditの値を渡すことによって、プロジェクト ファイルを変更できるかどうかを判断する必要があります。 その後、プロジェクトで次の操作を行う必要があります。

    • VSQueryEditResult パラメーターで返されるpfEditCanceled値がQER_EditOK場合は、プロジェクト ファイルを書き込むことができるため、アップグレードを続行できます。

    • VSQueryEditResult パラメーターで返されるpfEditCanceled値がQER_EditNotOKされ、VSQueryEditResult値にQER_ReadOnlyNotUnderScc ビットが設定されている場合は、ユーザーがアクセス許可の問題を自分で解決する必要があるため、UpgradeProjectはエラーを返す必要があります。 その後、プロジェクトで次の操作を行う必要があります。

      ReportErrorInfoを呼び出してユーザーにエラーを報告し、VS_E_PROJECTMIGRATIONFAILEDエラー コードをIVsProjectUpgradeに返します。

    • VSQueryEditResult値がQER_EditNotOKされ、VSQueryEditResultFlags値にQER_ReadOnlyUnderScc ビットが設定されている場合は、QueryEditFiles (QEF_ForceEdit_NoPrompting、QEF_DisallowInMemoryEdits,...) を呼び出してプロジェクト ファイルをチェックアウトする必要があります。

  4. プロジェクト ファイルの QueryEditFiles 呼び出しによってファイルがチェックアウトされ、最新バージョンが取得された場合、プロジェクトはアンロードされ、再読み込みされます。 プロジェクトの別のインスタンスが作成されると、 UpgradeProject メソッドが再度呼び出されます。 この 2 回目の呼び出しでは、プロジェクト ファイルをディスクに書き込むことができます。プロジェクトは、前の形式でプロジェクト ファイルのコピーを保存することをお勧めします。OLD 拡張機能を使用して、必要なアップグレードを変更し、プロジェクト ファイルを新しい形式で保存します。 ここでも、アップグレード プロセスのいずれかの部分が失敗した場合、メソッドは VS_E_PROJECTMIGRATIONFAILEDを返すことによってエラーを示す必要があります。 これにより、ソリューション エクスプローラーでプロジェクトがアンロードされます。

    QueryEditFiles メソッドの呼び出し (ReportOnly の値を指定) がQER_EditNotOKフラグとQER_ReadOnlyUnderScc フラグを返す場合に、環境内で発生する完全なプロセスを理解することが重要です。

  5. ユーザーがプロジェクト ファイルを開こうとします。

  6. 環境は、 CanCreateProject 実装を呼び出します。

  7. CanCreateProjectがtrueを返す場合、環境はCanCreateProject実装を呼び出します。

  8. 環境は、 Load 実装を呼び出してファイルを開き、プロジェクト オブジェクト (Project1 など) を初期化します。

  9. 環境は IVsProjectUpgrade::UpgradeProject 実装を呼び出して、プロジェクト ファイルをアップグレードする必要があるかどうかを判断します。

  10. QueryEditFilesを呼び出し、QEF_ReportOnly パラメーターに rgfQueryEdit の値を渡します。

  11. 環境はVSQueryEditResultのQER_EditNotOKを返し、VSQueryEditResultFlagsでQER_ReadOnlyUnderSccビットが設定されます。

  12. IVsProjectUpgrade実装では、IVsQueryEditQuerySave::QueryEditFiles (QEF_ForceEdit_NoPrompting、QEF_DisallowInMemoryEdits) が呼び出されます。

この呼び出しにより、プロジェクト ファイルの新しいコピーがチェックアウトされ、最新バージョンが取得される可能性があります。また、プロジェクト ファイルを再読み込みする必要があります。 この時点で、次の 2 つのいずれかが発生します。

  • 独自のプロジェクトの再読み込みを処理する場合、環境は ReloadItem (VSITEMID_ROOT) 実装を呼び出します。 この呼び出しを受け取ったら、プロジェクトの最初のインスタンス (Project1) を再読み込みし、プロジェクト ファイルのアップグレードを続行します。 環境は、GetProperty (VSHPROPID_HandlesOwnReload) にtrueを返すと、自分のプロジェクトの再読み込みを処理することを認識しています。

  • 自分のプロジェクトの再読み込みを管理しない場合は、GetProperty (VSHPROPID_HandlesOwnReload) に対してfalseを返します。 この場合、 QueryEditFiles(QEF_ForceEdit_NoPrompting、QEF_DisallowInMemoryEdits) が返される前に、次のようにプロジェクトの別の新しいインスタンス (Project2 など) が作成されます。

    1. 環境は、最初のプロジェクト オブジェクト Project1 で Close を呼び出し、このオブジェクトを非アクティブ状態にします。

    2. 環境は、プロジェクト Project2 の 2 番目のインスタンスを作成するために、 IVsProjectFactory::CreateProject 実装を呼び出します。

    3. 環境は、 IPersistFileFormat::Load 実装を呼び出してファイルを開き、2 番目のプロジェクト オブジェクト Project2 を初期化します。

    4. 環境は IVsProjectUpgrade::UpgradeProject をもう一度呼び出して、プロジェクト オブジェクトをアップグレードする必要があるかどうかを判断します。 ただし、この呼び出しは、プロジェクト Project2 の新しい 2 番目のインスタンスで行われます。 これは、ソリューションで開かれるプロジェクトです。

      注

      最初のプロジェクト Project1 が非アクティブな状態になっている場合は、最初の呼び出しからS_OK実装へのUpgradeProjectを返す必要があります。

    5. QueryEditFilesを呼び出し、QEF_ReportOnly パラメーターに rgfQueryEdit の値を渡します。

    6. 環境は QER_EditOK を返し、プロジェクト ファイルを書き込むことができるため、アップグレードを続行できます。

アップグレードに失敗した場合は、VS_E_PROJECTMIGRATIONFAILEDからIVsProjectUpgrade::UpgradeProject返します。 アップグレードが必要ない場合、またはアップグレードしない場合は、 IVsProjectUpgrade::UpgradeProject 呼び出しを no-opとして扱います。 VS_E_PROJECTMIGRATIONFAILEDを返すと、プレースホルダー ノードがプロジェクトのソリューションに追加されます。

プロジェクト項目のアップグレード

実装していないプロジェクト システム内の項目を追加または管理する場合は、プロジェクトのアップグレード プロセスに参加することが必要になる場合があります。 Crystal Reports は、プロジェクト システムに追加できる項目の例です。

通常、プロジェクト項目の実装者は、既に完全にインスタンス化され、アップグレードされたプロジェクトを活用したいと考えています。アップグレードの決定を行うには、プロジェクト参照の内容とその他のプロジェクト プロパティを把握する必要があるためです。

プロジェクトのアップグレード通知を取得するには

  1. プロジェクト項目の実装で SolutionOrProjectUpgrading フラグ (vsshell80.idl で定義) を設定します。 これにより、Visual Studio シェルでプロジェクト システムがアップグレード中であると判断されたときに、プロジェクト項目 VSPackage が自動読み込みされます。

  2. IVsSolutionEventsProjectUpgradeメソッドを使用して、AdviseSolutionEvents インターフェイスにアドバイスします。

  3. IVsSolutionEventsProjectUpgrade インターフェイスは、プロジェクト システムの実装がアップグレード操作を完了し、アップグレードされた新しいプロジェクトが作成された後に発生します。 シナリオに応じて、 IVsSolutionEventsProjectUpgrade インターフェイスは、 OnAfterOpenSolution、 OnAfterOpenProject、または OnAfterLoadProject メソッドの後に起動されます。

プロジェクト項目ファイルをアップグレードするには

  1. プロジェクト項目の実装でファイル バックアップ プロセスを慎重に管理する必要があります。 これは、特に、fUpgradeFlag メソッドのUpgradeProject パラメーターが PUVFF_SXSBACKUP に設定され、バックアップされたファイルが ".old" として指定されたファイルと共に配置されるサイド バイ サイド バックアップに適用されます。 プロジェクトがアップグレードされたシステム時刻より古いバックアップ ファイルは、古いものとして指定できます。 さらに、これを防ぐための特定の手順を実行しない限り、上書きされる可能性があります。

  2. プロジェクト項目がプロジェクトのアップグレードの通知を受け取った時点で、 Visual Studio 変換ウィザード は引き続き表示されます。 そのため、 IVsUpgradeLogger インターフェイスのメソッドを使用して、ウィザード UI にアップグレード メッセージを提供する必要があります。