August 2006 - Posts

Introduction

One of the goals of workflows in general is to make "logic", "business processes", etc more visible by having a graphical representation of these. At design time it's pretty easy to compose a workflow using the Visual Studio 2005 designer but to this extent a workflow stays pretty static. So what about adapting or modifying a workflow at runtime? In this series of posts I'll outline various methodologies to modify a running workflow. For part one of this series, take a look over here.

Modification from the outside

In the previous part we've been looking at workflow modification from the inside. One of the problems with such an approach is that the workflow has to be prepared in some way or another to allow changes. That is, code must be present inside the workflow to make the changes. For that reason it might be more interesting in some scenarios to make the change from the ouside. This is what we'll be looking at for now.

Consider the workflow from the previous part again, but now with the first set of activities disabled as shown below. Of course you can just neglect those and create a new empty workflow and add the non-disabled stuff. I just want to point out the powerful "comment out" feature in WF once more :-).

Again we stick with simple CodeActivity activities, this time with the following ExecuteCode definitions:

private void killMeFromOutsideActivity_ExecuteCode(object sender, EventArgs e)
{
   Console.WriteLine("I should have been dead by now!"
);
}

private void HappyEndActivity_ExecuteCode(object sender, EventArgs
e)
{
   Console.WriteLine("The happy end :-)"
);
}

In order to change the workflow from the outside we need to reach a (what I use to call) "safe point". Tol illustrate this, I'm showing you the use of a SuspendActivity. Over to the hosting code now:

using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
   AutoResetEvent waitHandle = new AutoResetEvent(false
);
workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs
e) {waitHandle.Set();};
   workflowRuntime.WorkflowTerminated +=
delegate(object sender, WorkflowTerminatedEventArgs
e)
   {
      Console
.WriteLine(e.Exception.Message);
      waitHandle.Set();
   };

   workflowRuntime.WorkflowSuspended +=
new EventHandler<WorkflowSuspendedEventArgs
>(workflowRuntime_WorkflowSuspended);

   Dictionary<string, object> arguments = new Dictionary<string, object
>();
   arguments.Add(
"AllowUpdates", true
);

   WorkflowInstance
instance = workflowRuntime.CreateWorkflow(typeof(DynamicWf.Workflow1), arguments);
   instance.Start();

   waitHandle.WaitOne();
}

Most of the code is the same as in part 1. Recall that the AllowUpdates argument is used to determine whether updates are allowed or not by using it inside the workflow's DynamicUpdateCondition Code Condition. So, you can just ignore this for now and in case you're starting from an empty workflow, just ignore this piece of code.

The most important piece of code however is the following:

   workflowRuntime.WorkflowSuspended += new EventHandler<WorkflowSuspendedEventArgs>(workflowRuntime_WorkflowSuspended);

with the following corresponding event handler:

static void workflowRuntime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs e)
{
   Console.WriteLine("I'm suspended"
);

   WorkflowInstance
workflowInstance = e.WorkflowInstance;
   Activity
wRoot = workflowInstance.GetWorkflowDefinition();

   WorkflowChanges changes = new WorkflowChanges
(wRoot);
   changes.TransientWorkflow.Activities.Remove(changes.TransientWorkflow.Activities[
"KillMeFromOutsideActivity"
]);

   try
   {
      workflowInstance.ApplyWorkflowChanges(changes);
   }
   catch (InvalidOperationException ex)
   {
      Console.ForegroundColor = ConsoleColor.Red;
      Console.WriteLine("No update allowed - " + ex.Message);
      Console.ResetColor();
   }


   Console.WriteLine("Let's resume"
);
   e.WorkflowInstance.Resume();
}

The code displayed above should be pretty self-explanatory. Again the WorkflowChanges class is at the center of the update logic. In order to obtain a reference to the running (correction: at this point suspended) workflow we can use the WorkflowSuspendedEventArgs argument's WorkflowInstance property.

Note: An important thing is to call ApplyWorkflowChanges on the workflow object of which the root activity (GetWorkflowDefinition) was passed to the WorkflowChanges constructor. I've run into some troubles when experimenting with this and the code above is the only one which is correct.

The result should look like this:

Again, when making the workflow's DynamicUpdateCondition evaluate to false (see previous episode), as shown below, the update will fail:

   Dictionary<string, object> arguments = new Dictionary<string, object>();
   arguments.Add(
"AllowUpdates", false);

