JIT

Fri, December 31, 2004, 06:35 AM under MobileAndEmbedded
By now, all .NET developers know that their managed code (C#, VB.NET etc) gets compiled to Intermediate Language (IL) which itself, at runtime, gets Just-In-Time (JIT) compiled to native code. Here we'll look at some of the differences of the NET Compact Framework JIT engine compared to the desktop (full framework), as well as what CF 2.0 will change.

As a historical aside, the alpha (pre-RTM) version of the CF did not have a JIT compiler and instead IL was interpreted on the device. Since RTM (for CF version info please go here), the IL is JITted to native code on the device/target. This is done on a per method basis (like on the Full Fx). When a method is called, it is detected that there is no native code for the method, so IL is compiled into native code and executed; next time the method is called the native code gets executed, which means that the JIT performance penalty is only incurred once.

The major difference on the CF is that the native code is cached in the GC heap (i.e. in RAM) and is susceptible to "pitching" if a full GC occurs (for more detail on GC phases and pitching look there). In other words, the JITted native code can be thrown away under memory pressure, so next time a recompilation has to take place for any methods that were pitched. Do not confuse pitching methods with the actual type data structures (metadata), which are never pitched once loaded.

To obtain some numbers for your CF app, you should use the perf counters. In particular focus on: Bytes Jitted, Native Bytes Jitted, Number Of Methods Jitted, Bytes Pitched and Number Of Methods Pitched

Another difference in the same area is that ngen is not supported on the NETCF. So you cannot pre-compile your assemblies to native images.

Finally, note that the JITted code has a limit of 64K (native size, not managed). You wouldn't expect to hit that limit, but very large forms can break the rule in their auto-generated InitializeComponent method. The workaround is to split the method into smaller ones (at the expense of losing designer support).

CF 1.0 comes with two JIT compilers: sJIT and iJIT. The former is for ARM devices only and the latter is for all other CPU architectures (inc. SH3, MIPS, x86). SJIT takes slightly longer to compile IL to native code, but the resulting code is faster than what IJIT can produce (there is a detailed slide "Differencies between JITs" in this ppt, for anoraks :-)

CF 2.0 comes with a unified JIT, which is more performant and optimised than what we have today. Note that VS2005 will ship with ARM CPU Emulators and not x86 like today, so the emulation experience will be enhanced from a performance perspective too.

As you recall I have read all CF books, so I can tell you that both Building Solutions with the CF and CF Kick Start include short paragprahs on JITting. The NETCF bible dedicates a few pages on the JITted Code Pool / native image cache.

Happy New Year!

Red Cross Disaster Relief

Fri, December 31, 2004, 06:34 AM under Random
Amazon Honor SystemClick Here to PayLearn More

BackgroundWorker Sample

Wed, December 29, 2004, 06:46 PM under MobileAndEmbedded
You should be familiar by now with Whidbey's excellent BackgroundWorker class and my implementation of it for the Compact Framework 1.0 - for immediate use today :-)

Although the MSDN examples and walkthroughs (as described on the above link) are great, I thought I would port Chris Sells's sample from the excellent article he wrote a while back: Asynchronous Calculation of PI digits. I encourage you to download the code from that article and compare it against the code I present here. It will instantly become apparent what power the BackgroundWorker brings in terms of simple code to write, read and maintain (let alone understand, but that might be a drawback depending on your outlook :-).

The form looks like this.

You can download the project at the end of this entry, but here is all of the relevant code (works on both CF and desktop):
        // Declare the worker
private BackgroundWorker mBW;

// Call this method in form's ctor
private void InitBW(){
mBW = new BackgroundWorker(this);
mBW.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(mBW_RunWorkerCompleted);
mBW.ProgressChanged
+= new ProgressChangedEventHandler(mBW_ProgressChanged);
mBW.DoWork += new DoWorkEventHandler(mBW_DoWork);
mBW.WorkerReportsProgress = true;
mBW.WorkerSupportsCancellation = true;
}

// Handles click for Calc/Cancel button
private void cmdCalc_Click(object sender, System.EventArgs e) {
if (cmdCalc.Text == "Calc"){
// read digits from numeric updown control
int digits = (int)nuDigits.Value;
pbLeft.Maximum = digits;
// ask worker to do its job
mBW.RunWorkerAsync(digits);
cmdCalc.Text = "Cancel";

}else if (cmdCalc.Text == "Cancel"){
// ask worker to cancel
cmdCalc.Enabled = false;
mBW.CancelAsync();

}else{
// Only two enabled states for
// this button: Calc and Cancel
System.Diagnostics.Debug.Assert(false);
}
}

// Completion event
private void mBW_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e) {
// Just get ready for next time
cmdCalc.Text = "Calc";
cmdCalc.Enabled = true;
}

