March 2007 - Posts

Developer & IT Pro Days 2007 has come to an end. This year's edition in Ghent was in my opinion the best edition so far; congratulations to the entire organization: Tom, Ritchie, David, Arlindo, Wim and many others who made it a great success once more. I think the technical curiosity of the audience has been satisfied a bunch; let's make it even better next year!

For me, it was a quite busy week too. Yesterday, I delivered my talk on IIS 7.0 for developers, focusing on the most exciting features in the next-generation web application server platform from Microsoft. More specifically, we focused on extensibility using managed code (handlers and modules), the configuration system, the new IIS Manager and a bit of diagnostics and security. I'll post demo scripts and sample code later this week or beginning of next week, so stay tuned!

But Dev & IT Pro Days 2007 was also an important milestone for me. On the conference I made it official: starting October this year, I'll join the Microsoft Corporation headquarters in Redmond, WA to start to work on the WPF team, taking on a role as SDE in Building 10. I'll talk about the whole story later in a separate blog post.

PS: No worries, I'll keep blogging about exciting topics over here for the next couple of months!

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

Only two weeks left for this year's Belux Developer and IT Pro Days 2007. If you haven't registered yet, here are some good reasons to do so:

  • Two preconferences on March 27, covering Microsoft Virtualization and The Microsoft Web Story.
  • A total of 70 breakout sessions delivered by top speakers on March 28 and March 29.
  • Keynote delivered by David Chappell.
  • An end-to-end track on architecture by Ron Jacobs.
  • Meet your Developer and IT Pro peers to network (already over 1000 (!) attendees registered).
  • Visug geek bowling at the Overpoort, Ghent on Wednesday March 28. Register via www.visug.be.

Oh almost forget to mention my own covering Internet Information Services (IIS) 7.0: End-to-End Overview of Microsoft's New Application Web Server on 29 March 2007 at 9 AM (rescheduled!).

A few quick links of the organizers:

Don't hesitate any longer; this is your chance to stay tuned. Register now!

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

The latest Service Pack for Windows Server 2003 and Windows XP Pro x64, SP2, is ready to be downloaded from http://www.microsoft.com/technet/windowsserver/sp2.mspx. There a lots of enhancements that also have impact on developers:

  • XmlLite is a library that allows developers to write XML-driven apps that perform faster than the current MSXML/DOM and MSXML/SAX2 implementations.
  • MMC 3.0 is the next generation of the Microsoft Management Console technology, enabling managed code snap-ins explained on my blog previously (MMC 3.0 - A managed code 'task manager' MMC 3.0 snap-in). It's possible to use Windows Forms to be hosted inside a snap-in; the snap-in model is richer than before; there's the new actions pane; asynchronous execution increases reliability and user experience; etc.
  • ICALCS will be your next big friend if you deal with ACLs at lot. It's already in Vista.
  • SQL Server 2005 SP2 performance improvements.

A more complete overview is available over here.

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

To the Belgian developer (academic) audience: save the date. I'll deliver a (Dutch-spoken) session on .NET 3.0 at the Erasmushogeschool in Brussels on April 16, 2007 between 1 PM and 4 PM. More information can be found on Walter Stiers's Blog.

Topics covered during the session will be WPF, WCF, WF and WCS as well as a short sneak preview of "Orcas" (.NET 3.5 and Visual Studio tools).

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

You can find the original quiz over here. There have been lots of great answers, thanks to all readers! The bottom line however is that one should be careful when doing performance optimizations; in much cases the code doesn't become cleaner (even the opposite). One shouldn't trade design guidelines for speed unless there are very very good reasons to do so. An example includes trading a class for a struct (see Framework Design Guidelines for a full elaboration on these topics).

Below you can find a piece of code that illustrates a few performance optimizations. General recommendations include:

  1. Avoid the use of accessor functions like properties and structs if you can get to the data directly (without breaking encapsulation however).
  2. Calculations sometimes benefit from an accumulator variable, as illustrated below.
  3. Jagged arrays outperform multidimensional arrays because of a variety of reasons. See Performance Tips and Tricks in .NET Applications for more info; this article dates from the v1 ages of .NET but most guidelines still hold.

The code:

