Welcome to MSDN Blogs Sign in | Join | Help

PDC I’m waiting for my last load in the dryer, so I can finish packing for my first PDC, in Los Angeles beginning tomorrow.  If you’re going to be there as well, hopefully we’ll catch each other among the other thousands of folks that will be there taking part in the workshops, 160+ technical sessions, Birds of a Feather discussions, hands-on labs, and other special events.

If you’re not going to LA though, you can still be part of the buzz and excitement happening there. 

  • Watch the two keynotes via Silverlight smooth-streaming from the comfort of your own office (or get a group of folks together over lunch).  Both keynotes begin at 11:30 Eastern time.

Day 1, November 17th, Ray Ozzie and Bob Muglia

Day 2, November 18th, Scott Guthrie, Kurt DelBene, and ???

  • Channel 9 will be broadcasting live (and unscripted) from the PDC Big Room each of the three days (beginning around 1:30 EST).  They’ll be interviewing presenters and attendees alike, and you can help drive the conversation by submitting your tweets to @ch9live.
  • Check out the Not@PDC site.  There’s nothing there at the moment I’m writing this post, but last year quite a few presentations were made available BY non-attendees FOR non-attendees.  You can follow their twitter feed as well via the hashtag #notatpdc
Visual Studio 2010 .NET Framework 4


You’re probably aware that the Beta 2 release of Visual Studio 2010 and .NET 4.0 became available a couple of weeks ago.  Did you know there’s a “Go Live” license?  … you can build and deploy your application even before Visual Studio 2010 is released next March. 

That’s even more reason to not delay and get a head start diving into the new features and technologies.  Our friends at DevelopMentor are hosting a free series of .NET 4.0 Webcasts in the coming weeks, including the following:

  • Introducing MVC
    Presenter: Brock Allen
    Thursday November 12th, 12 noon- Register Here

  • Building Modern Websites in ASP.NET Webforms
    Presenter: Michael Kennedy
    Monday November 23rd, 12 noon - Register Here

  • Meet The New Workflow: WF4
    Presenter: Maurice De Beijer
    Tuesday December 1st, 12 noon - Register Here


Don’t forget too the 10-4 series on Channel 9, with 35 episodes thus far presenting overviews of specific new features that are coming with the new release of Visual Studio.

It’s going to be a busy week in the capital area of New York next week, and a great time to get knee deep in all things technical!

Trojan Horse Tech Valley Code Camp – Saturday, Nov. 7th at SUNY Albany

There’s 20 sessions and over 100 signed up thus far!  I hope to see you there as I deliver my “7 on 7” spiel.

Tech Valley User Group – Tuesday, Nov. 10th at VersaTrans in Latham

For the group’s monthly meeting, Rob Fisch, Director of Global Technology at Kaz, Inc, is speaking on Getting Started with Reporting Services.

Northeast Roadshow – Thursday, Nov. 12th at RPI

Chris and I are bringing you the “Don’t Fear the Coder” tour with topics including Silverlight and MVVM, ASP.NET, LINQ, and WCF.  (We’re taking the show to six other venues as well!)

With all the talk about Windows Azure and hosting your application in the “cloud”, it’s easy to forget that somewhere there’s a computer, or perhaps thousands, that are actually running your application.

There’s a fascinating write-up and photo series on CNET about the new Microsoft data center in Chicago.  Here are some of the cool facts I lifted from the article (with some help from Wolfram Alpha) followed by a video interview featuring Daniel Costello and Christian Belady of Microsoft.

 

Thanks to my New York Metro colleague, Peter Laudati, for pulling all of these events together in one place.  While Chris and I are rather partial to the Northeast Roadshow :), we realize a number of you prefer the warmer climes this time of year, and so we wanted you to be aware of all great work being done up and down the East coast. 

Across the board, this is a pretty amazing opportunity for deep technical content -and, of course, unique brands of humor courtesy of your local developer evangelist(a)s.  For the price of FREE, it’s definitely a few of your hours of your day well spent.

Note, PDC is happening in the middle of our series (say hi to Chris and me if you’re coming to LA), so we are primed for last minute updates at our December talks as well!

Psst… register with the code WIN7 and you may receive one of seven free copies of the MCTS Self-Paced Training Kit (Exam 70-536): Microsoft .NET Framework Application Development Foundation.


n_east_roadshow_120x120

MSDN Northeast Roadshow: ”Don’t Fear the Coder”
Piloted by Chris Bowen & Jim O’Neil

Cities & Dates:

metro_roadshow_120x120

MSDN Metro Roadshow
Piloted by Peter Laudati & Asli Bilgin

Cities & Dates:

  • 11/12/2009 – Parsippany, NJ
  • 12/10/2009 – East Windsor, NJ
  • 12/15/2009 – New York, NY
mid_atl_roadshow_120x120

MSDN Mid-Atlantic Roadshow
Piloted by G. Andrew Duthie, Dani Diaz, and
     Dave Isbitski

Cities & Dates:

  • 11/12/2009 – Pittsburgh, Pa
  • 12/1/2009 – Harrisburg, Pa
  • 12/3/2009 – Reston, Va
  • 12/8/2009 – Roanoke, Va
  • 12/10/2009 – Malvern, Pa
s_fried_roadshow_120x120

MSDN Southern Fried Roadshow
Piloted by Brian Hitney & Glen Gordon

Cities & Dates:

  • 11/4/2009 – Greensboro, NC
  • 11/5/2009 – Raleigh, NC
  • 11/6/2009 – Columbia, SC
  • 12/8/2009 – Atlanta, GA
  • 12/9/2009 – Montgomery, AL
tiki_roadshow_120x120

MSDN Tiki Hut Roadshow
Piloted by Joe Healy & Russ Fustino

Cities & Dates:

  • 11/30/2009 – Tampa, FL
  • 12/2/2009 – Fort Lauderdale, FL
  • 12/14/2009 – Orlando, FL


 

 

Here’s a one-stop shopping spot for the 7 on 7 blog series from the past week (each image leads to a post on a specific technology).  Hopefully, the series has given you great ideas on how to start leveraging the new Windows 7 features in your own applications.  And if you’re doing something especially cool with Windows 7, drop me a line; I’d love to hear about it.

7 on 7 Intro Post

7 on 7 Code Camp Presentation Links

XP Mode Taskbar Federated Search Extended Linguistic Services Direct2D and DirectWrite Sensor and Location API Multitouch

Windows 7Windows Multitouch, in my opinion, is the most emotive new feature of Windows 7.  From the kids at home to the audiences to whom I’m demoed Windows 7, there’s something fresh and fun about being able to manipulate an application with simple hand gestures. 

We’ve all used touch screens in some form before, whether it be a tablet PC, your ATM, or a mall kiosk, but generally you’re just substituting your finger for a mouse.  Multitouch is different; it mimics the way we work with physical objects and as such opens up a new world of user interaction scenarios.

When characterizing existing or new applications running on a multitouch device, three categories of the user experience emerge: good, better, and best.  As we examine those categories in this post, you should get a good idea of the technical aspects that enable these experiences as well.

 

The Good Experience

Legacy applications will automatically provide a touch experience on touch devices, even though those applications were not designed for the Windows 7 touch capabilities.  Basic interactions like panning with one or two fingers, resizing using a pinch gesture, and right clicking with a tap-and-press gesture are automatically translated by Windows 7 into analogous mouse messages, such as WM_VSCROLL and WM_HSCROLL.  As a result, applications like Microsoft Word 2007 will ‘do the right thing’:  when you pan the document, it scrolls; when you use the resize gesture, it changes the zoom factor as if you’d used the slider at the bottom right or the ribbon’s Zoom option.

You may want to check out the MSDN article Legacy Support for Panning with Scroll Bars for additional guidance to ensure your legacy application works well with the ‘out-of-the box’ touch capabilities.  Troubleshooting Applications also has good tips for diagnosing unexpected behaviors in touch-enabled applications; for example, disabling flicks is generally recommended.

 

The Better Experience

Windows 7 introduces three new notifications and messages to support touch-enabled applications; two of these notifications (WM_GESTURENOTIFY and WM_GESTURE) form the basis of “the better experience” for multitouch.  To respond to these new messages, managed developers need to include code in WndProc since the the .NET Framework classes do not include explicit touch events. Additionally be sure to filter these message up the chain, via DefWindowProc (unmanaged) or a call to the WndProc of the base class in managed code.

