Building Applications with .NET Compact Framework
In this article, author explains various components of Microsoft .NET Compact Framework and how to build compact device applications using .NET Compact Framework.
With an ever increasing usage of Mobile Devices, supporting them has become the need of any present generation business applications. Microsoft .Net Compact Framework provides a framework to develop client applications for smart devices i.e. Pocket PC 2000 etc. Just like any other development environment from Microsoft, .Net Compact Framework is also powered by ease of usability. It simplifies the development and deployment of applications for smart devices. .Net Compact Framework, essentially a subset of .Net Framework, brings the concept of managed code to smart devices, which provides core services like Memory Management, Security etc. Just like .Net Framework, .Net Compact Framework is also an abstraction of underlying operating system features, thereby enabling the usage of those features via standard APIs. Apart from this developers can extend the same to write code for accessing any special feature of the Operating System if the same is not accessible via standard APIs.
.Net Framework developers can easily develop applications for smart devices without much training, thereby reducing the Training and Development cost.
This article aims to introduce basic features of .Net Compact Framework and then discusses Interoperability feature in .Net Compact Framework. It also lists some best practices to be followed for developing applications using .Net Compact Framework.
As stated above, .Net Compact Framework is essentially a subset of .Net Compact Framework which eases development and deployment of applications for smart devices. Primarily it has two components i.e. Common Language Runtime and .Net Compact Framework Class Library.
Following diagram explains .Net Compact Framework architecture.
Figure 1.1: Architecture of Compact Framework
All compact framework applications runs inside application domain (very similar to an Operating System Process), which offers fault isolation, security to the application.
Application Domain host creates an instance of CLR for running a managed code.
. Net Compact Framework doesn't control the behavior of Application Domain Host.
.Net Compact Framework supports multiple application domains. Each application domain loads its own Common Language Runtime.
CLR (Common Language Runtime) manages the managed code i.e. code that targets .Net Compact Framework. Apart from managing the execution of managed code, it also provides functionalities like Memory Management, Thread Management, and Security etc.
Some key features of CLR
- It employs CTS (Common Type System) to enable cross language support.
- Uses JIT (Just In Time) Compiler to provide better performance.
- Uses Garbage Collector for Memory Management.
- Encapsulates Operating System features and exposes them as APIs, thereby making is simple to access OS level features.
- It's Extensible, so that developers can write their own APIs to access Operating System features.
.Net Compact Framework Class Library is a set of APIs provided for building applications.
Some Key Class Libraries are
- Windows Form: For developing windows client application
- Base Classes: Enables advance features i.e. Threading, Network resources etc
- GDI: Basic support for GDI for building graphics.
- Data and XML: Enables easy handling of Data and XML content.
- Web Service: To enable development of web service clients.
Features not supported in .Net Compact Framework
Being a subset of .Net Framework, not all features are supported by .Net Compact Framework. Following are some key features that are missing in compact framework.
- ASP .Net: Primarily being a rich client platform, it doesn't provide any ASP .Net support.
- Assemblies and GAC: There is no support for multimodule assemblies.
- COM Interoperability: Even though interoperability with COM objects is not supported, there are other ways of accessing a COM object. Platform Invoke method can be used to call native DLLs which in turn can access COM DLLs.
- Asynchronous Delegates: Not supported.
- Reflection: No support for System.Reflection.Emit namespace.
- XML Web Services: Developers cannot host web services under .Net Compact Framework.
- Remoting: Cannot develop Remoting applications.
- Printing: No support for printing functionalities.
- GDI+: Advance GDI support is missing in Compact Framework.
- XML: XML Schema validations and XPath are not supported.
In order to access unmanaged code in native DLLs, .Net Compact Framework supports Platform Invoke.
To declare the function in Native DLL, we use [DllImport] attribute in C# as shown below
Note: GetDiskFreeSpaceEx function retrieves information about the amount of space available on a disk volume: the total amount of space, the total amount of free space, and the total amount of free space available to the user associated with the calling thread. [Reference 3]
Here SetLastError property is set to true (Default value is false), so that CLR will call GetLastError method to cache the error value and other functions won't be able to override the value.
We can also hide the name of the function by using EntryPoint attribute as shown below.
.NET Compact Framework does not support full COM Interop, so to access COM Dll from the .NET Compact Framework; we need to write a wrapper to handle the calls to the COM Dll and the type marshaling.
Following method ReturnLargestNumber is available in an embedded Visual C++ Dll (MarshallingExample.dll) as shown below.
The function is prefixed with _declspec (dllexport) so that it can be called from outside the Dll. Another keyword extern "C" is used to force the compiler to avoid mangling of function name. This is to ensure that the name of the exported function remains to be ReturnLargestNumber.
We can access the same in our managed code as shown below
- In .Net Compact Framework Version 1, max of 12 parameters can be passed as argument to a native function.
- Callbacks are not supported by P/Invoke on the .NET Compact Framework. However we can pass parameter to the unmanaged code by value or reference.
- .Net Compact Framework supports marshalling for blittable type. Blittable types are those, which has a similar representation in memory in managed and unmanaged code. .Net Compact Framework supports automatic marshalling for value type variable less than 32 bits. Similarly it supports return values of value type variable less than 32 bits. Others i.e. 64 bit integers etc need to be passed by reference. It is possible to pass a variable by reference from managed code to unmanaged code. In this case, unmanaged code will receive a pointer to the managed heap where the reference type variable is located.
- In .Net Framework, we can set the default character set to control the marshaling behavior by using various property of DllImport attribute as shown below.
[DllImport ("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,
public static extern bool MoveFile (String src, String dst);
Here we can set CharSet property to Unicode, Auto or Ansi where as in .Net Compact Framework only Unicode setting is allowed. .Net Compact Framework doesn't support any other properties of DllImport attribute.
- .Net Framework supports three different calling conventions using CallingConvention property i.e. Cdecl, StdCall and ThisCall whereas .Net Compact Framework supports only Winapi (default calling convention for the platform) value for CallingConvention i.e. Cdecl for Windows CE.Net platform.
- MarshalAS attribute supported by .Net Framework is not available in .Net Compact Framework. So type conversion need to be ensured in the managed code itself.
- In .Net Framework, we use Handle (public property that gets the window handle that the control is bound to) property of Form class to pass the handle to a window to a function. Also for custom processing of messages sent by the OS, we can override DefWndProc (Protected method, overridden method of Control.DefWndProc Sends the specified message to the default window procedure) method. Form class in .Net Compact Framework doesn't support above properties or methods. However it supports MessageWindow and Message classes. We can inherit MessageWindow class and override its WndProc (Protected method, Processes Windows messages) method to catch specific messages. Also SendMessage and PostMessage methods of MessageWindow class can be used to send messages to other windows.
- Exceptions thrown by .Net Compact Framework are different from those thrown by .Net Framework. EntryPointNotFound and ExecutionEngineException are thrown by .Net Framework if the function cannot be located or the function is declared improperly, where as incase of .Net Compact Framework NotSupportedException and MissingMethodException are thrown.
NotSupportedException: Many of the features supported by P/Invoke in .Net Framework is not supported in .Net Compact Framework. NotSupportedException is thrown when the declaration is incorrect or the restrictions imposed by .Net Compact Framework are violated.
MissingMethodException: This exception is thrown mainly because of following reasons.
- Function Name is incorrect.
- Parameter passed to the functions are correct
- Marshalling issues on non blittable type
- The DLL being called using P/Invoke is not dependent on other DLLs (which might be missing)
Usability: Size of device being a key constraint, usability becomes a key factor to be considered while developing applications for smart devices
- Keep the UI simple and easy going.
- Avoid multiple data entries
- Avoid new forms, try using tab controls
- Use Hardware functions
- Keep the functionality simple i.e. avoid complex functionality
- Use Disconnected Dataset
- Reduce Data joins
- Use Multi Threading
- Create threads for long jobs
- User Asynchronous Calls
- Mostly making a call to unmanaged code will be costly from performance point of view
- Use ADO.NET datasets
- Sometime it's better to de-normalize the tables to ensure faster data access
- Multiple SQLCE connections not possible
- Avoid Desktop ActiveSync
- Use CABs.
- Deploy .NETcf core and SQLCE as separate CABs