1 using System; 2 using System.Threading; 3 using System.Text; 4 using System.Diagnostics; 5 6 class Matrix 7 { 8 private double[,] m; 9 internal double[][] mj; 10 11 public Matrix(int dim0, int dim1) 12 { 13 m = new double[dim0,dim1]; 14 mj = new double[dim0][]; 15 for (int i = 0; i < dim0; i++) 16 mj[i] = new double[dim1]; 17 } 18 19 public int Height { get { return m.GetLength(0); } } 20 public int Width { get { return m.GetLength(1); } } 21 22 public double this[int x, int y] 23 { 24 get { return m[x,y]; } 25 set { m[x,y] = value; } //hasn't changed to set mj value - avoid perf influence 26 } 27 28 public static int algo = 0; 29 public static string desc; 30 31 public static Matrix operator*(Matrix m1, Matrix m2) 32 { 33 if (m1.Width != m2.Height) 34 throw new InvalidOperationException("Matrices should have compatible dimensions for multiplication."); 35 36 switch (algo) 37 { 38 case 1: 39 { 40 desc = "Avoid properties"; 41 int h = m1.Height; 42 int w = m2.Width; 43 int l = m1.Width; 44 Matrix m = new Matrix(h, w); 45 for(int i = 0; i < h; i++) 46 { 47 for(int j = 0; j < w; j++) 48 { 49 m[i,j] = 0; 50 for (int k = 0; k < l; k++) 51 m[i,j] += m1[i,k] * m2[k,j]; 52 } 53 } 54 return m; 55 } 56 57 case 2: 58 { 59 desc = "Avoid indexers"; 60 int h = m1.Height; 61 int w = m2.Width; 62 int l = m1.Width; 63 Matrix m = new Matrix(h, w); 64 for(int i = 0; i < h; i++) 65 { 66 for(int j = 0; j < w; j++) 67 { 68 m.m[i,j] = 0; 69 for (int k = 0; k < l; k++) 70 m.m[i,j] += m1.m[i,k] * m2.m[k,j]; 71 } 72 } 73 return m; 74 } 75 76 case 3: 77 { 78 desc = "Use accumulator variable"; 79 int h = m1.Height; 80 int w = m2.Width; 81 int l = m1.Width; 82 Matrix m = new Matrix(h, w); 83 for(int i = 0; i < h; i++) 84 { 85 for(int j = 0; j < w; j++) 86 { 87 double res = 0; 88 for (int k = 0; k < l; k++) 89 res += m1.m[i,k] * m2.m[k,j]; 90 m.m[i,j] = res; 91 } 92 } 93 return m; 94 } 95 96 case 4: 97 { 98 desc = "Use jagged arrays"; 99 int h = m1.Height; 100 int w = m2.Width; 101 int l = m1.Width; 102 Matrix m = new Matrix(h, w); 103 for(int i = 0; i < h; i++) 104 { 105 for(int j = 0; j < w; j++) 106 { 107 double res = 0; 108 for (int k = 0; k < l; k++) 109 res += m1.mj[i][k] * m2.mj[k][j]; 110 m.mj[i][j] = res; 111 } 112 } 113 return m; 114 } 115 116 case 5: 117 { 118 desc = "Go unsafe with multidimensional"; 119 int h = m1.Height; 120 int w = m2.Width; 121 int l = m1.Width; 122 Matrix m = new Matrix(h, w); 123 unsafe 124 { 125 fixed (double* pm = m.m, pm1 = m1.m, pm2 = m2.m) 126 { 127 int i1, i2; 128 for(int i = 0; i < h; i++) 129 { 130 i1 = i * l; 131 for(int j = 0; j < w; j++) 132 { 133 i2 = j; 134 double res = 0; 135 for (int k = 0; k < l; k++, i2 += w) 136 res += pm1[i1 + k] * pm2[i2]; 137 pm[i * w + j] = res; 138 } 139 } 140 } 141 } 142 return m; 143 } 144 145 default: 146 { 147 desc = "Naive"; 148 Matrix m = new Matrix(m1.Height, m2.Width); 149 for(int i = 0; i < m.Height; i++) 150 { 151 for(int j = 0; j < m.Width; j++) 152 { 153 m[i,j] = 0; 154 for (int k = 0; k < m1.Width; k++) 155 m[i,j] += m1[i,k] * m2[k,j]; 156 } 157 } 158 return m; 159 } 160 } 161 } 162 } 163 164 class Program 165 { 166 static void Main() 167 { 168 Random rand = new Random(); 169 Stopwatch sw = new Stopwatch(); 170 TimeSpan original = TimeSpan.FromSeconds(0); 171 172 Matrix m1 = new Matrix(20,30); 173 for (int i = 0; i < m1.Height; i++) 174 for (int j = 0; j < m1.Width; j++) 175 m1[i,j] = rand.Next(-100,100); 176 177 Matrix m2 = new Matrix(30,40); 178 for (int i = 0; i < m2.Height; i++) 179 for (int j = 0; j < m2.Width; j++) 180 m2[i,j] = rand.Next(-100,100); 181 182 Matrix ro = null; 183 184 { 185 sw.Start(); 186 for (int k = 0; k < 10000; k++) 187 ro = m1 * m2; 188 sw.Stop(); 189 original = sw.Elapsed; 190 Console.WriteLine("Original - {0}", original); 191 } 192 193 { 194 for (Matrix.algo = 1; Matrix.algo <= 5; Matrix.algo++) 195 { 196 Matrix r = null; 197 sw.Reset(); 198 sw.Start(); 199 for (int k = 0; k < 10000; k++) 200 r = m1 * m2; 201 sw.Stop(); 202 Console.WriteLine("Algo {0} - {1} {3} ({2:#.00}x)", Matrix.algo, sw.Elapsed, ((double)original.TotalMilliseconds) / sw.Elapsed.TotalMilliseconds, Matrix.desc); 203 } 204 } 205 } 206 }

Needless to say, performance figures will vary from machine to machine and on every execution. Over here the figures look roughly like this:

Original - 00:00:07.9269539
Algo 1   - 00:00:03.0053351 Avoid properties (2,64x)
Algo 2   - 00:00:02.5814237 Avoid indexers (3,07x)
Algo 3   - 00:00:02.4030079 Use accumulator variable (3,30x)
Algo 4   - 00:00:01.5665534 Use jagged arrays (5,06x)
Algo 5   - 00:00:01.0873534 Go unsafe with multidimensional (7,29x)

The last optimization is likely the most risky one since it uses unsafe code to get rid of bounds checking overhead. Unless you really know what you're doing, it's better to avoid unsafe code anyhow (a speed-up of a factor 5 just by applying managed code optimizations is great already!).

Have fun!

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

Time for another security feature in Windows Vista: WinSta0 isolation. The first question that might pop up in your head is "So, what exactly is WinSta0?". Keith Brown has the answer.

The problem with WinSta0 is the possibility for Windows Services to display a UI prompt in the window station. Pre-Vista, this prompt just appears on top of the desktop of the user logged on to the system. Because of this, the service is exceeding its boundary of isolation and the inware user is providing information across that "trust boundary".

Windows Vista reduces this risk by isolating WinSta0 from the active user's desktop; a user has to provide his/her consent to switch to the bare WinSta0 when that screams for attention (which is detected by an executable called UI0Detect.exe as displayed below):

When you see this kind of message, the app you're dealing with has "partial incompatibility with Windows Vista". The message to developers: fix it - Windows doesn't like the old approach anymore! An example I've been faced with in practice is the HP LaserJet 1020 software that uses WinSta0 to show out of paper messages and other printer maintenance messages.

In this post, I'm showing you the code for a demo of a WinSta0 isolation demo I gave some time ago, together with demonstration instructions.

 

Step 1 - Creating an interactive Windows Service

So, for sake of the demo, let's create something we really shouldn't have created: an interactive Windows Service. Open Visual Studio 2005 and create a new Windows Service project called "WinSta0Inspector" in C#:

Next, go to Service1.cs and change the service name to WinSta0Inspector:

Right-click the designer surface and choose Add Installer. This will create a new file ProjectInstaller.cs that makes the executable installutil.exe-able. In there, select the serviceProcessInstaller1 "control" and set the Account property to Local System (to make things really bad):

In order to make the service interactive, we'll create a simple Windows Form. Right click the project in the Solution Explorer, choose Add New Item and add a Windows Form called ExecuteCommand.cs. Design it so that it looks like this:

Hook up event handlers for both LinkLabels, with definitions like this:

private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { Process.Start("cmd.exe"); } private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { DialogResult = DialogResult.OK; }

Don't forget to import System.Diagnostics in order to have access to the Process class. Now go back to Service1.cs and switch to the code view. Define the Service1 class as follows:

public partial class Service1 : ServiceBase { private ExecuteCommand dialog = new ExecuteCommand(); public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { } protected override void OnCustomCommand(int command) { MessageBox.Show("Welcome to WinSta0.", "WinSta0 is calling you!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); dialog.ShowDialog(); } }

You'll need to import System.Windows.Forms to have access to MessageBox. This completes our interactive service.

 

Step 2 - Installing it

Compile the solution and switch to a Visual Studio 2005 Command Prompt which runs elevated with administrator privileges. Install the service using installutil -i WinSta0Inspector.exe. Then open the Services MMC snap-in (services.msc), locate the WinSta0Inspector service and change its properties to make it interactive:

Command-line freaks could also use the following command to install the service directly as an interactive service; no need to run installtutil then, just do this:

sc create WinSta0Inspector binPath= WinSta0Inspector.exe type= interact DisplayName= "WinSta0 Inspector"

 

Step 3 - Action!

In order to see it in action, start the service and send it a custom command. You could write another app to send the custom command using the System.Service.ServiceController::ExecuteCommand method, but sc.exe has everything we need:

First, we started the service using net start WinSta0Inspector. Next, we sent a command to the service by using sc control WinSta0Inspector 129 (valid commands should be higher than 128, other values are system-reserved). Right away you'll see the Interactive services dialog detection dialog popping up in the background:

Click Show me the message and Vista will bring you to the raw WinSta0 environment which should look somewhat like this:

Press OK in our message box; the WinForms dialog will show up now:

Feel free to take a look around WinSta0 using the command-prompt link on the form. For example, run whoami /all to find out about your SYSTEM power :-)

If you have a hacker's mindset you might find HKLM\SECURITY\SAM an attractive place to visit while you're the Windows übermensch :o. Below you can see a few other screenshots of what it is like to be in WinSta0 (e.g. how did I create the screenshots?):

 

Have fun!

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

Note: This article applies to the Visual Studio "Orcas" March 07 CTP build that can be downloaded from the Microsoft website.

In this post we'll talk about embedding UAC (User Account Control) manifests in managed code executables without having to rely on rather dirty tricks, as I explained in my older blog post entitled Windows Vista - Demand UAC elevation for an application by adding a manifest using mt.exe. Please read this post prior to reading this post, in order to get a good idea about UAC and manifests.

Essentially, this article performs a little word substitution on the title of the previous post: adding a manifest using mt.exe using Visual Studio "Orcas".

 

Step 1 - Creating the Windows Forms app

We'll start by creating the same app as we did in the previous post mentioned above. Open up VS "Orcas", create a new (C#) Windows Forms project called UacDemo and add a label called "label1" to the designer surface. As a side-note, play around with the IDE designer for Windows Forms a bit, you'll see that the Layout toolbar has been revamped (for example, add another label, select both labels and observe the options in this toolbar):

Next, go to the code and add an event handler for Form1_Load that does the following:

label1.Text = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator) ? "Yup" : "Nope";

You'll need to bring the System.Security.Principal namespace in scope in order to compile the code above.

 

Step 2 - Add a manifest to the project

Add a new item to the project and choose for an XML file. Call it UacDemo.exe.manifest:

Add the following contents to it:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="UacDemo" type="win32"/> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="requireAdministrator"/> </requestedPrivileges> </security> </trustInfo> </assembly>

Notice that the name attribute of the assemblyIdentity element has to be set to the name of the executable (without .exe extension). Information about UAC manifests can be found by searching "requestedPrivileges" on the internet for instance.

 

Step 3 - Tell the build environment to include the manifest

This is where things got difficult in the past. A solution pre-Orcas was explained on my aforementioned previous blog entry on UAC using a post-build step calling the mt.exe tool. Now, things have become much more simple. Just go to the properties of the project, tab Application and scr