Happy WF-ing once again!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Introduction

Conditional compilation is one of the much unknown powerful features that are available in .NET and more specifically in the C#, VB.NET and J# compilers. In this post, I'd like to show you how to take benefit from this feature, applied to C#.

An example

using System;
using
System.Diagnostics;

class
Program
{
   static void Main(string
[] args)
   {
      DebugLog(
"Before loop"
);

      for (int
i = 0; i < 10; i++)
         Console
.WriteLine(i);

      DebugLog(
"After loop"
);
   }

   [
Conditional("DEBUG")]
   private static void DebugLog(string
s)
   {
      Console
.WriteLine(s);
   }
}

First compile the program using one of the following options:

  1. In Visual Studio 2005 with the active configuration set to Debug.
  2. On the command-line using csc /define:DEBUG Program.cs. (Note: this is not the same as csc /debug+ Program.cs)
  3. Add #define DEBUG in the program code.

When you execute the program, you'll see:

Before loop
0
1
2
3
4
5
6
7
8
9
After loop

In the IL code you'll see something like this:

IL_0000: nop
IL_0001: ldstr "Before loop"
IL_0006: call void Program::DebugLog(string)
IL_000b: nop
IL_000c: ldc.i4.0
IL_000d: stloc.0
IL_000e: br.s IL_001b
IL_0010: ldloc.0
IL_0011: call void [mscorlib]System.Console::WriteLine(int32)
IL_0016: nop
IL_0017: ldloc.0
IL_0018: ldc.i4.1
IL_0019: add
IL_001a: stloc.0
IL_001b: ldloc.0
IL_001c: ldc.i4.s 10
IL_001e: clt
IL_0020: stloc.1
IL_0021: ldloc.1
IL_0022: brtrue.s IL_0010
IL_0024: ldstr "After loop"
IL_0029: call void Program::DebugLog(string)
IL_002e: nop
IL_002f: ret

Nothing special going on despite the declaration of the [Conditional("DEBUG")] attribute. However, let's compile the same application now as a release build:

  1. In Visual Studio 2005 with the active configuration set to Release.
  2. On the command-line using csc Program.cs.

Now the output will be:

0
1
2
3
4
5
6
7
8
9

and the corresponding IL is:

IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0010
IL_0005: ldloc.0
IL_0006: call void [mscorlib]System.Console::WriteLine(int32)
IL_000b: nop
IL_000c: ldloc.0
IL_000d: ldc.i4.1
IL_000e: add
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: ldc.i4.s 10
IL_0013: clt
IL_0015: stloc.1
IL_0016: ldloc.1
IL_0017: brtrue.s IL_0005
IL_0019: ret

So, no single call to the DebugLog method was emitted in the Main's code. Powerful isn't it? The coolest thing about all this is that you don't have to decorate your code using a bunch of #if statements, like this:

   static void Main(string[] args)
   {
#if DEBUG
      DebugLog(
"Before loop"
);
#endif

      for (int
i = 0; i < 10; i++)
         Console
.WriteLine(i);

#if DEBUG
      DebugLog("After loop");
#endif
   }

One advantage of the latter approach might be that you can also #if DEBUG ... #endif the DebugLog method itself. Using conditional compilation the DebugLog method will get compiled no matter what.

