Thursday, September 08, 2005

It appears that I'm all switched over to my new ISP and things are going pretty well.  I got so fed up with my last provider and their constant drops.  You may recall that I was completely down for 11 days last month.  I've dropped a few other times since then as well for 1+ days.  Invariably, it seems that my old ISP knew when I was out of town and needed remote access because that's when it would go down.

Now, I'm on Comcast with a business account.  My download perf is pretty good (better than before) but ironically my upload speed is a little slower (though I think it's more consistent as well, so you might see better results anyway).  However, I'm very excited to have transitioned so smoothly and things seem to be on the up and up.

Hopefully these reliability issues are now a thing of the past.

Thursday, September 08, 2005 6:42:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, September 06, 2005

This occurred to me the moment I heard about it, but I'm just now putting my thought down to virtual paper.  Microsoft recently announced the official renamings of various code-named products; code names that had become pretty popular.  Sometimes, however, you've gotta wonder how sane their decisions were.

Code Name New Name Acronym
Indigo Windows Communication Foundation WCF
Avalon Windows Presentation Foundation WPF

What's next? are they going to rename Team Foundation Server "Windows Team Foundation Server"? There sure would be a bunch of WTFs flying around!

Tuesday, September 06, 2005 4:42:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
I had the opportunity tonight, along with a few of my fellow affiliates from the Utah .NET User Group, to attend a presentation given by Aaron Skonnard to the Northern Utah .NET User Group.  He covered the topic of Indigo (Windows Communication Foundation).  Wow, what a cool presentation!  I'm very glad I went and was able to participate.  Aaron talked about the history of Indigo, it's Borg-like effect (though he didn't use those words) of assimilating the various teams and technologies within Microsoft such as ASMX, COM+, MSMQ, Remoting, Messaging, Biztalk.  He had some pretty cool demos too.  All in all, it was a great event!
Tuesday, September 06, 2005 4:27:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, September 03, 2005

A buddy of mine pointed me to this blog post today.  He had the need to pull a single random record from a database table.  Traditionally, this has not been a completely trivial task, but not unattainable either.  Well, the technique employed here is pretty cool.  All you need to do is leverage the NewID() function in SQL Server 2000+.

SELECT TOP 1 * FROM tblSomeTable ORDER BY NEWID()

Pretty slick, eh?

Saturday, September 03, 2005 1:58:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, August 29, 2005

Well, now that I'm back from my usual Santa Barbara trip, life is getting back to its usual frenetic, over-extended form.  I had the opportunity this morning to attend the morning segment of what will be a two-day lecture/demo course on VS.NET 2005.  The course is presented by my good friend Scott Golightly (our local Microsoft Regional Director) and our new Microsoft Developer Evangelist, Ani Babaian.  Unfortunately, I had to leave early in order to be able to meet some deliverables this week, but I wanted to show up and show my support.

This evening, I had the opportunity to have a special Microsoft Insider's community leadership roundtable with Ani Babaian, Ashwin Karuhatty (our departing DE), Aaron Skonnard, Scott Golightly, Pat Wright, Robert Love, T.J. Belt, Jason Walker, Justin Long, Ben Galbraith (of our local Java User Group).  Others were invited as well, but apparently were unable to make it.  It was a fun time catching up with my long-time friends and associates and discussing the community and what we can do to help bolster enthusiasm.

All in all, it was a pretty good day.  Now onward for another 8 hrs or so (and yes, it's already 9:30 PM).  Se la vi.

Monday, August 29, 2005 2:33:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, August 25, 2005

I've been working pretty intensively with COM Interop lately - especially in conjunction with an add-in that I've written that integrates with Outlook.  This particular add-in has the need to run asynchronously and multi-threaded within Outlook, while at the same time interacting with COM components.  For those uninitiated, COM components have several threading models, single threaded, free threaded, both threaded, neutral threaded, etc.  Each of these apartment models has different characteristics and advantages and disadvanges, a topic I won't be covering to any appreciable depth here.  Suffice it to say, when interacting with COM components from .NET, you have to be sure that the thread is running in the appropriate apartment state in order to interact with the component.

The two threading apartment states for .NET components are STA (Single Threaded Apartment) and MTA (Multi Threaded Apartment).  Many components (especially those targeted to be consumed by VB.NOT (e.g. VB 6.0 and prior)) are intended to be run in a single-threaded apartment.

As it turns out, you can only set the ApartmentState property of a thread once (thereafter the property is readonly).  Therefore, care must be taken when calling STA components from an MTA thread.

My solution below, basically creates a new thread (if necessary) to run an STA component.  The calling thread effectively waits for the component to finish before continuing.

internal void DoWork() {
   if ( ApartmentState.STA != Thread.CurrentThread.ApartmentState ) {
      Thread staThread = new Thread(new ThreadStart(doActualWork));
      staThread.ApartmentState = ApartmentState.STA;
      staThread.Start();
      staThread.Join();
   }
   else {
      // we're already running in an STA apartment so it's ok to call the method as-is
      doActualWork();
   }
}

private void doActualWork() {
}

Thursday, August 25, 2005 7:22:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, August 20, 2005

I had this interesting problem the other day when creating an add-in for Office (Outlook specifically), but I believe it would apply to any Office add-in.  The problem goes as follows:

I would create a CommandBar and embed controls on it.  I would then wire up an event procedure for each control to fire accordingly.  The events would run properly once.  After that they wouldn't run.  Upon loading the first time, the add-in would create the CommandBar, and that's the only time it would work.  If I closed Outlook and reloaded it, the events would not get raised.  This was a tad frustrating.

So how did I solve it?  Well, to solve it, I had to dig a bit lower than the actual appearances and try to figure out what is really going on.  First of all, this is managed code (that is, the add-in is written in C#).  On the other hand, add-ins are COM components.  So there's this inherent COM-Interop layer between my add-in and the Office environment.  When an event gets wired up, you're really establishing a delegate instance (which is a managed component).  So this is what happened:

  1. call procedure to create CommandBar and constituent controls
  2. COM component CommandBar created via RCW (Runtime Callable Wrapper)
  3. COM components for each CommandBarControl created and each one added to the CommandBar via RCW (Runtime Callable Wrapper)
  4. .NET managed delegate wired up for each event
  5. procedure ends, local variables for each COM component goes out of scope
  6. Garbage collector (GC) determines that RCWs are no longer used so .NET references to COM components deleted (along with delegates)

So the solution was, effectively, to create a container of some sort simply to persist the references to the COM components beyond the creation procedure for the duration the add-in is loaded.  I opted for an ArrayList for ease and simplicity.

private outlook.Application _app;
private ArrayList           _controls = new ArrayList();

private void createControls() {
   CommandBar bar = _app.ActiveExplorer().CommandBars.Add(“Test CommandBar“, MsoBarPosition.msoBarTop, Type.Missing, true);
   CommandBarButton btn = (CommandBarButton)bar.Controls.Add(MsoControlType.msoControlButton, Type.Missing, “Test“, Type.Missing, true);
   btn.Tag = “TestButton“;
   btn.Caption = “Click Me“;
   btn.Click += new _CommandBarButtonEvents_ClickEventHandler(btn_Click);
   btn.Visible = true;
   // add the control to the collection so its reference persists
   _controls.Add(btn);
   bar.Visible = true;
}

private void btn_Click(CommandBarButton Ctrl, ref bool CancelDefault) {
   MessageBox.Show(“You clicked the button!“);
}

All in all, it's a pretty simple solution, but without knowing what's going on (or just a lucky guess), it's not the most straightforward problem to solve.  Hope this comes back to help someone who may be experiencing a similar problem.

Saturday, August 20, 2005 5:30:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [5]  |  Trackback
 Sunday, August 14, 2005

It's so reassuring when you start digging into the .NET Framework and discover that functionality is already there - especially if you've already gone through the effort to solve the problem in question.

Recently, for example, I needed to implement help-related functionality in an application that I had written.  Well, I had been fully aware that the WinForm controls provided a HelpRequested event to which I could enlist and receive notification.  This event didn't make much sense to me at first (I guess I was above reading documentation, relying instead on my wiles to interpret its intentions).  The HelpRequested event received a HelpEventArgs parameter that contains a MousePos parameter that indicates the screen coordinates of the mouse position at the moment the help was requested.  This is useful if you need to resolve the control over which the mouse is positioned to provide context-sensitive help, as in the following example:

Point pt = this.PointToControl(e.MousePos);
Control targetControl = this.GetChildAtPoint(pt);

Well, I was getting multiple HelpRequested events raised for each F1, '?'-mouse click, etc; sometimes 2 or 3+ events.  Well, this is no good - I just want one.  I took it upon myself, therefore to 'fix' the problem, not thinking that there might be a logical solution to the problem.  My solution was fine - it worked without a problem, but was very limited in its practicality (at least in this case).  I'll show what I did, nonetheless, because it might be beneficial to a future generation.

I returned to my roots of Win32 application programming and overrode the WndProc() method, catching Windows Messages and responding to them accordingly.  In this case, I wanted the WM_HELP message.  Once I received this message, the LParam points to a HELPINFO structure that I could pull data from (potentially more useful information that just the mouse coordinates).  Being that I'm dealing with managed .NET code, I had to convert the unmanaged, pointed-to data to a managed structure for interpretation.  Then, once I had the data, I could act upon it accordingly.  My code resembled the following:

using System.Runtime.InteropServices;

// ..defined with the control class...

[StructLayout(LayoutKind.Sequential)]
private struct POINT {
   public Int32 X, Y;

   public Point ToPoint() {
      return new Point(X, Y);
   }
}

[StructLayout(LayoutKind.Sequential)]
private struct HELPINFO {
   public UInt32   cbSize;
   public Int32    iContextType;
   public Int32    iCtrlId;
   public IntPtr   hItemHandle;
   public Int32    dwContextId;
   public POINT    MousePos;
}

protected override void WndProc(ref Message m) {
   const int WM_HELP = 0x0053;
   if ( WM_HELP == m.Msg ) {
      // copy the data to the managed structure
      HELPINFO hi = (HELPINFO)Marshal.PtrToStructure(m.LParam, typeof(HELPINFO));
      // deal with the 'event' accordingly...
      // ...
   }
   else {
      base.WndProc(ref m);
   }
}

All of this was, of course for naught, as I soon realized that the HelpEventArgs has a .Handled property that, once set to true will suppress further raisings of the event.  By working with the event correctly we more readily support the known event pattern and can more directly work in the inheritance chain.  Silly me...things of such blatent obviousness don't usually go uncaught (at least I not noticed if they haven't).  All in all, however, it was a good 15 minute exercise.  Fortunately o coder was hurt during the writing of this code, but a coder did indeed feel silly fixing it to the way it should be.

Sunday, August 14, 2005 5:16:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I really dig Microsoft MSN Desktop Search.  And for a lot of reasons.  Not only is the application cleaner and more accessible that the equivalent Google Desktop search (which I never did really like), but I love the integration with Outlook and my desktop.  To have the shortcut bars so available and the results not stale (which was a shortcoming of the Google product) is great.  Not to mention the full Windows Explorer integration is awesome...just right-click any result and you get true Windows context menus, not a generic menu from within a browser.

But all of this isn't to say that it isn't without its shortcomings.  For example, when establishing the folders you want indexable you can't see hidden/system folders to de/select them (they default to be indexed).  This is a pain partly because I don't really care if those directories get indexed.  Case in point:  I had (re)installed MSN Desktop Search when I reinstalled my OS a few weeks ago and I noticed that the index NEVER finished building...my hard drive would churn and churn and churn.  I decided to let the indexer run overnight to no avail.  This was a bit disturbing so I right-clicked the handy tray icon and selected 'Indexing Status'.  Lo and behold it was indexing files in my C:\RECYCLER folder.  I currently have Norton Utilities installed and it installed a 'Norton Protected Recycle Bin'.  It turns out that this little utility is constantly updating the contents of that folder so it kept putting the Desktop Search into a continual state of never being able to finish the index.

Rather that simply deselecting that directory to not be indexed (which I would prefer), I had to instruct the Desktop Search to not index files with the .000, .001, or .002 extensions that the Norton Protected Recycle Bin utilizes.  Though I doubt those extensions are in use elsewhere, I don't like making such a broad assumption, but I couldn't think of another way to limit the scope of the indexing.

Sunday, August 14, 2005 4:42:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback