Monday, June 02, 2008

My Mobiler

I recently wrote a blog regarding the ActiveSync_Remote_Display (ARD) tool here that comes with Windows Mobile Power Toys.

Fellow MVP Peter Nowak told me about My Mobiler after reading my ARD blog post above. My Mobiler is a tool very similar to the ARD tool but better and best of all it's free.

There are a few things with My Mobiler that make remotely controlling your device from your desktop easier and more feature rich than ARD. Some of these features are as follows:

  1. Auto reconnect to your device after being previously connected via ActiveSync without having to close the application and reload it as you have to do in ARD.
  2. Automatic deployment of the device host (remote.exe) when you run the client tool on your desktop. This used to work with ARD in pre WM5.
  3. Support for landscape mode.
  4. Support for recording a video (very cool feature).
  5. Support for saving image to file or clipboard.
  6. System tray icon for quick access
Some screen shots are as follows:



Rotating the screen.



Result of copying the screen to the clipboard (contents of clipboard).


You can record video to an AVI which is quite neat for things like demoing etc. I've provided an example below of this.


Screen in landscape mode after invoking this from the tool.


Example of a recorded video using the record feature in the tool.

My ActiveSync_Remote_Display is now shelved :)

Sunday, June 01, 2008

HTC Touch Diamond

Another new cool device recently released from HTC named the Touch Diamond: http://www.htc.com/www/product.aspx?id=46278

Plenty of contracts available for this device here in the UK over at: http://www.expansys.com





















As you can see it looks quite impressive. If you go to the HTC home page, you can download a really cool video for this device: http://www.htc.com/www/default.aspx


Specification is as follows:

Processor Qualcomm® MSM7201A™ 528 MHz
Operating System Windows Mobile® 6.1 Professional
Memory ROM: 256 MB
RAM: 192 MB DDR SDRAM
Internal storage: 4 GB
Dimensions 102 mm (L) X 51 mm (W) X 11.35 mm (T)
Weight 110 g (with battery)
Display 2.8-inch TFT-LCD flat touch-sensitive screen with VGA resolution
Network HSDPA/WCDMA:
  • Europe/Asia: 900/2100 MHz
  • Up to 384 kbps up-link and 7.2 Mbps down-link speeds
Tri-band GSM/GPRS/EDGE:
  • Europe/Asia: 900/1800/1900 MHz

(Band frequency and data speed are operator dependent.)

Device Control TouchFLO™ 3D
Touch-sensitive navigation control
GPS GPS and A-GPS ready
Connectivity Bluetooth® 2.0 with EDR
Wi-Fi®: IEEE 802.11 b/g
HTC ExtUSB™ (11-pin mini-USB 2.0 and audio jack in one)
Camera Main camera: 3.2 megapixel color camera with auto focus
Second camera: VGA CMOS color camera
Audio Built-in microphone, speaker and FM radio with RDS
Ring tone supported formats:
  • MP3, AAC, AAC+, WMA, WAV, and AMR-NB
  • 40 polyphonic and Standard MIDI format 0 and 1 (SMF)/SP MIDI
Battery Rechargeable Lithium-ion or Lithium-ion polymer battery
Capacity: 900 mAh
Talk time:
  • Up to 270 minutes for WCDMA
  • Up to 330 minutes for GSM
Standby time:
  • Up to 396 hours for WCDMA
  • Up to 285 hours for GSM
Video call time: Up to 145 minutes for WCDMA
(The above are subject to network and phone usage.)
AC Adapter Voltage range/frequency: 100 ~ 240V AC, 50/60 Hz
DC output: 5V and 1A

I will be putting my order in soon!!...

Saturday, May 31, 2008

ActiveSync_Remote_Display

You might have noticed in my previous post that I used the ActiveSync remote display tool. This is quite a powerful in many senarios including pre-sales demoing, debugging, presenting etc. This particular tool is part of the Windows Mobile Power Toys toolkit.

Although this toolkit just worked pre WM5, it doesn't work on WM5 and later out of the box.

There is a relatively easy workaround in order to get the ActiveSync remote display tool to work on WM5 and WM6.0, WM6.1. You need to simpy copy the files: cerdisp2.exe and KillProc.exe from (similar) C:\Program Files (x86)\Windows Mobile Developer Power Toys\ActiveSync_Remote_Display\devices\wce400\armv4 to \Windows of your device.

Then simply run client application: C:\Program Files (x86)\Windows Mobile Developer Power Toys\ActiveSync_Remote_Display\ASRDisp.exe

I have used this workaround on all devices mentioned, WM5, Wm6.0 and WM 6.1 without issues.

Memory management on Windows Mobile <= 6.1

Recently in the communities a question was asked: "Why should I bother finalizing my objects, shouldn't I let the GC do it for me?". It's true we have the wonderful Garbage Collector (GC) in managed code and luckily it is supported on the Compact Framework. Here's a statement: *never* rely on the GC, in fact don't call it, ever. OK, there may be some scenarios you might want to call it in extreme cases, but for the most part, please don't, think of your users ;) instead write better code!
This article is was written to show an example of how Windows Mobile 6.1 and earlier handles memory management and the various events you can hook into to develop more robust applications.

I'm running the following code on a HTC P3300 with 64meg RAM not much by todays standards but the device is 18 months old now so in mobility terms ready for the scrap heap. I happen to have just 22meg free after running this application:




You'll see from the screenshot above I have written out the physical free memory available to applications on my device. Although there is no managed function to achieve this even in CF 3.5, it can be done by P/Invoking function GlobalMemoryStatus. The code to do this is fairly simple ie:
public struct MemoryStatus
{
internal uint dwLength;
public int MemoryLoad;
public int TotalPhysical;
public int AvailablePhysical;
public int TotalPageFile;
public int AvailablePageFile;
public int TotalVirtual;
public int AvailableVirtual;
}