A few remarks to conclude:

  • The ConditionalAttribute can only be applied to methods and to attribute classes (that is: classes that derive from System.Attribute). Thus property and event accessors can't be decorated using this attribute.
  • The Debug and Trace classes of the .NET Framework use the ConditionalAttribute. So you don't have to worry about any performance hit whatsoever when you call various methods of these classes as a debugging aid. These calls just won't make it in the release build (or better: non-debug builds), e.g.:

    [Conditional("DEBUG")]
    public static void Assert (
        bool condition
    )

  • The C++ compiler doesn't support the ConditionalAttribute; you'll have to rely on #if conditionals to include/exclude debugging code.
  • The ConditionalAttribute allows multiple decorations per method (or attribute class):

    [AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Method, AllowMultiple=true)]

    Therefore you can do things such as (cf. section 17.4.2.2 of the C# specification):

       [Conditional("ALPHA")]
       [Conditional("BETA")]
       private static void DebugLog(string
    s)
  • Attribute decorations are emitted to the metadata of a class. Because of this, you can get ConditionalAttribute working across languages and assemblies. An example of a class definition in C#:

    public static class Helper
    {
       [Conditional("DEBUG")]
       public static void DebugLog(string
    s)
       {
          Console
    .WriteLine(s);
       }
    }


    and its usage in VB:

    Class Program
       Shared Sub Main()
          Helper.DebugLog(
    "Before loop"
    )

          Dim As Integer
          For
    i = 0 To 10
             Console
    .WriteLine(i)

          Helper.DebugLog(
    "After loop"
    )
       End Sub
    End Class

    This will yield the same result as the C# only example, because the VB compiler can find out (using the metadata of class Helper) that calls to DebugLog should only be made when a DEBUG build is made.

References

Enjoy!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

The problem statement

One of my friends asked me how to implement some kind of "process monitor" that makes sure a (system) process stays alive. In this sample I'm showing you how to implement such a thing in C#. An alternative situation would be to monitor a Windows Service but the SCM (Service Control Manager) in Windows can take care of that (tab Recovery).

The code

using System;
using
System.Diagnostics;

class
Demo
{
   public static void
Main()
   {
      Launch();
      Console
.ReadLine();
   }

   private static void
Launch()
   {
      ProcessStartInfo psi =
new
ProcessStartInfo();
      psi.FileName =
"notepad.exe"
;

      Process p =
new
Process();
      p.StartInfo = psi;
      p.EnableRaisingEvents =
true
;
      p.Exited +=
LaunchAgain; //C# 2.0 syntax - alternative: p.Exited += new EventHandler(LaunchAgain);

      p.Start();
   }

   private static void LaunchAgain(object o, EventArgs
e)
   {
      Console.WriteLine("Process was killed; launching again"
);
      Launch();
   }
}

!!! Warning !!!

  1. Don't use this to annoy people with a non-disappearing prgram.
  2. Of course, the monitoring process can still crash (or be terminated). This is a chicken-egg situation but of course you can't create an endless chain of monitors.
  3. Security matters! A process that crashes can be the indication of a security problem or risk (e.g. a compromised service). In case of unmanaged code a buffer overrun (maybe as part of an attack) could be the reason the process stops. So, you shouldn't restart the process forever. It's better to have a maximum amount of automatic process restarts, just like the SCM only permits three service restarts.

Keep it alive and have fun!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Passioned about Visual Studio 2005? Then this should be something for you. On Friday 8 September, Steven Wilssens will deliver a full day training on Visual Studio 2005 Team System for the Visual Studio User Group Belgium (VISUG). More information can be found on www.visug.be. Unfortunately I'm unable to attend, but hope to see you on some other Belgian event soon.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Introduction

For quite a while now, I'm running on Windows Vista build 5472 as my daily operating system. Without big troubles, so I'm a happy man. However, I couldn't resist to download build 5536 a couple of days ago to give it a try. I'll install it on my main machine on a separate harddisk later on (especially to take benefit from my graphics hardware) but for now I decided to run it in a virtualized environment. Here's how.

The situation

  • Windows Vista build 5472 as primary OS on my laptop (Dell Inspiron 9400), running various betas such as the 2007 Microsoft Office System.
  • Goal: running Windows Vista build 5536 on top of that in Virtual Server 2005.

The procedure

  1. Go to http://connect.microsoft.com and download the latest build of Virtual Server 2005 R2 SP1.
  2. Make sure you have installed IIS7 (see Windows Components) on the machine and install Virtual Server 2005 R2 SP1.
  3. After the installation, opening the Virtual Server 2005 Administration Website will fail:



    To solve this, go to the start menu, find a shortcut to Internet Explorer under All Programs, right-click and choose "Run as administrator". The website should appear fine then.
  4. Create a new virtual machine but allocate enough memory (in my case I've allocated 1GB of RAM).
  5. Put the burned ISO (vista_5536.16385.060821-1900_vista_rc1_x86fre_client-LR1CFRE_EN_DVD.iso) in the DVD drive of the system. Note: I've burned the ISO to a DVD-RW disc because I want to run the setup on other machines too. I didn't try to mount the ISO file (VS2005 has or had a limitation of a maximum of 2.2GB ISO files). You might be successful to mount the ISO under the guest OS using some mount tool and use that "virtual drive" in Virtual Server to start setup from.
  6. Boot the virtual machine and run the installation. This will take quite some time to complete. Be patient.
  7. When the installation has completed, Vista will run very slow inside the virtual machine. This is not due to the beta but due to the lack of Virtual Machine Additions. The solution: go back to http://connect.microsoft.com, again to the Virtual Server 2005 R2 SP1 beta program and download the Virtual Machine Additions for Vista Beta 2. The site mentions compatibility up to build 5472 but it seems to work very well on build 5536 too:

Have fun!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Introduction

One of the goals of workflows in general is to make "logic", "business processes", etc more visible by having a graphical representation of these. At design time it's pretty easy to compose a workflow using the Visual Studio 2005 designer but to this extent a workflow stays pretty static. So what about adapting or modifying a workflow at runtime? In this series of posts I'll outline various methodologies to modify a running workflow.

Modification from the inside

One of the options to change a workflow is doing it from the inside. Basically this means that the "basic" logic of the workflow foresees that something might have to be changed and that the workflow modifies itself (from the inside) when certain criteria are met. Assume the following workflow but ignore the disabled activities (marked with a green background) - we'll examine these in another blog post because these illustrate modifying a workflow from the outside:

We have - for illustration purposes and to keep things simple - four CodeActivity activities and one DynamicSequenceActivity. Under normal (non-modification) circumstances the system would execute these one after another in a sequential order; Our goal is to add and remove activities in this workflow.

Modification 1 - Adding another activity

Assume we want to add another activity dynamically in between the SelfModificationActivity and the AnotherModificationActivity (you could choose another position too however). An ideal place to do that is inside the SelfModificationActivity, in a real situation based on some decision logic. In our case, we're just going to make the change under any circumstance. Take a look at the ExecuteCode handler logic for the SelfModificationActivity:

private void SelfModificationActivity_ExecuteCode(object sender, EventArgs e)
{
   Console.WriteLine("This is the SelfModificationActivity speaking"
);

   WorkflowChanges wc = new WorkflowChanges(this
);
   MyActivity ma = new MyActivity("With greetings from SelfModificationActivity"
);
   wc.TransientWorkflow.Activities.Insert(1, ma);

   try
   {
      this
.ApplyWorkflowChanges(wc);
   }
   catch (InvalidOperationException
ex)
   {
      Console.ForegroundColor = ConsoleColor.Red;
      Console.WriteLine("No update allowed - "
+ ex.Message);
      Console
.ResetColor();
   }
}

The most important class to notice in here is the WorkflowChanges class. As the API describes this class is the wrapper around a set of proposed changes to a workflow. Therefore applying the changes using the ApplyWorkflowChanges method can throw an exception - something I'll illustrate later on. In this piece of code I'm just adding another activity on position 1 of the workflow (that is, immediately after the SelfModificationActivity). This index-based modification might not be the most ideal way of working, but it's a nice mind-setting example to start with.

The code displayed above inserts an activity of type MyActivity. What's going on in there isn't very important for the sake of the demo, but here is a possible definition for our demo:

public partial class MyActivity: SequenceActivity
{
   private string
message;

   public
MyActivity()
   {
      InitializeComponent();
   }

   public MyActivity(string message) : this
()
   {
      this
.message = message;
   }

   private void MainActivity_ExecuteCode(object sender, EventArgs
e)
   {
     
Console.WriteLine("This is the MyActivity speaking - "
+ message);
   }
}

Modification 2 - Deleting an activity

Deleting an activity can be an interesting option to skip certain activities under some circumstances where logic isn't expressed in the workflow itself (you might consider an if-else structure in the workflow to get a similar and designer-visible effect). Nevertheless, let's assume you want to remove an activity from the running workflow instance at runtime based on some conditions (of which the logic might be loaded at runtime, e.g. using reflection). More specifically I want to kill the DeadManWalkingAcitivity:

private void DeadManWalkingActivity_ExecuteCode(object sender, EventArgs e)
{
   Console.WriteLine("If you can see this, you are God :o"
);
}

The code to remove this activity will be added to the AnotherModificationActivity's ExecuteCode handler:

private void AnotherModificationActivity_ExecuteCode(object sender, EventArgs e)
{
   Console.WriteLine("Let's kill the dead man"
);

   WorkflowChanges wc = new WorkflowChanges(this
);
   Activity deadman = wc.TransientWorkflow.GetActivityByName("DeadManWalkingActivity"
);
   wc.TransientWorkflow.Activities.Remove(deadman);

   try
   {
      this
.ApplyWorkflowChanges(wc);
   }
   catch (InvalidOperationException
ex)
   {
      Console.ForegroundColor = ConsoleColor.Red;
      Console.WriteLine("No update allowed - "
+ ex.Message);
      Console
.ResetColor();
   }
}

Again, the general approach is the same. Use a WorkflowChanges object, manipulate the TransientWorkflow's Activities collection (in this case by calling Remove) and call ApplyWorkflowChanges passing in the WorkflowChanges object with proposed changes. In this piece of code however, the activity to be removed is retrieved by name, not by some index number using GetActivityByName.

Modification 3 - Using the SequenceActivity

A third possibility is to foresee a placeholder in which activities will be loaded dynamically at runtime. Instead of filling out the "Drop activities here" at design time, we'll add activities in there at runtime. For demo purposes, the code to do this will be added to the DynamicSequenceActivity CodeActivity:

private void DynamicSequenceActivity_ExecuteCode(object sender, EventArgs e)
{
   if (dynamicActivityType == null
)
      return
;

   Type t = Type
.GetType(dynamicActivityType);

   WorkflowChanges wc = new WorkflowChanges(this
);
   Activity a = t.Assembly.CreateInstance(t.FullName) as Activity
;
   ((
SequenceActivity)wc.TransientWorkflow.GetActivityByName("DynamicSequence"
)).Activities.Add(a);

   try
   {
      this
.ApplyWorkflowChanges(wc);
   }
   catch (InvalidOperationException
ex)
   {
      Console.ForegroundColor = ConsoleColor.Red;
      Console.WriteLine("No update allowed - "
+ ex.Message);
      Console
.ResetColor();
   }
}

Instead of just statically adding some activity, we're using reflection in the demo above to load an activity from the type specified as "dynamicActivityType". Again for demo purposes, this variable is just a simple property in the workflow class:

private string dynamicActivityType;

public string
DynamicActivityType
{
   get { return
dynamicActivityType; }
   set { dynamicActivityType = value
; }
}

This property is set when starting the workflow (e.g. upon calling a webservice method) but one can imagine various sources to get this property value from (e.g. a database). To illustrate setting this property, look at the following piece of demo code:

static void Main(string[] args)
{
   using(WorkflowRuntime workflowRuntime = new WorkflowRuntime
())
   {
      AutoResetEvent waitHandle = new AutoResetEvent(false
);
      workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs
e) {waitHandle.Set();};
      workflowRuntime.WorkflowTerminated +=
delegate(object sender, WorkflowTerminatedEventArgs
e)
      {
         Console
.WriteLine(e.Exception.Message);
         waitHandle.Set();
      };

      Dictionary<string, object> arguments = new Dictionary<string, object
>();
     
arguments.Add("DynamicActivityType", "DynamicWf.DynamicallyLoadedActivity, DynamicWf"
);

      WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(DynamicWf.Workflow1
), arguments);
      instance.Start();

      waitHandle.WaitOne();
   }
}

