# Wednesday, April 02, 2008

On the newsgroup, a developer asked if it was possible to use antialiasing on a Label font. By default on Windows Mobile the text does not use antialiasing unless you turn on the global ClearType option under Settings > System > Screen > ClearType. The platform has the capability to smooth fonts, we just need an easy way to specify the quality from our code. The System.Drawing.Font class doesn't support this directly, but Microsoft.WindowsCE.Forms contains a wrapper for the native LOGFONT structure in the LogFont class. There is a static method on the Font class of FromLogFont(object o) which when passed a Microsoft.WindowsCE.Forms.LogFont will draw the font with the specified options. The following code shows setting three labels with default quality, antialiasing and cleartype, the following screen grab shows the result from my device screen:-Microsoft.WindowsCE.Forms.LogFont lf = new Microsoft.WindowsCE.Forms.LogFont();lf.FaceName = "Tahoma";

lf.Height = 48;

lf.Quality = Microsoft.WindowsCE.Forms.LogFontQuality.Default;

label1.Font = Font.FromLogFont(lf);

Microsoft.WindowsCE.Forms.LogFont lf2 = new Microsoft.WindowsCE.Forms.LogFont();

lf2.FaceName = "Tahoma";

lf2.Height = 48;

lf2.Quality = Microsoft.WindowsCE.Forms.LogFontQuality.AntiAliased;

label2.Font = Font.FromLogFont(lf2);

Microsoft.WindowsCE.Forms.LogFont lf3 = new Microsoft.WindowsCE.Forms.LogFont();lf3.FaceName = "Tahoma";

lf3.Height = 48;

lf3.Quality = Microsoft.WindowsCE.Forms.LogFontQuality.ClearType;

label3.Font = Font.FromLogFont(lf3);

Wednesday, April 02, 2008 3:30:36 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Thursday, March 06, 2008

Martijn Hoogendoorn provides a description of how to avoid the message:-

"An error message is available for this exception but cannot be displayed because these messages are optional and are not currently installed on this device. Please install ‘NETCFv35.Messages.EN.wm.cab’ for Windows Mobile 5.0 and above or  ‘NETCFv35.Messages.EN.cab’ for other platforms. Restart the application to see the message."

Even if you have installed the cab file with message resources. A useful link:-

http://blogs.msdn.com/martijnh/archive/2008/01/03/fixing-exception-messages-on-the-net-compact-framework-3-5.aspx

Thursday, March 06, 2008 2:48:58 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Saturday, February 23, 2008

A question came up on our forums and so I investigated writing a wrapper for the GetSystemPowerState API function. This allows you to retrieve the power state name, and also a bitmask of flags - Is the backlight on, is the device password protected etc. This is the result in VB.NET. We will add it to the wish list for the next version of the library.

<DllImport("coredll.dll")> _
Public Shared Function GetSystemPowerState(ByVal pBuffer As System.Text.StringBuilder, ByVal Length As Integer, ByRef pFlags As PowerState) As Integer
End Function

<Flags()> _
Public Enum PowerState
[On] = &H10000 '// on state
Off = &H20000 ' // no power, full off
Critical = &H40000 '// critical off
Boot = &H80000 ' // boot state
Idle = &H100000 ' // idle state
Suspend = &H200000 ' // suspend state
Unattended = &H400000 ' // Unattended state.
Reset = &H800000 ' // reset state
UserIdle = &H1000000 ' // user idle state
BackLightOn = &H2000000 ' // device screen backlight on
Password = &H10000000 ' // This state is password protected.
End Enum


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim sb As New System.Text.StringBuilder(260)
Dim flags As PowerState = 0
Dim ret As Integer = GetSystemPowerState(sb, sb.Capacity, flags)

TextBox1.Text = sb.ToString()
TextBox2.Text = flags.ToString()
End Sub

The last method is just a very simple example of calling the function and displaying the result.

Saturday, February 23, 2008 4:29:11 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Tuesday, February 12, 2008

