Rants, rambles, news and notes from another geek

Annoying COM Interop Problem

Yesterday I discovered something annoying about COM Interop from C# (I don’t know if this applies to VB.NET or not).

I was working my way through one of the Office 2K3 Smart Documents tutorials, which was written for VB6, when I ran across this line on VB code:

Dim strText As String
strText = objDoc.SmartTags.Item _
&nbsp_place_holder;&nbsp_place_holder;&nbsp_place_holder; (Index:=SMARTDOC).SmartTagActions.Item _
&nbsp_place_holder;&nbsp_place_holder;&nbsp_place_holder; (Index:=SMARTDOC & _
&nbsp_place_holder;&nbsp_place_holder;&nbsp_place_holder; SMARTDOC_TEXTBOX).TextboxText

Now, I assumed that I would be able to type the following C# code:

string text = TheDocument.SmartTags[SMARTDOC].SmartTagActions[SMARTDOC + SMARTDOC_TEXTBOX].TextboxText;

The most interesting thing is that the VS.NET Intellisense actually liked it when I typed it that way. It kept prompting me with the members lists as I worked my way through the object model.

But when I compiled it, I got a nasty error:

error CS1546: Property, indexer, or event ‘this’ is not supported by the language; try directly calling accessor method ‘Microsoft.Office.Interop.Word.SmartTags.get_Item(ref object)’

Bummer. I popped over to the VS.NET object browser and it looked alright, but no dice. After digging around on Google Groups, I saw somebody mention that some VB-focused COM code will expect a ByRef Variant, hence the ‘ref object’ in the error message.

So the only way to fix that is to pass a ref object to the actual getter method, which isn’t the array indexer but is a method called get_Item. Here is the code I ended up with:

object temp = SMARTDOC;
string text = ThisDocument.SmartTags.get_Item(ref temp).SmartTagActions.get_Item(ref temp).TextboxText;

The get_Item method isn’t shown in the object browser, but it is really there so you can call it. Crazy, eh? But it works.

If you ever see that “not supported by the language” error, remember this.

Outlook 2003 Keyboard Shortcut

I just accidentally discovered a nice little keystroke for OL2K3. With an email message selected and the focus on the message list, press the insert key. It will ‘flag’ the message. Press it again, and it will change to ‘complete’.

Cool.

Microsoft.com Web Services SDK

This looks interesting…

The Microsoft.com Web Service is an XML Web service that will enable you to integrate information and services from MSDN, Technet, other Microsoft.com sites, and Microsoft Support. In order to serve as a test for our new architecture, Version 1.0 of the Microsoft.com Web Service is limited to providing information about top downloads from Microsoft.com. Future releases will build on this architecture to provide access to a broader variety of Microsoft content and services.

Unfortunately it looks somewhat limited now, but it could prove to be very interesting. My hope is that this the first step on the way to having VS.NET (and other tools) use the MSDN website as its integrated help system. We’ll see.

NUnit 2.1 RC1 Released

NUnit 2.1 is almost out…

This is the third major release of NUnit and the second since it was
rewritten to take advantage of .NET custom attributes. Highlights of this release include:

  • Support for the .NET framework versions 1.0 and 1.1
  • The ability to run test suites across multiple assemblies
  • New TestFixtureSetup and TestFixtureTeardown attributes
  • Improvements to the GUI interface
  • New command line switches for both GUI and Console runners
  • Some degree of integration with Visual Studio
  • Tests now execute in the same order as they are displayed in the gui.
  • Substantial improvements in error and exception reporting.
  • Now runs on Windows 98

Download either the msi file or the source zip from the following link:
http://sourceforge.net/project/showfiles.php?group_id=10749&release_id=179125

Using IHttpHandler to Add Error Handling to ASPX Pages

I was just putting together a presentation on the ASP.NET Runtime/Pipeline for a customer when this little tidbit popped up&nbsp_place_holder;on Craig Andera’s weblog.

Basically Craig needed to add error handling to a whole&nbsp_place_holder;bunch of ASPX pages and he didn’t want to mess up the code that was already there.

IHttpHandler to the rescue! Since IHttpHandler is what is really driving the whole ASPX process anyway, and since System.Web.UI.Page implements IHttpHandler, you can reimplement it yourself and provide a try..catch block to catch those pesky exceptions.

Read Craig’s post for a nice code sample.

More Fun With CodeDOM

In WinTechOffTopic, Chris Sells asked for generalized permutation engine. A number of poeople posted a bunch of different solutions, one of which was the naive nested for-loop approach. Works well, but required you to add new for-loops every time you want to add a new element to the search.

That’s when I thought, “You could always use a little dynamic code generation to do the simple algorithm for the general case.”

The performance isn’t as good as what Chris actually found, but it is an interesting way to play with CodeDOM.

Here’s the code. Note you’ll need Shawn&nbsp_place_holder;A. Van Ness’ HiResTimerClass from http://www.arithex.com/hirestimer.cs.html. Enjoy!

using Microsoft.CSharp;
  
using System;
  
using System.CodeDom.Compiler;
  
using System.IO;
  
using System.Reflection;
  
using System.Text;
  

  
namespace SellsPermutationSpike
  
{
  
  /// <summary>
  
  /// Summary description for Class1.
  
  /// </summary>
  
  class Class1
  
  {
  
    /// <summary>
  
    /// The main entry point for the application.
  
    /// </summary>
  
    [STAThread]
  
    static void Main(string[] args)
  
