Tag Archives: Custom Attribute

Visual TorqueScript #3.5

Small update: After hours and hours of error and trial (and implementing a few interfaces by using Copy&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 those interested in writing Debug Engines:

  • See my previous post for the ProvideDebugEngine helper attribute
  • There exists a really nice managed debug engine example, that isn't part of the SDK.
    You can find it here.
  • You are required to set a PortSupplier, even if the documentation says otherwise (this was a major source of frustration in the last hour).
  • Since ProvideDebugEngine requires a Type for PortSupplier, I've been using this stub class:
        /// <summary>
        /// The class is just a stub for use with ProvideDebugEngine.
        /// It seems it's mandatory to provide a PortSupplier GUID with a debug engine.
        /// </summary>
        [Guid("708C1ECA-FF48-11D2-904F-00C04FA302A1")]
        internal sealed class DefaultPortSupplier
        {
        }
    
  • I've also added another attribute (ProvideClass) for convenience to register a class directly (it's the same as using ProvideObject on the current class type).
    Since the code is quite short, I'm going to supply it directly:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Microsoft.VisualStudio.Shell
    {
        /// <summary>
        /// This is just a wrapper for ProvideObject to provide the class the attribute is used on
        /// </summary>
        [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);
            }
        }
    }
    

And yes, I love the tag :-)
Cheers,
Andreas

Visual TorqueScript #3

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 MSBuild anymore.

I've spent more time, however, on reading up on Debug Engines in Visual Studio 2008 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 Packages and Language Services by using attributes like ProvidePackage and ProvideLanguageService.

The code has turned out pretty nicely and now you can use the attributes like this, for example, to register a debg engine:

    [ProvideDebugEngine("{5887F58F-3B7F-401d-95CE-A7BADA1E4D7D}", "TorqueScript Debug Engine",
        Attach = true, ProgramProvider = typeof(VSTorqueScript_DebugEngine))]
    [ProvideIncompatibleEngineInfo( "{5887F58F-3B7F-401d-95CE-A7BADA1E4D7A}" )]
    [ProvideIncompatibleEngineInfo( "{5887F58F-3B7F-401d-95CE-A7BADA1E4D7F}" )]
    [ProvideAutoSelectIncompatibleEngineInfo( "{5887F58F-3B7F-401d-95CE-A7BADA1E4D7F}" )]
    [ProvideObject(VSTorqueScript_DebugEngine)
    [Guid(GuidList.guidVSTorqueScript_DebugEngineString)]
    public sealed class VSTorqueScript_DebugEngine
...

In my opinion this looks pretty neat - and it works.. \o/
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).

You can find the code here: http://www.icculus.org/~black/weblog/VS_DebugEngine/

A few notes:

  • The implementation was done making heavy use of copy&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)
  • At first I used Type.GetProperties 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 HashTable approach that I first found in SDK's implementation of ProvideLanguageServiceAttribute.
  • The restriction that all attribute parameters must be constant expressions forced me to make a few changes - at first I had Guid properties and for the incompatible engines list I expected a Guid[], which didn't work. I changed the Guids to Strings and added the Provide*EngineInfo attributes instead of the incompatible engines list (same for the autoselect one, of course).
  • The Provide*EngineInfo attributes contained their registry code at first. This was ugly because they kind of required a ProvideDebugEngine attribute to exist, too, which I couldn't enforce. Later I changed them to be pure value holders and moved all registry code into ProvideDebugEngine.
    Now nothing happens if you don't supply a ProvideDebugEngine attribute, too.

Now I'll try to start to work on the actual Debug Engine for TorqueScript.

Cheers,
Andreas