//Declaration.
[DllImport("coredll", SetLastError = false)]
internal static extern void GlobalMemoryStatus(out MemoryStatus status);

This app has been developed using CF 3.5 and VS 2008 Team Suite. I have created a simple form with one button labled "Eat memory". The code looks like the following:
 public partial class Form1 : Form
{
public struct MemoryStatus
{
internal uint dwLength;
public int MemoryLoad;
public int TotalPhysical;
public int AvailablePhysical;
public int TotalPageFile;
public int AvailablePageFile;
public int TotalVirtual;
public int AvailableVirtual;
}

[DllImport("coredll", SetLastError = false)]
internal static extern void GlobalMemoryStatus(out MemoryStatus status);

private List bytelist = new List();

public Form1()
{
InitializeComponent();
}

private void Form1_Closed(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0} : Form1_Closed called",
DateTime.Now.ToLongTimeString()));
}

private void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0} :
CurrentDomain_UnhandledException called",
DateTime.Now.ToLongTimeString()));
}

private void MobileDevice_Hibernate(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0} : MobileDevice_Hibernate
called",
DateTime.Now.ToLongTimeString()));
Clear();
}

private void Clear()
{
if (bytelist != null)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0} : Clear called
(cleanup unused memory objects)",
DateTime.Now.ToLongTimeString()));
bytelist.Clear();
}
}

private void eatMemory_Click(object sender, EventArgs e)
{
MemoryStatus status = GetMemoryStatus();

for (int i = 0; i < 21; i++)
{
bytelist.Add(new MyClass());
}

status = GetMemoryStatus();
memoryAfter.Text = "Memory after: " +
status.AvailablePhysical.ToString();

}

private MemoryStatus GetMemoryStatus()
{
MemoryStatus status = new MemoryStatus();
GlobalMemoryStatus(out status);
return status;
}

private void resetTest_Click(object sender, EventArgs e)
{
Clear();
MemoryStatus status = GetMemoryStatus();
memoryBefore.Text = "Memory before: " +
status.AvailablePhysical.ToString();
memoryAfter.Text = "Memory after: -";
}

private void Form1_Load(object sender, EventArgs e)
{
Microsoft.WindowsCE.Forms.MobileDevice.Hibernate += new
EventHandler(MobileDevice_Hibernate);
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Closed += new EventHandler(Form1_Closed);
Closing += new CancelEventHandler(Form1_Closing);
resetTest_Click(this, EventArgs.Empty);
}

private void Form1_Closing(object sender, CancelEventArgs e)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0} : Form1_Closing called",
DateTime.Now.ToLongTimeString()));
}
}

public class MyClass
{
private byte[] mybyte = new byte[1000000];
}
The code is very simple. We have created a class named MyClass which allocates a 1mb byte array. We simply have hardcoded a loop to iterate through 21 times whwn the "Eat memory" button is pressed so we get less than 2mb free RAM. You'll probebly thinking, why didn't I just calculate the amount of free RAM before the test and allocate a buffer slightly smaller than the free physical memory limit. This didn't seem to work because of the way the OS allocates and frees memory. I found simply hardcoding it worked better for this test. I needed to get between 1 and 2 free mb which was actually harder than it seems! We create a generic array list to hold references to each of the 1mb MyClass objects. We store this array list object at class level so the GC won't try to clean it up when times get tough.

Just to be clear, usally you wouldn't handle all these events under the UI layer, it would be abstracted out usally to the DeviceManagement level (business). We have added hooks to the following events:

Microsoft.WindowsCE.Forms.MobileDevice.Hibernate
System.Windows.Form.Closing
System.Windows.Form.Closed
System.AppDomain.CurrentDomain.UnhandledException

The OS will send the WM_HIBERNATE message to all applications when the amount of free RAM falls below its minimum limit and will stop when it has enough reserve resources to do whatever it needs to do. In .NET, the event that traps the WM_HIBERNATE message is Microsoft.WindowsCE.Forms.MobileDevice.Hibernate. The objective of handling this message is to give your app a chance to redeem itself and clean up any unused memory it may be hogging. Note: You have to explicitly add the Microsoft.WindowsCE.Forms.dll assembly to your project, VS doesn't do this for free.

WM_CLOSE will be sent if the WM_HIBERNATE made little difference sometime after WM_HIBERNATE was sent (I'll show an example of this architecture later). System.Windows.Form.Closing event will be called when the OS sends the WM_CLOSE message if the app is hogging memory which the OS needs then finally, System.Windows.Form.Closed will be called which terminates the app.

System.AppDomain.CurrentDomain.UnhandledException this traps unhandled exceptions in the current app domain which allow us to clean up our code and write a file somewhere, so next time our app loads it sends debugging information to the back office which can be used to fix the error in future builds. I'll show an example of this later.

Remember we said my HTC 3300 device had 22 meg of free RAM before pressing the "Eat memory" button in the above code, well after pressing the "Eat memory" button we now have 1.6 meg of free RAM. Not alot at all, navigating the device is very very slow as one would imagine.


Free RAM after running "Eat memory".

So what should happen now? well, the OS should firstly send the WM_HIBERBATE message to each application running in hand until it has enough memory as the device is in an unstable state and needs more memory to handle things like phone calls, radio etc. I think this freshhold is somewhere above 2mb.

Guess what, WM_HIBERNATE is called which should give our application a chance to cleanup that horrible 21 meg array that we're not using. But in the code documented earlier, did you notice in the MobileDevice_Hibernate event, we commented out the call to the Clear() method.
private void MobileDevice_Hibernate(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0} : MobileDevice_Hibernate
called",
DateTime.Now.ToLongTimeString()));
//Clear();
}
This of course was deliberate to demonstrate what happens in this scenario which emulates what could happen if you do not code for these scenarios. Well as I mentioned earlier the WM_CLOSE will be sent soon after if there are still not sufficient free resources after initiating a WM_HIBERNATE message. We are using the Dianostics.Debug.WriteLine() method to let us know what is happening.