A number of controls within .NETCF have built in ScrollBars. Occasionally you may want to operate these programmatically on behalf of the user. When you do this you want both the control to scroll and the scrollbars to correctly reflect the current position. Faced with this requirement I found a solution in the WM_VSCROLL (and equivalent HSCROLL) message. You can send this message to the native handle of your control along with a number of present constants to offer hands-free scrolling. Along the way I discovered that to work you must have the handle of the native control which implements the scroll bars. In the case of the WebBrowser this is a grand-child of the outer managed control so we have to use the native GetWindow API call to get down to the right HWND. I wrapped this up in a class I've called ScrollBarHelper which allows the user to move left, right, up and down. The code for the class is:-

/// <summary>
/// Helper class to programmatically operate scrollbars.
/// </summary>
public class ScrollBarHelper
{
  private IntPtr handle;


  public ScrollBarHelper(Control c)
  {
    if (c is WebBrowser)
    {
      //special case for complex control
      //get the inner IE control
      IntPtr hInternetExplorer = NativeMethods.GetWindow(c.Handle, NativeMethods.GW.CHILD);
      //get the first child (status bar)
      IntPtr hStatus = NativeMethods.GetWindow(hInternetExplorer, NativeMethods.GW.CHILD);
      //get the html body area
      handle = NativeMethods.GetWindow(hStatus, NativeMethods.GW.HWNDNEXT);
    }
    else
    {
      handle = c.Handle;
    }
  }



public void LineRight()
{
  SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_LINEDOWN);
}
public void LineLeft()
{
  SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_LINEUP);
}

public void PageRight()
{
  SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_PAGEDOWN);
}
public void PageLeft()
{
  SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_PAGEUP);
}

public void LineDown()
{
  SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_LINEDOWN);
}
public void LineUp()
{
  SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_LINEUP);
}

public void PageDown()
{
  SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_PAGEDOWN);
}
public void PageUp()
{
  SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_PAGEUP);
}

private void SendMessage(int msg, int value)
{
  Microsoft.WindowsCE.Forms.Message m = Microsoft.WindowsCE.Forms.Message.Create(handle, msg, (IntPtr)value, handle);
  Microsoft.WindowsCE.Forms.MessageWindow.PostMessage(ref m);
}

[DllImport("coredll.dll")]
internal static extern IntPtr GetWindow(IntPtr hWnd, GW uCmd);

internal enum GW : int
{
  HWNDFIRST = 0,
  HWNDLAST = 1,
  HWNDNEXT = 2,
  HWNDPREV = 3,
  OWNER = 4,
  CHILD = 5,
}

//scrollbar messages
internal const int WM_HSCROLL = 0x0114;
internal const int WM_VSCROLL = 0x0115;

//constants for scrollbar actions
internal const int SB_LINEUP = 0;
internal const int SB_LINEDOWN = 1;
internal const int SB_PAGEUP = 2;
internal const int SB_PAGEDOWN = 3;

}

In order to use the control you create a new instance passing it the control of your choice. Then call methods to scroll the control e.g.

private ScrollBarHelper wsbh;
private ScrollBarHelper tsbh;

private void Form1_Load(object sender, EventArgs e)
{
  wsbh = new ScrollBarHelper(webBrowser1);
  tsbh = new ScrollBarHelper(textBox1);
}

private void button1_Click(object sender, EventArgs e)
{
  tsbh.PageUp();
}

The control contains methods to Scroll via single lines or pages at a time, I didn't get around to looking at setting the explicit value of the scrollbar control, but this should be possible also - refer to the documentation for WM_VSCROLL for how to pass the value.

Tuesday, February 12, 2008 11:00:04 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Wednesday, January 09, 2008

While testing code using HttpWebRequest it can be observed in the debug output that a number of exceptions are thrown within the GetResponse call of a HttpWebRequest. If you run exactly the same code on the desktop you don't see this behaviour. For reference the following is a simple example which displays the issue:-

