September 9 2010




 

Maarten's Blogs

The life of a Windows Mobile Developer and Windows Embedded Evangelist.

Search Blog Entries:

 
Friday, November 27, 2009
Windows Mobile Application Development DVDsMobile Part 9 Available Now
If you want to learn how to create a full blown Windows Mobile Application from scratch using Visual Studio 2008 this is your chance. Over the upcoming months DotNETForDevices will show you how to create DVDsMobile, an application that stores a personal collection of DVD’s, can add DVD’s to a wish list, makes use of location awareness to find nearby DVD stores, makes use of a Web Service to quickly enter DVD information and consists of one single binary, being able to target multiple different Windows Mobile Devices. Besides an article and a growing number of downloadable videos, all source code will be made available for download at a later time, as well as a complete book, explaining the entire application and introducing best practices to develop applications for Windows Mobile Devices. Today, video number nine is available for download. In this video you will learn how to setup a DataGrid control in such a way that columns are adjusted depending on the column header width, scroll bars being visibile and display orientation mode of the device. This video, as well as all previous episodes in this series and additional documentation can be obtained by navigating here.

In the upcoming weeks, all source code that is created for DVDsMobile will be published as well. Complete documentation and additional videos will be published soon as well.



   What is this?19:55 PM
Blog Ref URL:  http://www.dotnetfordevices.com/forum.html#386


Thursday, November 19, 2009
Windows Mobile and Location Awareness through GPSID

In one of the developer forums on MSDN an interesting question was asked around using the GPS sample code that is shipped as part of the Windows Mobile 6 SDK. Running the sample code as is always worked fine for me when running the sample code inside Device Emulator and making use of FakeGPS. The developer that asked the question was however running on a real device and noticed that the application was sometimes hanging on application close down or on stopping GPS data retrieval. Since I am very passionate about location aware applications I wanted to find out what is going on here. The beauty of Windows Mobile Sample code is that all source code is available for you. Of course there are disclaimers that the code is provided “AS IS” with no warranties. I understand that and I respect that. Well, after examining the GPSSample I strongly recommend not to use this for study purposes. I probably should go one step further and also warn you against using this sample as a managed wrapper around the GPS Intermediate Driver inside your production code. I have shown location aware applications based upon the Microsoft.WindowsMobile.Samples.Location namespace in How-Do-I for Devices videos, in Webcasts and during conferences like Tech-Ed. And only now I realize that I was extremely lucky because my code samples did not crash while demonstrating them.

Let me try to explain the issues I found with this particular sample and how to create a quick and dirty fix for them. I will only concentrate on the issues I found so far, but given the nature of these issues I would not be surprised if there are more issues. First let me show you an edited version of the class diagram of the Microsoft.WindowsMobile.Sample.Location assembly. It looks pretty nice, straight forward and easy to use, as it should be to be a useful managed wrapper around a lot of native code (being the GPS Intermediate Driver implementation).

The class GpsPosition has a large number of properties that allow you to easily retrieve GPS readings like Latitude and Longitude. However, you can also see that it defines two public methods, one called GetSatellitesInView, the other called GetSatellitesInSolution. The latter is an interesting one, since it returns the number of satellites that are used to obtain our current position. This number is equal or smaller to the number of satellites in view. This number of satellites that are used to obtain our position depends on information that is passed in an array containing extended satellite information. This is where the first potential problems in the GPSSample code can be found.

Here is the original code that is available in the GpsPosition.cs source file:

Listing 1

As you can see, the method GetSatellitesInSolution calls the method GetSatellitesInView internally. Now imagine that the variable dwSatellitesInView in the method GetSatellitesInView is 0. That means that the return value of this method will be null. In itself this is fine, but GetSatellitesInSolution is using it and does not check for a null return value, but instead simply uses the variable called inViewSatellites. If a null was returns, this means we will get a NullReferenceException, which in the GPSSample will be reported to the user when new GPS readings are updated in the main form. Solving this problem involves two modifications, the first one being a check for null in the GetSatellitesInSolution method that can be found in the source file GpsPosition.cs:

Listing 2 