// Progress event
private void mBW_ProgressChanged(object sender,
ProgressChangedEventArgs e) {
// Touch GUI, no problem
pbLeft.Value = e.ProgressPercentage;
txtPi.Text = (string)e.UserState;
}

// On worker thread! Only method with real logic
private void mBW_DoWork(object sender, DoWorkEventArgs e) {
int digits = (int)e.Argument;
BackgroundWorker bw = (BackgroundWorker)sender;

// we will be updating the UI with progress
string pi = "3";

// Show progress (ignoring Cancel so soon)
bw.ReportProgress(0, pi);

if( digits > 0 ) {
pi += ".";

for( int i = 0; i < digits; i += 9 ) {
// Work out pi. Scientific bit :-)
int nineDigits = NineDigitsOfPi.StartingAt(i + 1);
int digitCount = System.Math.Min(digits - i, 9);
string ds = System.String.Format("{0:D9}", nineDigits);
pi += ds.Substring(0, digitCount);

// Show progress
bw.ReportProgress(i + digitCount, pi);

// Deal with possible cancellation
if (bw.CancellationPending == true){
e.Cancel = true;
break;
}
}
}

}

Download the project (zip).

CF 2.0 Performance Statistics revisited

Tue, December 28, 2004, 10:57 AM under MobileAndEmbedded
In the past, I have talked about the performance counters for CF 1.0 apps, including a list of the new counters that CF 2.0 adds (based on the VS2005 Beta 1). It seems that with the November CTP the list has changed again. Rather than list what has changed from Beta 1 or comparing it with what we have today with NETCF 1.0, I give you the complete list. Notice that some of today's counters have been removed (e.g. "Execution Engine Startup Time") and some have clearer names (e.g. "Peak Bytes Allocated (native + managed)"). Finally, before we look at the list, note that the statistics file has changed from mscoree.stat to ExeName.stat

List of perf counters with the November CTP of CF 2.0:
Total Program Run Time (ms)
App Domains Created
App Domains Unloaded
Assemblies Loaded
Classes Loaded
Uncontested Monitor.Enter Calls
Contested Monitor.Enter Calls
Threads in Thread Pool
Pending Timers
Scheduled Timers
Timers Delayed by Thread Pool Limit
Work Items Queued
Peak Bytes Allocated (native + managed)
Managed Objects Allocated
Managed Bytes Allocated
Garbage Collections (GC)
Bytes Collected By GC
Managed Bytes In Use After GC
Total Bytes In Use After GC
GC Compactions
Code Pitchings
Calls to GC.Collect
GC Latency Time (ms)
Pinned Objects
Objects Moved by Compactor
Objects Not Moved by Compactor
Objects Finalized
Boxed Value Types
Process Heap
Short Term Heap
Jit Heap
App Domain Heap
GC Heap
Native Bytes Jitted
Methods Jitted
Bytes Pitched
Methods Pitched
Exceptions
Platform Invoke Calls
COM Calls Using a vtable
COM Calls Using IDispatch
Complex marshaling
Runtime Callable Wrappers
Socket Bytes Sent
Socket Bytes Received

UPDATE: Ask and you shall receive. Scott Holden gives us the official list based on the latest internal builds.

Blog link of the week 52

Sun, December 26, 2004, 02:22 PM under Links
Imagine if all weeks were as slow (from a blogging activity perspective) as the one just gone by (I also wonder if the next one will be quieter)...anyway...

Rather than a specific blog entry link, we welcome one more .NET dev to the blogging world, Angelos Petropoulos; and if you don't have time to read all 3 posts he made in his first week (and not a "Hello World" in sight), enjoy this one.

December CTP failure

Fri, December 24, 2004, 03:58 PM under Whidbey | VisualStudio
---------------------------
Microsoft Visual Studio 2005 Beta 2 Setup
---------------------------
Error 1305.Error reading from file d:\vs\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bootstrapper\Packages\InstMSI\instmsiA.exe. Verify that the file exists and that you can access it.
---------------------------
Retry Cancel
---------------------------

I have been trying all day to get the December CTP installed. Every sinlge time the message above halts the show. Yes, the file (and the instmsiW.exe) are both present on the C hard drive and the D dvd drive. The one on the C drive seems to be used by something because it will not let me delete/rename/overwrite it. Maybe there is already too much alcohol in me, but the fact is I can't see a solution and am giving up :-(

Merry (hic) Xmas!

Visual Studio WinCE Emulators

Thu, December 23, 2004, 03:09 PM under MobileAndEmbedded
Visual Studio.NET 2003 shipped with a WindowsCE 4.1 Emulator (as well as PPC 2002 emulator, of course). Although the PPC emulators where updated via separate SDK downloads, the WinCE emulator never was. It never got updated, so even today some devs fall into the trap of thinking it is a 4.2 emulator. For example, with the 4.1 emulator, trying to use the InputPanel control (SIP) results in crashing (NullReferenceException more often than not).

