Sunday, August 14, 2005
« MSN Desktop Search and Hidden Files | Main | Losing events in Office Add-ins »

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