So as we haven't cleaned anything up, we should expect a WM_CLOSE pretty soon.....guess what, we do. See the following output window:


Output when memory limit hits the threshold and WM_HIBERNATE and WM_CLOSE messages are received.

You can see how long it takes for the WM_CLOSE event to occur after the WM_HIBERNATE because we have timestamped the events, here it is 14 seconds. One thing to note after the WM_HIBERNATE message is received a full implicit GC.Collect() is executed. But because we didn't in the above code example clear the array list which is holding onto 21 meg of valuable resource, the GC did little good, so a WM_CLOSE message was sent. Often if the WM_CLOSE has little effect then the OS will kill the app!

So what happens if we uncomment the Clear() method in the MobileDevice_Hibernate event? well lets see.....


Output when memory limit hits the threshold and WM_HIBERNATE message is received

Now this is a different story from before. We can clearly see the hibernate message has been received from the output above and this was received because we reached less then 2meg of free physical memory on the device after pressing the "Eat memory" button. We then called the Clear() method which clears the array of 21 meg MyClass objects. Remember the GC would then be called as soon as the WM_HIBERNATE message returns. So lets examine the available memory in control panel:


Memory applet after cleaning up unused objects.

Wow, this is amazing, now look, we are back to where we were in terms of free physical memory before clicking the dreadful badly written "Eat memory" button!

This demonstrates the fact that you should never rely on the GC even though we are coding in a memory managed evironment today. Native development principles in terms of memory management still apply today as they ever did. This also backs up the fact that sometimes the GC won't help you ;)

There are scenarios where you could blow the free amount of RAM in almost one hit. In these senarios, the OS simply doesn't have a chance to try and get the app to behave itself as clearlyit's not and there is no time to try and get it to behave itself . Usually in these cases an OutOfMemory exception is generated. Here we can then trap these exceptions by registering the AppDomain.CurrentDomain.UnhandledException message. Of course there is no way to rescue your app in these situations, so the only thing you can really do is close everything down safely and write a debug file and transmit it to your back office for debugging information purposes. It is also nice to applogize to the end user once the app loads again and maybe display some info as to what happened. This can be done by simply writing a log file somewhere than the app checks on load.

Saturday, May 17, 2008

The first ever .NET CF Code Profiler

You can get this profiler from here: http://www.eqatec.com/tools/profiler it is free.

I've not installed this yet, so I am not sure how well it works. I will post back my experiences.

Thursday, May 15, 2008

Sending an ICMP packet to a remote server on the CF (Ping)

This question has been coming up a lot recently in the community "How do I ping a remote server from a device?".

I thought I'd write this quick article with some code in how to do this.

Even if you are using the latest version of the Compact Framework which is 3.5, there is no support for this without getting your hands dirty with native code.

A ping is essentially an Internet Control Message Protocol (ICMP) message and can be achieved from managed code by P/Invoking IcmpSendEcho2. This function can be found in Iphlpapi.dll and this call is supported on Windows CE 4.1 and later. For previous versions you'll need to link in library Icmplib.lib.

NOTE: If the machine is sitting behind a router (usual case), some routers give the option for blocking ICMP protocol, if the call doesn't work, you might want to check your router first.

Now this is the good part, instead of having to code the call to the IcmpSendEcho2 function yourself, OpenNETCF has kindly already provided a managed wrapper for us. The OpenNETCF Ping class can be found in the OpenNETCF.Net.NetworkingInformation namespace. Something like the following should work:

