Friday, September 19, 2008
Smart Device Framework 2.3 is really close to release - we've frozen the code base and have been working on the installer (a large chunk of work since we're getting it fully automated).  The hope is that with all of this CI infrastructure in place, we'll be able to turn SDF releases far more frequently (right now it's taken over a month to go from the decision to release to get where we are - and the release still hasn't shipped). 

In order to turn out releases more often, we need ideas for features to add - after all we need a reason to release.  This is where you come in.  Navigate over to the SDF Product Page and you'll see a new "Feedback" widget over on the side (courtesy of UserVoice).Click on it and create or vote for feature ideas.

We've also added the widget to the Padarn page, so if you've a Padarn user, let us know what you'd like to see there too.


Smart Device Framework Suggestions

Padarn Suggestions

9/19/2008 12:54:42 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [2]  | 
 Thursday, September 18, 2008
As part of our push to implement continuous integration, we need to have TFS generate CAB files for us.  Unfortunately the only tool we have for this is the archaic piece of crap CABWIZ and it's not a very friendly tool for automating.  What we did was create a custom build task that calls cabwiz for you and will output the error file back to the build log on failure. Now all we have to do is add this to our build script:

    <CabWiz
      InfPath="$(CABFolder)\SDF.INF"
        ErrorLog="Error.log"
        OutputPath="$(CABFolder)" />


The custom build task looks like this:

namespace OpenNETCF.Build.Utilities
{
  using System;
  using System.IO;
  using System.Text;
  using Microsoft.Build.Framework;
  using Microsoft.Build.Utilities;
  using Microsoft.Win32;
  using System.Diagnostics;

  /// <summary>
  /// Uses CabWiz to create a Smart Device CAB installer.
  /// </summary>
  /// <example>
  /// <code><![CDATA[
  /// <CabWiz
  ///   InfPath="MyApp.inf"
  ///   ErrorLog="Error.log"
  ///   WorkingFolder="..\Build"
  ///   Cpu="x86"
  ///   Compress="true"
  ///   NoUninstall="false"
  ///   OutputPath="..\Release"
  ///   Platform="wm"
  ///   PreXml="Pre.xml"
  ///   PostXml="Post.xml"
  /// />
  /// ]]></code>
  /// </example>
  public sealed class CabWiz : ToolTask
  {
    [Required]
    public string InfPath { get; set; }

    public bool Compress { get; set; }
    public string Cpu { get; set; }
    public string ErrorLog { get; set; }
    public bool NoUninstall { get; set; }
    public string OutputPath { get; set; }
    public string Platform { get; set; }
    public string PostXml { get; set; }
    public string PreXml { get; set; }

    private static string CabWizSubPath
    {
      get { return @"SmartDevices\SDK\SDKTools"; }
    }

    protected override string ToolName
    {
      get { return "cabwiz.exe"; }
    }

    public override bool Execute()
    {
      bool ret = base.Execute();

      if (!ret)
      {
        string path = Path.GetDirectoryName(InfPath);
        path = Path.Combine(path, ErrorLog);

        if (File.Exists(path))
        {
          Log.LogMessageFromText(string.Format("!!! BEGIN CABWIZ ERROR FILE DUMP !!!", path), MessageImportance.High);
          Log.LogMessagesFromFile(path, MessageImportance.High);
          Log.LogMessageFromText(string.Format("!!! END CABWIZ ERROR FILE DUMP !!!", path), MessageImportance.High);
        }
        else
        {
          Log.LogMessageFromText(string.Format("CABWIZ: Couldn't find error log at '{0}'", path), MessageImportance.High);
        }
      }
      return ret;
    }