Of course, if you are going to be targeting a non-PPC device, you should obtain an SDK that includes an emulator from the provider of the custom CE-based device. Nevertheless, having a generic WinCE emulator out of the box is nice for those quick generic tests.

Whidbey will not ship with a CE 5.0 emulator (and hence none of the Beta or CTPs include one either). The plan, apparently, is to make a CE 5.0 image available after the release of VS2005. If you don't know about it yet, CF 2.0 will only run on CE 5.0 devices and greater (and PPC2003 and greater). I tried installing an SDK created with PlatformBuilder 5.0 but had no success (Beta 1 on Win2K, November CTP on XP) then found out via the private ng that it is not supported yet.

Only recently came across this; granted you can't straightforwardly debug with it and it doesn't work in a Virtual PC, but at least via copying files you can run NETCF 1.0 apps and also CF 2.0 apps (if you deploy the x86 Compact Framework 2.0 cab first)

Generics in Compact Framework

Wed, December 22, 2004, 05:09 AM under MobileAndEmbedded
A disclaimer up front: This is by no means a tutorial or even my original work on Generics. The subject has been discussed in depth ever since it was announced as part of Whidbey. Given that generics were not available in the Compact Framework in previous releases and I did say I would talk about them a bit, here goes some code for CF from the November CTP (tested in the emulator):

I bet 90% of the mileage on generics use will come out of using the classes in the framework and specifically the System.Collections.Generic namespace. An example is this:
' VB - consuming built-in collections
        Dim s As New System.Collections.Generic.Stack(Of Int32)
        s.Push(5)          'no boxing
        s.Push(6)
        's.Push("invalid") 'will not compile :-)
        Dim tot As Int32 = s.Pop() + s.Pop()          'no cast

// C# - consuming built-in collections
    System.Collections.Generic.Stack<int> s;
    s = new Stack<int>();
    s.Push(5); //no boxing
    s.Push(6);
    //s.Push("invalid"); //will not compile :-)
    int tot = s.Pop() + s.Pop(); //no cast

However, you can create your own generics classes and even structs:
' VB - Declare generic struct
Public Structure MyPoint(Of T)
    Dim x As T
    Dim y As T
End Structure

// C# - Declare generic struct
public struct MyPoint<T> {
    T x;
    T y;
}

...and of course consume them:
' VB - consume generic struct
        Dim mp As New MyPoint(Of Single)
        mp.x = 12.3
        mp.y = 5

// C# - Consuming own struct
    MyPoint<float> mp = new MyPoint<float>();
    mp.x = 12.3;
    mp.y = 5.2;

Even more useful, you can create generic methods and impose constraints on the types:
'VB - generic method with constraints
Public NotInheritable Class MyMath
    Private Sub New()
    End Sub
 
    Public Shared Function Min(Of T As IComparable)(ByVal a As T, ByVal b As T) As T
        If a.CompareTo(b) < 0 Then         'no casting + intellisense help
            Return a
        End If
        Return b
    End Function
End Class

// C# - generic method with constraints
public static class MyMath {
    //Min with constraints
    public static T Min<T>(T a, T b) where T : IComparable {
        if (a.CompareTo(b) < 0) {//no casting + intellisense help
            return a;
        }
        return b;
    }
}

' VB - Consume generic method
        Dim m As Int32 = MyMath.Min(6, 8)

// C# - Consume generic method
    int m = MyMath.Min(6, 8);

I have only scratched the surface here, if you want to know more about Generics I encourage you to go searching. I can recommend these articles: [1, 2]

UPDATE (7 Jan 05): Roman Batoukov has the implementation details
UPDATE (26 Jan 05): Nazim Lala has the details on reflection with generics

Watchdog design for CF app

Tue, December 21, 2004, 04:02 PM under MobileAndEmbedded
I encourage you to read my previous entry on watchdogs, even if you are familiar with the topic. It will ensure we are on the same page on principles and terminology.

CF's non-deterministic nature in combination with some areas that can indeed take 100s of milliseconds to process (e.g. form loading) dictate the design choices. Cutting to the chase, I'd say your only viable option is to have another blind process as the dog and then choose a high interval for kicking it from the CF app (i.e. >9 seconds). Further, I suggest the dog is an eVC app with as little baggage as possible. For the kick, you can choose between a variety of IPC mechanisms, and I suggest using a named event. The CF app signals the event and the eVC app waits on it, with a timeout twice as large as the time interval.

The CF app will signal the event exactly like I have described here (i.e. cmdWrite_Click method). Obviously you create the named event and store the handle. On a timer's tick (System.Windows.Forms.Timer; *not* a Threading.Timer) signal the event. Also, signal it before any method that will take some time to complete. You can basically kick the dog from a number of places, but the important one is the kick from the UI thread on a timer whose interval is half the interval defined in the dog process.

So the C app acting as the dog has code similar to this pseudo code:
// in a thread