WM_GESTURENOTIFY is your opportunity to indicate which of the built-in gestures that your application supports.  Respond to this message via a call to SetGestureConfig, passing in an array of GESTURECONFIG structures that detail which gestures your application will recognize.   There are five specific gestures:

 

Gesture ID Behavior Gesture Diagram
GID_ZOOM 3 zoom Zoom gesture
GID_PAN 4 pan / scroll Pan gesture
GID_ROTATE 5 rotate Rotate gesture
GID_TWOFINGERTAP 6   Two-finger tap gesture
GID_PRESSANDTAP 7 right click Press-and-tap gesture

 

The ID numbers in the chart above refer to the dwID field of the GESTUREINFO structure, which you would retrieve via the GetGestureInfo method as part of the message processing loop.  Two other ID values, GID_START (1) and GID_END (2), complete the list and enable detecting the beginning and end of a long-running gesture, like panning across a document.   The GESTUREINFO structure contains additional fields (ptsLocation and ullArguments) that store data pertinent to a specific gesture, like the center point of a rotation or the distance between two fingers.

Putting this all together, below is a bit of code from the MTGestures sample provided with the Windows 7 SDK.  The two cases for the WndProc function (lines 8 and 22) handle the two new notifications for gesture handling.  Here, the application subscribes to all of the gestures (line 13), and defers the gesture handling to the DecodeGesture method (line 23).  Each gesture has its own case within the switch statement (lines 46, 49, 52, 80, 102, 127, and 132) where gesture-specific code accesses the additional information in ptsLocation and ullArguments to carry out the processing.

 

   1:  protected override void WndProc(ref Message m)
   2:  {
   3:      bool handled;
   4:      handled = false;
   5:   
   6:      switch (m.Msg)
   7:      {
   8:          case WM_GESTURENOTIFY:
   9:              {
  10:   
  11:                  GESTURECONFIG gc = new GESTURECONFIG();
  12:                  gc.dwID = 0;    
  13:                  gc.dwWant = GC_ALLGESTURES; 
  14:                  gc.dwBlock = 0;
  15:   
  16:                  bool bResult = SetGestureConfig( Handle,  0,   1, 
  17:                       ref gc,  _gestureConfigSize);
  18:              }
  19:              handled = true;
  20:              break;
  21:   
  22:          case WM_GESTURE:
  23:              handled = DecodeGesture(ref m);
  24:              break;
  25:   
  26:          default:
  27:              handled = false;
  28:              break;
  29:      }
  30:      base.WndProc(ref m);
  31:   
  32:      if (handled)
  33:            m.Result = new System.IntPtr(1);
  34:  }
  35:   
  36:   
  37:  private bool DecodeGesture(ref Message m)
  38:  {
  39:      GESTUREINFO gi;
  40:      gi = new GESTUREINFO();
  41:      gi.cbSize = _gestureInfoSize;
  42:      GetGestureInfo(m.LParam,ref gi)
  43:   
  44:      switch (gi.dwID)
  45:      {
  46:          case GID_BEGIN:
  47:              break;
  48:   
  49:          case GID_END:
  50:              break;
  51:   
  52:          case GID_ZOOM:
  53:              switch (gi.dwFlags)
  54:              {
  55:                  case GF_BEGIN:
  56:                      _iArguments = (int)(gi.ullArguments & 
ULL_ARGUMENTS_BIT_MASK);
  57:                      _ptFirst.X = gi.ptsLocation.x;
  58:                      _ptFirst.Y = gi.ptsLocation.y;
  59:                      _ptFirst = PointToClient(_ptFirst);
  60:                      break;
  61:   
  62:                  default:
  63:                      _ptSecond.X = gi.ptsLocation.x;
  64:                      _ptSecond.Y = gi.ptsLocation.y;
  65:                      _ptSecond = PointToClient(_ptSecond);
  66:                      Point ptZoomCenter = new Point(
                               (_ptFirst.X + _ptSecond.X) / 2,
  67:                          (_ptFirst.Y + _ptSecond.Y) / 2);
  68:                      double k =  (double)(gi.ullArguments & 
                               ULL_ARGUMENTS_BIT_MASK) / 
  69:                          (double)(_iArguments);
  70:   
  71:                     _dwo.Zoom(k, ptZoomCenter.X, ptZoomCenter.Y)
  72:                      Invalidate();
  73:   
  74:                      _ptFirst = _ptSecond;
  75:                      _iArguments = (int)(gi.ullArguments & 
                               ULL_ARGUMENTS_BIT_MASK);
  76:                      break;
  77:              }
  78:              break;
  79:   
  80:          case GID_PAN:
  81:              switch (gi.dwFlags)
  82:              {
  83:                  case GF_BEGIN:
  84:                      _ptFirst.X = gi.ptsLocation.x;
  85:                      _ptFirst.Y = gi.ptsLocation.y;
  86:                      _ptFirst = PointToClient(_ptFirst);
  87:                      break;
  88:   
  89:                  default:
  90:                       _ptSecond.X = gi.ptsLocation.x;
  91:                      _ptSecond.Y = gi.ptsLocation.y;
  92:                      _ptSecond = PointToClient(_ptSecond);
  93:   
  94:                      _dwo.Move(_ptSecond.X - _ptFirst.X, 
_ptSecond.Y - _ptFirst.Y);
  95:                      Invalidate();
  96:   
  97:                      _ptFirst = _ptSecond;
  98:                      break;
  99:              }
 100:              break;
 101:   
 102:          case GID_ROTATE:
 103:              switch (gi.dwFlags)
 104:              {
 105:                  case GF_BEGIN:
 106:                      _iArguments = 0;
 107:                      break;
 108:   
 109:                  default:
 110:                      _ptFirst.X = gi.ptsLocation.x;
 111:                      _ptFirst.Y = gi.ptsLocation.y;
 112:                      _ptFirst = PointToClient(_ptFirst);
 113:   
 114:                      _dwo.Rotate(
 115:                          ArgToRadians(gi.ullArguments & 
                                            ULL_ARGUMENTS_BIT_MASK)
 116:                          - ArgToRadians(_iArguments),
 117:                          _ptFirst.X, _ptFirst.Y
 118:                      );
 119:   
 120:                      Invalidate();
 121:   
 122:                      _iArguments = (int)(gi.ullArguments & 
ULL_ARGUMENTS_BIT_MASK);
 123:                      break;
 124:              }
 125:              break;
 126:   
 127:          case GID_TWOFINGERTAP:
 128:              _dwo.ToggleDrawDiagonals();
 129:              Invalidate();
 130:              break;
 131:   
 132:          case GID_PRESSANDTAP:
 133:              if (gi.dwFlags == GF_BEGIN)
 134:              {
 135:                  _dwo.ShiftColor();
 136:                  Invalidate();
 137:              }
 138:              break;
 139:      }
 140:   
 141:      return true;
 142:  }

 

The Best Experience

Gestures (“the better experience”) are limited in that they cannot be combined, so while you can rotate or zoom, you can’t rotate and zoom.  Additionally, you can’t manipulate more than one object at a time, like say drag two pictures on a photo album application.  To ratchet up the experience another level, applications need to opt into handling the raw touch messages, namely WM_TOUCH, by registering each window subject to touch treatment via the RegisterTouchWindow method.

As with the WM_GESTURE message, WM_TOUCH messages should be intercepted in the WndProc and the GetTouchInputInfo method used to return information about the current touch event.  That information is returned within an array of TOUCHINPUT structures, in much the same way as the GESTUREINFO structure was leveraged above, but this time returning information about multiple touch points.

