Initialization Sequence of Project Subtypes
The environment constructs a project by calling the base project factory implementation of CreateProject. The construction of a project subtype starts when the environment determines that the project type GUID list for a project file's extension is not empty. The project file extension and project GUID specify whether the project is a Visual Basic or Visual C# project type. For example, the .vbproj extension and {F184B08F-C81C-45F6-A57F-5ABD9991F28F} identify a Visual Basic project.
Environment's Initialization of Project Subtypes
The following procedure details the initialization sequence for a project system aggregated by multiple project subtypes.
The environment calls the base project's CreateProject, and while the project parses its project file it discovers that the aggregate project type GUIDs list is not
null
. The project discontinues directly creating its project.The project calls
QueryService
on SVsCreateAggregateProject service to create a project subtype using the environment's implementation of the CreateAggregateProject method. Within this method the environment makes recursive function calls to your implementations of PreCreateForOuter, SetInnerProject and InitializeForOuter methods while it is walking the list of project type GUIDs, starting with the outermost project subtype.The following details the initialization steps.
The environment's implementation of the CreateAggregateProject method calls the
HrCreateInnerProj
method with the following function declaration:<CodeContentPlaceHolder>0
When this function is called for the first time, that is, for the outermost project subtype, the parameters
pOuter
andpOwner
are passed in asnull
and the function sets the outermost project subtypeIUnknown
topOuter
.Next the environment calls
HrCreateInnerProj
function with the second project type GUID in the list. This GUID corresponds to the second inner project subtype stepping in toward the base project in the aggregation sequence.The
pOuter
is now pointing to theIUnknown
of the outermost project subtype, andHrCreateInnerProj
calls your implementation of PreCreateForOuter followed by a call to your implementation of SetInnerProject. In PreCreateForOuter method you pass in the controllingIUnknown
of the outermost project subtype,pOuter
. The owned project (inner project subtype) needs to create its aggregate project object here. In the SetInnerProject method implementation you pass in a pointer to theIUnknown
of the inner project that is being aggregated. These two methods create the aggregation object, and your implementations need to follow COM aggregation rules to ensure that a project subtype does not end up holding a reference count to itself.HrCreateInnerProj
calls your implementation of PreCreateForOuter. In this method, the project subtype does its initialization work. You can, for example, register solution events in InitializeForOuter.HrCreateInnerProj
is called recursively until the last GUID (the base project) in the list is reached. For each of these calls, the steps, c through d, are repeated.pOuter
points to the outermost project subtypeIUnknown
for each level of aggregation.
Example
The following example details the programmatic process in an approximate representation of the CreateAggregateProject method as it is implemented by the environment. The code is just an example; it is not intended to be compiled, and all error checking was removed for clarity.
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);
}