System.Net.WebRequest request = System.Net.WebRequest.Create("http://www.microsoft.com");
System.Net.WebResponse webResponse = request.GetResponse();
webResponse.Close();

Since the exceptions are caught it doesn't stop the code from running but I considered it annoying enough to investigate and try to find the cause. Here is the typical output during the call to GetResponse:-

A first chance exception of type 'System.IO.IOException' occurred in mscorlib.dll
A first chance exception of type 'System.UriFormatException' occurred in System.dll
The thread 0x577c6eaa has exited with code 0 (0x0).
The thread 0xaf16af8a has exited with code 0 (0x0).
A first chance exception of type 'System.UriFormatException' occurred in System.dll
The thread 0x577c6eaa has exited with code 0 (0x0).
The thread 0xaf16af8a has exited with code 0 (0x0).
The thread 0xaf399a02 has exited with code 0 (0x0).

I eventually tracked it down to an issue with WebProxy. It occurs if you do not specify a Proxy or use the system proxy:-

request.Proxy = System.Net.GlobalProxySelection.Select;

If you won't be using a proxy you can set the Proxy property to an empty WebProxy:-

request.Proxy = System.Net.GlobalProxySelection.GetEmptyWebProxy();

After making this change you'll see the method progress without any exceptions - you'll just see the 5 thread exit notifications in the output. Whether or not this makes a noticeable difference to performance I have yet to discover but it does indicate an underlying issue since the desktop has no such problem.

Wednesday, January 09, 2008 8:39:47 PM (GMT Standard Time, UTC+00:00)  #    Comments [5]  | 
# Friday, November 23, 2007

One of the new features in v3.5 of the Compact Framework is the ability to easily detect the platform you are running on from Smartphone (Standard Edition), PocketPC (Classic or Professional Editions) or WinCEGeneric (Everything else). The code is very straight-forward:-

using Microsoft.WindowsCE.Forms;

if(SystemSettings.Platform == WinCEPlatform.Smartphone)
{
   //do something smartphone specific...
}

 

In the latest (v3.0) version of Mobile In The Hand I've implemented a matching property, so for the above code sample you'd just change the using statement to use InTheHand.WindowsCE.Forms and the code would work the same way. This is available in both the .NETCF v1.0 and v2.0 builds of the library.

Friday, November 23, 2007 11:58:38 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Friday, September 21, 2007

In The Hand Ltd today released Networking In The Hand, a developer library for the .NET Compact Framework 2.0 and 3.5 Beta. This library adds additional networking functionality not found in in the Compact Framework while matching the object model used in the full .NET framework to make it easy to share your code between platforms. Functionality includes:-

  • InTheHand.Net.WebClient - Provides helper methods for working with information upload and download over HTTP and FTP transports, and any other WebRequest based implementations.
  • InTheHand.Net.FtpWebRequest - Provides a complete desktop compatible implementation of the WebRequest pattern for FTP.
  • InTheHand.Net.WebRequestMethods - Provides a reference of all the HTTP and FTP methods (GET/POST etc)
  • InTheHand.Net.NetworkInformation.Ping - Perform a Ping and determine network availability and performance.
  • InTheHand.Net.NetworkInformation.IPGlobalProperties - Retrieve a wide range of networking statistics to measure traffic and help identify faults.

The library is licensed on a per-developer basis with no additional royalties required to distribute the runtime with your applications. Full details on the product can be found on the product details page - http://inthehand.com/content/Networking.aspx. A fully functionality Evaluation version is available to download - http://inthehand.com/files/folders/evals/entry4014.aspx.

Friday, September 21, 2007 3:45:22 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Tuesday, August 21, 2007

In .NETCF v3.5 there is a new namespace - System.Media which brings audio support to the Compact Framework. Previously the common way to add sounds to your application was to use the PlaySound API (either P/Invoking yourself or using one of many wrappers). Now that the framework itself has built-in support, which matches the desktop .NET v2.0 framework it makes sense to standardise on the SoundPlayer component.

