Friday, October 26, 2007

SystemState StateChanged Subscription Must Occur on UI Thread?

I posted the following to the .NET CF newsgroup this morning:

The Microsoft.WindowsMobile.Status.SystemState class offers a great way to track a number of interesting and useful device system states (e.g., incoming phone calls, battery strength, etc.). However, recently I observed that the SystemState.Changed += new ChangeEventHandler(OnSystemStateChanged) subscription must be made from the UI thread. Has anyone else run into this? I attempted to write a console app that uses many of these system state notifications; however, none of the events were actually occurring. Once I switched to a form-based application, everything worked great.

Is this documented somewhere? If so, I couldn't find it. I am programming in .NET CF 2 for Windows Mobile 5.0 devices.


Chris Tacke responded with,

Most of those events come from windows messages being posted at a low level (FileSystemWatcher works int he same way too). If you never call Application.Run, no message pump is ever created, so no windows messages are ever dispatched.

I don't think I've ever seen it documented, but if you walk through the aygshell source code in Platform Builder (which a lot of these come from eventually), you'll see that's how they work. I agree that it's a poor choice, but it's how it was implemented. The workaround is a very long, tedious process (again, we've done it for file system notifications) of reimplementing the entire listening system, creating a hidden window for your app or implementing a Run() that doesn't take a Form (like we did in the SDF).

Thursday, October 25, 2007

Image Download in .NET CF

Even though it seems more popular to use the WebClient class to download a single image or two, that class is not available on .NET CF. Nonetheless, it's easy enough with WebRequest and WebResponse.

//grab icon
Uri uri = new Uri("valid url to image");
HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream imageStream = httpResponse.GetResponseStream();
Bitmap buddyIcon = new Bitmap(imageStream);
httpResponse.Close();
imageStream.Close();

//save icon as jpeg
string iconFilePath = Path.Combine(FullContactsPath, contact.UserId + ".jpg");
buddyIcon.Save(iconFilePath, ImageFormat.Jpeg);

Tuesday, October 02, 2007

Security Manager for WM5

Though the Device Security Manager PowerToy for Windows Mobile 5.0 has been available since June 6th, 2006, it's such an important application that it deserves mention even a year after its release. For one thing, it allows developers to easily bypass the incessant prompting that occurs every time a binary is changed and loaded on the device. And for two, it allows you as a developer to test different security policies on one device.

The website says:

Device Security Manager helps developers test various security policies for Windows Mobile devices. It is designed as a desktop application that ships w ith a preset list of “security configurations”. A security configuration can be thought of as a template, which contains a collection of individual policies and settings. For example, a security configuration could define policies such as whether unsigned applications are allowed to execute, whether RAPI is disabled etc. Using this tool, the developer can provision a Windows Mobile device with different configurations, and then test the application’s behavior under these configurations. This tool can be used either on an emulator or an unlocked Windows Mobile device.

Tuesday, September 11, 2007

Force Closing the CameraCaptureDialog

The camera API in .NET CF 2 offers a great improvement over .NET CF 1, which had no common interface to the device's camera (you needed to work with the OEM's directly to obtain a reference to their camera driver information). The CameraCaptureDialog class in .NET CF 2 can be used to capture still photographs or video (with or without audio) in a few lines of code. However, like many of the more "advanced" features in the .NET CF 2 library, not all of the OEMs have correctly implemented the managed camera functionality on their devices. For example, one common complaint on discussion boards is not being able to close the camera after invoking it with the CameraCaptureDialog.ShowDialog() method--CameraCaptureDialog.Dispose() does not work. Thus, on some devices, the camera application stays open sucking up memory and disturbing your window z-order even after calling Dispose().

The code below provides a fix to this issue. It relies on a FindWindow P/Invoke to grab the handle to the device's camera application and a DestroyWindow P/Invoke to force it to close. Note that the Cingular 2125 device (which is where I tested this code) always appends [Photo] or [Video] to the camera title (no matter what title you set yourself). Thus, I have a function called GetCameraCaptureDialogTitle that appends that right suffix depending on the capture mode (e.g., video or photo).

//Open the camera capture dialog
CameraCaptureDialog cameraCaptureDialog = new CameraCaptureDialog();
string windowTitle = GetCameraCaptureDialogTitle(cameraCaptureDialog);
DialogResult dr = cameraCaptureDialog.ShowDialog();
if (dr == DialogResult.OK)
{
string capturedFileName = cameraCaptureDialog.FileName;
//do stuff with file!
}
cameraCaptureDialog.Dispose();

