Thursday, February 14, 2008

How to deploy the .Net Compact Framework and SQL Server Compact Edition

If we've developed a .Net Compact Framework application, we'll need to have the .Net CF installed on the device before the application is launched. It's the same case if we're using SQL Server Compact Edition, it should be installed on the device or our application will not able to open the database. So very obvious, but so very important. It's particularly important when we're designing a deployment strategy.

We already know how to create a .cab installer for the application, but we also know that there is no way to define dependencies in a cabinet file. We cannot say that OurApp.cab depends on the compact framework cab files and/or the SQLSCE cab installer.

And how can we do it?

During the development process, Visual Studio deploys both components to the device/emulator when needed, but this is not a feasible method when your app has been brought to production. We need to check manually if the .Net CF and SQLSCE are installed on the device and deploy them if needed. I suggest the following options to do this:

1) Using a desktop Installer

*If a desktop installer is an option* in your scenario, you can build an MSI which register the .cab installers, and using ActiveSync/WMDC checks if it's necessary to deploy and install each one. You can take a look at this very helpful article by Stan Adermann explaining how to create an MSI Package that detects and updates the .Net Compact Framework. Nice stuff.

2) Using a third party update library

You can use a library like the Q4Tech Mobile Updater Application Block which is an open source library which can be customized according with your scenario, or some similar one.
Update (04/29/2009): The Q4Tech Mobile Updater has been moved to the MobileContrib project at codeplex under MS-PL License.

3) Create a light-weight native installer

You can create a native application (i.e. using Visual C++) which will be installed on the device and should check whether the .Net CF is already installed, get the cab if needed, and launch it. Once the .Net CF is installed it can continue updating SQLSCE and the app assemblies. An alternative is just use this native installer to install a new managed installer application which can do the remaining work.
This option needs also a server-side component to publish the .cab installers to the native client. It can be in its minimal version just a web server publishing the .cab files.

You can choose the option which fits better on your scenario, and probably another good option for you can be to use third-party products or if you want, you can even include separate framework files on your .cab file, but it needs lot of work and it will carries on with security problems if you need to sign your application.

As you can see, deployment is not a trivial part of the mobile application development. The deployment strategy you design will have a big impact on the success of your project. I hope this post helps you achieving that success. Stay tuned!

Sunday, February 10, 2008

GZip compression/decompression support on .Net Compact Framework 3.5 out of the box!

Along several years doing mobile development the main thing I've learned is that a mobile device is a resource constrained device, and it will impact directly and inevitably into our software architecture. Part of the problem are the small storage space and the limited communication bandwidth, and trying to tackle both problems a very good option is the usage of compression tools, but moderately, we should keep in mind that compression and decompression are processes which require processor and can be very expensive in terms of resource management.

The .Net CF 3.5 is the first version that includes compression support out of the box! In the past we had to rely on third party libraries or, what is even worst, build our own compression library.

In this version, we can find the GZipStream class included in the System.IO.Compression namespace.

It's indeed a very nice and expected addition to the .Net Compact Framework. Now it's time to start using it!

Wednesday, February 6, 2008

Creating .testrunConfig files to run .Net Compact Framework Unit Tests on different platforms and devices

Currently we have the possibility to run .Net CF unit tests on the device (or emulator) and additionally, we can include unit test runs on our automated build processes. In the first case, it's very important to know how to define where the unit tests will run; and that is possible using test run configuration files (.testrunConfig).

By default, when you create a Smart Device Unit Test project, Visual studio includes a "[SolutionName].testrunConfig" file into the Solution Items folder, as follows:

image

It includes the default configuration according to your project platform. If you double click the .testrunConfig file, it will be open with the Test Run Configuration Editor, a very friendly tool which help us to edit a .testrunConfig file using a nice UI which looks like this:

image

We can also modify the file with the XML Editor if you right click on the file and select "Open with...". But let's see what we can do using this Test Run Configuration Editor.

Unfortunately, Code Coverage is not supported for Smart device projects, but you can play around with the other options, and particularly in this post, I want to focus on the Hosts group.

image

Here we can define on what platform we want to our unit tests run:

image 

Or even better, we can define the device where the unit tests will run:

image

Very cool stuff! Does It mean that we can change the settings targeting a different platform whenever we need to run the tests on it? Yes, but we can have more than one .testrunConfig files, which means we can have different configurations on each file.

We can change the settings as follows and press the Save As... button

image

And save the file as SmartphoneWM5.testrunConfig

image Now we have two .testrunConfig files in the solution, and we can add a third one right clicking the solution and selecting Add - New Item... and selecting Test Run Configuration in Categories:

image

And entering and applying the settings on the Test Run Configuration Editor. Now we have three .testrunConfig files on the solution. How we select the current Test Run Configuration file?. Just go to Test menu and select it!

image