There are some differences in behaviour which you'll need to be aware of. When you specify a filename this doesn't simply call through to the native APIs passing the filename, the file is first loaded into memory and then the WaveOut APIs are used to play it. This means that if you simply create a new SoundPlayer and call Play the file will not be loaded, the Play method will have to first load the file contents, and then play the sound. This will create a noticable delay before the sound is heard. The class allows you to load the file at any time prior to calling play - you can use either Load or LoadAsync to do this. Once the file is loaded the Play method will be able to immediately begin playing the file. Exactly where you call the Load/LoadAsync method will depend on your application design. Keeping a large audio file cached will tie up valuable memory, you should dispose of the SoundPlayer instance once you have finished with it.

Tuesday, August 21, 2007 3:51:09 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Friday, July 27, 2007

On the newsgroup somebody asked how to have multiple lines of text on a .NETCF Button control. The native control supports this but the appropriate style is not set by default. The following code snippet shows how to enable this:-

private const int BS_MULTILINE = 0x00002000;
private const int GWL_STYLE = -16;

[System.Runtime.InteropServices.DllImport("coredll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[System.Runtime.InteropServices.DllImport("coredll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

public static void MakeButtonMultiline(Button b)
{
    IntPtr hwnd = b.Handle;
    int currentStyle = GetWindowLong(hwnd, GWL_STYLE);
    int newStyle = SetWindowLong(hwnd, GWL_STYLE, currentStyle | BS_MULTILINE);
}

The usage is simple, just pass the specific Button control to MakeButtonMultiline:-

MakeButtonMultiline(button1);

Here is what the amended button looks like on the left (default appearance on the right)

The designer fully supports entering multiple lines for the Button Text property, just click the dropdown at the end of the field and it will pop up a window into which you can add linebreaks with your text.

Friday, July 27, 2007 9:24:36 AM (GMT Standard Time, UTC+00:00)  #    Comments [2]  | 
# Tuesday, July 24, 2007

I'm now a member of the CodePlex workspace for the Facebook Developer Toolkit. I've been working on porting across my modifications into the codebase. The .NETCF v2.0 version uses a project called Facebook.Compact but refers to the existing source files from the desktop project. Then some conditional compilation is used to hide a few unsupported features from .NETCF and implement some workarounds for missing functionality. This will be a familiar technique if you've been to Daniel's sessions (or read his blog posts on the subject). It's not quite working yet since my code made use of a couple of my own libraries for speed, so I'll need to implement a few of the features within those in the Facebook.Compact project.

Tuesday, July 24, 2007 8:21:07 PM (GMT Standard Time, UTC+00:00)  #    Comments [4]  | 
# Friday, July 20, 2007

The Facebook API allows third-party web and desktop applications to interact with Facebook features. There is an excellent shared-source library for .NET to wrap the Facebook calls but currently it only supports the full framework. I did some work converting this source to compile and run on .NETCF v2.0. There are some example screens here of the login process, and pulling back information about our book group.

   

Since the login screen uses the same page as the desktop it's not a great fit on a Pocket PC screen, so that's an area for improvement.

Friday, July 20, 2007 8:52:49 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Monday, June 25, 2007

João Paulo was investigating Guid performance when used as identifiers in a SQL Compact database and discovered that the performance of Guid.NewGuid() left a lot to be desired. The reason for this is that the function uses lowest-common-denominator support, using a random number generator and setting a couple of specific bits to conform to guid standards. Another method I've been recommending for some time is to use the native CoCreateGuid() function - see http://www.peterfoot.net/NeedAGUIDInAHurry.aspx. This method is supported in all devices running Windows Mobile 2003 and above, and in Windows CE 4.x. I've been using it in the InTheHand.Guid2 class in Mobile In The Hand (Will be renamed to GuidHelper in the next version). I did some tests creating 100,000 guids in a row with both methods. Guid.NewGuid() took 139 seconds, and GuidHelper.NewGuid() took a mere 9 seconds. As you can see that is quite a significant difference.

Monday, June 25, 2007 7:13:33 PM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
# Monday, May 14, 2007

There have been numerous occasions where I've needed to write code to launch another process and wait for it to complete, usually taking some action based on the exit code. Therefore I've got a handy helper method to do this. It has changed a few times and is made much simpler in .NETCF v2.0 by taking advantage of the Process class. Most recently I used the code in one of the book chapters to show automatic installation of the Microsoft Message Queue (MSMQ) components onto a Windows Mobile device. The method is named ShellWait, as the name implies it launches a process and waits, the return value is the exit code from the process. If the application doesn't exist it returns -1 immediately.

[C#]

//helper function to launch a process and wait for the result code
private static int ShellWait(string app, string args)
{
   if (!File.Exists(app))
   {
      return -1;
   }


   Process p = Process.Start(app, args);
   p.WaitForExit();


   return p.ExitCode;
}

 

[VB]

Private Shared Function ShellWait(ByVal app As String, ByVal args As String) As Integer
   If Not File.Exists(app) Then
      Return -1
   End If

   Dim p As Process = Process.Start(app, args)
   p.WaitForExit()

   Return p.ExitCode
End Function

Monday, May 14, 2007 3:24:55 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Tuesday, May 01, 2007

The Windows Mobile 6 SDK Refresh is available today. It includes some documentation enhancements and new samples. One of these is called RingtoneManager and is a C# application which wraps all the Sound APIs for ringtone management and sound playback, the latter of which were introduced with Windows Mobile 6. This is great because it gives you all the P/Invokes etc you need to use this functionality yourself. However expect to see these Windows Mobile specific APIs in the next version of Mobile In The Hand.

Tuesday, May 01, 2007 3:14:51 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Monday, March 26, 2007

I've been a bit quiet over the past few weeks, on vacation and at the Microsoft MVP Summit. I've also been working on the TomTom In The Hand library and today have released a new version.

It turns out that TomTom SDK 6 shipped with a known bug that prevents you from passing negative co-ordinates into any of the methods (returned values were okay). At the moment I believe that our library is the only one which has a fix for this bug which was a major headache for developers. You can now use TomTom through this library wherever you reside in the world (assuming you have map coverage of course) without making any changes to your existing code.

This release also adds some new functionality - The RawGpsReceived event on the Navigator object allows you to receive NMEA data from TomTom which allows you to share this data if you are not already using a multiplexer such as the Windows Mobile 5.0 GPS service or Franson GPS Gate or similar.

Monday, March 26, 2007 11:40:00 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Monday, February 26, 2007

Windows Mobile devices, both Smartphone and Pocket PC support Speakerphone functionality. When operating through the Phone application the end user can toggle the state, up until now there has been no documented way to achieve this through code. Last year I investigated the issue on behalf of one of my readers and failed on several attempts at simulating a press-and-hold of the green phone button. It turns out that the device issues a specific key constant to change the state, and this can be simulated through code. It also turns out that the constant is equivalent to VK_F16 (thats Keys.F16 for managed code). I've wrapped up the necessary P/Invoke into the following code:-

public sealed class SpeakerPhone
{
private SpeakerPhone() { }

/// <summary>
/// Toggles the SpeakerPhone state.
/// </summary>
public static void Toggle()
{
//keydown
NativeMethods.keybd_event((byte)Keys.F16, 0, 0, 0);
//keyup
NativeMethods.keybd_event((byte)Keys.F16, 0, NativeMethods.KEYEVENTF_KEYUP, 0);
}

internal static class NativeMethods
{
internal const int KEYEVENTF_KEYUP = 0x0002;


[System.Runtime.InteropServices.DllImport("coredll.dll")]
internal static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
}
}

 

Since this just toggles the state, you can't determine the current state at any particular time. This code has been tested on Windows Mobile 5.0 and beyond (It possibly works on Windows Mobile 2003 but I haven't tested), it doesn't work on the Windows Mobile 5.0 Emulators as Speakerphone isn't implemented. I was able to establish a call on speakerphone using the following code:

Microsoft.WindowsMobile.Telephony.Phone p = new Microsoft.WindowsMobile.Telephony.Phone();
p.Talk("01234567890");
SpeakerPhone.Toggle();

Once the call is ended the speakerphone state is restored on subsequent calls.

Monday, February 26, 2007 7:08:03 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Wednesday, February 21, 2007

Richard has just started blogging, starting with a sample for maximising screen space by creating a Vista style textbox with integral label, and a description of what he has been up to in the fight against "Monkey Code". I've subscribed to his RSS feed and added him to the blogroll.

Wednesday, February 21, 2007 8:34:25 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Wednesday, February 14, 2007

When I previously posted the list of additional system properties I was using the Windows Mobile 6 SDK Documentation as a reference. Well it turns out that there are even more new properties, you can view them using Object Browser in your project but they aren't included in the documentation. The other new properties are:-

  • CameraEnabled - This in addition to existing CameraPresent property
  • CellularSystemAvailable1xrtt
  • CellularSystemAvailableEdge
  • CellularSystemAvailableEvdo
  • CellularSystemAvailableEvdv
  • CellularSystemAvailableGprs
  • CellularSystemAvailableHsdpa
  • CellularSystemAvailableUmts
  • CellularSystemConnected1xrtt
  • CellularSystemConnectedEdge
  • CellularSystemConnectedEvdo
  • CellularSystemConnectedEvdv
  • CellularSystemConnectedGprs
  • CellularSystemConnectedHsdpa
  • CellularSystemConnectedUmts
  • ClamshellClosed
  • DeviceLocked
  • KeyLocked
  • LockStates - A combination of flags for Device, Key and Sim locks
  • SimLocked
  • PhoneTalkingCallStartTime

 

Wednesday, February 14, 2007 5:09:38 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Wednesday, January 10, 2007

Excellent news from the SQL Server Everywhere blog (those guys need to change the name of their blog again :-)). Tomorrow the runtimes and tools for SQL Server Compact Edition will be released to the web. It will replace the RC1 download so the link will remain the same:-

http://www.microsoft.com/downloads/details.aspx?FamilyID=85E0C3CE-3FA1-453A-8CE9-AF6CA20946C3&displaylang=en

 

Wednesday, January 10, 2007 5:08:06 PM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
# Thursday, November 30, 2006

The full framework TreeView control supports setting a Font on a per-node basis, the Compact Framework control doesn't support this, however with a little interop magic you can mark individual nodes as Bold. Because the .NETCF v2.0 TreeView control exposes it's own window handle, and each TreeNode also exposes it's handle, we have all the raw data we need to format the node. First we need to define a structure and a couple of enumerations:-

internal struct TVITEM
{
public TVIF mask;
public IntPtr hItem;
public TVIS state;
public TVIS stateMask;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
string pszText;
int cchTextMax;
int iImage;
int iSelectedImage;
int cChildren;
int lParam;
}

[Flags()]
internal enum TVIF
{
TEXT =0x0001,
IMAGE =0x0002,
PARAM =0x0004,
STATE =0x0008,
HANDLE =0x0010,
SELECTEDIMAGE =0x0020,
CHILDREN =0x0040,
}

[Flags()]
internal enum TVIS
{
SELECTED =0x0002,
CUT =0x0004,
DROPHILITED =0x0008,
BOLD =0x0010,
EXPANDED =0x0020,
EXPANDEDONCE =0x0040,
EXPANDPARTIAL =0x0080,

OVERLAYMASK =0x0F00,
STATEIMAGEMASK =0xF000,
USERMASK =0xF000,
}

 

Then I've created a single static method which can set the bold state of any node:-

public static void SetNodeEmphasis(TreeNode n, bool bold)
{
//get the control and node handles
IntPtr hTreeview = n.TreeView.Handle;
IntPtr hNode = n.Handle;

//create a TVITEM struct
TVITEM t = new TVITEM();
t.hItem = hNode;
//mark only the handle and state members as valid
t.mask = TVIF.HANDLE | TVIF.STATE;
//set the state to bold if bold param was true
t.state = bold ? TVIS.BOLD : 0;
//set statemask to show we want to set the bold state
t.stateMask = TVIS.BOLD;

//pin the struct in memory
GCHandle hTVITEM = GCHandle.Alloc(t, GCHandleType.Pinned);
//create a TVM_SETITEM message with the handle of our pinned struct
Microsoft.WindowsCE.Forms.Message m = Microsoft.WindowsCE.Forms.Message.Create(hTreeview, 0x113F, IntPtr.Zero, hTVITEM.AddrOfPinnedObject());
//send the message to the treeview
Microsoft.WindowsCE.Forms.MessageWindow.SendMessage(ref m);
//free the pinned structure
hTVITEM.Free();
}

The method is easy to reuse as you only need to pass the TreeNode in, it will grab the handle of the parent control from the node itself. After applying the formatting to a couple of nodes you'll get something like this:-

 

Thursday, November 30, 2006 10:08:27 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
# Wednesday, November 15, 2006

First things first a disclaimer, the following code is written for Mobile In The Hand (Professional Edition), it does apply equally to a Windows Mobile 5.0 project with the Microsoft.WindowsMobile managed APIs, you'll just need to change the namespaces and assembly references.

A normal MessageInterceptor is valid only for the lifetime of your application, once you shut down you'll no longer be able to respond to messages that match your rule. In many cases you'll want a specific message to launch your application and then process as normal. The IApplicationLauncher interface which MessageInterceptor implements contains methods to set this up. This allows the system to start your application, optionally with command line arguments of your choosing. This is useful so that you can tell when your app was called by an incoming SMS and when launched manually. The following code snippet is called in Form_Load, it checks for an existing registration, if not present it sets up all the required settings. The ApplicationLaunchId is a string which is unique to your application, if you try to register with an id which is already in use you'll receive an Exception.

if (InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessageInterceptor.IsApplicationLauncherEnabled("testapp"))
{
    mi = new InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessageInterceptor("testapp");
}
else
{
    mi = new InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessageInterceptor(InTheHand.WindowsMobile.PocketOutlook.MessageInterception.InterceptionAction.NotifyAndDelete);
    mi.MessageCondition = new InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessageCondition(InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessageProperty.Body, InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessagePropertyComparisonType.StartsWith, "test:", false);

    mi.EnableApplicationLauncher("testapp","\\Program Files\\InterceptorTest\\InterceptorTest.exe");
}

mi.MessageReceived += new InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessageInterceptorEventHandler(mi_MessageReceived);

Finally the event handler just displays the message body in a MessageBox:-

void mi_MessageReceived(object sender, InTheHand.WindowsMobile.PocketOutlook.MessageInterception.MessageInterceptorEventArgs e)
{
    MessageBox.Show(((InTheHand.WindowsMobile.PocketOutlook.SmsMessage)e.Message).Body, "Message");
}

Download the skeleton project: InterceptorTest.zip (11.08 KB)
Wednesday, November 15, 2006 4:13:46 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Wednesday, October 11, 2006

I recently ran into a problem with a Smart Device CAB Project in Visual Studio 2005, which as it turns out is a known issue. You can build a CAB file which will register your .NETCF dlls into the GAC - the File System Editor has a standard folder called "Global Assembly Cache Folder" which you can put your files into. Behind the scenes this deploys the dlls to the windows folder and generates a .GAC text file with a list of paths to your dll(s). The problem is that the generated GAC file is a Unicode text file and doesn't work on devices prior to Windows Mobile 5.0. I'm assuming the same is true with generic CE 4.2 devices versus CE 5.0. In itself this seems bizarre since CE is fully Unicode based so shouldn't have any problem reading the file. It just so happens that when you are doing this the old fashioned way with notepad you get an ANSI text file which works just fine on all devices.

The workaround is simple, don't use the whizzy GAC support in the CAB project, place your dlls into the Windows Folder, and manually create a .GAC text file and place this in the Windows Folder also. The downside to this approach is that you must update your GAC file if you add or remove dlls from your setup project. I'd like to say thanks to fellow MVP Jan Yeh for helping to test the issue and to Manish Vasani from the Visual Studio for Devices team for following up with more details on the issue.

Wednesday, October 11, 2006 4:23:01 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Friday, September 22, 2006

If you refer to the original Windows Mobile 5.0 documentation (or the Intellisense) when using this component you'll notice it has a property called LockDirectory which is supposed to prevent the user from browsing outside of the folder you specified in InitialDirectory. To cut a long story short this property is not implemented and setting it will not affect the behaviour of the dialog. The online MSDN documentation has since been updated to indicate this.

When faced with this problem my first thought was to look at the native API which this component uses (GetOpenFileNameEx) and P/Invoke it since the documentation still indicates that there is a flag to achieve this behaviour. However as it turns out this too is unimplemented. It was a late change in Windows Mobile 5.0 and hence the SDK and documentation were innacurate.

Friday, September 22, 2006 10:28:31 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
# Monday, August 28, 2006

Although it took a lot longer than I originally anticipated I've finally put the finishing touches to v2.0 of the 32feet.NET library. v2.0 is a major re-write of the code so that the single codebase can be built into separate dlls for desktop or device. This was primarily to get around the bug in the desktop VB.NET compiler which couldn't cope with redirecting the device System.dll reference to the desktop equivalent. It has had the pleasant side-effect of making the footprint much smaller. The 4 previous dlls are now merged into the single InTheHand.Net.Personal.dll which range from 91kb for the .NETCF v1.0 version to 76kb for the desktop v2.0 version.

You can download the installer which includes the library, documentation and samples from the 32feet website. This release is the first release version to have the full source code available since the project was hosted at CodePlex. You can also use the CodePlex site to download other builds of the code and post bugs/feature requests. If you want to get involved in the project drop me a mail, or join the discussions on the 32feet site.

Monday, August 28, 2006 3:56:47 PM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
# Friday, August 25, 2006

Although many Windows CE devices include the aygshell.dll component which offers some functionality available in the Pocket PC shell, it's not directly taken advantage of by .NETCF. For example, when you add a ContextMenu to a control in a Pocket PC project you automatically get tap-and-hold behaviour on the control. Run the same code on an aygshell equipped CE device and nothing happens. Therefore I wrote the following helper class to allow you to hook up the context menus. Simply call HookAllControls(Me.Controls) from your code (e.g. in your form constructor after the call to InitializeComponent() ) or at any other stage if you are dynamically creating controls on your form. Now when you run your app you'll get the tap and hold circles and your context menu will be displayed. Obviously this only works on CE devices which have aygshell support. Just to mix it up a bit this sample is in VB.NET but you should find it easy to convert to C#.

Namespace InTheHand.Windows.Forms


Public Class ContextMenuHelper


Private Shared mousedelegate As System.Windows.Forms.MouseEventHandler = New System.Windows.Forms.MouseEventHandler(AddressOf ControlMouseDown)

Public Shared Sub HookAllControls(ByVal thecontrols As Control.ControlCollection)

'attach to the mousedown event on all controls with a context menu
For Each thiscontrol As Control In thecontrols

If Not thiscontrol.ContextMenu Is Nothing Then

AddHandler thiscontrol.MouseDown, mousedelegate

End If

HookAllControls(thiscontrol.Controls)
Next

End Sub


Private Shared Sub ControlMouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)

Dim senderctrl As Control = CType(sender, Control)