public static PingReply Ping(string ipAddress)
{
Cursor.Current = Cursors.WaitCursor;
Ping ping = new Ping();
PingReply reply = null;
try
{
reply = ping.Send(ipAddress, 10000);
switch (reply.Status)
{
case IPStatus.Success:
Cursor.Current = Cursors.Default;
if (ipAddress.IndexOf(".") > -1)
{
MessageBox.Show(string.Format(Properties.Resources.PingServerOK,
ipAddress,
reply.RoundTripTime),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk,
MessageBoxDefaultButton.Button1);
}
else
{
MessageBox.Show(string.Format(Properties.Resources.PingServerOK2,
ipAddress,
reply.RoundTripTime,
reply.Address.ToString()),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk,
MessageBoxDefaultButton.Button1);
}
break;
case IPStatus.BadDestination:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingBadDestination,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.BadOption:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingBadOption,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.BadRoute:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingBadRoute,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.DestinationHostUnreachable:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingDestinationHostUnreachable,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.DestinationNetworkUnreachable:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingDestinationNetworkUnreachable,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.DestinationPortUnreachable:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingDestinationPortUnreachable,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.DestinationProhibited:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingDestinationProhibited,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;

case IPStatus.DestinationScopeMismatch:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingDestinationScopeMismatch,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.DestinationUnreachable:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingPingDestinationUnreachable,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.HardwareError:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingHardwareError,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.IcmpError:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingIcmpError,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.NoResources:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingNoResources,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.PacketTooBig:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingPacketTooBig,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.ParameterProblem:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingParameterProblem,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.SourceQuench:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingDestinationScopeMismatch,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.TimedOut:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingTimeout,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.TimeExceeded:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingTimeExceeded,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.TtlExpired:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingTtlExpired,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.TtlReassemblyTimeExceeded:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingTtlReassemblyTimeExceeded,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.Unknown:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingUnknown,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
case IPStatus.UnrecognizedNextHeader:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingUnrecognizedNextHeader,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
default:
Cursor.Current = Cursors.Default;
MessageBox.Show(string.Format(Properties.Resources.PingUnknown,
ipAddress),
Properties.Resources.Ping,
MessageBoxButtons.OK,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
break;
}
}

catch (PingException ex)
{
Cursor.Current = Cursors.Default;
DialogResult result = MessageBox.Show(ex.Message,
Properties.Resources.Ping,
MessageBoxButtons.RetryCancel,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
if (result == DialogResult.Retry)
Ping(ipAddress);
}
catch (Exception ex)
{
DialogResult result = MessageBox.Show(ex.Message,
Properties.Resources.Ping,
MessageBoxButtons.RetryCancel,
MessageBoxIcon.Hand,
MessageBoxDefaultButton.Button1);
if (result == DialogResult.Retry)
Ping(ipAddress);
}
finally
{
Cursor.Current = Cursors.Default;
}
return reply;
}
That's all there is too it!

Dropping Defaults (Column Constraint) in SQL Compact 3.5

This interesting post talks about the DEFAULT SQL statement is no longer a database constraint in SQL Compact 3.5. You merely use just DEFAULT.

To remove a default simply use SQL syntax: ALTER TABLE table ALTER COLUMN col DROP DEFAULT. This has always been the recomended way to remove defaults.

See here for more info: http://blogs.msdn.com/sqlservercompact/archive/2008/04/03/dropping-defaults.aspx

Tuesday, May 13, 2008

Visual Studio 2008 and .NET Framework 3.5 Service Pack 1 Beta

UPDATE: ADO.NET team blog talk about what changes to expect from this BSP. One major thing is support for SQL Server 2008 via Server Explorer. So now you can use SQL Server 2008 with the Entity Framework (I've not tried this so do not know how well it works). Read the post here. A little information on this subject can be found over at LINQinAction here.

Visual Studio 2008 and .NET 3.5 SP1 beta is now available and been officially released.

VS 2008 SP1: http://download.microsoft.com/download/7/3/8/7382EA08-4DD6-4134-9B92-8585A5B07973/VS90sp1-KB945140-ENU.exe

.NET 3.5 SP1: http://download.microsoft.com/download/8/f/c/8fc1fe13-55de-4bf5-b43e-375daf01452e/dotNetFx35setup.exe

Express with SP1:
  1. http://download.microsoft.com/download/F/E/7/FE754BA4-140B-413C-933F-8D35FB150F12/vbsetup.exe
  2. http://download.microsoft.com/download/F/E/7/FE754BA4-140B-413C-933F-8D35FB150F12/vcsetup.exe
  3. http://download.microsoft.com/download/F/E/7/FE754BA4-140B-413C-933F-8D35FB150F12/vcssetup.exe
  4. http://download.microsoft.com/download/F/E/7/FE754BA4-140B-413C-933F-8D35FB150F12/vnssetup.exe

TFS 2008 SP1: http://download.microsoft.com/download/a/e/2/ae2eb0ff-e687-4221-9c3e-9165a942bc1c/TFS90sp1-KB949786.exe

Note: This release does *not* include SP1 for .NET CF 3.5. No announcements have been made when this will occur.

Scott Guthrie talks about some interesting features/fixes with the advent of this SP.

Wednesday, May 07, 2008

Every Developer, Now a Mobile Developer!

The Mobile Developer Group at Microsoft has just recently created this blog: http://blogs.msdn.com/mobiledev/default.aspx

There is not much on there as yet, but book mark or subscribe via RSS as I'm sure the group will release some interesting stuff to read.

Sunday, May 04, 2008

Bring back XP Alt-Tab in Windows Vista!

This post hits the nail on the head with regards to the problem with the new Alt-Tab in Windows Vista. Win-Tab is quite cool and useful in which I will eventually move over to. But I want something fast and something that I can quickly find,hmmm much like in XP. In Vista, when pressing Alt-Tab instead of showing the icon of the application as in pre-Vista, this has been replaced with a very small image of the whole window which is too small to identify.

To restore the XP Alt-Tab functionality simply add a DWORD named AltTabSettings to HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer and set its value to 1.


Friday, May 02, 2008

Rethrowing Exceptions in .NET

I recently learnt after all this time using .NET that rethrowing an exception such as throw ex in a catch block causes the CLR to alter the original exception meaning you will not get the full trace stack in the exception when it is finally bubbled up the chain.

Consider the following code:
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Foo(true);
}
}

public class MyClass
{
public void Foo(bool includeTraceStack)
{
if (includeTraceStack)
ThrowExceptionIncTraceStack();
else
ThrowExceptionNotIncTraceStack();
}

public void ThrowExceptionIncTraceStack()
{
int a = 0;
int b = 0;

try
{
Divide(a, b);
}
catch (DivideByZeroException)
{
throw;
}
}

public void ThrowExceptionNotIncTraceStack()
{
int a = 0;
int b = 0;
try
{
Divide(a, b);
}
catch (DivideByZeroException ex)
{
throw ex;
}
}

public decimal Divide(int a, int b)
{
return a / b;
}
}
Calling MyClass.Foo(true) gives you the following trace stack:
 at ConsoleApplication1.MyClass.Divide(Int32 a, Int32 b) in C:\Develop\ConsoleApplication1\ConsoleApplication1\Program.cs:line 58
at ConsoleApplication1.MyClass.ThrowExceptionIncTraceStack() in C:\Develop\ConsoleApplication1\ConsoleApplication1\Program.cs:line 38
at ConsoleApplication1.MyClass.Foo(Boolean includeTraceStack) in C:\Develop\ConsoleApplication1\ConsoleApplication1\Program.cs:line 22
at ConsoleApplication1.Program.Main(String[] args) in C:\Develop\ConsoleApplication1\ConsoleApplication1\Program.cs:line 13
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Calling MyClass.Foo(false) gives you the following trace stack:
at ConsoleApplication1.MyClass.ThrowExceptionNotIncTraceStack() in C:\Develop\ConsoleApplication1\ConsoleApplication1\Program.cs:line 52
at ConsoleApplication1.MyClass.Foo(Boolean includeTraceStack) in C:\Develop\ConsoleApplication1\ConsoleApplication1\Program.cs:line 24
at ConsoleApplication1.Program.Main(String[] args) in C:\Develop\ConsoleApplication1\ConsoleApplication1\Program.cs:line 13
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Notice when throwing the original exception by qualifying the exception ie: throw ex as opposed to just throw clears the trace stack lower down in the calling chain. Just using throw gives us more information in the trace stack.

I must say I have always coded thow ex for clarity, not anymore!

Thursday, May 01, 2008

Mobile Client Software Factory

You might remember, last year I wrote a couple articles regarding the Mobile Software Client Factory Data Access Application Block (which I still use today) and how to use them etc These articles can be found here: Part1 and Part2.

It turns out Microsoft is no longer developing the MCSF but it can be found on codeplex here.

Wednesday, April 30, 2008

SQL Server CE 3.0 version inconsistencies

Many people in the community are reporting inconsistencies when viewing the version of SQL Server CE 3.0 through File Explorer file properties and Visual Studio Add Reference dialog.

I use SQL Server Compact 3.5 (note the naming differences) now which seems to be OK in terms of versioning. But earlier versions (3.0, 3.1) don't. See the screen shots attached.


As per Visual Studio.


As per the file system.

This diference is related to the build process between Mobile and Desktop assemblies. Microsoft has partially fixed SQL Server CE 3.1 but fully fixed SQL Server Compact 3.5.

Tuesday, April 29, 2008

Develop SQL Server Compact 3.5 apps with VS 2005

UPDATE 01 June 08: This is quite confusing but you can use VS 2008 RTM to manipulate a SQL Server Compact 3.5 database but not SQL Server 2008 database unless you install the newly released VS 2008 Beta Service Pack 1: http://simonrhart.blogspot.com/2008/05/visual-studio-2008-and-net-framework-35.html

I see this question asked all the time in the community, "Can I use SQL Server Compact 3.5 with Visual Studio 2005" the answer is Yes.

Although it is a little bit ugly, but does work. You have to explicitly add the SQL Server Compact manually by clicking on the Browse tab in Add Reference dialog if it doesn't exist in the .NET tab. Of course the limitations are not being able to use Server Explorer in VS 2005 for v3.5 databases and any UI tools that help with data binding etc (as if anyone actually uses these for corporate LOB apps!).

You can use SQL Server Management Studio 2008 to manipulate the SQL Compact 3.5 database or if you haven't got SQL Server 2008 as SQL Server 2008 is not in RTM yet then you can use Visual Studio 2008 Server Explorer to do this.

You can find SQL Server 3.5 engine here(or similar): C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v3.5\Devices.

See here for the reasons why you might want to move to SQL Server Compact 3.5 and how to get it.

Tuesday, April 22, 2008

MVP Summit 2008 - recap

Well I'm back from Seattle and what an experience. I love Seattle, it's a kind of city that's more like a town than a city in that people tend to be more laid back than most other cities. I admit I found it smaller and cleaner than expected which adds to its appeal. I think I now have an even bigger caffine addiction than before I left! Unfortunately because of my busy schedule, I didn't have the time I would have liked to explore the city in more detail, maybe next time!

That out of the way, I found the Summit probably the most influential event of my career. It was great to meet so many smart people many of which I hope to keep in touch with, many of us exchanged business cards. I learnt alot from these elite passionate people and I think Microsoft did a great job which was a massive investment in the summit which proves Microsoft's commitment to the programme in which I am honored to be part of. I'd like to thank everyone at Microsoft and everyone else who helped make it a truly great experience for all of us.

Steve Ballmers keynote followed Ray Ozzies speech and ended the summit quite nicely. The guy is a great showman. You can read the keynote on the Microsoft Press site.

Just some of the mobility people I met were: Ginny Caughy, Steve Lasker, Rob Miles, Scott Holden, Chris Craft, Loke Uei Tan, Jan Yeh, Nino Benvenuti, Tony Whitter....and lots more...

I've embedded some random pictures that I took.


Taken from within the Washington State Convention and Trade Centre, downtown Seattle.


A view from my hotel room.


The Seattle Space Needle

Downtown Seattle - taken from the Space Needle.
South East view of Seattle from the Space Needle.
Random photo west Seattle somewhere.
One of the research buildings (I think 99) on Microsoft Campus, Redmond. I remember ordering a shuttle from here.
Some cool devices. HTC Advantage, HTC Shift...
The Microsoft Surface, cool.



Random building on Microsoft Campus, Redmond.

I stayed at the Seattle Grand Hyatt - highly recomended.

Monday, April 21, 2008

Databinding issues on the Compact Framework <= 2.0

I had a requirement the other day to databind an alphanumeric id - reasons for which are not that important. What is important is that setting the ValueMember property to the alaphanumeric string is fine, but setting the SelectedValue to the alphanumeric value doesn't work on Visual Studio 2005 running any version of the Compact Framework. This however does work on the desktop (2.0 - not tried 1.1).

Whats more, this seems to be fixed in Visual Studio 2008 regardless whether you target CF 2.0 or CF 3.5.

The failing code was tested on CF 2.0 SP2. The code worked on VS 2008 CF 2.0 and CF 3.5.

A simple work around that I quickly knocked up (if you are still targeting CF 2.0 with VS 2005) is illustrated as follows:-

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

List list = new List();
MyData mydata = new MyData();
mydata.Id = "1";
mydata.Desc = "Desc 1";
list.Add(mydata);

MyData mydata2 = new MyData();
mydata2.Id = "2";
mydata2.Desc = "Desc 2";
list.Add(mydata2);

//Now bind the list to our combo box.
comboBox1.DataSource = list;

comboBox1.DisplayMember = "Description";
comboBox1.ValueMember = "Id";

//DOES NOT WORK ON VS 2005 (CF 2.0) comboBox1.SelectedValue = "2";
//This does work.
comboBox1.SelectedValue = Convert.ToInt32(mydata2.Id);
}
}