Or if you're using MSTest.exe to run the tests from the command line or an automated build, you can select the .testrunConfig file using the /runconfig parameter as I did in this post.

<Exec Command="MSTest /testcontainer:bin\debug\testproject1.dll /runconfig:..\SmartDeviceTestRun.testrunconfig" />


Nice! Now you can create several configuration files and run your tests on different platforms and devices. Enjoy!

Saturday, February 2, 2008

How to create a windows mobile (Smart Device) .Cab installer

This time I'm going back to a basic topic: How to create a windows mobile installer for our mobile (Pocket PC / Smartphone)application. I've already blogged before about how to build a .cab which registers the assemblies on the .Net CF GAC. But this time I'm focusing on the .cab installer itself.

A Cab file is the default setup format for Windows CE and Windows Mobile devices (similar to windows .msi files). You probably already have installed several application using .cab files, and are familiar with the concept. One point which is often unknown is that .cab files are processed by wceloader.exe, and it can only install one .cab file at a time. That means we cannot have nested .cab files. It doesn't mean we cannot have .cab files contained by another .cab, but the contained .cab files will not be installed during the installation of the container .cab. We should install it manually after the container .cab file installation has been completed.

There are two ways to create a cabinet (.Cab) file. The traditional one, and the friendly VS Smart Device Cab project which doesn't require additional coding, but which also relies on the traditional one at low-level.

Traditionally, the process to create a .cab file was tedious and totally unfriendly. There is a command line tool called CAB Wizard (cabwiz.exe) which still being used to create cabinet (.cab) files. If you follow this link, you can take a look at the documentation for this tool. What the .cab does, is defined on a rather cryptic and confused information (.inf) file which is *kind of* installation script.

The easiest way to build a .cab file is using Visual Studio. It allows us to create Smart Device CAB Projects, including internal project outputs, external files, resource files, required registry entries, shortcuts and more, resulting in a cabinet file after build. Let's see an example:

Walkthrough: How to create a Smart Device CAB Project

Assume we have the following solution:

image

and we want to include a project to create the cab installer for our application, which should:
1) Copy DeviceCoolApp.exe, the referenced assembly MyDeviceLibrary.dll and the resource file called SampleKindOfResourceFile.xml to the application folder.
2) Additionally, it should create a shortcut in the Programs folder on the device and
3) Set the string value HKLM\Software\Mobile Practices\DeviceCoolApp\Version to "1.0".

First of all, we need to add a new Smart Device CAB Project to the solution: Right click on the solution, Add - New Project...

image

Call it DeviceCoolAppInstaller and press OK. The new project will appear at the bottom in the Solution Explorer window.

Now, I recommend we change the project properties to get a *nice* product installation. Set the Manufacturer (Mobile Practices) and Product Name (DeviceCoolApp) as follows:

image

It's time to add DeviceCoolApp.exe (the DeviceCoolApp project output) to the CAB Project. Right click on DeviceCoolAppInstaller - Add - Project Output...

image

Select DeviceCoolApp on the Project selector, and Primary Output as follows, and press OK.

image

Visual Studio will detect automatically the DeviceCoolApp dependencies. In this case it will detect MyLibrary.dll

image 

**If the dependencies are not detected, you can rebuild the solution and then Right Click on Detected Dependencies - Refresh Dependencies.

As you can see, due to the automatic dependencies detection, we don't need to add MyDeviceLibrary as Project Output on DeviceCoolAppInstaller.

