added some development tools
[windows-sources.git] / developer / VSSDK / VisualStudioIntegration / Common / Source / CSharp / Shell100 / Flavor / FlavoredProjectBase.cs
bloba96b42cddee77db6e224e7e713fa90e292797d08
1 /***************************************************************************
3 Copyright (c) Microsoft Corporation. All rights reserved.
4 This code is licensed under the Visual Studio SDK license terms.
5 THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
6 ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
7 IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
8 PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
10 ***************************************************************************/
12 namespace Microsoft.VisualStudio.Shell.Flavor
14 using System;
15 using System.Diagnostics;
16 using System.Diagnostics.CodeAnalysis;
17 using System.Globalization;
18 using System.Runtime.InteropServices;
19 using Microsoft.VisualStudio.Shell.Interop;
20 using Microsoft.VisualStudio.OLE.Interop;
21 using Microsoft.VisualStudio.Shell;
22 using ErrorHandler = Microsoft.VisualStudio.ErrorHandler;
24 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject"]/*' />
25 /// <devdoc>
26 /// A project that is a subtype/flavor of an inner project.
27 /// The default behavior of all methods is to delegate to the
28 /// inner project. For any behavior you want to change, simply
29 /// handle the request yourself.
30 /// </devdoc>
31 [CLSCompliant(false)]
32 public abstract class FlavoredProjectBase :
33 IVsAggregatableProjectCorrected,
34 System.IServiceProvider,
35 IVsHierarchy,
36 IVsUIHierarchy,
37 IOleCommandTarget
39 // Keep interface reference for all interface we override
41 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject._innerVsAggregatableProject"]/*' />
42 protected IVsAggregatableProjectCorrected _innerVsAggregatableProject;
43 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject._innerVsHierarchy"]/*' />
44 protected IVsHierarchy _innerVsHierarchy;
45 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject._innerVsUIHierarchy"]/*' />
46 protected IVsUIHierarchy _innerVsUIHierarchy;
47 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject._innerOleCommandTarget"]/*' />
48 protected IOleCommandTarget _innerOleCommandTarget;
50 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.serviceProvider"]/*' />
51 protected System.IServiceProvider serviceProvider;
53 private OleMenuCommandService _menuService;
54 private DocumentsEventsSink _documentsEventsSink;
55 private bool _hierarchyClosed = false;
56 private int _inExecCommand = 0;
58 uint cookie = 0;
60 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.FlavoredProject"]/*' />
61 public FlavoredProjectBase()
63 _documentsEventsSink = new FlavoredProjectBase.DocumentsEventsSink(this);
66 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.GetComInterface"]/*' />
67 /// <devdoc>
68 /// A project derived from this base class will be aggregated with a native COM component (the ProjectAggregator object)
69 /// that can also aggregate an inner project in case of flavoring.
70 /// Because of this structure, all the request for interfaces exposed to COM must be handled by the external object that
71 /// has a special implementation of QueryInterface that handles both inner and outer projects.
72 /// If you don’t use this helper method when requesting an interface you can get unexpected InvalidCast exceptions.
73 /// Note that if you want to get the implementation of an interface implemented by your FlavoredProjectBase-derived
74 /// object, then you must use the standard cast operator.
75 /// </devdoc>
76 public Interface_T GetComInterface<Interface_T>() where Interface_T : class
78 IntPtr thisUnknown = IntPtr.Zero;
79 IntPtr interfacePtr = IntPtr.Zero;
80 try
82 thisUnknown = Marshal.GetIUnknownForObject(this);
83 Guid iid = typeof(Interface_T).GUID;
84 if (ErrorHandler.Failed(Marshal.QueryInterface(thisUnknown, ref iid, out interfacePtr)) || (IntPtr.Zero == interfacePtr))
86 return null;
88 return Marshal.GetObjectForIUnknown(interfacePtr) as Interface_T;
90 finally
92 if (IntPtr.Zero != thisUnknown)
94 Marshal.Release(thisUnknown);
96 if (IntPtr.Zero != interfacePtr)
98 Marshal.Release(interfacePtr);
103 #region IVsAggregatableProjectCorrected
105 /// <devdoc>
106 /// This is where all QI for interface on the inner object should happen
107 /// Then set the inner project
108 /// wait for InitializeForOuter to be called to do the real initialization
109 /// </devdoc>
110 int IVsAggregatableProjectCorrected.SetInnerProject(IntPtr innerIUnknown)
112 // delegate to the protected method
113 this.SetInnerProject(innerIUnknown);
115 return VSConstants.S_OK;
118 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.SetInnerProject"]/*' />
119 /// <devdoc>
120 /// This is were all QI for interface on the inner object should happen
121 /// Then set the inner project
122 /// wait for InitializeForOuter to be called to do the real initialization
123 /// </devdoc>
124 protected virtual void SetInnerProject(IntPtr innerIUnknown)
126 object inner = null;
128 inner = Marshal.GetObjectForIUnknown(innerIUnknown);
130 // Keep a reference to each interface we want to call on the inner project
131 // we must do it now as once we call SetInner the AddRef would be forwarded to ourselves
132 _innerVsAggregatableProject = inner as IVsAggregatableProjectCorrected;
133 Debug.Assert(inner != null, "Failed to retrieve IVsAggregatableProjectCorrected from inner Project");
134 _innerVsHierarchy = (IVsHierarchy)inner;
135 _innerVsUIHierarchy = (IVsUIHierarchy)inner;
136 // "As" should return null without throwing in the event the base project does not implement the interface
137 _innerOleCommandTarget = inner as IOleCommandTarget;
139 // Setup our menu command service
140 if (this.serviceProvider == null)
141 throw new NotSupportedException("serviceProvider should have been set before SetInnerProject gets called.");
142 _menuService = new OleMenuCommandService(this, _innerOleCommandTarget);
144 // Pass the inner project pointer to the VisualStudio.ProjectAggregator2 object. This native object
145 // has a special implementation of QueryInterface that delegates first to our managed FlavoredProjectBase
146 // derived object and then to the inner project (either the base project or the next project flavor down).
147 IntPtr thisIUnknown = IntPtr.Zero;
148 IVsProjectAggregator2 vsProjectAggregator2 = null;
151 thisIUnknown = Marshal.GetIUnknownForObject(this);
152 vsProjectAggregator2 = (IVsProjectAggregator2)Marshal.GetObjectForIUnknown(thisIUnknown);
153 if (vsProjectAggregator2 != null)
154 vsProjectAggregator2.SetInner(innerIUnknown);
156 finally
158 if (thisIUnknown != IntPtr.Zero)
159 Marshal.Release(thisIUnknown);
163 /// <devdoc>
164 /// Do the initialization here (such as loading flavor specific
165 /// information from the project)
166 /// </devdoc>
167 int IVsAggregatableProjectCorrected.InitializeForOuter(string fileName, string location, string name,
168 uint flags, ref Guid guidProject, out IntPtr project, out int canceled)
170 int hr = VSConstants.S_OK;
171 project = IntPtr.Zero;
172 canceled = 0;
174 if (_innerVsAggregatableProject == null || guidProject != VSConstants.IID_IUnknown)
175 throw new NotSupportedException();
177 IntPtr thisIUnknown = IntPtr.Zero;
180 thisIUnknown = Marshal.GetIUnknownForObject(this);
181 if (thisIUnknown != IntPtr.Zero)
182 hr = Marshal.QueryInterface(thisIUnknown, ref guidProject, out project);
184 finally
186 if (thisIUnknown != IntPtr.Zero)
187 Marshal.Release(thisIUnknown);
190 bool cancel;
191 this.InitializeForOuter(fileName, location, name, flags, ref guidProject, out cancel);
192 if (cancel)
193 canceled = 1;
195 return hr;
198 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.InitializeForOuter"]/*' />
199 /// <devdoc>
200 /// Allow the project to initialize itself.
201 /// At this point it possible to call the inner project
202 /// Also allow canceling the project creation
203 /// </devdoc>
204 /// <returns>Return true to cancel the project creation</returns>
205 protected virtual void InitializeForOuter(string fileName, string location, string name, uint flags, ref Guid guidProject, out bool cancel)
207 cancel = false;
209 /// <devdoc>
210 /// This is called when all object in aggregation have received InitializeForOuter calls.
211 /// At this point the aggregation is complete and fully functional.
212 /// </devdoc>
213 int IVsAggregatableProjectCorrected.OnAggregationComplete()
215 this.OnAggregationComplete();
216 if (_innerVsAggregatableProject != null)
217 return _innerVsAggregatableProject.OnAggregationComplete();
218 return VSConstants.S_OK;
221 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.OnAggregationComplete"]/*' />
222 /// <devdoc>
223 /// This is called when all object in aggregation have received InitializeForOuter calls.
224 /// At this point the aggregation is complete and fully functional.
225 /// </devdoc>
226 protected virtual void OnAggregationComplete()
228 // This will subscribe to the IVsTrackProjectDocumentsEvents.
229 // This is not required to flavor a project but makes it easier for derived class
230 // to subscribe to these events.
231 IVsTrackProjectDocuments2 trackDocuments = GetTrackProjectDocuments();
232 ErrorHandler.ThrowOnFailure(trackDocuments.AdviseTrackProjectDocumentsEvents(_documentsEventsSink, out cookie));
235 /// <devdoc>
236 /// This must be delegetated to the inner most project
237 /// </devdoc>
238 int IVsAggregatableProjectCorrected.SetAggregateProjectTypeGuids(string projectTypeGuids)
240 if (_innerVsAggregatableProject == null)
241 throw new NotSupportedException();
243 return _innerVsAggregatableProject.SetAggregateProjectTypeGuids(projectTypeGuids);
246 /// <devdoc>
247 /// This must be delegetated to the inner most project
248 /// </devdoc>
249 int IVsAggregatableProjectCorrected.GetAggregateProjectTypeGuids(out string projectTypeGuids)
251 if (_innerVsAggregatableProject == null)
252 throw new NotSupportedException();
254 return _innerVsAggregatableProject.GetAggregateProjectTypeGuids(out projectTypeGuids);
257 #endregion
259 #region IVsHierarchy
261 // Most methods call protected virtual methods which delegate to the inner project.
262 // Derived classes should override those protected method if they want to change the
263 // behavior.
266 int IVsHierarchy.AdviseHierarchyEvents(Microsoft.VisualStudio.Shell.Interop.IVsHierarchyEvents eventSink, out uint cookie)
268 cookie = this.AdviseHierarchyEvents(eventSink);
269 return VSConstants.S_OK;
272 int IVsHierarchy.Close()
274 _hierarchyClosed = true;
275 this.Close();
277 if (cookie != 0)
279 // Unsubscribe to events
280 IVsTrackProjectDocuments2 trackDocuments = GetTrackProjectDocuments();
281 trackDocuments.UnadviseTrackProjectDocumentsEvents(cookie);
282 cookie = 0;
285 if (this._menuService != null)
287 OleMenuCommandService tempService = this._menuService;
288 this._menuService = null;
289 tempService.Dispose();
292 if (_inExecCommand == 0)
293 FreeInterfaces();
295 return VSConstants.S_OK;
298 public virtual void FreeInterfaces()
300 if (this._menuService != null)
302 OleMenuCommandService tempService = this._menuService;
303 this._menuService = null;
304 tempService.Dispose();
307 _innerOleCommandTarget = null;
308 _innerVsAggregatableProject = null;
309 _innerVsUIHierarchy = null;
310 _innerVsHierarchy = null;
315 int IVsHierarchy.GetCanonicalName(uint itemId, out string name)
317 return this.GetCanonicalName(itemId, out name);
320 int IVsHierarchy.GetGuidProperty(uint itemId, int propId, out System.Guid guid)
322 guid = this.GetGuidProperty(itemId, propId);
323 return VSConstants.S_OK;
326 int IVsHierarchy.GetNestedHierarchy(uint itemId, ref System.Guid guidHierarchyNested, out System.IntPtr hierarchyNested, out uint itemIdNested)
328 return this.GetNestedHierarchy(itemId, ref guidHierarchyNested, out hierarchyNested, out itemIdNested);
331 int IVsHierarchy.GetProperty(uint itemId, int propId, out System.Object property)
333 // While other methods expect the protected method to throw, for GetProperty
334 // we break this pattern as it is called much more often and it is legitimate to
335 // return not implemented. Therefore it can help perf and debugging experience
336 return this.GetProperty(itemId, propId, out property);
339 int IVsHierarchy.GetSite(out Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider)
341 serviceProvider = this.GetSite();
342 return VSConstants.S_OK;
345 int IVsHierarchy.ParseCanonicalName(string name, out uint itemId)
347 return this.ParseCanonicalName(name, out itemId);
350 int IVsHierarchy.QueryClose(out int canClose)
352 canClose = 0;
353 if (this.QueryClose())
354 canClose = 1;
355 return VSConstants.S_OK;
358 int IVsHierarchy.SetGuidProperty(uint itemId, int propId, ref System.Guid guid)
360 this.SetGuidProperty(itemId, propId, ref guid);
361 return VSConstants.S_OK;
364 int IVsHierarchy.SetSite(Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider)
366 this.serviceProvider = (System.IServiceProvider)new ServiceProvider(serviceProvider);
367 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.SetSite(serviceProvider));
368 return VSConstants.S_OK;
371 int IVsHierarchy.UnadviseHierarchyEvents(uint cookie)
373 this.UnadviseHierarchyEvents(cookie);
374 return VSConstants.S_OK;
377 int IVsHierarchy.SetProperty(uint itemId, int propId, System.Object property)
379 return this.SetProperty(itemId, propId, property);
382 int IVsHierarchy.Unused0()
384 this.Unused0();
385 return VSConstants.S_OK;
388 int IVsHierarchy.Unused1()
390 this.Unused1();
391 return VSConstants.S_OK;
394 int IVsHierarchy.Unused2()
396 this.Unused2();
397 return VSConstants.S_OK;
400 int IVsHierarchy.Unused3()
402 this.Unused3();
403 return VSConstants.S_OK;
406 int IVsHierarchy.Unused4()
408 this.Unused4();
409 return VSConstants.S_OK;
412 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.AdviseHierarchyEvents"]/*' />
413 protected virtual uint AdviseHierarchyEvents(Microsoft.VisualStudio.Shell.Interop.IVsHierarchyEvents eventSink)
415 uint cookie=0;
416 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.AdviseHierarchyEvents(eventSink, out cookie));
417 return cookie;
420 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.Close"]/*' />
421 protected virtual void Close()
423 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.Close());
426 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.GetCanonicalName"]/*' />
427 protected virtual int GetCanonicalName(uint itemId, out string name)
429 return _innerVsHierarchy.GetCanonicalName(itemId, out name);
432 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.GetGuidProperty"]/*' />
433 protected virtual Guid GetGuidProperty(uint itemId, int propId)
435 Guid property = Guid.Empty;
436 if (_innerVsHierarchy != null)
437 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.GetGuidProperty(itemId, propId, out property));
438 else
439 return Guid.Empty;
440 return property;
443 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.GetNestedHierarchy"]/*' />
444 protected virtual int GetNestedHierarchy(uint itemId, ref System.Guid guidHierarchyNested, out System.IntPtr hierarchyNested, out uint itemIdNested)
446 if (_innerVsHierarchy != null)
447 return _innerVsHierarchy.GetNestedHierarchy(itemId, ref guidHierarchyNested, out hierarchyNested, out itemIdNested);
448 else
450 hierarchyNested = IntPtr.Zero;
451 itemIdNested = VSConstants.VSITEMID_NIL;
452 return VSConstants.E_NOINTERFACE;
456 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.GetProperty"]/*' />
457 protected virtual int GetProperty(uint itemId, int propId, out Object property)
459 if (_innerVsHierarchy != null)
460 return _innerVsHierarchy.GetProperty(itemId, propId, out property);
461 else
463 property = null;
464 return VSConstants.E_UNEXPECTED;
468 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.GetSite"]/*' />
469 protected virtual Microsoft.VisualStudio.OLE.Interop.IServiceProvider GetSite()
471 Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider;
472 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.GetSite(out serviceProvider));
473 return serviceProvider;
476 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.ParseCanonicalName"]/*' />
477 protected virtual int ParseCanonicalName(string name, out uint itemId)
479 return _innerVsHierarchy.ParseCanonicalName(name, out itemId);
482 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.QueryClose"]/*' />
483 protected virtual bool QueryClose()
485 int canClose;
486 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.QueryClose(out canClose));
487 return (canClose != 0);
490 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.SetGuidProperty"]/*' />
491 protected virtual void SetGuidProperty(uint itemId, int propId, ref System.Guid guid)
493 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.SetGuidProperty(itemId, propId, ref guid));
496 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.UnadviseHierarchyEvents"]/*' />
497 protected virtual void UnadviseHierarchyEvents(uint cookie)
499 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.UnadviseHierarchyEvents(cookie));
502 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.SetProperty"]/*' />
503 protected virtual int SetProperty(uint itemId, int propId, System.Object property)
505 return _innerVsHierarchy.SetProperty(itemId, propId, property);
508 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.Unused0"]/*' />
509 protected virtual void Unused0()
511 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.Unused0());
514 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.Unused1"]/*' />
515 protected virtual void Unused1()
517 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.Unused1());
520 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.Unused2"]/*' />
521 protected virtual void Unused2()
523 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.Unused2());
526 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.Unused3"]/*' />
527 protected virtual void Unused3()
529 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.Unused3());
532 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.Unused4"]/*' />
533 protected virtual void Unused4()
535 ErrorHandler.ThrowOnFailure(_innerVsHierarchy.Unused4());
537 #endregion
539 #region IVsUIHierarchy Members
541 // All methods (except for QueryStatusCommand and ExecCommand) call the IVsHierarchy implementation.
542 // QueryStatusCommand and ExecCommand call a protected virtual method that the base class can override.
543 // Note that we QI for IVsUIHierarchy on this so that if we are flavored we call the outer IVsHierarchy.
546 int IVsUIHierarchy.QueryStatusCommand(uint itemid, ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
548 return this.QueryStatusCommand(itemid, ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
550 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.QueryStatusCommand"]/*' />
551 protected virtual int QueryStatusCommand(uint itemid, ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
553 return _innerVsUIHierarchy.QueryStatusCommand(itemid, ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
556 int IVsUIHierarchy.ExecCommand(uint itemid, ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
558 int hr = VSConstants.S_OK;
561 _inExecCommand++;
562 hr = this.ExecCommand(itemid, ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
564 finally
566 _inExecCommand--;
567 Debug.Assert(_inExecCommand >= 0);
568 if (_hierarchyClosed && _inExecCommand == 0)
570 FreeInterfaces();
573 return hr;
575 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.ExecCommand"]/*' />
576 protected virtual int ExecCommand(uint itemid, ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
578 return _innerVsUIHierarchy.ExecCommand(itemid, ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
581 int IVsUIHierarchy.AdviseHierarchyEvents(IVsHierarchyEvents pEventSink, out uint pdwCookie)
583 return ((IVsHierarchy)this).AdviseHierarchyEvents(pEventSink, out pdwCookie);
586 int IVsUIHierarchy.Close()
588 return ((IVsHierarchy)this).Close();
591 int IVsUIHierarchy.GetCanonicalName(uint itemid, out string pbstrName)
593 return ((IVsHierarchy)this).GetCanonicalName(itemid, out pbstrName);
596 int IVsUIHierarchy.GetGuidProperty(uint itemid, int propid, out Guid pguid)
598 return ((IVsHierarchy)this).GetGuidProperty(itemid, propid, out pguid);
601 int IVsUIHierarchy.GetNestedHierarchy(uint itemid, ref Guid iidHierarchyNested, out IntPtr ppHierarchyNested, out uint pitemidNested)
603 return ((IVsHierarchy)this).GetNestedHierarchy(itemid, ref iidHierarchyNested, out ppHierarchyNested, out pitemidNested);
606 int IVsUIHierarchy.GetProperty(uint itemid, int propid, out object pvar)
608 return ((IVsHierarchy)this).GetProperty(itemid, propid, out pvar);
611 int IVsUIHierarchy.GetSite(out Microsoft.VisualStudio.OLE.Interop.IServiceProvider ppSP)
613 return ((IVsHierarchy)this).GetSite(out ppSP);
616 int IVsUIHierarchy.ParseCanonicalName(string pszName, out uint pitemid)
618 return ((IVsHierarchy)this).ParseCanonicalName(pszName, out pitemid);
621 int IVsUIHierarchy.QueryClose(out int pfCanClose)
623 return ((IVsHierarchy)this).QueryClose(out pfCanClose);
626 int IVsUIHierarchy.SetGuidProperty(uint itemid, int propid, ref Guid rguid)
628 return ((IVsHierarchy)this).SetGuidProperty(itemid, propid, ref rguid);
631 int IVsUIHierarchy.SetProperty(uint itemid, int propid, object var)
633 return ((IVsHierarchy)this).SetProperty(itemid, propid, var);
636 int IVsUIHierarchy.SetSite(Microsoft.VisualStudio.OLE.Interop.IServiceProvider psp)
638 return ((IVsHierarchy)this).SetSite(psp);
641 int IVsUIHierarchy.UnadviseHierarchyEvents(uint dwCookie)
643 return ((IVsHierarchy)this).UnadviseHierarchyEvents(dwCookie);
646 int IVsUIHierarchy.Unused0()
648 return ((IVsHierarchy)this).Unused0();
651 int IVsUIHierarchy.Unused1()
653 return ((IVsHierarchy)this).Unused1();
656 int IVsUIHierarchy.Unused2()
658 return ((IVsHierarchy)this).Unused2();
661 int IVsUIHierarchy.Unused3()
663 return ((IVsHierarchy)this).Unused3();
666 int IVsUIHierarchy.Unused4()
668 return ((IVsHierarchy)this).Unused4();
671 #endregion
674 #region IOleCommandTarget Members
676 int IOleCommandTarget.Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
678 int hr = ((IOleCommandTarget)_menuService).Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
679 return hr;
682 int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
684 int hr = ((IOleCommandTarget)_menuService).QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
685 return hr;
688 #endregion
690 #region IServiceProvider Members
692 object System.IServiceProvider.GetService(Type serviceType)
694 if (serviceType.IsEquivalentTo(typeof(IOleCommandTarget)))
695 return ((IOleCommandTarget)_menuService);
696 else if (serviceType.IsEquivalentTo(typeof(System.ComponentModel.Design.IMenuCommandService)))
697 return ((System.ComponentModel.Design.IMenuCommandService)_menuService);
698 else
699 return this.serviceProvider.GetService(serviceType);
703 #endregion
705 #region Events (subset of IVsTrackProjectDocumentsEvents)
706 // This makes it easier for the derived class to subscribe to only the events it
707 // is really interested in and get one event per file. This also filter events
708 // and only send events that have to do with this project
710 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.EventHandler"]/*' />
711 public delegate void EventHandler<ProjectDocumentsChangeEventArgs>(object sender, ProjectDocumentsChangeEventArgs e);
713 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.FileAdded"]/*' />
714 /// <devdoc>
715 /// Called after a file was added to this project.
716 /// </devdoc>
717 public event EventHandler<ProjectDocumentsChangeEventArgs> FileAdded;
718 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.FileRemoved"]/*' />
719 /// <devdoc>
720 /// Called after a file was remove from this project.
721 /// </devdoc>
722 public event EventHandler<ProjectDocumentsChangeEventArgs> FileRemoved;
723 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.FileRenamed"]/*' />
724 /// <devdoc>
725 /// Called after a file was renamed in this project.
726 /// </devdoc>
727 public event EventHandler<ProjectDocumentsChangeEventArgs> FileRenamed;
729 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.DirectoryAdded"]/*' />
730 /// <devdoc>
731 /// Called after a directory was added to this project.
732 /// </devdoc>
733 public event EventHandler<ProjectDocumentsChangeEventArgs> DirectoryAdded;
734 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.DirectoryRemoved"]/*' />
735 /// <devdoc>
736 /// Called after a directory was remove from this project.
737 /// </devdoc>
738 public event EventHandler<ProjectDocumentsChangeEventArgs> DirectoryRemoved;
739 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.DirectoryRenamed"]/*' />
740 /// <devdoc>
741 /// Called after a directory was renamed in this project.
742 /// </devdoc>
743 public event EventHandler<ProjectDocumentsChangeEventArgs> DirectoryRenamed;
745 /// <include file='doc\FlavoredProject.uex' path='docs/doc[@for="FlavoredProject.SccStatusChanged"]/*' />
746 /// <devdoc>
747 /// Called after the source code control status of a file in this project changed.
748 /// </devdoc>
749 // Below suppression cannot be added to the fxcop baseline file as the code analysis phase just ignores it.
750 [SuppressMessage("Microsoft.Naming","CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId="Scc", Justification="VSIP Shell MPF")]
751 public event EventHandler<ProjectDocumentsChangeEventArgs> SccStatusChanged;
752 #endregion
754 #region IVsTrackProjectDocumentsEvents2 Members
755 internal class DocumentsEventsSink : IVsTrackProjectDocumentsEvents2
757 private FlavoredProjectBase _flavoredProjectBase;
759 internal DocumentsEventsSink(FlavoredProjectBase flavoredProjectBase)
761 _flavoredProjectBase = flavoredProjectBase;
764 /// We subscribes to IVsTrackProjectDocumentsEvents and trigger the
765 /// corresponding event once per file per event.
766 /// We filters the events to only reports those related to our project.
767 /// This is NOT required for flavoring, but simplify the work the
768 /// derived classes have to do when subscribing to these events
770 int IVsTrackProjectDocumentsEvents2.OnAfterAddDirectoriesEx(int cProjects, int cDirectories, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgpszMkDocuments, VSADDDIRECTORYFLAGS[] rgFlags)
772 _flavoredProjectBase.GenerateEvents(rgpProjects, rgFirstIndices, rgpszMkDocuments, _flavoredProjectBase.DirectoryAdded, new ProjectDocumentsChangeEventArgs());
773 return VSConstants.S_OK;
776 int IVsTrackProjectDocumentsEvents2.OnAfterAddFilesEx(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgpszMkDocuments, VSADDFILEFLAGS[] rgFlags)
778 _flavoredProjectBase.GenerateEvents(rgpProjects, rgFirstIndices, rgpszMkDocuments, _flavoredProjectBase.FileAdded, new ProjectDocumentsChangeEventArgs());
779 return VSConstants.S_OK;
782 int IVsTrackProjectDocumentsEvents2.OnAfterRemoveDirectories(int cProjects, int cDirectories, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgpszMkDocuments, VSREMOVEDIRECTORYFLAGS[] rgFlags)
784 _flavoredProjectBase.GenerateEvents(rgpProjects, rgFirstIndices, rgpszMkDocuments, _flavoredProjectBase.DirectoryRemoved, new ProjectDocumentsChangeEventArgs());
785 return VSConstants.S_OK;
788 int IVsTrackProjectDocumentsEvents2.OnAfterRemoveFiles(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgpszMkDocuments, VSREMOVEFILEFLAGS[] rgFlags)
790 _flavoredProjectBase.GenerateEvents(rgpProjects, rgFirstIndices, rgpszMkDocuments, _flavoredProjectBase.FileRemoved, new ProjectDocumentsChangeEventArgs());
791 return VSConstants.S_OK;
794 int IVsTrackProjectDocumentsEvents2.OnAfterRenameDirectories(int cProjects, int cDirs, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgszMkOldNames, string[] rgszMkNewNames, VSRENAMEDIRECTORYFLAGS[] rgFlags)
796 _flavoredProjectBase.GenerateEvents(rgpProjects, rgFirstIndices, rgszMkNewNames, _flavoredProjectBase.DirectoryRenamed, new ProjectDocumentsChangeEventArgs());
797 return VSConstants.S_OK;
800 int IVsTrackProjectDocumentsEvents2.OnAfterRenameFiles(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgszMkOldNames, string[] rgszMkNewNames, VSRENAMEFILEFLAGS[] rgFlags)
802 _flavoredProjectBase.GenerateEvents(rgpProjects, rgFirstIndices, rgszMkNewNames, _flavoredProjectBase.FileRenamed, new ProjectDocumentsChangeEventArgs());
803 return VSConstants.S_OK;
806 int IVsTrackProjectDocumentsEvents2.OnAfterSccStatusChanged(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgpszMkDocuments, uint[] rgdwSccStatus)
808 _flavoredProjectBase.GenerateEvents(rgpProjects, rgFirstIndices, rgpszMkDocuments, _flavoredProjectBase.SccStatusChanged, new ProjectDocumentsChangeEventArgs());
809 return VSConstants.S_OK;
812 int IVsTrackProjectDocumentsEvents2.OnQueryAddDirectories(IVsProject pProject, int cDirectories, string[] rgpszMkDocuments, VSQUERYADDDIRECTORYFLAGS[] rgFlags, VSQUERYADDDIRECTORYRESULTS[] pSummaryResult, VSQUERYADDDIRECTORYRESULTS[] rgResults)
814 return VSConstants.S_OK; // We are not interested in this one
817 int IVsTrackProjectDocumentsEvents2.OnQueryAddFiles(IVsProject pProject, int cFiles, string[] rgpszMkDocuments, VSQUERYADDFILEFLAGS[] rgFlags, VSQUERYADDFILERESULTS[] pSummaryResult, VSQUERYADDFILERESULTS[] rgResults)
819 return VSConstants.S_OK; // We are not interested in this one
822 int IVsTrackProjectDocumentsEvents2.OnQueryRemoveDirectories(IVsProject pProject, int cDirectories, string[] rgpszMkDocuments, VSQUERYREMOVEDIRECTORYFLAGS[] rgFlags, VSQUERYREMOVEDIRECTORYRESULTS[] pSummaryResult, VSQUERYREMOVEDIRECTORYRESULTS[] rgResults)
824 return VSConstants.S_OK; // We are not interested in this one
827 int IVsTrackProjectDocumentsEvents2.OnQueryRemoveFiles(IVsProject pProject, int cFiles, string[] rgpszMkDocuments, VSQUERYREMOVEFILEFLAGS[] rgFlags, VSQUERYREMOVEFILERESULTS[] pSummaryResult, VSQUERYREMOVEFILERESULTS[] rgResults)
829 return VSConstants.S_OK; // We are not interested in this one
832 int IVsTrackProjectDocumentsEvents2.OnQueryRenameDirectories(IVsProject pProject, int cDirs, string[] rgszMkOldNames, string[] rgszMkNewNames, VSQUERYRENAMEDIRECTORYFLAGS[] rgFlags, VSQUERYRENAMEDIRECTORYRESULTS[] pSummaryResult, VSQUERYRENAMEDIRECTORYRESULTS[] rgResults)
834 return VSConstants.S_OK; // We are not interested in this one
837 int IVsTrackProjectDocumentsEvents2.OnQueryRenameFiles(IVsProject pProject, int cFiles, string[] rgszMkOldNames, string[] rgszMkNewNames, VSQUERYRENAMEFILEFLAGS[] rgFlags, VSQUERYRENAMEFILERESULTS[] pSummaryResult, VSQUERYRENAMEFILERESULTS[] rgResults)
839 return VSConstants.S_OK; // We are not interested in this one
843 #endregion
845 #region Helpers for IVsTrackProjectDocumentsEvents2
847 /// <devdoc>
848 /// Used to subscribe/unsubscribe to those events
849 /// </devdoc>
850 private IVsTrackProjectDocuments2 GetTrackProjectDocuments()
852 IVsTrackProjectDocuments2 trackDocuments = ((System.IServiceProvider)this).GetService(typeof(SVsTrackProjectDocuments)) as IVsTrackProjectDocuments2;
853 Debug.Assert(trackDocuments != null, "Could not get the IVsTrackProjectDocuments2 object");
854 if (trackDocuments == null)
856 throw new InvalidOperationException();
858 return trackDocuments;
861 /// <devdoc>
862 /// Look at the list of projects and files and for each file that is part of this
863 /// project, set the MkDocument on the event argument and trigger the event.
864 /// </devdoc>
865 private void GenerateEvents(
866 IVsProject[] projects,
867 int[] firstFiles,
868 string[] mkDocuments,
869 EventHandler<ProjectDocumentsChangeEventArgs> eventToGenerate,
870 ProjectDocumentsChangeEventArgs e)
872 if (eventToGenerate == null)
873 return; // no event = nothing to do
875 if (projects == null || firstFiles == null || mkDocuments == null)
876 throw new ArgumentNullException();
877 if (projects.Length != firstFiles.Length)
878 throw new ArgumentException();
880 // First find out which range of the array (if any) include the files that belong to this project
881 int first = -1;
882 int last = mkDocuments.Length - 1; // default to the last document
883 for (int i = 0; i < projects.Length; ++i)
885 if (first > -1)
887 // We get here if there is 1 or more project(s) after ours in the list
888 last = firstFiles[i] - 1;
889 break;
891 if (IsThisProject(projects[i]))
892 first = firstFiles[i];
894 if (last >= mkDocuments.Length)
895 throw new ArgumentException();
896 // See if we have any documents
897 if (first < 0)
898 return; // Nothing that belongs to this project
900 // For each file, generate the event
901 for (int i = first; i <= last; ++i)
905 e.MkDocument = mkDocuments[i];
906 eventToGenerate(this, e);
908 catch(Exception error)
910 Debug.Fail(error.Message);
915 private bool IsThisProject(IVsProject prj)
917 bool areSame = false;
918 Guid IID_IUnknown = VSConstants.IID_IUnknown;
919 IntPtr otherPtr = IntPtr.Zero;
920 IntPtr otherIUnk = IntPtr.Zero;
921 IntPtr thisPtr = IntPtr.Zero;
922 IntPtr thisIUnk = IntPtr.Zero;
925 otherPtr = Marshal.GetIUnknownForObject(prj);
926 Marshal.QueryInterface(otherPtr, ref IID_IUnknown, out otherIUnk);
928 thisPtr = Marshal.GetIUnknownForObject(this);
929 Marshal.QueryInterface(thisPtr, ref IID_IUnknown, out thisIUnk);
930 areSame = (otherIUnk == thisIUnk);
932 finally
934 if (IntPtr.Zero != otherPtr)
936 Marshal.Release(otherPtr);
938 if (IntPtr.Zero != otherIUnk)
940 Marshal.Release(otherIUnk);
942 if (IntPtr.Zero != thisPtr)
944 Marshal.Release(thisPtr);
946 if (IntPtr.Zero != thisIUnk)
948 Marshal.Release(thisIUnk);
951 return areSame;
954 #endregion