Since GetSatellitesInSolution can now return null as well, another modification should be made in the Form1.cs file of the GPSSample that makes use of this information. The UI of Form1 is updated inside this method with the highlighted code snippet causing the next potential problem:

Listing 3

Besides the potential problem the above code can cause, there is also a performance improvement possible. It is not necessary to call the position.GetSatellitesInView method (which is internally used in position.GetSatellitesInSolution). Instead, the property position.SatellitesInViewCount can be used that retrieves the same number that we want to display in the sample code. If you change the highlighted code into the following code, the easy problems are solved:

Listing 4

A more complex issue to solve:

Using the managed wrapper around the GPS Intermediate Driver you have the possibility to subscribe to LocationChanged and DeviceStateChanged events. If you subscribe to these events, your event handler will be called each time a change occurs in either location information (received from satellites) or device information (received from the connected GPS hardware). These changes are passed to your event handler(s) on a separate thread. This has a few consequences. The first one is that you cannot simply update UI Controls with the new readings that you can retrieve inside your event handler. If you take a look in the Form1.cs source file that is part of the GpsSample, you can see the following code snippet:

Listing 5

There is even some meaningful comment in this code snippet, because it is not allowed to update the UI immediately on any other thread then its creator. Instead, Control.Invoke is needed to update a UI control. Control.Invoke updates the UI control using the thread that created the UI control on behalf of the thread requesting the UI update. However, Control.Invoke is a synchronous method, it will block until the UI control is actually updated. Here is where our complex problem starts to appear. In order to understand the problem, we now have to take a look at the thread inside the source file Gps.cs that sets the events to inform any subscriber of new data being available. This is the thread responsible for that action:

Listing 6

In this code snippet I have highlighted a block containing the statement lock(this) which is a potential cause of hanging the sample application. During its lifetime, the thread that reads location information marks the entire GPS class as critical for the entire lifetime by calling lock(this). This means that this thread has exclusive access to everything that is defined in the class Gps, including the variables of type GpsPosition and GpsDeviceState that are passed as EventArgs when the event handlers inside Form1.cs are called.

The sample UI that is defined in Form1.cs tries to retrieve location information and device state information. In listing 4 you can see that, in order to display location information, a call to a method inside a GpsPosition object is made. Since this object is passed to us from inside the worker thread of listing 5, the thread wanting to retrieve that information (through Control.Invoke, being the main thread), will be blocked until the worker thread of listing 6 terminates. Well, guess what, the worker thread can only terminate when the user selects menu entries to Exit the application or to Stop GPS. This code can never execute, because our main thread is still waiting for the worker thread of listing 6 to terminate. This is a typical deadlock situation. Two different threads are waiting on each other, without any of them being able to release locked resources. The real problem is the fact that the worker thread of listing 6 contains lock(this) to protect variables. Even the MSDN documentation indicates this as something you should not do. In the sample everything in the class is locked, and probably only a few variables need to be protected against mutual access by different threads. Also, the lock is never released until the worker thread terminates, even though good practice is to protect variables against mutual access for a short a time as possible.

Since I don’t want to change too much code right now, I take a very pragmatic approach here (and in fact, you should do something similar if you are making use of the Microsoft.WindowsMobile.Samples.Location assembly with only the modifications as I described earlier in this blog entry implemented). Leaving the GPS.cs file as is (as most of possible), you can solve this deadlock situation by modifying the UI code. You already saw the two different locations where the screen is updated through an Invoke method (in listing 5). Since Control.Invoke works synchronously, the main thread will block until the thread that refreshes satellite readings will terminate. The problem is that this latter thread will only terminate when the main thread sets an event, which it can't do because it is blocked. And there is the deadlock situation. The quick and dirty solution to solve this problem is by modifying the code inside Form1.cs, not updating UI controls through Control.Invoke, but through Control.BeginInvoke, which is an asynchronous way of updating the UI control, not blocking the main thread. So if you modify the code inside Form1.cs to this, you have solved the potential deadlock situation, even though the Gps object is entirely locked by the data retrieval thread:

Listing 7