In this case, I'm just referring to "DynamicWf.DynamicallyLoadedActivity, DynamicWf" in the same assembly but you can make it much more flexible of course. You can think of some "DynamicallyLoadedActivity" yourself, just define a custom activity of your choice. An example is (how original again :$) a one-CodeActivity-wrapping custom activity with the CodeActivity's ExecuteCode set so:

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
   Console.ForegroundColor = ConsoleColor.Green;
   Console.WriteLine("Greetings from a dynamic friend!"
);
   Console
.ResetColor();
}

The result

Executing the workflow constructed above (ignore the disabled activities for a while) yields the following result:

This is exactly the result we expected: the MyActivity was inserted on the right position; the "dead man activity" wasn't executed and another activity (DynamicallyLoadedActivity) was - as the name implies - loaded dynamically using reflection.

Changes allowed?

You might be concerned about the fact that a workflow seems to allow dynamic updates at all times, especially when we'll be looking (in a next post) at modifications from the outside. The good news is that there is a way for a workflow to decide on whether it allows updates to be made or not. This is done by setting the DynamicUpdateCondition property of the defined workflow. You can use a "Declarative Rule Condition" or a "Code Condition". Let's choose the latter option for now:

The corresponding code looks as follows:

private void CanBeUpdated(object sender, ConditionalEventArgs e)
{
   e.Result = allowUpdates;
}

