Windows or Web? A question you've asked and have been asked countless numbers of times for the past five years.
And yet, when it comes to the mobile field and building business applications for smart devices, many are surprised when they realize the same question needs to be answered. The question is slightly dissimilar but the answers are entirely different. “Windows CE or Mobile Web?” you might ask. As for the answer, the .NET world can steer you in two very opposite directions: .NET Compact Framework or ASP.NET Mobile Controls.
Welcome to Mobile CoDe.NET, the regular CoDe Magazine column dedicated to the development of mobile business solutions using Microsoft .NET mobility technologies. In the last issue, we explored the various Microsoft technologies for mobile development and the field of mobility in general. If you haven't checked it out yet, I strongly suggest you dig out the July/August issue from under your two-month supply of empty pizza boxes and start reading.
You'll remember I brushed the “Windows vs. Web” topic very rapidly as it applies to mobile development. And while I'm not here to reopen the debate or force you down one path, I'll nonetheless thread the “Windows” path over the next few pages to enlighten you on how to build rich-client mobile applications for Windows CE using the .NET Compact Framework. I promise I'll cover the “Web” path and the ASP.NET Mobile Controls in a future issue.
.NET Device Programming
With the release of Visual Studio .NET 2003 in April, .NET developers can now extend the .NET programming model to software development projects targeting smart devices. By smart device, we usually mean a mobile device of some sort with a relatively low encumbrance factor. This could potentially include notebooks and Tablet PCs, but for the sake of this column, I typically limit the term to the various devices running one inception or another of Windows CE.
The fusion of at least three radically different programming models in .NET was in itself an already amazing feat. No longer would programming practices be limited to a programming language. All .NET languages can now benefit from RAD (Rapid Application Development, both a blessing and a curse) using forms and the composition of graphical controls to design a GUI, which was brought to us by the Visual Basic world. All .NET languages can now use the power of subclassing to inherit and extend the functionality of a library of base classes (à la C++ or Java) thus maximizing the functionality of an application while minimizing code and low-level plumbing. All .NET languages can now be used to build Web-based applications by embedding server-side code inside dynamically generated HTML pages, thus fusing forever the paradigms of Web development and OOP.
Windows CE or Mobile Web? The .NET world can steer you in two very opposite directions: .NET Compact Framework or ASP.NET Mobile Controls.
Traditionally, mobile development would introduce yet another programming model specific to the language, the device, the operating system and the development environment. This meant that?with all the device types, OS generations and vendors out there?mobility developers would have to specialize on a single mobility platform or become jacks-of-all-trades on many of them. With .NET, device programming doesn't bring a new programming model, it reuses an existing one: the .NET model, which is the merger of all those models outlined above, taking root in the worlds of Visual Basic, C++, J++, ASP, and others.
You may not have to learn an entirely new programming model here, but you nevertheless have to learn how to think about a new platform. This isn't your cushy little Windows world anymore; you are entering Windows CE territory and your primary vehicle will be the .NET Compact Framework.
What Is the .NET Compact Framework?
Microsoft introduced the .NET Compact Framework to bring the “managed” world of .NET to Windows CE and smart devices. The .NET Compact Framework (.NETcf) is in fact the little cousin of the full-featured .NET Framework which has so radically changed the landscape of Windows and enterprise development over the past 18 months. This analogy actually works pretty well since your little cousin would merely be a smaller “being” very similar to you, not an incomplete version of you with missing parts. The same goes for the .NET Framework and .NETcf: the .NET Compact Framework isn't missing any vital organs found in the full .NET Framework, most of it is there; it is only smaller and less powerful.
So why is the .NET Compact Framework smaller? Why do we have to compromise? Well, for starters, the full .NET Framework 1.1 is well over 20 MB in size and most Windows CE devices only have a total of 32 or 64 MB of memory, roughly half of which is used for storage and the other half for program memory allocation. Even if the whole thing was put in ROM (which would require to more than double in size), there still wouldn't be enough RAM or CPU power to run anything. It'd be like running Windows XP and a .NET application on an old Pentium 75 MHz with 32 MB of RAM. The bottom line is very simple: the .NET Framework wasn't designed for such a resource-constrained environment and smart devices needed their own version of .NET.
This is exactly what we got: a scaled-down version of the .NET Framework designed specifically for smart devices and optimized for this limited environment. So what's in there you might wonder? The fact .NET was scaled down implies something was either cut or reduced in functionality, this is true, but instead of focusing on what didn't make the cut, let's start with what we do get in the .NET Compact Framework 1.0:
- A “compact” CLR (Common Language Runtime) which serves as the execution engine for your managed mobile applications.
- Support for the full Visual Basic .NET and C# languages.
- A library of base classes which is in fact a 25-30% subset of the full base class library from the .NET Framework 1.1.
- A Global Assembly Cache (GAC) that acts as a repository for your shared assemblies and the base class libraries.
- Error string files (one per language).
- Globalization data files (one per language/region package).
- All within a 2.5 MB deployment package.
Throughout this article I'll expand on most of these characteristics, but for now, let's answer the following question: How do you build applications to target the .NET Compact Framework? The answer lies in a new feature of Visual Studio .NET 2003: the Smart Device Extensions.
Smart Device Extensions
Contrary to the previous approach for mobile development in the Microsoft world where the Embedded Visual Tools 3.0 required a separate IDE outside of Visual Studio 6.0, the Smart Device Extensions (SDE) are integrated directly in the Visual Studio .NET 2003 IDE. This feature is available to the Professional Edition and above in Visual Studio .NET 2003 and unless you perform a full install, make sure you select the “Smart Device Programmability” under the Visual Basic .NET and Visual C# .NET languages during setup when choosing which options to install.
With .NET, device programming doesn't bring a new programming model, it reuses an existing one: the .NET model.
With this IDE integration comes a lot of power since you get to use existing Visual Studio components and apply them to mobility projects, such as the Solution Explorer, the Toolbox, the Server Explorer, the Class Viewer, all the documentation features, and many more. For example, the integration with the SDE enables IntelliSense to know which classes exist in the full .NET Framework 1.1 and which can be used legally in SDE projects, thus optimizing productivity regardless of the project type. IntelliSense isn't your only guide in terms of discovering what's in and what's out. The MSDN documentation that ships with Visual Studio .NET 2003 also covers the .NET Compact Framework by tagging supported class members throughout the thousands of online pages with the “Supported by the .NET Compact Framework” label. Hit F1 and search for any class in there and look for this label, indicating whether or not you can use that class or member in your SDE projects.
MSDN also allows you to filter its massive content by selecting the Filtered by option in the Contents pane and then choosing the .NET Compact Framework as the filter parameter. While this will narrow down the library considerably, it won't remove unsupported class members from supported classes. Ultimately, you'll soon realize that trying it first hand is the best way to go since there are a few class members that still won't work even if they are marked “Supported by the .NET Compact Framework.”
Getting Started with the Smart Device Extensions
Let's begin by creating a new SDE application. Make sure you have the latest Visual Studio .NET 2003 installed, Professional Edition or higher, and that you have selected support for mobile development under either Visual Basic .NET or Visual C# .NET during setup. While all the precepts presented here and in future issues apply to both Visual Basic .NET and Visual C# .NET, being the veteran VB guy that I am I'll stick to the former in all my samples.
Create a new project, select the Smart Device Application template under the Visual Basic .NET branch and name it MobileCoDeSDEApp. Once you accept these options, you are presented with another window and it is… you've guessed it… a wizard! More specifically the Smart Device Application Wizard. Don't gasp or expect too much though, this is merely a popup asking you to choose two options: the targeted platform, and the mobile project type you want to create.
Selecting Windows CE would mean targeting a generic Windows CE .NET 4.1 device, but since these devices are still fairly rare, we'll opt for Pocket PC support, which is probably what you are most familiar with if you own a Microsoft Pocket PC 2002 device such as an iPaq, a Dell Axim, a Toshiba e740, or some other compatible device. If you do not own a device, you needn't worry; the SDE features a choice of powerful smart device emulators for you to test with. In fact, choosing a target platform in this window configures your SDE project to use the proper emulator for when you eventually deploy and test your mobile application. Select Pocket PC as the platform for now. Future articles will focus on Windows CE .NET if you're interested in this next-generation Windows-Powered platform.
The second option you must select in this wizard is the project type. Just like in standard .NET Framework applications, SDE projects can be used to create many types of applications. There are naturally fewer options, especially since all server-side ASP.NET-based applications, including Web Forms and XML Web services projects, do not exist in the world of the .NET Compact Framework.
You can either create your whole project from scratch using the Empty Project template or you can create applications without any graphical user interface (GUI) using the Non-Graphical Application option. This latter option differs depending on the targeted platform. On the Pocket PC, it means the application is invisible and cannot display text or capture user input. This is because the notion of a console doesn't exist in that variant of the OS. If you target Windows CE.NET (feel free to try selecting it to see the difference), that option is replaced by a Console Application list item to select from. This should then be familiar territory for console application developers on the desktop. Don't be fooled, because the Console object does exist and work (i.e. no exceptions thrown) in the .NET Compact Framework, even in Pocket PC projects, but its ReadLine, Write and WriteLine members are useless in such a case.
All server-side ASP.NET-based applications, including Web Forms and XML Web services projects, do not exist in the world of the .NET Compact Framework.
The two options you are most likely to use are the Windows Application and Class Library project types. Provided you stick to the bounds of .NET Compact Framework classes, class libraries work in pretty much the same way as their desktop of server counterparts. These are in-process .NET assemblies (.dll) that run within the same application domain as the calling assembly (.exe), and their usage within a client application architecture follows the same rules you are already familiar with. Let's pick the Windows Application project type, which is a standard .NET assembly compiled as an IL (Intermediate Language) portable executable (.exe), since we want to design a Pocket PC application that sports a form-based GUI.
Once you accept these settings, Visual Studio .NET and the SDE proceed to creating a basic Pocket PC application project that is ready for device deployment. The SDE features a Windows Forms designer very similar to the one used in standard Windows Forms projects. You'll notice the form is automatically sized to the proper Pocket PC screen dimensions and even though you can resize the form, you should leave it as it is to ensure that your application interface covers the whole display area.
Before adding controls and code to our new mobile application, I want to make sure we cover the basics of the SDE and .NET Compact Framework features. Jumping in blindly can be fun at times, but understanding the development mechanisms and the underlying architecture of this mobile framework is too important to ignore. Don't forget: RAD stands for Rapid, not Reckless Application Development.
Working with the Emulator
Running and testing a .NET Compact Framework application is a bit different than it is for standard Windows projects. In fact, it's a bit like Web development: just like ASP.NET applications (i.e. Web Forms) need to be tested in their run-time environment?the Web browser?.NET Compact Framework applications need to be tested in their own run-time environment: a “smart” Windows Powered device, or an emulated version of one. I already mentioned the emulators included with the SDE. These are, in fact, a single emulator engine running Virtual PC technology from Connectix packaged with multiple OS images. Each image contains a full instance of the mobile OS and can run in Virtual PC emulation on top of an x86 processor. There are two default images you can use, one for each of the two platforms you can target with the SDE: Pocket PC 2002 and Windows CE.NET 4.1. With newer versions of mobile OS specs based on Windows CE.NET 4.2 on the way ? such as the new Windows Mobile 2003 (see the Mobility World News sidebar) and others?you can expect Microsoft to provide additional SDE support and emulator images in Visual Studio .NET updates in the coming year. And with Microsoft's acquisition of the Connectix Virtual PC technology earlier this year, you can also expect to see it creep into many other products in the near future.
To see the emulator in action, simply use the Connect to Device option from the Device toolbar. It is also available under the Tools menu in the Visual Studio .NET 2003 IDE. The SDE then launches the emulator and loads the default OS image for Pocket PC 2002 (see Figure 1). Feel free to click around using your mouse; you'll soon realize all the basic Pocket PC 2002 features are there, from Pocket Word to Solitaire. It's a good idea to leave the emulator loaded and connected while building and testing SDE applications. This way you'll save yourself the time it takes to launch the emulator every time you run your application. But for now, close the emulator since we'll look at configuration options.
You'll notice there are two options presented to you in the Shut Down dialog window that appears when you close the emulator: you can select Save Emulator state to preserve all the settings you have configured, applications you loaded and files you transferred (just like a real device which maintains a persisted state), or you can select Turn off emulator, in which case all your changes made in terms of device configuration and files copied are lost and the emulator reverts back to the default “vanilla” package.
The SDE features a Windows Forms designer very similar to the one used in standard Windows Forms projects.
Since not all Pocket PCs are identical, you might want to configure this device. Not all Pocket PCs feature the same amount of memory or support the same color depth. Fortunately, you can tweak a few options to make the emulator's behavior closer to the actual device you'll be deploying to in production. Select the Device Options button on the Device toolbar to access these configuration options (see Figure 2). You are presented with three tab pages of options. The first allows you to change the screen size and color depth. Since all Pocket PC 2000/2002 devices support a fixed 240x320 screen resolution, I advice against changing that. These settings are typically reserved for generic Windows CE projects where the screen resolution is variable from device to device (e.g. 240x320, 320x240, 640x240, 640x480, 800x600, etc.)
The second tab page presents you with two additional options. The first allows you to set the amount of memory in your emulated device. Real-world Pocket PC devices have both ROM and RAM. The ROM is typically “flashable” and contains the operating system itself whereas the RAM is used for both application memory and storage. You should experiment with the amount of memory you need for your mobile applications and make sure you test them using the amount of memory that corresponds to your least powerful device. The host key option allows you to configure which key you want to use to control menus in the emulator using the keyboard. The last tab page enables you to map a “virtual” device port to the physical ports available on your development workstation. Before making such changes, first make sure you haven't saved the state of your emulator. You need to turn off the emulator and lose all persistent state completely before making configuration changes related to hardware characteristics.
If you happen to own a Pocket PC 2000, Pocket PC 2002, or Windows CE .NET device, you can use it instead of the emulator to deploy and test your .NETcf applications. Simply make sure your device is connected to your development workstation via ActiveSync using either a USB or Wi-Fi connection and you're set! Deploying to the physical device will be as easy as it is with the emulator. Mobile deployment can be a pretty daunting topic and is beyond the scope of this article. The only things you need to know about deployment for now are the following:
- .NETcf requires either the Pocket PC 2000 or 2002 platform or the Windows CE .NET 4.1 and higher to run. Devices running a generic or custom Windows CE 3.0 OS other than Pocket PC are not and will not be supported by .NETcf.
- This also means there is no .NETcf support for Microsoft Smartphone 2002 yet since it is also based on the Windows CE 3.0 OS.
Now that you are familiar with the development environment and the virtual execution environment, it's time we moved on to the .NET Compact Framework and see what lies beneath.
.NET Compact Framework: The Architecture
The .NET Framework is what could be called a high-level platform in that it shields developers from the intricacies of the Win32 API and the low-level plumbing that would normally be required. The .NET Compact Framework works in the same way, isolating you from the nitty-gritty details of Windows CE development. It nonetheless remains important for developers to understand how that platform works and what kind of architecture lies underneath. Note that for the sake of discussion here, I assume you are already somewhat familiar with the basic architectural workings of the .NET Framework.
The base class libraries are a subset of the full .NET Framework 1.0, bringing you roughly between 25% to 30% of the classes and functionality.
The basic architecture of the .NET Compact Framework starts with the Execution Engine (EE), which is the core component that manages everything else in .NET. This is where you'll find the Common Language Runtime (CLR) designed for the .NET Compact Framework. This CLR works just like the CLR in the .NET Framework by consuming IL assemblies to produce native code for the target CPU. Since the Execution Engine is built in native code, there is one set of EE files for every CPU and Windows CE OS supported. The CLR is contained in the MSCOREE.dll and MSCOREE1_0.dll files, which also contains the Platform Adaptation Layer (PAL). This layer is akin to the Hardware Adaptation Layer (HAL) in Windows NT-based operating systems (Windows NT 4.0, 2000, XP, 2003) in that is serves as a “translation” tier between generic code and a hardware specific CPU. This PAL is what enables any .NET Compact Framework assembly to run on any compatible Windows CE device using any CPU, whereas classic Embedded Visual C++ applications would require a separate recompile for each OS and CPU. Other native code files outside of the EE include NETCFAGL.dll for the GWES (Graphics, Windowing, and Events Subsystem) interface, which is the graphical user interface between the user, application, and the operation system, and CGACUTIL.exe for the Global Assembly Cache (GAC) manager.
Indeed, there is a GAC in the .NET Compact Framework where you can deploy you own assemblies for shared reuse. It comes preloaded with a subset of the .NET base class libraries, which are CPU- and operating system-independent managed DLLs you can call from your applications through references to reduce the overall amount of code required. These class libraries follow the same hierarchical structure of namespaces as the ones found in the .NET Framework 1.0 and 1.1. I'll come back to .NETcf namespaces very soon.
I mentioned earlier that only Visual Basic .NET and Visual C# .NET were supported in the .NET Compact Framework. This is not entirely true. Since the CLR only runs IL code, this means any .NET language could potentially be used to create .NET Compact Framework assemblies. The limitation to these two languages actually rests on the SDE which only initially supports VB .NET and C# from Microsoft. Should another company decide to port their .NET language to .NETcf and create an SDE-style compiler that understands the limitations, the compact CLR would accommodate it just as well. I have not seen any official announcement yet as far as .NETcf third-party languages are concerned.
One interesting difference in the architecture lies in the way error messages are handled. Typically, when an error is raised, an error message accompanies it and the developer can choose to display it or display their own message to the end user. In the .NETcf, Microsoft extracted all the error messages for memory considerations and put them in separate error string files (SYSTEM.SR.dll). There is one such file per supported language and you can choose whether to deploy an error string file or not along with your mobile application.
.NET Framework: Compact/Desktop Commonalities
As stated earlier, the .NET Framework and the .NET Compact Framework share many commonalities, and many of these have to do with the .NET programming model. For instance, both benefit from a verifiable type safe execution of assembly code in a managed environment, thanks to CLR services. This means that?unlike Embedded Visual Basic 3.0?you cannot rely on uninitialized variables or unsafe casts. Nor can you have bad array indexing or bad pointer math, which could corrupt your application.
And while it may be compact, the “mobile” CLR is just as complete. The Garbage Collector (GC) eliminates the need for reference counting (à la COM), allocates and deallocates memory, and prevents memory leaks. The “Blue Screen of Death” may not exist in Windows CE, but memory corruptions can still occur and the .NETcf GC safeguards what happens in those tiny application domains. Just-in-Time (JIT) compilation is also inherited from the desktop cousin. .NETcf strictly runs IL code and nothing else, and with many more CPUs on mobile devices than on the desktop, this design feature brings many more benefits, such as portability of assemblies, facilitated deployment, and more.
Interestingly enough, the MainMenu control is automatically rendered in different locations based on the targeted OS.
Should something go haywire in your code, error handling in .NETcf also relies on structured exception handling; using the same constructs you have become familiar with in .NET. And of course, there's the Common Type System (CTS) which brings unity across data types and languages. You'll be pleased to hear that all the basic types (e.g. Boolean, integer, long, string, decimal, etc.) made it to the .NETcf, ensuring compatibility between desktop, server, and mobile code. As for complex types and other classes, it depends on their respective namespaces.
The object model is also the same, giving you full access to true OOP on mobile devices. This is a given since .NETcf supports the same IL assembler as .NET, which means you're using the same Visual Basic .NET and Visual C# .NET languages as .NET, and not some stripped-down variant. With this CLS (Common Language Specification) compliance comes many code mechanisms and development benefits such as object calling, cross-language inheritance, and source-level debugging across different languages.
The good news is ADO.NET is very well supported in .NETcf, including DataSets and DataViews, as well as other classes.
The bottom line is clear enough: There are so many features that are part of the common denominator here that it's probably easier to say that a .NET feature is supported in .NETcf unless stated otherwise. Which brings us to the question: What is different?
.NET Framework: Compact/Desktop Differences
You'll probably agree that we're already getting a lot as part of the .NET Compact Framework, especially if you've done mobile development with other toolkits or mobile platforms before. But it's time I told you what we lost along the way from Windows to Windows CE.
For starters, there is no ASP.NET in the .NET Compact Framework. This means you get none of the System.Web namespace aside from the client classes from System.Web.Services (calling XML Web Services from mobile clients is supported). When you think about it, it kinda makes sense since very rarely will you want to host a full Web server on a Windows CE-based smart device.
A big bummer is that we get no COM interoperability, which means the compact CLR doesn't include the COM marshaler from .NET that is able to translate inbound and outbound calls between .NET objects and COM objects. Windows CE does support COM and this limitation of .NETcf makes it difficult for your mobile code to “talk” to mobile COM libraries, such as the Pocket Outlook Object Model (POOM). COM Interop was omitted because of size and mobile resource considerations. It was important to keep the size of the mobile CLR down and COM Interop was simply too expensive. Your only way out of a .NETcf application domain is Platform Invoke (P/Invoke), which enables you to call Win32 DLLs in Windows CE, whether they are native or third party in nature. COM objects would then have to be “wrapped” using a native message-based DLL built with eVC++. This native wrapper would make all the COM interactions and your .NET application would talk to the wrapper through P/Invoke. Interoperability and COM Interop in .NETcf is too big a topic for the scope of this article, so I'll come back to it in a future issue. Also, note that there is no support in .NETcf for writing a COM object.
The base class libraries are a subset of the full .NET Framework 1.0, bringing you roughly between 25% to 30% of the classes and functionality. It is important to note that this difference in compatibility goes all the way down to the method level. The same class might exist in both .NET and .NETcf, but it doesn't mean the .NETcf version will have all the class members (properties, methods, or events) from the full version. Sometimes a class isn't implemented at all, and sometimes it's only partially implemented. Look up the documentation and IntelliSense to figure out what's in and what's out.
A .NETcf application will always load the exact version of a shared library that was referenced at compile-time.
Another huge drawback is the lack of a .NET Remoting infrastructure to perform remote calls to server-side objects over HTTP or TCP/IP using binary or SOAP formatters. This is again because of size considerations since the Remoting infrastructure is fairly heavy on system resources. Client Web services calls are fully supported, and while the XML/SOAP overhead can be pretty costly when it comes to remote invocation over a wireless WAN connection that surfs at 30-40 Kbps, it remains your only high-level alternative. For more control and efficiency, you could build your own proprietary Remoting infrastructure using Windows Sockets in the System.Net namespace.
If you're a fan of delegates (and you should be), note that while they work just fine in .NETcf, asynchronous delegates (i.e., BeginInvoke and EndInvoke methods) are not supported. This can be misleading since the documentation seems to indicate they work. Don't be fooled, they don't?even despite the presence of the two async methods in the Delegate class as reported by IntelliSense. Try as you might, even if you code it, the application will compile successfully but as soon as the CLR tries to enter the procedure containing the illegal code, a NotSupportedException will be thrown. Listing 1 shows such an excerpt of faulty code. All appearances lead to conclude this should work, but it doesn't and Microsoft confirmed async delegates are not supported in .NET Compact Framework 1.0.
Because of the nature of the file system in Windows CE that differs from Windows NT-based systems, the .NET Compact Framework sports a different IO model. The primary consequence here is that you cannot capture file change notifications since none are fired by the operating system itself.
Don't worry. We may be losing some things in the transition to the mobile world, but we are also gaining a few, such as the System.Net.IrDA namespace for programmatic access to the infrared port found in almost all Windows CE smart devices. This is a namespace that is exclusive to .NETcf and cannot be found in the full .NET Framework.
Additionally, here are some additional noteworthy features that are not supported or behave differently in the .NET Compact Framework:
- No generic serialization, although SOAP calls can be serialized and deserialized as in .NET when making XML Web service calls.
- No reflection emit (System.Reflection.Emit), which means you won't be able to compile code at run-time to create IL assemblies dynamically.
- No install-time JIT (nGen) where assemblies are pre-compiled from IL to native code before execution.
- You cannot load assemblies into a domain-neutral code area for use by multiple application domains.
- There is no support for multimodule assemblies, although .NETcf does support satellite assemblies.
- You get no late binding (i.e., As Object in VB .NET).
- And there are, of course, other important security differences and considerations, as well as different size and scalability characteristics that I will highlight throughout this article and in future articles.
The features noted in this section are by no means an exhaustive account of all the differences between the .NET Framework and .NETcf, but it gives you a fairly good idea to get started. Remember that experience counts just as much here as it does for desktop or server development, and with time, you'll figure out what you can and cannot do in mobility projects and learn how to effectively design applications with these considerations in mind.
Exploring Namespaces and Classes
What makes .NET so powerful and so productive takes root in the base class libraries. We can be thankful the .NET Compact Framework team managed to port so many namespaces to smart devices considering the whole thing is less than 3 Megabytes big. Let's review what's in and what's out:
- All the base data types are there; including their associated functions and methods for type conversion, display formatting, string manipulation, and array sorting.
- Threading and synchronization classes (System.Threading) also made it.
- Storage classes (System.IO) can be used.
- For those who need to build international applications, you'll be pleased to hear that System.Globalization and System.Resources are included in .NETcf.
- Many collections are supported (System.Collections), but not Queues, SortedLists, and other specialized collections.
- Reflection is supported to peruse through mobile assembly metadata (System.Reflection).
- Basic XML classes are supported, such as XmlDocument (for DOM parsing) and XmlTextReader/XmlTextWriter classes.
- Networking (System.Net) is included for Windows Sockets programming, Http clients, Http servers, and other communication schemes.
- Windows Forms is of course included, along with the designer classes for Visual Studio .NET.
- And last but not least, data access using ADO.NET is included and fully compatible with server-side objects, such as the DataSet for seamless exchange in a distributed scenario.
Even if those namespaces are supported, many are only partially implemented and have missing classes and members. There are also some namespaces that are missing altogether for various reasons.
Namespaces Lost, No Grief
We can easily identify two types of missing namespaces: those that didn't make sense on smart devices or for which there was no underlying Windows CE feature, and those that were omitted because of size, performance, or limited resource considerations. Here are some namespaces that we lost at no high cost in functionality:
- System.DirectoryServices isn't supported since Windows CE itself doesn't support Active Directory. If you need to query the AD, have a server-side component do it for you and then make a Web service call to that component.
- System.EnterpriseServices isn't there either since there are no COM+ component services in Windows CE; this is a server-side engine.
- System.Management was cut too because there are no WMI services on Windows CE… yet!
- System.ServiceProcess has no use either since Windows NT-style background services are not supported on Windows CE. You would have to create a non-graphical application or?as is the case for MSMQ CE?write a device driver using eVC++.
- System.Web and System.Web.Mobile don't exist in .NETcf because they are used to create server-side ASP.NET applications and the form factor is not suited for Web hosting. To use these Web applications from a Pocket PC or other smart device, simply use Pocket Internet Explorer; no programming required.
- System.Security.Principal isn't implemented in .NETcf because, designed as a single user environment, there is no need for role-based security on a smart device.
Mourning for Namespaces
There are, however, namespaces that didn't make it and these are costly omissions since they prevent us from leveraging key Windows CE or .NET features. These are the namespaces we'll sorely miss.
- System.Configuration, which means you can't use the standard .config files familiar to .NET developers. Your alternative is to either use (dare I say it?) the Windows CE Registry, or better yet, to implement your own custom configuration file schema and access method using file IO and/or XML. Check the sidebar on ActiveNick's Recommended Mobility Book; chapter 2 of that book shows you how to use supported XML classes to create a simple configuration settings class that is compatible with the .NET schema.
- System.Messaging, your doorway to Microsoft Message Queue Server (MSMQ), isn't supported either, which is a disappointment since MSMQ CE does exist on Windows CE, providing you with an excellent asynchronous reliable messaging infrastructure that is ideal for seldom-connected devices. Your alternative is to use P/Invoke to call MSMQ CE.
- As mentioned above, the .NETcf team pulled System.Runtime.Remoting out because of high costs in size and resources. Use either XML Web services calls or Windows Sockets.
- Some XML classes didn't make it, namely the classes related to XmlDataDocument for relational and hierarchical views of XML, XPath for queries over unstructured XML data, XSL and XSLT for transforming XML data to other forms, and XML schema validation to verify correctness of XML document. It is recommended to process and transform XML data on the server-side using these mechanisms in the full .NET Framework before returning it to the mobile client device.
- System.Runtime.Serialization.Formatters.Soap is also out, blocking the way to generic serialization. Mimicking this feature would require a custom serialization scheme. You would have to be careful to ensure compatibility with .NET serialization, so you'd be better to stick to passing application data, not object states that could corrupt your session if the deserialization scheme introduces an error.
Compact Windows Forms
Now that we've pretty much established what you can and cannot do with the .NET Compact Framework, let's explore a bit further the path that leads to mobile GUIs. The Windows Forms Designer included with the SDE allows you to easily create GUIs for smart devices by leveraging the System.Windows.Forms namespace. There are over 25 standard controls supported in .NETcf (see sidebar), and unlike .NET which uses new rewritten controls for its Windows Forms engine, the .NETcf Windows Forms code actually wraps itself around native Windows CE and other common controls. This is what enables .NETcf Forms to benefit from an adequate performance since rewritten controls would have severely hindered display speeds.
While eVB developers will certainly appreciate all the advanced controls available here, .NET developers will notice some favorites are missing, such as:
- DataRepeater
- CheckedListBox
- DateTimePicker
- MonthCalendar
- RichTextBox
- ToolTip
- All third-party controls designed for .NET necessarily don't work in .NETcf. Control library ISVs will have to migrate their controls to .NETcf should they wish to do so. Only ComponentOne (www.componentone.com) has so far committed to third-party controls for .NETcf. Their ComponentOne Studio™ for Mobile Devices?featuring grid, charting (see Figure 3), and zip compression components for the Microsoft .NET Compact Framework?is currently in final beta.
One of my all-time favorite components has to be the DataGrid. This advanced control is, in fact, supported in .NETcf, but in read-only mode alone. To edit the grid's contents, you would have to capture the tap input to identify the selected cell and provide a control for editing, such as a TextBox. While you would have to do all of this programmatically, you could easily reuse the functionality for future projects. You could also wait for ComponentOne's MobileFlexGrid control which sports more advanced features than the DataGrid.
Beyond controls, the .NETcf Windows Forms engine does support many of the .NET features such as overlapping and child windows, Z-order, focus, capture, and activation. Unfortunately, many form properties have been removed, such as AcceptButton, CancelButton, AutoScroll, Anchor, IsMdiContainer (no MDI support… sorry!), KeyPreview, TabIndex, and TabStop. You can also forget about the following events, which hardly make sense in a stylus-driven environment: DoubleClick, Activate, Deactivate, KeyPreview, KeyDown, and KeyUp. The Timer control also doesn't have any Start or Stop methods; you'll have to rely on the Enabled property instead.
.NETcf assemblies are “retargetable.” This feature allows a .NETcf assembly to run within the context of another Execution Engine that is known to be compatible if the specified version cannot be found.
If there is one control you'll use often because of screen size considerations, it's the MainMenu control. Interestingly enough, the MainMenu control is automatically rendered in different locations based on the targeted OS. In Windows CE .NET, the menu is displayed at the top, just like Windows XP and other desktop variants; but in Pocket PC, the menu is displayed at the bottom of the screen. When creating a new Windows Application project using the SDE, a MainMenu control is automatically added to your default form. Rename the control to mnuMain in your current project and add a File menu item (named mnuFile) and an Exit sub-menu item (named mnuFileExit). Aside from the displaced rendering at the bottom, the MainMenu control works just like the desktop version. Since tapping the “X” at the top-right of a Windows CE form merely “minimizes” the application instead of closing it, it's a good idea to add code in the Exit menu to enable users to quit without wasting precious mobile memory. Add the following exit code to the mnuFileExit Click event handler:
Private Sub mnuFileExit_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles mnuFileExit.Click
If MessageBox.Show("Do you want to exit?", _
"Exit", MessageBoxButtons.YesNo, _
MessageBoxIcon.Question, _
MessageBoxDefaultButton.Button1) _
= DialogResult.Yes Then
'It's important to provide a true exit
'option in your Windows CE apps since
'they would otherwise remain in memory,
'locking up valuable resources that are
'already limited in the mobile device
Me.Close()
End If
End Sub
We may have lost a few controls by moving from .NET to .NETcf, but we also gained a new exclusive control, found only in Pocket PC projects: the InputPanel control. This control consists of an on-screen keyboard-style panel that can pop open and shut at the bottom of the screen. It's automatically managed by the Pocket PC environment as far as input is concerned, even when entering text in your own controls, but you have to design your GUI around this control to make sure none of your controls are hidden when the InputPanel is open. Here's how:
Start by adding a few random controls to fill the form. Add a DataGrid (named MyGrid) that nearly fills the whole form, leaving only enough room near the bottom edge of your mobile form for a few controls. Figure 4 shows a sample layout using a Label, a TextBox and a Button (the names of the controls are the same as their Text property in the figure). These three controls run the risk of being hidden if the InputPanel opens, so you'll add code to rearrange the form's layout when this happens.
Next, add a new InputPanel control by dragging it on top of your form. It will be added to the design area at the bottom of the window where the MainMenu control is already located. Change its name to MyKeyboard and then double-click on it to add the code from Listing 2 to its **EnabledChanged **event handler.
Run the application. You will be asked if you want to deploy to the emulator or to an actual device. Choose to deploy to the emulator and wait a bit until the application fires. The first time you deploy to a fresh or reset emulator takes longer since the whole .NET Compact Framework has to be deployed as well. Once the form is displayed, try the InputPanel button on the menu bar at the bottom right to see how your form layout behaves. Figure 5 shows how the DataGrid is made smaller in height to accommodate the three controls that need to be moved higher because of the InputPanel. Always remember the InputPanel in your control layouts. Mobile GUI design is an art that needs to be mastered if you want your field users to feel comfortable with your application.
Mobile Data Access
Data access to and from mobile devices is a pretty big topic that will eventually warrant an article of its own. I nonetheless want to give you the basics. The good news is ADO.NET is very well supported in .NETcf, including DataSets, DataViews, and other much-loved classes. You can connect to two types of databases natively since .NETcf provides you with ADO.NET data providers for:
- SQL Server 2000 (System.Data.SqlClient)
- SQL Server 2000 for Windows CE, also known as SQL CE (System.Data.SqlServerCe)
The following list highlights the main differences in ADO.NET support in .NETcf:
- No connection pooling.
- No distributed transactions.
- No encrypted connections to SQL Server.
- Some classes are missing, such as the SqlClientPermission class and the SqlClientPermission attribute located in the System.Data.SqlClient namespace.
- Windows authentication requires the presence of the username and password data in the connection string since Windows NT security isn't fully supported in Windows CE.
- No System.Data.OleDb namespace.
As for data binding in Windows Forms, classes inheriting from the Control class support simple data property binding. On the other hand, classes that inherit from ListControl, (i.e. ListBox, ComboBox) can bind to objects that expose IList or IListSource (ArrayList). Another limitation is that you cannot use casting in data binding. As for our friend the DataGrid, while it does support data binding even though it is read-only, it can only bind to a single table unlike the desktop DataGrid that can bind to many tables. This means the DataSource property must be set to a DataTable object, and not a DataSet.
Versioning
Ever since Windows developers started using COM, versioning has become synonymous with nightmare. Fortunately, .NET solves most of the versioning issues, namely by getting rid of “DLL Hell.” This remains true in the .NET Compact Framework which does support explicit binding by default. The end result is that a .NETcf application will always load the exact version of a shared library that was referenced at compile-time. The Microsoft motto here is “Never break a functioning app!” (It's about time…)
The great news is that side-by-side execution at the Execution Engine level is also supported. This means your application will always run against the same execution engine and class libraries it was built with, and when a new version of .NETcf is introduced in the future, both versions 1.0 and the new one will be able to coexist in the same device without breaking existing applications, just like the .NET Framework's versions 1.0 and version 1.1 which can coexist in the same machine today.
I would like to add a last word of note on versioning. If you use the ILDASM utility to peek through the manifest of an assembly compiled with the SDE, you'll notice a new attribute: .NETcf assemblies are “retargetable.” This feature allows a .NETcf assembly to run within the context of another Execution Engine that is known to be compatible if the specified version cannot be found. Since the .NET Framework 1.0 or 1.1 is such a compatible EE, you can then launch .NETcf assemblies in Windows XP and they'll run just fine, provided you haven't references anything exclusive to .NETcf in your code (e.g. IrDA, InputPanel, etc.)
The Future
Other than the fact that Microsoft is working on the next release of .NET Compact Framework, not much is publicly known today. What is in the works, though, is .NET Compact Framework support for the next generation of Microsoft Smartphones (labeled v.Next). This Smartphone platform will be based on Windows CE .NET 4.2 and will support most Pocket PC features. The Windows Forms engine will feature controls specially adapted to have the Smartphone look & feel, and the Smartphone navigation model using buttons, the tiny joystick, keypad navigation and keypad events. The .NET Compact Framework will be pre-deployed in ROM and development will be done through an add-on to VS .NET 2003. This updated SDE will have Smartphone x86 emulation images and will feature an adapted Forms Designer experience, with the proper control set in the toolbox and appropriate properties on controls (including size, font, etc.)
'Til Next Time
Being such a vast topic, I could have gone on and on about the .NET Compact Framework. Fortunately for us, the commonalities between the .NET Framework and the compact version mean that many principles and techniques designed for one apply to the other. There are nevertheless areas where I wished I could have dug deeper, and I also had to omit other areas entirely since this is an article, not a book. Rest assured I plan to discuss the .NET Compact Framework again.
That doesn't mean you have to wait though. There are many great resources on this topic out there, and here a just a few of the main ones to help you in your Microsoft mobility journey.
- For .NET Compact Framework resources and other .NET mobility links, visit the Developer section of the Windows Powered Mobile Devices Web site at msdn.microsoft.com/vstudio/device and the Official Microsoft Smart Devices Developer Community Web site at smartdevices.microsoftdev.com.
- DEVBUZZ.COM (www.devbuzz.com) is a great site dedicated to development tools, programming techniques, and solutions for the Pocket PC. While it covers more than just the .NET Compact Framework, you'll find many great resources there.
- O'Reilly's ONDotnet.com also has some content on .NETcf. While this is a fairly new section, the O'Reilly Network remains a premier source of information for .NET developers (www.ondotnet.com/topics/dotnet/dotnetcf).
- Attend the fall event of Visual Studio Connections and ASP.NET Connections, October 12-15 2003, at the La Quinta Resort & Club in beautiful Palm Springs, CA (www.devconnections.com). You can join me in cool .NET mobility talks and other CoDe Magazine authors and speakers for great sessions on how .NET applies in the real world.
As usual, you can send feedback, questions, comments, and abuse to me via e-mail at mobilecode@activenick.net. If there are topics you'd like to see covered in future installments, feel free to communicate them to me. 'Til next time, enjoy this ongoing journey of excitement and great promises in .NET mobility development land!
Listing 1: Lack of support for async delegates in .NET Compact Framework
Private Delegate Sub MyDelegate(ByVal param As Boolean)
Private Sub mnuToolsAsyncDelegates_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles mnuToolsAsyncDelegates.Click
'This line declares & creates a delegate
Dim TestDelegate As MyDelegate = AddressOf MySub
Dim aResult As IAsyncResult
Try
'This *should* normally make the asynchronous call
aResult = TestDelegate.BeginInvoke(True, Nothing, Nothing)
Catch ex As System.NotSupportedException
'Although we can try to catch such exceptions, most
'often than none the CLR will throw it as soon as
'it enters the procedure
MessageBox.Show("Async delegates are not supported!")
Catch ex As Exception
MessageBox.Show("Something else went wrong.")
Finally
'While this code won't be run at all, it is nonetheless
'a good practice to call EndInvoke in *all* async calls,
'even when there are no results. This is a scenario
'where you can't trust the garbage collector to clean
'up everything for you... you better do it yourself
aResult.AsyncWaitHandle.WaitOne()
TestDelegate.EndInvoke(aResult)
End Try
End Sub
Private Sub MySub(ByVal p1 As Boolean)
'This line will never get executed
MessageBox.Show("Async Delegates Work!")
End Sub
Listing 2: How to handle the InputPanel.EnabledChanged event that fires whenever the InputPanel is shown or hidden.
Private Sub MyKeyboard_EnabledChanged(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles MyKeyboard.EnabledChanged
'If the InputPanel becomes visible...
If MyKeyboard.Enabled Then
'...we squeeze the DataGrid and move the other controls
'upwards using the InputPanel's height as a reference.
MyGrid.Height = MyGrid.Height - MyKeyboard.Bounds.Height
MyLabel.Top = MyLabel.Top - MyKeyboard.Bounds.Height
MyTextBox.Top = MyTextBox.Top - MyKeyboard.Bounds.Height
MyButton.Top = MyButton.Top - MyKeyboard.Bounds.Height
Else
'Otherwise, we restore the original control layout,
'which is the default.
MyGrid.Height = MyGrid.Height + MyKeyboard.Bounds.Height
MyLabel.Top = MyLabel.Top + MyKeyboard.Bounds.Height
MyTextBox.Top = MyTextBox.Top + MyKeyboard.Bounds.Height
MyButton.Top = MyButton.Top + MyKeyboard.Bounds.Height
End If
End Sub