Now it's time to add the resource file SampleKindOfResourceFile.xml which should be installed on the Installation folder. Let's use the File System Editor, having the DeviceCoolAppInstaller project selected press the File System Editor button (btw, it's probably already open).

image

Now, right click on Application Folder - Add - File....

image

Browse and find SampleKindOfResourceFile.xml and press OK.

image

Congrats!, now we have all the necessary files ready to be installed. The next step is to add the shortcut.

Unfortunately, the Programs Folder is not already included on the File System Editor, and we need to include it manually: Right click on File System on Target Machine - Add Special Folder - Programs Folder.

image

And now, select Programs Folder on the File System tree, and right click on the empty panel at right and select Create New Shortcut

image

And select Application Folder - Primary output from DeviceCoolApp (Active) and press OK.

image

And rename it to "Device Cool App"

image

This will be the application shortcut on the Programs group on the smart device after installation. Now we just have to add the registry entry. Press the Registry Editor button:

image

And add the string value "HKLM\Software\Mobile Practices\DeviceCoolApp\Version". You need to create the path key by key, and the add the string value on the right panel.

image

Name it "Version" and then, select it, and enter "1.0" into the Value field on the Properties Window

image

And *voila* the Smart Device CAB Project is done! We're ready to build the solution, right click on the DeviceCoolAppInstaller project and select Build.

You can find the DeviceCoolAppInstaller.cab file in the DeviceCoolAppInstaller\debug folder.

image

We are ready to ship our application and distributing it. If you want to test it (highly recommendable), you can copy it to the emulator (or share de folder to make it visible from the emulator as a Storage Card) or to the device and install it. You can also uninstall it thru the Remove Programs option.

As you can see, in the same folder, there is also a DeviceCoolAppInstaller.inf file. This file is generated by Visual Studio and passed to CabWiz.exe to generate the .cab file. As I've said before, Visual Studio still using the traditional way to build a cabinet file at low-level. But it DOESN'T mean that Visual Studio Smart Device CAB projects are just a graphical front-end for the cabwiz.exe tool. The main advantage of using a Smart device cab project is that it also integrates our development, it automatically updates the .inf file according with the changes we make to our projects, it includes renaming of output files (DeviceCoolApp.exe is not physically linked, if we change the assembly name setting in our project to DeviceCool.exe, we don't need to modify the DeviceCoolInstaller project) and dependencies which are automatically detected.

Well, work is done. Now you can start creating your own smart device cab projects and please don't forget to read my previous post about how to build a .cab which registers the assemblies on the .Net CF GAC which can be also very useful. Stay tuned!

Update (10/28/2008): You can also read a Setup.dll walkthrough for adding a Terms & Conditions dialog before the installation for further info about how to customize a cab installer.

Thursday, January 31, 2008

Automated Builds running .Net CF Unit Tests!

Having the capability of run unit testing for the .Net Compact Framework within Visual Studio 2008 is a very nice feature, but it goes beyond than just launch test runs from the IDE. If we have an automated build process or even a build server, we can include the .Net CF unit tests as part of the automated process. This is a great feature for practices like continuous integration or just for automated build processes.

But it's not completely painless. Probably you cannot even build the test project using MSBuild in your first try. I'm including in this post a sample solution, obviously a VS 2008 solution, which does can be built using MSBuild. It also run all the tests first on Windows Mobile 6 Classic Emulator and then on Windows Mobile 5 Pocket PC Emulator. Pretty sweet! But here goes the question:

How to make the project build and run the tests using MSBuild?

The first problem I found trying to build the test project is a missing reference. Actually, it's a missing search path on the project, because it's prepared for run from Visual Studio and not using MSBuild. To fix this, we just need to add a new search path in the project when it's not building inside Visual Studio:

1) Edit the test project file (i.e. TestProject1.csproj):
    - Unload the project (Right click - Unload Project)
    - Edit TestProject1.csproj

2) Add the following PropertyGroup:

<PropertyGroup Condition="'$(BuildingInsideVisualStudio)'!='true' ">
<DeviceTestAssemblySearchPath>$(DevEnvDir)\\PublicAssemblies</DeviceTestAssemblySearchPath>
</PropertyGroup>

3) Now the project can be built from the command line! But we need to launch "MSTest" after build in order to run the tests as part of the *automated* testproject1 build process:

<Target Name="AfterBuild" Condition="'$(BuildingInsideVisualStudio)'!='true' ">
<Exec Command="MSTest /testcontainer:bin\debug\testproject1.dll /runconfig:..\SmartDeviceTestRun.testrunconfig" />
</Target>

4) We can save the changes and reload the project (Right click - Reload Project)

It's done! Now you can build TestProject1.csproj using the default target and it will run the tests on the emulator as part of the build process.

Additionally, in the provided sample, I've removed the test list file (.vsmdi) and added a new .testrunConfig file which will be launched on Windows Mobile 5 Pocket PC (the first one will be launched on WM6 Classic Emulator, and I renamed it to clarify), and added a second <Exec> MSTest on AfterBuild target pointing this configuration file. Doing this, the automated build process will run the tests on BOTH platforms.

I'll post soon about how to create those testrun configuration files to setup different target platform for each test run in detail and what other ways we have to use them. But now, if you have Visual Studio 2008, and the WM6 Professional SDK installed on your machine, you can download the sample solution, try and open a "Microsoft Visual Studio 2008 Command Prompt" on the solution folder and just type MSBuild...

This is what I got:


Here's the sourcecode:


It seems we finally have automated test runs on the device as part of the build process... Sweet!!

Thursday, January 17, 2008

Unit Testing for .Net Compact Framework is now friendly enough!

When I joined to Microsoft Patterns & Practices Mobile Client Software Factory team a couple of years ago, I discovered test-driven development as a reality, but the first big issue we had to face then, was the lack of unit testing support for the .Net Compact Framework.

Having so many testing frameworks for the full framework, the .Net CF was nobody's land regarding unit testing. Not even Visual Studio 2005, which includes on its Team Suite edition a nicely integrated Unit Testing framework provides support for .Net CF Unit Testing. There was only one option: build our own Unit Testing framework (or at least our test runner), and that was what we called the p&p Compact Framework Test Runner, which is part of the Mobile Client Software Factory.

