{"id":91,"date":"2011-05-21T14:36:49","date_gmt":"2011-05-21T21:36:49","guid":{"rendered":"http:\/\/www.myopictopics.com\/?p=91"},"modified":"2011-06-07T22:48:32","modified_gmt":"2011-06-08T05:48:32","slug":"let%e2%80%99s-make-a-visual-studio-addin-%e2%80%93-part-3","status":"publish","type":"post","link":"https:\/\/www.myopictopics.com\/?p=91","title":{"rendered":"Let\u2019s Make a Visual Studio Addin \u2013 part 3"},"content":{"rendered":"<hr \/>\n<h6><a href=\"https:\/\/www.myopictopics.com\/wp-content\/uploads\/2011\/05\/MT_Addin3.zip\"\">Download the source code for this post (10k)<\/a><\/h6>\n<hr \/>\n<p>In the <a title=\"previous\" href=\"https:\/\/www.myopictopics.com\/?p=12\">previous<\/a> <a title=\"installments\" href=\"https:\/\/www.myopictopics.com\/?p=86\">installments<\/a> of this series, we worked completely within the confines of the AutoExp.dat framework which was pretty limiting. That\u2019s not really surprising given that that mechanism dates back at least 15 years as of this writing. That was back before the dot-com bubble happened, I think most people still had non-vestigial tails, and dinosaurs still roamed the earth in the some rural areas. It\u2019s been awhile. In this installment, we\u2019re going to take things up a notch by using mechanisms that are only a mere 10 years old \u2013 that\u2019s right, a time <strong>after<\/strong> most of you were born. Crazy!<\/p>\n<p>We want to deal with several of the big limitations and unknowns we ran into in the previous two parts. Unfortunately, that will have to wait until part 4. First we need to update the way we hook into the debugger. Microsoft has been developing and expanding the <a title=\"Development Tools Environment\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/envdte._dte.aspx\" target=\"_blank\">Development Tools Environment<\/a> framework or \u2018DTE\u2019 which is at the heart of Visual Studio extensibility since VS2003. It contains quite a lot of interfaces that allow you to inspect and extend several areas of Visual Studio. The scope of what is available is actually pretty impressive. This is one of the interfaces that make products like <a href=\"http:\/\/www.wholetomato.com\/\" target=\"_blank\">Visual Assist X<\/a> possible, But trust me, there\u2019s a lot more to it!<\/p>\n<p>Within DTE, you can do simple things like add new menus and buttons, or you can write more complex tasks like traversing the solution hierarchy. You can also write code that automates certain coding tasks and even add an entirely\u00a0new language. Clearly, we\u2019re not going to use most of this stuff. For our part, we really only care about hooking some events in the debugger and then doing some simple expression evaluation.<\/p>\n<p>So what\u2019s the plan here, anyway? First, we want to get a new add-in project up and running that will host our next steps. Thankfully, the new-project wizard has a decent template to accomplish most of that. Then we want to get access to the debugger to tell us when the user is debugging something. <span style=\"color: #ff00ff;\"> <\/span><\/p>\n<h2>A Brave New Project<\/h2>\n<p>If you select File-&gt;New-&gt;Project and then look through the project templates under \u201cOther Project Types\u201d and then \u201cExtensibility\u201d, you\u2019ll find \u201cVisual Studio Add-in\u201d as an option. There are several options in the ensuing wizard, but most of them are just nice-to-have features. For this project, I selected a C++\/ATL project and disabled as many of the add-on features as possible.<\/p>\n<p>Right out of the gate, we get a many-filed project with lots\u00a0 of inscrutable plumbing. You can download the <a href=\"https:\/\/www.myopictopics.com\/wp-content\/uploads\/2011\/05\/MT_Addin3.zip\">new project here (10k)<\/a>. Let\u2019s do a quick run-down of what\u2019s in there:<\/p>\n<p><strong>stdafx.h<\/strong>\/<strong>.cpp<\/strong> \u2013 As usual, this is the special header that drives the precompiled headers feature in the compiler. If you look closely, however, you\u2019ll see several #import statements. Depending on your version of Visual Studio, they might contain some messy GUIDs or they might contain references to files like \u201c<span style=\"font-family: courier;\">dte80a.olb<\/span>\u201d. In either case, these are the large sets of interfaces that we\u2019re going to be using\u00a0 to integrate with Visual Studio.<\/p>\n<p><strong>Addin.rgs<\/strong> \u2013 This odd little file is actually a registry fragment that will be used to register your add-in with Windows. Don\u2019t panic, but we\u2019re actually making a registered component here. The registry is the mechanism that Visual Studio uses to find your add-in.The top section registers your component with Windows while the bottom section registers your add-in with Visual Studio. Don\u2019t worry, this stuff will happen automatically.<\/p>\n<p><strong>Addin.cpp<\/strong> \u2013 It might seem like this is where you\u2019ll put the important code in your add-in, but it actually just contains some basic plumbing code that allows your add-in to be a DLL and to register itself as a control.<\/p>\n<p><strong>Addin.idl<\/strong> \u2013 IDL stands for interface definition language. It\u2019s used to generate data marshaling code for your control\u2019s type library. Again, don\u2019t worry about this file. We won\u2019t be editing it.<\/p>\n<p><strong>Connect.h<\/strong> \u2013 This is where the CConnect class lives. It is the main class for your add-in. It will implement the Visual Studio interfaces that we want to use. Notice that CConnect already derives from something called IDTExtensibility2. This is the main interface that makes a class into a Visual Studio Add-in.<\/p>\n<p><strong>Connect.cpp<\/strong> \u2013 THIS is where all your awesome code can go, but notice what\u2019s in there already. It has functions called OnConnection and OnStartupComplete. These functions are part of Visual Studio\u2019s IDTExtensibility2 interface that was mentioned above. These functions will be called at various times as your add-in is loaded. Also note in OnConnection, there is some code to fill in a class variable called m_pDTE. This is the access point to most of the things we care about in Visual Studio.<\/p>\n<p>When you build, two non-standard things will happen. First, a few more files will be generated. This is the IDL file doing its thing and creating its glue code. This code is generated every time you compile, so don\u2019t bother changing it. You don\u2019t even have to add it to the project, so just ignore it unless you\u2019re curious what\u2019s in there. The second thing that will happen was your new control should have been quietly registered with Windows. This is important when you start debugging your code. It doesn\u2019t matter if Visual Studio is pointing to the Debug build profile. It will debug whatever profile was built most recently. Keep that in mind as a possible gotcha when things seem to be going all wrong.<\/p>\n<p>Just like last time, if you run your add-in, you will start a new copy of Visual Studio \u2013 it\u2019s like launching an aircraft carrier to test out the galley appliances. Go ahead and look under \u201cTools-&gt;Add-in Manager&#8230;\u201d. You should see MT_Addin3 on the list of add-ins and it should be activated. If you put some breakpoints in Connect.cpp before you ran, you should have gotten a break or two in <span style=\"font-family: courier;\">OnConnection<\/span>, <span style=\"font-family: courier;\">OnStartupComplete<\/span>, or one of the other <span style=\"font-family: courier;\">IDTExtensibility2<\/span> handlers.<\/p>\n<h2>Hooking a Debugger<\/h2>\n<h6>(Easier than debugging a hooker! \u2013 hey-o!)<\/h6>\n<p>Everything we\u2019ve touched on so far is just to get an add-in working inside of the Visual Studio framework. We won\u2019t get the notification we really want. We want to get the chance to act just before the watch windows are updated. In other words, we want to be told whenever the target program is halted, and the user can inspect variables. That requires that we hook the debugger events interface.<\/p>\n<p>We only need to hang a few new bits of code on out <span style=\"font-family: courier;\">CConnect<\/span> class in order for it to handle debugger events. For now, we only care about the event called <span style=\"font-family: courier;\">OnEnterBreakMode<\/span>. This is the event that is fired every time the debugger stops the execution of the target process. The obvious case is when the debugger encounters a breakpoint, but this function will also be called every time the user steps into, out of, or over a line of code.<\/p>\n<p>You can follow along in the code sample for these changes, I\u2019ve denoted each one with the comments<\/p>\n<pre>\/\/*** Hooking debugger events ***\/<\/pre>\n<p>The first thing we need to do is make out CConnect class derive from the debugger events interface. This is as simple as adding the following line of code to the class inheritance in Connect.h:<\/p>\n<pre>IDispEventImpl&lt;0, CConnect, &amp;EnvDTE::DIID__dispDebuggerEvents, &amp;EnvDTE::LIBID_EnvDTE, 8, 0&gt;<\/pre>\n<p>That\u2019s a bit of a mouthful, so in the sample code, I use a simple typedef to make it easier.<\/p>\n<p>The next thing we need to do is tell CConnect what events it should expect and then what to do with them. For this, we need to add\u00a0 a sink-map:<\/p>\n<pre>BEGIN_SINK_MAP(CConnect)\r\n SINK_ENTRY_EX(0, EnvDTE::DIID__dispDebuggerEvents, 3, OnEnterBreakMode)\r\nEND_SINK_MAP()<\/pre>\n<p>This is essentially saying that when the EnvDTE::DIID__dispDebuggerEvents interface sends event #3 our way, we should shunt it to a function called <span style=\"font-family: courier;\">OnEnterBreakMode<\/span>. But wait, that seems a little voodoo \u2013 just a magic number three<span style=\"color: #000000;\">? Honestly, COM is hardly my strong suit, and I<\/span>\u2019<span style=\"color: #000000;\">m still trying to track down the origin of this value. It<\/span>\u2019<span style=\"color: #000000;\">s likely tied up in the definition of the IDispatch interface that<\/span>\u2019<span style=\"color: #000000;\">s part of the debugger events object.<br \/>\n<\/span><\/p>\n<p>The other part of this event-sink mechanism is attached and detached at run-time from the Add-in\u2019s <span style=\"font-family: courier;\">OnConnection<\/span> and <span style=\"font-family: courier;\">OnDisonnection<\/span> handlers. We use the DTE interface once again to get access to the events interface and then ask for the debugger events interface specifically. Once we have the debugger events interface, we can simply register that we want to be notified about those events.<\/p>\n<p>Finally, we declare the <span style=\"font-family: courier;\">CConnect::OnEnterBreakMode<\/span> function in Connect.h and make a stub for it in Connect.cpp.<\/p>\n<h2>A Quick Test Drive<\/h2>\n<p>Set a breakpoint in the OnEnterBreakMode function and run the project. When the other copy of Visual Studio comes up, load up another project in it, set some breakpoints, and then run THAT project. When one of those breakpoints hits, you should get popped all the way back to the first Visual Studio with the Add-in project. Neat, huh? Now we can really do whatever we want within Visual Studio, so take a look at what\u2019s available. Next time we\u2019ll be looking at the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/envdte.debugger.getexpression.aspx\">GetExpression<\/a> specifically.<\/p>\n<p>Ok, that\u2019s it for now. My apologies that this posting was mostly just a building block for what\u2019s to come. I promise we\u2019ll tie some stuff together next time out.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,3,8],"tags":[],"class_list":["post-91","post","type-post","status-publish","format-standard","hentry","category-debuggin","category-engineering","category-visual-studio","category-5-id","category-3-id","category-8-id","post-seq-1","post-parity-odd","meta-position-corners","fix"],"_links":{"self":[{"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=\/wp\/v2\/posts\/91","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=91"}],"version-history":[{"count":43,"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=\/wp\/v2\/posts\/91\/revisions"}],"predecessor-version":[{"id":285,"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=\/wp\/v2\/posts\/91\/revisions\/285"}],"wp:attachment":[{"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=91"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=91"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.myopictopics.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=91"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}