Below is some code from the MTScratchPadWMTouch example from the Windows 7 SDK.  Similar the above code sample, DecodeTouch is used to extract information from the WM_TOUCH message and carry out appropriate actions.  In lines 15 though 20, the dwFlags information for each touch point is consulted and an associated event handler assigned: Touchdown if the touch message indicates a touch was initiated; Touchup if a finger was removed from the screen; and TouchMove if a finger was moved.  Once the action is complete (handlers are executed in line 39), the touch handle, which comes from the LPARAM of the WM_TOUCH message, must be closed (line 44).
 

   1:  private bool DecodeTouch(ref Message m)
   2:  {
   3:      int inputCount = LoWord(m.WParam.ToInt32()); // # of inputs
   4:      TOUCHINPUT[] inputs;
   5:      inputs = new TOUCHINPUT[inputCount];
   6:   
   7:      GetTouchInputInfo(m.LParam, inputCount, inputs, touchInputSize);
   8:   
   9:      bool handled = false;
  10:      for (int i = 0; i < inputCount; i++)
  11:      {
  12:          TOUCHINPUT ti = inputs[i];
  13:   
  14:           EventHandler<WMTouchEventArgs> handler = null;  
  15:          if ((ti.dwFlags & TOUCHEVENTF_DOWN) != 0)
  16:              handler = Touchdown;
  17:          else if ((ti.dwFlags & TOUCHEVENTF_UP) != 0)
  18:              handler = Touchup;
  19:          else if ((ti.dwFlags & TOUCHEVENTF_MOVE) != 0)
  20:              handler = TouchMove;
  21:   
  22:          if (handler != null)
  23:          {
  24:              WMTouchEventArgs te = new WMTouchEventArgs();
  25:   
  26:              te.ContactY = ti.cyContact/100;
  27:              te.ContactX = ti.cxContact/100;
  28:              te.Id = ti.dwID;
  29:              {
  30:                  Point pt = PointToClient(
                                          new Point(ti.x/100, ti.y/100));
  31:                  te.LocationX = pt.X;
  32:                  te.LocationY = pt.Y;
  33:              }
  34:              te.Time = ti.dwTime;
  35:              te.Mask = ti.dwMask;
  36:              te.Flags = ti.dwFlags;
  37:   
  38:   
  39:              handler(this, te);
  40:              handled = true;
  41:          }
  42:      }
  43:   
  44:      CloseTouchInputHandle(m.LParam);
  45:      return handled;
  46:  }

 

This example is a simple paint application, so the events track individual strokes on a canvas.  Touchdown, for instance, initiates a stroke and assigns it a color.  Touchup removes the stroke for a collection of active strokes, and TouchMove draws the stroke corresponding to the given touch point on the canvas.   Below is the code for the TouchMove handler:

 

   1:  private void OnTouchMoveHandler(object sender, 
   2:        WMTouchEventArgs e)
   3:  {
   4:      // Find the stroke in the collection of the strokes in drawing.
   5:      Stroke stroke = ActiveStrokes.Get(e.Id);
   6:      Debug.Assert(stroke != null);
   7:   
   8:      // Add contact point to the stroke
   9:      stroke.Add(new Point(e.LocationX, e.LocationY));
  10:   
  11:      // Partial redraw: only the last line segment
  12:      Graphics g = this.CreateGraphics();
  13:      stroke.DrawLast(g);
  14:  }

 

Manipulations and Inertia

While WM_TOUCH provides all the low level details, the jump from translating individual touch messages to end-user interactions like rotating and resizing may seem a bit overwhelming.  That’s where the manipulation and inertia processors come in.

The manipulation processor (IManipulationProcessor and _IManipulationEvents) takes as input the raw WM_TOUCH messages and converts them into 2-d affine transformations, combining scale, rotation, and translation, essentially providing a superset of the more basic gesture support.  IManipulationProcessor exposes a number of methods depending on the source gesture.  For instance, you’d call ProcessMoveWithTime to feed the manipulation processor information on the movement of a finger on the screen as reported by one of the WM_TOUCH messages. 

As you’re feeding raw touch information into the processor, it’s firing events defined on the _IManipulationEvents interface, namely ManipulationStarted, ManipulationDelta, and ManipulationCompleted.  The ManipulationDelta event gives you access to the affine transformation, so you can carry out whatever update is required to the object being manipulated.

Most high-end touch applications will also want to take advantage of inertia mechanics.  As users interact with objects on the screen in a tactile fashion, they expect objects to behave with similar physics to the real world.  Flick a photo across the screen, and you expect it to move fast at the start and then slow down, and you may expect it to bounce gently off the edge of the screen if it reaches the perimeter of the display.   That’s where the inertia processor (IInertiaProcessor) comes in.

Similar to the manipulation processor (with which is shares the _IManipulationEvents interface), you instantiate a reference to the processor and invoke the Process or ProcessTime method to carry out the physics calculations and raise the ManipulationDelta or perhaps ManipulationCompleted event, just as the manipulation processor does.

 

WPF 4 and the Evolution of Multitouch

The touch capabilities in Windows 7 are obviously implemented at the core operating system level, namely via COM objects.  Managed code developers tend to want to operate at a higher level of abstraction, and currently, if you’re using WPF, you would likely do so by integrating with the Real-Time Stylus interface.  For example, the MTScratchpad I described above has an alternative implementation in the SDK as well, one using stylus events and other functionality enabled by the IRealTimeStylus3 and ITablet3 interfaces.

You may also be familiar with Microsoft Surface, the multi-touch, multi-user tabletop device that you’ve seen on Extra Entertainment, Boston's Channel 7, or perhaps in the Sheraton Boston lobby.  The Surface is based on Windows Vista and the .NET Framework 3.5, and its touch capability is provided via a Surface-specific SDK and controls.  On the traditional computing end, Windows 7 provides a native touch API, and WPF 3.5 can tap into it via either interop or the real-time stylus functionality. In pictures, it’s something like the following; the key point to take away is that a touch application for Surface will not run on Windows 7 and vice-versa… today, anyway.
 

Multitouch scenario today

 

With .NET 4 and the next iteration of Microsoft Surface, there will be considerable interoperability.  The architecture changes from the above to what you see below.  Most notably, both devices will be built on a core of Windows 7.  Additionally, WPF 4 has been enhanced to support touch events directly on the core UI classes, UIElement and UIElement3D, so implementation via interop or the stylus events will no longer be necessary.  Of course, Surface will still deliver additional functionality and controls relevant for that device’s use and form factor, but presuming you confine your application to core .NET 4 (and WPF 4) functionality, you should have nearly seamless interoperability.

 

Multitouch scenarios post .NET 4


If you’re considering building multitouch capabilities into your WPF applications, there’s no time like the present.  You can download the Beta 2 release of Visual Studio 2010 and .NET Framework 4 now (it was just released last week), and there is a go-live license!

 

More Hands-On (pun intended!) Information

Windows Touch (MSDN)

Troubleshooting Applications (MSDN)

Windows Touch: Developer Resources (CodeGallery)

MultiTouch Capabilities in Windows 7 (MSDN Magazine)

Windows Touch Pack for Windows 7

Where the Multitouch Devices Are (Channel 10 blog)

Windows 7You just arrived in LA from Boston, and when you get to your hotel and pop open your laptop, the weather widget on your desktop notes the local temperature on this bright sunny day, and when you search for a coffee shop in Santa Monica the nearest one 10 miles away, not 3000.  Once you get to the coffee shop, the only table is near a window, and while the glare is awful, your laptop adjusts to the ambient lighting so you can use your applications with ease.  What’s the secret?  sensors and location awareness.

Depending on the source, notebook sales eclipsed desktop sales as long ago as 2006, and with the Netbook phenomenon, we are only becoming more and more mobile, computing-wise.  *We* know where we are, why shouldn’t our computer?  That’s the primary scenario that the Windows 7 Sensor and Location Platform enables.

Sensor and Location Framework You can almost think of the API as “ODBC for sensors.”  Just as ODBC provided a common API to access essentially any relational (and some not) data sources, the new API provides a common approach for both driver vendors and software developers to tap into the power of devices like GPS, accelerometers, temperature sensors, biometric devices, and so on. 

As you can see on the left, vendors can build sensor drivers, which amount to COM objects, via the User-Mode Driver Framework along with a specific  Sensor Class Extension that simplifies the effort and amount of code required.  If you’re looking to build your own driver, I’d recommend the Windows Hardware Developer Center as a start, where you can download the Windows Driver Kit specifically.

Virtual light sensorIf you just want to experiment with an existing sensor, there’s a couple of options.  The Windows 7 SDK includes a virtual light sensor (look in the Bin directory), which provides a simple user interface to simulate various lighting conditions.  If you have an application that interacts with the sensor API, this a quick way to test.

Another option is the Freescale JM Badge board, which includes a light-sensor, accelerometer, and capacitive touch sensors.  Bob’s blog post will lead you through the setup and installation of the driver and hardware, so you can do cool things like play around with the XNA Racing Game!

When you’ve installed a sensor, it surfaces in the Control Panel under Hardware and Sound > Location and Other Sensors, where you can enable or disable the sensor hardware.  If you select a sensor from the list, you can even provide access policies, specifying which users and groups have access to that sensor.

 

