Visual Studio services and VS Editor extensions
If you are familiar withВ Visual Studio Integration SDK you already know that "...Creating a VSPackage is a powerful way to extend Visual Studio...". You probably also know that VSPackages use Services to interact with each other and the core of the Visual Studio. Many components of the Visual Studio core are packages and can be accessed as services. To access a service all you need is an appropriateВ service provider implementing the IServiceProvider interface. You also need to know the type of the service you want to access. Once you have both - call the GetService method on the provider and it will return the service you desire. All of this is good and handy when you are building your own VSPackage.
What about Visual Studio Editor extensions? What if all youВ are planningВ is an editor extension withВ just one small thing which goes beyond editor?
Guess what - all this wealth of the Visual Studio core services is still available to you without the formal frame of the VSPackage. It is available, that is, if you can get your hands onВ a service provider which is aware of the service you are after.
In my NDjango designerВ in addition to syntax colorization, code completion and other wonders of the Visual Studio Editor extensions I wanted to show the errors in both the Error List and a separate pane of the Output Window. There is aВ variety of ways to do it.В
In NDjango designerВ it is done in NodeProviderBroker object byВ accessingВ the IVsOutputWindow service.В OnceВ I have the service I useВ its CreatePane method to create the Django Output pane (an IVsOutuptWindowPane object). And then, in the NodeSnapshot object I generate the messages using the OutpuTaskItemString method. You can find examples of how to use these services on the web and in the Visual Studio SDK, as well as in the source code of the NDjango designer
What is somewhat less obvious is how do you get to the starting point - the IVsOutputWindow service. It is promised that in the future it will be as easy as importing the ServiceProvider, and then calling the GetService method on the service provider. We are not there yet, so here is what I did to get by for now:
private object GetService(ITextBuffer textBuffer, Type type) { var vsBuffer = adaptersFactory.GetBufferAdapter(textBuffer); if (vsBuffer == null) return null; Guid guidServiceProvider = VSConstants.IID_IUnknown; IObjectWithSite objectWithSite = vsBuffer as IObjectWithSite; IntPtr ptrServiceProvider = IntPtr.Zero; objectWithSite.GetSite(ref guidServiceProvider, out ptrServiceProvider); Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)Marshal.GetObjectForIUnknown(ptrServiceProvider); Guid guidService = typeof(SVsOutputWindow).GUID; Guid guidInterface = typeof(IVsOutputWindow).GUID; IntPtr ptrObject = IntPtr.Zero; int hr = serviceProvider.QueryService(ref guidService, ref guidInterface, out ptrObject); if (ErrorHandler.Failed(hr) || ptrObject == IntPtr.Zero) return null; IVsOutputWindow taskList = (IVsOutputWindow)Marshal.GetObjectForIUnknown(ptrObject); Marshal.Release(ptrObject); return taskList; }
This code is based on the code posted by Noah RichardsВ and it uses the text buffer (an object implementingВ IVsTextBuffer interface) as a gateway to access Visual Studio global services. Works for me.