Compsoft Flexible Specialists

Compsoft plc

Compsoft Weblog Compsoft Website News Archive Privacy Policy Contact Us  

Monday, May 18, 2009

Combatting "Unspecified error"

In one of our Windows Mobile applications we've been noticing some bizarre exceptions where we're logging a rare exception of "Unspecified Error".

It's always a pain getting this kind of error, you really have no clue where to turn. Pin pointing the general area and finding the point at which the application fails tends to be the only route and led us to find it was database related.

Further research into the error implies that the issue lies in SQL CE (we're using SQL CE 3.5 SP1). It's at the point we're touching the database but ONLY after the device has come out of stand by mode and ONLY if the database file is located on the storage / memory card. Database files stored on the internal memory are fine.

It turns out that the SQL Server Mobile engine has a bug when the database file is accessed before the block device driver (that allows you to access the database file) has started up after the device is restored from suspend mode.

There's a hotfix available for previous versions but not the latest and it only seems to give a more intelligible error message of "The disk is not ready" or "The OS storage system (RAM, CF, SD, or IPSM) is not responding. Retry the operation".

Which leaves us with the choice of what to do in this instance.

1. Handle database access exceptions until the device is ready again.

2. Wire up to the device's power events and handle the Power up event.

3. Move the database file to the Internal memory.

I decided to go with option 2. A significant amount of work would have been required for option 1. The devices we're working against have a 2GB storage card versus a 64mb internal memory so I felt this wouldn't work for us without impacting performance so I didn't go for option 3.

The easiest way to go with option 2 is by using the opennetcf smart device framework framework which in the OpenNETCF.WindowsCE.PowerManagement namespace allows you to wire up to all the Power related states and their changes.

Here's one possible solution:

   1: static void Main()
   2: {
   3:     OpenNETCF.WindowsCE.PowerManagement.PowerUp += new 
OpenNETCF.WindowsCE.DeviceNotification(PowerManagement_PowerUp);
   4:     //Run the app
   5: }
   6:  
   7: private static void PowerManagement_PowerUp()
   8: {
   9:     System.Windows.Forms.Application.Exit();
  10: }

OpenNetCF has some great products, their download count is at 3/4 million at the time of writing. They have good customer service too.

Labels: , ,

Monday, March 09, 2009

Implementing visual inheritance in windows mobile

We've been working on a Windows Mobile 6 PDA application and one requirement is to have a status bar that shows internet connectivity and updates.

In Windows programming, a common way to do this is to create a base form which has a status bar and a mechanism to update it, this form is then used as a template for other forms. This means that you have a single point of failure, update and maintenance. This is a good thing as if you added that status bar to all your forms, you'd increase your maintenance headache with each new form.

On Windows Mobile, there is support for the same visual templating mechanism, but there are a few pitfalls. If for example on your base form you wanted to add a popup keyboard, you'd need to add a reference to Microsoft.WindowsCE.Forms. This unfortunately breaks the visual inheritance in Visual Studio's form designer saying "Visual inheritance is currently disabled", this also occurs when using Platform Invoke (a method of calling methods in the base operating system) in the base form.

Luckily there are a few workarounds for this:

Add a class diagram, select your base form, add a custom attribute of DesktopCompatible(true), this adds an XML Metadata Attribute file (.xmta).The xmta file can cause a genasm.exe error, ensure the build action is set to None and the copy to output directory is set to Do not copy, this should now build fine.


Job done, we have visual inheritance visible in the designer.

Labels: , , ,

Thursday, February 12, 2009

Empty UpdatePanels add a blank line after callback in IE

We hit a bug the other day where we found that UpdatePanels misbehave somewhat in Internet Explorer.

We spotted it because we always have an area at the top of our pages for displaying error messages. (You can see an example of this if you go to our Contact Us page and click "Send Message" without filling in your contact details.)

If you did a callback to the page that didn't result in any errors, the UpdatePanel around the error box would remain empty. Thus in most browsers you wouldn't see anything happen at the top of the page.

However, IE would insert a blank line where the UpdatePanel was, bumping the rest of the page content down by 12 pixels or so.

This is supremely annoying as it can really throw out the design of your site. It turns out it happens even if there elements in the UpdatePanel, if they're elements that don't render anything visible on the page (empty spans, hidden input controls, etc.).

Now, one way to fix it is to set the RenderMode of the UpdatePanel to Inline. This stops the bug in IE, but it also makes the UpdatePanel render as a span instead of a div. This is no good for us because the error box (when it renders) is a div, and nesting a div inside a span is invalid html.

So here's the solution we came up with - I hope it's useful to you too!

We created a class that inherits from UpdatePanel, but overrides how it renders, adding a style of display:inline if it's rendering as a div. So now it's still a div (and so it's valid to nest div within it), but it renders inline as a span would, thus sidestepping the IE bug.

Also, as it inherits directly from UpdatePanel, we can use <Compsoft:UpdatePanel> everywhere that we'd use <asp:UpdatePanel>. It's fire-and-forget: it behaves exactly like an UpdatePanel, except without the problems.

public class UpdatePanel : UpdatePanel
{
  protected override void RenderChildren(HtmlTextWriter writer)
  {
    // IsInPartialRendering is a reliable way of
    // telling it's a callback
    if (!this.IsInPartialRendering &&
      this.RenderMode == UpdatePanelRenderMode.Block)
    {
      StringBuilder sb = new StringBuilder();
      base.RenderChildren(new HtmlTextWriter(
        new StringWriter(sb)));

      string renderedHtml = sb.ToString();

      if (!renderedHtml.StartsWith("<div "))
        // This should never happen; better safe than sorry
        throw new Exception(
          "An UpdatePanel with a RenderMode of Block "
          + "isn't rendering as a <div>");

        writer.Write("<div style=\"display:inline\"");
        writer.Write(renderedHtml.Substring(4));
    }
    else
      base.RenderChildren(writer);
  }
}

Labels: , , , , , , , ,