<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BlackHC's Adventures in the Dev World &#187; Visual Studio Extensibility</title>
	<atom:link href="http://blog.blackhc.net/category/coding/visual-studio-extensibility/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.blackhc.net</link>
	<description>Just another weblog</description>
	<lastBuildDate>Wed, 16 Nov 2011 23:12:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>A Visual Studio Macro Day</title>
		<link>http://blog.blackhc.net/2008/10/a-visual-studio-macro-day/</link>
		<comments>http://blog.blackhc.net/2008/10/a-visual-studio-macro-day/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 21:08:32 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[Code Model]]></category>
		<category><![CDATA[Extensibility]]></category>
		<category><![CDATA[Macros]]></category>
		<category><![CDATA[Visual Basic]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=237</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/10/a-visual-studio-macro-day/" title="A Visual Studio Macro Day"></a>Today I decided to continue work on a Visual Studio macro I started developing on Sunday (I mainly worked on it today though - Sunday was just document reading before heading back to Munich and going out with friends). The &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/10/a-visual-studio-macro-day/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/10/a-visual-studio-macro-day/" title="A Visual Studio Macro Day"></a><p>Today I decided to continue work on a Visual Studio macro I started developing on Sunday (I mainly worked on it today though - Sunday was just document reading before heading back to Munich and going out with friends).</p>
<p>The samples from Microsoft simply use the comments from MSDN on functions/methods that are part of a class's interface implementation.</p>
<p>I 'documented' a few of my functions by copying the summary out of MSDN but it's a tedious job and consequently I decided to try and automate it.<br />
Although Visual Basic 'sucks' or is a least quite some change from writing C/C++/C# code all the time, the Automation model is very powerful and quite nice to use.</p>
<p>My macro provides two methods:</p>
<ul>
<li>One to add comments to all methods that are part of an interface's implementation</li>
<li>One to add comments to the method the cursor currently resides in</li>
</ul>
<p>My code currently only adds comments from interface definitions that have been defined outside the current project. It's pretty nifty in my opinion because usually these interface comments won't change a lot and thus it's safe to add them to the source code, while the interfaces one has written themself can still change and the macros can't track that and/or update the comments afterwards.</p>
<p>However, I've added a configuration boolean, so this behavior can be turned off if needed.</p>
<p><em>My code won't remove or replace comments, it will just add the comment in front of other comments - if the comment doesn't already exist - I've tried to make it quite safe, so code loss or corruption will be avoided.<br />
</em></p>
<p>I hope this code is helpful. I'm releasing it under the Microsoft Public License. If there are good reasons to use a different license, feel free to tell me so <img src='http://blog.blackhc.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Cheers,<br />
Andreas</p>
<p><span id="more-123"></span></p>
<pre class="brush: vb; title: ; notranslate">
' Andreas 'BlackHC' Kirsch 2008
' released under Microsoft Public License
Imports System
Imports EnvDTE

Public Module CommentImplementedMethods
    ' we usually only want to use external interfaces because it's safer to assume those won't change anytime soon
    Const UseExternalInterfaceCommentsOnly = True

    Private Function GetSummaryFromDocComment(ByVal docComment As String) As String
        Const summaryStartTag = &quot;&lt;summary&gt;&quot;
        Const summaryEndTag = &quot;&lt;/summary&gt;&quot;
        Dim summaryIndex = docComment.IndexOf(summaryStartTag)
        If summaryIndex = -1 Then
            Return &quot;&quot;
        End If
        Dim summaryStart = docComment.Substring(summaryIndex + summaryStartTag.Length)
        Return summaryStart.Substring(0, summaryStart.IndexOf(summaryEndTag))
    End Function

    'Private Function GetInterfaceByName(ByRef classObject As CodeClass, ByRef name As String) As CodeInterface
    '    For Each implementedInterface As CodeInterface In classObject.ImplementedInterfaces
    '        If implementedInterface.Name = name Then
    '            Return implementedInterface
    '        End If
    '    Next
    'End Function

    Private Function GetMethod(ByRef interfaceObject As CodeInterface, ByRef methodObject As CodeFunction) As CodeFunction
        Dim prototypeFlags As Int32 = vsCMPrototype.vsCMPrototypeParamTypes Or vsCMPrototype.vsCMPrototypeType
        Dim prototype As String = methodObject.Prototype(prototypeFlags)

        Dim separationIndex = methodObject.Name.IndexOf(&quot;.&quot;c)
        If separationIndex &lt;&gt; -1 Then
            Dim interfaceName = methodObject.Name.Substring(0, separationIndex)
            If interfaceName &lt;&gt; interfaceObject.Name Then
                Return Nothing
            End If

            Dim realMethodName = methodObject.Name.Substring(separationIndex + 1)
            prototype = prototype.Replace(methodObject.Name, realMethodName)
        End If

        For Each member As CodeElement In interfaceObject.Members
            If member.Kind &lt;&gt; vsCMElement.vsCMElementFunction Then
                Continue For
            End If

            Dim method As CodeFunction = member
            If method.Prototype(prototypeFlags) = prototype Then
                Return method
            End If
        Next

        Return Nothing
    End Function

    Private Function GetInterfaceMethod(ByRef methodObject As CodeFunction) As CodeFunction
        Dim parentClass As CodeClass = methodObject.Parent
        For Each implementedInterface As CodeInterface In parentClass.ImplementedInterfaces
            If implementedInterface.InfoLocation = vsCMInfoLocation.vsCMInfoLocationProject And UseExternalInterfaceCommentsOnly Then
                Continue For
            End If
            Dim matchedMethod = GetMethod(implementedInterface, methodObject)
            If Not IsNothing(matchedMethod) Then
                Return matchedMethod
            End If
        Next
    End Function

    Private Function GetCurrentMethod() As CodeFunction
        Dim sel As TextSelection = _
            CType(DTE.ActiveDocument.Selection, TextSelection)
        Dim pnt As TextPoint = CType(sel.ActivePoint, TextPoint)

        Dim method As CodeFunction = pnt.CodeElement(vsCMElement.vsCMElementFunction)
        Return method
    End Function

    Private Sub AddCommentToMethod(ByRef methodObject As CodeFunction, ByRef newComment As String)
        If methodObject.Comment.IndexOf(newComment) &lt;&gt; -1 Then
            ' This comment has already been added
            Exit Sub
        End If
        methodObject.Comment = newComment &amp; vbNewLine &amp; methodObject.Comment
    End Sub

    Public Sub CommentImplementedMethod()
        Try
            Dim currentMethod = GetCurrentMethod()
            If IsNothing(currentMethod) Then
                MsgBox(&quot;Not inside a method scope at the moment!&quot;)
                Exit Sub
            End If

            Dim interfaceMethod = GetInterfaceMethod(currentMethod)
            If IsNothing(interfaceMethod) Then
                If UseExternalInterfaceCommentsOnly Then
                    MsgBox(&quot;*External* interface method could not be found!&quot;)
                Else
                    MsgBox(&quot;Interface method could not be found!&quot;)
                End If
                Exit Sub
            End If

            Dim newComment = GetSummaryFromDocComment(interfaceMethod.DocComment)
            AddCommentToMethod(currentMethod, newComment)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    Private Sub TraverseAndCommentImplementedMethods(ByRef elements As CodeElements)
        For Each child As CodeElement In elements
            If child.Kind = vsCMElement.vsCMElementFunction Then
                Dim currentMethod = CType(child, CodeFunction)
                If IsNothing(currentMethod) Then
                    Exit Sub
                End If

                Dim interfaceMethod = GetInterfaceMethod(currentMethod)
                If IsNothing(interfaceMethod) Then
                    Exit Sub
                End If

                Dim newComment = GetSummaryFromDocComment(interfaceMethod.DocComment)
                AddCommentToMethod(currentMethod, newComment)
            End If
            TraverseAndCommentImplementedMethods(child.Children)
        Next
    End Sub

    Public Sub CommentAllImplementedMethodsInFile()
        Try
            TraverseAndCommentImplementedMethods(DTE.ActiveDocument.ProjectItem.FileCodeModel.CodeElements)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
End Module
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/10/a-visual-studio-macro-day/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>VSTorqueScript #6</title>
		<link>http://blog.blackhc.net/2008/10/vstorquescript-6/</link>
		<comments>http://blog.blackhc.net/2008/10/vstorquescript-6/#comments</comments>
		<pubDate>Fri, 03 Oct 2008 22:35:32 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[Debug Engine]]></category>
		<category><![CDATA[TorqueScript]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=235</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/10/vstorquescript-6/" title="VSTorqueScript #6"></a>I've spent the last two days working on the Debug Engine and I've made some progress: Tracepoint Support Breakpoint Support Support for the Watch window (I might have enlisted this already once but now support is more complete) I'm not &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/10/vstorquescript-6/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/10/vstorquescript-6/" title="VSTorqueScript #6"></a><p>I've spent the last two days working on the Debug Engine and I've made some progress:</p>
<ul>
<li>Tracepoint Support</li>
<li>Breakpoint Support</li>
<li>Support for the Watch window (I might have enlisted this already once but now support is more complete)</li>
</ul>
<p>I'm not going to post any screenshots this time, instead I'll try to create an alpha package for you to test. This will probably take some time, too, because I want to make sure that you can install and uninstall it cleanly. I've been using the experimental hive so far, so I have to make sure it doesn't corrupt anyone's installation accidentially... <img src='http://blog.blackhc.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>A few implementation notes for interested people as always:</p>
<ul>
<li>If you ever have to <a title="What is Marshalling?" href="http://bytes.com/forum/thread239603.html" target="_blank">marshal</a> an object to an <strong>IntPtr</strong>, be very careful, because doing the wrong thing will certainly crash your application - <em>I had that happen to me and it took me quite some time to figure out why Visual Studio was suddenly  'experiencing internal problems' and had to be closed'</em> <em>all the time</em>:<br />
When you have to convert an IntPtr to a wrapped object, use</p>
<pre class="brush: csharp; title: ; notranslate">
MyObject = (MyType) GetObjectFromIUnknown( intPtr ); // or As MyType;
</pre>
<p>As you see, the intPtr is a COM object and every COM object implements IUnknown, so the call is pretty safe. The conversion afterwards is already 'managed', so safe, too.<br />
If you want to convert an IntPtr from an object, you have to be more careful though. The <strong>Marshal</strong> namespace offers at least two methods for it:</p>
<ul>
<li>
<pre class="brush: csharp; title: ; notranslate">
public static IntPtr GetComInterfaceForObject(
	Object o,
	Type T
)
</pre>
</li>
<li>
<pre class="brush: csharp; title: ; notranslate">
public static IntPtr GetIUnknownForObject(
	Object o
)
</pre>
</li>
</ul>
<p><strong>Don't use the latter for anything except if you really need an <em>IUnknown </em>interface <em>IntPtr </em>pointer!<br />
</strong>The method really only returns a pointer to the <em>IUnknown </em>interface of the object, which usually isn't what the unmanaged code expects - which probably will result in misinterpreting some uninitialized memory as a <strong>vtable </strong>that is <em>not</em> there.<br />
You have to use <strong>GetComInterfaceForObject </strong>and don't forget this. Because you're only working with <em>IntPtrs </em>in the end, there is nothing to warn you about your misstep.</li>
<li>If you want to use an object with <strong>System.Collection.Generic.Dictionary&lt;K,V&gt;</strong>, it's not sufficient to implement <strong>IEquatable&lt;K&gt; </strong>as stated in the documentation - you also have to override <strong>GetHashCode</strong> (<em>and override the normal <strong>Equals</strong>, too, then while you're at it</em>), because <strong>Dictionary </strong>uses <strong>GetHashCode </strong>for the bucket assignments and you can implement <strong>IEquatable </strong>as hard as you want, <strong>GetHashCode </strong>might simply assign two 'equal' objects to different buffers and you have a problem..</li>
<li>One of the benefits of COM is that no one cares about your implementation.. take advantage of it!<br />
I had to remember this the hard way, when I implemented my breakpoint code. At first I wrote a <strong>PendingBreakpoint </strong>class, which implemented <strong>IDebugPendingBreakpoint2</strong>, and then a <strong>BoundBreakpoint </strong>one, which implemented <strong>IDebugBoundBreakpoint2</strong>. It was unnecessary messy and today I sighed and rewrote the breakpoint code to use just one <strong>Breakpoint </strong>class that implements both interfaces and it's a lot more elegant now.</li>
<li>Funny fact: An enum that is even mentioned in MSDN and the SDK docs is missing from the <em>Interops</em> library:
<pre class="brush: csharp; title: ; notranslate">
public enum enum_BP_UNBOUND_REASON
{
    BPUR_UNKNOWN = 0x0000,
    BPUR_CODE_UNLOADED = 0x0002,
    BPUR_BREAKPOINT_REBIND = 0x0003,
    BPUR_BREAKPOINT_ERROR = 0x0004
};
</pre>
</li>
<li>The initialization process for the DE is as follows:
<ol>
<li>DebugEngine and Program Creation Events</li>
<li>Load Complete Event</li>
<li>Call CreatePendingBreakpoint for all known breakpoints</li>
<li>First Continue Call</li>
<li>Entry Point Event</li>
<li>Either the second Continue call or the SDM enters break mode</li>
</ol>
</li>
</ul>
<p>I had to write a few wrapper classes, too, which I might post about next time around. It's enough for today though.</p>
<p>Cheers,<br />
Black</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/10/vstorquescript-6/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>VSTorqueScript #5.1</title>
		<link>http://blog.blackhc.net/2008/09/vstorquescript-51/</link>
		<comments>http://blog.blackhc.net/2008/09/vstorquescript-51/#comments</comments>
		<pubDate>Mon, 29 Sep 2008 09:04:30 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[Message Sending]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=221</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/vstorquescript-51/" title="VSTorqueScript #5.1"></a>Sadly there isn't a lot new that I can post since I've hardly had time to work on my pet project during the last week - a few friends from Texas and California came over for the Oktoberfest and it &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/vstorquescript-51/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/vstorquescript-51/" title="VSTorqueScript #5.1"></a><p>Sadly there isn't a lot new that I can post since I've hardly had time to work on my pet project during the last week - a few friends from Texas and California came over for the Oktoberfest and it suffices to say that I drank a lot of beer last week.</p>