public class MyData
{
private string id;
private string desc;

public string Id
{
get
{
return id;
}
set
{
id = value;
}
}

public string Description
{
get
{
return desc;
}
set
{
desc = value;
}
}
}

Friday, April 11, 2008

MVP Summit 2008

Next week I'll be attending the MVP Summit in Seattle and Redmond, WA. If you've never heard of the MVP Summit or would like to learn more, see here.

I'm really looking forward to meeting up with my fellow MVP's and the Windows Mobile and Compact Framework product teams. There are a lot of sessions in which I'll hopefully learn alot from and I'll find time to post my ramblings here. As MVP Summit attendees are under NDA (Non-disclosure agreement) I can't post direct information on products, technologies etc that arn't released yet and other confidential information, but alot of stuff, stuff that is in public domain etc, I will be able to talk about especially Silverlight for Windows Mobile....

I fly out tomorrow from Heathrow so I'll have some time to explore Seattle abit before the summit.

I hope to put faces to many names, if you're going, I'll see you there!

Monday, March 31, 2008

System.Windows.Forms.Form.Owner

Although this little chestnut has been in the CF since 2.0 (Nov 2005) I'd thought I'd mention it here as some people still don't know about it.

If you've written Windows applications for the desktop you'd probebly used this property. On devices what you used to have to do was to write a 'hack' something similar to the following when calling sub-forms from within your application:
using (Form1 form1 = new Form1())
{
this.Text = "";
string str = this.Text;
form1.ShowDialog();
this.Text = str;
}
NativeMethods.SetForegroundWindow(hwnd);
Quite ugly huh! You had to set the Text property for the form to blank before calling a sub-form so that you wouldn't get two entries visible in the memory applet under Settings. P/Invoking SetForegroundWindow was also required to ensure your app would come back to the foreground after closing the sub-form if you had viewed other windows during the lifecycle of the sub-form.