Location and Sensor control panel Sensor access

Now that you’ve got a sensor installed, how can you use it within your applications?  The Sensor API standardizes access by formalizing

  • Sensor categories, types and properties
  • Data formats
  • COM interfaces
  • Event mechanisms for asynchronously receiving sensor data

so you’re left with really just three steps:

  1. The entry point into the Sensor API is the Sensor Manager (COM: ISensorManager interface; managed: SensorManger class).   Via the Sensor Manager you can enumerate all of the sensors present on the machine, get a list of a specific class of sensors (say all accelerometers), or a pointer to a specific sensor.  In the unmanaged world, you’ll end up with either a ISensorCollection or a specific ISensor pointer.  With the Windows API Code Pack, static methods on the Sensor Manager classes return either a generic SensorList or an instance of the Sensor class.

    As you might expect, ISensor and the managed Sensor class, allow access to a number of properties of the sensor including type, friendly name, manufacturer, serial number, and so on.  The managed Sensor class includes a SensorChangedEvent (use ISensorEvent.OnStateChanged in the COM API) to enable your code to respond to state changes like ready, not available, error, etc.; these are defined by the SensorState enumeration.


  2. The main event here is DataReportChanged (exposed in COM as ISensorEvent.OnDataUpdated), which fires when the sensor has information to share with the host application.  In the handler for DataReportChanged, you’ll get a SensorReport as one of the event arguments; the report includes a timestamp, the sensor that collected the information, and essentially a property bag of information pertinent to that sensor. 

    Properties are defined in the SensorPropertyKeys class of the Windows API Code Pack, and they map back to the GUIDs defined in the sensors.h header of the Windows 7 SDK.  The managed API Code Pack abstracts these property keys somewhat by providing specific inherited classes for light and motion sensors, so they expose the data relevant to that sensor as named properties.

  3. The only thing you’re left to do then is react to the contents of the data report (or the current state of the sensor) when the DataReportChanged event fires.  Keep in mind, events may be firing quickly, so you may want to incorporate asynchronous patterns within your code to provide the responsiveness a user will expect.

One example you may have seen that highlights the sensor API is the MSDN Reader, a WPF application that is light-aware.  In low light conditions, text tends to shrink, and the color scheme matches the MSDN brand.  In extreme light conditions, the text grows, and the contrast increases to the point that the interface is rendered in black and white – to provide better readability outdoors, for instance.  Below you can see the difference in the rendering based on changing the ambient lighting as recorded through my JM Badge board.

 MSDN Reader - normal lighting

MSDN Reader in normal light conditions

 

MSDN Reader - intense lighting

MSDN Reader in intense lighting conditions 


The code for this is actually pretty simple, and in this case localized to a LightSensorProvider class.  Per the three steps above, the first action is to enumerate the sensors so we can get a handle to the light sensor.  Here the application actually attaches to all of the available light sensors (Line 4) and then ‘averages’ the output, but since I have only one sensor board, it’s not doing much.

  1. try {
  2.     SensorManager.SensorsChanged += OnSensorChanged;
  3.     // get a collection of ambient light sensors
  4.     var sensorCollection = SensorManager.GetSensorsByTypeId<AmbientLightSensor>();
  5.     AddSensorCollection(sensorCollection);
  6. }
  7. catch(SensorPlatformException ex) {
  8.     System.Diagnostics.Debug.WriteLine(ex.Message);
  9. }

 