Making the decision whether updates are allowed or not can be a complex piece of code of course, but let's stick to simplicity again and just use a boolean property for this purpose:

private bool allowUpdates;

public bool
AllowUpdates
{
   get { return
allowUpdates; }
   set { allowUpdates = value
; }
}

The decision is then communicated back using the ConditionalEventArgs's Result property. To illustrate the result in case of dynamic update denial, consider the following host code that sets the AllowUpdates property at startup of the workflow instance:

static void Main(string[] args)
{
   using(WorkflowRuntime workflowRuntime = new WorkflowRuntime
())
   {
      AutoResetEvent waitHandle = new AutoResetEvent(false
);
      workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs
e) {waitHandle.Set();};
      workflowRuntime.WorkflowTerminated +=
delegate(object sender, WorkflowTerminatedEventArgs
e)
      {
         Console
.WriteLine(e.Exception.Message);
         waitHandle.Set();
      };

      Dictionary<string, object> arguments = new Dictionary<string, object
>();
      arguments.Add("AllowUpdates", false);

     
arguments.Add("DynamicActivityType", "DynamicWf.DynamicallyLoadedActivity, DynamicWf"
);

      WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(DynamicWf.Workflow1
), arguments);
      instance.Start();

      waitHandle.WaitOne();
   }
}