while(1)
{
if (WaitForSingleObject(hDogEvent, 20000) != WAIT_OBJECT_0)
{
//RESET UNIT
}
ResetEvent(hDogEvent);
}

We implemented the above on our platform with a few additions.
1. The dog itself kicks the hardware watchdog on our unit. So should anything go wrong with that process (effectively should something go wrong in the OS), our unit resets.
2. The dog is also the launcher of the CF app on unit startup. So the dog starts the CF app and keeps the handle to the process. So, on a separate thread, it waits on the process handle; if that returns (interpreted as the app has exited), it also resets the unit. [Note there is no mechanism for the user to terminate the CF app but, in the case where the process is nuked for whatever reason, the dog does not have to wait for the interval and instead resets the unit immediately.]
3. Before resetting the unit, it stores in the registry the reset reason with a timestamp (the app also does that in cases where it legitimatly resets the unit e.g. language change) - the diagnostic value of this is obvious.
4. If I told you, I'd have to kill you :-)

And as an aside, my CF app displays on a diagnostics page the amount of time it has been running along with the reason it was last reset. We have a unit in the office that has been going for >100 days (although I am sure there are others on the field that have been going for longer ;-)

About Watchdog

Tue, December 21, 2004, 03:47 PM under MobileAndEmbedded
My experience in this area is with CF apps on CE, but the principles apply on other platforms/technologies.

So the requirement is that your application never hangs (e.g. like it would if you touched a UI control from a worker thread) *and* never sits there with a crash dialog the user stares at (like it would if an unhandled exception occurred).

The way we achieve this is by implementing a watchdog. In a sentence, a watchdog monitors your application and when the latter becomes unresponsive, the watchdog takes a certain action. How does the dog know your application is unresponsive? Your application tells it every X units of time (e.g. 5 milliseconds or 30 seconds etc) that it is OK. How does it tell it? By any mechanism you design, e.g. signaling a named event, calling a library/platform method etc. What does the watchdog do when it has not been told for some time? It restarts your app or resets the unit or notifies some other resource. For embedded devices you can get dedicated hardware watchdogs, and even some chips (e.g. the XScale) include watchdog features. WinCE 5.0 offers watchdog APIs so you could even use those rather than roll your own.

No matter how you implement it, the watchdog is usually very simple, in order to avoid it being susceptible to locks/crashes itself!

To recap:
1. You need a watchdog (be it another process, a physical part or whatever) a.k.a. the dog
2. Your watchdogged app tells the dog it is OK on a predefined interval (a.k.a. kick, pet, tickle, stroke etc)
3. When the dog has not received a kick (or a number of) on predefined interval(s) it takes some action (usually restart the app/unit)

You can make the situation more complex by adjusting at runtime the interval (depending on what your app does), you can have different threads in your app kicking at different intervals and so on and so forth.

Next time I'll discuss an application of the above principles for a CF app on a CE device.

AppDomain.UnhandledException Part 2

Mon, December 20, 2004, 04:01 PM under MobileAndEmbedded
Below find the VB code for global exception handling in NETCF, as described here. First though, a sort paragraph that you may skip if you desire.

It is worth noting some behaviours of surrounding Application.Run with try..catch (which we already established is not needed). On its own, it cannot catch exceptions thrown from a thread, but it can catch ones thrown on the GUI. It can also catch them when thrown in a Control.Invoke, but only after the built-in CF error dialog appears. If you use try..catch in combination with AD.UnhandledException, it gets more interesting. The try..catch handler is always hit straight after the AppDomain handler with a ThreadAbortException (and a different StackTrace); in those cases, your handling code better run fast, as the process is on its way out and even a MessageBox will not stay up for long. The exception (no pun intended) to the last comment and the order the two handlers are run, is when the exception is thrown on the GUI thread. So, once again, AppDomain.UnhandledException is all you need.

Without further ado here is the VB version:

Public NotInheritable Class EntryPoint
Private Sub New()
End Sub

<MTAThread()> _
Shared Sub Main()
' Add Global Exception Handler
AddHandler AppDomain.CurrentDomain.UnhandledException, _
AddressOf OnUnhandledException

Application.Run(New Form1)
End Sub

' In CF case only, ALL unhandled exceptions come here
Private Shared Sub OnUnhandledException(ByVal sender As Object, _
ByVal e As UnhandledExceptionEventArgs)
Dim ex As Exception = TryCast(e.ExceptionObject, Exception)
If (ex IsNot Nothing) Then
' Can't imagine e.IsTerminating ever being false
' or e.ExceptionObject not being an Exception
EntryPoint.HandleException(ex, e.IsTerminating)
End If
End Sub