    {
  
      Util.HiResTimer hrt = new Util.HiResTimer();
  

  
      hrt.Start();
  
      string code = GetPermutationCode( 0, 100, 7, 5, false );
  
      hrt.Stop();
  
      Console.WriteLine( "GetPermutationCode() method took {0} microseconds.",  
        hrt.ElapsedMicroseconds );
  

  
      hrt.Start();
  
      Assembly assembly = CompileCode( code );
  
      hrt.Stop();
  
      Console.WriteLine( "CompileCode() method took {0} microseconds.",  
        hrt.ElapsedMicroseconds );
  

  
      hrt.Start();
  
      Go( assembly );
  
      hrt.Stop();
  
      Console.WriteLine( "PermuteBySum() method pass 1 tool {0} microseconds.",  
        hrt.ElapsedMicroseconds );
  

  
      hrt.Start();
  
      Go( assembly );
  
      hrt.Stop();
  
      Console.WriteLine( "PermuteBySum() method pass 1 took {0} microseconds.",  
        hrt.ElapsedMicroseconds );
  
    }
  

  
    static void Go( Assembly assembly )
  
    {
  
      object o = assembly.CreateInstance( "DynamicPermutation" );
  
      Type t = o.GetType();
  
      t.InvokeMember( "Go", BindingFlags.InvokeMethod, null, o, null );
  
    }
  

  

  
    static Assembly CompileCode( string source )
  
    {
  
      CSharpCodeProvider cSharpProvider = new CSharpCodeProvider();
  
      ICodeCompiler compiler = cSharpProvider.CreateCompiler();
  

  
      CompilerParameters options = new CompilerParameters();
  
      options.GenerateInMemory = true;
  

  
      CompilerResults results = compiler.CompileAssemblyFromSource( options,  
        source );
  

  
      if( results.Errors.HasErrors )
  
      {
  
        StringBuilder sb = new StringBuilder();
  
        foreach( CompilerError error in results.Errors )
  
        {
  
          sb.Append( String.Format("{0} - {1}\n", error.Line,  
            error.ErrorText ) );
  
        }
  

  
        Console.WriteLine( sb.ToString(), "ERROR" );
  
        return null;
  
      }
  

  
      return results.CompiledAssembly;
  
    }
  

  
    static string GetPermutationCode( int start, int end, int count,  
      int skip, bool writeLine )
  
    {
  
      StringBuilder sb = new StringBuilder();
  
      
  
      sb.Append( @"
  
        using System;
  
        class DynamicPermutation
  
        {
  
          public static void Go()
  
          {
  
      " );
  

  
      for( int i=0; i<count; ++i )
  
        sb.AppendFormat( "for( int c_{0} = {1}; c_{0} < {2}; c_{0} += {3} )",  
          i, start, end, skip );
  

  
      if( writeLine )
  
      {
  
        sb.Append( "Console.WriteLine(\"" );
  

  
        for( int i=0; i<count; ++i )
  
        {
  
          sb.AppendFormat("}", i );
  
          if( i+1 < count )
  
            sb.Append( "," );
  
        }
  

  
        sb.Append( "\"," );
  

  
        for( int i=0; i<count; ++i )
  
        {
  
          sb.AppendFormat( "c_{0}", i );
  
          if( i+1 < count )
  
            sb.Append( "," );
  
        }
  

  
        sb.Append( ");" );
  
      }
  
      else
  
      {
  
        sb.Append(" { int temp = 0; } ");
  
      }
  

  
      sb.Append( @"
  
          }
  
        }
  
      " );  
  

  
      return sb.ToString();
  
    }
  
  }
  
}

Career Calculus

I’ve seen this sentiment echoed a number of times lately. Dave and Andy (The Pragmatic Programmers) put up a slide deck called How To Keep Your Job that I liked a lot. Then Doug Reilly posted Who is Responsible for Your Career.

Now we have Eric Sink’s post├é titled Career Calculus. I like his abstraction quite a bit. Eric breaks it down into a simple linear equation:

C = G + LT

C is Cluefulness. It is defined as an overall measure of your capabilities, expertise, wisdom and knowledge in the field of software development. It is the measure of how valuable you are to an employer. It is the measure of how successful your career is. When you graph your career, C is on the vertical axis.

G is Gifting.├é It is defined as the amount of natural cluefulness you were given “at the factory”.├é ├é For├é each individual, G├é is a constant,├é but it definitely├é varies from person to person.

L is Learning. It is defined as the rate at which you gain (or lose) cluefulness over time.

T is Time. It is on the horizontal axis of your career graph.

Now even though it is very clear to anyone who reads this that the only way to increase your Cluefulness is by constant learning, there will still be plenty of people who don’t bother.

You see, I don’t think this has anything to do with the computer or technology business. This simple little equation applies to almost everything you do in life. Want to increase your cluefulness about motorcycles? Read a book. Follow a mechanic around. Some people are born with a natural abillity (G above) but beyond that, you have to put effort into learning.

Eric closes with the statement, “Don’t work for a manager who is actively hindering your practice of constant learning. Just don’t do it.

I couldn’t agree more. But then I’m also a person who wouldn’t work in a job I don’t like for a million bucks. Some people don’t have enough self confidence to approach the world that way. These people also don’t think they can learn new things. They don’t think of a job interview as YOU interviewing THEM. They are afraid to try new things. They take shortcuts. They are lazy, but not lazy enough. They are doomed.