<p>Nonetheless there is some progress and I've finished support for stepping in break mode (although I still have no idea what enum_STEPKIND.STEP_BACKWARDS is about, since I've never heard of stepping <em><strong>backwards</strong></em> before).</p>
<p>There is no screenshot this time because you wouldn't really see a difference, except if I did, before/after screenshots to show that the stepping works.</p>
<p>A few coding notes as always:</p>
<ul>
<li>The current TorqueScript telnet debugger doesn't really tell you whether it breaks because of stepping or because it has hit a breakpoint, so I have to figure it myself. It is pretty straightforward though because stepping usually implies a certain callstack change (or the lack thereof) when finished:
<ul>
<li>"Step Into" implies that the new callstack height &gt; old height</li>
<li>"Step Over" implies no change</li>
<li>"Step Out" implies of course: new callstack height &lt; old height</li>
</ul>
<p>So it's pretty easy to figure out whether the stepping was finished or interrupted by a breakpoint.</li>
<li>The class diagram designer/viewer in Visual Studio 200x is awesome. If you haven't tried it, you've missed a really helpful feature of Visual Studio.<br />
Lately I've been using it to comment my public functions and parameters, etc. and for small refactorings (like name changes) in general.</li>
</ul>
<p>Last but not least I think I've written a neat communication class for synchronous and asynchronous message processing which I'd like to share (<strong><em>if you're going to use it though, please tell me and/or send me some feedback</em></strong>):</p>
<p><span id="more-120"></span></p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace BlackHC.VSTorqueScript.DebugEngine
{
    class Communication
    {
        [Flags]
        public enum ReturnAction
        {
            ContinueSearch = 0,
            AcceptMessage = 1,
            RemoveHandler = 2,
            Done = AcceptMessage | RemoveHandler
        }

        /// &lt;summary&gt;
        /// Delegate Communication will call to send a message
        /// &lt;/summary&gt;
        public delegate void SendMessageDelegate(string message);
        /// &lt;summary&gt;
        /// Delegate which Communication will call to read a message
        /// &lt;/summary&gt;
        public delegate string ReadMessageDelegate();

        public delegate void ReplyMessageHandler(string message);
        public delegate ReturnAction MessageHandler(Communication sender, string message);

        /// &lt;summary&gt;
        /// Events in this list are invoked in reverse order (to allow FILO-style message handler processing).
        /// Lock MessageHandlers when adding message handlers
        /// &lt;/summary&gt;
        public event MessageHandler MessageHandlers;

        private readonly ReadMessageDelegate ReadMessage;
        private readonly SendMessageDelegate SendMessage;

        private Thread asyncMessageReceiver;
        private object asyncLock = new object();

        /// &lt;param name=&quot;readMessage&quot;&gt;Delegate to read messages from&lt;/param&gt;
        /// &lt;param name=&quot;sendMessage&quot;&gt;Delegate to send messages with&lt;/param&gt;
        public Communication(ReadMessageDelegate readMessage, SendMessageDelegate sendMessage)
        {
            ReadMessage = readMessage;
            SendMessage = sendMessage;
        }

        /// &lt;summary&gt;
        /// Start processing incoming messages by starting the asynchronous processing thread
        /// &lt;/summary&gt;
        public void StartReceiving()
        {
            if (asyncMessageReceiver == null)
            {
                asyncMessageReceiver = new Thread(ReceiveMessages);
                asyncMessageReceiver.Start();
            }
        }

        /// &lt;summary&gt;
        /// End the asynchronous receiver thread
        /// &lt;/summary&gt;
        public void Close()
        {
            if (asyncMessageReceiver != null)
            {
                asyncMessageReceiver.Abort();
            }
        }

        /// &lt;summary&gt;
        /// Send a simple message
        /// &lt;/summary&gt;
        public void Send(string message)
        {
            SendMessage(message);
        }

        /// &lt;summary&gt;
        /// Send a request and wait for a reply that starts with the expected string. Time-out after a specified period of time
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;request&quot;&gt;Request to send&lt;/param&gt;
        /// &lt;param name=&quot;replyStartsWith&quot;&gt;Start of the reply to wait for&lt;/param&gt;
        /// &lt;param name=&quot;millisecondsTimeout&quot;&gt;Timeout time in msecs (-1 for infinite)&lt;/param&gt;
        /// &lt;param name=&quot;timedOut&quot;&gt;Out variable to be set depending of whether the request timed-out or not&lt;/param&gt;
        /// &lt;returns&gt;remaining part of the found message (after the replyStartsWith part)&lt;/returns&gt;
        public string SyncRequest(string request, string replyStartsWith, int millisecondsTimeout, out bool timedOut)
        {
            AutoResetEvent waitHandler = new AutoResetEvent(false);
            String reply = &quot;&quot;;

            MessageHandler handler = delegate(Communication sender, string message)
            {
                if (message.StartsWith(replyStartsWith))
                {
                    reply = message.Substring(replyStartsWith.Length);
                    waitHandler.Set();
                    return ReturnAction.Done;
                }
                else
                {
                    return ReturnAction.ContinueSearch;
                }
            };

            lock (asyncLock)
            {
                Send(request);
                MessageHandlers += handler;
            }

            timedOut = waitHandler.WaitOne(millisecondsTimeout, false);
            if (!timedOut)
            {
                // remove the handler again, since we timed-out
                lock (asyncLock)
                {
                    MessageHandlers -= handler;
                }
            }
            return reply;
        }

        public string SyncRequest(string request, string replyStartsWith, int millisecondsTimeout)
        {
            bool timedOut;
            return SyncRequest(request, replyStartsWith, millisecondsTimeout, out timedOut);
        }

        // TODO: add a time-out here, too? [9/18/2008 Andreas]
        /// &lt;summary&gt;
        /// Starts an asynchronous request.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;request&quot;&gt;Message request to be sent&lt;/param&gt;
        /// &lt;param name=&quot;replyStartsWith&quot;&gt;Start of the reply to wait for&lt;/param&gt;
        /// &lt;param name=&quot;replyMessageHandler&quot;&gt;Message handler that is passed the rest of the message (after the replyStartsWith part)&lt;/param&gt;
        public void AsyncRequest(string request, string replyStartsWith, ReplyMessageHandler replyMessageHandler)
        {
            MessageHandler handler = delegate(Communication sender, string message)
            {
                if (message.StartsWith(replyStartsWith))
                {
                    string reply = message.Substring(replyStartsWith.Length);
                    replyMessageHandler(reply);
                    return ReturnAction.Done;
                }
                else
                {
                    return ReturnAction.ContinueSearch;
                }
            };

            lock (asyncLock)
            {
                Send(request);
                MessageHandlers += handler;
            }
        }

        private void ReceiveMessages()
        {
            while (true)
            {
                try
                {
                    string message;
                    try
                    {
                        message = ReadMessage();
                    }
                    catch (System.Exception)
                    {
                        // the connection has been closed or something similar has happened, so terminate the thread
                        return;
                    }

                    if (message != null)
                    {
                        ProcessMessage(message);
                    }
                    else
                    {
                        // lost connection, terminate the thread, too
                        return;
                    }

                }
                catch (System.Exception e)
                {
                    // don't let Visual studio die here
                    Trace.WriteLine(&quot;Exception in ReceiveMessages: &quot; + e.ToString());
                }
            }
        }

        private void ProcessMessage(string message)
        {
            if (MessageHandlers != null)
            {
                System.Delegate[] invocationList;
                lock (asyncLock)
                {
                    invocationList = (System.Delegate[])MessageHandlers.GetInvocationList().Clone();
                }

                foreach (System.Delegate eventDelegate in invocationList.Reverse())
                {
                    MessageHandler handler = (MessageHandler)eventDelegate;

                    ReturnAction action = handler.Invoke(this, message);
                    if ((action &amp; ReturnAction.RemoveHandler) != 0)
                    {
                        // FIXME: is this lock necessary? [9/18/2008 Andreas]
                        lock (asyncLock)
                        {
                            MessageHandlers -= handler;
                        }
                    }
                    if ((action &amp; ReturnAction.AcceptMessage) != 0)
                    {
                        break;
                    }
                }
            }
            else
            {
                Trace.WriteLine(String.Format(&quot;Communication: Unhandled message - '{0}'&quot;, message));
            }
        }
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/vstorquescript-51/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>VSTorqueScript #5</title>
		<link>http://blog.blackhc.net/2008/09/vstorquescript-5/</link>
		<comments>http://blog.blackhc.net/2008/09/vstorquescript-5/#comments</comments>
		<pubDate>Wed, 17 Sep 2008 10:53:50 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Personal Rantings]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[Debug Engine]]></category>
		<category><![CDATA[TorqueScript]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=212</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/vstorquescript-5/" title="VSTorqueScript #5"></a>It took me quite long to make progess in the last days. Partially this is due me being in Munich again and working in my uni job part-time again - and I'm stunned each time how tired I am when &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/vstorquescript-5/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/vstorquescript-5/" title="VSTorqueScript #5"></a><p>It took me quite long to make progess in the last days. Partially this is due me being in Munich again and working in my uni job part-time again - and I'm stunned each time how tired I am when I come home.</p>
<p>It also is due to me experimenting with my <em>TelnetDebuggerClient</em> implementation that connects my debug engine to Torque's Telnet Debugger. I've tried quite a few different approaches for synchronous and asynchronous communication before I could settle for the simplest and the more advanced ones reside in the repository's history. I'll probably have to switch to them sooner or later because I only implement asynchronous communication at the moment which is fine for most things except when you need more advanced debugging info like for displaying objects properly in the debug window for example.</p>
<p>I've also had to read the "<a title="Page for the Book on the Pragmatic Programmer" href="http://pragprog.com/titles/tpantlr/the-definitive-antlr-reference" target="_blank">Definitive ANTLR Reference</a>" in one night because I had to return it to uni's library the next day, so I was busy for 7 hours reading 350 pages of a parser reference. It was interesting though and tonight I'll try to write a QuakeC grammar - that's the plan at least.</p>
<p>However yesterday, I had time to work on the debug engine some more and here's a picture that tells it all:</p>
<div id="attachment_213" class="wp-caption alignnone" style="width: 560px"><a href="http://blog.blackhc.net/wp-content/uploads/2008/09/callstack1.jpg"><img class="size-full wp-image-213" title="Callstack" src="http://blog.blackhc.net/wp-content/uploads/2008/09/callstack1.jpg" alt="VSTorqueScript now supports displaying the callstack, too" width="550" height="325" /></a><p class="wp-caption-text">VSTorqueScript now supports displaying the callstack, too</p></div>
<p>As you see you can now break a program and it will retrieve the callstack from Torque and update the callstack window automatically and open the right file and jump to the correct file position, too - <em>or rather as I've just noticed one-line off because VS line indicies have base 0 and TorqueScript uses base 1 &gt;_&gt;...</em></p>
<p>A few implementation notes as always:</p>
<ul>
<li>I t seems, if your<em> Debug Engine</em> doesn't implement <strong><em>IDebugEngineLaunch2</em></strong>, your <em>Program Provider</em> has to implement <em><strong>IDebugProgramProvider2.WatchForProviderEvents</strong></em></li>
<li>
<div>Moreover, if you don't implement <strong><em>IDebugEngineLaunch2</em></strong>, which in turn forces you to implement <em><strong>IDebugProcess2 </strong></em>(and maybe <em><strong>IDebugProcess3</strong></em>, too), suddenly some "deprecated" methods in your Program class (your <em><strong>IDebugProgram2</strong></em> implementation) will be called, which, if you follow MSDN and the debug engine sampe, will result in failed asserts and the nice fail message <em>"This function is not called by the debugger." </em> <img src='http://blog.blackhc.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
It's kind of logical that <em><strong>IDebugProgram2.Execute()</strong></em> is going to be called because the debugger has no <em><strong>IDebugProcess2 </strong></em>interface to call <em>Execute </em>on..</div>
</li>
<li>What is <strong><em>enum_FRAMEINFO_FLAGS_VALUES</em></strong>? It's undocumented and I suspect it's used for the undocumented <em><strong>m_dwFlags</strong></em> field in <em><strong>FRAMEINFO</strong></em>...</li>
<li>I'm totally stunned by how <strong>stable</strong> Visual Studio is. Most the interfaces I implement are only half implemented and return E_NOTIMPL on most calls and Visual Studio runs and runs well and only displays the information it can in a clean way.<br />
I guess this is one of the advantages of the <em>COM programming/design paradigma</em> and I think it's great. Being able to implement interfaces bit by bit and add functionality slowly makes debugging easier and also helps you understand things better - which is good because even though a lot is documented, you still need some practice and trial &amp; error to get things right eventually.</li>
</ul>
<p>Enough is enough though for now, and I'll head to uni in a bit.</p>
<p>Only one last remark: I've started reading the book "<a title="Page for the Book on the Pragmatic Programmer" href="http://www.pragprog.com/the-pragmatic-programmer" target="_blank">The Pragmatic Programmer</a>" and so far it's really entertaining and, I guess, good.<br />
I'll write more on it, when I've finished it and can actually assess its qualities..</p>
<p>Cheers,<br />
Andreas</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/vstorquescript-5/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>VSTorqueScript #4</title>
		<link>http://blog.blackhc.net/2008/09/vstorquescript-4/</link>
		<comments>http://blog.blackhc.net/2008/09/vstorquescript-4/#comments</comments>
		<pubDate>Fri, 12 Sep 2008 00:46:05 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[Debug Engine]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=201</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/vstorquescript-4/" title="VSTorqueScript #4"></a>My little pet project is actually called VSTorqueScript, so I've decided to use the correct title for my posts, too. Today has been a somewhat productive day, although not as productive as I've hoped, because I was stuck with a &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/vstorquescript-4/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/vstorquescript-4/" title="VSTorqueScript #4"></a><p>My little pet project is actually called <strong>VSTorqueScript</strong>, so I've decided to use the correct title for my posts, too.</p>
<p>Today has been a somewhat productive day, although not as productive as I've hoped, because I was stuck with a <a title="My Stupid Issue" href="http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/877e1933-e285-4d47-b268-9f3a23778c66" target="_blank">very stupid issue</a> for 3 or 4 hours. I'm not proud of it, but it made me go to the <a title="Visual Studio Extensiblity Forum" href="http://social.msdn.microsoft.com/Forums/en-US/vsx/threads/" target="_blank">VSX forum</a> and become <a title="Yay, I can help people, too \o/" href="http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/d7890a3c-5945-40dc-8f39-66dbbe3e7f3a" target="_blank">active</a> there.</p>
<p>I've worked more on the debug engine afterwards (well, actually I went jogging and swimming - <em>in that order.. think about it </em>) and made some progress. Quite a bit of the stub stuff is implemented now and I think I'll start implementing the real thing tomorrow.</p>
<p>No screenshots this time, I'm sorry, but for the SDK users, I have a little helper file. If you look at the managed debug example, you'll find an <em>AD7Events </em>file that wraps the debug event interfaces.<br />
I wasn't easily able to port it over, so I decided to write my own version of it (while keeping the comments).</p>
<p>I've appended it to the post, if you want to take a look.</p>
<p>On other news I'll probably switch this blog over to my own webspace soon to get some advantages (like expandable sourcecode amongst things), but I think I'll stick to wordpress.com for a few more weeks.<br />
It's really a pity that you can't redirect from wordpress to your domain, but only vice-versa <img src='http://blog.blackhc.net/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p>
<p>Anyway, off to work some more on my code.</p>
<p>Cheers,<br />
Andreas</p>
<p><span id="more-116"></span><br />
Here it is:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Debugger.Interop;
using Microsoft.VisualStudio;

namespace BlackHC.VSTorqueScript.DebugEngine
{
    #region Event base classes

    interface IEvent : IDebugEvent2
    {
        uint Attributes
        {
            get;
        }

        Guid IID
        {
            get;
        }
    }

    abstract class Event&lt;ieventType&gt; : IEvent where IEventType : class
    {
        public Guid IID
        {
            get { return typeof(IEventType).GUID; }
        }

        public int GetAttributes(out uint eventAttributes)
        {
            eventAttributes = Attributes;
            return VSConstants.S_OK;
        }

        public abstract uint Attributes
        {
            get;
        }
    }

    class AsynchronousEvent&lt;ieventType&gt; : Event&lt;ieventType&gt; where IEventType : class
    {
        public override uint Attributes
        {
            get { return (uint)enum_EVENTATTRIBUTES.EVENT_ASYNCHRONOUS; }
        }
    }

    class SynchronousEvent&lt;ieventType&gt; : Event&lt;ieventType&gt; where IEventType : class
    {
        public override uint Attributes
        {
            get { return (uint)enum_EVENTATTRIBUTES.EVENT_SYNCHRONOUS; }
        }
    }

    class StoppingEvent&lt;ieventType&gt; : Event&lt;ieventType&gt; where IEventType : class
    {
        public override uint Attributes
        {
            get { return (uint)enum_EVENTATTRIBUTES.EVENT_ASYNC_STOP; }
        }
    }

    #endregion

    #region Event classes

    /// &lt;summary&gt;
    /// The debug engine (DE) sends this interface to the session debug manager (SDM) when an instance of the DE is created.
    /// &lt;/summary&gt;
    sealed class EngineCreateEvent : AsynchronousEvent&lt;idebugEngineCreateEvent2&gt;, IDebugEngineCreateEvent2
    {
        private IDebugEngine2 engine;

        public EngineCreateEvent(IDebugEngine2 engine)
        {
            this.engine = engine;
        }

        #region IDebugEngineCreateEvent2 Members

        public int GetEngine(out IDebugEngine2 pEngine)
        {
            pEngine = engine;
            return VSConstants.S_OK;
        }

        #endregion
    }

    /// &lt;summary&gt;
    /// This interface is sent by the debug engine (DE) to the session debug manager (SDM) when a program is attached to.
    /// &lt;/summary&gt;
    sealed class ProgramCreateEvent : AsynchronousEvent&lt;idebugProgramCreateEvent2&gt;, IDebugProgramCreateEvent2
    {
    }

    /// &lt;summary&gt;
    /// This interface is sent by the debug engine (DE) to the session debug manager (SDM) when a module is loaded or unloaded.
    /// &lt;/summary&gt;
    sealed class ThreadCreateEvent : AsynchronousEvent&lt;idebugThreadCreateEvent2&gt;, IDebugThreadCreateEvent2
    {
    }

    /// &lt;summary&gt;
    /// This interface is sent by the debug engine (DE) to the session debug manager (SDM) when a program is loaded, but before any code is executed.
    /// &lt;/summary&gt;
    sealed class LoadCompleteEvent : StoppingEvent&lt;idebugLoadCompleteEvent2&gt;, IDebugLoadCompleteEvent2
    {
    }

    /// &lt;summary&gt;
    /// This interface is sent by the debug engine (DE) to the session debug manager (SDM) when a thread has exited.
    /// &lt;/summary&gt;
    sealed class ThreadDestroyEvent : StoppingEvent&lt;idebugThreadDestroyEvent2&gt;, IDebugThreadDestroyEvent2
    {
        private uint exitCode;

        public ThreadDestroyEvent(uint exitCode)
        {
            this.exitCode = exitCode;
        }

        #region IDebugThreadDestroyEvent2 Members

        public int GetExitCode(out uint pdwExit)
        {
            pdwExit = exitCode;
            return VSConstants.S_OK;
        }

        #endregion
    }

    /// &lt;summary&gt;
    /// This interface is sent by the debug engine (DE) to the session debug manager (SDM) when a program has run to completion
    /// or is otherwise destroyed.
    /// &lt;/summary&gt;
    sealed class ProgramDestroyEvent : StoppingEvent&lt;idebugProgramDestroyEvent2&gt;, IDebugProgramDestroyEvent2
    {
        private uint exitCode;

        public ProgramDestroyEvent(uint exitCode)
        {
            this.exitCode = exitCode;
        }

        #region IDebugProgramDestroyEvent2 Members

        public int GetExitCode(out uint pdwExit)
        {
            pdwExit = exitCode;
            return VSConstants.S_OK;
        }

        #endregion
    }

    #endregion

    /// &lt;summary&gt;
    /// Extensions for IDebugEventCallback2 implementations
    /// &lt;/summary&gt;
    static class IDebugEventCallback2Extension
    {
        static internal int Event(this IDebugEventCallback2 pCallback, IDebugEngine2 pEngine, IDebugProgram2 pProgram, IDebugThread2 pThread, IEvent pEvent)
        {
            Guid iid = pEvent.IID;
            return pCallback.Event(pEngine, null, pProgram, pThread, pEvent, ref iid, pEvent.Attributes);
        }
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/vstorquescript-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visual TorqueScript #3.75</title>
		<link>http://blog.blackhc.net/2008/09/visual-torquescript-375/</link>
		<comments>http://blog.blackhc.net/2008/09/visual-torquescript-375/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 10:55:44 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[custom project]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=196</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-375/" title="Visual TorqueScript #3.75"></a>Another minor update, which I'm mostly using to publish a useful patch. I've forgotten to mention that I've already created a custom settings page for my Visual TorqueScript projects. Yesterday night (before going to bed) I decided to add a &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/visual-torquescript-375/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-375/" title="Visual TorqueScript #3.75"></a><p>Another minor update, which I'm mostly using to publish a useful patch.<br />
I've forgotten to mention that I've already created a custom settings page for my Visual TorqueScript projects. Yesterday night (before going to bed) I decided to add a configuration dependent page, too.<br />
As you'll see it's very <em>Torsion-esque</em>, which is intentional and I plan to support .torsion files directly (as project files) later-on.</p>
<p>The main reason is that Torsion rocks and there is no reason to have yet another project file format for TorqueScript projects.</p>
<p>I hope that it will also be an incentive for people to give my plugin a try (if I ever release it).</p>
<p><a href="http://blog.blackhc.net/wp-content/uploads/2008/09/settingspage.jpg"><img class="alignnone size-large wp-image-197" title="Settings Page" src="http://blog.blackhc.net/wp-content/uploads/2008/09/settingspage.jpg?w=550" alt="" width="550" height="325" /></a></p>
<p>A few notes (<em>programatically</em> so to speak <img src='http://blog.blackhc.net/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> ):</p>
<ul>
<li>Again the managed project framework is awesome and once you figure out where to look for things you'll certainly find eternal bliss, too..</li>
<li>I generally derive from <em>SettingsPage</em> directly, because I don't want any of the regular faff in my project.</li>
<li>Don't forget to publish your pages via <em>ProvideObject </em>(or <em>ProvideClass</em> from my previous post)</li>
<li>You don't need to create your own GUIDs for everything. Classses are automatically provided with a unique GUID - try it and access <em>typeof(SomeClassWithoutGuidAttribute).GUID</em> and it'll still work.<br />
<strong>(If I said something wrong, please correct me..)</strong></li>
<li><em>SettingsPage </em>has an <em>IsDirty </em>property which you have to set, when a property is changed (to update the Apply button state).<br />
It results in pretty ugly copy'n'paste code, because you can't use default property accessors anymore.<br />
To fix this I spent an hour or two and I've come up with an elegant (in my opinion) patch to fix the issue:</p>
<pre class="brush: csharp; title: ; notranslate">
Index: ProjectBase/SettingsPage.cs
===================================================================
--- ProjectBase/SettingsPage.cs	(revision 10)
+++ ProjectBase/SettingsPage.cs	(working copy)
@@ -27,7 +27,26 @@

 namespace Microsoft.VisualStudio.Package
 {
+    // Added to make it easier to edit pages [9/10/2008 Andreas]

+    class SettingsPagePropertyDescriptor : DesignPropertyDescriptor
+    {
+        public SettingsPagePropertyDescriptor(PropertyDescriptor prop)
+            : base(prop)
+        {
+        }
+
+        public override void SetValue(object component, object value)
+        {
+            if (component is SettingsPage)
+            {
+                SettingsPage page = (SettingsPage)component;
+                page.IsDirty = true;
+            }
+            base.SetValue(component, value);
+        }
+    }
+
     /// &lt;summary&gt;
     /// The base class for property pages.
     /// &lt;/summary&gt;
@@ -78,7 +97,7 @@
             get { return this.grid; }
         }

-        protected bool IsDirty
+        protected internal bool IsDirty
         {
             get
             {
@@ -203,6 +222,13 @@

         #endregion

+        #region overriden methods.
+        public override DesignPropertyDescriptor CreateDesignPropertyDescriptor(PropertyDescriptor propertyDescriptor)
+        {
+            return new SettingsPagePropertyDescriptor(propertyDescriptor);
+        }
+        #endregion
+
         #region IPropertyPage methods.
         public virtual void Activate(IntPtr parent, RECT[] pRect, int bModal)
         {
@@ -410,6 +436,8 @@
                 try
                 {
                     Marshal.WriteIntPtr(ppUnk, p);
+                    // Reset IsDirty before rebinding all properties [9/10/2008 Andreas]
+                    IsDirty = false;
                     this.BindProperties();
                     // BUGBUG -- this is really bad casting a pointer to &quot;int&quot;...
                     this.grid.SetSelectedObjects(1, ppUnk.ToInt32());
</pre>
<p>It also contains a one-line fix to reset IsDirty when reloading the page or switching configurations (ie. any time the properties are reset to their old value).</li>
</ul>
<p>Cheers,<br />
Black</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/visual-torquescript-375/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visual TorqueScript #3.5</title>
		<link>http://blog.blackhc.net/2008/09/visual-torquescript-35/</link>
		<comments>http://blog.blackhc.net/2008/09/visual-torquescript-35/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 22:52:30 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Custom Attribute]]></category>
		<category><![CDATA[Debug Engine]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=191</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-35/" title="Visual TorqueScript #3.5"></a>Small update: After hours and hours of error and trial (and implementing a few interfaces by using Copy&#38;Paste wisely), I've finally managed to get Visual Studio to load my debug engine. This looks gorgeous, doesn't it? A few notes for &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/visual-torquescript-35/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-35/" title="Visual TorqueScript #3.5"></a><p>Small update: After hours and hours of error and trial (and implementing a few interfaces by using Copy&amp;Paste wisely), I've finally managed to get Visual Studio to load my debug engine.</p>
<p>This looks gorgeous, doesn't it?</p>
<p><a href="http://blog.blackhc.net/wp-content/uploads/2008/09/deregistered.jpg"><img class="alignnone size-full" title="TorqueScript Debug Engine " src="http://blog.blackhc.net/wp-content/uploads/2008/09/deregistered.jpg?w=545" alt="" width="550" height="324" /></a></p>
<p>A few notes for those interested in writing Debug Engines:</p>
<ul>
<li>See my previous post for the ProvideDebugEngine helper attribute</li>
<li>There exists a really nice <strong>managed debug engine example</strong>, that isn't part of the SDK.<br />
You can find it <a title="Visual Studio Debug Engine Sample" href="http://code.msdn.microsoft.com/debugenginesample" target="_blank">here</a>.</li>
<li>You are <strong>required</strong> to set a PortSupplier, even if the documentation says otherwise (this was a major source of frustration in the last hour).</li>
<li>Since <em>ProvideDebugEngine </em>requires a Type for <em>PortSupplier</em>, I've been using this stub class:
<pre class="brush: csharp; title: ; notranslate">
    /// &lt;summary&gt;
    /// The class is just a stub for use with ProvideDebugEngine.
    /// It seems it's mandatory to provide a PortSupplier GUID with a debug engine.
    /// &lt;/summary&gt;
    [Guid(&quot;708C1ECA-FF48-11D2-904F-00C04FA302A1&quot;)]
    internal sealed class DefaultPortSupplier
    {
    }
</pre>
</li>
<li>I've also added another attribute (<em>ProvideClass</em>) for convenience to register a class directly (it's the same as using <em>ProvideObject </em>on the current class type).<br />
Since the code is quite short, I'm going to supply it directly:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Microsoft.VisualStudio.Shell
{
    /// &lt;summary&gt;
    /// This is just a wrapper for ProvideObject to provide the class the attribute is used on
    /// &lt;/summary&gt;
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    class ProvideClass : RegistrationAttribute
    {
        public override void Register(RegistrationAttribute.RegistrationContext context)
        {
            ProvideObjectAttribute objectProvider = new ProvideObjectAttribute(context.ComponentType);
            objectProvider.Register(context);
        }

        public override void Unregister(RegistrationAttribute.RegistrationContext context)
        {
            ProvideObjectAttribute objectProvider = new ProvideObjectAttribute(context.ComponentType);
            objectProvider.Unregister(context);
        }
    }
}
</pre>
</li>
</ul>
<p>And yes, I love the  tag <img src='http://blog.blackhc.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
Cheers,<br />
Andreas</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/visual-torquescript-35/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Visual TorqueScript #3</title>
		<link>http://blog.blackhc.net/2008/09/visual-torquescript-3/</link>
		<comments>http://blog.blackhc.net/2008/09/visual-torquescript-3/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 16:24:55 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Custom Attribute]]></category>
		<category><![CDATA[Debug Engine]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=186</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-3/" title="Visual TorqueScript #3"></a>I've spent a part of the last two days cursing the managed project framework (it's a bliss, too, and I'm thankful that it's available at the same time), because it is too different from what I need, and I'll probably &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/visual-torquescript-3/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-3/" title="Visual TorqueScript #3"></a><p>I've spent a part of the last two days cursing the managed project framework (it's a bliss, too, and I'm thankful that it's available at the same time), because it is too different from what I need, and I'll probably end up rewriting most of it to use different approaches and not use <em>MSBuild </em>anymore.</p>
<p>I've spent more time, however, on reading up on <em>Debug Engines</em> in <em>Visual Studio 2008</em> and I've started work on my own yesterday. To be honest, I haven't really started to work on it, I've rather spent the evening and most of today figuring out how to register a debug engine at all and write attributes for that, so that it becomes an automated process, just like it's done for <em>Packages </em>and <em>Language Services</em> by using attributes like ProvidePackage and ProvideLanguageService.</p>
<p>The code has turned out pretty nicely and now you can use the attributes like this, for example, to register a debg engine:</p>
<pre class="brush: csharp; title: ; notranslate">
    [ProvideDebugEngine(&quot;{5887F58F-3B7F-401d-95CE-A7BADA1E4D7D}&quot;, &quot;TorqueScript Debug Engine&quot;,
        Attach = true, ProgramProvider = typeof(VSTorqueScript_DebugEngine))]
    [ProvideIncompatibleEngineInfo( &quot;{5887F58F-3B7F-401d-95CE-A7BADA1E4D7A}&quot; )]
    [ProvideIncompatibleEngineInfo( &quot;{5887F58F-3B7F-401d-95CE-A7BADA1E4D7F}&quot; )]
    [ProvideAutoSelectIncompatibleEngineInfo( &quot;{5887F58F-3B7F-401d-95CE-A7BADA1E4D7F}&quot; )]
    [ProvideObject(VSTorqueScript_DebugEngine)
    [Guid(GuidList.guidVSTorqueScript_DebugEngineString)]
    public sealed class VSTorqueScript_DebugEngine
...
</pre>
<p>In my opinion this looks pretty neat - and it works.. <strong>\o/<br />
</strong>I really love the whole concept of attributes and the way they make coding a lot easier (even though it's hard to find information about useful attributes, as you only find out they exist when you stumble over them or write them on your own).</p>
<p>You can find the code here: <a title="Source Code of the Debug Engine Attributes" href="http://www.icculus.org/~black/weblog/VS_DebugEngine/" target="_blank">http://www.icculus.org/~black/weblog/VS_DebugEngine/</a></p>
<p>A few notes:</p>
<ul>
<li>The implementation was done making heavy use of copy&amp;paste and quick replace (I copied the table containing the help description of the metrics into the source file and reworked it using RE magic to look the way it does now)</li>
<li>At first I used <em>Type.GetProperties</em> to enumerate all properties and write them out into the registry but that bloated the resulting registry entry, of course. Because of this I later switched to the <em>HashTable</em> approach that I first found in SDK's implementation of <em>ProvideLanguageServiceAttribute</em>.</li>
<li>The restriction that all attribute parameters must be constant expressions forced me to make a few changes - at first I had <em>Guid </em>properties and for the incompatible engines list I expected a <em>Guid[]</em>, which didn't work. I changed the <em>Guid</em>s to <em>String</em>s and added the <em>Provide*EngineInfo</em> attributes instead of the incompatible engines list (same for the autoselect one, of course).</li>
<li>The <em>Provide*EngineInfo</em> attributes contained their registry code at first. This was ugly because they kind of required a <em>ProvideDebugEngine </em>attribute to exist, too, which I couldn't enforce. Later I changed them to be pure value holders and moved all registry code into <em>ProvideDebugEngine</em>.<br />
Now nothing happens if you don't supply a <em>ProvideDebugEngine </em>attribute, too.</li>
</ul>
<p>Now I'll try to start to work on the actual Debug Engine for TorqueScript.</p>
<p>Cheers,<br />
Andreas</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/visual-torquescript-3/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Visual TorqueScript #2</title>
		<link>http://blog.blackhc.net/2008/09/visual-torquescript-2/</link>
		<comments>http://blog.blackhc.net/2008/09/visual-torquescript-2/#comments</comments>
		<pubDate>Sun, 07 Sep 2008 00:40:21 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[custom project]]></category>
		<category><![CDATA[guidance package]]></category>
		<category><![CDATA[TorqueScript]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=183</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-2/" title="Visual TorqueScript #2"></a>I haven't found time to add IntelliSense to the language service yet, so I've only added a basic parser and enabled brace highlighting/matching which was easier to do. I've been told that a working debugger would be the most important &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/visual-torquescript-2/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-2/" title="Visual TorqueScript #2"></a><p>I haven't found time to add IntelliSense to the language service yet, so I've only added a basic parser and enabled brace highlighting/matching which was easier to do.</p>
<p>I've been told that a working debugger would be the most important feature, so I try to get started with it, but before I can do that I have to add a custom project type to support the standard .cs extension for TorqueScript and to offer a specialized debug options property page for Torque's telnet debugger.</p>
<p><a href="http://blog.blackhc.net/wp-content/uploads/2008/09/customprojecttype.jpg"><img class="alignnone size-full" title="Custom Project Type" src="http://blog.blackhc.net/wp-content/uploads/2008/09/customprojecttype.jpg" alt="" width="550" height="325" /></a></p>
<p>Here you can see the progress I've made so far:<br />
I've added a new custom project type and changed everything to support TorqueScript files that use the usual .cs extension. There is no conflict with C# whatsoever. (At least from what I know..)</p>
<p>Next I'll look into removing the MSBuild faff (if possible at all) and adding the debug configuration page.</p>
<p>Last but not least I've found another neat tool that I can only recommend and want to share with whoever might read this:<br />
It's called <strong>VSSDK Assist</strong> and it's a so-called <em>Guidance Package</em> - it provides you with a neat assistance window that helps you do common tasks using the Visual Studio SDK in the preferred way (it supplies you with lots of dialog-based wizards for all kinds of things like custom pages/tools/editors/projects/...).</p>
<p>You can grab it <a title="VSSDK Assist's Official Page" href="http://www.codeplex.com/vssdkassist" target="_blank">here</a>.</p>
<p>More to come.<br />
Cheers,<br />
Black</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/visual-torquescript-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visual TorqueScript #1</title>
		<link>http://blog.blackhc.net/2008/09/visual-torquescript-1/</link>
		<comments>http://blog.blackhc.net/2008/09/visual-torquescript-1/#comments</comments>
		<pubDate>Fri, 05 Sep 2008 12:00:05 +0000</pubDate>
		<dc:creator>BlackHC</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[GarageGames]]></category>
		<category><![CDATA[Visual Studio Extensibility]]></category>
		<category><![CDATA[TorqueScript]]></category>
		<category><![CDATA[Visual Studio SDK]]></category>

		<guid isPermaLink="false">http://blackhc.wordpress.com/?p=178</guid>
		<description><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-1/" title="Visual TorqueScript #1"></a>I've spent most of this week learning as much about Visual Studio's extensibility features as possible and I've decided to start a tiny project to see how easy it is to add a new language service to Visual Studio. My &#8230;<p class="read-more"><a href="http://blog.blackhc.net/2008/09/visual-torquescript-1/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.blackhc.net/2008/09/visual-torquescript-1/" title="Visual TorqueScript #1"></a><p>I've spent most of this week learning as much about Visual Studio's extensibility features as possible and I've decided to start a tiny project to see how easy it is to add a new language service to Visual Studio.</p>
<p>My conclusion so far is: it's not easy and that obvious but it certainly is easier than writing your own IDE. There is also the advantage that you have access to a nice debugging environment if you manage to write your own debugger service.</p>
<p>Anyway, I've started to work on adding basic support for TorqueScript to Visual Studio and after much learning, I've finished implementing the colorizer for TorqueScript today:</p>
<p><a href="http://blog.blackhc.net/wp-content/uploads/2008/09/scannertest.jpg"><img class="alignnone" title="Visual TorqueScript Syntax Highlighting" src="http://blog.blackhc.net/wp-content/uploads/2008/09/scannertest.jpg?w=640" alt="" width="640" height="480" /></a></p>
<p>As you see I have to use the extension <strong>.tscript</strong> for now, because as you know <strong>.cs</strong> is already reserved for C#. I'm going to fix this later by adding a TorqueScript project type that overrides this link locally for your TorqueScript projects (I could live with that).</p>
<p>Creating your own language services is pretty easy, if you are ok with using C# and ManagedBabel. You just have to supply the specific grammar files for the managed lexer and parser generators and you're pretty much done with the basic stuff.</p>
<p>The Visual Studio SDK is pretty neat (you can grab it from <a title="Visual Studio SDK Download Page" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=59EC6EC3-4273-48A3-BA25-DC925A45584D&amp;displaylang=en" target="_blank">here</a> if you want) and another neat thing no one has probably heard about is that Microsoft gives away the <a title="Visual Studio Shell Info Page" href="http://msdn.microsoft.com/en-us/vsx/bb933751.aspx" target="_blank">Visual Studio Shell</a> for free - yeah for free. That means you can build your own custom tools that have the Visual Studio look and feel and you don't have to pay Microsoft a dime for it.</p>
<p>A good place to start in general if you're interested is the <a title="Microsoft's VS Extensibility Center" href="http://msdn.microsoft.com/en-us/vsx/default.aspx" target="_blank">VS Extensibility Center</a>.</p>
<p>Stay tuned for more features (syntax parsing and debugging featues are the next thing on my plan).<br />
Cheers,<br />
BlackHC</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.blackhc.net/2008/09/visual-torquescript-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