'' This should not throw any exceptions
'' and should run as quick as possible
Private Shared Sub HandleException(ByVal ex As Exception, _
ByVal t As Boolean)
' Log ex.StackTrace or whatever
'MessageBox.Show(ex.StackTrace, ex.Message);
Dim fs As FileStream = Nothing
Dim sw As StreamWriter = Nothing
Try
fs = New FileStream("GEH.txt", FileMode.Append, _
FileAccess.Write, FileShare.None, 1000, False)
sw = New StreamWriter(fs)
sw.WriteLine("DateStamp: " + DateTime.Now.ToString())
sw.WriteLine("ToString(): " + ex.ToString())
sw.WriteLine("Message: " + ex.Message)
sw.WriteLine("StackTrace: " + ex.StackTrace)
System.Threading.Thread.Sleep(1000) 'for a laugh
sw.WriteLine("THE END")
sw.Flush()
Finally
If sw IsNot Nothing Then
fs.Close()
sw.Close()
End If
End Try
End Sub
End Class


AppDomain.UnhandledException Part 1

Mon, December 20, 2004, 03:49 PM under MobileAndEmbedded
The punchline is that the AppDomain class (along with other enhancements such as AppDomain.Unload), also offers AppDomain.CurrentDomain.UnhandledException. As soon as I saw that (in combination with this), I started running various tests (over 20 different combination scenarios run in release mode with no debugger attached) in order to update an older post on Global Exception Handling on the CF 2.0.

Let's remember that unhandled exception tests must include: Throwing on the GUI, on a ThreadPool thread, Thread, Control.Invoke, object finalizer and after Application.Run when the app is exiting. As you recall, on the desktop the only way to cater for all of these is by hooking into AppDomain.UnhandledException, Application.ThreadException and surround Application.Run with try..catch. CF 1.0's limitation was fully described here.

With NETCF 2.0, we still don't have Application.ThreadException but, unlike the desktop scenario, we don't need it since the NETCF 2.0 AppDomain.UnhandledException catches *all* unhandled exceptions. Here is an example of its use:

static class EntryPoint {
[MTAThread]
static void Main() {
// Add Global Exception Handler
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(OnUnhandledException);

Application.Run(new Form1());
}

// In CF case only, ALL unhandled exceptions come here
private static void OnUnhandledException(Object sender,
UnhandledExceptionEventArgs e) {
Exception ex = e.ExceptionObject as Exception;
if (ex != null) {
// Can't imagine e.IsTerminating ever being false
// or e.ExceptionObject not being an Exception
SomeClass.SomeStaticHandlingMethod(ex, e.IsTerminating);
}
}
}


Note that I have never seen e.IsTerminating be false, in other words after your handler gets run the process exits. The last statement includes the case where you throw an exception in the handler; so, exceptions thrown in the global exception handling routine are swallowed (why would you throw in there in the first place is a valid question).

Next entry will serve as a holder of the VB equivalent code plus a blurb on try..catch around Application.Run. Go :-)

I stripped this article from the fine detail and instead just presented the result; if you have a deeper interest let me know and I'll send you how I arrived at the conclusions.

Blog link of the week 51

Sun, December 19, 2004, 01:36 PM under Links
The worst thing that can happen to me from a BLOTW perspective is this: a good post appears on a Monday so the people focusing on link blogging have already told the world about it. Given my BLOTW policy, that eliminates it from my shortlist for Sunday's BLOTW entry. This week I was lucky :-)

If you haven't already, go read why going to the bathroom will help you understand threading (Monitor.Xxxx methods) (long)

