Friday, March 03, 2006

One of my colleagues recently purchased the Treo 700w and fall in love with it. Being a developer he came up with the idea to try to use the button on the phone's headphones to initiate the Voice Commander. So he approached me with the question on how to place a hook in the WM device in order to listen for all hardware button presses. As a matter of fact, Windows CE does support a keyboard hook through the SetWindowsHookEx API. This API requires the usage of the native callback, which was not possible in the first version of the CF. The current version of .NetCF empowered us with this very useful capability. So what are hooks? Put shortly, a hook is a function that you can create as a part of your application in order to monitor on the messages inside the operating system. Hooks were provided by Microsoft primarily to help developers with the debugging their applications. The incorrect usage of them very easily could bring the system down. Therefore the hooks should be a last resort when all other a more traditional methods don't satisfy your requirents. Below you will find the class HookKeys that wraps all appropriate API calls and exposes all catched messages as a managed HookEvent:

public class HookKeys

{

        #region delegates

 

        public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

        public delegate void HookEventHandler(HookEventArgs e, KeyBoardInfo keyBoardInfo);

 

        public HookEventHandler HookEvent;

 

        #endregion

 

        #region fields

 

        private HookProc hookDeleg;

        private static int hHook = 0;

 

        #endregion

 

 

        public HookKeys()

        {

 

        }

 

        #region public methods

        ///

        /// Starts the hook

        ///

        public void Start()

        {

            if (hHook != 0)

            {

                //Unhook the previouse one

                this.Stop();

            }

 

            hookDeleg = new HookProc(HookProcedure);

            hHook = SetWindowsHookEx(WH_KEYBOARD_LL, hookDeleg, GetModuleHandle(null), 0);

 

            if (hHook == 0)

            {

                throw new SystemException("Failed acquiring of the hook.");

            }

        }

 

        ///

        /// Stops the hook

        ///

        public void Stop()

        {

            UnhookWindowsHookEx(hHook);

        }

 

        #endregion

 

        #region protected and private methods

 

        protected virtual void OnHookEvent(HookEventArgs hookArgs, KeyBoardInfo keyBoardInfo)

        {

            if (HookEvent != null)

            {

                HookEvent(hookArgs, keyBoardInfo);

            }

        }

     

 

        private int HookProcedure(int code, IntPtr wParam, IntPtr lParam)

        {

           KBDLLHOOKSTRUCT hookStruct =  (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));

 

           if (code < 0)

                return CallNextHookEx(hookDeleg, code, wParam, lParam);

 

           // Let clients determine what to do

           HookEventArgs e = new HookEventArgs();

           e.Code = code;

           e.wParam = wParam;

           e.lParam = lParam;

 

           KeyBoardInfo keyInfo = new KeyBoardInfo();

           keyInfo.vkCode = hookStruct.vkCode;

           keyInfo.scanCode = hookStruct.scanCode;

           OnHookEvent(e, keyInfo);

 

           // Yield to the next hook in the chain

           return CallNextHookEx(hookDeleg, code, wParam, lParam);

 

       }

 

        #endregion

 

       #region P/Invoke declarations

 

       [DllImport("coredll.dll")]

       private static extern int SetWindowsHookEx(int type, HookProc hookProc, IntPtr hInstance, int m);

 

       [DllImport("coredll.dll")]

       private static extern IntPtr GetModuleHandle(string mod);

 

       [DllImport("coredll.dll")]

       private static extern int CallNextHookEx(

               HookProc hhk,

               int nCode,

               IntPtr wParam,

               IntPtr lParam

               );

 

       [DllImport("coredll.dll")]

       private static extern int GetCurrentThreadId();

 

       [DllImport("coredll.dll", SetLastError = true)]

       private static extern int UnhookWindowsHookEx(int idHook);

 

       private struct KBDLLHOOKSTRUCT

       {

           public int vkCode;

           public int scanCode;

           public int flags;

           public int time;

           public IntPtr dwExtraInfo;

       }

 

       const int WH_KEYBOARD_LL = 20;

 

       #endregion

   }

 

        #region event arguments

  

    public class HookEventArgs : EventArgs

    {

        public int Code;    // Hook code

        public IntPtr wParam;   // WPARAM argument

        public IntPtr lParam;   // LPARAM argument

    }

 

    public class KeyBoardInfo

    {

        public int vkCode;

        public int scanCode;

        public int flags;

        public int time;

    }

 

        #endregion

 

 

