プロジェクト サブタイプの初期化シーケンス
環境では、CreateProject の基本プロジェクト ファクトリ実装を呼び出すことによってプロジェクトを構築します。 プロジェクト サブタイプの構築は、プロジェクト ファイルの拡張子のプロジェクト タイプ GUID の一覧が空ではないと環境によって判断された時点で開始します。 プロジェクト ファイル拡張子とプロジェクト GUID により、プロジェクトが Visual Basic と Visual C# のどちらのプロジェクト タイプであるかが指定されます。 たとえば、.vbproj 拡張子と {F184B08F-C81C-45F6-A57F-5ABD9991F28F} では Visual Basic プロジェクトが識別されます。
環境でのプロジェクト サブタイプの初期化
次の手順では、複数のプロジェクト サブタイプによって集約されたプロジェクト システムの初期化シーケンスについて詳しく説明します。
環境で基本プロジェクトの CreateProject が呼び出され、プロジェクトでそのプロジェクト ファイルを解析している間、集約プロジェクト タイプの GUID リストが
null
ではないことが環境によって検出されます。 プロジェクトでは、そのプロジェクトの直接作成を中止します。プロジェクトでは SVsCreateAggregateProject サービスに対して
QueryService
を呼び出し、環境での CreateAggregateProject メソッドの実装を使用してプロジェクト サブタイプを作成します。 このメソッド内では、環境によって、最も外側のプロジェクト サブタイプを起点に、プロジェクト タイプ GUID のリストを順次処理しつつ、PreCreateForOuter、SetInnerProject、InitializeForOuter の各メソッドの実装に対して再帰的な関数呼び出しを行います。以下、初期化手順の詳細を示します。
環境での CreateAggregateProject メソッドの実装により、次の関数宣言を使用して
HrCreateInnerProj
メソッドが呼び出されます。<CodeContentPlaceHolder>0
この関数の最初の (つまり、最も外側のプロジェクト サブタイプに対する) 呼び出し時に、パラメーター
pOuter
とpOwner
がnull
として渡され、関数は最も外側のプロジェクト サブタイプIUnknown
をpOuter
に設定します。次に、環境によって、リスト内の 2 番目のプロジェクト タイプ GUID を使用して
HrCreateInnerProj
関数が呼び出されます。 この GUID は、集約シーケンスで基本プロジェクトに向かってステップインする、内側から 2 番目のプロジェクト サブタイプに対応します。この時点で、
pOuter
は最も外側のプロジェクト サブタイプのIUnknown
を指しており、HrCreateInnerProj
は PreCreateForOuter の実装を呼び出し、続いて SetInnerProject の実装を呼び出します。 PreCreateForOuter メソッドでは、最も外側のプロジェクト サブタイプpOuter
の制御側IUnknown
を渡します。 被所有プロジェクト (内側のプロジェクト サブタイプ) では、集約プロジェクト オブジェクトをここに作成する必要があります。 SetInnerProject メソッドの実装では、集約中である内側のプロジェクトのIUnknown
へのポインターを渡します。 これらの 2 つのメソッドは集計オブジェクトを作成します。実装では、COM の集約ルールに従って、プロジェクト サブタイプが自分自身への参照カウントを保持する結果にならないようにする必要があります。HrCreateInnerProj
は PreCreateForOuter の実装を呼び出します。 このメソッドでは、プロジェクト サブタイプがその初期化処理を行います。 たとえば、InitializeForOuter でソリューション イベントを登録できます。HrCreateInnerProj
は、リスト内の最後の GUID (基本プロジェクト) に到達するまで再帰的に呼び出されます。 これらの呼び出しごとに、c から d までの手順が繰り返されます。pOuter
は、集約の各レベルの最も外側のプロジェクト サブタイプIUnknown
を指します。
例
次の例は、プログラムによるプロセスを、CreateAggregateProject メソッドが環境によって実装される場合の近似表現で詳しく示しています。 このコードは単なる例です。コンパイルは想定されておらず、わかりやすくするためにすべてのエラー チェックを省いています。
HRESULT CreateAggregateProject
(
LPCOLESTR lpstrGuids,
LPCOLESTR pszFilename,
LPCOLESTR pszLocation,
LPCOLESTR pszName,
VSCREATEPROJFLAGS grfCreateFlags,
REFIID iidProject,
void **ppvProject)
{
HRESULT hr = NOERROR;
CComPtr<IUnknown> srpunkProj;
CComPtr<IVsAggregatableProject> srpAggProject;
CComBSTR bstrGuids = lpstrGuids;
BOOL fCanceled = FALSE;
*ppvProject = NULL;
HrCreateInnerProj(
bstrGuids, NULL, NULL, pszFilename, pszLocation,
pszName, grfCreateFlags, &srpunkProj, &fCanceled);
srpunkProj->QueryInterface(
IID_IVsAggregatableProject, (void **)&srpAggProject));
srpAggProject->OnAggregationComplete();
srpunkProj->QueryInterface(iidProject, ppvProject);
}
HRESULT HrCreateInnerProj
(
WCHAR *pwszGuids,
IUnknown *pOuter,
IVsAggregatableProject *pOwner,
LPCOLESTR pszFilename,
LPCOLESTR pszLocation,
LPCOLESTR pszName,
VSCREATEPROJFLAGS grfCreateFlags,
IUnknown **ppInner,
BOOL *pfCanceled
)
{
HRESULT hr = NOERROR;
CComPtr<IUnknown> srpInner;
CComPtr<IVsAggregatableProject> srpAggInner;
CComPtr<IVsProjectFactory> srpProjectFactory;
CComPtr<IVsAggregatableProjectFactory> srpAggPF;
GUID guid = GUID_NULL;
WCHAR *pwszNextGuids = wcschr(pwszGuids, L';');
WCHAR wszText[_MAX_PATH+150] = L"";
if (pwszNextGuids)
{
*pwszNextGuids++ = 0;
}
CLSIDFromString(pwszGuids, &guid);
GetProjectTypeMgr()->HrGetProjectFactoryOfGuid(
guid, &srpProjectFactory);
srpProjectFactory->QueryInterface(
IID_IVsAggregatableProjectFactory,
(void **)&srpAggPF);
srpAggPF->PreCreateForOuter(pOuter, &srpInner);
srpInner->QueryInterface(
IID_IVsAggregatableProject, (void **)&srpAggInner);
if (pOwner)
{
IfFailGo(pOwner->SetInnerProject(srpInner));
}
if (pwszNextGuids)
{
CComPtr<IUnknown> srpNextInner;
HrCreateInnerProj(
pwszNextGuids, pOuter ? pOuter : srpInner,
srpAggInner, pszFilename, pszLocation, pszName,
grfCreateFlags, &srpNextInner, pfCanceled);
}
return srpAggInner->InitializeForOuter(
pszFilename, pszLocation, pszName, grfCreateFlags,
IID_IUnknown, (void **)ppInner, pfCanceled);
}