I can't help making a NETCF observation here. We only have Monitor.Enter/Exit in CF 1.0; CF 2.0 adds TryEnter but that's it, no Pulse methods :-(

StackTrace

Sat, December 18, 2004, 02:56 AM under MobileAndEmbedded
If you are a desktop developer, imagine life without Exception.StackTrace. Has it sunk in yet? Good, your imagination has just taken you to what is reality for CF developers today (add to that CF's absence of GEH and you'll realise why it is the *compact* framework).

If you are a CF developer you feel my words no doubt... well feel no longer, because CF 2.0 (available now in a CTP release near you) gets Exception.StackTrace :-D

Before you ask, no the standalone StackTrace class is not available and neither is Environment.StackTrace but you can't win them all right?

As you'd expect, the built-in CF error dialog that comes up when an uncaught exception is thrown, now takes advantage of StackTrace to give us better info as to where the unhandled exception occurred.

November CTP

Fri, December 17, 2004, 02:01 PM under Whidbey | VisualStudio
As you should be aware by now, there is a November CTP out (I learned about it here). Thought I'd briefly share some experiences on the sleek VS2005 Standard Edition.

The install went though OK, including launching VS. Creating a project was not so smooth though; some error about System.XML being corrupt. Repaired the installation and tried again: bingo! So now I do my usual thing of creating one of each Windows App and NETCF app (in both C# and VB) to see if it is worth continuing and yes, it all worked. Then turned my focus to CF projects only (if you are asking "why", welcome to my blog :-).

First noticeable omission compared to the Beta 1 (the October CTP escaped me), is Deploy to My Computer! Where has it gone? That was way cool (previously mentioned it in passing here - penultimate paragraph) and I hope it will come back before Whidbey RTMs. UPDATE: If you also want this feature back, GO VOTE FOR IT NOW (it has been cut and is not on the list for RTM.

Looking into the above further, I actually try to execute a CF exe on the desktop and it fails to find the right assemblies (exception and death). This also worked before and works today with VS2003! So I move the exe to the actual directory where the CF assemblies are, and now it works... interesting.

Major setback now: I cannot debug with the emulators (I am running XP in a VPC). This worked in Beta 1, so it is either a step backwards or something wrong with my installation. Just running up the emulators works fine, by the way. Taking that last step further, I decide to manually copy the exe to the emulator (even a plain deploy with VS doesn't work). I can now run the exe and have a play with it (after also copying the CF 2.0 cab and installing it, of course). BTW, sharing files is made much easier with the direct option to have a "Shared Folder" in the options of the emulator; it then appears as "Storage Card" in the image. UPDATE: Got emulator debugging working with thanks to Amit Chopra (Brian Chamberlain really).

Next thing to examine are the NETCF framework assemblies in ILDASM (yes I like Object Browser and other tools but I prefer exploring what's new through ILDASM - call me crazy). I like what I see, but this is not the purpose of this blog entry. I find a couple of areas of particular interest and decide to drill into them (as in look at the implementation of the methods). No IL!!! All methods have a code size of 1, which is the ret statement. What's going on here? I open the CF assembly I just created and, sure, I can see the IL fine. Also fine are the desktop framework assemblies. I must be missing something here but I have never encountered this before, so if anybody has any clue please share. UPDATE: Turns out with this release the CF assemblies on the desktop are just designer shims and have no real code in them; the workaround for examining non-publics and implementations is to copy the files from the device to the desktop and disassemble them - thank you to Mike Zintel and his team for pointing this out. BTW, if you don't fancy copying the files and can cope with unfriendly file names, just extract the appropriate cab files directly on your PC :-)

I'll update this entry with any relevant info, but that's all for now. Next time we'll see a cool addition to CF 2.0 that was not in the Beta. At some future date I will cover Generics, which are also available in this build.

Stopwatch

Thu, December 16, 2004, 01:03 PM under MobileAndEmbedded
A useful class in .NET 2.0 for measuring performance, but not only, is the System.Diagnostics.Stopwatch class. Once again this does not appear to be part of CF 2.0, so I set out to implement one for both CF 1.0 and desktop version today (.NET 1.1) and tomorrow (CF 2.0).

You can download the dll from here (so you get the BackgroundWorker as a bonus) or get the code at the end of this entry.

The interface is very simple:
1. Create an instance of a Stopwatch class.
2. Start it and stop it at will, or reset it back to zero.
3. At any moment in time, access one of its Elapsed properties (returning TimeSpan, milliseconds or ticks)
4. You can check if an instance is running

There are also a bunch of static (Shared in VB) calls you can make:
5. If you are lazy and want a new already started Stopwatch with one call, use the StartNew static method
6. If you just want to know the current number of ticks in the timer mechanism, call the static GetTimeStamp
7. The number of ticks per second is accessible via another static: Frequency

Cannot get much simpler, can it :-) In addition, on MSDN you can find: .NET Client Stopwatch Application Sample

My implementation uses the high resolution QueryPerformanceCounter/Frequency APIs. If they are not supported on your device, you will get an exception when creating a Stopwatch [note that the .NET 2.0 version copes with a fallback mechanism, I have not implemented that]. If you are the unfortunate owner of such a device then I suggest you use Environment.TickCount.

Download the DLL here
Download the VB code here
Download the C# code from OpenNETCF

Blog link of the week 50

Sun, December 12, 2004, 03:18 PM under Links
Regular readers know by now that I would not talk about some conference that is 10 months away or some autocomplete search feature (in the same way I will not be talking tomorrow about yet another desktop search feature).

Did you think that "GC" and "leak" could exist in the same sentence? Apparently they can.

To balance things out, go to this not so technical post about MSFT shipping practices/processes.

Finally, take a seat back and enjoy the arguments discussions between one of the 3 amigos and the respectable opposition (if ever I needed proof that MSFT recruitment works well, I got it when they hired some of the best UK UML/methodology minds - all they need is this guy and they'll be flying).

Multifile assemblies in CF 2.0

Thu, December 9, 2004, 04:05 PM under MobileAndEmbedded
A question came up in the ng, and my reply included the statement "CF 1.0 does not support multi-module assemblies [...]". So I thought I'd check to see if that changed in CF2.0. The short answer is "yes, they are supported"! If you are on the CF team, please let me know why you are offering this feature. What was the driver for it? Anyway, read on to see an example of multifile assemblies in CF 2.0.

If you don't know about multi module/file assemblies, I suggest you search the web for definitions, as I am not going to describe the principles (the feature is available in the .NET full framework today). In a small nutshell, you compile code in modules (.netmodule extension and nothing to do with VB's module) that you can link to from an existing assembly. (Alternatively, using al.exe you create an assembly that holds the manifest only and references the real code in one or more netmodules).

So here is how to do it with CF 2.0

1. Create a ProgramMixed.cs file with this code in it
namespace MixedLanguages {
static class Program {
[System.STAThread]
static void Main() {
System.Windows.Forms.Application.Run(
new MixedLanguages.Form1());
}
}
}

2. Create a Form1Mixed.vb file with this code in it
Namespace MixedLanguages
Public Class Form1
Inherits System.Windows.Forms.Form

Public Sub New()
Me.Text = "Run from Csharp code"
Me.MinimizeBox = False
End Sub
End Class
End Namespace

3. In the command line type the following (assuming you have all the PATH variables set and you are pointing to the right directories):


vbc /netcf /noconfig /nostdlib /r:"E:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\CompactFramework\WindowsCE\mscorlib.dll","E:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\CompactFramework\WindowsCE\System.dll","E:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\CompactFramework\WindowsCE\System.Windows.Forms.dll" /t:module Form1Mixed.vb


You should get a Form1Mixed.netmodule file created (note that /sdkpath crashes with Beta 1).

4. Also type this:


csc /noconfig /nostdlib /r:"E:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\CompactFramework\WindowsCE\mscorlib.dll","E:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\CompactFramework\WindowsCE\System.dll","E:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\CompactFramework\WindowsCE\System.Windows.Forms.dll" /addmodule:Form1Mixed.netmodule ProgramMixed.cs


You should have a ProgramMixed.exe created.

In both successful command line compiles, the output looks something like this:

Microsoft (R) Visual Basic .NET Compiler version 8.0.40607.16
for Microsoft (R) .NET Framework version 2.0.40607.16
Copyright (C) Microsoft Corporation 1987-2003. All rights reserved.


5. You now have 2 files. Copy them to your device or the emulator and run the exe (in fact, since they are retargetable, you can run the exe on the PC as well). That's it!

So, apart from the ability to mix languages without having to create separate dlls, what is the advantage of multifile assemblies? I am not sure. Maybe the search you did earlier has given you the answer, in which case let me know. There are some benefits listed here (and an example).

I would be much more excited if we could actually statically link the netmodules into a single file. This becomes reality in VS2005 on the desktop, but only for C++.

UPDATE: Turns out we can merge the netmodule into a single exe file.

.NET CF MVP Chat

Thu, December 9, 2004, 11:28 AM under MobileAndEmbedded
I've blogged before about the SDP chat. Today it was the MVP's turn to host the monthly chat. These are not MSFT employees and therefore the format of the chat is more of a troubleshooting session; there isn't much opportunity of obtaining official info on future features, etc. As always the experts got a standing ovation in the end.

So, once more, update your calendars with the chat dates you are interested in or keep missing out!

BackgroundWorker for CF 1.0

Mon, December 6, 2004, 10:50 AM under MobileAndEmbedded
TIP: Download the class at the bottom of this post

.NET 2.0 makes threading easier by offering a BackgroundWorker class (not sure if CF 2.0 will have it, though). Read on to find out how to take advantage of it today in the CF 1.0 (also works on the desktop .NET 1.1).

The beauty (for someone not into documentation like me) of implementing a desktop class for the CF is that you don't need to document its usage (to an extent). There are already MSFT samples (and others) for the full Fx's class, so all you have to do is preserve the interface and behaviour.

So this is my summary of the BackgroundWorker story with hyperlinks to msdn.

In its simplest:
1a. Create an instance of the class (new BackgroundWorker())
2a. Hook up to its events (DoWork, RunWorkerCompleted)
3a. Tell it you want to do some background work (RunWorkerAsync)
4a. It raises the event. In your DoWorkEventHandler method do your background stuff (without touching GUI of course)
5a. When done, your RunWorkerCompletedEventHandler method will run on the GUI

Let's add value [Pass state in, cancel from job]:
3b. Optionally pass an object to the worker method (RunWorkerAsync, DoWorkEventArgs.Argument)
4b. Optionally decide in your background work to cancel (DoWorkEventArgs.Cancel=true)
5b. In your RunWorkerCompletedEventHandler method, check whether the operation was cancelled (RunWorkerCompletedEventArgs.Cancelled)

It gets better [Get a result back]:
4c. From your background work, optionally pass a result to the GUI when it's finished (DoWorkEventArgs.Result)
5c. Check for it (RunWorkerCompletedEventArgs.Result)

Wait, there is more! [Progress notification]
2b. Additionally hook up to a progress event (ProgressChanged) if you configure the object to allow it (.WorkerReportsProgress)
4d. From your worker method, let the object know the percentage (ReportProgress) optionally passing some state (ReportProgress)
6. In your ProgressChangedEventHandler method that runs on the GUI, check the percentage (ProgressChangedEventArgs.ProgressPercentage) and optionally the state given (ProgressChangedEventArgs.UserState)

Finally [Cancel from outside the job]
2c. Optionally Configure the object to allow cancellation (WorkerSupportsCancellation) other than just from the background worker method itself
4e. In your worker method check periodically if a cancel has been issued (CancellationPending) and if it has proceed as 4b
7. From any place in the code, ask the worker to cancel (CancelAsync)

If you have VS2005 just drag and drop it from the toolbox and start playing with it (on the desktop, not the CF). Browse its interface in object browser (it is under System.dll in the System.ComponentModel namespace)

Also read:
How to: Run an Operation in the Background
Walkthrough: Implementing a Form That Uses a Background Operation (Highly recommended)

Note that with my CF implementation you cannot drag the component on a form, but instead you have to manually create it from code (the assumption being you will do that from the GUI thread).

Download the DLL here (works on all platforms/versions)
Get the VB source here
Get the C# source at the next drop of the SDF

UPDATE: Also read this comprehensive BackgroundWorker sample

Blog link of the week 49

Sun, December 5, 2004, 02:16 PM under Links
Where did you read about yet another CTP, new spaces for blogs, unit testing software release, the number one word for 2004 and an antisapm screensaver? ...not here...

Brad Adams shows how to validate parameters in security-sensitive operations; I would have never thought of that and probably still won't ever use it..how about you?

I bet you can't sleep at night [:-)] not knowing why Windows run the timer at 55ms

Go back to basics with a performance analysis of the ArrayList

Are you thankful?

Fri, December 3, 2004, 02:59 PM under dotNET

Threading blah blah

Thu, December 2, 2004, 03:00 PM under Events
Just came back from the local VBUG meeting session, where Benjamin Mitchell presented an introduction to .NET threading. It went down well but, every time I see someone presenting threading topics (and I have seen a few), I always think this stuff is hard to explain to others (it's hard enough knowing how to use it, but teaching it takes the biscuit).

The second thought that crossed my mind (besides that I should finally volunteer to run a session or two at VBUG), was how lucky the desktop guys are with all those resources in the Threading namespace (I cannot use them in my full Fx projects, as virtually all my desktop code runs on the CF as well).

He mentioned in passing how Whidbey makes life easier and that got me thinking: I have blogged about threading topics before but how much easier would it be to explain the usage of BackgroundWorker? I guess that has to be the subject next time.

Satellite Assemblies

Wed, December 1, 2004, 12:48 PM under MobileAndEmbedded
So we looked at how you change the language in a Compact Framework scenario and how we can read the current locale. The most popular reason for which users change language, is to read the text of your UI in their own language (profound statement or what? :-)

The .NET way of doing that is using RESX files and resource dlls (a.k.a. satellite assemblies). The process is very similar to the desktop scenario, but the file formats are incompatible (and that will be the case for CF 2.0 too). There is a lot of info on using RESX files, so I won't go into any detail here. (In a nutshell, in the designer you can set the Localizable property of your forms to true and then change the strings once per language; this creates a RESX file per form per language and, on compilation, all RESX of a language are rolled into a resources dll. When deploying your app, place each .resources dll in its own folder under your app's directory, naming each directory as per the two-letter language code. At runtime, the CLR picks up automatically the system's locale and hence which resources dll to load and life is goodness).

Note that the SatelliteContractVersion attribute is supported at compile time but does not work at runtime so don't use it. Essentially you must deploy all your satellite dlls with your exe every time you roll the version (unless the only change is the revision in which case they are considered compatible as per the CF rules).

Also note that, if you need additional strings for translation (e.g. MessageBox strings), they have to reside in their own resx file (that you create manually and must include as an embedded resource). To retrieve these you need to explicitly use the ResourceManager (i.e. like this).

Finally, you may find the CFResgen tool useful. It allows for conversion between txt/resx/resources files (tip: save your txt file as utf-8).

So I leave you with my approach:
I do not use the RESX files created by the forms, and in fact I leave Form.Localizable to false. Instead, I maintain one text file of name/value pairs and whenever I need a string in my app I add it to the txt file. The implication is that I set the Text for all controls outside the InitializeComponent method (ctor or OnLoad as appropriate). I then run cfresgen on the text file to get a single RESX file, which is the one included in my project as a resource. I send it to the translators and they send me back a translated RESX file that I also add to my project; from those, the compiler spits out the satellite assemblies. Note that our translators use a localisation tool that works great with RESX files, but we had one who did not have access to the tool, so sending them the txt file and then performing the conversion to RESX on our end worked out great. The attraction to the aforementioned method is the simplicity of dealing with a single txt file from which everything else stems.