Now all you have to code is the following:
using (Form1 form1 = new Form1())
{
form1.Owner = this;
form1.ShowDialog();
}
Lovely!

Wednesday, March 19, 2008

XSLT Profiler for Visual Studio 2008 CTP

I wrote a blog recently regarding a Biztalk XSLT mapper tool named Xselerator which is a tool that allows you to debug XSLT and run translations. I mentioned at the time Visual Studio didn't support this, but now it does with this plug-in, but only on VS 2008 Team Suite with the performance tools feature installed.

Get it from here: http://www.microsoft.com/downloads/details.aspx?FamilyId=F43314ED-95B7-435F-95C5-0E326E64543B&displaylang=en

Monday, March 17, 2008

Rolling back Visual Studio 2008 projects to Visual Studio 2005

You might ask, why would I want to roll back my VS 2008 projects to VS 2005? Well if like me you were hasty in upgrading your solution and didn't relise or forgot that CF 1.0 projects are not supported under VS 2008 and upgrading will upgrade CF 1.0 to CF 2.0, then you have every reason to do so.

We still have CF 1.0 projects or project which is used for an autorun app which gets shipped on a memory card on PPC 2003 SE and later because CF 1.0 is installed in ROM from PPC 2003 SE. Doing this enables our application to self-install on cold-boots or power failures.

Luckily it isn't too difficult rolling back your projects (although you should use some kind of source control system to roll back to). If you don't a source control system or just curious how to do it, it is dead easy.

Simply open up the project and change the ToolsVersion attribute to 2.0. Change the TargetFrameworkVersion element to 2.0. You can get rid of the Import element which specifies CF 3.5. IE:
<import condition="'$(TargetFrameworkVersion)' == 'v3.5'"
project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets"></import>

Ensure a CF 1.0 or CF 2.0 exists. If you have a desktop project you might have a
<requiredtargetframework>3.5</requiredtargetframework>
for some of the framework assemblies, if rolling back, these can be deleted.

Rolling back the solution couldn't be easier. At the header of your solution file (.sln) you'll have the following:

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008

Change the above to:

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005

That's it!

Friday, March 14, 2008

Device Unit Testing using Visual Studio 2008 Team System

With the release of Visual Studio 2008 device unit testing or in fact desktop unit testing is now built into the IDE which makes unit testing alot easier than before. Note device unit testing is only supported on Visual Studio Team System 2008 with Test Edition or Team Suite. See here for a Visual Studio product comparison.

If you would like to learn more about what agile unit testing is see here.