This should solve at least the most dramatic issues you might run into when playing with the GpsSample application, or (even worse) when using similar code inside your own (commercial) application. There are a few more issues with the sample code, for instance omitting to unsubscribe to event handlers. In this simple example this is not dramatic, but in a real application this might lead to managed memory leaks. All in all, I think it is time to completely revise the GpsSample and the Microsoft.WindowsMobile.Samples.Location assembly. Once the conference season is over for me on December 2nd and I don’t have to deliver presentations for a whole month at least, I will probably rewrite the entire sample and the managed wrappers and of course I will publish them, most likely both on DotNETForDevices and on Code Gallery.



   What is this?17:51 PM
Blog Ref URL:  http://www.dotnetfordevices.com/forum.html#385


Tuesday, November 17, 2009
Adjusting DataGrid Columns on a Windows Mobile Device

I ran into a few challenges when displaying a DataGrid control inside a Windows Mobile application. The DataGrid only contains two different columns. One of the columns must have a fixed length that is determined by the title of the column. The other column will have a variable width, depending on the display orientation mode of the device and also depending on the presence or absence of both a column header and a vertical ScrollBar. Also, the number of pixels occupied by column separators must be taken into consideration. To retrieve the width of the column header and the width of an individual column separator, a little bit of reflection is needed. The column header width is stored in a private instance variable of the DataGrid with the name v_cxDefaultRowHdrWidth. The width of one single column separator is stored in a private instance variable of the DataGrid with the name v_cxyDefaultResizePixel. Even though both values are stored in private instance variables of the DataGrid, you can retrieve them through reflection, as shown in the following code snippet:

To measure the size of one of the column headers dynamically, which is necessary because the application will be localized, it is possible to call out to MeasureString, a method that is exposed on the Graphics class. To set the correct width of this column, the following code snippet is used:

The code snippet shown above also adds two times the width of an individual column separator, since the column is surrounded by two different column separators. What I showed so far is relatively easy and straight forward. The real challenge came when trying to adjust the column width of the other column, depending on presence or absence of a ScrollBar. My original idea was to P/Invoke to the Win32 API GetSystemMetrics when a vertical ScrollBar is displayed in the DataGrid. To determine if a ScrollBar is present I used the following if statement:

It turned out that the if statement shown above is not the best approach. My idea was that a vertical scroll bar would be displayed automatically if the number of records visible in the DataGrid is smaller than the number of records available in the underlying BindingSource. This is usually the case, but I found out that a record in the DataGrid is considered visible, even if only a small part of it is visible in the DataGrid. Finding this out was purely coincidental. When testing the application with a database containing 10 records and changing the display orientation mode of the test device from portrait to landscape, it seemed that I had 10 records visible (so no need for a vertical ScrollBar). However, in reality there were only 9.5 records visible, meaning a vertical ScrollBar was displayed, and because I didn’t adjust properly for this, a horizontal ScrollBar was displayed as well. Solving this problem took a bit of thinking and a bit of interrogating DataGrid members. A DataGrid is a control container, being able to host other controls. Without adding additional controls myself, I found out that a DataGrid already owns to Controls, a horizontal and a vertical ScrollBar. After finding this out, the solution to my original problem all of a sudden became easy, and I also could get rid of the original way to measure the width of the vertical ScrollBar through P/Invoke. So instead of the previously displayed if statement, the code now has changed into the following:

With verticalDataGridScrollBarIdx defined as 1. Not only does this an accurate indication if the ScrollBar is visible, the performance of this particular piece of code is better as well, since there is no need to P/Invoke to a native Win32 API. Since the column with the fixed length is making use of reflection to determine the width, its width is only calculated once. This improves performance as well, especially since reflection, like P/Invoking to native code consists of ‘expensive’ operations as far as performance is concerned. A more complete sample snippet now looks like this:

And that is it. Knowing a bit more about the internal operation of the DataGrid, combined with a bit of thinking, just led to more efficient code that is working better as well.



   What is this?21:03 PM
Blog Ref URL:  http://www.dotnetfordevices.com/forum.html#384










SpiralFX Technology Solutions
www.spiralfx.com

:: ::