Monthly Archives: October 2008

A Visual Studio Macro Day

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 samples from Microsoft simply use the comments from MSDN on functions/methods that are part of a class's interface implementation.

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

My macro provides two methods:

  • One to add comments to all methods that are part of an interface's implementation
  • One to add comments to the method the cursor currently resides in

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.

However, I've added a configuration boolean, so this behavior can be turned off if needed.

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.

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 :)

Cheers,
Andreas

Read more »

VSTorqueScript #6

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 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... :-)

A few implementation notes for interested people as always:

  • If you ever have to marshal an object to an IntPtr, be very careful, because doing the wrong thing will certainly crash your application - 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' all the time:
    When you have to convert an IntPtr to a wrapped object, use

    MyObject = (MyType) GetObjectFromIUnknown( intPtr ); // or As MyType;
    

    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.
    If you want to convert an IntPtr from an object, you have to be more careful though. The Marshal namespace offers at least two methods for it:

    • public static IntPtr GetComInterfaceForObject(
      	Object o,
      	Type T
      )
      
    • public static IntPtr GetIUnknownForObject(
      	Object o
      )
      

    Don't use the latter for anything except if you really need an IUnknown interface IntPtr pointer!
    The method really only returns a pointer to the IUnknown interface of the object, which usually isn't what the unmanaged code expects - which probably will result in misinterpreting some uninitialized memory as a vtable that is not there.
    You have to use GetComInterfaceForObject and don't forget this. Because you're only working with IntPtrs in the end, there is nothing to warn you about your misstep.

  • If you want to use an object with System.Collection.Generic.Dictionary<K,V>, it's not sufficient to implement IEquatable<K> as stated in the documentation - you also have to override GetHashCode (and override the normal Equals, too, then while you're at it), because Dictionary uses GetHashCode for the bucket assignments and you can implement IEquatable as hard as you want, GetHashCode might simply assign two 'equal' objects to different buffers and you have a problem..
  • One of the benefits of COM is that no one cares about your implementation.. take advantage of it!
    I had to remember this the hard way, when I implemented my breakpoint code. At first I wrote a PendingBreakpoint class, which implemented IDebugPendingBreakpoint2, and then a BoundBreakpoint one, which implemented IDebugBoundBreakpoint2. It was unnecessary messy and today I sighed and rewrote the breakpoint code to use just one Breakpoint class that implements both interfaces and it's a lot more elegant now.
  • Funny fact: An enum that is even mentioned in MSDN and the SDK docs is missing from the Interops library:
    public enum enum_BP_UNBOUND_REASON
    {
        BPUR_UNKNOWN = 0x0000,
        BPUR_CODE_UNLOADED = 0x0002,
        BPUR_BREAKPOINT_REBIND = 0x0003,
        BPUR_BREAKPOINT_ERROR = 0x0004
    };
    
  • The initialization process for the DE is as follows:
    1. DebugEngine and Program Creation Events
    2. Load Complete Event
    3. Call CreatePendingBreakpoint for all known breakpoints
    4. First Continue Call
    5. Entry Point Event
    6. Either the second Continue call or the SDM enters break mode

I had to write a few wrapper classes, too, which I might post about next time around. It's enough for today though.

Cheers,
Black

Crysis notes - random

Last week I had the joy of playing and beating Crysis (you'll find out later why I emphasize that I beat it). While playing I took some notes, which I want to share with you (some might be funny facts, others might show why Crysis sucks and others could be proof for some awesomeness that you can - still? - find in the game).

First off though, this is going to contain lots and lots of spoilers, so just lemme put up a

SPOILER ALERT

sign before continuing.

Read more »