With Visual Studio 2005 there were tools such as Test Driven.net, NUnit, MBUnit typically were used and still are today, in fact we still use NUnit mainly because we like it, it works and we have hundreds of tests written using it. There are differences with the above tools, we chose NUnit because it was ported from JUnit which worked also.

This article will cover how to use unit testing on a Windows Mobile device and show how simple it is. In fact I am very fond of it as it does in fact do alot of work for you that NUnit doesn't. Also the difference with the VS unit testing over NUnit is that in VS the unit testing is integrated in the IDE.

There are two ways to create unit tests in VS 2008, one is to create tests from production code or to create them by hand. Of course it is less work to create the tests from production code so this is what I'll talk about in this article.

1. Start off with a simple device class library. In this example I have created a simple calculator which adds two numbers together. The code looks like the following:
namespace Calculator
{
public class SimpleCalculator
{
public decimal Add(decimal num1, decimal num2)
{
return num1 + num2;
}
}
}
As you can see, it is very simple.

2. Right click the source for which you would like to create the test project, then select "Create Unit Tests..." option.



3. Select the method for which you would like to create the test.



4. Clicking on "Settings..." button will allow you to configure how the unit test wizard will create your test.

Most of the options are self explanatory. I always change the name to the name of the class coupled with "Fixture" ie in this case "SimpleCalculatorFixture". It stems from NUnit days.

The only option that needs to be clarified below is the "Mark all test results Inconclusive by default". This option forces the test to fail when run because it is not implemented. Of course it is good practice to honor this setting.



5. Clicking OK to the Test Generation Settings dialog then click OK again on the Create Unit Tests dialog will prompt you to enter a name for your new test project, enter a name and click OK.

6. After completing the above Visual Studio creates the test project and some test methods. quite neat when you think in the past you'd have to do all this yourself.

In the above example the test code VS generated looks like the following:
using Calculator;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace CalculatorTest
{

[TestClass()]
public class SimpleCalculatorTest
{
private TestContext testContextInstance;

public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}

#region Additional test attributes
//
//You can use the following additional attributes as you write your tests:
//
//Use ClassInitialize to run code before running the first test in the class
//[ClassInitialize()]
//public static void MyClassInitialize(TestContext testContext)
//{
//}
//
//Use ClassCleanup to run code after all tests in a class have run
//[ClassCleanup()]
//public static void MyClassCleanup()
//{
//}
//
//Use TestInitialize to run code before running each test
//[TestInitialize()]
//public void MyTestInitialize()
//{
//}
//
//Use TestCleanup to run code after each test has run
//[TestCleanup()]
//public void MyTestCleanup()
//{
//}
//
#endregion


///
///A test for Add
///

[TestMethod()]
public void AddTest()
{
SimpleCalculator target = new SimpleCalculator();
Decimal num1 = new Decimal();
Decimal num2 = new Decimal();
Decimal expected = new Decimal();
Decimal actual;
actual = target.Add(num1, num2);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
}
}

As you can see from the above test code, it is very similar to how things are done using NUnit. Notice the similar attributes used to mark methods. The most notable one being the TestClass attribute the NUnit equivilent is TestFixture. These attributes and all testing methods etc can be found in a simple assembly named: Microsoft.VisualStudio.TestTools.UnitTesting.dll. You don't need to add this to your test project because Visual Studio has already done this for you. It doesn't get any easier than this!!

Many of the methods VS has added for us such as MyClassInitialize, MyClassCleanup etc are commented out they have been added for ease of implementation if required.

7. Now we have everything in place, lets see what happens when we run the test, bearing in mind we haven't written any tests yet, we have simply let VS do its job and create a test project for us.
/// 
///A test for Add
///

