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