{"id":74193,"date":"2017-11-03T12:38:21","date_gmt":"2017-11-03T12:38:21","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=74193"},"modified":"2021-07-29T19:47:40","modified_gmt":"2021-07-29T19:47:40","slug":"hacking-visual-studio","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/hacking-visual-studio\/","title":{"rendered":"Hacking Visual Studio"},"content":{"rendered":"<p>Microsoft Visual Studio is a great IDE (integrated development environment). It looks good from both the functional and design perspective, even though it is restricted by the need to maintain legacy aspects. It is so good that you will want to use it and extend it to meet your requirements.<\/p>\n<p>There is a long history to having an extensible IDE, probably originating from Alan Kay&#8217;s SmallTalk design. There is a range of reasons for wanting to add features: You might be tempted to create a custom color scheme, a tool to automate a mundane task or for moving files around. You might even need a complete support for a new programming language!<\/p>\n<p>When you are creating a Visual Studio plugin, you will most likely come across several frameworks such as native Visual Studio API, DTE automation object and Managed Extensibility Framework. You might even need to resort to using all of them at once to solve a more knotty problem.<\/p>\n<p>Some features of the IDE are not accessible from these frameworks, but you can always use them if you fully understand the caveats. I\u2019ll mention these later in this article. To use these features, you first may need to take a look on how the creators of the IDE write their code or maybe even call their internal methods! Some of them are written in C++ but the most interesting bits are in .NET so you won&#8217;t need to resort to anything more complex than disassembling .NET assemblies.<\/p>\n<p>I do this disassembly work quite regularly while working on <a href=\"https:\/\/revdebug.com\/\">RevDeBug <\/a>or while helping other developers on the <a href=\"https:\/\/gitter.im\/microsoft\/extendvs\">ExtendVS Gitter.im channel<\/a>. I became convinced, after seeing questions and problems repeatedly reappearing on this channel, that I should write an article about how to tackle such issues. To illustrate how to do this in practice, I\u2019ll use two of the example questions that keep cropping up on the Channel.<\/p>\n<p>The first issue was how to gain access to the Visual Studio Notifications. I couldn\u2019t find any information about it on the MSDN pages or on other sites so I have put my software archeologist hat on and started a deep dig inside the internals of Visual Studio. It is a pretty new feature so I assumed that it would be fully implemented in .NET. I thought that checking how the \u201cNotifications\u201d tool window is created would be a good place to start my search. For that I\u2019ve used Snoop, a WPF spy utility. With it I was able to track down the class of the window, which was <br \/>\n`Microsoft.VisualStudio.Services.UserNotifications.UserNotificationsWindow`. Using Snoop\u2019s PowerShell tab I\u2019ve also extracted the path to the containing assembly file.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"865\" height=\"368\" class=\"wp-image-74194\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/10\/word-image-3.png\" \/><\/p>\n<p>Knowing the type and the path to the assembly, I was able to view the code using the <a href=\"http:\/\/www.red-gate.com\/products\/dotnet-development\/reflector\/\">.NET Reflector disassembler<\/a>. Because this window was responsible for showing the user notifications, I hoped that, by using Reflector\u2019s Analyze tool, I would be able to find further leads or even a real source of notifications. And I was right \u2013 in the \u201cDepends On\u201d section there was a reference to a separate assembly, that sounded just right: <strong>Microsoft.Internal.VisualStudio.UserNotifications<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1074\" height=\"685\" class=\"wp-image-74195\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/10\/word-image-4.png\" \/><\/p>\n<p>This was exactly, what I needed. Inside, I found the interfaces of notifications and a `<strong>SVsUserNotificationService` <\/strong>class for extracting the service that manages them.\u00a0<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"367\" height=\"415\" class=\"wp-image-74196\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/10\/word-image-5.png\" \/><\/p>\n<p>I then started to prepare the sample code I needed to check whether it would actually work. I had to use the .NET Reflector <strong>Analyze<\/strong> function few more times to learn how those interfaces are actually used before I was confident enough to be able to come up with the working code listed below.<\/p>\n<p>It requires a reference to `Microsoft.Internal.VisualStudio.UserNotifications.dll` to run.<\/p>\n<pre class=\"theme:vs2012 lang:c# decode:true\">var notificationService = this.ServiceProvider.GetService(typeof(SVsUserNotificationService)) as IVsUserNotificationService;\r\n  var manager = notificationService.GetNotificationManagerAsync().Result;\r\n  \/\/ ExtensionManager provider guid.\r\n  var notifications = manager.GetNotifications(new Guid(\"2B7364A1-1482-4b25-9339-3A6BD7A8A86D\"));<\/pre>\n<p>All notifications have their own provider with a unique identifier: If we then want to extract existing notifications from the notification manager, we have to provide a valid GUID. In this example I have used <strong>ExtensionManager<\/strong>\u2019s GUID which I extracted from `<strong>ExtensionManangerUpdateNotificationProvider<\/strong>` in `<strong>Microsoft.VisualStudio.ExtensionManager.Implementation.dll<\/strong>`<\/p>\n<p>The second case was a bit more tricky &#8211; how can we programmatically trigger the print code function from an opened editor. Although there is a method within the DTE automation that provides this functionality (https:\/\/msdn.microsoft.com\/en-us\/library\/envdte.document.printout.aspx), it doesn\u2019t seem to work in newer versions of Visual Studio. Because the printing feature works just fine via the good old Ctrl-P shortcut, I wanted to give it a try and check whether it is possible to run it directly from code (and obviously not by emitting Ctrl+P keystroke).<\/p>\n<p>This time around I didn\u2019t have a good starting point within Visual Studio, so I just loaded all VS private assemblies and looked for anything containing `print` in it.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1091\" height=\"600\" class=\"wp-image-74197\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/10\/word-image-6.png\" \/><\/p>\n<p>It didn\u2019t take me long to find <strong>`IPrintingService<\/strong>` interface with a very promising method called `<strong>PrintTextBuffer<\/strong>`. Now I just had to find a way to call it from code, so I once more used the Analyze tool of .NET Reflector to see where it is used. At first I got no results, but after adding libraries from <strong>CommonExtensions\/Microsft\/Editor <\/strong>I found this little nugget:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"448\" height=\"478\" class=\"wp-image-74198\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/10\/word-image-7.png\" \/><\/p>\n<p>The <strong>PrintingClient<\/strong> class was responsible for providing everything that is needed to print a single code view represented by an <strong>IWpfTextView <\/strong>interface. With this knowledge, I could then try to write my own code and create an instance of this type. I could also check how exactly it is used within the Visual Studio.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"629\" height=\"115\" class=\"wp-image-74199\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/10\/word-image-8.png\" \/><\/p>\n<p>Another look at the `<strong>Analyze<\/strong>` tool via the `<em>Instantiated By<\/em>` option drove me to `<strong>SimpleTextViewWindow<\/strong>`. This class initializes the <strong>PrintingClient<\/strong> when it receives a proper command like \u201cPrint\u201d or \u201cPageSetup\u201d. from a user in the <strong>InnerExec<\/strong> method, This couldn\u2019t be better. If only this object was available for each code file that can be printed in the Visual Studio, I would be able to use reflection to invoke methods on the `<strong>PrintingClient<\/strong>`. When I rechecked the class declaration, I noticed that this class implements the `<strong>IVsTextView<\/strong>`. I decided to take a gamble that all printable text views which are returned from <strong>IVsTextManager.GetActiveView()<\/strong> are actually objects of the `<strong>SimpleTextViewWindow<\/strong>` type (<a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.textmanager.interop.ivstextmanager.aspx\">https:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.textmanager.interop.ivstextmanager.aspx<\/a>).<\/p>\n<p>It was worthwhile to give it a shot, especially because I hadn\u2019t found any other class that would use the <strong>PrintingClient<\/strong>. I also assumed, that if the `<strong>IVsTextView<\/strong>` isn\u2019t an instance of a `<strong>SimpleTextViewWindow<\/strong>` type, then we wouldn\u2019t be able to use its print functionality anyway.<\/p>\n<p>Based on the knowledge I\u2018d gathered, I could then start preparing an exploratory method you can see below. As the <strong>PrintClient<\/strong> property that we need to access is not visible publicly, I resorted to obtaining its reference with the use of Reflection API. To run the code, you will need a reference to the `<strong>Microsoft.VisualStudio.Editor.Implementation.dll<\/strong>` library, because it uses the `<strong>Assembly.GetType<\/strong>` call for extracting types via reflection. It might be easily replaced with a proper assembly-qualified name for the needed types, but it was a quick hack just to get it running.<\/p>\n<pre class=\"theme:vs2012 lang:c# decode:true\">var textManager = ServiceProvider.GetService(typeof(VsTextManagerClass)) as IVsTextManager;\r\n  IVsTextView vTextView = null;\r\n   \r\n  textManager.GetActiveView(0, null, out vTextView);\r\n   \r\n  var simpleTextViewWindowType = typeof(Microsoft.VisualStudio.Editor.Implementation.AnnotationTagger).Assembly.GetType(\"Microsoft.VisualStudio.Editor.Implementation.SimpleTextViewWindow\");\r\n  var printingClientType = typeof(Microsoft.VisualStudio.Editor.Implementation.AnnotationTagger).Assembly.GetType(\"Microsoft.VisualStudio.Editor.Implementation.PrintingClient\");\r\n  var wpfTextView = simpleTextViewWindowType.GetProperty(\"WpfTextView\").GetValue(vTextView);\r\n  var printingClient = simpleTextViewWindowType.GetProperty(\"PrintClient\", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).GetValue(vTextView);\r\n  printingClientType.GetMethod(\"TryPrint\").Invoke(printingClient, new object[3] { wpfTextView, false, filePath });<\/pre>\n<p>When run from a Visual Studio plugin, the code above will trigger the printing facilities of Visual Studio, which was what I was striving for.<\/p>\n<p>Before concluding this article I should probably warn you that, if you want to resort to using internal APIs of Visual Studio, you must keep in mind that they might be rapidly changed by Microsoft and will differ from release to release. This approach is prone to bugs and could affect the stability of the IDE, so make your code dependent on exact VS versions and keep track of what the VS team will add in next release: They might introduce an API that will provide exactly what you wished for \ud83d\ude42<\/p>\n<p>I hope that these two cases have encouraged you to start hacking Visual Studio. Most of the assemblies that you might want to look at are held inside \u201c&lt;Visual Studio installation location&gt;\\Common7\\IDE\\\u201d directory. Great places to check are:<\/p>\n<ul>\n<li><strong>PublicAssemblies<\/strong> &#8211; public and in almost all cases well documented interfaces. If possible, rely on those.<\/li>\n<li><strong>PrivateAssemblies<\/strong> &#8211; Those change between Visual Studio versions and they lack documentation. Many of the public methods execute code from it.<\/li>\n<li><strong>CommonExtensions\/Microsoft &#8211; Microsoft extensions for VS<\/strong>. This place is always worth looking into so you can learn from the masters \ud83d\ude09<\/li>\n<\/ul>\n<p>Happy hacking!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Visual Studio, like any Integrated Development Environment, can host extensions for more specialist languages or development tasks. This sort of work is reasonably straightforward most of the time but occasionally you need functionality that isn&#8217;t available in the APIs. Michal takes two examples, printing code in an editing window, and gaining access to the Visual Studio Notifications, and explains how to hack Visual Studio to get to the functionality.&hellip;<\/p>\n","protected":false},"author":316522,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,5788,4159],"coauthors":[50437],"class_list":["post-74193","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-disassembly","tag-visual-studio"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/74193","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/316522"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=74193"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/74193\/revisions"}],"predecessor-version":[{"id":92059,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/74193\/revisions\/92059"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=74193"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=74193"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=74193"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=74193"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}