In Line 5 above, the sensor collection is passed to a method for initialization, which looks like the following; it’s in Line 10 that we’re performing Step 2 of our setup, assigning a handler to the DataReportChanged event.

 

  1. private void AddSensorCollection(IEnumerable<AmbientLightSensor> sensorCollection) {
  2.     foreach(AmbientLightSensor sensor in sensorCollection) {
  3.         AddSensor(sensor);
  4.     }
  5. }
  6.  
  7. private void AddSensor(AmbientLightSensor sensor) {
  8.     if(sensor != null) {
  9.         System.Diagnostics.Debug.WriteLine("AddSensor: " + sensor.FriendlyName);
  10.         sensor.DataReportChanged += OnDataUpdated;
  11.         Sensors.Add(sensor);

 

Here’s what happens in DataReportChanged (delegating to OnDataUpdated), Step 3 of the process.  The data report isn’t actually used here since all that’s needed is to access the sensor’s current intensity at line 8.

 

  1. void OnDataUpdated(Sensor sensor, EventArgs e) {
  2.     var alsReport = sensor.DataReport;
  3.     if(alsReport != null) {
  4.         System.Diagnostics.Debug.WriteLine("Data event timestamp: " + alsReport.TimeStamp.ToString());
  5.         var alsSensor = (AmbientLightSensor)sensor;
  6.  
  7.         // get the illuminance property value
  8.         double lightLux = alsSensor.CurrentLuminousIntensity.Intensity;
  9.  
  10.         // Get the sensor id so we can associate the sensor lux value
  11.         // with a specific sensor id in our collection
  12.         Guid sensorId = (Guid)sensor.SensorId;
  13.         if(sensorId != Guid.Empty) {
  14.             // Set the sensor light value
  15.             SetSensorLightLuxValue(sensorId, lightLux);
  16.         }
  17.     }
  18. }

 

There’s a bit of code I’m leaving out at that point, code that aggregates the multiple light sensors (if there are multiple ones) and handles a timer and threshold values to prevent reacting too much. 

Ultimately though a dependency property on the class comprising the sensor (LightSensorProvider) is set to a lux value.  From that point, the UI update – this is WPF remember – is handled via a simple binding.   On line 4 below is the XAML to address the change in font size according to the value of that dependency property: LightSensorProvider.LuxValue.  The magic of data binding in WPF takes over, and the application adjusts itself based on the ambient lighting.

 

  1. <Window.Resources>
  2.   <Style x:Key="StoryPhotoCredit" TargetType="{x:Type TextBlock}">
  3.     <Setter Property="FontFamily" Value="Arial" />
  4.     <Setter Property="FontSize" Value="{Binding Source={StaticResource LightSensorProvider}, Path=LuxValue, Converter={StaticResource LightLevelToFontSizeConverter}, ConverterParameter=8pt}" />
  5.     <Setter Property="TextAlignment" Value="Right" />
  6.     <Setter Property="Foreground" Value="{DynamicResource Brush_ChromeSolidColor}" />
  7.   </Style>

 

Location API

Now what about the Location API?  As you can see from the diagram at the top of this post, the location API is an abstraction of the lower level sensor API.  It extends the sensor API to provide a couple of new interfaces (in the COM world).  Specifically it provides two specialized data reports, one containing a latitude/longitude pair and the other containing a civic (street) address for the detected location.


COM Interface Purpose
ILocation main sensor class
ILatLongReport report of lat/long location
ICivicAddressReport report of location as street address
IDefaultLocation access to default location
ILocationEvents events to handle change in sensor status and location

 

Note, at this point, a managed interface for the Location API has not yet been released as part of the Windows API Code Pack.  There is, however, an alternative interoperability library at the Windows Sensor and Location Platforms project on Code Gallery.

What’s cool with the Location API is that you can control it as well via JavaScript, and since desktop widgets are merely combinations of JavaScript, CSS, and HTML, you can quickly create some location aware widgets for the desktop, like the weather and places of interest.

Weather widget Places widget


Links to Get You Started

Here’s a few more links to get help you start integrating the Sensor and Location API with your own applications.  Have fun!

Freescale JM Badge board

Sensor Development Kit (for use with Freescale board)

Windows API Code Pack (managed wrapper for Sensor library)

Windows Sensor and Location Platforms (Code Gallery)

Sensor API (MSDN)

Location API (MSDN)

Gavin Gear’s Tech Blog (MSDN Blogs)

On the Fence?Microsoft PDC is just a few weeks away, and you’ve probably already heard some of the buzz.   Windows Azure will go live, and of course, we’ve just released Windows 7 and Beta 2 of Visual Studio 2010 and the .NET Framework 4 (by the way, not 4.0 as the marketing folks have told me).

It’s obviously an investment, both in time and in money, but as the premiere conference for developers and architects, where and when else are you going to have the opportunity to get the technical details and future strategy of the platform straight from the Microsoft product experts?  And Come to PDC!where else and when else will you have the chance to network with so many of your colleagues from around the world in one place?  You’ll have conversations that will guide your professional efforts far beyond the few days you’ll spend in LA, and besides, I hear there’s great parties too (you can leave that part out when you ask your boss to go!).

If you act before Friday, October 30th, you can get $300 off of the conference pass, and you can take advantage of the FREE Windows 7 Boot Camp on Monday, Nov. 16th, even if you can’t join us for the rest of the conference.

Windows 7I’m a technical introvert; I love dealing with data, services, interoperability… the plumbing.  So I have to admit, the new graphics stack that Windows 7 introduces – with Direct3D 11, Direct2D, and DirectWrite – didn’t resonate that much with me.  Sure I can appreciate the cool spinny demos as much at the other guy, but I was looking for more… well I found it!

There’s certainly no way to cover in one blog post what is likely a topic for many books in the future, but I wanted to provide the insight I’ve gained into why Direct2D and DirectWrite exist and why they are important to understand.  Let’s start with the obligatory eye-chart showing the changes in Windows 7, and go from there.

 Windows 7 Graphics Stack

One of the first things to note is that the realm of Win32 (and ergo Windows Forms) is out there on the right, not much happening in that world.  And the reason is really rather simple, it’s technology rooted in the last millennium when 16-bit was the rage and GPUs weren’t installed de facto on your machine.  GDI did give way to GDI+ which was an attempt to modernize capabilities, like provide a transparency channel, but since it was still predicated on the original foundation (along with its fundamental limitations), there was only so much that could be improved.

Meanwhile, DirectX was out there on its own track, the stuff for game developers and high-performance graphics.  DirectX was built, more or less, from the ground up to support graphics cards, to handle software vs. hardware rendering, and so on.  Since GDI/GDI+ was about as mature as it could be, DirectX offered a way forward.  We’ve already seen DirectX go mainstream as the underlying graphics engine for WPF and Silverlight, and it’s clear the level of user experience it provides eclipses the prototypical ‘battleship-grey’ interfaces of the past.

So rather than continue the square-peg/round-hole battle with GDI/GDI+, why not build a new graphics subsystem leveraging the investment in DirectX?  And that’s where Direct2D and DirectWrite come in.  Let’s start from the bottom (right above the Kernel) and work up to the new Windows 7 features.

DirectX Graphics Infrastructure (DXGI) resulted from a refactoring of the DirectX runtime to provide better insulation from lower level details.  This allows the graphics components that sit above it to evolve more quickly and provides a framework to plug in new components.  The first ‘new’ component here is Direct3D 10, which was actually introduced in Windows Vista.

Direct3D 10 (or 10.1 as the most recent version is labeled) adds a number of new capabilities that hopefully the graphically-inclined among you can appreciate!  This ships with D3D10Level9, which is sort of a thunking layer that allows Direct3D 10 applications to work on Direct3D 9 hardware.

Direct3D 11, announced at Gamefest 2008, updates the graphics processing pipeline introducing more capabilities including tessellation.  Direct3D 11 also adds the capability to perform general purpose GPU processing (i.e., use the GPU as an extra CPU).

You can think of Direct2D as the successor of GDI/GDI+ for developers that want to bring the next generation of user experiences to their applications.  It’s built on the foundation of Direct3D and in Windows 7 provides efficient interoperability with the older APIs: you can write Direct2D content to a GDI device context, and you can use GDI right on a Direct2D render surface.

DirectWrite brings the enhanced “Direct2D experience” to text. It provides a device-independent layout system for text, to bring the on-screen reading experience closer to the print experience.  It leverages advancements in OpenType (an extension of TrueType) lending capabilities to native and WinForm developers that were previously not available.

Instead of digging into the APIs here (something better left to MSDN documentation in any case), let’s take a look at two scenarios involving Direct2D and DirectWrite to get a handle on how these technologies improve the user experience.

DirectWrite

If you compare text in a GDI (WinForms) application to that of a WPF application, you’ll probably notice some differences.  Both UI technologies do take advantage of ClearType, but GDI is essentially a generation behind in terms of what features it supports.  Most notably, WPF supports both sub-pixel positioning and y-axis anti-aliasing.

Sub-pixel positioning leverages the fact that each pixel is actually made up of three sub-pixels: red, green and blue.  By lighting up only one or two of the subpixels, a more precise ‘edge’ on the glyph boundary can be achieved.  Of course, if you’re turning off a color in the pixel, you introduce color fringes, and edges may appear more greenish, bluish, or reddish.  Depending on the individual’s color sensitivity, DPI settings, etc., this may or may not be an important issue.

y-axis anti-aliasing is best shown in a picture.  On the left, there is jaggedness near the top and bottom curves of the ‘e’, but on the right the image is crisp.   

GDI   DirectWrite


The left was generated via GDI and the right was generated using DirectWrite (and both are using ClearType).  That’s DirectWrite on the right, not WPF, meaning of course, that DirectWrite is now a mechanism that native developers and Windows Forms developers can engage to unlock the newer capabilities of ClearType.  It also unlocks other capabilities such as adornments, that GDI doesn’t render.  Below for instance is a sample of the new Gabriola font rendered in GDI on the left and DirectWrite on the right.

GDI with Gabriola   DirectWrite with Gabriola

Direct2D

For the recent Windows 7 launch event, my colleague Bob Familiar presented on the Direct2D and DirectWrite topic and demonstrated an application that brings to light the differences in the various rendering options.  

The application allows you to render a number of different graphical elements (bitmaps, lines, rectangles) and change the rendering method to demonstrate the differences in the technologies.  Below, you see the application rendering a Bezier curve.

Direct2D example

By changing the API and observing the frames-per-second (fps) as well as the rendering experience, you can get a better appreciation for the various tradeoffs.  The application also enables turning on-and-off anti-aliasing, which provides another dimension of performance versus appearance.

I’ve captured some statistics below based on my own rudimentary tests.  Focus on the relative values of the numbers; they varied quite a bit as I was executing the sample, and these were more-or-less eyeballed.

 

API fps fps
(Anti-aliased)
Comments
GDI 120 120 anti-aliasing not supported in GDI
GDI+ 32 26 definitely a penalty for enhanced capabilities!
D2D HW 415 160 anti-aliasing is expensive but still more responsive than GDI
D2D SW 70 50-130 FPS variance was pretty large (dependency on how much anti-aliasing needed on given frame)?
D2D DXGI 420 170 close to the D2D HW results but integration point is one level lower in the graphics stack
D2D WARP 65 25 on par with D2D SW, but relative disparity with anti-aliasing result is interesting

The last entry here, D2D WARP, refers to the Windows Advanced Rasterization Platform, which provides software rasterization capabilities and enables additional scenarios when graphics hardware is not available.  In my case, I would have expected results similar to Direct2D software rendering.

The Future

Admittedly, I’m scratching the surface here regarding the strengths and weaknesses of each approach, but the key point to take away is that Direct2D is the future of 2-dimensional rendering on Windows. 

Will GDI/GDI+ go away?  Certainly not in the near future, there’s far too many applications relying on it.  That said, there is a migration path here (you can intermingle GDI and Direct2D, for instance) and you should start equipping yourself to set out on that path.

But what if you’re using WPF now, you’re already tapping in to the DirectX pipeline, so is Direct2D relevant to you?  Well, as in all questions like this, the answer is ‘it depends.’ 

Direct2D (like GDI) is an immediate mode API, meaning you tell it everything required to render a portion of the screen.  WPF has retained-mode semantics; it stores the scene in the background and allows the application to directly interact with the graphical elements on it.  That makes for easier development, but less control.  In much the same way that Windows Forms programmers get closer to the metal by passing hWnds to API calls, WPF programmers have Direct2D to provide the additional control or performance, should they need it.

More Reading

Introducing Direct2D (MSDN Magazine – June 2009)

Introducing the Microsoft Direct2D API (Tom Olsen’s blog)

Comparing Direct2D and GDI (DirectX Developer Blog)

Direct2D on MSDN

DirectWrite on MSDN

Windows 7 Extended Linguistic Services (ELS): another cryptic name for some pretty powerful capabilities.  ELS is a platform supporting language processing with a consistent service-based API for language detection and transliteration.

So what’s in it for you?  Today, many of us are working in a very diverse and global economy, and assuming all the work you do in documents, e-mail, etc. is tied to a single culture (your Region and Language settings) is becoming less realistic.  ELS provides a way for developers to respond more richly to who is using their application at any given time.

Start typing Spanish in a document processing system, for instance, and the application could change the menus to Spanish, cue up the Spanish version of the help file, etc. – kind of a localization on-the-fly.  Consumer-centric media applications could automatically display news or top music and movies for the detected country.  It’s all about applications being more aware of who is using them - and as we’ll see with the sensor and location API – where they are being used.

As a native API, the framework is fairly compact.  It’s implemented via a static (elscore.lib) or dynamic (elscore.dll) library versus exposing a COM interface, as many other Windows 7 features do.  There are actually only a half-dozen methods in the API, providing a lightweight and consistent way to access any existing or future service.  As with most of the other Windows 7 APIs, the Windows API Code Pack provides a managed wrapper for those of us writing C# or Visual Basic code.

The general flow for engaging the framework is to

  1. Enumerate the services (native: MappingGetServices; managed: MappingService.GetServices static method), resulting in a list of available services (native: MAPPING_SERVICE_INFO structure; managed: MappingService class). At present there are three categories of services implemented: language detection, script detection, and transliteration; we’ll look at them later in this post.

  2. Call MappingRecognizeText (native) or MappingService.RecognizeText (managed) passing in a string to be processed by the designated service.  For native developers, the MAPPING_SERVICE_INFO structure is passed as an argument to MappingRecognizeText to indicate the service requested.  For managed developers, the service type is retained in the MappingService instance. 

    It’s also possible to perform the recognition asynchronously and pass in a callback routine, and since the framework itself supports this, the individual services do not need to implement asynchronous functionality on their own.
  3. Interpret the results.  For native developers the recognition function returns a MAPPING_PROPERTY_BAG structure, which for managed developers is wrapped by the MappingPropertyBag class.  That property bag contains a number of MAPPING_DATA RANGE structures (MappingDataRange class instances for managed developers), the interpretation of which varies depending on the invoked service.

  4. Have the service to do something with the results.  Each service may have a set of defined actions, and the ID of one of those actions is passed to the native method MappingDoAction or the managed method MappingService.DoAction, along with the mapping property bag.  The DoAction method can also be called asynchronously.

That’s it! Any service is invoked the same way.

So what services are available?  With Windows 7 there are three ‘in-the-box’: Language Detection, Script Detection, and Transliteration.  These services are identified by these same non-localizable strings, so you can use them (or alternatively a GUID) to locate the desired service among those enumerated in Step 1 above.

Language Detection [module: elslad.dll]

When text recognition occurs in the Language Detection service, the output (in the property bag) is a list of languages that are matches for the text, in order of confidence.  The languages are generally represented by their 2-letter (neutral) identifiers, like en for English, nl for Dutch, etc.  In some cases the full identifier is used, for instance to distinguish traditional Chinese (zh-Hant) from simplified Chinese (zh-Hans).

Script Detection  [module: elslad.dll]

Script detection refers to identifying the characters of the script in which the submitted text is written.   For instance, “Ich bin ein Berliner” is German (language: de), but the script is Latin.  You can find a list of all scripts and the number of characters within each on The Unicode Consortium site.

Note, there are two special script types:

  • Qaai, which comprises ‘inherited’ characters; these are combining characters like circumflexes and umlauts, and
  • Zyyy,  ‘shared’ characters, those that are regularly used in multiple scripts.  

With the Script Detection service, characters in these two special classifications are subsumed by the previous script range, or by the first script range if they are leading characters in the string.  In other words, the Script Detection service will not return Qaai or Zyyy as a script type.

The output that is returned is a set of ranges indicating the starting and ending index of each script type as well as the name of the script identified for that range. 

The following string, for instance, yields two ranges: Latn (Latin) from character 1 to 15 and Cyrl (Cyrillic) from characters 16 to 21.

 

This is English. АБВГД.

 

Transliteration [module: elstrans.dll]

The goal of this service – actually a category of services – should be self-evident. You provide an input string of a certain script type, and the service transliterates it, that is, it performs a character-by-character mapping from the source to the destination script type. 

These are the specific transliteration services available now in Windows 7:

  • Traditional to Simplified Chinese (zh-Hant to zh-Hans)
  • Simplified to Traditional Chinese (zh-Hans to zh-Hant)
  • Malayam to Latin
  • Cyrillic to Latin
  • Bengali to Latin
  • Devanagari to Latin

 

Try it Out

Check out the Extended Linguistic Services samples in the Windows API Code Pack.  You’ll find two solutions.  One is a simple console application that automatically exercises all three services.  The other is a Windows Forms application in which you can enter text for transliteration (or pull it from a file).  I think the screen shot from that sample application below pretty much says it all, wouldn’t you agree?

Transliteration example

Windows 7 It’s a stuffy-sounding name, but I’m finding the Federated Search capability in Windows 7 rather cool, and starting the see all kinds of uses of it to improve my own productivity.

Federated Search leverages the OpenSearch API and the common syndication formats of RSS and Atom to enable searching of enterprise and internet sources directly from Windows Explorer, with the results displayed just as if they were files on the local file system.

How it Works

The premise is rather straightforward and is captured by the diagram below (with explanation following).

Federated Search

  1. You first need to install a search connector in the form of an .osdx (OpenSearch description) file.  It’s simply an XML file that follows the schema detailed here.  Windows 7 has a file association for an .osdx already so when you double-click an .osdx file or download one from the Web, it will install the search connector for you.  [If you’re itching to do that now, there’s one for Channel 9 that you can download here].

  2. FavoritesOnce the connector has been installed, you’ll see an option in Favorites that will access the search capability.  This is actually just a shortcut to the real connector that’s been copied to your user profile’s Searches directory.

    Presuming the connector isn’t set up to automatically search, like say provide the most recent 10 posts on Channel 9, you’ll need to add your search criteria in Windows Explorer.


    Channel 9 search
    What you’re actually setting in motion here is a call to the search provider specified in the .osdx file.  For Channel 9, it’s just a straightforward URL:

    http://channel9.msdn.com/Search/feed/rss/?Term={searchTerms}

    In this scenario, what I typed into the search box in Windows Explorer (Northeast Roadshow) is substituted for the {searchTerms} placeholder, and the HTTP request is sent over the wire.

  3. The Channel 9 search service then does its job and returns results in RSS format. If you have "Feed Reading View" turned off in Internet Explorer, you'll actually be able to see the raw markup just by entering the same URL in a browser.

    RSS feed

  4. Given that RSS (and the alternative Atom) feeds are well-known formats, Windows Explorer can parse the output and assign semantic meaning based on the various tags.  For instance, the <title> tag is an obvious choice for the main item of the search result, and <description> seems pretty clear too, so you end up with the results below.

    Search Results

Customizing the Display

Now comes the fun part.  You actually have a bit of control over what information is displayed and where.  One area you can customize is the Content View (the area showing information for each search result).  That view can display up to seven fields, placed as follows:

 

Search result fields

 


Obviously, there’s a default placement and assignment of information from the feed to the various slots, but that can be overridden either in the search results (via additional tags embedded the Atom or RSS markup) or, conveniently, in the client .osdx file.  If you open the .osdx file in Notepad or any other text editor, you can get a better idea of how things work.

Now, remember that the feed that comes back is the result of the URL referenced in the .osdx file, so there may be other information of interest in that feed that you want to surface within Windows Explorer.  Three things that stand out to me from the RSS markup above are the number of views, the date of publication, and the link to the associated blog post, so let’s modify the output to include those.

The key to doing this is realizing that each slot in the layout can be occupied by a Shell property associated with the search item result.  By coupling a known shell property with a specific data item in the RSS feed, you can populate the search result view as you’d like to see it.  There is a default mapping of items in the RSS feed to shell properties which drives how the search results look now; here’s a few of them:

RSS XML Path Windows Shell Property (Canonical Name)
Link System.ItemUrl
Title System.ItemName
Author System.Author
pubDate System.DateModified
Description System.AutoSummary
Category System.Keywords

But I’m looking to get a display something like the following, where I’ve highlighted the new items.  Note, I also got rid of the size and tags fields.


Search results (improved)

 

What I need to do first is map the property values in the RSS to some Shell properties; the table below summarizes my choices.

RSS tag RSS namespace Shell Property
pubDate default System.DateModified
evnet:views http://www.mscommunities.com/
rssmodule/
System.Search.HitCount
comments default System.OriginalFileName


Additional XML added to the .osdx file captures this mapping:

.osdx mapping markup

The ResultsProcessing tag (unclosed in the snippet above) envelops tags to provide a customization of the base RSS results.   That’s followed by a number of PropertyMap tags.  Each of those names a Source property in the RSS (possibly qualified by a sourceNamespaceURI) and maps it to a Shell property, the name of which is the attribute of the child Property tag.

You might ask how I knew which Shell properties to use.  While I couldn’t find a definitive resource, I selected these based on their relative correlation to what I was trying to display.  Some Shell properties are used by the results processing step itself (like System.Item.PathDisplay) so you can’t use them.

Now that I have the source data mapped the Shell properties, I need to specify how I want them placed in the user interface.  Enter another bit of XML:

ContentViewModeForSearch


The PropertyDefaultValues tag (which is another child node of ResultsProcessing)wraps the ContentViewModeForSearch property, indicating the intention to adjust the layout of the seven items in the search results line.  You can adjust the layout in the details at the bottom of Windows Explorer as well as the tooltip, but that’s an exercise left to the reader!

The value for the property is the literal string “prop:”, followed by a semi-colon delimited list of Shell properties ordered according the field map above.  You should always have seven Shell properties in this list; if you want to leave a slot empty, specify the property System.LayoutPattern.PlaceHolder, versus leaving it blank.   Parsing the string in the snippet above and overlaying it on the ‘map’ results in something like this:

 Search result layout

 

By default, the values will be preceded with a label that’s associated with it by the handler for that Shell item.  If you don’t want to see the label, preface the property with the tilde character.   Lastly, be sure there is no white space in this string, including preceding the “prop:” literal, or you’ll results will not display correctly (if at all).

Hopefully, if you wanted to follow along, you were successful in your venture.  I’ve also uploaded the final .osdx file to this blog post in case you want to start there and deconstruct it.

Additional Resources

There’s definitely a lot going on under the covers here, and mucking with the base XML is error-prone (for me at least!).  For more detailed documentation to help fill in the gaps, check out:

Federated Search in Windows 7 (MSDN)

Creating an Open Search Description File

SQL Server Connector Example

Be aware too, that we really just discussed the client part.  You can write your own WCF services that return Atom or RSS to provide a search over just about anything you like.  You can even write a local provider that implements IOpenSearchSource.  Just make sure you follow the OpenSearch guidelines and best practices as much as possible to ensure a smooth integration into the Windows Explorer experience.

Windows 7 One of the more noticeable changes in the Windows 7 experience is the refinement of the taskbar. 

Whoa! This looks like lots of reading; is there a movie?

Taskbar Geography

In Windows 7, the taskbar has three distinct areas: the Start menu button, the taskband, and the notification area.

The Start menu has been enhanced to support the notion of most recently (or frequently used) documents and to better surface shutdown options, but overall it has pretty much the same role as it did in Windows Vista. 

The notification area has been streamlined, so the most icons you’ll see by default there are just four.  Associated with the notification area is an overflow (popup) to store application-specific icons that previously would have cluttered up the area.  The idea here is that the user is in charge, so it’s up to them, not the application, to decide which icons to surface directly on taskbar.  (Check here for user interface guidelines.)

Notification area

The most dramatic change is undoubtedly in the taskband itself.  Rather than provide an icon for launching an application and additional icons for currently executing applications, Windows 7 combines the notion of application launching and switching.  The appearance of the icon indicates the current state of affairs. 

For instance, in the snippet below, Windows Explorer is pinned to my taskbar, but there are no open windows for it.   The frame around the Outlook icon indicates that indeed Outlook is open.  The stacking effect on the IE icon signifies that there are multiple IE windows (or web pages) currently open.  The last icon, for Live Writer, is framed indicating a window is open, but beyond that, the highlighting shows it’s the active application as well.  Windows 7 will use the predominant color of your application icon to create the highlight effect, so your own icon’s design and color choice significantly affects your users’ experience.

Taskbar icons

 

For the most part, Windows 7 and the underlying Desktop Window Manager (DWM) manage the launching and switching experience for you.  Items have an affinity for a specific taskband icon based on the Application User Model Id (or AppUserModelId), a string value assigned by the developer.   Each application, or windows within the application, as well as jumplist items (introduced later in this article) can be assigned an AppUserModelId, which determines how the application and windows within it are represented on the taskbar.

By default, an AppUserModelId is generated heuristically for legacy applications, so they’ll just do the expected thing, but you have flexibility for instance to:

  • create a taskbar presence for a specific window within the application, by assigning a unique AppUserModelId to that window (a one-to-many approach).

  • create a taskbar presence that different executables can share by reusing the same AppUserModelId  across those applications (a many-to-one approach).

In your application, you might consider setting an AppUserModelId just in case you want to take advantage of this flexibility later.  As you might expect, there’s a new API for that (the not-so-succinct SetCurrentProcessExplicitAppUserModelID).

Presuming you’re using the Windows API Code Pack (and I’ll assume you are for this and other articles in the series), you’ll use code such as the following:

   1: String appId = "com.mycompany.PicViewer";
   2: TaskbarManager.Instance.ApplicationId = appId;

 

Thumbnail Previews

Windows 7 also expands on the notion of preview that debuted in Vista’s Aero feature.  An application can expose multiple preview thumbnails, as IE does.  When you hover over a thumbnail, the Aero Peek feature takes over, rendering all other windows in the application as transparent so you can immediately find the window of interest, as shown below.


Toolbar thumbnails & Aero Peek

 

The Desktop Windows Manager (DWM) does a lot of this work for you, but it only knows about ‘top-level’ windows by default.  In IE, for instance, each of the thumbnails is not really a separate instance of IE, but rather a tab within the IE window.  For tabbed-document interfaces (TDI) and multiple-document interfaces (MDI), you have to programmatically expose the child windows as main windows so that the DWM surfaces them as desired.

To do so, you essentially create an off-screen (or proxy) window for the child window, and let DWM do the rest.  At a low level, you’re interacting with the RegisterTab method of the ITaskbarList3 interface.  Within managed code and the Windows API Code Pack, you create a new instance of the TabbedThumbnail class.  Registering that class with the Taskbar manager (line 19 below) creates the association with the main window and the tab or child window that should have its own preview thumbnail.  You can also assign a title and icon to appear in the fly-out (lines 3 and 6):

   1: TabbedThumbnail thumbnail = new TabbedThumbnail(this.Handle, childForm.Handle)
   2:     {
   3:         Title = System.IO.Path.GetFileName(PathOrUrl),
   4:         DisplayFrameAroundBitmap = true
   5:     };
   6: thumbnail.SetWindowIcon(childForm.Icon);
   7: thumbnail.TabbedThumbnailBitmapRequested += (o, e) =>
   8: {
   9:     try
  10:     {
  11:         e.SetImage(new Bitmap(childForm.picImage.Image));
  12:         e.Handled = true;
  13:     }
  14:     catch
  15:     {
  16:         e.Handled = false;
  17:     }
  18: };
  19: TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(thumbnail);

The TabbedThumbnailBitmapRequested event (line 7) is the workhorse here.  This event is a wrapper for responding to two new Window messages:

It’s up to your application to provide the image.  In line 11 above, the assumption is that there’s an image control on the childForm that will provide the preview.  The preview could, however, be a completely different image or perhaps a clip region of the original image.

 

Thumbnail Toolbar Buttons

Thumbnail Toolbar buttonsTake a look at the enhanced experience provided by Windows Media Player to the left.  Notice that the preview is accompanied by VCR-style buttons at the bottom, allowing the user to interact with the application just via the thumbnail.

You can programmatically add your own buttons (up to seven of them) as well; in managed code, it’s via the ThumbnailToolbarButton class (a THUMBBUTTON structure in the unmanaged world).  Although you can’t add and remove them dynamically, you can toggle their visible and enabled properties.

Each button has, of course, a Click event and that’s where you can put your application-specific code.

 

Overlay and Progress indicators

In concert with the overall goal for Windows 7 to not take attention away from your task, as alerts and ‘toast’ in the notification area tend to do, you can surface application state directly on the icon itself.

Via the SetOverlayIcon method (available on the ITaskbarList3 interface and the managed TaskbarManager class) you can provide a 16x16 icon overlay to represent the state of the application: perhaps a connected/disconnected icon to indicate the state of the network connection, for instance.

Icon overlay

 

Progress: stalledProgress: OK

You can also superimpose a progress bar on the icon, color-coded to the state of the progress (ok, paused, or error).  There’s an API to provide the information explicitly (SetProgressValue and SetProgressState), but you get the feature free as well if you are already plugging into the standard progress dialog, as SHFileOperation and IFileOperation do.

 

Jumplist

IE8 Jumplist The jumplist exposes an application-specific start menu for your application.  Internet Explorer 8 takes advantage of this capability by exposing specific features of use to the consumer as you can see to the right.

Each jumplist has four distinct sections:

  1. Pinned – these are documents and links the customer wants to always see in the list.  Since the ‘user is in charge,’ an application cannot programmatically manipulate this area.

  2. Launch area – this is the bottommost section which always contains three options for running applications or two for pinned applications (where “close” is omitted).  The DWM surfaces these items automatically, even for legacy applications.  As with the Pinned section, applications cannot modify these options.

  3. Destinations – these are (generally) documents that the application has acted upon (recent or frequent list) or which your application wants to surface to the user.  Above you can see that IE shows a Frequent group; Office applications instead show a Recent group.  These categories and the documents within them area managed by the Windows Shell.  For an application to take advantage of these groups, it merely needs to associate itself with the various file extensions supported by the applications.  File associations (such as .docx with Microsoft Word) are typically addressed as part of the installation of the application via registry entries, something that many legacy application are already plugged into.

    In addition to the built-in Frequent and Recent options, you can add your own custom categories and documents within them.  At the OS level, these entries are IShellItem instances and wrapped via the JumpListItem class in the Windows API Code Pack.  To build a custom category, you merely populate a collection of the items you want and apply them to the taskbar instance (via ICustomDestinationList.AppendCategory for unmanaged developers or Jumplist.AddCustomCategories for the managed folks).

  4. Tasks – while destinations are typically documents that the application will act on, tasks are common operations that user carries out from the context of the current application; tasks themselves can launch other applications. There can be only one task list per jumplist, but the mechanism for adding tasks is similar to what you do to add custom destinations.  Tasks generally equate to IShellLink instances (JumpListLink in the managed world), and collections of them are added via the AddUserTasks method.

 

Show Me the Code

For an example that brings all of this together, take a look at PicViewer, a very simplistic MDI application I created to demonstrate programming against the Taskbar API for a recent Northeast Roadshow presentation.

PhotoView is a more substantial example that illustrates the user of this and other Windows 7 light-up features. As the “XP to Windows 7 reference app,” it also demonstrates how to retain backward compatibility for XP users while providing an enhanced experience to Windows 7 consumers.

 

The Movie Version

Of course it’s not as good as the book (above), but spend 15 minutes and get the low down on everything in this post, including a peek at real, live code!

Get Microsoft Silverlight

Windows 7The first Windows 7 feature I’m going to talk about is - of all things  - Windows XP, well, more exactly, Windows XP Mode.  In a nutshell, XP Mode allows you to run legacy applications in an XP virtual machine right on Windows 7.  It may seem a bit counterintuitive to perpetuate an operating system that has already reached the end of its mainstream support, but the WHO, WHAT, WHERE, WHEN, WHY, and HOW below should give you a good idea of the rationale and target audience.  In addition, I recommend Running Windows XP Mode with Windows Virtual PC: A How-to Guide for Small Businesses for more details.

 

WHAT

Windows XP Mode is a virtual PC image of Windows XP Service Pack 3 that can be run on Windows 7 Professional, Enterprise or Ultimate.  It requires a hardware chipset and BIOS supporting virtualization.  Most newer AMD and many Intel chips do support this configuration.  There’s a utility available on the download page you can use to see if your own system is supported.

Applications installed into Windows XP Mode can be run in Desktop Mode or Seamless Mode.  In Seamless Mode, applications appear to run natively within Windows 7, but are actually running inside the Windows XP virtual machine.

Desktop Mode

Windows XP Mode with IE 6 in Desktop Mode

Seamless Mode

Windows XP Mode with IE 6 in Seamless Mode (left) and IE 8 (right)

 

Windows XP Mode provides additional integration that traditional Virtual PC images do not:

  • Applications installed on the XP image can be exposed to the Windows 7 Start menu (auto publish)
  • Applications run in seamless mode have automatic access to the Windows 7 known folders (Documents, Pictures, Desktop, Music, etc.)
  • Cut-and-paste is enabled between native Windows 7 applications and those running in Windows XP Mode.
  • Applications running in Windows XP Mode can access your Windows 7 network connection and USB devices.

WHY

Deploying a new operating system is a scary proposition, especially in light of the tarnished reputation of Microsoft Vista.  Many users and businesses have retained an affinity to Microsoft XP, and many of us are certainly running older versions of in-house or 3rd-party software as part of our normal workflow.

The emphasis on application compatibility in Windows 7 and the fact Windows 7 extends the investment in Vista should provide a pain-free upgrade experience for Vista users specifically.   For Windows XP, the application compatibility lessons learned with Vista have also been folded into the Windows 7 release.

That said, there’s always a chance an application isn’t going to work well (or at all) on Windows 7, perhaps because of some change in the operating system but more likely due to implementation decisions made by the software designer (e.g., reliance on operating system version numbers or failure to account for non-administrative users).

Windows XP Mode provides the best of both worlds for people affected by such incompatibilities.  You can start running Windows 7 right away and take advantage of the myriad features and enhancements, but retain peace-of-mind knowing that your old workhorse applications are still available – from the Start menu, no less.  Hopefully, the vendor of that application is busy on an upgrade that’s Windows 7 friendly, but in the meantime you can adopt Windows 7 on your schedule rather than theirs.

WHO

If you have a licensed copy of Windows 7 Professional, Enterprise, or Ultimate, you’re entitled to a copy Windows XP Mode.  Windows XP Mode does require installation of Windows Virtual PC as well.  Both Windows Virtual PC and Windows XP Mode are available as downloads.

Windows XP Mode is intended for individuals or smaller offices (say 25 or less machines). Each XP Mode installation is controlled by the end-user.  It is not really a solution for organizations requiring centralized management and deployment of images; that’s the domain of another virtualization option MED-V, which is part of the Microsoft Desktop Optimization Pack (MDOP).

WHERE

Download Windows XP Mode and Windows Virtual PC here. 

WHEN

Whenever… the RTM (Release to Manufacturing) version became available on October 22nd, coincident with the release of Windows 7.

HOW

    1. Determine if your machine supports hardware virtualization.  This utility can help.
    2. Download both Microsoft Virtual PC and Windows XP Mode.
    3. Remove any beta or RC versions of both products.
    4. Install Windows XP Mode.
    5. Install Microsoft Windows Virtual PC.
    6. Reboot to finish the installation steps.
    7. Launch Windows Virtual PC>Windows XP Mode and follow the configuration steps.

Start Menu with XP Mode options Any applications you now install within Windows XP Mode should also surface on the Windows 7 Start menu (see right). 

If there’s an application that’s preinstalled that you wish to expose to Windows 7, like IE 6 here, create a shortcut in the XP virtual machine and copy it to the C:\Documents and Settings\All Users\Start Menu folder there.

Windows 7Given that Windows 7 is now mainstream, I thought I’d spend some time highlighting some of the main features that developers can leverage.  Beginning tomorrow and over the next week, I’ll have a post a day on one of the new APIs or capabilities enabled by Windows 7.  [For those of you at Boston Code Camp 12 or planning to attend the Tech Valley Code Camp, this will all sound very familiar!]

My posts obviously can’t go into great detail of all that Windows 7 has to offer, so make sure you’ve got some bookmarks set to the following sites as you begin to explore the capabilities of the new operating system.

  • Windows 7 Developer Center on MSDN
  • Windows 7 Training Kit – a download providing code samples, hands-on labs, presentations, and demos that highlight the new features.
  • Windows SDK – in ISO or web download format.
  • Windows 7 on Channel 9 – awesome introductions and deep-dives into the new features by the Windows 7 Technical Evangelist, Yochay Kiriaty, and members of the Windows 7 engineering teams.
  • Windows API Code Pack – managed code wrappers for most of the new APIs offered by Windows 7 (sensor and location, Direct2D, taskbar and libraries, etc.).
More Posts Next page »
 
Page view tracker