When executing the code now, you'll see the following:

As you can see, every time the ApplyWorkflowChanges method is called, the dynamic update condition is evaluated. In case it evaluates to false, an InvalidOperationException is thrown, which gets caught by our update-code that foresees this possibility:

   try
   {
      this
.ApplyWorkflowChanges(wc);
   }
   catch (InvalidOperationException
ex)
   {
      Console.ForegroundColor = ConsoleColor.Red;
      Console.WriteLine("No update allowed - "
+ ex.Message);
      Console
.ResetColor();
   }

Happy WF-ing!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

The story

In the beta 2 ages of Windows Vista, I decided to give BitLocker Drive Encryption a try. It turned out to be pretty straightforward to turn this feature on (using a USB key for key storage as my laptop lacks a TPM) by just going to the Control Panel, Security and the BitLocker Drive Encryption "snap-in":

A few weeks later however I found myself cleaning my whole harddisk, kicking out the Windows XP installation that was still there on another partition and which was barely booted after my Vista Beta 2 installation, and installing build 5472 (which I'm still posting this blog entry in). Switching on BitLocker wasn't so easy this time however, Vista kept complaining about my harddisk partitioning.

So what's the problem? On my beta 2 installation I had a separate (unencrypted) partition with Windows XP and another one with Windows Vista. During installation, the (new) boot loader ended up on the XP partition. When turning on BitLocker, the entire Vista partition is encrypted and the bootloader is able to detect that booting Vista requires the BitLocker key to be loaded (in my case from USB as there is no TPM in the machine to get the key from).

However, on my 5472 installation, I didn't create such a partition and allocated the entire disk for Vista. So, there was no (unencrypted) place left on the harddisk to put the boot loader in and BitLocker refused to work.

Installing Vista with BitLocker in mind

Check out the following page for more information: http://www.microsoft.com/technet/windowsvista/library/c61f2a12-8ae6-4957-b031-97b4d762cf31.mspx#BKMK_S1. It guides you through the diskpart work you have to do prior to setup in order to get BitLocker to work properly. Notice that the Windows Vista setup is fully Windows-based (thanks to Windows PE) and things such as recovery are now fully GUI-based. Vista brings clarity, even to the setup :-). To go short, this is what you should do:

  • Make one primary partition for the Vista installation and assign it drive letter C
  • Shrink that partition with 1.5 GB (wonder why this should be so much)
  • Make a second primary partition on the 1.5 GB of free space and assign it drive letter S
  • Format both partitions as NTFS
  • Install Vista on C

Turning on BitLocker should now be as easy as clicking through a few dialogs and waiting for disk encryption to complete (in the meantime you can just continue to work).

Check out the BitLocker team blog on http://blogs.technet.com/bitlocker/ too. There is some very good news in there on the field of this partitioning need. It appears the team is working on a (re-)partitioning tool to make the system BitLocker ready after installation. Fingers crossed to see the result in a later build...

You might wonder what goes on the S: partition. The answer is the boot loader, which is completely revampes compared to Windows NT <= 5.2. No boot.ini anymore. This is what my S drive looks like:

S:\>dir /a /S
 Volume in drive S has no label.
 Volume Serial Number is 78B8-4F3A

 Directory of S:\

26/07/2006  01:17    <DIR>          Boot
14/07/2006  08:40           432.696 bootmgr
26/07/2006  01:17             8.192 BOOTSECT.BAK
               2 File(s)        440.888 bytes

 Directory of S:\Boot

26/07/2006  01:17    <DIR>          .
26/07/2006  01:17    <DIR>          ..
27/08/2006  23:36            24.576 BCD
27/08/2006  23:36            21.504 BCD.LOG
26/07/2006  01:17                 0 BCD.LOG1
26/07/2006  01:17                 0 BCD.LOG2
14/07/2006  15:25             1.024 bootfix.bin
26/07/2006  01:17            65.536 bootstat.dat
26/07/2006  01:17    <DIR>          en-US
14/07/2006  08:22           219.648 fixfat.exe
14/07/2006  08:22           231.936 fixntfs.exe
26/07/2006  01:17    <DIR>          Fonts
14/07/2006  08:37           381.512 memtest.exe
               9 File(s)        945.736 bytes

 Directory of S:\Boot\en-US

26/07/2006  01:17    <DIR>          .
26/07/2006  01:17    <DIR>          ..
14/07/2006  15:25            61.440 bootmgr.exe.mui
14/07/2006  15:26            35.840 memtest.exe.mui
               2 File(s)         97.280 bytes

 Directory of S:\Boot\Fonts

26/07/2006  01:17    <DIR>          .
26/07/2006  01:17    <DIR>          ..
06/07/2006  17:16         3.694.184 chs_boot.ttf
06/07/2006  17:16         3.876.932 cht_boot.ttf
06/07/2006  17:16         1.984.144 jpn_boot.ttf
06/07/2006  17:16         2.371.272 kor_boot.ttf
06/07/2006  17:16            47.556 wgl4_boot.ttf
               5 File(s)     11.974.088 bytes

     Total Files Listed:
              19 File(s)     13.458.233 bytes
              18 Dir(s)   1.522.487.296 bytes free

A few interesting things are the memtest.exe that can test your RAM memory for problems (which used to be a Microsoft Online Crash Analysis tool in the past, see http://oca.microsoft.com/en/windiag.asp for a free download of it), the fixntfs.exe program (what's in a name?) and the directory structure as a whole. This whole thing listens to the name "Boot Configuration Data Store" or BCD store. More information on the BCD and the bcdedit tool that comes with Vista (as a replacement for the boot.ini-related recovery console tools in the past) can be found on http://www.microsoft.com/technet/windowsvista/library/85cd5efe-c349-427c-b035-c2719d4af778.mspx.

On to Windows Vista RC1. Last week I've downloaded build 5536 which is still pre-RC1 which I intend to install on my second machine. Once the final RC1 build hits the roads, it will become my day-to-day OS on this machine.

Have fun!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Windows Workflow Foundation (WF) is one of the key pillars of the .NET Framework 3.0 (formerly known as WinFX), next to Windows Presentation Foundation (WPF), Windows Communication Foundation (WCF) and Windows CardSpace (WCS). If you haven't done so, download the July CTP now.

A personal opportunity

Now, why am I telling you this? Historically, I've been avoiding BizTalk-related stuff just to be able to concentrate on the basic stuff I'm usually spending time with, such as CLR, C# language features, the BCL, SQL Server, web services, etc. Learning to work with another server product like BizTalk implies yet another learning curve and time was rather limited. But enough boring excuses.

Workflow is more widely accepted than a few years ago and is growing up to become (if it isn't already) a mainstream paradigm in software development. Combine this with the opportunity to write a university thesis on workflow (at UGent) and guess what Bart said to himself a couple of months ago? Indeed, time to enter the world of Windows Workflow Foundation. The research subject is entitled "Dynamic and Generic Workflows with WF", quite a broad definition with a lot of freedom. One of the things that will be researched is how to adapt workflows dynamically under various (stress) conditions. So, stay tuned for additional information on WF-related experiments.

Reading resources

In the meantime I recommend the following book, which was handed out at the PDC 05 last year. It's already quite outdated due to "CTP madness" (well, I should say "evolution", we're talking about technologies which are still under development