[TestMethod()]
public void AddTest()
{
SimpleCalculator target = new SimpleCalculator();
Decimal num1 = new Decimal();
Decimal num2 = new Decimal();
Decimal expected = new Decimal();
Decimal actual;
actual = target.Add(num1, num2);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
Now running the test will execute the above, of course the line Assert.AreEqual will fail because we have already written our production code which adds the two numbers together so the result of this method call will not be equal. Visual Studio has guessed here what the likely result might be, clever but not quite clever enough!

So running the above test results in failure on my machine. I am attemping to run the test on an emulator. The error message I am getting is:

The test adapter ('Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') required to execute this test could not be loaded. Check that the test adapter is installed properly. Exception of type 'Microsoft.VisualStudio.SmartDevice.TestHostAdapter.DeviceAgent.NetCFNotInstalledException' was thrown.
I wrote a blog regarding this error a while back here.

This basically means .NET CF 3.5 is not installed and VS doesn't deploy .NET CF 3.5 before executing the test if required even though the option under the test project properties Devices tab "Deploy the latest version of the .NET Compact Framework (including service packs)" is set.




You can simply deploy a Windows Forms application with the above option set and VS will deploy CF 3.5 just as it's always done, if you don't have a Windows Forms application, deploy the CAB file to the device/emulator manually then run it. After this the tests should execute.

8. Now I have fixed the above problem, lets try running the test again. This time I get the following results in the new Test Results window.



From the above Test Results window it is difficult to read the error as to why the test failed. Double clicking the error row loads the properties window for this particular test which gives us some more information as to why the test failed.




9. As we can see from the error message above the Asset.Inconclusive failed. If you remember when VS creates a test template, it inserts the Assert.Inconclusive which will fail when run. So to fix this problem, we simply change the test to the following:
        /// 
///A test for Add
///

[TestMethod()]
public void AddTest()
{
SimpleCalculator target = new SimpleCalculator();
Decimal num1 = new Decimal();
Decimal num2 = new Decimal();
Decimal expected = new Decimal();
Decimal actual;
actual = target.Add(num1, num2);
Assert.AreEqual(expected, actual);
}
We have simply removed the call to the static method Inconclusive.

Now if we run the above test we get the following:



Suprisingly, the test passes. It's not really that suprising because if you look at the AddTest method above, you'll notice that VS has created an instance of two decimal objects which both will be 0 and declared a returning type which isn't instanciated, but the AddTest method creates it and passes it back to the test method. So we are performing this calculation: 0 + 0. Of course the result will be 0 which is why the test passes.

Explore the Assert class, there are many methods to use against your tests much like NUnit. It seems the Testing framework in VS 2008 was built on NUnit and I like it alot!

Friday, March 07, 2008

Adding a block of XML to an existing XmlDocument object

Sometimes you have the need to add a block of XML (string) to an existing XmlDocument (DOM object).

Luckily you don't have to create nodes then import them etc, instead the class XmlDocumentFragment comes to our rescue which allows us to write much cleaner code in this senario - and we all love clean code!

Take the following peice of XML file named myXml.xml:
<Sys>
<Header\>
<Body\>
</Sys>
Now take the following code:
XmlDocument doc = new XmlDocument();
doc.Load("myXml.xml");

Now take the following XML block:
<Start id="7672-2322-2322-3324"/>
Now what if I wanted to add the above block of XML into the Body element of the doc XmlDocument object but I didn't have control over the schema -or maybe I don't care what the schema looks like or don't even know what it looks like, all I want to do is insert it into the body. I could use the CreateNode() method, but this is ugly and I have to know the schema, also this would add a maintance overhead as everytime the schema is changed, I'd have to change my code too.

Instead the XmlDocumentFragment class can be used. Take the following code:
XmlDocument doc = new XmlDocument();
string s = "<Start id="7672-2322-2322-3324"/>";
doc.Load("myXml.xml");
XmlDocumentFragment fragment = doc.CreateDocumentFragment();
fragment.InnerXml = s;
//Use GetElementsByTagName instead of XPath incase the schema changes.
XmlNodeList body = doc.GetElementsByTagName("Body");
if (body.Count > 0)
body[0].AppendChild(fragment);
That is all there is too it. The output of the above will now look like the following:
<Sys>
<Header\>
<Body>
<Start id="7672-2322-2322-3324"/>
</Body>
</Sys>

Thursday, February 28, 2008

Visual Studio Gallery

The Microsoft Visual Studio Ecosystem team recently announced the Visual Studio Gallery web site: http://visualstudiogallery.com/.

This web site is a central respository for Visual Studio extensions. It is possible for developers to add their own Visual Studio extensions to this site for others to access. The site however doesn't host the extensions, the site contains web links to where they can be found and information about the extension.

Wednesday, February 13, 2008

Upgrading your device solutions to Visual Studio 2008 and the .NET CF 3.5

As the title says upgrading your pre 2008 device solutions to Visual Studio 2008 and to run under the .NET CF 3.5 is a two step process. This is because Visual Studio 2008 supports multi-targeting.

By default when you upgrade your VS 2005 projects to VS 2008 they continue to target the .NET Framework 2.0. This is true for both desktop and devices. This article quickly talks about how you target the new frameworks after conversion.

1. Open your VS 2005 solution in VS 2008. The conversion wizard will load, simply run though this.



2. This particular solution contains device projects as well as desktop projects.

3. As you can see, after the project has been converted, it is still compiled against the CF 2.0.



4. In VS 2008 there is a new menu option labeled "Upgrade Project" (among others) under Project or the same option can be accessed under the context menu by right clicking the project.

NOTE: This new option is only visible to device applications.

Clicking it will upgrade your Compact Framework 2.0 application to compile against the Compact Framework 3.5.



5. Clicking the "Upgrade Project" menu option will prompt you to continue.



Once you have clicked Yes, the process is very quick and does indeed upgrade your device application to compile against the CF 3.5.



6. After doing the above you will notice the "Upgrade Project" menu option will disapear from the project context and main menus.



Although this post is mainly about devices I thought I'd mention converting your desktop applications from .NET Framework 2.0 to .NET Framework 3.5 is slightly different. There is no "Upgrade Project" menu option for desktop projects, instead you have to use the muli-targeting support features under project properties to target the .NET Framework 3.5.

Sunday, February 03, 2008

NETCFv35.Messages is the new System_SR

In Visual Studio 2008 and the .NET Compact Framework 3.5, NETCF35.Messages replaces the System_SR found in previous versions of the CF.

So if you had the message similar to the following running pre CF 3.5 when a framework exception occured: "An error message cannot be displayed because an optional resource assembly containing it cannot be found". A solution to this was to install System_SR_ENU_wm.cab (if running Windows Mobile) or System_SR_ENU.cab (if running Windows CE). Both of which ships with the Windows Mobile SDK's. Doing this only worked if you were lucky! not really, there is some science to it, science that I am not sure of. A combination of installing the CF and combination of localized apps on the device

In Visual Studio 2008, this new cab that replaces System_SR is named: (NETCFv35.Messages.ENU.wm.cab for Windows Mobile or NETCFv35.Messages.ENU.cab for Windows CE) is not installed by VS initially when you start debugging whereas in pre VS 2008 we enjoyed the automatic install on debugging for the first time. You have to install this CAB explicitly. This cab can be found here: C:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics - of course assuming C: is where you decided to install the CF.

Friday, February 01, 2008

MVP Summit 2008

I'll be attending the MVP Summit April 2008 in Redmond. Anyone else coming!!??