/// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.SetInnerProject"]/*' /> /// <devdoc> /// This is were all QI for interface on the inner object should happen /// Then set the inner project /// wait for InitializeForOuter to be called to do the real initialization /// </devdoc> protected virtual void SetInnerProject(IntPtr innerIUnknown) { object inner = null; inner = Marshal.GetObjectForIUnknown(innerIUnknown); // Keep a reference to each interface we want to call on the inner project // we must do it now as once we call SetInner the AddRef would be forwarded to ourselves _innerVsAggregatableProject = inner as IVsAggregatableProjectCorrected; Debug.Assert(inner != null, "Failed to retrieve IVsAggregatableProjectCorrected from inner Project"); _innerVsHierarchy = (IVsHierarchy)inner; _innerVsUIHierarchy = (IVsUIHierarchy)inner; // "As" should return null without throwing in the event the base project does not implement the interface _innerOleCommandTarget = inner as IOleCommandTarget; // Setup our menu command service if (this.serviceProvider == null) { throw new NotSupportedException("serviceProvider should have been set before SetInnerProject gets called."); } _menuService = new OleMenuCommandService(this, _innerOleCommandTarget); // Pass the inner project pointer to the VisualStudio.ProjectAggregator2 object. This native object // has a special implementation of QueryInterface that delegates first to our managed FlavoredProjectBase // derived object and then to the inner project (either the base project or the next project flavor down). IntPtr thisIUnknown = IntPtr.Zero; IVsProjectAggregator2 vsProjectAggregator2 = null; try { thisIUnknown = Marshal.GetIUnknownForObject(this); vsProjectAggregator2 = (IVsProjectAggregator2)Marshal.GetObjectForIUnknown(thisIUnknown); if (vsProjectAggregator2 != null) { vsProjectAggregator2.SetInner(innerIUnknown); } } finally { if (thisIUnknown != IntPtr.Zero) { Marshal.Release(thisIUnknown); } } }
int IVsAggregatableProjectFactoryCorrected.PreCreateForOuter(IntPtr outerProjectIUnknown, out IntPtr projectIUnknown) { projectIUnknown = IntPtr.Zero; // always initialize out parameters of COM interfaces! var newProject = PreCreateForOuter(outerProjectIUnknown); var newProjectIUnknown = IntPtr.Zero; var localRegistry = (ILocalRegistryCorrected)this._serviceProvider.GetService(typeof(SLocalRegistry)); Debug.Assert(localRegistry != null, "Could not get the ILocalRegistry object"); if (localRegistry == null) { throw new InvalidOperationException(); } var clsid = typeof(Microsoft.VisualStudio.ProjectAggregator.CProjectAggregatorClass).GUID; var riid = VSConstants.IID_IUnknown; var dwClsCtx = (uint)CLSCTX.CLSCTX_INPROC_SERVER; var aggregateProjectIUnknown = IntPtr.Zero; IVsProjectAggregator2 vsProjectAggregator2 = null; try { ErrorHandler.ThrowOnFailure(localRegistry.CreateInstance(clsid, outerProjectIUnknown, ref riid, dwClsCtx, out aggregateProjectIUnknown)); // If we have a non-NULL punkOuter then we need to create a COM aggregated object with that punkOuter, // if not then we are the top of the aggregation. if (outerProjectIUnknown != IntPtr.Zero) { newProjectIUnknown = Marshal.CreateAggregatedObject(outerProjectIUnknown, newProject); } else { newProjectIUnknown = Marshal.CreateAggregatedObject(aggregateProjectIUnknown, newProject);; } vsProjectAggregator2 = (IVsProjectAggregator2)Marshal.GetObjectForIUnknown(aggregateProjectIUnknown); if (vsProjectAggregator2 != null) { vsProjectAggregator2.SetMyProject(newProjectIUnknown); } // We return the native ProjectAggregator COM object as the project created by our project // factory. This ProjectAggregator main purpose is to manage the fact that the punkInner pointer // for the project aggregation is not known until after IVsAggregateProject::SetInnerProject is // called. This native object has a special implementation of QueryInterface that can handle // the SetInnerProject mechanism. The ProjectAggregator will first delegate QueryInterface // calls to our managed project and then delegates to the inner Project. // Note: we need to return an AddRef'ed IUnknown (AddRef comes from CreateInstance call). projectIUnknown = aggregateProjectIUnknown; aggregateProjectIUnknown = IntPtr.Zero; } finally { if (newProjectIUnknown != IntPtr.Zero) { Marshal.Release(newProjectIUnknown); } if (aggregateProjectIUnknown != IntPtr.Zero) { Marshal.Release(aggregateProjectIUnknown); } } if (projectIUnknown == IntPtr.Zero) { return(VSConstants.E_FAIL); } return(VSConstants.S_OK); }