//sometimes the camera capture dialog does not close automatically
//we look for the window title and force close it ourselves
IntPtr ptr = WindowUtils.FindWindow(windowTitle);
Debug.WriteLine(string.Format("Found window '{0}' with ptr={1} ", windowTitle, ptr));
if (ptr != IntPtr.Zero)
{
//force the camera closed
WindowUtils.DestroyWindow(ptr);
}

Here are the helper functions:

private string GetCameraCaptureDialogTitle(CameraCaptureDialog dlg)
{
if (
dlg.Mode == CameraCaptureMode.Still)
{
return string.Format("{0} [{1}]",
dlg.Title, "Photo");
}
else
{
return string.Format("{0} [{1}]",
dlg.Title, "Video");
}
}

[DllImport("coredll.dll", SetLastError = true)]
public static extern IntPtr DestroyWindow(IntPtr hWnd);

[DllImport("coredll.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

public static IntPtr FindWindow(string windowTitle)
{
return FindWindow(null, windowTitle);
}


Please e-mail me or post a comment if you have any questions. Also, I use this trick in the MyExperience tool--the source for which can be found here and is open sourced under the BSD license.

Finally, moving beyond CameraCaptureDialog, it would be nice if .NET CF provided events for when a new image or video is captured on the device (e.g., a NewMediaCapturedEvent would be cool to have at the SystemState level if not in the CameraCaptureDialog as well). Furthermore, .NET CF 2 does not allow you to take images/video automatically without user intervention. This feature might be useful for taking timer-based pictures (e.g., for those times when you want to take a self/group portrait but have no one around to take the picture for you). Marcus Perryman has C++ code that turns a Windows Mobile device into a wireless webcam using using DirectShow (see this post). It would be cool to have this fully fleshed out in managed code.

Thursday, August 16, 2007

WM5 Maximum Storage Card Capacity

Most of the Windows Mobile 5 devices that I've used including the T-Mobile MDA, SDA, and Cingular 2125 use miniSD flash storage. The Samsung Blackjack, however, uses microSD. With ever-increasing storage capacities available in these formats, I was curious if there was an upper capacity bound on WM5 devices. It looks like the internets are mixed on this one.

This post by Mike Calligaro on the Windows Mobile blog points out that most cards and card readers available (at least on Jan 1st, 2007) follow the SD Spec 1.1, which maxes out at 2 gigabytes. Here's an excerpt,

"Up to 2G, the only negative to larger storage cards is that they cost more. They don't burn any more power than smaller ones and they're not inherently any slower than smaller ones. I've used 2G cards in my Windows Mobile devices, and they work fine. Unfortunately, 4G and larger cards aren't likely to work yet.

Most cards and card readers out there follow the 1.1 version of the SD specification. That spec maxed out with 2G cards. There's a new 2.0 version of the spec that allows for larger cards, but Windows Mobile currently doesn't support SD 2.0. Even though we don't explicitly support SD 2.0, it's possible for our OEMs to add support themselves (I don't know if any have). So if you've got a Windows Mobile device that's able to read 4G SD cards, you don't have to call me a liar. Ignorant, yes. Liar, no."

Riki commented on this blog entry, however, and said:

"The maximum capacity of SD card is 2GB under SD 1.1 of SD spec; however, by using FAT32, many SD 1.1 host devices can use 4GB SD cards. SD 1.0/1.1 uses traditional “Byte Addressing” scheme which limits the maximum capacity to 4GB while SD 2.0 adopts “Sector Addressing” scheme."

So it looks like when purchasing new SD memory for a WM5 device, you should go with 2 gigabyte cards--those are guaranteed to work. However, some devices may support 4 gigabytes and up, especially if the OEM implemented the SD 2.0 Spec.

On a related note, my advisor found two programs that turn a WM5 device into a USB SD reader. I haven't used either of these, so I cannot comment on them:
http://www.softick.com/pocket-pc/cardexport2/
http://www.modaco.com/WM5torage-t238545.html

Sunday, July 22, 2007

Configuring the GPS Intermediate Driver

I recently purchased the QSTARZ Bluetooth GPS Receiver Model BT-Q818 to play around with some location-aware research ideas I've had. First, the GPS receiver worked out-of-the-box after following the configuration instructions in the directions (or see this post on the Windows Mobile team blog). I tested it both on my Cingular 2125 SmartPhone and Cingular 8125 Pocket PC Phone. Second, it works amazingly well with the new Windows Live Search--I can get smooth map scrolling, hybrid maps, and real time traffic overlays on my phone automatically centered on my current location. To configure Windows Live on WM to use GPS, open Live Search->Menu->Settings and then set the GPS COM port (in my case, COM6). Then, open Map and make sure that Menu->Center on GPS is checked.

I was anxious to start my own hacking. I knew that Windows Mobile 5 shipped with the GPS Intermediate Driver framework, unfortunately I did not realize that this is an unmanaged API. However, both the Windows Mobile 5 SDK and the Windows MObile 6 SDK ship with sample code that provides a managed wrapper around that native GPS API. On my computer, these two samples can be found in:
  1. C:\Program Files\Windows Mobile 6 SDK\Samples\Smartphone\CS\GPS
  2. C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Samples\Cs\Gps
Unfortunately, neither of these samples worked for me immediately. I don't have a WM6 device, so I'll focus on the WM5 sample. The sample includes the Microsoft.WindowsMobile.Samples.Location GPS wrapper API and a small test app called GpsSample. To get the sample to work, you must configure the GPS Intermediate Driver, which requires either editing the registry or, alternatively, running the "GPS Intermediate Driver Control Panel." See Configuring the GPS Intermediate Driver on msdn. Well, where can I find this control panel? As the msdn link points out, many OEMs hide the application icon. On my Cingular 8125 Pocket PC Phone, this was certainly the case. Here's what I did to unhide it:
  1. On the desktop, open Start->All Programs->Microsoft Visual Studio 2005->Visual Studio Remote Tools->Remote Registry Editor
  2. Connect to your Windows Mobile device in the Remote Registry Editor
  3. Find the path: HKEY_LOCAL_MACHINE\ControlPanel\GPS Settings
  4. Delete any "Redirect" or "Hide" keys under HKEY_LOCAL_MACHINE\ControlPanel\GPS Settings.
Then, on my Pocket PC device, I opened Settings->System and there was a GPS icon. Click on that icon and choose an unused COM port. This is the COM port that your GPS applications are going to communicate through--the GPS intermediate driver talks to the hardware directly and serves as a virtual device sending data out this COM port. I selected COM0. Then select the Hardware tab and choose the GPS hardware port. On my device, I setup GPS to communicate via COM6 (at the highest baud rate possible). Then on the third and final tab ("Access"), make sure that Manage GPS Automatically is selected. After doing this, I reran the WM5 managed GPS sample and it worked great :)

Successfully configured GPS Intermediate Driver on Pocket PC Phone

Well, what if you have a SmartPhone? According to Jason Fuller on the Windows Mobile Team blog, the SmartPhone does not have the GPS Intermediate Driver Control Panel (see his post here). You can, however, manually configure the GPS Driver by modifying the registry. Again, using the Remote Registry Editor found in the Visual Studio Remote Tools directory:
  1. [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS Intermediate Driver] "IsEnabled"=dword:00000001
  2. [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS Intermediate Driver\Drivers]
    "CurrentDriver"="BT GPS"
  3. [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS Intermediate Driver\Drivers\BT GPS]
    "CommPort"="COMX:" where X = the hardware COM port (for me COM6)
    "FriendlyName"="BT GPS"
    "InterfaceType"="COMM"
See this post on xda-developers for more information about modifying the registry to configure the GPS Intermediate Driver. Alternatively, someone has created a small tool to modify the registry settings--run this from your SmartPhone. Here's the GpsSample running on my Windows Mobile 5 SmartPhone (Cingular 2125).

Successfully configured GPS Intermediate Driver on SmartPhone

Update 07/24/2007 11:58PM: Some have asked me to post further details on the registry settings I am using on the Pocket PC and SmartPhone. Here's a PDF displaying screenshots of my key/value pairs related to the GPS Intermediate Driver.

Friday, July 20, 2007

Wallpaper, Screenshots, and Application Switching

To get around some of the Today Screen API limitations (see this post for a Today Screen rant), I've played around quite a bit with programatically switching the wallpaper on a WM device. However, there a number of problems with this approach, most significantly: changing the device wallpaper is slow and once the device has been signaled that the wallpaper has been updated, it does not actually redraw the wallpaper until the desktop is visible (e.g., the desktop is the top level window). For more about this issue, see my .NET CF newsgroup post. Nonetheless, changing the device wallpaper is one of the easiest ways to display ambient information.

A project at Intel Research required that a screenshot be taken of a specified application, cropped, and displayed as the wallpaper on the device. However, as mentioned above, setting the wallpaper on a user's device can be an intrusive operation--not only can it take between 10-30 seconds but the wallpaper update does not actually happen until all applications are minimized making the desktop visible.

I created a little test application which fulfills our requirements and attempts to avoid disrupting the user by waiting to execute until the device is idle. Here's how it works:
  1. Waits for device idle
  2. Finds handle to specified application (based on its window title)
  3. Switches from current app to specified application (saving current foreground window handle)
  4. Takes screenshot
  5. Crops screenshot (if necessary)
  6. Sets background wallpaper to screenshot
  7. Minimizes all open applications so phone background refreshes
  8. After background refresh, restores state of open applications
  9. Returns to saved foreground window handle
  10. Puts device back to sleep
Yes, it's hacky but I could think of no better way to do this. Note that in this case it was not possible to create a Today Screen plug-in.

Download the source code and the binary. You should be able to compile and deploy as long as you have the Smart Device Framework 2.0 from the OpenNETCF team installed. This sample will probably work with the SDF 2.1 as well but I haven't tested it. Alternatively, you can download the binary zip file and add those .dll references to the source code project. I've also added this sample code to the samples directory in Roam (see SourceForge). Roam is a Windows Mobile open source library which provides functionality like a SQL connection pool, power management functions, and a whole slew of UI code.

Note: this code has been tested on the Cingular 2125 and the T-Mobile SDA device. In addition, I also ran it on the Cingular 8125 Pocket PC Phone and everything worked except for the wallpaper changing code--this is because Roam's wallpaper changer methods only work on the SmartPhone.

Programming the Today Screen, A Rant

I find the Today Screen APIs (and lack thereof) to be one of the great failures in the design of the Windows Mobile framework. Many times in my mobile computing research, I have looked enviously at the Today Screen as prime real estate for ambient display of information and novel interactions. From an HCI perspective, it should be one of the most configurable components on the WM platform--it is, after all, a part of the display that the user glances at nearly every time they open/use their phone be it to check the time or simply to make a phone call. That is why, of course, Microsoft themselves include Today Screen plug-ins for calender information, text messages, emails. Microsoft has also recently recognized the value of ambient information on the desktop--Vista now ships with the Gadget Bar, which displays information about stocks, weather, email, traffic, etc. in an ambient manner.

This same functionality should be available on WM. Unfortunately, not only are these plug-ins difficult to develop for Windows Mobile (e.g., they hook into a rather archaic Windows messaging scheme, cannot be C#/VB, and cannot easily be animated) they also require that the user modify their Today Screen settings by selecting a new configuration XML file. This latter point sounds harmless; however, it requires some effort to allow the user to maintain their current Today Screen look and feel with the addition of the new plug-in (even if this plug-in is a one line text output). They must copy over the XML into each of their existing Today Screen profiles--otherwise the plug-in will not be visible. I've seen some developers simply ship their plug-in with a fresh Today Screen XML file that is meant to overwrite the user's existing profile; however, unless the XML file has the exact same plug-ins specified, the user may miss out on a plugin they've previously installed (or a layout they've established via Settings->Home Screen->Home screen layout).

Note: I speak only out of my own personal experience and watching others in my lab attempt to play around with Today Screen functionality. Though I haven't used WM6, it does not appear that this functionality has been improved with that release--perhaps WM7?

Saturday, June 02, 2007

Measuring Time on .NET CF 2

If you develop code on both the desktop with the full .NET and on the mobile platform with .NET CF, you have to be careful with the behavioral differences of some classes. DateTime is one such class. On the desktop, DateTime.Now is capable of 10 millisecond resolution (at least on WinXP and Vista). On the mobile platform, however, DateTime.Now only has a resolution of 1 second. Quite the difference if you're using DateTime.Now as an easy way to timestamp data. Note that this also includes the DateTime.Now.Ticks, which on the desktop is measured in 100-nanosecond units but is only at the 1-second level in Windows Mobile. So, what are the alternatives?

The most straightforward method may be Environment.TickCount (which is different from DateTime.Ticks). Environment.TickCount represents a 32-bit signed integer containing the amount of time in milliseconds that has pass since the last time the computer was started. The problem with TickCount, however, is that it is only a 32 bit value. Therefore, if the system runs continuously (e.g., no restarting) for 24.9 days the TickCount value will reach int.MaxValue and then wrap to int.MinValue, which is a negative value. Then, for the next 24.9 days, Environment.TickCount will increment from int.MinValue to 0 and start the cycle all over again.

Alternatively, you can P/Invoke QueryPerformanceCounter and QueryPerformanceFrequency. The QueryPerformanceCounter function retrieves the current value of the high-resolution performance counter, if one exists, on the computer. The QueryPerformanceFrequency function retrieves the frequency of the high-performance counter, if it exists. The frequency cannot change while the system is running. The frequency is also platform dependent. I'm not sure if any mobile device ships with a performance counter that offers higher resolution than Environment.TickCount but it is worth experimenting with. Here's what MSDN has to say about "high resolution timers"

If a high-resolution performance counter exists on the system, you can use the QueryPerformanceFrequency function to express the frequency, in counts per second. The value of the count is processor dependent. On some processors, for example, the count might be the cycle rate of the processor clock.

The QueryPerformanceCounter function retrieves the current value of the high-resolution performance counter. By calling this function at the beginning and end of a section of code, an application essentially uses the counter as a high-resolution timer. For example, suppose that QueryPerformanceFrequency indicates that the frequency of the high-resolution performance counter is 50,000 counts per second. If the application calls QueryPerformanceCounter immediately before and immediately after the section of code to be timed, the counter values might be 1500 counts and 3500 counts, respectively. These values would indicate that .04 seconds (2000 counts) elapsed while the code executed


Here's the code to use the QueryPerformanceCounter in .NET CF 2 on Windows Mobile.

public static class PerformanceUtils
{
[DllImport("coredll.dll", EntryPoint = "QueryPerformanceCounter")]
private static extern bool QueryPerformanceCounter(out long count);

[DllImport("coredll.dll", EntryPoint = "QueryPerformanceFrequency")]
private static extern bool QueryPerformanceFrequency(out long countsPerSecond);

//these two variables are initialized in the PerformanceUtils static constructor
public static readonly long Frequency;
public static readonly long FrequencyInMs;

static PerformanceUtils()
{
if (QueryPerformanceFrequency(out Frequency) == false)
{
throw new Exception("The high resolution timer is not available on this device.");
}

FrequencyInMs = Frequency / 1000;
}

public static long GetTimestampMs()
{
long count;
QueryPerformanceCounter(out count);
return (long)Math.Round(count / (double)FrequencyInMs);
}

public static long GetPerformanceCount()
{
long count;
QueryPerformanceCounter(out count);
return count;
}
}


Update 06/07/2007 @ 1:45PM: Note that on a PocketPC the Environment.TickCount value is reset when you "soft or hard reset" the device. It is not reset when you suspend and resume (power off/on) the device. This is according to Ercan Turkarslan from Microsoft Mobile Devices Developer Support. On a Pocket PC Phone or a SmartPhone, the Environment.TickCount value is reset when you power off/on the device.

Friday, April 13, 2007

Announcing Roam

Roam is a .NET CF 2 open source library for Windows Mobile devices that I've been developing off and on for the past year or so. A majority of the development has been driven off my own needs as a SmartPhone developer and HCI researcher. Although the source code is hosted on SourceForge and released under the BSD license (link), I have not had a chance to write a webpage or formal documentation. Thus, I've held off on advertising it on newsgroups/forums. I thought I would mention it here because I believe the source code could be of some use to my readers. Note that Roam requires OpenNETCF's Smart Device Framework (SDF 2.0) library. They just recently released SDF 2.1, I'm not sure if Roam is compatible or not...

Currently, the Roam library is broken down into four namespaces: Roam, Roam.Common, Roam.SqlCe, and Roam.UI. Each of these namespaces are compiled into their own assembly to save space.
  1. Roam: contains media related functionality (e.g., sound player, camera media sniffer), pocket outlook related code (e.g., semi-robust SMS sending system), and low level device related utility classes (e.g., power notifications, storage card utilities, device id)

  2. Roam.Common: contains code that is not-specific to Windows Mobile (i.e., this .dll also runs on the desktop). The largest subnamespace in this library is the Collections classes which include a HashSet, a Tree, a PriorityQueue, and a ReadOnlyHashtable among other things.

  3. Roam.SqlCe: contains code relevant to SQL Server Mobile / Compact Edition. Currently, only two classes exist: SqlCeConnectionManager which offers thread safe connection pooling using a singleton paradigm and SqlCeWrapper which also offers thread safe access to the database by wrapping the SqlCeConnection object.

  4. Roam.UI: this is the largest assembly in the Roam project. It contains many of the UI controls I've needed over the past year and were not included in .NET CF (e.g., scrollable label) I've developed a fairly simple drawing architecture that many of my custom UI classes use. Currently, Roam.UI contains custom controls for image buttons, radio list boxes, check box lists, key filtered lists, numeric text boxes and scrollable labels. In addition, Roam.UI features a set of utility classes that wrap P/Invoke calls to draw rounded rectangles, change the device's wallpaper, etc.
Below are two brief demos of Roam.UI custom controls: the TextBoxFilteredList and the ScrollableLabel. Note that the embedded videos below are hosted on YouTube which changes the aspect ratio and overall quality. :( The original source videos can be found here and here.





Wednesday, April 04, 2007

Deprecated Features In Windows Mobile 6

Channel9 Wiki has a list of deprecated API features in WM 6 that should no longer be used.

(link)

Windows Mobile Platform Growth

A Microsoft developer posted about why he loves to work on Windows Mobile on the Windows Mobile Team Blog. In it he details the massive growth the Windows Mobile platform has experienced in the past few years:

I’ve talked a lot about not understanding marketers. It’s even harder to understand accountants (even though I’m married to one…). For some reason, our accountants think that the “year” starts in July and ends in June. Well, in the first half of this “year” (in the accounting sense), we sold over five million phone units. Last “year” we sold 150% more units than the year before. And in that year we sold 150% more units than the one before it. Weird accounting speak aside, we’ve been growing at 150% for a couple of years now. That’s easy to do if you’re small. But we’re not small. Exciting times.

(link)

SMS Toolkit

A colleague pointed me to MSR India's SMS Toolkit. I haven't had a chance to check it out but it looks very cool.

Tuesday, March 20, 2007

The Indexer Name

Any guesses why the following class won't compile?

public class SuperSimpleIndexerClass
{
__public double this[int index]
__{
____get { return 0; }
__}

__public double Item
__{
____get { return 0; }
__}
}


It has to do with the way indexers are internally represented in C#. By default, indexers have the name "Item." Thus, the indexer property and the explicit Item property will have a naming collision. We can fix this problem by providing the following attribute.

public class SuperSimpleIndexerClass
{
__[System.Runtime.CompilerServices.IndexerName("TheItem")]
__public double this[int index]
__{
____get { return 0; }
__}

__public double Item
__{
____get { return 0; }
__}
}


Now, this indexer will have the name TheItem.

Tuesday, February 20, 2007

Windows Mobile 6 != Windows CE 6

Microsoft is once again attempting to clarify the difference between Windows Mobile and Windows CE. Sue Loh on the Windows CE Base Team blog states:

Windows Mobile 6 does NOT run the CE 6 OS.
Technically the OS version # in WM6 is 5.02; it's an advancement of the OS (5.01) that was in WM5. Certain CE6 OS features have been ported to WM6. But the kernel VM architecture we've been discussing here does NOT apply to Windows Mobile 6.


(link)

Sunday, February 18, 2007

Oh No, Not Again, ActiveSync

My ActiveSync posts (e.g., ActiveSync Sit & Spin) are the most visited blog entries on this site by nearly an order of magnitude. It's clear that many others have encountered the same problems as I. ActiveSync 4.5 beta, however, was working very well for me--in fact, flawlessly. So, perhaps I should not have been so eager to upgrade to the full release. Now, my current problem could be completely coincidental with my upgrade--I'd been running 4.5 for two straight days without experiencing a any problems. However, yesterday I plugged in my Cingular 2125 WM5 SmartPhone and a dialog box popped up that read "The software you are installing for this hardware: SmartPhone USB Sync has not passed Windows Logo testing to verify its compatibility with Windows XP." (see Figure 1 below)

Figure 1: Windows Logo Testing Dialog

If you click "STOP Installation" the SmartPhone device will not be recognized by your computer; thus, you must press "Continue Anyway." In my two years of SmartPhone development, I have never seen this dialog (not sure if it is related to ActiveSync 4.5 or not). After selecting "Continue Anyway," ActiveSync opened and properly synchronized my SmartPhone. However, after unplugging the phone and plugging it in again, I received another dialog box--this one was a bit more alarming: "One of the USB devices attached to this computer has malfunctioned, and Windows does not recognize it." (see Figure 2 below)

Figure 2: USB Device Not Recognized

After this point, no amount of restarting (either my computer or device) would fix this issue. I'm not sure if Figure 2 is related to Figure 1 at all, but it seems likely. Interestingly, my other WM5 device (a Pocket PC Phone) still synchronized fine.

I was able to fix the problem by:
  1. Unplugging device from computer
  2. Uninstalling ActiveSync 4.5
  3. Restarting Computer
  4. Reinstalling Activesync 4.5
  5. Plugging device back in
Unfortunately, it only took me about three hours to get this right. Troubleshooting included a hard reset on my SmartPhone, thus losing all of my installed programs of which there are many. I don't believe the problem is on the device side, however, so a hard reset is probably not required (in fact, after my hard reset, plugging in my device would still cause the Figure 2 dialog to pop up).

Thursday, February 15, 2007

ActiveSync 4.5 Released

You can download ActiveSync 4.5 here. The readme.doc includes an overview of new features, a select few are below.
  • Feature: A device can stay connected to cellular and wireless networks while also connected to PC.
    • Benefit: Enables the device to receive incoming VoIP calls and MMS messages when it is connected to a PC.
  • Feature: An integrated troubleshooter utility is included.
    • Benefit: The utility scans your PC and device to identify problems that can affect the use of your device with the PC.
  • Feature: Overall stability has been improved.
    • Benefit: Enhances the reliability of connecting devices and syncing.
  • Feature: USB support has been improved.
    • Benefit: ActiveSync 4.5 provides the fastest USB transport between your PC and your mobile device to date.
There's also a plethora of exchange related features, but I don't use those so I'm not sure how useful they are.

Tuesday, February 13, 2007

What's New in Windows Mobile 6

Jim Wilson has posted an article "What's New for Developers in Windows Mobile 6" on msdn (link). Note that the difference between WM 5 and WM 6 is much less substantial than the difference between WM 2003 (WM4) and WM5. This is, in part, more due to the transition between .NET CF 1 and .NET CF 2 imo. Nonetheless, Here is a quick summary of the new WM 6 features I'm most interested in:

Update 02-15-2007: According to this post on the Windows Mobile Team Blog, the Windows Mobile 6 SDK won't be out until March 1st with a "refreshed" version on May 1st.

Thursday, January 11, 2007

Keeping SqlCeConnection Open and Thread Safety

I've done quite a bit of searching online and it's fairly clear that there is a bit of confusion about how one should use the SqlCeConnection object, particularly with regards to two interrelated issues: (1) whether to keep the SqlCeConnection open and (2) whether the SqlCeConnection is thread safe. For example, some people advocate for keeping one static SqlCeConnection open and shared for the lifetime of an application. However, if the application is multithreaded, can we assume that we can safely share the connection object? I've blogged about this once before here.

I think some of this confusion stems from the differences between the desktop version of SQL Server (SqlConnection) and SQL Server Mobile (SqlCeConnection). For example, in a MSDN forum post, Dave Hayden (a .NET/C# MS MVP) suggests that "For 99% of all applications, the best practice is to open and dispose of database connections right when you need them and not to leave them open for the duration of the application. Open the database connection as late as possible and close/dispose of it as soon as possible." If, like Dave recommends, we always open a local connection within our method calls (and do not access the SQL connection as a state object), we don't really have to worry about the thread safety of the SQL connection object.

Although this may be good advice for accessing SQL Server from the desktop, it contradicts the advice given by Microsoft developer Marcus Perryman in his SQL Mobile post on his blog, "The SqlCeConnection class implements the IDisposable interface because it allocates a number of unmanaged resources, and therefore the code must call Dispose() on the object before it goes out of scope to ensure these resources are cleaned up in a timely manner. Creating and destroying SQL Mobile database connections is an expensive task and so the SqlCeConnection is designed to be a long lived, shared instance across the lifetime of the application.".

Thus, it appears that Dave and Marcus contradict each other. However, Dave's advice was (I believe) given under the assumption that the person was using SQL Server and not SQL Server Mobile. So, it looks like the correct usage of the SqlCeConnection object is to reduce the amount of creating and destroying SQL Mobile database connections (the reasoning behind this is that SQL Server Mobile supposedly does not have connection pooling, see Marcus Perry link above).

So, then what about thread safety? The MSDN documentation is clear. Most objects within the SQL Mobile namespace are not threadsafe. For example, the SqlCeConnection documentation states, "Any public static members of this type are thread safe. Any instance members are not guaranteed to be thread safe." Thus, instance methods like BeginTransaction(), CreateCommand(), etc. are not thread safe. I'm not sure what the detriment/exception would be if this was not followed, but MSDN is clear, SqlCeConnection was not meant to be shared across threads.

OK, so what if you have a multithreaded application? It seems like there are two prevailing methods: (1) Marcus Perry suggests that "for a complex app, ideally the SqlCeConnection instance would be placed in a singleton wrapper class that manages access to the database." or (2) Ginny Caughey (MS MVP) offers the other approach, using a separate SqlCeConnection object for each thread. For the first approach, I would imagine the simplest wrapper possible may look something like the following (I will implement it as a static class rather than a singleton):


static class SqlWrapper
{

private static SqlCeConnection _sqlCeConnection;
private static object _objLock = new object();

static void Open(string connectionString)
{
lock (_objLock)
{
if (_sqlCeConnection != null)
throw new InvalidOperationException("Connection already open.");
_sqlCeConnection = new SqlCeConnection(connectionString);
}
}

static void Close()
{
lock (_objLock)
{
if (_sqlCeConnection != null)
{
_sqlCeConnection.Dispose();
_sqlCeConnection = null;
}
}
}

static int ExecuteNonQuery(SqlCeCommand sqlCommand)
{
lock (_objLock)
{
sqlCommand.Connection = _sqlCeConnection;
return sqlCommand.ExecuteNonQuery();
}
}

static SqlCeDataReader ExecuteReader(SqlCeCommand sqlCommand)
{
lock (_objLock)
{
sqlCommand.Connection = _sqlCeConnection;
return sqlCommand.ExecuteReader();
}
}
}


Does this seem right to people? In this class, we do not expose the underlying SqlCeConnection object, thus commands must be passed in via the wrapper interface to be executed (as they require a reference to a SqlCeConnection).

For the second approach, one connection per thread, the difficulty isn't necessarily in opening 1 connection per thread but knowing when to close those connections. In other words, a SqlCeConnectionManager class might manage access to SqlCeConnections and might serve as a SqlCeConnection factory (with, perhaps, an underlying connection pool). The factory may look at which thread is active (Thread.CurrentThread), check to see if a connection has been allocated for that thread (create one if not) and return the SqlCeConnection. However, the onus would be on the threads themselves to close their connections before exiting (this seems messy to me). I suppose one could spawn a monitoring thread that looked as the status of Threads and, once dead, would either close the respective SqlCeConnection or return the connection the connection pool. However, .NET CF 2.0 does not support the instance property IsAlive so it's not clear how one could do this.

I would imagine that a multithreaded application that launches many short-lived threads that need database access should probably go with the SQL wrapper solution as the overhead of opening/closing connections would introduce a performance hit (even with connection pooling).

An interesting side note: I created a test app on the mobile phone which launched 50 threads on a shared SqlCeConnection and proceeded to read/write random bits of data. No exception was thrown. Of course, the lack of error does not mean that it will always work.

Get Control From Handle

I have not yet determined a clean way to invoke code on the UI thread without access to a Form/Control. The Process class has a property called "MainWindowHandle," which returns the window handle of the main window of the associated process. So, for example, Process.GetCurrentProcess().MainWindowHandle would return a Handle (HWND) to the main window. But how can we translate a window handle to a Form?

In .NET 2.0, this is relatively easy, we can simply call Control.FromHandle(IntPtr handle). Thus, receiving access to the main window is simply:
(Form)Control.FromHandle(Process.GetCurrentProcess().MainWindowHandle)

Unfortunately, however, .NET CF 2.0 does not expose the Control.FromHandle method. I have not found anyone on the web who has solved this problem. A few relevant links:

1. How do I get System.Control object from a Win32 Handle?
2. Google Groups.

Given the limitations of CF, one hacky way to do this would be to expose a static property on your MainForm class which would return a reference to itself. This would actually work in my case as the MainForm should not be instantiated more than once.

Update 01/30/2007: I just made a post to Google Groups about this (link).