In order to use this class in your program, just declare the varialble and hook up into HookEvent:

 

HookKeys hook = new HookKeys();

hook.HookEvent += new HookKeys.HookEventHandler(HookEvent);  

The HookKeys class should work properly, but there is something missing from this class to be complete. I am not going to tell you what it is. This is going to be a self learning quiz for my readers. You can post the anwers in the comments. I'll anounce the winners in the next post.

3/3/2006 10:32:08 PM (GMT Standard Time, UTC+00:00)  #     | 
 Friday, February 24, 2006

Ever wanted to display images in the header of a ListView control in the .NET CF application? Sure we can do that. The Windows CE SDK documentation reveals that practically all messages that are available on a desktop are supported by the ListView. In particular we should be interested in HDM_SETITEM message which supposed to be send to the ListView header with the pointer to the HDITEM structure.  Fifteen minutes later I had this class ready:

public class ListViewHeaderIcon

{

        IntPtr hWndHeader;

        ListView listView;

 

        public ListViewHeaderIcon(ListView listView)   

        {

            this.listView = listView;

            //Get HWND of the header

            hWndHeader = SendMessage(listView.Handle, LVM_GETHEADER,

             IntPtr.Zero, IntPtr.Zero);

        }

        public void SetHeaderImage(int columnIndex, int imageIndex, bool placeOnRight)

        {

            //Make sure that we have handle of the header

            if (hWndHeader == IntPtr.Zero)

                throw new Exception("Handle of header does not exist.");

 

            //Create HDITEM and populate with values

            HDITEM hdItem = new HDITEM();

 

            hdItem.mask = HDI_TEXT | HDI_IMAGE | HDI_FORMAT;

            hdItem.fmt = HDF_STRING | HDF_IMAGE | (placeOnRight ? HDF_BITMAP_ON_RIGHT : 0);

            hdItem.iImage = imageIndex;           

            hdItem.pszText = Marshal.StringToBSTR(listView.Columns[columnIndex].Text);

                     

            //Sending HDM_SETITEM message

            SendMessage(hWndHeader, HDM_SETITEM, (IntPtr)columnIndex, ref hdItem);

 

        }

 

        #region P/Invokes

 

         const uint HDM_FIRST = 0x1200;

         const uint HDM_SETITEM = HDM_FIRST + 12;

         const uint HDI_FORMAT = 0x0004;

         const uint HDI_TEXT = 0x0002;

         const uint HDI_BITMAP = 0x0010;

         const uint HDI_IMAGE = 0x0020;

         const int HDF_STRING = 0x4000;

         const int HDF_BITMAP = 0x2000;

         const int HDF_IMAGE = 0x0800;

         const int HDF_BITMAP_ON_RIGHT = 0x1000;

         const uint LVM_FIRST = 0x1000;

         const uint LVM_GETHEADER = LVM_FIRST + 31;       

 

        [DllImport("coredll.dll")]

         static extern IntPtr SendMessage(IntPtr hWnd,

         uint uMsg, IntPtr wParam, ref HDITEM lParam);

 

        [DllImport("coredll.dll")]

        static extern IntPtr SendMessage(IntPtr hWnd,

        uint uMsg, IntPtr wParam, IntPtr lParam);

       

        struct HDITEM

        {

            public uint mask;

            public int cxy;

            public IntPtr pszText;

            public IntPtr hbm;

            public int cchTextMax;

            public int fmt;

            public int lParam;

            public int iImage;

            public int iOrder;

            public uint type;

            public IntPtr pvFilter;

        }

 

        #endregion

 

 }

As you can see, the SetHeaderImage accepts the index of the column, index of the image from the ImageList that is ssigned to the SmallImageList property of the ListView and a boolean that you can use to show the image left or right justified.

In order to use this class, drop ther ListView on your form, populate it with some data. Don't forget to add the ImageList with some images and assign it to the SmallImageList property:

ListViewHeaderIcon header = new ListViewHeaderIcon(listView1);

 

for (int i = 0; i < listView1.Columns.Count; i++)

{

     header.SetHeaderImage(i, i, false);

}

