Category: NETCF

  • SQL Server Compact Edition – Coming Tomorrow

    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


     

  • Make Individual TreeView Nodes Bold

    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:-


     

  • Using MessageInterceptor to launch an application on SMS

    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 FilesInterceptorTestInterceptorTest.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)

  • Bug in GAC Installation from VS2005 Device CAB Projects

    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.

  • SelectPictureDialog.LockDirectory property

    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.

  • 32feet.NET Reaches v2.0 Milestone

    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.

  • Windows Mobile Context Menu Behaviour On Windows CE

    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)

    ‘if theres no context menu do nothing
    If Not senderctrl.ContextMenu Is Nothing Then

    Dim shrgi As New SHRGINFO
    shrgi.cbSize = 20
    shrgi.hwndClient = senderctrl.Handle
    shrgi.dwFlags = 3
    shrgi.ptDownx = e.X
    shrgi.ptDowny = e.Y
    Dim result As Integer = SHRecognizeGesture(shrgi)
    If result = 1000 Then

    senderctrl.ContextMenu.Show(senderctrl, New System.Drawing.Point(e.X, e.Y))
    End If
    End If

    End Sub

    <System.Runtime.InteropServices.DllImport(“aygshell.dll”)> _
    Private Shared Function SHRecognizeGesture(ByRef shrg As SHRGINFO) As Integer
    End Function

    Public Structure SHRGINFO
    Public cbSize As Integer
    Public hwndClient As IntPtr
    Public ptDownx As Integer
    Public ptDowny As Integer
    Public dwFlags As Integer
    End Structure

    End Class

    End Namespace

  • Disable the Touch Screen

    If you really need to disable the touch screen on a device, there is a method available, but you’ll need to soft-reset the device to restore the functionality. You can call the TouchPanelDisable API, it’s not documented in the Windows Mobile SDKs but you’ll find it in the CE documentation, declaration is very simple:-


    <System.Runtime.InteropServices.DllImport(“touch”)> _
    Private Shared Sub TouchPanelDisable()
    End Sub


     


    or


    [DllImport(“touch”)]

    private static extern void TouchPanelDisable();


    There is a possibility that the dll in which this function appears may be different on some devices, so you’ll need to do some experimentation first.



  • SQL Mobile Access Sync Coming Soon

    For a while the migration path from Pocket Access to SQL CE / SQL Mobile has been missing a key piece of functionality which many Pocket Access applications relied on – the Synchronisation functionality in ActiveSync which synchronised with an Access database on the PC.


    Today we have some good news from the SQL Mobile Team – A tool called here “Sync with Access”, which is due out in Beta form in August, will return this functionality for SQL Mobile (and the forthcoming SQL Everywhere Edition).

  • Take a Shortcut

    There are a number of ways you can make use of Shortcuts within your project. You may create a shortcut to your application during your CAB file installation – either on the Start Menu or perhaps in the WindowsStartup folder. VS2005 makes this easy because it has a nice file system graphical editor for CAB projects. Another way you can use shortcuts is within your code itself. There are two API functions to support this – SHCreateShortcut and SHGetShortcutTarget. By P/Invoking these from your .NETCF application you can create your own launcher applications which reuse the shortcuts setup for your Start Menu for example.


    There are some caveats when using these functions though which you need to be aware of, the documentation has been revised since the Pocket PC 2003 SDK to warn you of this. To understand why let’s have a quick look at the contents of an LNK file:-


    34#”My DocumentsTemplatesMemo.psw”


     


    As you can see it’s a very simple text format. The number indicates the length of the path, this is followed by the # symbol then the full path to the target. When the path contains a space it must be wrapped in quotes. So what were those caveats? Well whatever path you pass to SHCreateShortcut it doesn’t add these quotes how you would expect – you end up with:-


    34#”My” DocumentsTemplatesMemo.psw


     


    This path is invalid and the shortcut won’t work. The solution is to wrap any path you pass into SHCreateShortcut with quotes to begin with. Even if the path doesn’t contain spaces this will give you a valid shortcut.


    The second caveat comes with the SHGetShortcutTarget API. When this reads the shortcut file it doesn’t strip out the quotes if present, this means your returned path cannot be used as-is with any of the System.IO functionality. The solution to this one is very simple – perform a Trim() on the returned string passing in the ” character – this will remove the leading and trailing quotes and leave you with a valid path. If your shortcuts are to executables and also have arguments specified you will need to split the quoted path from any following arguments.


    To demonstrate both of these techniques I’ve attached a sample VB.NET project. It can create and list shortcuts and when you tap on an item it will launch the target document. For a true launcher application there are some additional steps, for example retrieving the Icon for the file, these are not included in this sample.

    Shortcuts.zip (7.27 KB)