It was just enough effort to make things work. There was a big wish list for cool features that never were done like IDE integration. I want to mention also another old project with the same mission, the CFNUnitBridge by Trey.

Now Visual Studio 2008 (formerly Orcas) has arrived, and it includes support for .Net CF Unit Testing which very nice IDE-integration, with the same approach of the full framework unit testing. Such a good news!

Wanna try it?

Let's do a remake of a very interesting Daniel Moth's post from a couple of years ago:

1) Let's create a new Smart Device Class Library for .Net CF 3.5 on Visual Studio 2008

2) Add a new class to the project with the following content:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;

namespace AppForTest
{
public class Class1
{
public Int32 GetBuildVersionPart()
{
return System.Environment.Version.Build;
}

}
}

3) Right Click on the method and choose "Create Unit Tests..."
image


And select only the GetBuildVersionPart() method
image


Enter the Test Project name
image


It will create a new test project, unit testing class and the following unit test method:

/// <summary>
///
A test for GetBuildVersionPart
///</summary>
[TestMethod()]
public void GetBuildVersionPartTest()
{
Class1 target = new Class1(); // TODO: Initialize to an appropriate value
int expected = 0; // TODO: Initialize to an appropriate value
int actual;
actual = target.GetBuildVersionPart();
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}

4) Replace expected = 0 with expected = 50727 which is the build number for the full framework 3.5, and comment out the Assert.Inconclusive line (or delete it).


5) Run the GetBuildVersionPartTest from the Test View window:


image


It will build the projects, launch the emulator and run the tests on the emulator. After some seconds, the result will be:


image


This time the test has failed, the expected value was 50727, the build number for the full framework, but the actual value was 7283, the build number for the compact framework.


This time the Unit Test has run on the emulator! It really was a .Net CF Unit Test :)

Friday, January 11, 2008

Making Multiline MeasureString work with different font sizes

Today I got an email asking for help using my suggested Multiline MeasureString implementation when the control has a different font size.

Well, in the provided sample code I'm using the default font size on all the controls. To get a simpler code, I'm using always the form graphics as parameter for MeasureString:

textboxHeight = CFMeasureString.MeasureString(CreateGraphics(), newText,textboxRect, true).Height;

CreateGraphics() as shown gets the Graphics object for the form. MeasureString will calculate the height based on the selected font on that Graphics.


Let's work now with the adaptative UI sample. What if we change the font size in one of the controls?


image image


Let's see what happen if we change it to 15:


image


The application will not work properly anymore, because the font of the label is not the same font of the provided Graphics:


image


Apparently, the solution could be to get the graphics from the control instead of still using the form graphics. We can create an overload for CreateGraphics like this:

private Graphics CreateGraphics(Control control)
{
return Graphics.FromHdc(control.Handle);
}

But it doesn't work because the Graphics won't have any font selected. .Net CF releases fonts after using them when i.e. you call DrawString (thanks god!)... that's the reason for having the same measure based on the default font size in spite of what graphics we are using.


The real solution


Obviously, the problem has a solution. We can create a new overload for MeasureString, which receives the control as one of its parameters and: 1)creates the right graphics object 2)select the control's font in the graphics and 3)releases it after the string has been measured.


To get all this working, we'll add two imports into our CFMeasureString class: GetDC and SelectObject.


Please include the following code as part of the CFMeasureString class:

[DllImport("coredll.dll")]
static extern IntPtr GetDC(IntPtr hWnd);

[DllImport("coredll.dll")]
static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

/// <summary>
///
Measure a multiline string for a Control
/// </summary>
/// <param name="control">
control</param>
/// <param name="text">
string to measure</param>
/// <param name="rect">
Original rect. The width will be taken as fixed.</param>
/// <returns>
A Size object with the measure of the string according with the params</returns>
static public Size MeasureString(Control control, string text, Rectangle rect)
{
Size result = Size.Empty;
IntPtr controlFont = control.Font.ToHfont();
IntPtr hDC = GetDC(control.Handle);
using (Graphics gr = Graphics.FromHdc(hDC))
{
IntPtr originalObject = SelectObject(hDC, controlFont);
result = MeasureString(gr, text, rect, control is TextBox);
SelectObject(hDC, originalObject); //Release resources
}
return result;
}

In our sample application, we can replace the MeasureString calls in Form1.cs with the following:

labelHeight = CFMeasureString.MeasureString(label1, label1.Text, labelRect).Height;
textboxHeight = CFMeasureString.MeasureString(textBox1, newText, textboxRect).Height;
instructionsLabel.Height = CFMeasureString.MeasureString(instructionsLabel,instructionsLabel.Text, instructionsLabel.ClientRectangle).Height;

Now, even if we additionally change the textbox font size to 20, the application still working!


image


Thanks Sven for the feedback, I hope it helps!