Here is where I'm am at the moment:
- My implementation is based on the Package and MEF objects (and the services I can get from there)
- I now have a full REPL environment inside VisualStudio, so I can code VisualStudio dynamically :) (i.e when I'm working on my Extension I don't need to recompile the Extension assembly everytime I make a code change or want to try some DTE , MEF or WPF action)
- I'm able to get an DTE object by using: packageObject.GetService(typeof(EnvDTE.DTE)) (I use a similar technique to get and ErrorListProvider, IVsUIShell, OleMenuCommandService objects)
- In this case the packageObject implements Package and is marked with the [PackageRegistration(UseManagedResourcesOnly = true)] attribute
- Once I had the ErrorListProvider object (created using ErrorListProvider(packageObject) ) , I was able to add items to it
- To create windows I used the packageObject.CreateToolWindow(typeof(WindowPane_WPF), index++) ;
- The WindowPane_WPF is a class I added which implements ToolWindowPane and sets its Content to a vanila WPF grid (I also have a WindowPane_WinForms which sets the content to a System.Windows.Forms.Integration.WindowsFormsHost control
- In order for this to work, I had to preregister them on packageObject classes with:
- [ProvideToolWindow(typeof(WindowPane_WPF) , MultiInstances = true, Style=VsDockStyle.Linked, Orientation = ToolWindowOrientation.Top, Window=EnvDTE.Constants.vsWindowKindOutput)]
- [ProvideToolWindow(typeof(WindowPane_WinForms), MultiInstances = true, Style = VsDockStyle.Linked, Orientation = ToolWindowOrientation.Top, Window = EnvDTE.Constants.vsWindowKindSolutionExplorer)]
- A number of problems I had initially where caused by threading issues. My scripts run a separate thread and there where a number of cases where the request needs to be executed from the main VisualStudio thread (although I usually got weird COM errors which didn't point that way). I dealt with this problem by creating an extension method that used the Dispatcher object from System.Windows.Application.Current
- I also had issues getting the Events I subscribed via the DTE.Events.BuildEvents callbacks, until I pinned the object DTE.Events.BuildEvents to a static variable in my class
- I'm adding menus dinamically using dte.CommandBars["MenuBar"] (since I didn't want to hard code the menus in my extension dll)
- I'm using the [ProvideAutoLoad(UIContextGuids80.NoSolution)] on my packageObject to get a callback on VisualStudio load
- I implemented a couple wrappers on some MEF exports which give me easy access to the WPF TextEditor:
- IWpfTextViewCreationListener (allows the manipulation of Code content and add new Adornments)
- IWpfTextViewMarginProvider (allows adding a new margin or section to the Code provider)
Here are the issues/questions I currently have:
- How to get a live instance of the AddIn object. I currently have a DTE object, but don't know where to get the EnvDTE.AddIn
- This is the object that is passed as the addInInst parameter of the OnConnection method from the VsConnect : IDTExtensibility2, IDTCommandTarget (I needed that in order to be able to correctly set the variables used by consumed add-ins
- How to control the position of a new ToolWindowPane when created programatically.
- If you noticed from the ProvideToolWindow attribute above, I use it to define the place where new instances of this window are created. My issue in that at the moment I don't seem to be able to set them programatically (specially the target Window GUID).
- Faster way to add menu items. The dte.CommandBars works ok, but it still takes about a couple secs to do it (and it hangs the GUI) so, I was wondering if there was another way. I have access to the main WPF VisualStudio window, so maybe that will be faster. Note that I don't need to preregister these items as MenuCommands, I just want to get Action callback when they are clicked
- Is the [ProvideAutoLoad(UIContextGuids80.NoSolution)] the best way to get some code to run on VisualStudio load?