    protected override string GenerateFullPathToTool()
    {
      if (String.IsNullOrEmpty(ToolPath))
      {
        string path = string.Empty;
        using (RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0\Setup\VS", false))
        {
          if (regKey != null)
          {
            path = (string)regKey.GetValue("ProductDir");
          }
        }
        ToolPath = Path.Combine(path, CabWizSubPath);
      }

      return Path.Combine(ToolPath, ToolName);
    }

    protected override string GenerateCommandLineCommands()
    {
      GenerateFullPathToTool();
      StringBuilder cabWizArgs = new StringBuilder();
      cabWizArgs.AppendFormat("\"{0}\" ", InfPath);

      if (!string.IsNullOrEmpty(OutputPath))
      {
        cabWizArgs.AppendFormat("/dest \"{0}\" ", OutputPath);
      }

      if (!string.IsNullOrEmpty(ErrorLog))
      {
        cabWizArgs.AppendFormat("/err \"{0}\" ", ErrorLog);
      }

      if (!string.IsNullOrEmpty(PreXml))
      {
        cabWizArgs.AppendFormat("/prexml \"{0}\" ", PreXml);
      }

      if (!string.IsNullOrEmpty(PostXml))
      {
        cabWizArgs.AppendFormat("/postxml \"{0}\" ", PostXml);
      }

      if (!string.IsNullOrEmpty(Cpu))
      {
        cabWizArgs.AppendFormat("/cpu {0} ", Cpu);
      }

      if (!string.IsNullOrEmpty(Platform))
      {
        cabWizArgs.AppendFormat("/platform {0} ", Platform);
      }

      if (Compress)
      {
        cabWizArgs.Append("/compress ");
      }

      if (NoUninstall)
      {
        cabWizArgs.Append("/nouninstall");
      }

      Log.LogMessage(MessageImportance.High, cabWizArgs.ToString());
      return cabWizArgs.ToString();
    }
  }
}


9/18/2008 10:22:34 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [1]  | 
 Wednesday, September 10, 2008
Every now and then (much less now that .NET languages have been around are are pretty mature) I see people who are moving into .NET programming and they ask "which is better, C# or VB.NET."  Generally speaking there is no "better" but there are some things available in one language but not the other.  Typically I've always thought that C# had just a little more - it has the ability to support unsafe code, which I like and use occasionally.  I could never come up with something VB had that C# didn't.  Until today.

A friend asked me how he could use the Contains() method of a string inside a case statement, and it reminded me of an old VB 6 construct that I'd used, so I tried it to be sure VB.NET still supported it, and sure enough, it works fine:

        Dim myvar As String = "My Test String"

        Select Case True
            Case myvar.Contains("not there")
                Debug.WriteLine("Contains 'not there'")
            Case myvar.Contains("Test")
                Debug.WriteLine("Contains 'Test'")
            Case myvar.Contains("Other")
                Debug.WriteLine("Contains 'Other'")
        End Select

However the construct won't work in C#.  It won't even compile because C# expects case labels to be constants.

        string myvar = "My Test String";

        switch (true)
        {
          case myvar.Contains("not there"):
            Debug.WriteLine("Contains 'not there'");
            break;
          case myvar.Contains("Test"):
            Debug.WriteLine("Contains 'Test'");
            break;
          case myvar.Contains("Other"):
            Debug.WriteLine("Contains 'Other'");
            break;
        }

So there you go VB lovers - score on point for your side.  I'm not saying that I'm going to start writing all my code in VB now (not that I have anything against VB, I mean I did co-author a book on it, I'm just really rusty) but here's some fodder for what some consider a religious debate.

9/10/2008 11:55:08 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0]  | 
 Wednesday, September 03, 2008
Here's another quick peek at an upcoming class in the next release of the SDF:

Object Model

keyhook2.PNG

Usage

    private KeyboardHook m_keyHook;
    
    public Form1()
    {
      m_keyHook = new KeyboardHook();
      m_keyHook.KeyDetected += OnKeyDetected;
      m_keyHook.Enabled = true;
    }

    void OnKeyDetected(OpenNETCF.Win32.WM keyMessage, KeyData keyData)
    {
      // Do Stuff
    } 


Sample App in the SDF

keyhook1.PNG

9/3/2008 1:40:08 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [4]  | 
 Thursday, August 28, 2008
This afternoon I learned of a few APIs that I was completely unaware of (that would have made my life a lot easier on some earlier projects).  3 hours later, We have this fully implemented:

radios.PNG

Usage looks like this:

Radios radios = Radios.GetRadios();

Debug.WriteLine("\nBefore\r\n--------");
foreach (IRadio radio in radios)
{
  Debug.WriteLine(string.Format("Name: {0}, Type: {1}, State: {2}", radio.DeviceName, radio.RadioType.ToString(), radio.RadioState.ToString()));

  // toggle all radio states
  radio.RadioState = (radio.RadioState == RadioState.On) ? RadioState.Off : RadioState.On;
}

// give the radios enough time to change state - some (like BT) seem to be slow
Thread.Sleep(1000);

radios.Refresh();

// display again
Debug.WriteLine("\r\nAfter\r\n--------");
foreach (IRadio radio in radios)
{
  Debug.WriteLine(string.Format("Name: {0}, Type: {1}, State: {2}", radio.DeviceName, radio.RadioType.ToString(), radio.RadioState.ToString()));
}
Debug.WriteLine("\r\n\n");
Thread.Sleep(100);


The only down side is that they are WinMo 5.0 and later only, so sorry CE devs.

I'm going to add it to the SDF source tree so it will be in the next release (soon, I promise).

8/28/2008 5:25:21 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [2]  |