项目子类型的初始化序列

环境通过调用基础项目工厂实现 CreateProject来构造项目。 当环境确定项目文件扩展名的项目类型 GUID 列表不是空时,项目子类型的构造将开始。 项目文件扩展名和项目 GUID 指定项目是 Visual Basic 还是 Visual C# 项目类型。 例如,.vbproj 扩展和 {F184B08F-C81C-45F6-A57F-5ABD9991F28F} 标识 Visual Basic 项目。

项目子类型的环境初始化

以下过程详细介绍了由多个项目子类型聚合的项目系统的初始化序列。

  1. 环境调用基本项目 CreateProject,当项目分析其项目文件时,它发现聚合项目类型 GUID 列表不是 null。 该项目停止直接创建其项目。

  2. 项目调用QueryServiceSVsCreateAggregateProject服务,以使用环境的方法实现CreateAggregateProject创建项目子类型。 在此方法中,环境对实现PreCreateForOuterInitializeForOuter方法进行递归函数调用,SetInnerProject同时它正在走项目类型 GUID 列表,从最外部的项目子类型开始。

    下面详细介绍了初始化步骤。

    1. 方法的环境 CreateAggregateProject 实现使用以下函数声明调用 HrCreateInnerProj 该方法:

      <CodeContentPlaceHolder>0

      首次调用此函数时,即,对于最外层的项目子类型,参数pOuter并作为传入null,函数将最外层的项目子类型IUnknown设置为 pOuterpOwner

    2. 接下来,环境调用 HrCreateInnerProj 具有列表中的第二个项目类型 GUID 的函数。 此 GUID 对应于聚合序列中第二个内部项目子类型单步执行到基本项目。

    3. 现在,它 pOuter 指向 IUnknown 最外部的项目子类型,并 HrCreateInnerProj 调用你的实现 PreCreateForOuter ,然后调用对实现的 SetInnerProject调用。 在PreCreateForOuter方法中,传入最外层项目子类型的控制IUnknownpOuter 拥有的项目(内部项目子类型)需要在此处创建其聚合项目对象。 在方法实现中 SetInnerProject ,将指针传递给正在聚合的内部项目的指针 IUnknown 。 这两种方法创建聚合对象,实现需要遵循 COM 聚合规则,以确保项目子类型最终不会将引用计数保留给自身。

    4. HrCreateInnerProj调用你的实现。PreCreateForOuter 在此方法中,项目子类型执行其初始化工作。 例如,可以在 . 中 InitializeForOuter注册解决方案事件。

    5. 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);
}