Here is a screen shot of the sample:

2/24/2006 8:11:54 PM (GMT Standard Time, UTC+00:00)  #     | 
 Tuesday, February 07, 2006

In one of the comments to the post “Licensing classes in the SDF v2 (part 2)” a user asked a question about a way to tie up the license to the particular device and prevent coping licensed component or application between different user devices. This requirement would make the licensing process a little bit more complicated by adding a few more steps. It is driven by the fact that you will need to include the device id into the license key which later is signed with your private key. Evidently, you will have to add some code in your application that:


1. Will retrieve this device id (that's the easy part - just use the OpenNETCF.WindowsCE.DeviceManagement.GetDeviceid) and either automatically send it to your server or display it to the user.
2. Generate and sign the license that includes the device id with your private key.
3. Send this license to the user.
4. During validation of the license, retrieve the device id and include it into validation.

In order to utilize the Licensing library, you will need to create a new license provider by inheriting from the LicenseProvider class. Also you can either modify the .lic file by adding the DeviceID tag into the xml or append the device id to the contents of the .lic file during validation. If my schedule permits I'll try to add this implementation to the base library.

2/7/2006 2:11:21 PM (GMT Standard Time, UTC+00:00)  #     | 
 Thursday, February 02, 2006

Walter, the IE Program Manager, just announced on the IEBlog that the Windows RSS Platform is going to be available on the Windows XP as well as Vista. It will be installed as a part of IE7 package. This is indeed a great news and shows Microsoft's commitment to the “RSS anywhere” paradigm and would like to remind that they should not forget the Windows CE world. I am a strong believer that RSS has a great potential that is going to grow beyond Weblogs and news feed applications.

RSS
2/2/2006 6:35:14 PM (GMT Standard Time, UTC+00:00)  #    Comments [38]  | 
 Thursday, January 26, 2006

In my previous post I showed you the class diagram and the usage for the Licensing classes that are available as a part of SDF v2.

Today I'll explain a few other steps that you will be required to do in order to have licensing enabled in your application.

Attentive readers had probably noticed from looking at the class diagram that I have provided implementation of a concrete class PublicKeyLicenseProvider that inherits from the abstract LicenseProvider. The internal implementation of the PublicKeyLicenseProvider class is based on the asymmetric encryption such as RSACryptoServiceProvider. This was made possible by the fact that Microsoft has provided the implementation of the System.Security.Cryptography namespace to the CF v2.

Little bit of the background information on the asymmetric encryption. Asymmetric Encryption is a form of encryption where keys come in pairs. What one encrypts, only the other can decrypt. Asymmetric Encryption is also known as Public Key Cryptography, since users typically create a matching key pair, and make one public while keeping the other secret.

This fact has brought me to the idea of possibility to implement an almost fool proof system for licensing of components and applications in the CF v2. Even considering an "openness" of the .NET assemblies through the tools like Reflector, as long as your private key will stay unknown to a possible hacker, they will have a little chance to break the encryption.

And now after you have digested this information, you should be able to understand the other steps that are required:

1. You will have to generate a pair of the Public and Private keys. I have created a class LicenseKeyGenerator to help you with this task. Here's the CreateKeyPair method that you can use on either Windows CE or a desktop to generate these keys:

public static void CreateKeyPair( string path, int keySize )

{

      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider( keySize );

      // Open the file stream for writing of the public key

      FileStream keyWriter = new FileStream(Path.Combine(path, "Pub.key"), FileMode.Create);

      // Get the key from provider

      byte[] key1 = rsa.ExportCspBlob(false);

      //Write it to the file

      keyWriter.Write(key1, 0, key1.Length);

      keyWriter.Close();

 

      // Open the file stream for writing of the private key

      keyWriter = new FileStream(Path.Combine(path, "Priv.key"), FileMode.Create);

      // Get the key from provider

      byte[] key2 = rsa.ExportCspBlob(true);

      //Write it to the file

      keyWriter.Write(key2, 0, key2.Length);

      keyWriter.Close();

}

2. Add the generated public key file Pub.key to the root (this is very important) of your project and set its Build Action to the Embedded Resource.

3. Add the LicenseProviderAttribute to your component as I had already shown to you in the previouse post.

4. Generate the license file based on the user data. The license is a simple XML file in the following format:

<licenseKey version="1.0">

    <product version="1.0.3.2489">NewControlproduct>

    <customerInfo>

        <Name>John DoeName>

        <Email>john.doe@mail.comEmail>

    customerInfo>

    <key>f4/WgB2JhgR9bQibFa6rbGDugM+4wqbyM/ES+6W17gxx+x//G9at5he3yT0wZGwk2okSAzqrRJoNfsakEDMlFg==key>

licenseKey>

 

The value of the key tag is the public key that we have generated in the previouse step. Here is the method Generate from the LicenseKeyGenerator class:

public void Generate(string publicKeyFile, string licenseFile)

{

      //Open public key file

      FileStream fs = new FileStream(licenseFile, FileMode.Open);

      BinaryReader keyReader = new BinaryReader(fs);

      // Create encryptor

      RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();

      rsaProvider.ImportCspBlob(keyReader.ReadBytes((int)keyReader.BaseStream.Length));

 

      // sign and save.

      this.Sign(rsaProvider);

      this.Save(licenseFile);

}

And you will use it like so:

private void cmdGenerate_Click(object sender, EventArgs e)

{

       // Create new license key.

       LicenseKeyGenerator licenseKey = new LicenseKeyGenerator();

       licenseKey.ProductName = txtProduct.Text;

       licenseKey.ProductVersion = txtVersion.Text;

       licenseKey.CustomerName = txtCustName.Text;

       licenseKey.CustomerEmail = txtCustEmail.Text;

 

       licenseKey.Generate((Application.ExecutablePath) + @"\Keys\Priv.Key", "MyCompany.NewControl.lic");

}

You can download the full version for the LicenseKeyGenerator class and a sample project from here:

GenLicense.zip (23.81 KB)

After you are done with these steps, the result is simple and effective - you've got a licensing system in place that would be rather hard to brake and easy to use.

1/26/2006 1:52:45 PM (GMT Standard Time, UTC+00:00)  #     | 
 Wednesday, January 25, 2006

The beta of the SDF v2.0 is available for download. We have worked really hard toward this release. Of course it fully supports the VS 2005 and CF v2. The SDF v2 also includes a lot of new functionality. Among those I would like to present to you the Licensing classes that I have developed. In the next few posts I will try to describe its design and show you how to actually use it.

The design of the Licensing functionality is based on the existing classes from the System.ComponentModel on the desktop like the Lisense, LicenseProvider, etc... Here is the class diagram representing the class structure of the Licensing library in the SDF v2:

So how would you use this library? The same way it is described in the MSDN documentation. Add the LicenseProviderAttibute to your component and use the LicenseManager to validate the license:

[LicenseProvider(typeof(PublicKeyLicenseProvider))]

public partial class NewControl : UserControl

{

     public NewControl()

   {

         InitializeComponent();

         

         if (!LicenseManager.IsValid(typeof(NewControl)))

         {

              MessageBox.Show("NewControl has invalid license");

         }

   }

 }

 

In the next post I'll explain to you which additonal steps are required to use the Licensing classes in your CF v2 application.

1/25/2006 4:47:00 PM (GMT Standard Time, UTC+00:00)  #    Comments [46]  | 
 Tuesday, January 17, 2006

The DateTimePicker control in the .NetCF v2 doesn't implement DropDown and CloseUp events which could be really helpful whe dealing with the picker. It doesn't mean that these events or messages are not available in the native counterpart. Win CE SDK docs show the presence of the DTN_CLOSEUP and DTN_DROPDOWN notification messages. It means that they are sent by the DateTime picker to its parent. So, I pulled the NativeWindow class to whip up the DateTimePickerEntender class that suclasses the form, catches the messages and raises the events to the client:

public class DateTimePickerExtender : NativeWindow

{

        public event System.EventHandler CloseUp;

        public event System.EventHandler DropDown;

 

        private IntPtr handle;

 

        public DateTimePickerExtender(IntPtr handle)

        {

            this.handle = handle;

            // Subclass the window

            this.AssignHandle(handle);

        }

 

        protected override void WndProc(ref Message m)

        {

            // Check for notification messages

            if (m.Msg == WM_NOTIFY)

            {

                NMHDR nmhdr = new NMHDR();

                        Marshal