 MSDN Magazine March 2003

MSDN Magazine March 2003

Visual Studio .NET: What You Need to Know Today About the New and Upgraded Features in Visual Studio .NET 2003

Any time an upgrade of a favorite tool is released, questions about compatibility, versioning, and changes in methodology abound. The release of Visual Studio .NET 2003 is no exception. Developers will be relieved to learn that breaking changes have been kept to a minimum, and delighted to learn that important new features, like Visual J#, have been added. These and other new features of the .NET Framework 1.1 and Visual Studio .NET 2003, including mobile support and improved debugging, are discussed here.

Carl Franklin Visual C++ .NET: Language Enhancements and Simplified GUI Development Enrich Your C++ Apps

Managed Extensions for C++ is the preferred programming language for developing Windows Services. Visual Studio .NET 2003 introduces C++ support for designers, providing all the RAD facilities that were available to other languages for developing forms, controls, components, and DataSets. Furthermore, support has been added for the creation of verifiable assemblies with C++.In this article, the author reviews these additions as well as the new compiler and linker switches, demonstrating how C++ remains the premier systems language while becoming a powerful tool for .NET GUI development as well.

Richard Grimes Windows Forms: .NET Framework 1.1 Provides Expanded Namespace, Security, and Language Support for Your Projects

With the much-anticipated release of the .NET Framework 1.1, developers are eager to know what's been added to their programming bag of tricks. In this article, the author focuses on new developments in Windows Forms, such as namespace additions, support for hosting managed controls in unmanaged clients, and designer support for C++ and J#. Integrated access to the Compact Framework and new mobile code security settings also make this release noteworthy. Along with these features, the author reviews the best ways to handle multiple versions of the common language runtime and highlights some potential pitfalls.

Chris Sells Smartphones: Design Robust Apps that Take Advantage of Windows CE-powered Smartphone Devices

Smartphone applications promise to be at the crest of a new wave of cell phone advances as the familiar process of using Microsoft dev tools can produce cutting-edge mobile phone applications. Because Smartphones are Windows-powered devices, developers can easily and inexpensively extend both new and time-tested business applications to mobile users. These applications will possess the necessary levels of enterprise functionality while integrating mobile phone features through the use of several easy to use APIs. This article looks at the basics of building a real-world business application for the Smartphone.

Chris Dellinger Site Skinning: Rich XML Classes Let Users Personalize Their Visual Experience on Your ASP.NET Site

One way that Web sites and applications become better able to meet the needs of customers is by allowing them to personalize their experience. For Web sites, this means displaying the content as the user wants to see it. For rich-client applications, this often means allowing the user to choose the user interface through a technique known as skinning, which is similar to themes in Windows XP. This article shows how you can apply skinning to Web sites, wrapping their functionality in a new user interface. The technique uses the rich XML classes in the .NET Framework and the built-in extensibility of ASP.NET.

Harry Pierson Contexts in .NET: Decouple Components by Injecting Custom Services into Your Object's Interception Chain

The .NET Framework can use contexts as an object's execution scope and intercept calls going to and from the object, similar to the way COM+ provides component services. What is new with this mechanism is that the runtime allows developers to take part in the interception chain and add powerful services, thus extending existing component services. This in turn decouples the business logic from the system plumbing and simplifies long-term maintenance. Presently, .NET contexts and interception are undocumented aspects of .NET. This article presents the underlying interception architecture and message processing, explains custom context attributes, and walks through a custom interception-based component service.

Juval Lowy Editor's Note: Patterns Patterns Everywhere

As loyal readers of MSDN Magazine know, each month's Editor's Note starts out with a tepid, last-minute stab at humorous content. The formula's pretty tried-and-true by now, and you could probably fill in the details in your sleep.

New Stuff: Resources for Your Developer Toolbox

StarPrint Limited has released VS. NETcodePrint, a Visual Studio® . NET Add-in that allows you to produce printouts of source code in Visual Basic® . NET. You can preview the printouts before printing and exporting to RTF, HTML, and PDF formats.

Theresa W. Carey Web Q&A: IDs as Anchors, Preventing Search, and More

Edited by Nancy Michell The XML Files: Merging XML Files, Schema Validation, and More

Aaron Skonnard Cutting Edge: Customize Your Open File Dialog

Displaying an Open File dialog is certainly easy in the Microsoft® . NET Framework with Windows® Forms, but the resulting window is not as customizable as when you create it through the Win32® API. With Windows 2000, Microsoft added a nice feature—the places bar, which is the vertical toolbar that appears on the left side of the window to let you select a frequently visited folder.

Dino Esposito Design Patterns: Creating Dynamic Factories in .NET Using Reflection

Design patterns are a powerful tool for designing flexible soft-ware. They provide well-tested solutions to recurring software design problems. One such widely used pattern is the Concrete Factory.

Romi Kovacs Advanced Basics: Handling Null Values with Controls

Ken Spencer House of Web Services: Accessing Raw SOAP Messages in ASP.NET Web Services

Web Services exchange XML messages. Most of today's Web Service toolkits do their best to hide this fact from developers, by exposing a Web Service's behavior as method invocations against objects instead.

Tim Ewald Basic Instincts: Static Event Binding Using WithEvents

This month's Basic Instincts column builds upon my last three columns in which I introduced and explained the fundamental concepts and syntax associated with delegates and events. Last month I showed you how to design and write a simple class that defines and raises events.

Ted Pattison C++ Q&A: Find Icons, Launch an App from List Control, and More

Paul DiLascia Talking To…: Michael Howard Discusses the Secure Windows Initiative

The growth of interconnected computers in recent years has pushed security concerns to the forefront of development and application design. The Microsoft effort, dubbed the Secure Windows Initiative (SWI), focuses on securing new and legacy code.


Visual Studio .NET: What You Need to Know Today About the New and Upgraded Features in Visual Studio .NET 2003

Visual Studio .NET

What You Need to Know Today About the New and Upgraded Features in Visual Studio .NET 2003

Carl Franklin
This article assumes you're familiar with Visual Studio .NET
Level of Difficulty 1 2 3
SUMMARY

Any time an upgrade of a favorite tool is released, questions about compatibility, versioning, and changes in methodology abound. The release of Visual Studio .NET 2003 is no exception. Developers will be relieved to learn that breaking changes have been kept to a minimum, and delighted to learn that important new features, like Visual J#, have been added. These and other new features of the .NET Framework 1.1 and Visual Studio .NET 2003, including mobile support and improved debugging, are discussed here.

Contents
Breaking Changes
New Language: Visual J# .NET 2003
Support for Mobile Devices
Mobile Client Applications
Mobile Web Applications
C++ Overhaul
New Data Providers for Oracle and ODBC
IP Version 6
Changes in Visual Studio .NET
Conclusion

I
f you ask developers what they think of Visual Studio® .NET 2003 and the Microsoft® .NET Framework version 1.1 you may get a cold response lamenting the lack of some features like the ability to break, edit, and continue in the debugger. If so, don't be discouraged. If you think there's nothing new or important in this new version, think again. There are plenty of new, exciting features, and if you're not so sure you want to take the plunge, you can take it in steps—you can still run Visual Studio .NET 2002 after you install Visual Studio .NET 2003.

Since Chris Sells has done a great job of explaining the compatibility issues and Windows® Forms features in "Windows Forms: .NET Framework 1.1 Provides Expanded Namespace, Security, and Language Support For Your Projects" in this issue, I'll focus on all the other notable changes and features in .NET Framework version 1.1 and Visual Studio® .NET 2003. First, I'll focus on the changes that matter most, then get down to the minutiae.

Breaking Changes

The biggest "breaking" changes (updates that can break existing code) in the Framework can be found in its XML capabilities. In System.Xml.Xsl.XslTransform, an XmlResolver argument is now required on the Load and Transform methods. The only other breaking changes are that the System.Environment.HasShutdownStarted property is now Static, and the System.Security.Cryptography.DSACryptoServiceProvider class is now sealed (or in Visual Basic® .NET, NotInheritable). There are actually seven other changes that break code, but they are in the internal libraries iehost and iiehost. The remaining changes will not affect your code at all. In addition, there is support for multiple versions of the .NET Framework. You can create installers that target a specific version of the .NET Framework using a launch condition that checks for the correct version and redirects the user to a Web location to download redistributables if necessary.

New Language: Visual J# .NET 2003

Perhaps one of the biggest features of .NET Framework 1.1 is support for Visual J#™ .NET 2003, which is a managed version of the Java language. It's not the Java platform, but Java developers will feel right at home. Visual J# .NET also supports most of the features of Visual J++® 6.0, including Microsoft extensions. Add to that the ability to convert some Java binaries to run in the common language runtime (CLR), and Visual J# .NET is quite a nice little package for Java developers.

Since Visual J# .NET is just another CLR-targeted language, you can develop the same kinds of apps that developers using C# and Visual Basic .NET can (Web Services, ASP.NET, and so on). You also enjoy the security, cross-language, and deployment benefits of the .NET Framework.

The Visual J# Binary Converter Tool will transform Java bytecode into Microsoft intermediate language (MSIL). Be aware, however, that it works for most Java Development Kit (JDK) 1.1.4 level libraries and applications, but not all of them. The preferred method of porting is to recompile the Java-language source as Visual J# .NET. Use this tool only as a last resort.

Visual J# .NET is designed to provide class library support functionally equivalent to most of the JDK level 1.1.4 packages that were included in Visual J++ 6.0. It also provides classes specified in the College Board's Advanced Placement curriculum for Computer Science. Visual J# .NET also supports the Windows Foundation Classes (WFC) libraries and the following com.ms. packages: com.ms.lang, com.ms.dll, com.ms.com, com.ms.win32, com.ms.util, and com.ms.jdbc.odbc.

The Visual J# .NET compiler will not compile Java-language source code into Java-language bytecode, but into MSIL instead. Visual J# .NET does not support applet development, the ability to host applets in browsers, or the ability to create applications that will run on a Java VM. However, you can create Windows Forms controls that will render nicely in a browser on a client machine that has both the .NET Framework 1.1 runtime and the J# Redistributable Package 1.1 installed.

Visual J# .NET also does not support Java Native Interface (JNI), Raw Native Interface (RNI), and Remote Method Invocation (RMI). Figure 1 shows the relationships between Java binaries, source code, the JDK, and the .NET Framework.

Figure 1 Java Binaries, Source Code, the JDK, and the CLR
Figure 1 Java Binaries, Source Code, the JDK, and the CLR

Java binaries can be converted to MSIL, although this is not a recommended practice. Once again, the best course of action is to convert Java-language source to Visual J# .NET so that you end up with pure Visual J# .NET source. An even better solution is to remove support for the JDK libraries altogether and recode directly to the .NET Framework. At that point you can move forward to CLR-targeted code without having to carry around legacy binaries or the JDK libraries. You will note that Visual J# .NET can target both the JDK-level 1.1.4 managed libraries and the .NET Framework proper.

Now, let's take a look at the language and compare it to C#. Figure 2 shows a simple Hello World application in C# developed in Visual Studio .NET 2003. Figure 3 is the same project written in Visual J# .NET.

Figure 3 Hello World in Visual J# .NET (Close Figure 3)
package HelloJS;

import System.Drawing.*;
import System.Collections.*;
import System.ComponentModel.*;
import System.Windows.Forms.*;
import System.Data.*;

/**
 * Summary description for Form1.
 */
public class Form1 extends System.Windows.Forms.Form
{
    private System.Windows.Forms.Button button1;
    /**
     * Required designer variable.
     */
    private System.ComponentModel.Container components = null;

    public Form1()
    {
        //
        // Required for Windows Form Designer support
        //
        InitializeComponent();

        //
        // TODO: Add any constructor code after InitializeComponent call
        //
    }

    /**
     * Clean up any resources being used.
     */
    protected void Dispose(boolean disposing)
    {
        if (disposing)
        {
            if (components != null)
            {
                components.Dispose();
            }
        }
        super.Dispose(disposing);
    }

    #region Windows Form Designer generated code
    /**
     * Required method for Designer support - do not modify
     * the contents of this method with the code editor.
     */
    private void InitializeComponent()
    {
        this.button1 = new System.Windows.Forms.Button();
        this.SuspendLayout();
        //
        // button1
        //
        this.button1.set_Location(new System.Drawing.Point(48, 40));
        this.button1.set_Name("button1");
        this.button1.set_TabIndex(0);
        this.button1.set_Text("button1");
        this.button1.add_Click( new System.EventHandler(this.button1_Click)
            );
        //
        // Form1
        //
        this.set_AutoScaleBaseSize(new System.Drawing.Size(6, 15));
        this.set_ClientSize(new System.Drawing.Size(192, 120));
        this.get_Controls().Add(this.button1);
        this.set_Name("Form1");
        this.set_Text("Form1");
        this.ResumeLayout(false);

    }
    #endregion

    /**
     * The main entry point for the application.
     */
    /** @attribute System.STAThread() */
    public static void main(String[] args)
    {
        Application.Run(new Form1());
    }

    private void button1_Click (Object sender, System.EventArgs e)
    {
        MessageBox.Show("Hello World");
    }
}
Figure 2 Hello World in C# (Close Figure 2)
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace HelloCS
{
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button button1;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after
            // InitializeComponent call
            //
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support—do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // button1
            //
            this.button1.Location = new System.Drawing.Point(48, 48);
            this.button1.Name = "button1";
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.Click += new
                System.EventHandler(this.button1_Click);
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
            this.ClientSize = new System.Drawing.Size(208, 128);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            MessageBox.Show("Hello World");
        }
    }
}

As you can see, the two are very similar. The using statement becomes an Import statment. The C# bool datatype is a Boolean in Visual J# .NET. To derive a new class in C# you use the colon, like so:

public class Form1 : System.Windows.Forms.Form
Visual J# .NET uses the extends keyword instead:
public class Form1 extends System.Windows.Forms.Form

There are other obvious differences. The main point to remember is that Visual J# .NET is the Java language, not the Java platform. It is provided to allow Java developers (especially developers using J++) to leverage their talents and existing codebase.

Support for Mobile Devices

Although it might not seem big right now, because development for Pocket PC and Windows CE-powered devices is still gathering steam, support for mobile devices is huge. It's easy to imagine the significance of developing programs for these devices. They let you take your data with you wherever you go, modify it, bring it back to the desktop, and sync up.

If you've been following the beta versions of either the Smart Device Extensions (for developing binary client-side apps for mobile devices) or the Microsoft Mobile Internet Toolkit (for developing Web applications targeted to mobile devices), you've probably noticed a few name changes. You don't use the Mobile Internet Toolkit anymore. Now you create a mobile Web application and place mobile Web controls on mobile Web Forms. As for the Compact Framework, you still create smart device applications.

Generally, developing mobile applications goes much more smoothly with the final release than with previous betas you may have tried. The emulator seems to work well most of the time now, for example. Let me explain what's there for both mobile client and Web applications.

Mobile Client Applications

As the name implies, the .NET Compact Framework is a subset of the .NET Framework 1.1. There is no support for technologies that don't exist on Windows CE, like Active Directory® or Enterprise Services, but there is also no support for things that could have been included, like .NET Remoting and Configuration.

All the fundamental tools are there, however, including sockets, data access, support for calling Web Services, and graphics. I was able to write a quick utility to download an image from a URL and show it in a PictureBox in no time. You can easily get a bitmap object from a stream, and you can return a stream from an HttpWebResponse object. Put the two together and you've got a way to load images from URLs dynamically, as shown in Figure 4.

Figure 4 Loading Images from URLs (Close Figure 4)
Imports System.Net
Imports System.IO

Private Sub LoadPictureFromURL(ByVal pb As PictureBox, _
  ByVal URL As String)
    Dim MyStream As Stream
    Try
        '-- Create request and response objects
        Dim Request As HttpWebRequest = _
          CType(WebRequest.Create(URL), HttpWebRequest)
        Dim Response As HttpWebResponse = _
          CType(Request.GetResponse(), HttpWebResponse)
        '-- Get the response back as a Stream
        MyStream = Response.GetResponseStream()
        '-- Create a bitmap from that Stream
        Dim Bm As Bitmap = New Bitmap(MyStream)
        '-- Set the bitmap into the Picturebox
        pb.Image = Bm
        '-- Close the stream
        MyStream.Close()
    Catch ex As Exception
        If Not MyStream Is Nothing Then
            MyStream.Close()
        End If
        MsgBox(ex.Message)
    End Try
End Sub

Since Beta 1, the Compact Framework team has added a DataGrid control, although finding it was tough. In some circumstances, the DataGrid doesn't show up in the Visual Studio .NET toolbox. You can get it by selecting the Toolbox, selecting Add/Remove Items, then pressing the Reset button in the Add/Remove dialog box. Other cool controls for Windows CE, like the TreeView, Toolbar, InputPanel, ListView, ProgressBar, TabControl, StatusBar, and TrackBar, are also available.

One feature I really like about mobile apps is that you can run a .NET Compact Framework-compiled assembly (mobile app) directly in the desktop version of the .NET Framework, without recompiling. To do this, Microsoft supplies a Retargetable enum keyword in the assembly manifest. I don't know if this is such a good practice, but it's good to know that it's possible to run a mobile app on the desktop. This won't work in reverse; you cannot copy a desktop .NET Framework-centric app onto a device and run it without recompiling.

You should definitely take care not to overdo a mobile application. Keep your interface simple. The stylus and software keyboard are limiting factors, and the overall goal of a mobile app is to let users enter data quickly with a very simple interface.

You can debug mobile applications on your PC using a hardware and software Pocket PC emulator that comes with Visual Studio .NET 2003. Note that you don't even need a device to write the code. When you are ready to deploy, you can deploy directly to the device or create a CAB file, which can be used to install the application on the device.

Figure 5 FnetSchedule
Figure 5 FnetSchedule

I have written a small mobile app called FnetSchedule that accesses a Web Service at http://www.franklins.net/fnservice/schedule.asmx to return a DataSet containing a schedule of upcoming hands-on Visual Basic .NET classes, along with a graphic for the location, as shown in Figure 5. You can access it at http://www.franklins.net/dotnet.

Mobile Web Applications

Mobile Web applications are ASP.NET applications that are targeted to devices like WAP-compatible cell phones. Smaller pages, less generated HTML and code, and a scaled down user interface are just the beginning. Like their big brother ASP.NET applications, mobile Web applications employ server-side controls that render device-specific content.

The best thing about mobile Web apps is that you can write one application and access it from just about any device, including cell phones. The controls in System.Mobile.Web.UI.MobileControls support more than 200 different devices, and that number is growing all the time. All of the device capabilities are stored in the Machine.Config file on the Web server. You can download device updates at http://asp.net/mobile/deviceupdate.aspx.

Mobile Web Form controls include AdRotator, Calendar, Command (button), CompareValidator, CustomValidator, DeviceSpecific, Image, Label, Link, List, ObjectList, Panel, PhoneCall, RangeValidator, RegularExpressionValidator, RequiredFieldValidator, SelectionList, StyleSheet, TextBox, TextView, and a ValidationSummary control.

As with standard ASP.NET applications, the browser-based HTML controls are also available for access by client-side scripting languages like JavaScript and VBScript.

Among the controls I should point out here are the SelectionList, which can be a list, dropdown list, or combobox. Multiple items can be selected, and making a selection does not cause the form to post back. Also, the SelectionList does not support pagination, so it's ideal for small lists.

The DeviceSpecific control is an easy way to provide your own device-dependent content. You can render different code and HTML based on the type of client device.

The TextView control displays arbitrary amounts of text with optional markup tags. The format of the text in a TextView control is identical to that in literal text on a form. However, unlike literal text on a form, you can set the text in a TextView control. The TextView control supports internal pagination.

The PhoneCall control is an easy-to-use, text-based, output-only control that can be used to represent a phone number. For devices such as cell phones that support making phone calls, the PhoneCall control is presented as an interactive element that makes a call when activated. On other devices, the phone number is displayed as text with an optional hyperlink.

Finally, the ObjectList control provides a feature-rich view of a list of data objects. The ObjectList control inherits much of its behavior, including support for templated rendering, by using device template sets and internal pagination from the List control, but gives you more control than a list.

I was able to take my FnetSchedule app over to a mobile Web app with little modification. You can access it with your mobile device at http://www.franklins.net/mobile/schedule.

C++ Overhaul

The new version of C++ in Visual Studio .NET 2003 is perhaps the most significant upgrade to Visual C++® in a long time. Now C++ programmers can access the same Windows Forms engine that C# enjoys. This feature includes full support of the Toolbox and Server Explorer, which allows you to drag and drop or cut and paste controls and components directly onto your Windows Forms application. In addition, you can easily manipulate the properties of your controls and components through the Properties grid.

Visual C++ .NET is also more ANSI-conformant than the previous version. With this comes a number of breaking changes, many of which take the form of compiler errors, where they were waved through in previous releases. However, there are also a number of silent or runtime errors. Because of this conformance, in many cases it is possible to compile C++ code developed for other platforms.

Changes to the compiler include:

  • A feature that allows you to create a delegate on a method of a value type.
  • The /arch (Minimum CPU Architecture) compiler option, which has been added to take advantage of streaming SIMD Extensions (SSE) and SSE2 instructions.
  • A /G7 (Optimize for Processor) compiler option to tell the compiler to optimize code generation for the specified processor.
  • An enhanced /GS compiler option to help protect local variables from direct buffer overruns.
  • The /Zm compiler option now specifies the precompiled header memory allocation limit.
  • The /noBool option has been removed.
  • /Gf is deprecated and will be removed in the next version of Visual C++.

Documentation has been provided for intrinsics _InterlockedCompareExchange, _InterlockedDecrement, _InterlockedExchange, _InterlockedExchangeAdd, and _InterlockedIncrement, and the _ReadWriteBarrier intrinsic has been added, which effectively blocks the optimization of reads and writes to global memory. This can be useful to ensure the state of global variables at a particular point in your code for multithreaded applications.

A handful of link options have been added as well: /ASSEMBLYDEBUG emits the Debuggable attribute with debug information tracking and disables just-in-time (JIT) optimizations. /ASSEMBLYLINKRESOURCE creates a link to a .NET Framework resource in the output file./DELAYSIGN lets you only place the public key in the assembly. /KEYFILE specifies a strong name key file. /KEYCONTAINER specifies a container for the key, and /SAFESEH tells the linker to only produce an image if it can also produce a table of the image's safe exception handlers.

Visual C++ .NET offers new property pages and a number of new objects, as well as new properties and methods for existing objects that enhance the project build model. Property pages include a Managed Resources Property Page, an XML Data Generator tool, a managed wrapper, a primary interop page, and an auxiliary managed wrapper property page.

New Data Providers for Oracle and ODBC

Probably the second biggest new feature (depending on how important Oracle and ODBC development is to you) is the addition of these two new ADO.NET data providers.

I can't comment on how well they work, except to say that reports on using ODBC for accessing DB2 have been very positive so far. Now you can avoid the COM layer (OLE DB) and code directly to the ODBC API (ODBC.DLL) and/or a managed-code Oracle provider, and just use the ADO.NET objects you already know and love.

Another change is that the System.Data.SqlClient.SqlDataReader HasRows property holds the value for whether a reader has returned data. This makes dealing with empty resultsets easier.

IP Version 6

The Internet is running out of IP addresses in the current 255.255.255.255 format. The demand for static IP addresses continues to grow. Tricky hardware and software schemes like Network Address Translation (NAT) and IP sharing on Web sites are necessary to get around the simple fact that there are only 2554 or about 4,300,000,000 unique numbers to use as IP addresses. This is a problem.

In 1995, the Internet Engineering Task Force (IETF) released the basic spec for Internet Protocol version 6 (IPv6). Most of today's Internet uses IPv4, which is nearly 20 years old. IPv6 is expected to gradually replace IPv4, with the two coexisting for a number of years during a transition period.

IPv6 addresses are 128 bits, as opposed to IPv4's 32-bit IP addresses. According to the WIDE project if the total number of IPv4 addresses is represented as a millimeter, the total IPv6 address space would be 80 times the diameter of our galactic system. That should do it, don't you think?

Besides adding support for more IP addresses, IPv6 also adds many improvements to IPv4 in areas such as routing and stateless network autoconfiguration. IP addresses can be dynamically managed and assigned by the routers without resorting to Dynamic Host Configuration Protocol (DHCP). You can read all about autoconfiguration at IPv6 Stateless Address Autoconfiguration.

Another great feature of IPv6 is true multicasting. This will allow routers to send the same packet to multiple routers. This allows clients to tap into streams of packets that have a single destination IP address, called a multicast Address, thereby eliminating the need for every client to get their own stream of data.

A live webcast with IPv4 looks like a regular webcast, but in reality the same packets are sent to multiple clients. It's sort of like radio broadcasting. There is a single wave. It is up to the client to put up the antennae and capture that data. Much less of a burden is put on the infrastructure, and everyone gets the same data at roughly the same time.

The .NET Framework 1.1 includes support for IPv6 in the System.Net namespace. You should expect to hear much more about IPv6 in the near future.

Changes in Visual Studio .NET

I'll get back to .NET Framework 1.1 in a minute, but first let me tell you what's new in Visual Studio .NET 2003.

Design The design of Visual Studio .NET 2003 is basically the same, but a bit snazzier. I find it's easier to get around the Start page, as shown in Figure 6. Unfortunately, you can still get lost in a docking maze, and that's not going to change anytime soon. Just remember to double-click a window's title bar to undock it, and then double-click the title bar to re-dock it, and you'll escape the worst of it. Also remember, you can always click the Reset Window Layout button in the Environment | General tab in the Tools | Options dialog.

Figure 6 Visual Studio .NET 2003 Start Page (Close Figure 6)

Auto-completion features in Visual Basic .NET A Catch statement and End Try is now automatically written when you type Try. It's a nice feature (that should have been there all along), but how about automatic implementation of interfaces?

When you type an Implements statement in Visual Basic .NET, the interface is now written for you instantly. Try it. Create a new class with the following statement:

Public Class Foo
    Implements IDisposable

End Class
As soon as you hit the Enter button after IDisposable, you get the following:
Public Class Foo
    Implements IDisposable

    Public Sub Dispose() Implements System.IDisposable.Dispose

    End Sub
End Class

Adding Web references In Figure 7, the "Start Browsing for Web Services" pane in the Add Web Reference dialog box now provides Web links to available Web Services both locally and on the Internet. Interestingly, browsing the local machine for Web references had been available as early as Beta 1, but it was removed at the last minute. I'm glad to see it come back.

Figure 7 Start Browsing for Web Services
Figure 7 Start Browsing for Web Services

You can also rename the Web reference before you add it, as shown in Figure 8.

Figure 8 Rename Web Reference
Figure 8 Rename Web Reference

New debugger features Remote debugging can now be done with pipes, which has security benefits not found in TCP/IP. Debugging with pipes requires the Remote Debug Manager, which is only available for C++. The debugger also gets support for SOS, a great managed code dump viewing tool, which gets hooked from the Command window. Error messages have been improved in general, particularly when debugging ASP.NET applications. Debug symbols can now reside on a separate symbol server, your own server, or the Microsoft public symbol server, and can automatically be downloaded if an exception occurs. In addition to all that, there are new debugging security settings so that, for example, you can specify who gets to debug and who doesn't.

Migrating settings from Visual Studio .NET 2002 You can copy certain Options dialog box settings from a previous version of Visual Studio .NET to the new version. If you have different versions of the program installed on the same machine, the first time you launch Visual Studio .NET 2003, a dialog box appears, giving you the choice to migrate your existing settings. Just click Yes to have your options and settings migrated.

Changes in the Solution Explorer One purpose of Visual Studio is to synchronize the designers with the underlying source code. This idea has now been taken one step further. A new option tells Visual Studio .NET that whenever you bring up a particular designer, it will be automatically selected in the Solution Explorer. Open the Projects and Solutions | Environment | Options dialog box, and check off Track Active Item.

Enterprise Services Low-level enrollment in Enterprise Services is now available. The idea is that now you can use Enterprise Services without having to inherit from a ServicedComponent.

ASP.NET features The big news here is the System.Web.UI.Page.ViewStateUserKey property. As you have probably experienced by now, letting ASP.NET manage the ViewState can be dicey. There's a great article that outlines the pitfalls of this at Viewstate Optimization Strategies in ASP.NET.

Not only does care have to be taken for purposes of scalability, but there are security risks as well. The __VIEWSTATE variable can be hacked, which would open up your ASP.NET app for a one-click attack.

Setting the ViewStateUserKey property can help you prevent one-click attacks on your application. It does this by allowing you to assign an identifier to the __VIEWSTATE variable for individual users.

You can set this property to any string value, such as the user's session ID, but realize that you must set this property during the Page_Init phase of page processing. Setting this property during the Page_Load phase will cause an exception to be thrown.

Rounding out the new ASP.NET changes, the Checkbox, ListBox, ListControl, RadioButtonList, and Dropdown Listbox controls now support the SelectedValue property.

Enterprise Instrumentation Framework The Enterprise Instrumentation Framework (EIF) takes event logging, tracing, and performance counters and kicks them up a notch to support these functions (and more) across the network more easily. The EIF will help businesses reduce development and maintenance costs. It will help customers provide effective monitoring and troubleshooting in high-volume production environments, a key challenge when building distributed applications. To unify existing event logging and tracing mechanisms built into Windows, the EIF will provide a consistent, low-profile API and configuration layer. Developers can use this feature to publish audits, errors, warnings, business events, and diagnostic events for support teams to monitor and analyze. In short, you get better instrumentation across a wider scope of environments.

Support for Universal Time Universal Time is the international standard by which all other times are calculated. Coordinated Universal Time (UTC) was previously known as Greenwich Mean Time (GMT). Several classes in the .NET Framework have been upgraded to support values expressed in UTC.

Date and time in Windows Management Instrumentation (WMI) is represented in DMTF datetime format. This format is explained in the WMI SDK documentation. (The SDK is available at Windows Management Instrumentation (WMI) Tools.) The lowest precision in DMTF is microseconds and in DateTime it is a Tick, which is equivalent to 100 nanoseconds. When you convert from Ticks, the value is rounded off to the nearest microsecond.

There is a new System.Management.ManagementDateTimeConverter class that converts between DMTF datetime format and CLR-compliant DateTime formats.

SMP thread synchronization .NET Framework 1.1 adds features for multiprocessor thread synchronization (volatile reads and writes, and memory flushing). Of course, these thread synchronizations should be handled with care.

Conclusion

So there you have it—a rundown of all the major changes to .NET Framework 1.1 and Visual Studio .NET 2003, with the exception of Windows Forms. It's hard to get used to the idea that installing new applications within .NET won't destroy or replace the old ones. Of course, knowing what I know about the .NET Framework, it should have been no surprise, since eliminating versioning problems is a major focus. But I was so used to spending hours and hours undoing what a rogue installation had done to my system. I don't know what I'm going to do with all of this newfound free time.

For related articles see:
Windows CE.NET: New Version Offers Revamped Platform Builder, Improved Tools, Enhanced API, and Source Code
Windows CE: Develop Handheld Apps for the .NET Compact Framework with Visual Studio .NET
NetBSD IPv6 Networking FAQ

Carl Franklinis president of Franklins.Net (http://www.franklins.net) where he teaches Visual Basic .NET classes and hosts .NET Rocks!, an Internet audio talk show for developers using the .NET Framework.

© 2007 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.


Visual C++ .NET: Language Enhancements and Simplified GUI Development Enrich Your C++ Apps

Visual C++ .NET

Language Enhancements and Simplified GUI Development Enrich Your C++ Apps

Richard Grimes
This article assumes you're familiar with C++
Level of Difficulty 1 2 3
Code download available at: VisualC++NET.exe (61KB)
SUMMARY

Managed Extensions for C++ is the preferred programming language for developing Windows Services. Visual Studio .NET 2003 introduces C++ support for designers, providing all the RAD facilities that were available to other languages for developing forms, controls, components, and DataSets. Furthermore, support has been added for the creation of verifiable assemblies with C++.

In this article, the author reviews these additions as well as the new compiler and linker switches, demonstrating how C++ remains the premier systems language while becoming a powerful tool for .NET GUI development as well.

Contents
Designers
References
Window Forms Designer and Satellites
Localizing Non-form Resources
Web References
Verifiable Library Assemblies
New Compiler Switches
New Linker Switches
Conclusion

W
hen work started on the Microsoft® .NET Framework, the C++ team had the most difficult task of all of the language teams. Unlike the C# team, which had a clean slate, the C++ team had a mature language full of features—some useful, some not. Their job was clear: make sure that all code that compiled and ran as native code would also compile and run as intermediate language (IL). Although this sounds straightforward, it actually involved a lot of effort, and the result, It Just Works (IJW), is a great feature that deserves the accolades it has received. However, the work on IJW had a deleterious effect on Visual C++®: there simply was not enough time to add the bells and whistles that were present in the other Microsoft .NET-compliant languages.

With the Visual Studio® .NET 2003 release, the Visual C++ team had the opportunity to add some of the missing polish as well as other new features. Managed C++ has always been a first class common language runtime (CLR)-targeted language, but now it has the RAD features of the other CLR-targeted languages, which gives you the ease of use of designers and raw power of C++.

Designers

C++ is the language of choice for developing fast, efficient code for Windows® Services (formerly known as Windows NT® Services), COM+ components, and library code where efficiency is a priority. However, a sizable portion of C++ developers also use the language to create GUI applications, either by writing to the Win32® API directly or using MFC. With version 1.0 of the .NET Framework you could write a managed GUI application with C++, but one of the features that did not make the cut in the previous version of Visual Studio .NET was support for designers. The effect of this was that while developers working in C# and Visual Basic® .NET could use RAD features to drag and drop components and controls from the toolbox or the Server Explorer, the C++ developer had to do all this work by hand.

This has changed in Visual Studio .NET 2003, which now supports the Windows Forms Designer, the Controls Designer, the Components Designer, and the XML Schema (Dataset) Designer. Designers allow you to create forms and composite controls by dragging and dropping them in a WYSIWYG fashion. The composition is serialized to your project as code generated by a CodeDOM. Visual Studio .NET 2003 has a CodeDOM for C++ (in the MCppCodeDomProvider and MCppCodeDomParser assemblies), which means that the designers can parse and generate C++. Figure 1 shows a C++ Windows Forms project where a form is being edited using the Windows Forms Designer.

Figure 1 Editing with Windows Forms Designer
Figure 1 Editing with Windows Forms Designer

The C++ designers have been written to fit into the designer architecture used by C# and Visual Basic .NET in the first version of Visual Studio .NET; in those languages a class is implemented in a single file. As a consequence, the project wizards for C++ will put the code for the class in the header file, although it does generate a .cpp file. When the designer generates new methods for event handlers, it will place the implementation in the header file. However, as a C++ developer you are used to separating implementation from interface. You can remove the implementation of methods from the header file and place them in the associated .cpp file. The situation when you are most likely to do this is with the InitializeComponent method. As with C#, this method is used to perform initialization on the components that you added through the designer. If you move the implementation to the .cpp file, the designer will recognize this by continuing to place initialization code in the method body.

References

The toolbox contains controls and components that can be dropped onto a designer's surface. These components will be implemented in many different assemblies, and they can even be COM components. When you drop a component onto a designer, the designer will change the project's settings to enable the compiler to access the type information of the component's assembly (or type library) and to enable the final output assembly to access the assembly (or COM server) at run time.

This is achieved through the References folder, which you can see in Solution Explorer. Managed C++ accesses an assembly's metadata through the #using statement. The C++ team decided not to employ #using for components dropped onto designers; they chose to use the command line equivalent, /FU, instead. The /FU switch can be used multiple times on the compiler command line and gives the compiler a path to each metadata file that will be used. All entries in the References folder will add the /FU switch to the project's default compiler command line. The References folder can contain assemblies that are in a project beneath the current solution, assemblies in another location on your hard disk, standard assemblies that are listed on the .NET tab of the Add Reference dialog, and type libraries. Each of these assemblies requires different handling.

By default, Visual Studio .NET 2003 will set a configuration's output folder for each project in a solution to the same folder. This means that at run time all the project outputs will be in the same folder and there will be no problem locating the assemblies. If you select an assembly from another location, the Add References dialog will copy the assembly to the current configuration's output folder (this procedure will be repeated when you build the solution for another configuration) so that this assembly is in the same folder as the assemblies that use it. In both cases, the path used for /FU will be the path to the assembly in the output folder.

The Add Reference dialog will also list standard assemblies. These are typically the Framework assemblies which can be found in the Global Assembly Cache (GAC). The IDE actually looks for a key under the following location in the registry:

HKLM\Software\Microsoft\VisualStudio\7.1\AssemblyFolders
For the Enterprise Architect edition, use 7.1Exp rather than 7.1.

The default value of each child key is the location of the metadata files. The /FU entry for the assemblies added through this tab will have the path given in the key under AssemblyFolders. Framework assemblies are usually installed into the Global Assembly Cache and are often stored as native images with ngen. However, there will be an additional copy of these assemblies in the current framework folder under %systemroot%\Microsoft.NET, which will allow you access to its metadata. If you add such an assembly to the References folder, the path to the copy under %systemroot%\Microsoft.NET will be used in /FU.

Type libraries present a different issue. The /FU switch cannot be passed a type library; instead, the Add References dialog will use an interop assembly. For example, if you add a reference to the Microsoft.mshtml type library, the path for /FU will be:

C:\Winnt\assembly\Gac\Microsoft.mshtml\7.0.3300_b03f5F7f11d50a3a
  \\Microsoft.mshtml.dll
This is the primary interop assembly generated with tlbimp, signed by Microsoft, and inserted into the GAC when Visual Studio is installed. If you add your own COM server, the dialog will use tlbimp to create an interop assembly, which will be copied to your project configuration's output folder. This means that even though C++ can access the COM server through IJW, the actual access will be performed through COM interop.

Note that types in modules (.netmodule) and .obj files can be accessed through #using. For a module, this is the same as using the linker /addmodule switch, and for an .obj file it is the same as adding the .obj file to the linker command line. However, the Add Reference dialog does not allow you to add a module or an .obj file, so it will only work with assemblies.

Window Forms Designer and Satellites

The Windows Forms Designer was always the most visible of the designers in the first version of Visual Studio. Managed C++ missed this first wave of tools for the .NET Framework, but to a large extent this was not a problem because all of the controls and their events were adequately documented in the MSDN® library. This meant that you could develop forms and controls without a designer, although it wasn't quite as quick a process.

The one area where the Windows Forms Designer is useful is in the development of satellite assemblies. A satellite contains localized resources as opposed to the assembly that uses the satellite, which only has locale-neutral resources. A satellite assembly is a library assembly and takes the short name of the neutral assembly appended with .resources. The culture part of the satellite name defines the name of the culture for which it holds resources, and since the Windows file systems only recognizes the short name of the assembly, each satellite should be stored in a subfolder with the name of the culture. At run time the form code uses a ResourceManager object, which will search for and load the appropriate satellite for the current thread's CurrentUICulture setting and access the resource associated with the form.

The Windows Forms Designer allows you to develop localized forms using satellite assemblies. Each form has a Language property, and when you change its value, the designer will load a .resx file associated with the specified culture. The .resx file is an XML file that contains the localized resources, and any binary resources are serialized first before being stored in the file. This means that if the binary resources (most likely icons) change, they have to be serialized again by adding the resource through the Property window. You will develop your satellites simply by changing the form's properties for each culture you support; the IDE does all of the heavy lifting for you at build time.

Behind the scenes, the build process uses resgen to compile each .resx file, naming the compiled resources after the .resx file (that is, the culture is part of the name of the compiled resources). The satellite assemblies are created using the assembly linker tool (al.exe), which is passed the compiled resources file as well as the culture that you used for the Language property of the form. Unfortunately, you have little control over the build process; the only build property you can change is the name of the compiled resources file by way of the property pages of the .resx file.

Indeed, this name is alluded to in the code generated by the New Project wizard, which warns you that if you change the name of the class (from Form1) you are responsible for editing the resource's filename property. My solution is to remove the Form1.h file from the project and use the Add New Item wizard to create a form with a more meaningful name (the full instructions are in the code download available at the link at the top of this article). I would have preferred a more creative name of the first form in a project, perhaps based on the project name. Calling the first form Form1 just adds more work, which is not what a wizard should be doing.

Localizing Non-form Resources

Some resources are not associated with forms. For example, if you decide to follow the Microsoft recommendations and use the EventLog class to log messages to the Windows NT Event Log, you have the responsibility of localizing the messages that it logs. I recommend that instead you use ReportEvent through platform invoke or IJW. This is because the Event Log is designed to perform localization when the message is read (when the locale of the reader is known), but the EventLog class is designed for localization to be performed as the message is logged and when the reader of the message is unknown.

To create localized resources, you should use the naming scheme of name.culture.resx, where name is the name of the resource that you pass to the constructor of ResourceManager and culture is the culture for which the resources are localized. For UK English, you would use en-GB, and for the neutral resource, you would omit this part of the name. The build process will assume that any .resx file with a culture in its name will be used to generate a satellite assembly, and any resource without a culture will be embedded as the neutral resource. However, at the time of writing (release candidate 1), there were a couple of problems with this, which derive from the fact that you don't get complete control over the command lines used to create the resources.

The first problem is trivial. When the Add New Item wizard adds a .resx file, it provides the following for the name of the compiled resource file, where culture is the culture identifier that you have used:

$(IntDir)/$(RootNamespace).$(SafeParentName).<culture>.resources
The problem is in the use of the two macros, $(RootNamespace) and $(SafeParentName), which are new with Visual Studio .NET 2003. $(RootNamespace) will be the namespace where a form is defined (for a non-form resource, the name of the project is used). $(SafeParentName) is described by the MSDN Library as the name of the immediate parent, which is usually the form name. However, for a file that you add through the Add New Item wizard, this macro will be the static string "ResourceFiles". As a consequence, the name that you pass to the constructor of ResourceManager should be a combination of the two. For example:
// project called Test
ResourceManager __gc* rm;
rm = __gc new ResourceManager(
   S"Test.ResourceFiles", Assembly::GetExecutingAssembly());

The solution is to edit the Resource File Name property and remove the $(SafeParentName) macro. Furthermore, since the name of the resource is always assumed to be the root namespace, if you have multiple resources in the same culture, they will each compile to the same file name—with each new compilation overwriting the last file.

Web References

The References folder context menu also gives you an option to add a Web Reference, but strangely, when you add a reference, it will not actually be added to the References folder. Instead, each Web Reference will get a node at the top level in Solution Explorer. The entries within this node are a .discomap that contains information about the discovery documents available for the Web Service and the .disco and .wsdl files.

The wsdl.exe tool is run on the .discomap file to generate a Web proxy for the service. In Visual Studio .NET 2002, a similar procedure was performed, but Web Services Description Language (WSDL) was requested to create a C# file that was compiled at build time to a .netmodule and linked to the assembly. As I said earlier, Visual Studio .NET 2003 has a CodeDOM for C++ and this is passed to the wsdl.exe tool through its /language switch so that wsdl.exe creates a managed C++ proxy. Curiously, the build process will compile this code into an assembly, giving it the same name as that of the generated proxy source file. Therefore, if you are accessing a Web Service on the local machine, the node generated in Solution Explorer will be called localhost, the proxy source file will be called localhost.h, and the proxy assembly will be called localhost.h.dll. You can change the name of the node, but you cannot directly access the name of the generated proxy assembly so that .h will always appear in its short name.

Verifiable Library Assemblies

One of the restrictive aspects of the first version of Visual Studio .NET was the lack of verifiability of C++ assemblies. When the CLR loads an assembly, it performs certain tests to check that the assembly has not been corrupted or altered in some way that would adversely affect your machine. Part of this process involves an analysis of the code that ensures it has valid IL and also that the stack is set up correctly before each opcode is called. It also performs checks to ensure that code is valid, like making sure that jumps are only performed within a method. However, some valid code may perform actions that are unsafe and thus can only be performed in a trusted context. These trickier checks are called verification.

There are several steps involved in making a library verifiable; the most important involves writing code that will not fail verification. Thus, you cannot use __nogc types or unmanaged pointers. You should be wary of using interior pointers in your code because although you can assign and dereference them, if arithmetic is performed on them, the code will not be verifiable. Exceptions must be managed objects, so you cannot throw primitive types.

Of course, a verifiable assembly should not use unmanaged code of any kind. This means you should not be bringing in code through static libraries, though you can use platform invoke. This also discounts the use of the CRT so you have to use the linker switch /noentry. Also be wary of casts: you cannot use static_cast<> for downcasts between class types and you should never use reinterpret_cast<> because it will produce unverifiable code. Keywords like __asm, __try, and __except are used with unmanaged code, so they are not allowed and clearly #pragma unmanaged is also not allowed.

The C++ compiler can optimize code which you will turn on for release configurations. However, the code that the otherwise verifiable code that optimizer generates will actually fail the verification process, so in all configurations, you should turn off optimizations with /Od. The verifier does not like empty data sections in the portable executable (PE) file, so you should add a global variable in one of the source files so that you get the following in the initialized data section:

extern "C" int _dummy = 1;

The compiler adds a call to an internal C runtime (CRT) function called _check_commonlanguageruntime_version to check if it's version 1.1 of the CLR. However, since you have removed support for the CRT by using the /noentry linker switch, the linker will complain that the CRT is not accessible by complaining that it can't find the symbol _main. The way to get around this problem is to link with the nochkclr.obj file provided in the Visual C++ .NET libraries folder or to compile with /clr:initialAppDomain described in the next section.

Of course, the purpose of an assembly being verifiable is that it can be verified! By default, the C++ compiler will add [SecurityPermissionAttribute] to your code to tell the runtime to skip verification, so you have to explicitly tell the runtime to perform the action with the assembly-level attribute:

[assembly: SecurityPermissionAttribute(
              SecurityAction::RequestMinimum,
              SkipVerification=false)];

The final step is to mark the assembly to indicate that it only contains IL. To do this, you have to alter the CLR header of the PE file and add the COMIMAGE_FLAGS_ILONLY flag. There is no mechanism in the IDE to do this, but Visual C++ .NET provides the source code for a tool called silo.exe (in the SetILOnly project).

New Compiler Switches

The compiler has one new switch: /clr:initialAppDomain. In order to understand the reason for this switch, consider the code in Figure 2 and the following snippet:

// Compile with /LD but without /clr so an unmanaged DLL is created
typedef void (*FUNC) (void);
extern "C" __declspec(dllexport)
void ExternalFunc(FUNC f)
{
   f();
}
The function ExternalFunc is implemented in a native DLL and it is used to simulate the situation of calling a native function while passing a function pointer to managed code in your assembly. ExternalFunc merely calls the function pointer which then will print out the name of the application domain. Therefore in the Proc method there is a managed-to-native transition followed by a native-to-managed transition. If you create an instance of ADClass in your main function and then call Proc, you should get the name of the default application domain, which will be the exact same name as the process.

Figure 2 Reentering Managed Code (Close Figure 2)
// Compile with /clr and link to the export library created from
// compiling the DLL in the code in text that follows
#using <mscorlib.dll>
using namespace System;

typedef void (*FUNC) (void);
extern "C" void ExternalFunc(FUNC f);

void ShowAppDomain()
{
   AppDomain* ad = AppDomain::CurrentDomain;
   Console::WriteLine(ad->FriendlyName);
}

public __gc class ADClass : public MarshalByRefObject
{
public:
   void Proc()
   {
      ExternalFunc(::ShowAppDomain);
   }
};

void main()
{
   AppDomain* ad = AppDomain::CreateDomain(S"new domain");
   Assembly* assem = Assembly::GetExecutingAssembly();
   ADClass* a = static_cast<ADClass*>(
      ad->CreateInstanceAndUnwrap(assem->FullName, S"ADClass"));
   a->Proc();
}

Now consider the main function shown in Figure 2. This creates a new application domain and creates an instance of the ADClass in the new domain before calling Proc. Logically, you would expect this code to print "new domain" at the console. However, there is a problem in the first version of the .NET Framework: when the call is made to native code, the thunk code forgets the application domain where the call originated. This means that when the native code calls back into managed code, the runtime does not know which application domain to use. In the first version of the Framework, the runtime was consistent and ensured that the callback into managed code would go to the first application domain. Consequently, if you compile and call this code using version 1.0 of the Framework, you will see the name of the first application domain (the name of the process) printed on the console.

To allow native code to call managed code, the compiler creates a vtable. At compile time, this is populated with the metadata token of the appropriate function. At run time, the CLR performs a fixup and will read the value in the vtable and determine the address of the identified method. It then puts this address into the vtable slot. The PE file requires an actual address at compile time, so the compiler creates a simple thunk that jumps to whatever value is in the vtable. The compiler will pass the address of this thunk to the unmanaged function when you call ExternalFunc.

With version 1.1 of the .NET Framework, the vtable includes a flag that indicates to the runtime that if the call comes into the assembly from native code, the application domain that's used will be that of the last application domain used to call into native code. If you look at an assembly with ILDasm, you'll see that there is a directive to perform the fixups on the vtable called .vtfixup. For the new behavior, the .vtfixup directive will have the flag retainappdomain, which is the default when using the /clr switch.

Unfortunately, this flag is invalid for version 1.0 of the CLR. If you want to compile code that will run on version 1.0, you have to rely on /clr:initialAppDomain, which uses the fromunmanaged flag on the .vtfixup directive. There is no property for a managed project in Visual Studio .NET that enables you to use this switch. However, if you use both /clr and /clr:initialAppDomain on a command line, the compiler will use the latter. So if you are compiling with the IDE, you can put /clr:initialAppDomain in the Additional Options edit box on the C/C++ Command Line Project property page.

New Linker Switches

There are five new linker switches in three main groups: resources, assembly signing, and debugging information. Only one of these switches, /assemblydebug, is available through the IDE. If you want to use the others, you'll have to use the Linker Command Line Project property page.

As the name suggests, the /assemblylinkresource switch allows you to supply the name of a resource file that will be linked to the assembly. The default is to embed resource files so that they become part of the assembly's PE file. Linking is used when the resource file will be a separate file that you deploy with the other assembly files. If you want to link a compiled .resx resource file, don't allow the IDE to build the .resx. Instead, you should exclude the file from the build, add a separate custom prelink build step, and also use the Linker Command Line Project property page to specify the /assemblylinkresource switch.

The /keyfile and /keycontainer switches let you to specify the name of a file or cryptographic container that contains the key to sign an assembly. These switches allow you to provide this information on the linker command line rather than through custom attributes in a source file. Indeed, these custom attributes are merely instructions passed through to the linker, so the new switches represent no new behavior. Similarly the /delaysign linker switch is equivalent to the [AssemblyDelaySign] attribute and indicates that the assembly will eventually be signed, but not right now.

The final linker switch, /assemblydebug, is interesting. This switch is available on the Linker Debugging Project property page through the Debuggable Assembly property. This switch is equivalent to the [Debuggable] attribute, which the compiler adds to indicate to the runtime that the assembly can be debugged. The values passed through the attribute tell the runtime to track information important to the debugger and to turn off just-in-time (JIT) optimization. When you build an assembly with Visual Studio .NET 2002 using the /Zi switch, the [Debuggable] attribute will be provided, as shown here:

[assembly: Debuggable(true, true)];

This is fine for a debug configuration, but if you use the /Zi switch to generate symbols for a release configuration, it means that the runtime will not use JIT optimizations. With Visual Studio .NET 2003 you have to explicitly specify the [Debuggable] attribute either with a custom attribute or through the /assemblydebug switch.

The /assemblydebug linker switch will specify [Debuggable(true, true)] and should be used for debug builds. If you want to generate symbols for a release configuration, you can change the Debuggable Assembly property on the Linker Debugging property page to explicitly specify that the assembly is not debugger-friendly. For example, use "No runtime tracking and enable optimizations (/ASSEMBLYDEBUG:DISABLE)".

Conclusion

Visual Studio .NET 2003 has several new features for managed C++ that were missing in the first version, such as support for designers, linked managed resources, and a CodeDOM for C++. These are features that enhance the RAD facilities of the language and catch up with the other popular CLR-targeted languages. Updates to how the code is generated means that native calls into multiapplication domain assemblies are handled better, release configuration assemblies can be created with symbols (without affecting the assembly performance), and verifiable assemblies can be created. All in all, these improvements help C++ retain its reputation as the best language for writing systems code while pushing it further into the world of GUI development at the same time.

For related articles see:
Managed Extensions Bring .NET CLR Support to C++
Tips and Tricks to Bolster Your Managed C++ Code in Visual Studio .NET

For background information see:
http://msdn.microsoft.com/vstudio

Richard Grimeswrites and speaks at conferences about the Microsoft .NET Framework. Richard is the author of Programming with Managed Extensions for Microsoft Visual C++ .NET, 2nd Edition (Microsoft Press, 2003), which has been updated for Visual Studio .NET 2003.


Windows Forms: .NET Framework 1.1 Provides Expanded Namespace, Security, and Language Support for Your Projects

Windows Forms

.NET Framework 1.1 Provides Expanded Namespace, Security, and Language Support for Your Projects

Chris Sells
This article assumes you're familiar with Windows Forms and C#
Level of Difficulty 1 2 3
Code download available at: WindowsForms.exe (135KB)
SUMMARY

With the much-anticipated release of the .NET Framework 1.1, developers are eager to know what's been added to their programming bag of tricks. In this article, the author focuses on new developments in Windows Forms, such as namespace additions, support for hosting managed controls in unmanaged clients, and designer support for C++ and J#. Integrated access to the Compact Framework and new mobile code security settings also make this release noteworthy. Along with these features, the author reviews the best ways to handle multiple versions of the common language runtime and highlights some potential pitfalls.

Contents
What's New
Moving to 1.1
Namespace Additions
Managed Controls in Unmanaged Hosts
Designer Support for C++ and J#
Compact Framework
Mobile Code Security Settings
Where Are We?

Y
ou know that the old saying that goes everyone complains about the weather but nobody does anything about it? Well, it can't be applied to programming. Microsoft® is continually working hard to produce the next greatest set of development tools and technologies. In the latest release of the Microsoft .NET Framework, version 1.1, forecasts are very promising. While originally intended only as a bug-fix release (the .NET Framework version 1.0 was released just last February, after all), version 1.1 has both fixed bugs and integrated much needed new features into one of my favorite parts of the .NET Framework—Windows® Forms.

This article is based on the final beta of the .NET Framework 1.1, which ships alongside Visual Studio® .NET 2003. Most features are likely to stay very similar, but some are bound to change by the time it is officially released.

What's New

According to a document that comes with the new .NET Framework SDK entitled "API Changes from v1.0 to v1.1," there are 48 additions, 14 removals, and no breaking changes in the System.Windows.Forms namespace. This news may, at first, cause you to rejoice at the addition of 48 new features and mourn the loss of 14 old features, while hoping that you weren't using anything that was axed. You might also wonder how there can be no breaking changes if 14 things were removed. Since the lack of breaking changes means that all of your existing Windows Forms code should continue to run without any changes, all of the removals have corresponding additions that are really changes, like the change of the declaration of the ProcessDialogKey method on the AxHost class, as shown here:

class AxHost {
  // .NET 1.0 declaration
  protected virtual bool ProcessDialogKey(Keys keyData);

  // .NET 1.1 declaration
  protected override bool ProcessDialogKey(Keys keyData);

  •••
}
This change shows that AxHost no longer provides a new virtual method but overrides an existing one, which means that ProcessDialogKey was declared as virtual further up the inheritance hierarchy. The vast majority of the additions fall into this category, making the changes to the Windows Forms namespace itself seem very boring. There are really only three noteworthy additions to the Windows Forms namespace (and one interesting addition to the System.Drawing namespace):
  • the System.Windows.Forms.FolderBrowserDialog class
  • the System.Windows.Forms.Application.EnableVisualStyles method
  • the System.Windows.Forms.CurrencyManager.MetaDataChanged event
  • the System.Drawing.Printing.PrintDocument.OriginAtMargins property

If that was the whole story, I certainly wouldn't need an entire article to describe what's new. There's much more, including namespace additions, support for hosting managed controls in unmanaged clients, Windows Forms designer support for managed C++ and Visual J#™, integrated access to the Compact Framework, and new mobile code security settings. Before I move on to all that is new, however, I'll discuss how to handle multiple versions of the common language runtime (CLR).

Moving to 1.1

With any new version, I always hope that Microsoft has added the features that I need without ruining any of the ones I depend on. As opposed to Win32® DLLs—where developers pretended that there weren't any versioning issues—and COM, where they pretended that versioning wasn't needed at all—the .NET Framework provides thorough, explicit support for multiple versions of multiple, simultaneously installed versions of components and the runtime itself. In fact, if you're running a version of Windows that's had Windows Update running, you've most likely got CLR version 1.0.3705.288, which is the .NET Framework 1.0 SP2. After installing .NET Framework 1.1, your CLR version will be bumped up to version 1.1.4322.510, which is the .NET Framework 1.1 final beta. However, installing version 1.1 doesn't replace any existing versions installed on your machine. Instead, both versions live in harmony in separate directories.

The version of the CLR that's loaded at run time depends on the version that the EXE assembly was built against. So, if you build a Windows Forms application against .NET Framework 1.0, even on a machine that has .NET Framework 1.1 (or later) installed on it, the 1.0 version of the CLR will be loaded to host your application. However, if a 1.0 application is launched on a machine without version 1.0 installed, will automatically be loaded into CLR version 1.1. This is to prevent every Windows Forms 1.0 application from requiring a .config file that says that it's OK to load a 1.0 application under 1.1. If you'd prefer to turn this behavior off, you can create your own .config file and turn off this auto-upgrade feature:

<!-- support only .NET 1.0 Framework -->
<configuration>
  <startup>
    <requiredRuntime version="v1.0.3705"/>
    <supportedRuntime version="v1.0.3705"/>
  </startup>
</configuration>

In that case, if your version 1.0 application is run on a machine without version 1.0 of the CLR, regardless of whether or not version 1.1 is installed, the user will get the error message indicating that she requires a specific version of the .NET Framework.

Finally, if you'd like to support version 1.0 but prefer version 1.1 if it's available (because it performs better, for example), take a look at the following code:

<!-- prefer .NET Framework 1.1, but support .NET Framework 1.0 -->
<configuration>
  <startup>
    <requiredRuntime version="v1.0.3705"/>
    <!-- order of these keys determines preference -->
    <supportedRuntime version="v1.1.4322"/>
    <supportedRuntime version="v1.0.3705"/>
  </startup>
  •••
</configuration>

Unfortunately, that's not the whole story. Since every assembly comes with a list of required assemblies (including their version numbers), building an application under the .NET Framework version 1.1 is going to require version 1.1 for all of the assemblies. Running a version 1.0 application that's been built under 1.1 on a machine with only 1.0 on it will fail since it won't be able to find the appropriate versions of the referenced assemblies. So, getting your application built under version 1.1 to actually run on an earlier version of the assemblies it references requires entries in the .config file for each assembly, as shown in Figure 1.

Figure 1 Running with Earlier Assemblies (Close Figure 1)
<!-- Bring in appropriate referenced assembly version  -->
<configuration>
  <startup>
    <requiredRuntime version="v1.0.3705"/>
    <supportedRuntime version="v1.1.4322"/>
    <supportedRuntime version="v1.0.3705"/>
  </startup>
  <runtime>

    <!-- binding rules under .NET 1.0: -->
    <assemblyBinding
      xmlns="urn:schemas-microsoft-com:asm.v1"
      appliesTo="v1.0.3705">

      <dependentAssembly>

        <!-- when binding to System.Windows.Forms, -->
        <assemblyIdentity
          name="System.Windows.Forms"
          publicKeyToken="b77a5c561934e089"
          culture="neutral"/>

        <!-- load System.Windows.Forms 1.0 -->
        <bindingRedirect
          oldVersion="0.0.0.0-65535.65535.65535.65535"
          newVersion="1.0.3300.0"/>

      </dependentAssembly>
      •••
    </assemblyBinding>

  </runtime>
</configuration>

These configuration settings specify that when running under version 1.0 of the .NET Framework and loading System.Windows.Forms from any version, version 1.0 of System.Windows.Forms will be loaded, even though the code was built against version 1.1. While this is a handy feature that allows you to use the updated version 1.1 tools, setting up the .config file to make all this happen is a bit of a pain. Luckily, Visual Studio .NET 2003 provides an extra project setting accessible from Project | Properties | Common Properties | General | Supported Runtimes. This setting exposes three runtime options through the .NET Framework Version dialog, namely: Microsoft .NET Framework version 1.1 (default), version 1.0 (advanced), and both.

By default, any application compiled under Visual Studio .NET 2003 will target only the 1.1 version of the CLR. If you'd like to restrict yourself to building just version 1.0 applications, you can check the version 1.0 option. The last option is supporting both versions of the Framework, but preferring 1.1. All three of these options will add an app.config file to your project with the appropriate settings, including an exhaustive list of how to map framework assemblies, saving you the trouble. The resulting app.config file will be copied to the output directory at project build time and renamed projectName.exe.config, as required by the CLR.

If you stop to read the text of the .NET Framework Version dialog, you'll notice that it uses some pretty strong language to dissuade you from choosing to support version 1.0 while using Visual Studio .NET 2003. The problem is that darn middle option that says to only support version 1.0. While Visual Studio .NET 2003 will update the .config file to properly require only version 1.0 of the Framework, neither IntelliSense® nor the compiler will tell you if you make use of a type or a member that's not available under version 1.0. You won't know until run time that the code has run afoul of the 1.0 feature list, and then only if the method that makes use of the missing type or method is actually called. If you decide to use Visual Studio .NET 2003 to build applications targeted at version 1.0, you'll need to do some thorough code coverage testing to make sure that it will actually run under version 1.0.

If you're targeting version 1.0 only and you're desperate to use Visual Studio .NET 2003, but just can't give up the compiler-time checking and accurate IntelliSense, there is a way to eat your cake and have it too. Unfortunately, you'll be without frosting, as you'll have to do more than just flip the bit in the .NET Framework Version dialog. First, you'll have to set Project | Properties | Configuration Properties | Advanced | Do not use Mscorlib to "true" (it defaults to "false") so that you don't pull in the version 1.1 mscorlib.dll when you're compiling. Second, you'll have to remove all of the assembly references that Visual Studio .NET 2003 adds to your project, as it will default to getting them from the version 1.1 Framework directory. Finally, you'll have to add project references from the version 1.0 Framework directory using the browser button in the Add Reference dialog to choose assemblies manually (including mscorlib.dll and system.dll). Since the compiler (and IntelliSense) will be referencing the version 1.0 assemblies, these manual steps let you continue to use Visual Studio .NET 2003, even for version 1.0-only assemblies.

On the other hand, if you're targeting both version 1.0 and version 1.1, it's likely that you'll want to take advantage of the new features of version 1.1. When you do that, you have to be careful to check the version number of the runtime through System.Environment.Version and to only use 1.1 features in methods that will never be called by any version 1.0 code. Even if the 1.1 code won't be called under 1.0, the just-in-time (JIT) compiler will require all types and methods to be present when a method is first called, throwing an exception if something is missing. Figure 2 provides an example of one way to isolate code that requires version 1.1. Notice that this code will only call a method with version 1.1-specific code in it if the version of the runtime supports it.

Figure 2 Specifying Version (Close Figure 2)
// This method called under .NET 1.0
void UseMyFolderBrowser() {
  MyFolderBrowseDialog dlg = new MyFolderBrowseDialog();
  dlg.ShowDialog();
}

// This method called under .NET 1.1
void UseFolderBrowser() {
  FolderBrowserDialog dlg = new FolderBrowserDialog();
  dlg.ShowDialog();
}

// This method called under .NET 1.0 or 1.1
// No 1.1 types or methods used in this method
void browseButton_Click(object sender, EventArgs e) {
  if( Environment.Version <= new Version("1.1") ) {
    UseMyFolderBrowser();
  }
  else {
    UseFolderBrowser();
  }
}

Namespace Additions

While I'm talking about taking advantage of Windows Forms features available only in version 1.1, recall the CurrencyManager.MetaDataChanged event, the PrintDocument.OriginAtMargins property, the FolderBrowserDialog class, and the Application.EnableVisualStyles method. The MetaDataChanged event is useful if you're employing data binding and you're interested in the underlying metadata changing in addition to new or updated rows and columns. The OriginAtMargins property is useful if you actually want your printed document's margins to align with the edge of the paper instead of the edge of the printable region of the printer (the former is the intuitive location, but the latter was the only option under the .NET Framework 1.0 and is still the default under version 1.1). The FolderBrowserDialog class is a wrapper around the Win32 ShBrowseForFolder function and works the way you'd expect:

void browseButton_Click(object sender, EventArgs e) {
  FolderBrowserDialog dlg = new FolderBrowserDialog();
  dlg.Description = "Please choose a folder:";
  DialogResult res = dlg.ShowDialog();
  if( res == DialogResult.OK ) {
    MessageBox.Show(dlg.SelectedPath, "Selected Path");
  }
}
Of course, the FolderBrowserDialog class is available for drag and drop from the Visual Studio .NET Toolbox, so you can use the Property Browser to set things like the initial folder and whether to show the Make New Folder button.

One other interesting thing about the Browse For Folder dialog box is the use of the cute, rounded, Windows XP-themed buttons. By default, a Windows Forms application will not get the cute, rounded, Windows XP theme—even running under Windows XP and .NET Framework version 1.1. Instead, the classic controls will be used, making your app look old-fashioned when running under Windows XP, especially in comparison to the standard dialogs, which always display in a themed manner.

Under version 1.0, enabling Windows XP themes required a .manifest file to select the themed version of the common controls and dialogs (see References for the manifest required under version 1.0 to enable themes). Enabling themes in version 1.1 no longer requires a manifest. Instead, you need to call the EnableVisualStyles method from the System.Windows.Forms.Application class before showing any UI:

static void Main() {
    Application.EnableVisualStyles();
    Application.Run(new Form1());
}

While EnableVisualStyles sounds comprehensive, you'll also need to set the FlatStyle on each control on your form from the default value of FlatStyle.Standard to FlatStyle.System. Figure 3 shows the difference when running under Windows XP. As a shortcut to setting the FlatStyle property on the subset of controls that support it (buttons, group boxes, and labels), consider the code shown in Figure 4.

Figure 4 Setting FlatStyle Properties (Close Figure 4)
public MyThemedForm() {
  // Required for Windows Form Designer support
  InitializeComponent();

  // Set the FlatStyle for all controls
  SetFlatStyleSystem(this);
}

void SetFlatStyleSystem(Control parent) {
  foreach( Control control in parent.Controls ) {
    // Only these controls have a FlatStyle property
    ButtonBase button = control as ButtonBase;
    GroupBox group = control as GroupBox;
    Label label = control as Label;
    if( button != null ) button.FlatStyle = FlatStyle.System;
    else if( group != null ) group.FlatStyle = FlatStyle.System;
    else if( label != null ) label.FlatStyle = FlatStyle.System;

    // Set contained controls FlatStyle, too
    SetFlatStyleSystem(control);
  }
}
Figure 3 FlatStyle
Figure 3 FlatStyle

Managed Controls in Unmanaged Hosts

While I'm on the topic of managed controls, one thing that version 1.0 supported was hosting Windows Forms controls in exactly one unmanaged host: Microsoft Internet Explorer. The syntax was special-purpose and tailored just for hosting Windows Forms controls, as shown here:

  <html> <body>
    <object
      id="iectrl"
      classid="iectrl.dll#iectrl.UserControl1"
      width="100" height="100" >
    </object>
  </body> </html>

While some special interop attributes are required on a Windows Forms control to support events, Internet Explorer didn't require any of the normal COM registry entries to make the control available to it as a COM control. Instead, the classid attribute of the object element takes the name of a Windows Forms control in the following form:

<dllName>#<namespace>.<className>

Internet Explorer simply loads the Windows Forms control itself and treats it as a COM control. However, no other popular COM control hosts, like MFC, Visual Basic® 6.0, or ATL, were supported in version 1.0. While neither Visual Basic 6.0 nor ATL is officially supported in version 1.1 either, the Windows Forms team did a full test cycle on hosting Windows Forms controls as COM controls in MFC 7.1—the version of MFC that comes with Visual Studio .NET 2003—and it is now an officially supported unmanaged host. However, while it is fully supported, it's not fully integrated. You'll need to augment the standard COM control containment infrastructure to support Windows Forms controls.

The core of the MFC support for COM controls lies in COleControlSite, which creates controls on demand given a CLSID. Instead, I'll be creating the Windows Forms control before attempting to host it, so my COleControlSite derivative will ignore the CLSID and create a host around the existing control (see Figure 5).

Figure 5 COleControlSite Implementation (Close Figure 5)
class CWinFormsControlSite : public COleControlSite {
public:
  CWinFormsControlSite(COleControlContainer* pCtrlCont)
  : COleControlSite(pCtrlCont) {}

  // Most of this implementation is copied from occsite.cpp
  virtual HRESULT CreateControl(
    CWnd* pWndCtrl,
    REFCLSID clsid, // ignored
    ...) {
      HRESULT hr = E_FAIL;
      •••

      // Wrap existing WinForms control
      // instead of creating a new COM control
      if (SUCCEEDED(hr = WrapWinFormsControl(...))) {
        •••
      }

      •••
      return hr;
    }

protected:
  // This code is based on COleControlSite::CreateOrLoad,
  // but without support for persistence or licensing
  virtual HRESULT WrapWinFormsControl(...) {
      HRESULT hr = E_FAIL;
      •••

      CWinFormsControlWnd* pWndCtrlLocal =
        (CWinFormsControlWnd*)m_pWndCtrl;

      CComPtr<IUnknown> spunk;
      hr = pWndCtrlLocal->GetControl(&spunk);

      •••
      return hr;
    }
};

The COleControlSite CreateControl method is used when the CWnd base class CreateControl method is called to create a COM control. My implementation of CreateControl is mostly a copy of the base class implementation, except that instead of calling the CreateOrLoad method that creates a COM control, it calls my custom WrapWinFormsControl method. My Windows Forms control hosting code depends on the COM interop that the .NET Framework supplies for Windows Forms controls exposing the appropriate COM interfaces.

Also, notice the use of the CWinFormsControlWnd class. Instances of this class hold the HWND that hosts the COM control as well as the IUnknown pointer on the Windows Forms control. The CWinFormsControlSite depends on instances of CWinFormsControlWnd to return the interface pointer on the COM façade around the Windows Forms control on demand via the GetControl method (see Figure 6).

Figure 6 CWinFormsControlWnd Class (Close Figure 6)
class CWinFormsControlWnd : public CWnd {
public:
  BOOL Create(
    IUnknown* punkControl, // Interface of WinForms control
    DWORD dwStyle,
    const RECT& rect,
    CWnd* pParentWnd,
    UINT nID) {
    // Cache control interface pointer
    spunkControl = punkControl;

    // This call will end up in CWinFormsControlSite
    // CreateControl, which is why it's OK to pass a
    // NULL CLSID (we're wrapping a pre-existing
    // WinForms control, not creating a new COM control)
    return CreateControl(CLSID_NULL, ...);
  }

  HRESULT GetControl(IUnknown** ppunk) {
    if( !ppunk ) return E_POINTER;
    if( !spunkControl ) return E_UNEXPECTED;
    return spunkControl->QueryInterface(ppunk);
  }

  •••
  CComPtr<IUnknown> spunkControl;
};

The implementation of GetControl returns a cached COM interface pointer from the Windows Forms control as passed into the Create method. The Create method caches the interface pointer and causes the CWinFormsControlSite class's CreateControl method to be called by calling the base CWnd class's CreateControl method. My custom CWinFormsControlSite class is provided to the CWnd class by overriding the CreateControlSite method of any CWnd-derived class that must host a Windows Forms control, as shown in the following:

BOOL CMfcWinFormsHostDlg::CreateControlSite(...) {
  ASSERT(ppSite);
  *ppSite = new CWinFormsControlSite(this->GetControlContainer());
  return TRUE;
}

As an example of such a class, Figure 7 shows a dialog that hosts the unmanaged and managed MonthCalendar controls side by side on the same MFC dialog.

Figure 7 Hosting a Control in an MFC 7.1 Container
Figure 7 Hosting a Control in an MFC 7.1 Container

The dialog in Figure 7 was created using the standard MFC wizard, overriding the CreateControlSite method and creating an instance of the CWinFormsControlWnd class:

class CMfcWinFormsHostDlg : public CDialog {
  •••
virtual BOOL CreateControlSite(...);

private:
  CWinFormsControlWnd m_wndWinFormsCalendar;
};

After hooking into the COM control creation process of MFC, I'm finally able to create instances of Windows Forms controls as the dialog is being created. This can be done from unmanaged code by manually hosting the common language runtime (CLR) and using COM interop to create an instance of any Windows Forms control. However, a far easier solution is to turn on the managed extensions to C++ by setting the Project | Properties | Configuration Properties | General | Use Managed Extensions option to "yes" (it defaults to "no"). This will enable the use of managed types, including Windows Forms controls, from your MFC application without requiring you to make any of your existing unmanaged C++ classes managed (see Figure 8).

Figure 8 Managed Types in Unmanaged C++ (Close Figure 8)
// Can't use this and create instances of managed types
//#ifdef _DEBUG
//#define new DEBUG_NEW
//#endif

// Bring in the System.Windows.Forms assembly
#using <System.dll>
#using <System.Windows.Forms.dll>

BOOL CMfcWinFormsHostDlg::OnInitDialog() {
  CDialog::OnInitDialog();

  // Create WinForms control(s)
  System::Windows::Forms::MonthCalendar* pcal =
    new System::Windows::Forms::MonthCalendar();

  // Get interface pointer from control
  CComPtr<IUnknown> spunkControl;
  spunkControl.Attach((IUnknown*)System::Runtime::InteropServices::
      Marshal::GetIUnknownForObject(pcal).ToPointer());

  // Get rect of placeholder control and then hide it
  CRect rectPlaceHolder;
  •••

  // Wrap control and place in on the parent window
  m_wndWinFormsCalendar.Create(
    spunkControl,
    WS_VISIBLE | WS_TABSTOP,
    rectPlaceHolder,
    this,
    0);

  return TRUE;  // return TRUE  unless you set the focus to a control
}

While these instructions are a bit cumbersome, the CWinFormsControlWnd and the CWinFormsControlSite helper classes provided in the sample with this article take most of the sting out and require no special support in your Windows Forms controls to host them in MFC 7.1 above and beyond what you already do to support Internet Explorer 5.01 and higher hosting. For more information about the interop story between COM and .NET, see Adam Nathan's book .NET and COM: The Complete Interoperability Guide (Sams, 2002).

Designer Support for C++ and J#

Like hosting Windows Forms controls as COM controls, support for languages other than C# and Visual Basic .NET in Visual Studio .NET 2002 was available, but not completely integrated. You could write a Windows Forms application in managed C++ or J#, but there was no designer support; you had to write all the code by hand. As big a fan as I am of Windows Forms, I wouldn't wish that task on anyone.

Luckily, for programmers who need to stay in C++ or J#, Visual Studio .NET 2003 provides full designer support for managed C++ and J#. When creating a new project, in the Visual C++® and Visual J#™ project types you'll see projects for building a Windows Control Library and a Windows Forms application, just like you're used to for C# and Visual Basic .NET. When creating a Visual C++ Windows Forms app, you'll see a very familiar environment, complete with a toolbox full of controls and components, the designer surface ready for your drag and drop operations, and the Property Browser. In fact, the only thing that's different is the Window tab, which says Form1.h instead of Form1.cs.

When a new C++ Windows Forms application project is created, you'll see a Form1.cpp and an AssemblyInfo.cpp file, as you'd imagine, but you'll also see a .h file for each form class you add to the project using Project | Add New Item. The .h file is where the designer does all of its work and where you're expected to add your own code. The .cpp file is merely a legacy from days gone by and serves only to include the precompiled header and the corresponding .h file. Only the wizard-generated Form1.cpp is at all interesting; it contains the entry point of the app (see Figure 9).

Figure 9 Form1.cpp (Close Figure 9)
// Form1.cpp
#include "stdafx.h"
#include "Form1.h"
#include <windows.h>

using namespace CppWinForms;

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow) {
  System::Threading::Thread::CurrentThread->ApartmentState =
      System::Threading::ApartmentState::STA;
  Application::Run(new Form1());
  return 0;
}

For former C++ programmers who now use C# to build their Windows Forms applications, this syntax should feel either like waking from a dream or falling into a nightmare. Either way, it's pure managed C++, although all of the real action happens in the header file, as shown in Figure 10.

Figure 10 Header File (Close Figure 10)
// Form1.h
namespace CppWinForms {
  using namespace System;
  using namespace System::ComponentModel;
  using namespace System::Collections;
  using namespace System::Windows::Forms;
  using namespace System::Data;
  using namespace System::Drawing;

public __gc class Form1 : public System::Windows::Forms::Form {
public:
  Form1(void) {
    InitializeComponent();
  }

protected:
  void Dispose(Boolean disposing) {
    if (disposing && components) {
      components->Dispose();
    }
    __super::Dispose(disposing);
  }

private:
  System::ComponentModel::Container * components;

  void InitializeComponent(void) {
    this->components = new System::ComponentModel::Container();
    this->Size = System::Drawing::Size(300,300);
    this->Text = S"Form1";
  }
};
}

For C# programmers, this code should also be very familiar. The custom Form1 class derives from the Form base class. The form's constructor calls the InitializeComponent class (although without the condescending comment granting permission to add other code to this function). The Dispose function is there to handle integration with nonvisual components, using the __super keyword to call the base class. InitializeComponent is there to set up the initial properties of the form and the controls on the form. Just as in C# or Visual Basic .NET, this function is owned by the designer and should be left alone unless you like playing with fire (and getting burned).

After the wizard generates the initial C++ code, the designer adds member variables as you drag and drop controls onto the form, sets their properties in InitializeComponent as you make changes in the Property Browser, and adds event handlers for you. Honestly, it's all pretty boring until you realize that now you've got all of the convenience of the Windows Forms tools that Visual Basic .NET andC# programmers enjoy, married with the power of both managed and unmanaged C++. For example, one of my favorite features that managed C++ projects allow is adding unmanaged resources, something that neither C# nor Visual Basic .NET support. That's in addition to templates, multiple inheritance, and the mixing of managed and unmanaged code and types, which managed C++ is already known and loved for.

Compact Framework

In Visual Studio .NET 2003, not only can you build desktop applications in C#, Visual Basic .NET, managed C++, and J#, but you now have support for building smart device applications in C# and Visual Basic .NET. This functionality was available in beta form as an add-in for Visual Studio .NET 2002, but it's now built right into the product.

A smart device application runs on a Pocket PC or a machine running Windows CE. When you choose the Smart Device Application project template, you're actually allowed to build an application or a class library. Choosing to build provides you with a familiar environment, except that the common language runtime classes are fewer and smaller. For example, getting 98 percent of an existing Windows Forms game application ported to the .NET Compact Framework was easy, but the rest took some digging. Unlike the .NET Framework, the .NET Compact Framework has, at most, one way to do anything—so some of the shortcuts you're used to taking in Windows Forms are unavailable. For example, when trying to set the background bitmap on the control, I had to draw it during the Paint event. Likewise, reading the bitmap in from a resource wasn't as easy as I'm used to:

// Loading a bitmap from a resource in the .NET
// Framework
Bitmap logo = new Bitmap(this.GetType(),
              "sblogo.PNG");

// Loading a bitmap from a resource in the
// Compact Framework
Assembly assem = Assembly.GetExecutingAssembly();
string file = "PocketWahoo.sblogo.PNG";
Bitmap logo = new Bitmap(assem.GetManifestResourceStream(file));
However, there's nothing like running your Windows Forms application on another device, even if the device is being emulated, as shown in Figure 11.

Figure 11 Windows Forms in Emulator
Figure 11 Windows Forms in Emulator

Mobile Code Security Settings

One more detail that you may find interesting has nothing to do with code at all, but with the security settings for smart clients and Windows Forms controls downloaded over the Web. In version 1.0, the .NET Framework provided the wonderful ability to host Windows Forms controls on a page in Internet Explorer, just like COM controls. Even better, version 1.0 introduced the idea of smart clients—that is, client applications executed from across the Web. If you haven't done it before, create a virtual directory, plop a Windows Forms application into it, and surf to it from Start | Run using a URL like this: http://localhost/itweb/hr452.exe. This will cause the application to be downloaded to the local machine and run like a standalone client app, but will be constrained by the permissions associated with where the app was launched from (see References in the SDK for more information about smart clients).

Both ways to download and host code from across the Web carry security considerations, of course, since that code could come from either the friendly intranet or the hostile Internet. To make sure that no bad things happen, the .NET Framework Code Access Security (CAS) model provides a partially trusted security sandbox for each assembly based on where it comes from. In version 1.0 SP0, assemblies from both intranet and Internet zones were allowed to run, but the Internet permissions were considerably reduced from intranet permissions. As of version 1.0 SP1, Microsoft changed the settings to disable code from the Internet altogether (although you can turn access back on). Now version 1.1 is a more secure release, and Microsoft has turned execution of code from the Internet back on by default without reducing the Internet permissions themselves. But that's not all. Version 1.1 of the .NET Framework also brings the Authenticode® model back from COM.

With the COM Authenticode model, if the user OK'd code to run, it could do absolutely anything it wanted, subject to the permissions of the user (most of whom run as administrators). If the code did something bad, a team of experts could track it, find the certificate, and bring the bad guys who wrote the code to justice. The .NET CAS model, on the other hand, is preventative in that the user is never asked, but the code only has a limited set of permissions if it's from a location other than the local hard drive. In practice, it turns out that both models have their uses. CAS is great, of course, for keeping bad things from happening. Authenticode, on the other hand, is good at letting the user know that code from outside their machine is about to execute and asking them if that's OK. Whether to ask or not is determined by the same Internet security settings that determine whether or not to ask for a COM control. The default settings for code from the Internet zone as of the final beta of version 1.1 are shown in Figure 12.

Figure 12 Version 1.1 Security Settings
Figure 12 Version 1.1 Security Settings

You'll notice when executing code from the Internet zone that there are no user prompts by default. The same is true of the intranet zone. This is more permission than the default settings for ActiveX®/COM controls, which default to Prompt for signed controls and Disable for unsigned controls. Of course, for COM controls, Authenticode is all the security that's available while in the .NET Framework, there's all of CAS to continue to protect the user.

Where Are We?

Windows Forms in version 1.1 of the .NET Framework provides a number of new and interesting features, ranging from some needed additions to the Windows Forms and Drawing namespaces to entire new subsystems, like the Compact Framework and managed C++ and J# support in the designer. As if that weren't enough, new security settings allow you new choices for your common language runtime-targeted code deployed over the Web. For a city that normally gets a lot of rain, things are definitely rather sunny in Redmond.

For related articles see:
Visual Studio .NET: Managed Extensions Bring .NET CLR Support to C++
You Can Take It with You

For background information see:
.NET Zero Deployment: Security and Versioning Models in the Windows Forms Engine Help You Create and Deploy Smart Clients
Windows Forms: A Modern-Day Programming Model for Writing GUI Applications

Chris Sellsis an independent consultant, speaker, and author specializing in distributed applications in the .NET Framework and COM. More information about Chris and his various projects is available at http://www.sellsbrothers.com.


Smartphones: Design Robust Apps that Take Advantage of Windows CE-powered Smartphone Devices

Smartphones

Design Robust Apps that Take Advantage of Windows CE-powered Smartphone Devices

Chris Dellinger
This article assumes you are familiar with C++, Windows CE, and XML
Level of Difficulty 1 2 3
SUMMARY

Smartphone applications promise to be at the crest of a new wave of cell phone advances as the familiar process of using Microsoft dev tools can produce cutting-edge mobile phone applications. Because Smartphones are Windows-powered devices, developers can easily and inexpensively extend both new and time-tested business applications to mobile users. These applications will possess the necessary levels of enterprise functionality while integrating mobile phone features through the use of several easy to use APIs. This article looks at the basics of building a real-world business application for the Smartphone.

Contents
Smartphone Versus Pocket PC Phone Edition
Building Smartphone Applications
Data Retrieval
Storing Data Locally
Database Options
Synchronizing Data
Accessing Phone Features
Conclusion

T
he release of the Windows®-powered Smartphone, which is currently available in Europe and expected in the US in the first half of 2003, raises the bar for mobile application development. The Smartphone is a state-of-the-art mobile phone that provides voice, wireless, and Internet capabilities in a familiar Windows environment. Unlike existing mobile phones, Smartphone devices have expansion slots to add memory and hardware, allow you to synchronize with your desktop computer through ActiveSync®, and provide features such as instant messaging, Outlook® contacts and calendaring, and a unified Inbox. And best of all, Smartphones pack these features into devices as small as existing mobile phones.

The Smartphone OS is based on Windows CE 3.0, so developers can quickly create a wide variety of powerful and exciting applications with the same tools and APIs they have been using for the Pocket PC. While games and personal productivity tools will surely represent large markets for the Smartphone, enterprise applications will also be a large development arena. There are many benefits to providing workers with mobile phones and the Smartphone leverages these benefits by allowing access to internal enterprise applications without expensive hardware. In addition, new types of applications that marry existing features with telephony will now be possible.

In this article, I'm going to build a real-world business application for the Smartphone. For topics outside the scope of this article, such as voice recognition, instant messaging, and Pocket Outlook, check out Windows Mobile.

Smartphone Versus Pocket PC Phone Edition

You may have heard of the Pocket PC Phone Edition, another phone powered by Microsoft® software. To avoid confusion, I will clarify the differences between the Pocket PC Phone Edition and the Smartphone. For a look at the differences between the two, see Figure 1. (If you are interested in more detailed information on building a Smartphone GUI, check out "Developing an Effective Smartphone User Interface".) The Pocket PC Phone Edition is a fully functioning Pocket PC device with mobile phone capabilities built in. It is similar in size to other Pocket PC devices and has a larger body than the Smartphone. The Pocket PC Phone Edition comes with more horsepower than a Smartphone in that it has more memory; in addition, it has a touch screen that's larger than the regular display screen on the Smartphone (which does not have touch-screen technology). User interaction with the devices is handled by separate methods: the Pocket PC Phone Edition uses a stylus for the touch screen while the Smartphone uses a phone keypad.

Figure 1 The Screens
Figure 1 The Screens

Which device best fits your needs boils down to three main issues: cost, functionality, and ease of use. Microsoft estimates that Smartphones will be priced comparably to other high-end mobile phones, but less than Pocket PC Phone Edition devices. The functionality you require will depend on what you design your application to do. For most mobile applications, the Smartphone and Pocket PC Phone Edition will perform equally well. However, if your application requires large amounts of disk space and memory, additional hardware, or a larger screen, then the Pocket PC Phone Edition is probably the right choice.

Whether the device, and the application you build to run on it, will be easy to use will depend in part on data entry considerations. First, you should decide whether you need a stylus or keypad data entry, or whether it matters at all. Data entry through menu options is easily handled by either device. However, for entering textual information, the Pocket PC Phone Edition is obviously easier to use. Fortunately, both devices support Windows CE APIs, allowing you to easily create one code base for both.

Building Smartphone Applications

What will your real-world Smartphone application need to deliver? Well, there are some tasks common to most mobile business applications. They include retrieving data from a remote data store, processing it, storing and manipulating it locally while offline, uploading changes, and interacting with phone features. If you are able to understand and build these elements when needed, you're ready for real-world Smartphone development.

The first step towards building your application is to download a copy of the Smartphone 2002 SDK. The next step is to decide what type of application you want to create: browser-based or standalone.

Browser-based solutions on the Smartphone consist of Web content that is accessed by Pocket Internet Explorer. This type of application is a great option for existing content providers who want to expand their offerings to Smartphone owners. Browser-based applications on the Smartphone offer the same benefits they do on other platforms, including easy software distribution and maintenance, since all code resides on the Web server. Of course, one drawback is that a connection to the Internet is not always guaranteed. Another is that Pocket Internet Explorer applications cannot access or interact with the built-in features of the device. Fortunately, however, browser-based applications can be developed with your existing Web devel- opment toolkits, such as ASP.NET Mobile Controls.

Instead of a Web application, you can build a custom application with a tool such as eMbedded Visual C++® (also downloadable from Tools and Downloads). Fortunately, the Smartphone and the Pocket PC platform are quite similar. Since many of the APIs are the same, existing applications written in eMbedded Visual C++ for the Pocket PC platform can easily be ported to the Smartphone, resulting in significant savings for organizations wanting to deploy a single application to both devices. I've ported two applications: one was simply a recompile, and the other took only a few hours to work around some slight differences between the platforms.

You have much greater flexibility when developing standalone applications, and such applications tend to be much more robust and can be used in both connected and disconnected modes. For most business uses, standalone applications are probably the best choice. They work in offline situations, yet provide a mechanism for passing data between remote systems when necessary.

In addition, standalone applications can take advantage of device-specific features including telephony features and access to local data stores such as Pocket Outlook and the Windows CE Database (CEDB) engine. When offline, data can be cached for later synchronization. As always, however, standalone applications come with more distribution and maintenance headaches. Also, creating standalone applications require C++ skills, which are more costly and harder to find for development shops. While this has not happened yet, it is expected that the Microsoft .NET Compact Framework and Smart Device Extensions will eventually be supported on Smartphones. Once that happens, developers will be able to use languages such as C# and Visual Basic® .NET for building Smartphone applications.

Data Retrieval

Since one of the most basic features of any business app is the retrieval of data, some of your design challenges will center around the type of connectivity available. Can you depend on a continuous connection or will connectivity be intermittent? Will your system have connectivity at only certain times or access points?

Smartphone devices offer several options for retrieving data from remote data sources. One is ActiveSync, which you can use to manually push and pull documents between a desktop computer and a Smartphone. Another option is to programmatically access the device from a PC and copy files by way of the Remote API (RAPI). While both of these methods get the job done, I do not believe they are the best choice. The built-in Internet connectivity of the Smartphone is far better.

It is very simple to retrieve remote data via the Internet on a Smartphone device. In fact, if you have already developed a Pocket PC application that retrieves data across the Internet, you may already know everything you need to know. The basic methods for communicating with a remote server on a Smartphone are the WinInet functions (HTTP or FTP), the XMLDOM APIs to load data remotely, and Microsoft Internet Explorer (see Figure 2).

Figure 2 Retrieving Remote Data on a Smartphone
Figure 2 Retrieving Remote Data on a Smartphone

The XMLDOM provides several methods for data retrieval which should be familiar to Web developers. With the DOM, you have can retrieve data through two main methods: the Load method of the document object and the XMLHTTP object. Both objects allow for data retrieval in an XML format from remote Web servers. The biggest difference between the two is that the XMLHTTP objects allow you to pass an XML object as part of your call, while the Load command does not. In cases where data must be passed in order to retrieve data, you should use the XMLHTTP object.

Regardless of which method you use on the XMLDOM, you will need to make a few adjustments in your code. First you need to include the correct headers:

#include <objsafe.h>
namespace MSXML
{
#include <msxml.h>
}
#include <ocidl.h>
The objsafe.h and ocidl.h files are required since they contain GUID descriptions that are necessary to make smart pointers work in COM. You need to create the MSXML namespace and include msxml.h in order to make COM calls into the MSXML parser. In addition, you need to add the ole32.lib and oleaut32.lib libraries to your linker settings for the project to compile correctly.

Once you have the code set up to use the XMLDOM, you easily retrieve data from a remote server by using the load method of the DOMDocument. This method simply requires a URL where it can find and retrieve an XML document. It iterates through the document to populate a spinner control on the form as shown in Figure 3. Upon completion, it displays a message box that contains the entire XML document.

Figure 3 XML Load Method Example (Close Figure 3)
MSXML::IXMLDOMDocument     *iXMLDoc     = NULL;
MSXML::IXMLDOMParseError   *pParsingErr = NULL;
MSXML::IXMLDOMElement      *iXMLElm     = NULL;
MSXML::IXMLDOMNodeList     *iXMLChild   = NULL;
MSXML::IXMLDOMNode         *iXMLItem    = NULL;
short tEmpty;
BSTR bStr;
VARIANT         vXMLSrc;
HRESULT         hr;
HWND            hListBox;
long            lLength;

hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if(!SUCCEEDED(hr)) return 0;
hr = CoCreateInstance (MSXML::CLSID_DOMDocument,
    NULL,CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
    MSXML::IID_IXMLDOMDocument, (LPVOID *)&iXMLDoc);
if(iXMLDoc)
{
   iXMLDoc->put_async(VARIANT_FALSE);

   // Smartphone 2002 workaround:
   // Remove document safety options
   IObjectSafety *pSafety;
   DWORD dwSupported, dwEnabled;

   if ( SUCCEEDED(iXMLDoc->QueryInterface(
                  IID_IObjectSafety, (void**)&pSafety)))
   {
      pSafety->GetInterfaceSafetyOptions(
      MSXML::IID_IXMLDOMDocument, &dwSupported, &dwEnabled );
      pSafety->SetInterfaceSafetyOptions(
      MSXML::IID_IXMLDOMDocument, dwSupported, 0 );
   }

    VariantInit( &vXMLSrc );
    vXMLSrc.vt = VT_BSTR;

    iXMLDoc->put_async(VARIANT_FALSE);

    vXMLSrc.bstrVal = SysAllocString(L"http://localhost/
                      smartphonearticledata.xml");
    hr = iXMLDoc->load(vXMLSrc, &tEmpty);
    SysFreeString(vXMLSrc.bstrVal);

   iXMLDoc->get_documentElement(&iXMLElm);
    iXMLElm->selectNodes(L"//DATA/STATUS/S",&iXMLChild);
   //iXMLElm->get_childNodes(&iXMLChild);
    iXMLChild->get_length(&lLength);

    hListBox = GetDlgItem( hWnd, IDC_LISTISSUES);
    for (int x=0;x<lLength;x++){
        iXMLChild->get_item(x,&iXMLItem);
        iXMLItem->get_text(&bStr);
        SendMessage (hListBox, LB_ADDSTRING, 0, (LPARAM) bStr);
    }
   //iXMLChild->get_item(1,&iXMLItem);
   iXMLDoc->get_xml(&bStr);
   MessageBox(NULL,bStr,TEXT("Article Demo"),MB_OK);

Storing Data Locally

After retrieving data to the Smartphone, the next step is to explore methods for storing data locally on the device. One option is to not store it at all. You could retrieve the data, perform some operation, and then release the data from memory. Unfortunately, in most situations it's not that simple, so you are forced to decide what format is appropriate for your application. You may save your data to a file store such as a flash card, or you can save it in a local data store such as CEDB.

For most business applications, you will need to persist your data to a file system. While it is possible to write data to the RAM file system, it is not recommended since all data would be lost when the device is turned off or loses power. For persisted storage, Smartphone devices provide a flash file system known as the IPSM memory space. This space will be limited on most Smartphones, but many devices will include a storage card slot that will allow for removable memory cards.

Programmatically determining where to save your data on a Smartphone is quite easy, thanks to a few APIs that you might recognize if you have developed on a Windows CE platform. These calls can be found in the Windows Shell API documentation. For now, I'm going to focus on SHGetSpecialFolderPath. This function allows you to access the main Smartphone file system and retrieve a full path at run time. Upon retrieving this path, you can use it to store data associated with your application. This function requires a CSIDL_ constant as an input parameter. These constants represent common folders (application data, favorites, programs, startup, and so on) within the Smartphone OS. Since the locations of these common areas may differ on each device, the CSIDL constants provide a unique system-independent way to identify these special folders. It is recommended that custom applications store data in a subdirectory of the directory returned using the CSIDL_APPDATA constant, as shown here:

#ifdef CSIDL_APPDATA
if(!SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_APPDATA, TRUE))
    {
         ASSERT(FALSE);
         hr = HRESULT_FROM_WIN32(GetLastError());
    }
#else
    // Pocket PC doesn't have this defined so put our directory
    // at the root. This will likely change
    // in the future and this code should still work.
    _tcscpy(szFolderPath, TEXT("\\"));
#endif

As I mentioned earlier, sometimes devices will require add-on storage cards. Unlike your desktop computer's hard drives, the Smartphone does not assign drive letters to storage cards. Instead, the OS creates directories in the root directory that represent each partition on each storage card. In order to access the various cards in a device, use the FindFirstFlashCard and FindNextFlashCard functions. FindFirstFlashCard returns a search handle and a pointer to the first storage card if any is found. If the handle returned is valid, you can pass it to FindNextFlashCard, which will return a pointer to the next storage card and a BOOL value indicating whether the search was successful.

Once you have found the flash card you want to use, your next step will be to find a location to store your data. The SHGetDocumentsFolder function should always be used when accessing documents on the device. It works equally well with both new and previously used storage cards. Here's an example of the use of SHGetDocumentsFolder:

TCHAR szDocPath[250];
if (!SHGetDocumentsFolder(L"\\",szDocPath))
    MessageBox(NULL,L"Retrieveing Path Failure",L"Call Failure",MB_OK); else
    MessageBox(NULL,szDocPath,L"Documents Folder Path",MB_OK);

One quick note on emulators: the Smartphone emulator does not emulate storage cards. It also does not support real cards that are attached to the PC that is running the emulator.

Database Options

For almost all business applications, saving data to a local database is a necessity; the same will be true for many Smartphone applications. Compared to Windows CE and the Pocket PC, there are a few differences when it comes to database options on the Smartphone. For the first Smartphone release, Smartphone 2002, only the native Windows CE database will be supported. Unfortunately, there is no support for SQL Server™ CE or Pocket Access at this time. In addition, your only option for accessing the Windows CE database will be to use the database APIs that are included in Windows CE 3.0. The good news is that the code to access the Windows CE database is nearly identical to code written for other Windows CE-powered devices.

Synchronizing Data

After working out the connection and manipulating data, the next step is synchronizing with a remote data store. Since I have already looked at retrieving data across the Internet with the XMLDOM, I will continue with that model and send my changes back to a remote server by way of the XMLHTTP object.

Before I dig into the details of using XMLHTTP, let's look at how Smartphones can consume Web Services. Currently, there are no built-in libraries or components on the Smartphone platform that provide SOAP client functionality. However, a SOAP client for the Smartphone is not out of the realm of possibility since all the necessary building blocks are supported by the Smartphone 2002 SDK. If you want to have a SOAP client on the Smartphone, I would suggest looking into several third-party libraries that might be ported to the Smartphone without too much trouble. Also you should keep in mind that once the .NET Compact Framework becomes available on the Smartphone, you should be able to use its SOAP client functionality.

The first step in synchronizing data from a Smartphone back to a remote data store is to retrieve all changed data from main memory and to put it into an XML format. Once this has been completed, the XMLHTTP object will be instantiated and the data will be passed to the specified URL that handles synchronization.

As mentioned previously, the XMLHTTP object will be used since it has the ability to send information to the remote server in XML format. The XMLHTTP object is another one of the objects available in the MSXML library that was included in the project previously. The code for using this object is shown in Figure 4. It is quite simple to use, employing an object created from the IXMLHttpRequest interface. In addition, a VARIANT is created to hold the IXMLDOMDocument object that is being based. In order to pass this complex type, the VARIANT must be set to a VT_DISPATCH type. The only remaining steps are to call the open and send methods of the XMLHTTP object.

Figure 4 XMLHTTP Example (Close Figure 4)
MSXML::IXMLDOMDocument      *iXMLDoc     = NULL;
MSXML::IXMLHttpRequest      *iXMLHttp    = NULL;
HRESULT                hr;
BSTR bStr = NULL;
VARIANT vUserID;
VARIANT vPassword;
VARIANT vPassValue;
VARIANT vAsync;
short tEmpty;

hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if(!SUCCEEDED(hr)) return 0;
hr = CoCreateInstance (MSXML::CLSID_DOMDocument, NULL,
   CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
   MSXML::IID_IXMLDOMDocument, (LPVOID *)&iXMLDoc);
if(iXMLDoc)
{
   iXMLDoc->put_async(VARIANT_FALSE);

   // Smartphone 2002 workaround:
   // Remove document safety options
   IObjectSafety *pSafety;
   DWORD dwSupported, dwEnabled;

    if ( SUCCEEDED(iXMLDoc->QueryInterface(IID_IObjectSafety,
         (void**)&pSafety)))
    {
        pSafety->GetInterfaceSafetyOptions(
        MSXML::IID_IXMLDOMDocument, &dwSupported, &dwEnabled );
        pSafety->SetInterfaceSafetyOptions(
        MSXML::IID_IXMLDOMDocument, dwSupported, 0 );
    }

    iXMLDoc->put_async(VARIANT_FALSE);
    iXMLDoc->loadXML(L"<customer><first_name>Joe</first_name>
        <last_name>Smith</last_name></customer>", &tEmpty);
}

VariantInit(&vAsync);
vAsync.vt = VT_BOOL;
vAsync.boolVal = false;

VariantInit(&vUserID);
vUserID.vt = VT_BSTR;
vUserID.bstrVal = L"";

VariantInit(&vPassword);
vPassword.vt = VT_BSTR;
vPassword.bstrVal = L"";

VariantInit(&vPassValue);
vPassValue.vt =  VT_DISPATCH;
vPassValue.pdispVal = iXMLDoc;

hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
     if(!SUCCEEDED(hr)) return 0;
hr = CoCreateInstance (MSXML::CLSID_XMLHTTPRequest, NULL,
   CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
   MSXML::IID_IXMLHttpRequest, (LPVOID *)&iXMLHttp);

iXMLHttp->open(L"GET", L"http://localhost/smartphonesavetest.asp",
               vAsync,vUserID,vPassword);
hr=iXMLHttp->send(vPassValue);

iXMLHttp->get_responseText(&bStr);

Accessing Phone Features

Through the Windows CE APIs, developers can easily add phone capabilities to their applications. Features such as automatic dialing, interaction with the call log, the ability to access the SIM card, and sending and receiving of SMS messages can easily be added to an application. One quick note: most of the telephony APIs require a real device or GSM radio attached to the emulator in order to work properly, so if you plan to develop these types of features, be prepared to test against the actual device.

One of the simplest phone features that can be added is the ability to establish a voice call from within an application. It is literally one line of code, thanks to the Assisted TAPI that ships with the Smartphone. All you need to do is include the astdtapi.h file in your code, add cellcore.lib to your linker settings, and call the tapiRequestMakeCall function, as shown here:

TCHAR szDefaultNum[] = TEXT("+1 (555) 555-5555");
LONG lResult;
lResult = tapiRequestMakeCall((LPTSTR) szDefaultNum, NULL, NULL, NULL);
return TRUE;

Sending SMS messages is almost as simple. As with Assisted TAPI, you will need to add a reference to one include file in the code (sms.h) and to one library in the linker settings (sms.lib). The first step when sending or receiving messages is to call the SmsOpen function. Next, initialize the source and destination addresses. After completing these steps, the SmsSendMessage function is called. The last step is to call SmsClose to clean up the SMS_HANDLE that was created. This can be seen in Figure 5.

Figure 5 SMS Code Sample (Close Figure 5)
SMS_HANDLE smshHandle;
SMS_ADDRESS smsaSource;
SMS_ADDRESS smsaDestination;
TEXT_PROVIDER_SPECIFIC_DATA tpsd;
SMS_MESSAGE_ID smsmidMessageID;

// try to open an SMS Handle
if(FAILED(SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, &smshHandle, NULL)))
{
    MessageBox(NULL,L"Call to SmsOpen failed.",L"Error",MB_OK |
               MB_ICONERROR);
    return;
}

// Create the source address
if(!bUseDefaultSMSC)
{
    smsaSource.smsatAddressType = SMSAT_INTERNATIONAL;
    _tcsncpy(smsaSource.ptsAddress, lpszSMSC, SMS_MAX_ADDRESS_LENGTH);
}

// Create the destination address
smsaDestination.smsatAddressType = SMSAT_INTERNATIONAL;
_tcsncpy(smsaDestination.ptsAddress, lpszRecipient, SMS_MAX_ADDRESS_LENGTH);

// Set up provider specific data
tpsd.dwMessageOptions = bSendConfirmation ? PS_MESSAGE_OPTION_STATUSREPORT
: PS_MESSAGE_OPTION_NONE;
tpsd.psMessageClass = PS_MESSAGE_CLASS1;
tpsd.psReplaceOption = PSRO_NONE;

// Send the message, indicating success or failure
if(SUCCEEDED(SmsSendMessage(smshHandle, ((bUseDefaultSMSC) ? NULL :
             &smsaSource),
             &smsaDestination, NULL, (PBYTE) lpszMessage,
             _tcslen(lpszMessage) * sizeof(TCHAR), (PBYTE) &tpsd,
             sizeof(TEXT_PROVIDER_SPECIFIC_DATA), SMSDE_OPTIMAL,
             SMS_OPTION_DELIVERY_NONE, &smsmidMessageID)))
{
    MessageBox(NULL, L"Message sent", L"Success",MB_OK);
}
else
{
    MessageBox(NULL, L"SmsSendMessage Failed", L"Error",MB_OK |
               MB_ICONERROR);
}

// clean up
VERIFY(SUCCEEDED(SmsClose(smshHandle)));

There are many more phone APIs available; unfortunately, I have enough space here to cover only a few of the basics. With these capabilities, applications can be greatly extended with features that were not previously possible in mobile applications. For example, automatic calls or messages can be triggered by applications when certain events occur within an application.

Conclusion

In this article, I've covered the basics of building real-world Smartphone applications. As you can see, the types of applications Smartphone makes possible in the world of enterprise computing are quite compelling. In the near future, you should see a wave of Smartphone applications, the inevitable result of the introduction of an inexpensive device with a familiar, easy development platform into the preexisting user base of mobile phones.

For related articles see:
Developing Applications For Windows Mobile-Based Smartphones
Smartphone 2002 SDK

For background information see:
Wireless Web: Microsoft Mobile Internet Toolkit Lets Your Web Application Target Any Device Anywhere
Windows Mobile

Chris Dellingeris a senior architect at Vytek Solutions in Raleigh, NC where he specializes in mobile technologies. He can be reached at dellinger_chris@hotmail.com.


Site Skinning: Rich XML Classes Let Users Personalize Their Visual Experience on Your ASP.NET Site

Site Skinning

Rich XML Classes Let Users Personalize Their Visual Experience on Your ASP.NET Site

Harry Pierson
This article assumes you're familiar with ASP.NET, C#, and XSLT
Level of Difficulty 1 2 3
Code download available at: SiteSkinning.exe (216KB)
SUMMARY

One way that Web sites and applications become better able to meet the needs of customers is by allowing them to personalize their experience. For Web sites, this means displaying the content as the user wants to see it. For rich-client applications, this often means allowing the user to choose the user interface through a technique known as skinning, which is similar to themes in Windows XP. This article shows how you can apply skinning to Web sites, wrapping their functionality in a new user interface. The technique uses the rich XML classes in the .NET Framework and the built-in extensibility of ASP.NET.

Contents
Extending ASP.NET
ASP.NET Pipeline
Skinning Your Web Pages
Implementing the Handler
FOR XML Queries
Business Objects
HTTP Request Collections
Transform
Sample Application
Conclusion

S
kinning refers to the ability to modify the GUI design of an application—wrapping it in another skin—without affecting its functionality. As popular as skinning is in the rich-client world, it has not made much of an impact on the Web client space even though it has a variety of benefits. For example, skinning your Web site can provide customization on a per-user basis. One of the reasons Web skinning has not become as popular as it could be is the lack of tools for creating skinned Web apps.

ASP.NET Web Forms are becoming a popular solution for delivering dynamic Web content. They are simply HTML template pages which are populated with dynamic data at request time. Skinning such pages would require changes to the HTML page template for each different type of page. But changing these page templates in Web Forms requires a great deal of custom code. Rather than trying to force the skinning of ASP pages in this manner, a new tool is needed. Luckily, thanks to the built-in extensibility of ASP.NET, a Web-skinning tool can be built without reinventing the wheel.

Extending ASP.NET

In the original ASP model, the system for handling Web requests was not extensible. Every Web request was mapped to an ASP file that acted essentially as a function that returned a string. If you wanted to produce content in some neutral format and then skin that content for display in the browser, you had to do all the heavy lifting yourself. You had to either manually code the ASP page to build the format-neutral content and then apply the user-selected skin, or you had to build your own ISAPI extension. ISAPI requires you to handle all of the low-level details; you don't have convenient abstractions like the ASP Request and Response objects. You have to build all of that yourself.

When setting out to build ASP.NET, it became obvious that at least two models for servicing Web requests would be needed: Web Forms and XML Web Services. Because support for more than one model was needed, it made sense to abstract the common functionality into a foundation or framework that the concrete models can build upon. This is exactly what the developers of ASP.NET did.

You can see this abstraction in the design of the Web-related namespaces. The foundation is contained within the System.Web namespace. Within this namespace are classes like HttpRequest and HttpResponse. Built upon this foundation are the System.Web.UI and System.Web.Services namespaces. These contain the classes related to Web Forms and XML Web Services, respectively. In this article, I will build a Web request model that is separate from Web Forms and XML Web Services, but that builds upon the same ASP.NET foundation that those models use.

ASP.NET Pipeline

Before extending the ASP.NET model, you need to understand how ASP.NET handles Web requests. The first step in the pipeline is Microsoft® Internet Information Services (IIS), through which all HTTP requests are routed. When you install ASP.NET, it installs an ISAPI extension that forwards requests for ASP.NET file types to the ASP.NET runtime. This forwarding is based on the file extension of the requested file.

Note that this changes slightly in Windows Server 2003. In that product, the HTTP listener code has been moved into the OS kernel and can be used by any process. Thus, services that handle Web requests directly (like ASP.NET) no longer need to route those requests through the IIS process. However, this has little if any impact on the code in this article and more impact on the way the server is configured to handle these Web requests.

Once the Web request is forwarded to the ASP.NET service, it enters the ASP.NET pipeline and a series of events are raised. Some of these events, such as AuthenticateRequest and AuthorizeRequest, are serviced by classes known as HTTP modules (which are similar to ISAPI filters). These classes register their interest in specific requests at Web application startup and perform tasks such as determining user identity and verifying whether the identified user has permission to access the requested resource. However, these modules do not generate the actual content that is returned to the client. That function is performed by an HTTP handler.

HTTP handlers are classes that must implement the IHttpHandler interface. This interface has two members: the ProcessRequest method and the read-only IsReusable property. ProcessRequest is the important one; it is called by the ASP.NET pipeline to generate the actual response content. IsReusable is only used for handler pooling, allowing the runtime to determine if this handler instance can be used again or if it must be disposed of and a new instance created for the next request. ProcessRequest takes one parameter, an HttpContext class which acts as a container for the global intrinsic objects of classic ASP: Request, Response, Server, Session, and Application. It also provides new intrinsic objects such as the User, Cache, and Trace properties. When called, the ProcessRequest function dynamically generates the response content and writes it out to the context.Response.Output stream.

HTTP handler information is stored in the Web.config file. Every Web application has a Web.config file that contains all the configuration information for that application. This information is inherited, so that base configuration can be specified once in the machine.config file rather than repeated in every Web.config file on the server. The data includes the httpHandlers information that maps specific paths and file names (with wildcards) to specific handler classes that will service those requests. Look in the machine.config file, in the httpHandlers section, for the following:

<add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler"/>
This specifies that any Web request for "trace.axd" will be handled by the class System.Web.Handlers.TraceHandler. I will be putting a similar entry in the Web.config file of my ASP.NET application to map requests for *.xml files to the custom HTTP handler.

While the ability to plug in a custom handler to service Web requests for custom file types is pretty powerful, ASP.NET gives you an even better mechanism for custom handling of Web requests. ASP.NET also supports handler factories. This is an implementation of the well-known abstract Factory pattern for determining which handler will service a Web request.

In Web.config (or machine.config), you can map a given path to a handler factory rather than to a handler class. You can see this in machine.config:

<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>

At Web request time, the ASP.NET pipeline will call to the handler factory's GetHandler method. The factory can then use any mechanism it chooses to build a handler class instance, including dynamically generating a handler class the first time a given page is requested. In fact, this is exactly how ASP.NET Web Forms support compiled Web pages. ASPX files are mapped to the PageHandlerFactory class that compiles the given Web page into an executable class the first time the page is requested. After that, PageHandlerFactory retrieves the compiled executable from the server cache, creates a new instance, and returns that handler to be executed for the current Web request.

Skinning Your Web Pages

In order to support Web site skinning, the content for the pages must be generated in a UI-neutral format. Once the UI-neutral content has been generated, a skin must be applied to provide the preferred design to the content. The obvious choice for a UI-neutral format is XML, which implies XSLT as the skin formatter. Building solutions with industry standards like XML and XSLT allows you to concentrate more on the specific implementation of Web skinning. It also allows you to utilize the deep support for XML and XSLT that is provided in the Microsoft .NET Framework Base Class Library.

As a quick aside, SQL Server™ 2000 provides a template mechanism for dynamically generating XML and applying XSLT. This mechanism provides a basic starting point for the Web skin engine, yet SQL Server 2000 XML templates have a couple of limitations for Web skinning. First, XML templates can only retrieve data from a single SQL Server 2000 database. Second, it provides no mechanism for retrieving XML data from other potential sources, such as business objects. Finally, there is no dynamic mechanism for choosing an XSLT skin at run time. The name of the XSLT file must either be embedded statically in the template or passed in on the query string. The Web skin engine I've built in this article overcomes these limitations.

Like the SQL XML template mechanism, the Web skinning engine defines a number of special tags that represent dynamic content to be pulled in at run time. These special tags are defined as part of the "urn:schemas-DevHawk-net:webskinui" namespace, which is mapped by convention to the "skin" namespace prefix. These tags allow the engine to find content exposed by SQL Server 2000 FOR XML queries, business objects, and intrinsic HTTP request data collections (query string, forms, cookies, and so on). The list of these tags is provided in Figure 1. Additionally, this list could be extended to support other sources of content such as XML Web Services and SQL Server 2000 XPath queries.

Figure 1 WebSkin Dynamic Content XML Tags (Close Figure 1)

Tag | Description
Class | Creates an instance of a business object and gives it a variable name.
Methodcall | Invokes a method on a business object that has been declared via the class tag. Stores the result of the method call in the DOM.
Database | Creates a connection to a SQL Server 2000 database and gives it a specific variable name.
Query | Invokes a FOR XML query against a SQL Server 2000 database that has been declared via the database tag. Stores the result of the query in the DOM.
Parameter | Specifies a parameter for a query. Parameter value may be explicitly specified or it may come from one of the HTTP request collections.
Requestvar | Retrieves data from one of the intrinsic HTTP request collections, encodes it as XML, and stores it in the DOM.
Transform | Invokes a method on a business object that has been declared via the class tag. Method returns a string containing the name of the XSLT file to be applied to the content being returned to the client.

Any XML nodes that aren't in the Web skin schema namespace are left as is. This allows the Web developer to enforce some static structure on the document, similar to the way an ASP developer can simply include static HTML tags in a Web page to be echoed out to the client.

Implementing the Handler

In the handler project file, there are two classes: SkinHandler and SkinUtil. SkinHandler contains all of the required code to be an ASP.NET handler by implementing the IHttpHandler interface and exposing the ProcessRequest method. However, some of the helper functions are located in the SkinUtil class as static methods. I did this because I may build a SkinHandlerFactory at a later time, and the SkinUtil helper functions could then be reused in the dynamically generated SkinHandlers.

The primary function of the SkinHandler class is the ProcessRequest method. The full class is included in the download (see the link at the top of this article), but I will examine several chunks of the code.

For debugging purposes, the first thing ProcessRequest does is check for the __admin query string value. If __admin equals "showxml", ProcessRequest will simply echo the raw XML template to the browser without processing it. This is enclosed within an #if DEBUG...#endif preprocessing block since I only want this feature to be enabled during debugging.

After checking for the debug scenario, the ProcessRequest function loads a DOM instance with the XML file being requested. It then queries the DOM through the GetElementsByTagName method to retrieve all the nodes in the document in the WebSkin namespace. It's important to note that this query returns a dynamic XmlNodeList—when you make changes to the underlying DOM, the XmlNodeList changes too. I will be stepping through the list and replacing the WebSkin nodes with the specified dynamic content. As you can see in the following code snippet, you're not iterating through the XmlNodeList as much as you are repeatedly processing and deleting the first element of the list until the list is empty:

//get a list of all the nodes in the SkinUI Namespace
    XmlNodeList l = dom.GetElementsByTagName("*",
                    PageUtil.SkinUINamespace);

    //process each of the SkinUI Nodes.
    while (l.Count > 0)
    {
XmlNode node = l[0];

•••
//process and replace node
    }

Once you've got the list of nodes to be processed, a switch statement checks the node's local name against the list of WebSkin nodes listed in Figure 1. Each node type, except for parameter and transform, is processed by its own helper function. Parameter nodes are always children of query nodes, so they get handled by the query helper function. Transforming the XML happens after all the other nodes have been processed, so the transform case handler just stores the node data in a helper class. Since there can only be one transform applied to the XML document, the transform case handler also ensures that the transform node is the only transform node in the document, throwing an error if the user specifies two transform tags.

FOR XML Queries

There are three WebSkin nodes that deal with SQL Server 2000 queries: they are database, query, and parameter. First, the database node sets up a connection to the SQL database via a connection string. The database node also sets up a variable name that will be used to refer back to this database connection. When the handler processes a database node, it creates a SqlConnection instance using the specified connection string. Then it stores the connection instance in an object dictionary that is initialized at the start of the process request function. This object dictionary stores all of the database connections and business object instances that are declared via class and database nodes. ProcessRequest uses a try...catch...finally block to trap errors. In the finally block, the object dictionary is walked and any database connections are explicitly closed.

Once a database has been declared, queries can be defined using the query node. This node specifies the database connection that the query will be run against and the type of query being specified (text or stored procedure, for example). The text of the node is the query to be run and it must be a query or stored procedure that returns XML. Under the query node are zero or more parameter nodes. Here is a query node with a child parameter node that comes from the sample application:

<skin:query var="nwind" type="Text">
    <skin:parameter name="@prodID" datatype="varchar" size="30"
                    key="id" collection="querystring" />
    SELECT * FROM Products productinfo
    WHERE productID = @prodID FOR XML AUTO
</skin:query>
In this query node, the parameter @prodID is being passed in as the id element of the query string. The parameter can specify any of the request collections and it can also include a default value that is to be used if the specified request collection item does not exist.

The code that processes this node creates a SqlCommand object with the specified SqlConnection and command text. The code then iterates through the child nodes looking for parameter nodes. Once found, the parameter nodes are converted into parameter objects and added to the SqlCommand's parameter list. Once they are processed, the command is executed through the ExecuteXmlReader command by the Execute helper function from the SkinUtil class. The resulting XmlReader is then imported as a document fragment which, in turn, replaces the query node. The XmlDocument class has a very useful function called ReadNode that converts from the stream-based XmlReader to the DOM-based XmlNode representation. The meat of the Execute helper function looks like this:

XmlReader xr = cmd.ExecuteXmlReader();

XmlDocumentFragment xdf = dom.CreateDocumentFragment();
XmlNode xn;

while ((xn = dom.ReadNode(xr)) != null)
{
    xdf.AppendChild(xn);
}

Business Objects

There are two WebSkin nodes for accessing business objects: class and methodcall. The class node provides an operation similar to that of the database node. It specifies the assembly, class name, and variable name for the business object. When the handler processes a class node, it dynamically loads the listed assembly from the bin subdirectory of the Web skin application. It then creates an instance of the specified class and stores that instance in the same object dictionary that stores database connections. This means that variable names must not be reused between database connections and business objects. This code dynamically loads a class by name:

string filename = context.Request.PhysicalApplicationPath + @"bin\" +
                  GetAttribException(node, "assembly") + ".dll";
Assembly a = Assembly.LoadFrom(filename);
Object o = a.CreateInstance(GetAttribException(node, "class"), true);
objDict.Add(GetAttribException(node, "var"), o);

Note that the GetAttribException helper function retrieves a named attribute from an XML node. If that attribute doesn't exist, an exception is thrown. There is also a GetAttribNull helper function that returns null when the attribute doesn't exist for situations in which the attribute is optional.

The handler uses reflection to process the methodcall node which provides the variable name and the method name to be invoked. .NET reflection provides a mechanism to query an object to see if it supports a method with a given name. The following code will query and invoke a method via reflection:

Type t = o.GetType();
MethodInfo m = t.GetMethod(GetAttribException(node, "method"));
XmlNode newnode = (XmlNode)m.Invoke(o, null);

The important thing to note is that the specified method must conform to a specific signature. Methods invoked through WebSkin must take no parameters and return an XmlNode object (though this could be null). Within the business object, information about the current HTTP context is available through the HttpContext.Current static property.

By requiring a specific method signature, the WebSkin engine is unable to call arbitrary methods of arbitrary business objects. This implies that business objects must be explicitly developed for use in a WebSkin site and not reused. It would be possible to build a parameter mechanism similar to the database parameter support I've just described. However, due to the inability of HTTP request collections to store complex types, this feature would be of marginal use. SQL queries and stored procedures use simple types as parameters and return XML. Many business objects use complex types, such as structs, as either input or output parameters which are difficult to process without code. In order to access business objects that don't have a conforming signature, the user should build a WebSkin-specific business object to handle this arbitrary business object.

HTTP Request Collections

The last sources of content are the various HTTP request collections: QueryString, Form, Cookies, ServerVariables, and Params. The WebSkin node for accessing one of these collections is requestvar. The requestvar node specifies which collection to retrieve content from and optionally specifies the variable name and target namespace. If the variable name is not specified, the entire collection will be included in the DOM. The target namespace enables the generated XML to have a specific namespace. If it is not specified, the parent node's namespace is used instead.

With the exception of the cookie collection, ASP.NET exposes the HTTP request collections as NameValueCollections. Since these collections are implemented the same way and expose their data in the same way, you can use a common method to process most requestvar nodes. The NameValCol method on the handler wraps a call to the SkinUtil.NameValCol method. That method uses a helper function (SkinUtil.NameValColWorkhorse) that encodes a specific collection entry in XML. The NameValCol method calls the helper function one time if the variable name is specified or one time per collection entry if the name is not specified.

ASP.NET exposes the cookie collection as an HttpCookieCollection which, as you can guess, exposes a collection of HttpCookie objects. In addition to the value, HttpCookies have a domain, expiration time, path, and secure setting, so the SkinUtil.CookieCol and CookieCol Workhorse functions work almost identically to the NameValCol and NameValColWorkhorse methods. The only difference is the collection type and encoding mechanism for the collection items. It would have been nice to use one set of methods for this, but the NameValueCollection and the HttpCookieCollection objects have no parent classes in common (except for System.Object).

Transform

Once all the WebSkin nodes have been processed, you need to apply an XSLT skin before sending the content to the browser. The transform tag can specify the XSLT either statically or dynamically. If the transform tag specifies a default attribute, that XSLT file is statically chosen to skin the XML content. Alternatively, if the transform tag specifies a variable and method name, the handler calls the specified method of the variable to determine the XSLT skin file to use. This is very similar to the way method call tags are processed, except that the return value of the transform tag method is a string rather than an XML node.

Once the XSLT skin file has been chosen, the handler calls to SkinUtil.Transform to perform the transform proper. If the XSLT file chosen is null or an empty string, the raw XML is dumped out to the browser client. Otherwise, a new XslTransform object is created, loaded with the selected XSLT file, and then applied to the XML DOM that contains all the content. In order to optimize the loading of the XSLT file, once it's been loaded into the XslTransform object, it's placed in the HTTP context cache. Subsequent requests for this XSLT file do not need to be loaded from disk. In order to keep the cache consistent, a CacheDependency object is created for the cache entry. This dependency automatically removes the cached object if the XSLT file on disk is modified. The XslTransform object is loaded and cached like this:

XslTransform xslt = (XslTransform)(context.Cache[xsltFile]);
if (xslt == null)
{
    xslt = new XslTransform();
    xslt.Load(xsltFile);
    context.Cache.Insert(xsltFile, xslt, new CacheDependency(xsltFile));
}
xslt.Transform(dom.DocumentElement, null, context.Response.Output);

Sample Application

Included in the code download for this article are both the WebSkin HttpHandler and a sample skinned Web application called DevHawk Books. This sample displays book, author, and publisher information from the pubs sample database. In order to run the sample, a copy of SQL Server or the Microsoft SQL Server 2000 Desktop Engine (MSDE 2000) is required. Each WebSkin page has a database tag that connects to the pubs database on localhost using a trusted connection. If this is not where your database is installed, you will need to modify the connection strings in the database tags on each page.

Figure 2 shows an XSLT skin with simple black text on white background, and Figure 3 shows a more pleasing XSLT skin with a cool logo. Switching between the two is done using a method call to the SetSkin method of the Controller object. This checks the query string for a new skin to use and writes a cookie. The same object also exposes a GetTransform method for retrieving the currently selected skin from the cookie.

Figure 3 XSLT Skin in Color (Close Figure 3)

Figure 2 Black and White XSLT Skin (Close Figure 2)

All the WebSkin pages in the DevHawk Books sample use .xml as their extension. Since IIS is not preconfigured to pass HTTP requests for .xml files along to ASP.NET, I have included a simple VBScript file to perform this configuration. I have also included a VBScript that will configure the DevHawk Books subdirectory as a virtual Web folder. Running the included install.bat file will launch both of these VBScripts.

Conclusion

Using ASP.NET is kind of like having your mind read. If you ever look at a site and think "I need something different," you'll most likely find that the ASP.NET architects have considered that need and provided a mechanism for you to hook in your custom functionality. In this case, I've bypassed the built-in Web Forms and Web Services support to build an entire engine that services Web requests in a unique way.

You can also improve the WebSkin engine's scalability by building a mechanism to compile the skinned Web pages. Writing code that writes code is always tricky, but the Microsoft .NET Framework does most of the heavy lifting through the objects in the CodeDOM namespace.

For related articles see:
HTTP Pipelines: Securely Implement Request Processing, Filtering, and Content Redirection with HTTP Pipelines in ASP.NET
Wicked Code: Code Your Way to ASP.NET Excellence

For background information see:
IHttpHandler Interface
HTTP Handlers

Harry Piersonis a Senior Architect Evangelist with the National Architecture Team at Microsoft. He can be reached through his Web site at http://www.devhawk.net.


Contexts in .NET: Decouple Components by Injecting Custom Services into Your Object's Interception Chain

Contexts in .NET

Decouple Components by Injecting Custom Services into Your Object's Interception Chain

Juval Lowy
This article assumes you're familiar with the .NET Framework and C#
Level of Difficulty 1 2 3
Code download available at: ContextsinNET.exe (326KB)
SUMMARY

The .NET Framework can use contexts as an object's execution scope and intercept calls going to and from the object, similar to the way COM+ provides component services. What is new with this mechanism is that the runtime allows developers to take part in the interception chain and add powerful services, thus extending existing component services. This in turn decouples the business logic from the system plumbing and simplifies long-term maintenance. Presently, .NET contexts and interception are undocumented aspects of .NET. This article presents the underlying interception architecture and message processing, explains custom context attributes, and walks through a custom interception-based component service.

Contents
Contexts in .NET
Call Interception Architecture
Cross-context Sinks
Message Sink Types
Custom Component Services
Custom Context Attribute
Custom Message Sink
Providing Four Types of Sinks
Processing Messages
The Logbook Service
Using the Logbook
The Logbook Service Architecture
Implementing the Logbook
Conclusion

O
ne of the most important aspects of the Microsoft® .NET Framework as a component technology is its use of contexts to facilitate component services. The core design pattern is interception: intercepting the call from the client to the object, performing some pre-call processing, forwarding the call to the object, and doing some post-call processing before returning control back to the client. Objects indicate to the Framework which component services they rely on, and using interception, the Framework ensures that they get the runtime environment they require.

In addition, the .NET Framework enables developers to provide their own custom component services. This is a major advancement for software engineering and component-oriented programming because now developers can fine-tune the way the .NET Framework supports their particular application and business logic. Custom component services decouple clients from objects because they don't need to coordinate the execution of the custom service and can instead focus on the business logic. Examples of custom services are: application logging and tracing, performance counters, custom thread management, method calls filtering, parameter checks, security access checks, and event subscriptions.

In this article I'll explain the interception architecture and how to build custom context attributes. Then I'll walk you through developing a real-life example of these techniques. The example will be a logbook services that logs method calls and exceptions.

Contexts in .NET

The .NET Framework provides component services through call interception. To intercept the call, a proxy is injected between the client and the object. In the same app domain, by default, the client gets a direct reference to an object; no proxies are involved. The common language runtime (CLR) can optionally subdivide an app domain into contexts. When making a cross-context call, there is always a proxy between the client and the object, even in the same app domain. If you want to take advantage of interception-based services, you need to derive your class from ContextBoundObject, as shown here:

public class SomeClass : ContextBoundObject
{...}
As the name implies, a context-bound object always executes in the same context, and all calls into the context are intercepted.

Objects indicate which services they require by using special context attributes. Out of the box, the .NET Framework provides just one such attribute, SynchronizationAttribute, defined in the System.Runtime.Remoting.Contexts namespace:

using System.Runtime.Remoting.Contexts;

[Synchronization]
public class SomeClass: ContextBoundObject
{...}

When a context-bound object uses the Synchronization attribute, the CLR ensures that only one thread at a time is allowed to access the object by associating the object with a lock. If the object is accessed by another thread, the calling thread is blocked until the concurrent call returns. The Synchronization attribute also provides ways for sharing the lock between objects in order to reduce the chances of a deadlock.

Call Interception Architecture

The cross-context interception architecture is very similar to the one used when performing remote calls across app domain boundaries. In the .NET Framework, the proxy has two parts: a transparent proxy and a real proxy. The transparent proxy exposes the same public entry points as the object. When the client calls the transparent proxy, it converts the stack frame to a message and passes the message to the real proxy. The message is an object implementing the IMessage interface, as shown here:

public interface IMessage
{
   IDictionary Properties{ get; }
}

The message comprises a collection of properties, such as a method's name and its arguments. In the case of a call across app domains, the real proxy needs to serialize the message using a formatter and pass it to the channel. In the case of a cross-context call, the real proxy needs to perform interception steps before forwarding the call to the object. It turns out that an elegant design solution allows the same real proxy to be used in both cases. The real proxy does not know about formatters, channels, or context interceptors. The real proxy passes the message to a message sink, which is an object that implements the IMessageSink interface that is defined in the System.Runtime.Remoting.Messaging namespace:

public interface IMessageSink
{
   IMessageSink NextSink{ get; }
   IMessageCtrl AsyncProcessMessage(IMessage msg,IMessageSink replySink);
   IMessage SyncProcessMessage(IMessage msg);
}

The common language runtime groups message sinks together in a linked list (see Figure 1). Each message sink knows about the next sink in the list and it passes the message to it when it has finished processing it. You can obtain the next sink through the NextSink property of IMessageSink.

Figure 1 Interception Architecture
Figure 1 Interception Architecture

The last sink in the chain is called the stack builder sink because it converts the message back to a stack frame and then calls the method on the object. When the call returns to the stack builder, it constructs a message with the method results and returns that message to the sink that called it. That sink performs some post-call processing and returns the message to the calling sink, and so on. The first sink in the chain returns control to the real proxy, providing it with the returned message from the object. The real proxy returns the message to the transparent proxy, which puts it back on the calling client's stack.

To pass the message through the sinks, the real proxy calls the SyncProcessMessage method of the first sink, allowing it to process the message. After processing the message, the first sink calls SyncProcessMessage on the next sink, as do the rest of the sinks. With cross-app-domain calls, the first sink on the client side is the message formatter. When the SyncProcessMessage method returns to the proxy, it returns the message returned from the object. The IMessageSink interface also provides the AsyncProcessMessage method that is used to intercept asynchronous calls. Unfortunately, the discussion of the interception of asynchronous calls is beyond the scope of this article.

Cross-context Sinks

In the case of a cross-context call, there is no need for a formatter, and the CLR uses an internal channel called CrossContextChannel which is also a message sink. It is up to the sinks to compensate for differences in component services configurations between the client and the object. To be able to accomplish that, the .NET Framework installs all the neccessary message sinks between the client and the object.

Figure 2 shows a generic sink implementation. The sink's constructor accepts the next sink in the chain. When the SyncProcessMessage method is called, the sink performs some pre-call processing and then calls SyncProcessMessage on the next sink. The call will advance down the sink chain, call the object, and return. The generic sink now has a chance to examine the returned message and do some post-call processing before returning control to the sink that called it.

Figure 2 Generic Message Sink Implementation (Close Figure 2)
public class GenericSink : IMessageSink
{
   IMessageSink m_NextSink;

   public GenericSink(IMessageSink nextSink)
   {
      m_NextSink = nextSink;
   }

   public IMessageSink NextSink
   {
      get
      {
         return m_NextSink;
      }
   }
   public IMessage SyncProcessMessage(IMessage msg)
   {
      PreCallProcessing(msg);

      //This calls the object:
      IMessage returnedMessage = m_NextSink.SyncProcessMessage(msg);

      PostCalm"rocessing(returnedMessage);

      return returnedMessage;
   }
   void PreCallProcessing(IMessage msg)
   {
      /*Do some pre call processing*/
   }
   void PostCallProcessing(IMessage msg)
   {
      /*Do some post call processing*/
   }
   public IMessageCtrl AsyncProcessMessage(IMessage msg,IMessageSink
                                           replySink)
   {
      /*Handle the asynchronous call, then:*/
      return m_NextSink.AsyncProcessMessage(msg,replySink);
   }
}

Message Sink Types

The call interception can occur in two places. Server-side sinks can intercept calls coming into the context as well as do some pre- and post-call processing, such as managing a thread lock. Client-side sinks intercept calls going out of the context and do some pre- and post-call processing. For example, the Synchronization attribute can optionally track calls outside the context and unlock the lock to allow other threads access while an outgoing call is in progress. This is done using a client-side sink. Server-side sinks intercepting all calls into the context are referred to as server context sinks, while those intercepting calls to a particular object are server object sinks. The server is responsible for installing server-side sinks. Client-side sinks installed by the client are called client context sinks, and they affect all calls going out of the client's context. Client-side sinks installed by the object are called envoy sinks. An envoy sink intercepts calls only to the particular object with which it is associated. The last sink on the client side and the first sink on the server side are instances of the CrossContextChannel type. The resulting sink chain is comprised of segments, with each segment made of a different type of sink, as shown in Figure 3.

Figure 3 Client-side and Server-side Sink Chains (Close Figure 3)

The .NET Framework installs a terminator at the end of each segment, which is a sink of the segment's type. The terminator is responsible for performing the final processing for the segment and forwarding the message to the next segment. For example, the last message sink in the server context sink segment is called the ServerContextTerminatorSink. The terminators behave like a true dead end: if you call IMessageSink.NextSink on a terminator, a null reference will be returned. The real next sink (the first in the next segment) is a private member of the terminator. As a result, there is no way to iterate using IMessageSink.NextSink on the entire length of the interception chain.

Custom Component Services

Custom component services are provided in the form of custom context attributes. Generic custom attributes have no use unless the developer provides the reflection code to look for these attributes, interpret their values, and act upon it. The .NET Framework is indifferent to such custom attributes.

Unlike generic custom attributes, the Framework is aware of custom context attributes when used on context-bound objects. They must derive from the ContextAttribute class. When creating a new context-bound object, the the object's metadata is reflected and placed in the appropriate context based on the behavior of the attributes. Custom context attributes can affect the context in which the object is activated and running in, as well as install all four types of message sink interceptors.

Custom Context Attribute

Each context has a set of properties associated with it. The properties are the component services that a context supports. A context-bound object will share a context with its client only if the client's context has the services that the component requires; in other words, the context has the required properties. If the client's context does not have at least one of the properties the object requires, the CLR will create a new context and put the object in it. In addition, a context property may require a new context irrespective of the client's context. Developers use context attributes to specify the required services. The context attributes are the ones deciding whether the client's context is sufficient.

To understand how context attributes affect a context's activation, consider one that adds a color property to a context. The color is an enum of type ColorOption:

public enum ColorOption{Red,Green,Blue};
You use ColorAttribute as a class attribute on a class derived from ContextBoundObject:
[Color(ColorOption.Blue)]
public class SomeClass: ContextBoundObject
{...}

The CLR will create objects of the SomeClass class in the client's context only if the creating client's context has a color property and if its value is set to ColorOption.Blue. Otherwise, a new context will be created, the attribute will be allowed to set its color property to ColorOption.Blue, and the new object will be created in the new context. The ColorAttribute also has a default constructor, setting the context color to ColorOption.Red:

[Color]//Default is ColorOption.Red
public class SomeClass: ContextBoundObject
{...}

Figure 4 shows the implementation of the custom context attribute ColorAttribute. ColorAttribute has a member called m_Color containing the required context color. The color is specified during the attribute construction either explicitly or by using the default constructor. As a custom context attribute, it must derive from the class ContextAttribute defined in the System.Run- time.Remoting.Contexts namespace. The single constructor of ContextAttribute requires a string naming the new context attribute. ContextAttribute derives and provides virtual implementation of the IContextAttribute interface, defined as:

public interface IContextAttribute
{
   void GetPropertiesForNewContext(IConstructionCallMessage msg);
   bool IsContextOK(Context ctx,IConstructionCallMessage msg);
}

Figure 4 Custom Context Attribute (Close Figure 4)
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;

public enum ColorOption {Red,Green,Blue};

[AttributeUsage(AttributeTargets.Class)]
public class ColorAttribute : ContextAttribute
{
   ColorOption m_Color;

   public ColorAttribute():this(ColorOption.Red)//Default color is red
   {}

   public ColorAttribute(ColorOption color):base("ColorAttribute")
   {
      m_Color = color;
   }
   //Add a new color property to the new context
   public override void GetPropertiesForNewContext
       (IConstructionCallMessage ctor)
   {
      ColorProperty colorProperty = new ColorProperty(m_Color);
      ctor.ContextProperties.Add(colorProperty);
   }
   //ctx is the creating client's context
   public override bool IsContextOK(Context
       ctx,IConstructionCallMessage ctorMsg)
   {
      ColorProperty contextColorProperty = null;
      //Find out if the creating context has a color property. If not,
      //reject it
      contextColorProperty = ctx.GetProperty("Color") as ColorProperty;
      if(contextColorProperty == null)
      {
         return false;
      }
      //It does have a color property. Verify color match
      return (m_Color == contextColorProperty.Color);
   }
}

//The ColorProperty is added to the context properties collection by the
//ColorAttribute class
public class ColorProperty : IContextProperty
{
   protected ColorOption m_Color;

   public ColorProperty(ColorOption ContextColor)
   {
      Color = ContextColor;
   }
   public string Name
   {
      get
      {
         return "Color";
      }
   }
   //IsNewContextOK called by the runtime in the new context
   public bool IsNewContextOK(Context ctx)
   {
      ColorProperty newContextColorProperty = null;
      //Find out if the new context has a color property. If not, reject it
      newContextColorProperty = ctx.GetProperty("Color") as ColorProperty;
      if(newContextColorProperty == null)
      {
         return false;
      }
      //It does have color property. Verify color match
      return (this.Color == newContextColorProperty.Color);
   }

   public void Freeze(Context ctx)
   {}
   //Color needs to be public so that the attribute class can access it
   public ColorOption Color
   {
      get
      {
         return m_Color;
      }
      set
      {
         m_Color = value;
      }
   }
}

The IsContextOK method lets the context attribute examine the creating client's context provided in the ctx parameter. Every context has an object of the Context type associated with it. The Context object provides easy access to the context properties. If the client's context is adequate, then no further action is required and the runtime activates the new object in the creating client's context. If the content attribute returns false from IsContextOK, then a new context is created and GetPropertiesForNewContext is called, allowing the context attribute to add new properties to the new context.

In fact, because there can be more than one context attribute on a single object, the .NET Framework can optimize its queries of the attributes when examining the client's context. It starts iterating over the attribute list, calling IsContextOK on each attribute in the process. As soon as it finds one attribute in the list that returns false, it aborts the iteration and creates a new context. It then calls GetPropertiesForNewContext on each context attribute, letting it add its properties to the new context. ColorAttribute needs to override both methods of IContextAttribute and manage its single context property. Context properties are objects implementing the IContextProperty interface:

public interface IContextProperty
{
   string Name{ get; }
   void Freeze(Context newContext);
   bool IsNewContextOK(Context newCtx);
}

Each context property is identified by name through the Name property of IContextProperty. ColorAttribute uses a helper class called ColorProperty to implement IContextProperty. ColorProperty names itself as "Color." ColorProperty also provides the Color public property of type ColorOption. This allows for type-safe checking of the color value.

In its implementation of IsContextOK, ColorAttribute checks whether the client's context has a property called "Color." If not, IsContextOK returns false. If the client's context has a color property, ColorAttribute verifies that there is a color match by comparing the value of the Color property with its own color.

The implementation of GetPropertiesForNewContext is straightforward as well. The single parameter is of type IConstructionCallMessage, providing a collection of properties for the new context through the ContextProperties property. ColorAttribute creates an object of the ColorProperty type, initializes it with the required color, and adds it to the collection of properties for the new context.

Because a single context-bound object can have multiple context attributes, it is possible that some of them conflict. To handle this, IsNewContextOK is called on each property after all the properties are added to the new context. If any one of the properties returns false, then the instantiation of the new object is aborted and an exception of the RemotingException type is thrown. In IsNewContextOK, ColorAttribute simply verifies that the new context has the correct color. The Freeze method lets a context property know that the final location of the context is established, and is available for advanced use only.

Figure 5 Custom Context Attribute Flow
Figure 5 Custom Context Attribute Flow

Figure 5 is an activity diagram describing the activation flow when using a custom context attribute and a context property.

Custom Message Sink

To provide a useful component service, the custom context attribute must install at least one custom message sink. The message sink can be a server context sink, a server object sink, a client context sink, or an envoy sink. Commonly, a custom context attribute will install only a server context sink. The other sinks are intended for advanced scenarios. For each type of custom sink you want to contribute to the interception chain, the custom context property must implement a matching interface.

Providing Four Types of Sinks

To contribute a server context sink, the custom context property needs to implement the IContributeServerContextSink interface, which is defined as:

public interface IContributeServerContextSink
{
   IMessageSink GetServerContextSink(IMessageSink nextSink);
}
In its implementation of GetServerContextSink, the context property creates a sink object and concatenates it with the next sink in the chain provided as the method parameter. GetServerContextSink should return the new sink it created so that it will be added to the interception chain. For example, here is how to install the GenericSink presented in Figure 2 as a server context sink:
public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
   IMessageSink sink = new GenericSink(nextSink);
   return sink;
}
The server context sink intercepts all calls coming into the context. GetServerContextSink is called after its call to IContextProperty.IsNewContextOK but before creating the object, allowing the context property to provide the sink. A server context sink can intercept construction calls.

To install a client context sink, the context property needs to implement the IContributeClientContextSink, defined as:

public interface IContributeClientContextSink
{
   IMessageSink GetClientContextSink(IMessageSink nextSink);
}
A client context sink affects the context-bound object only when it is the client of another object outside the context. A client context sink will intercept all calls exiting the context. GetClientContextSink is called only when the object makes its first call outside the context. The information in the message object passed to the sink will pertain to the target object, not the client.

If the context property implements the IContributeEnvoySink interface, shown in the following code snippet, then when a proxy is set up on the client's side to the object, the proxy will have the envoy sink as part of the interception chain leading to the particular object in question:

public interface IContributeEnvoySink
{
   IMessageSink GetEnvoySink(MarshalByRefObject obj,
       IMessageSink nextSink);
}

The envoy sink will intercept all calls going from the client to the object. Other objects accessed by the client are not affected. Every time a new client in a different context connects to the object, the runtime installs an envoy sink in the client's context. GetEnvoySink is called after the new object is created, but before returning control to the client. When using an envoy sink, it is not possible to intercept construction calls.

To install an object sink, the context property needs to implement the IContributeObjectSink interface, defined as:

public interface IContributeObjectSink
{
   IMessageSink GetObjectSink(MarshalByRefObject obj,
       IMessageSink nextSink);
}
The envoy sink is installed on an per object basis, meaning it will only intercept calls to an object whose reference is provided in the GetObjectSink call. Other calls to the context are not affected. GetObjectSink is called before the first method call is forwarded. As a result of this, when using an object sink, it is not possible to intercept construction calls.

Processing Messages

The IMessage interface presented previously is a collection of information about the method being intercepted. Although you could retrieve that information from the dictionary, there is another way. When intercepting an incoming call, the different message objects (used for synchronous methods, asynchronous methods, and constructor calls) all support the IMethodMessage interface, as defined in Figure 6.

Figure 6 IMethodMessage Interface (Close Figure 6)
public interface IMethodMessage : IMessage
{
   int ArgCount{ get; }
   object[] Args{ get; }
   bool HasVarArgs{ get; }
   LogicalCallContext LogicalCallContext { get; }
   MethodBase MethodBase { get; }
   string MethodName{ get; }
   object MethodSignature{ get; }
   string TypeName{ get; }
   string Uri{ get; }
   object GetArg(int argNum);
   string GetArgName(int index);
}

IMethodMessage provides information about the method name, its arguments, the type on which the method is called, and the object's location. You can use that information in your pre-call message processing logic. After the last sink (the stack builder) invokes the call on the object, it returns a different message object. Again, there are several types of returned method objects, but they are all polymorphic with the IMethodReturnMessage interface, defined as the following:

public interface IMethodReturnMessage : IMethodMessage
{
   Exception Exception { get; }
   int OutArgCount { get; }
   object[] OutArgs { get; }
   object ReturnValue { get; }
   object GetOutArg(int argNum);
   string GetOutArgName(int index);
}

IMethodReturnMessage derives from IMethodMessage and it provides additional information about the method returned value, the value of outgoing parameters, and exception information. The fact that exception information is captured is of particular interest. If an object throws an exception, the stack builder sink silently catches it, and saves it in the returned message object. This allows all the sinks up the call chain to examine the exception object. When control returns to the proxy, if exception information is present, the proxy rethrows it on the calling client's side.

The Logbook Service

It's time to put all the knowledge and intricacies I've described so far to use with a real-life example. One of the most beneficial steps you can take to achieve robustness in an application and to decrease time to market is to add a logbook capability to your application. The logbook is a simple custom component service that enables you to log method calls and exceptions. It intercepts incoming calls to your context-bound objects and logs most of the information in the message. As you will see shortly, you can use the same logbook to record method invocation from multiple machines and have the various entries interleaved in order.

Each logbook entry contains the following information, captured automatically by the logbook:

  • The location where the method was invoked, including the machine name, app domain name, thread ID and name, and the context ID
  • The caller's identity (user name)
  • Information about the target object: its assembly, its type, and the member being accessed (constructor, method, property, indexer, or event)
  • Invocation date and time
  • Error information if an exception was thrown; the type of the exception and the exception message

Using the Logbook

A key requirement in designing the logbook was that it should require no participation by the object. The object should focus on implementing its business logic, and the logbook should do the logging. To add logging support for a context-bound object, add the LogbookAttribute custom context attribute defined in the ContextLogger namespace:

using ContextLogger;

[Logbook]
public class SomeClass : ContextBoundObject
{...}

The logbook service enables developers to choose what specific information to log. Sometimes, it's necessary to record everything that takes place: method calls and errors. In other situations, it is sufficient to log only errors and exceptions. To that end, the logbook provides the enum LogOption, defined as:

public enum LogOption
{
   MethodCalls,
   Errors
}

You can provide the constructor of LogbookAttribute with the appropriate enum value. For example, to log errors only, you would write:

[Logbook(LogOption.Errors)]
public class SomeClass : ContextBoundObject
{...}

The parameterless constructor of LogbookAttribute defaults to LogOption.MethodCalls so these two declarations are equivalent and will log both method calls and errors:

[Logbook]
[Logbook(LogOption.MethodCalls)]

The Logbook Service Architecture

When you apply LogbookAttribute to a context-bound class, it will insist on having private contexts for each instance. This is required to support logging all calls coming into the object. If it were possible for two objects using the LogbookAttribute to share a context, then cross-context calls would have been logged, but the intra-context calls they made on each other would not have been logged. The LogbookAttribute adds a property called LogContextProperty to the new context, which itself adds a server context sink called LogSink. LogSink intercepts all calls to the object but does not log them itself. Instead, it uses the Logbook component. Logbook encapsulates the actual logging mechanism. The implementation provided here records the information into a SQL Server™ database, but you can replace that with a storage method or device of your choosing.

Also note that the Logbook is a remote singleton residing in an EXE host. As a result, all objects using the logbook service will actually log to the same repository, in order. This is a key feature, allowing you to trace the execution of a distributed application because the host can actually be on a dedicated machine that is used by all other machines.

Figure 7 Logbook Service Architecture
Figure 7 Logbook Service Architecture

Figure 7 depicts the logbook architecture. In addition, a logbook viewer application is provided, displaying in a grid control the content of the logbook database entries table. The logbook viewer does not connect to the database directly, but instead connects to the singleton object Logbook. If the logbook viewer connected directly to the database, it would couple the viewer to the repository being used (a database, in this case). As a result, you would have to modify the viewer every time you switched repositories, for example if you wanted to store the logbook entries in a flat file instead of a database. The Logbook provides the necessary degree of separation between them.

The source files accompanying this article provide the Logbook solution (see the link at the top of this article). The solution has the following projects: the ContextLogger class library contains the LogbookAttribute, the LogContextProperty, the LogSink, and the Logbook component itself. Logbook is an ADO.NET component, accessing a SQL Server database. Run the included Logbook.sql script file to create a database called Logbook with the Entries table. The LogbookHost project is a simple Windows® Forms EXE which hosts Logbook. The LogbookHost configuration file exposes the Logbook type as a server-activated singleton object.

The TestClient project is a Windows Forms application which has a test class and the test client. The test class is a context-bound class that uses the LogbookAttribute. The test client is a form which is able to exercise various calls on the test object. The configuration file of the TestClient application registers the Logbook component as a remote server-activated object whose URL connects to the LogbookHost application. The LogbookViewer project contains the logbook viewer, letting you browse the logbook entries or clear the table (see Figure 8). The LogbookViewer application registers the Logbook component as a remote server as well.

Figure 8 Logbook Viewer (Close Figure 8)

Implementing the Logbook

The LogbookAttribute class is not that much different from the ColorAttribute class shown in Figure 4. It refuses the client's context in its IsContextOK and installs the LogContextProperty in its GetPropertiesForNewContext method. Figure 9 shows the implementation of LogbookAttribute.

Figure 9 LogbookAttribute Class (Close Figure 9)
[AttributeUsage(AttributeTargets.Class)]
public class LogbookAttribute : ContextAttribute
{
   LogOption m_LogOption;

   public LogbookAttribute(): this(LogOption.MethodCalls)
   {}

   public LogbookAttribute(LogOption logOption):base("LogbookAttribute")
   {
      m_LogOption = logOption;
   }
   // Add a new logbook property to the new context
   public override void
       GetPropertiesForNewContext(IConstructionCallMessage ctor)
   {
      LogContextProperty logProperty = new
          LogContextProperty(m_LogOption);
      ctor.ContextProperties.Add(logProperty);
   }

   //Called by the runtime in the creating client's context
   public override bool IsContextOK(Context ctx,IConstructionCallMessage
                                    ctorMsg)
   {
      return false;
   }
}
/*The LogContextProperty implements the IContributeServerContextSink interface,
installing the LogSink server context sink:*/
public class LogContextProperty : IContextProperty,IContributeServerContextSink
{
   protected LogOption m_LogOption;

   public IMessageSink GetServerContextSink(IMessageSink nextSink)
   {
      IMessageSink logSink = new LogSink(nextSink,m_LogOption);
      return logSink;
   }
   /* Rest of the implementation  */
}

The interesting part of the logbook service is, of course, the LogSink class. In its implementation of IMessageSink, LogSink processes the message object, constructs an instance of the LogbookEntry structure, providing it with the information extracted from the message. LogbookEntry stores the information provided as construction parameters and captures additional information such as object location and execution scope (see Figure 10). LogSink then passes the LogbookEntry object to the Logbook component. Because it's accessed as a remote component, LogbookEntry is marshaled by value using the Serializable attribute.

Figure 10 LogbookEntry Structure (Close Figure 10)
[Serializable]
public struct LogbookEntry
{
   public LogbookEntry(string assemblyName,string typeName,
                       string methodName): this(assemblyName,
                       methodName,typeName,"","")
   {}
   public LogbookEntry(string assemblyName,string typeName,string
                       methodName, string exceptionName,string
                       exceptionMessage)
   {
      AssemblyName     = assemblyName;
      TypeName         = typeName;
      MemberAccessed   = methodName;
      ExceptionName    = exceptionName;
      ExceptionMessage = exceptionMessage;

      MachineName   = Environment.MachineName;
      AppDomainName = AppDomain.CurrentDomain.FriendlyName;
      ThreadID      = Thread.CurrentThread.GetHashCode();
      ThreadName    = Thread.CurrentThread.Name;
      ContextID     = Thread.CurrentContext.ContextID;
      Date = DateTime.Now.ToShortDateString();
      Time = DateTime.Now.ToLongTimeString();
      if(Thread.CurrentPrincipal.Identity.IsAuthenticated)
      {
         UserName = Thread.CurrentPrincipal.Identity.Name;
      }
      else
      {
         UserName = "Unauthenticated";
      }

   }
   //Location
   public readonly string MachineName;
   public readonly string AppDomainName;
   public readonly int    ThreadID;
   public readonly string ThreadName;
   public readonly int    ContextID;
   //Identity
   public readonly string UserName;
   //Object info
   public readonly string AssemblyName;
   public readonly string TypeName;
   public readonly string MemberAccessed;
   public readonly string Date;
   public readonly string Time;
   //Exception
   public readonly string ExceptionName;
   public readonly string ExceptionMessage;
}

Figure 11 contains most of the implementation of LogSink. The constructor saves the logging filer (methods or errors), as well as the next message sink in the chain, and creates a new Logbook object (a proxy to the remote singleton). In SyncProcessMessage, LogSink downcasts the message object to IMethodMessage and passes it to several helper methods. Then, it forwards the call to the next sink, eventually calling the object. When the call returns, LogSink downcasts the returned message to IMethodReturnMessage and uses other helper methods to get the exception information (if an exception took place). When the processing is finished, LogSink constructs a LogbookEntry object and adds it to the logbook using the Logbook object.

Figure 11 LogSink Class (Close Figure 11)
public class LogSink : IMessageSink
{
   IMessageSink m_NextSink;
   LogOption m_LogOption;
   Logbook m_Logbook;

   public LogSink(IMessageSink nextSink,LogOption logOption)
   {
      m_LogOption = logOption;
      m_NextSink = nextSink;
      m_Logbook = new Logbook();
   }
   public IMessageSink NextSink
   {
      get {return m_NextSink;}
   }
   public IMessage SyncProcessMessage(IMessage msg)
   {
      IMethodMessage methodMessage = (IMethodMessage)msg;
      string assemblyName = GetAssemblyName(methodMessage);
      string typeName     = GetTypeName(methodMessage);
      string methodName   = GetMethodName(methodMessage);

      IMethodReturnMessage returnedMessage;
      returnedMessage =
          (IMethodReturnMessage)m_NextSink.SyncProcessMessage(msg);

      string exceptionName     = GetExceptionName(returnedMessage);
      string exceptionMessage  = GetExceptionMessage(returnedMessage);

      LogbookEntry logbookEntry = new LogbookEntry(assemblyName,
                                      typeName,methodName,
                                      exceptionName,exceptionMessage);

      DoLogging(logbookEntry);

      return returnedMessage;
   }
   public IMessageCtrl AsyncProcessMessage(IMessage msg,IMessageSink
       replySink)
   {
      /* Processing of the message, similar to SyncProcessMessage()  */
   }

   void DoLogging(LogbookEntry logbookEntry)
   {
      if(m_LogOption == LogOption.MethodCalls)
      {
         LogCall(logbookEntry);
      }
      if(m_LogOption == LogOption.Errors)
      {
         if(logbookEntry.ExceptionName != "")
         {
            LogCall(logbookEntry);
         }
      }
   }
   void LogCall(LogbookEntry logbookEntry)
   {
      m_Logbook.AddEntry(logbookEntry);
   }
   static string GetMethodName(IMethodMessage methodMessage)
   {
      /* Processes methodMessage.MethodName  */
   }
   static string GetTypeName(IMethodMessage methodMessage)
   {
      /* Processes methodMessage.TypeName  */
   }
   static string GetAssemblyName(IMethodMessage methodMessage)
   {
      /* Processes methodMessage.TypeName  */
   }
   static string GetExceptionName(IMethodReturnMessage returnedMessage)
   {
      /* Processes returnedMessage.Exception */
   }
   static string GetExceptionMessage(IMethodReturnMessage returnedMessage)
   {
      /* Processes returnedMessage.Exception.Message */
   }
}

The Logbook component derives from the Component class defined in the System.ComponentModel namespace. Deriving from Component allows you to use Visual Studio .NET to generate much of the ADO.NET data connectivity classes and code. However, the Logbook must be available for remoting. Fortunately, Component derives from MarshalByRefObject. The Logbook component overrides InitializeLifetimeService and provides a null lease. This is required to maintain the singleton semantics so that the object will in fact live indefinitely:

public class Logbook : Component
{
   //Logbook should be used as a singleton
   public override object InitializeLifetimeService()
   {
      return null;
   }
   /* Rest of the implementation */
}

The Logbook component uses ADO.NET to connect to the Logbook database and store or retrieve the entries using a DataSet. It's is a thread-safe component that locks itself in every method call to synchronize concurrent access.

Conclusion

Interception-based services are not new to component developers, and previous component technologies from Microsoft (notably COM and COM+) used interception to provide for component services. With the .NET Framework, for the first time developers can define custom component services, which are as useful, productive, and powerful as any service provided by Windows operating systems. It is possible that Microsoft will provide additional services for context-bound objects in future releases of the Framework. Even though context attributes and custom message sinks are presently undocumented features of the .NET Framework, I believe that using them is a risk worth taking in order to unleash the power of custom component services.

For related articles see:
House of COM: Is COM Dead?
AOP: Aspect-Oriented Programming Enables Better Code Encapsulation and Reuse

For background information see:
Programming .NET Components by Juval Lowy (O'Reilly, March 2003)

Juval Lowyis a software architect providing consultation and training on .NET design and .NET migration. He is also the Microsoft Regional Director for the Silicon Valley. This article is adapted from his latest book, Programming .NET Components (O'Reilly, March 2003). Contact Juval at http://www.idesign.net.


Editor's Note: Patterns Patterns Everywhere

Editor's Note
Patterns Patterns Everywhere

As loyal readers of MSDN Magazine know, each month's Editor's Note starts out with a tepid, last-minute stab at humorous content. The formula's pretty tried-and-true by now, and you could probably fill in the details in your sleep. It goes like this: list three or four absurdly mismatched items ("skin diving, scrubbing toilets, puppy rodeos, and knitting acrylic scarves") and juxtapose them into some wacky situation ("yes, it's nearly springtime in New York City!"). Voilà—instant intro. It's easy to churn out a paragraph like this with minimal effort, and it can be used as a springboard to whatever discussion we're about to present.

We discovered this formula years ago, and we've perfected it over the years to the point where we can auto-generate Editor's Notes with a simple Microsoft Word macro. One might say that these pages have a predictable...pattern. A design pattern. It's commonly believed that the Gang of Four book was the publication that made design patterns popular in the development community, but we beg to differ. It was actually our tireless, selfless work on this page (and its predecessors in MSJ and MIND) that gave millions, if not thousands, of programmers their first experience with the world of design patterns.

In programming, design patterns have the same purpose. They take common, definable processes and distill them into the basic, repeatable steps that you can take to reproduce them in any language. This is an especially useful tool when you're building complex enterprise-scale apps. You can sit there for weeks, wondering which is the best way to implement a particular process, or you can rely upon the accumulated wisdom of the development community. Chances are good that you're not the first person to come up against a problem, no matter how it might feel at the time. Design patterns are real-world techniques for producing better, more reliable code more quickly.

This month, we're proud to launch a new column, called simply Design Patterns. As we've now established, MSDN Magazine nearly invented the concept of the pattern. Now we're adding a much-requested feature to the magazine—regular coverage of the world of architecture and design patterns. This month, our guest columnist discusses the Factory pattern—one of the core patterns that you should know—and shows how to implement it using the .NET Framework and C#. Future columns will discuss a number of design patterns and take a more general look at pattern-based architectural issues. If you have something you'd like to share with us for the column, drop us a line at mmpatt@microsoft.com.

But is that all the column news we've got for you this month? Of course not! (Like how we say "Of course not," as if we always go around introducing five new columns a month?) This month we're pleased to introduce a new collaborator, Tim Ewald. Tim's a well-known author and voice in the development community, and he'll be contributing some of his knowledge through our House of Web Services column. Tim knows as much about Web Services as anyone on earth. More importantly, he's one of the songwriters in the stunningly successful MSDN Magazine Band, which made quite a splash at last year's Tech•Ed in New Orleans.

Another well-established Editor's Note pattern is the awkward segue between topics, which is why we're especially excited about Visual Studio .NET 2003. You've probably used Visual Studio .NET by now. It was a revolutionary product that allowed developers to create their first programs built on the .NET Framework. Version 2003 consolidates and extends this model, providing built-in tools that allow you to use the Framework to build programs for Pocket PCs, Windows CE-powered devices, ASP.NET sites that work with mobile devices like cell phones, and lots of other exciting applications. At the same time, Visual Studio .NET 2003 uses the .NET Framework 1.1, which features a number of key improvements in Windows Forms.

One of the most important additions to the development package, however, is language based. If you like the Java language, you can now write your code in the managed environment of .NET—Visual J# is now part of the Visual Studio .NET product. If you're one of the huge segment of experienced programmers who've spent years honing your C++ skills, Visual Studio .NET 2003 has a lot to offer as well. In addition to better adherence to standards, managed C++ is now easier to use—you can access designers, just like you can in C# and Visual Basic .NET. This month's issue of MSDN Magazine brings you articles on Visual Studio .NET 2003, the .NET Framework 1.1, and the newest version of managed C++. Do you detect a pattern here?

—J.T.

Active Directory, ActiveSync, ActiveX, Authenticode, IntelliSense, JScript, Microsoft, MSDN, Outlook, Visual Basic, Visual C++, Visual J++, Visual Studio, Windows, Windows NT, and Win32 are registered trademarks of Microsoft Corporation. Visual J# is a trademark of Microsoft Corporation. Other trademarks or tradenames mentioned herein are the property of their respective owners.

MSDN Magazine does not make any representation or warranty, express or implied with respect to any code or other information herein. MSDN Magazine disclaims any liability whatsoever for any use of such code or other information.


New Stuff: Resources for Your Developer Toolbox

New Stuff
Resources for Your Developer Toolbox
Theresa W. Carey

Contents
Print Code in Visual Basic .NET
Barcodes in .NET-centric Apps
Web Site QA and Accessibility Check
Imaging Capabilities for Your Apps
Multimonitor Support
.NET Development Components
Manage Those Code Snippets
Object Modeling with UML
The Bookshelf

Print Code in Visual Basic .NET

StarPrint Limited has released VS.NETcodePrint, a Visual Studio® .NET Add-in that allows you to produce printouts of source code in Visual Basic® .NET. You can preview the printouts before printing and exporting to RTF, HTML, and PDF formats. You can print, preview, and export a complete solution, selected projects, project items, namespaces, classes, modules, and procedures. The program's WYSIWYG preview screens let you look at the formatted source code with zooming, multipage thumbnails, and side-by-side pages.

VS.NETcodePrint allows users to customize the font attributes and colors for comments, identifiers, keywords, line numbers, strings, procedure headings, table of contents, and page headers or footers. This color coding, combined with custom indenting, line numbering, and line spacing, shows the language statement constructs clearly and allows for speedy code inspections.

Barcodes in .NET-centric Apps

IDautomation.com Inc. has released Linear .NET Barcode Forms Control, which integrates barcode technology directly into applications built using the Microsoft .NET Framework. The managed code control is provided with sample projects in C# and Visual Basic .NET. By integrating barcode technology directly into apps, it is no longer necessary to export data to a proprietary label program to print barcodes. Linear .NET Barcode Forms Control is compatible with development environments that can utilize .NET Forms Controls.

Several bar code symbologies are supported in this control including Code 39, Code 128, UCC-128, Interleaved 2 of 5, UPC, EAN, Codabar, and POSTNET. In an application, the control can be used on a form or as a DLL that is not seen on a form. The control can also be used to create barcodes in WMF, JPEG, TIFF, BMP, PNG, and other image files.

Other features include device-independent graphics, data binding, adjustable orientation, and strong name support. All functionality is implemented in a single file that is less than 150KB.

Web Site QA and Accessibility Check

Watchfire Corporation recently released Watchfire WebQA 2.0, a Web site quality testing tool designed for small to medium-sized Web sites or departmental sites. The program provides a content testing solution for individual developers or quality assurance engineers.

WebQA 2.0 now includes the ability to test for an organization's level of compliance with government standards, including the U.S. Government's Section 508 and the W3C's Web Content Accessibility Guidelines (WCAG). WebQA scans and checks a site for more than 100 potential problems and reports on issues such as broken links, spelling mistakes, slow loading pages, missing keywords and ALT text, orphaned files, and page quality. WebQA can scan and check most file formats including HTML, JavaScript, Flash, and dynamically generated content (ASP, JSP, or CFM, for example).

WebQA allows developers to test Web pages and generate summary reports highlighting accessibility issues before posting the content to live servers. The software records and plays back scripts that duplicate the actions a user makes on a site to see if the transactions and interactions on the site, such as checkouts and login forms, are working as designed. WebQA can also automatically add, edit, and manage metatags in documents on the site to improve search engine effectiveness.

Imaging Capabilities for Your Apps

Atalasoft Inc. has released ImgX Controls 6.2 for Visual Basic .NET, a collection of controls that let you add basic imaging functions such as capturing, scanning, and printing images, as well as high-end image viewing and manipulation capabilities. ImgX will read and write most popular graphics file formats. ImgX uses a low-level C++ imaging library providing image processing with an ActiveX® front end. You can draw lines, rectangles, ellipses, and add text with a textured background and antialiasing. You can create linear and radial gradients and use them as texture for text and shapes.

ImgX includes 20 resampling methods and overlay images with an alpha transparency. You can display and zoom images with a scrollable viewport and create ActiveX Web imaging with the ImgX OCX control. In addition, you can control print settings, show dialogs, print images, and replace the Visual Basic Printer object with the ImgXPrint DLL. The controls suite includes a customizable image preview dialog for opening and saving images with the ImgXDialog DLL.

The ImgTwain DLL provides twain support for scanning images with basic and advanced duplex features. The ImgCapture DLL provides screen capture support. ImgX is .NET ready with strong-named .NET interop and extender libraries.

Multimonitor Support

Realtime Soft has released version 2.0 of the UltraMon Developer Edition, a collection of components for developers who want to add multimonitor support to their Windows®-based applications. The UltraMon Developer Edition provides a COM-based multimonitor API which can be used from most programming languages and environments, including Visual Basic, C++, and those that target the .NET Framework. UltraMon lets you get and set monitor properties (resolution, enabled, primary, and so on), move or maximize windows, provide a user interface for visually selecting a monitor, and treat a monitor as detached from the desktop (Virtual Independent Displays feature).

.NET Development Components

Steema Software SL has released two components for Visual Studio .NET development. teeChart.Net Charting Control provides a library of components with multiple graph styles in 2D, 3D, and OpenGL, 24 mathematical and financial functions, multiple axes, multiple export formats, page charts, and database charts. It includes optional C# source code, custom canvas, toolbar, and a chart gallery. teeChart.Net Charting Control can be used on the desktop as well as in server-based and ASP.NET applications. TeeGofer .Net Component Documenter is a help template builder for component writers working in Visual Studio .NET.

Manage Those Code Snippets

iCode has released version 3.0 of iCodeRepository, a utility that allows you to collect reusable source code. You can pick up your favorite source code snippets from your daily coding or Internet searches and organize them with iCodeRepository.

Other tools include txt2html, which converts the source of files to HTML format with syntax highlighting, Mini Spy++, which retrieves Windows system information, and File Killer, which provides a shortcut to deleting files from your hard disk.

You can monitor the text on your clipboard with the Clipboard Monitor and use Keyboard Viewer to get access to keyboard values, scan codes, and Ctrl-Alt shortcuts.

iCodeRepository has a built-in text editor that supports syntax highlighting in Visual Basic, C++, Java, Object Pascal, and 30 other programming languages. Version 3.0 includes a Windows XP-style interface and the ability to add icrEdit to the context menu, allowing users to open files by right-clicking them.

Object Modeling with UML

Visual Object Modelers recently announced the release of version 3.0 of Visual UML, a UML 1.3- and 1.4- compliant object-modeling tool that provides support for all of the UML diagram types: class, object, package, use case, component, deployment, activity, state and interaction (collaboration and sequence) diagrams. It also supports robustness diagrams and extensions for Web modeling, XML modeling, data modeling/database design, and business object modeling. Visual UML can be run as an add-in to Visual Basic and Visual Studio .NET.

The Visual UML Developer Edition includes Visual Basic, C++, C#, Visual Basic .NET, and Java code generation; reverse-engineering of Visual Basic, C#, Visual Basic .NET, and Java code; database schema generation and database reverse-engineering.

The Visual UML Plus Edition incorporates Visual Basic for Applications (VBA) 6.3, allowing users to create VBA projects and write VBA scripts to control and extend Visual UML through its OLE Automation/ActiveX interface and exposed object model.

The Bookshelf

O'Reilly's new MySQL Cookbook by Paul DuBois offers solutions to everyday programming dilemmas. For every problem addressed in the book, there's a worked-out solution or "recipe"—a short, ready-to-use piece of code. The discussion section explains how and why the code works, so readers can learn to adapt the techniques to similar situations. The source code and sample data used throughout the book are available at a companion Web site, http://www.bitbybit.dk/mysqlfaq.

From simple ways to find all records that contain a given string, to more difficult problems, such as finding matching and non-matching records in two tables, MySQL Cookbook addresses challenges that database administrators face every day. Learn how to import data from external sources, export data for use by external programs, access MySQL from your Web server, use scripts with MySQL to read queries from a file, and access MySQL from within client programs that use Perl, PHP, Java, Python, and other languages.

The book also guides you to construct queries that solve frequently asked questions, and identify, count, and remove duplicate records. For more information about the book see http://www.oreilly.com/catalog/mysqlckbk.

Contacts

Atalasoft Inc. 304 East Mountain Road, Westfield, MA 01085, http://www.atalasoft.com

iCode http://www.iCodeRepository.com

IDAutomation.com Inc. 550 North Reo Street, Suite 300, Tampa, FL 33609, 813-261-5064, http://www.IDAutomation.com

Realtime Soft Neufeldstrasse 27, 3012 Bern, Switzerland, +41 31 301 79 18, http://www.realtimesoft.com

StarPrint Limited P.O. Box 3139, Wokingham, Berkshire, RG41 2FZ UK, +44 (0) 118-979-4107, http://www.starprint2000.com

Steema Software SL Emili Grahit 31-35, Ent-D, 17002 Girona, Catalonia, Spain, +34-972-21-87-97, http://www.steema.com

Visual Object Modelers Inc. 4450 Arapahoe Avenue, Suite 100, Boulder, CO 80303, 800-900-1902, 303-448-8835, http://www.visualobject.com

Watchfire Corporation 200 West Street, Waltham, MA 02451, 800-282-5951, 781-810-1450, http://www.watchfire.com

Send your New Stuff to Theresa at newstuff@microsoft.com.

Theresa W. Careyis a freelance writer who lives in California. Her byline has appeared in Barron's and PC World.


Web Q&amp;A: IDs as Anchors, Preventing Search, and More

Web Q&A
IDs as Anchors, Preventing Search, and More
Edited by Nancy Michell

Q I use <base href="http://go.msn.com/"> on my Web pages to control page performance. I want to provide a "back to top" link, implemented as follows:

On the top of the page I use:

<a name="top"></a>
On the bottom I use:
<a href="#top">back to top</a>

Of course, the easy approach doesn't work because the browser resolves this link as http://go.msn.com/#top. So I need to build the href value for the back to top anchor within my ASP.NET code.

According to the standards, what should the format be in a case where there's a query string in the URL? Should it be this

http://www.foo.com/page.aspx#top?x=1
or this:
http://www.foo.com/page.aspx?x=1#top

A Actually, you can do this with even less code by putting id="top" in your <body> tag:

<body id="top">

There's no need for meaningless empty anchor tags. You can make your code even smaller by using the id attribute on the actual element you are trying to jump to. Instead of

<h2><a name="sectionfoo"></a>Here is headline for section foo</h2>
use this:
<h2 id="sectionfoo">Here is headline for section foo</h2>
You're just saving a few bytes, but it adds up for those larger pages. A link back to top looks like this:
http://www.foo.com/page.aspx?x=1#top

Q Is there HTML code for disabling full-text and other searches?

A A robots.txt file tells most robots what to do. You can put a robots.txt file in the root directory of your Web server. The file is plain text and looks like this:

User-agent: *
Disallow: /nosearch/
Disallow: /nosearch.htm

User-agent: * applies to all search engines. This tells search engines not to index any of the pages in this directory. For individual pages, use a meta tag in the HTML header like this:

<META name="robots" content="noindex, nofollow">
Other attributes you can add to the content, separated by commas, are: all, none, index, noindex, follow, and nofollow. Content="all" means all content is indexed and searchable. "None" means no content on the page is searchable; "follow" means all the links on that page can be crawled. And "nofollow" means none of them should be, and so on. For example,
<META name="robots" content="index, nofollow">
means that the content will be searchable, but the spider should not follow the links on that page to find more content to index.

Q I've been using Visual Basic® for a long time and I'm familiar with the Microsoft® .NET Framework, but I am by no means an expert in it. I really need help understanding some behavior a programmer on my team (who also has a background in Visual Basic) saw when using inheritance and overloading. This programmer has written what appears to be identical source logic in both Visual Basic and C#: a base class containing two functions taking single parameters (int and string), and a derived class which overloads the function and uses an Object data type.

The programmer creates an instance of the derived class and passes an int, string, and object. In Visual Basic .NET, the functions called are the int and string functions in the base class and the object function in the derived class. In C#, the object function appears to be called three times instead of the number corresponding to the data type. I don't understand this difference in behavior.

A What is happening is simple (see Figure 1). You have a method, test.DoSomething, which takes an object parameter—public void DoSomething(object value) . You then call this method three times:

tst.DoSomething(nr);
tst.DoSomething(str);
tst.DoSomething(2.3);
You shouldn't be surprised that when you call this method it runs and prints "DoSomething(object value)" three times. The int, the string, and the double (2.3) are upcast to object because object is the type your method takes. The test.DoSomething is then run three times with the expected output of:
DoSomething(object value)
DoSomething(object value)
DoSomething(object value)

Figure 1 Sample Code in C# and Visual Basic .NET (Close Figure 1)
C#
main()
{
    test tst = new test();
    int nr = 3;
    string str = "drie";

    tst.DoSomething(nr);
    tst.DoSomething(str);
    tst.DoSomething(2.3);
}

public class testbase
{
        public testbase(){}
        public void DoSomething(int waarde)
        {
                Console.WriteLine("DoSomething(int value)");
        }
        public void DoSomething(string waarde)
        {
                Console.WriteLine("DoSomething(string value)");
        }
}
public class test:testbase
{
        public test():base(){}

        public  void DoSomething(object waarde)
        {
                Console.WriteLine("DoSomething(object value)");
        }
}

/*Expected output:
   DoSomething(int value)
   DoSomething(string value)
   DoSomething(object value)

Program output:
   DoSomething(object value)
   DoSomething(object value)
   DoSomething(object value)*/
Visual Basic .NET
    Sub Main()
        Dim tst As test = New test()
        Dim nr As Integer = 3
        Dim str As String = "drie"

        tst.DoSomething(nr)
        tst.DoSomething(str)
        tst.DoSomething(2.3)

    End Sub

    Public Class testbase
        Public Sub New()
        End Sub
        Public Overloads Sub DoSomething(ByVal waarde As Integer)
            Console.WriteLine("DoSomething(int value)")
        End Sub
        Public Overloads Sub DoSomething(ByVal waarde As String)
            Console.WriteLine("DoSomething(string value)")
        End Sub
    End Class
    Public Class test
        Inherits testbase
        Public Sub New()
            MyBase.New()
        End Sub
        Public Overloads Sub DoSomething(ByVal waarde As Object)
            Console.WriteLine("DoSomething(object value)")
        End Sub
    End Class

'Expected output:
   'DoSomething(int value)
   'DoSomething(string value)
   'DoSomething(object value)
'Program output:
' = Expected output

Visual Basic .NET, C#, and C++ are not the same languages; they do not behave the same way. However, it's easy to see why your programmer is surprised. The overload C# uses is less efficient because it requires the argument to be boxed. Visual Basic uses the more precisely typed overload. From the language specs, you can see that C# tries to use an overload on the derived class, if possible, while Visual Basic tries to use the best match. Why prefer a less efficient overload just because it's declared in the derived class?

Visual Basic avoids that problem by having an explicit Overloads keyword; you can't slip an overload past the Visual Basic compiler. The reason for the C# rules is to be resilient in the face of class evolution (versioning). This ensures that the addition of a method in a base class doesn't break code that binds to a derived class because of accidental overloading.

Q I would like to convert the following code snippet from C# to Visual Basic .NET:

public struct Control : Component{
   private int handle;

   protected int Handle{
      get{
         return handle;
      }
   }
}
When I try to convert it, I get an error "structure cannot have inherits keyword." Is it possible for a structure to inherit an object in Visual Basic .NET?

Following is the code that a C# to Visual Basic .NET converter generates (this code generates the "structure cannot have inherits keyword" error):

Public Structure Control
    Inherits Component
    Private handle As Integer

    ReadOnly Property Handle() As Integer
        Get
            Return handle
        End Get
    End Property
End Structure

A First, you bring up an interesting point for other readers—that there are many converters out there (see http://www.kamalpatel.net/ConvertCSharp2VB.aspx for one). While we don't endorse any, you may find them useful to play around with. Note, however, that converters can get confused if you leave out the open and close braces for functions and may have other issues. Make sure you go through the output code as it may contain errors. Overall, the converters do a decent job and minor tweaking will take care of most of the issues.

On the question of this output code, it doesn't compile in C# either unless Component is an interface, not a class. The struct (in C#) and Structure (in Visual Basic) keywords imply value types, which do not support inheritance. Value types do support implementing interfaces, but this isn't of much use because you have to box the value type in order to use the interface. In other words, you end up with a structure on the stack and a copy on the heap. If Component is an interface instead of a class, then use Implements Component instead of Inherits Component.

Q I have a simple XML document (see Figure 2). I would like to query these nodes (in a Visual Basic 6.0-based app) using an XPath query. However, I'm having a problem querying all nodes. When I use the following query

Set oQueryElemList = oDOM.selectNodes("//TestCases/TestCase/
   Platforms[Platform='Client']")
I only get two test cases found when I'm expecting three. The TestCase with id=1 is skipped since the second <Platform> tag (which is of the value "Client") doesn't seem to be found.

Figure 2 XML Document (Close Figure 2)
<?xml version="1.0" encoding="UTF-8"?>
<TestCases>
       <TestCase id="1">
              <Platforms>
                     <Platform>Server</Platform>
                     <Platform>Client</Platform>
              </Platforms>
       </TestCase>
       <TestCase id="2">
              <Platforms>
                     <Platform>Client</Platform>
              </Platforms>
       </TestCase>
       <TestCase id="3">
              <Platforms>
                     <Platform>Client</Platform>
                     <Platform>Server</Platform>
              </Platforms>
       </TestCase>
</TestCases>

How can I modify my query to tell it to read all child elements in the XML document?

A You can add the $any$ token

Set oQueryElemList = oDOM.selectNodes("//TestCases/TestCase/
   Platforms[$any$ Platform='Client']")
or set the SelectionLanguage property to XPath:
oDOM.setProperty("SelectionLanguage", "XPath");
Set oQueryElemList = oDOM.selectNodes("//TestCases/TestCase/
   Platforms[Platform='Client']")

Q I've written some VBScript code to handle synchronous events fired on a Microsoft Exchange folder. This script includes two subs: ExStoreEvents_OnSyncSave and ExStoreEvents_OnSyncDelete. For the Windows® Script Host (WSH) calling VBScript, the object name, ExStoreEvents, is prepended to the event handler.

I want to write a JScript® version of this same code since JScript has more robust error handling, providing more options and flexibility. I found an article on MSDN® (Scripting Events) which describes how the WSH hooks up to events in JScript. One method is to call WScript.CreateObject on an appropriate object, specifying a second parameter, which is the prefix to use on the event handler name. This doesn't appear to work since I only have an interface to work with, not an actual object. (The object appears to be hidden, so I can't instantiate one of them to specify a name prefix.) The other possible approach is to use an <object> tag for a .wsf file. However, this doesn't work either as the parameter to the "progid" field must also be an automation object and I'm back to the same problem I have with the first approach. How can I write a JScript-based handler to catch these two events?

function Bill_ListView::EveDblClick(index){}

The problem is the name of the "object" to use. In Visual Basic, the name used is "ExStoreEvents", but there is no such object. In this case, what I have is an interface, IExStoreEventInfo, not an actual object (the interface is an object, but not of the proper form). Furthermore, even though the object IExStoreEventInfo is the proper interface, it can't be instantiated as there is no entry for it in the registry. (I looked under HKCR with the ExOleDB prefix and found nothing reasonable for an automation instantiation.)

A You said this doesn't appear to work since you only have an interface to work with, not an actual object, but this makes no sense. First, the question of what the interfaces are is irrelevant—neither JScript nor VBScript use any interface other than IDispatch to call methods on objects. Second, what does it mean to have an interface without having an object that implements it?

If you're using WSH, here's the deal: if your object is cocreatable then you can bind events on it in two ways: use the <object> tag and use the :: syntax, or call WScript.CreateObject and pass in "Foo_" as the prefix. Event "Bar" will then be handled by function "Foo_Bar". If the object is not cocreatable, then you can use WScript.ConnectObject, but the object must support IProvideClassInfo. The underlying explanation is that the outgoing event interface is only accessible if the sink is able to get class type information about the object. That means either supporting IProvideClassInfo or knowing the classid is required for sinking events in late-bound languages.

Got a question? Send questions and comments to WebQA@microsoft.com.

Thanks to the following Microsoft developers for their technical expertise: Michael Beatty, Daniel Boerner, John Caffrey, Sunit Carpenter, Tantek Celik, Matt Curland, Peter Golde, Sean Grimaldi, Glenn Hackney, Phil Johnson, Anton Lapounov, Dan Liebling, Eric Lippert, Michael Rys.


The XML Files: Merging XML Files, Schema Validation, and More

XML Files
Merging XML Files, Schema Validation, and More
Aaron Skonnard

Code download available at: XMLFiles0303.exe (174KB)

Q How can I merge the contents of multiple XML files into one?

A There are a variety of ways to accomplish this with the Microsoft® .NET Framework, each of which uses a different type of XML API. To do this with the DOM API, you need to use the ImportNode function for copying XmlNode objects between documents. Since ImportNode only transfers control of the object between documents, you still need to call AppendChild (or InsertBefore, and so forth) in order to inject the node into the tree.

Figure 1 shows a complete C# example that merges two XML documents (product.xml and material.xml) into one. The new document has a root Container element which will hold the contents of the other two files. Use the XmlReader and XmlWriter APIs. To do this you'd use a single XmlWriter to generate the new XML document, along with several XmlReaders to merge other documents into the new one. XmlWriter provides a WriteNode method that reads through the supplied XmlReader object and writes all of its nodes in one shot (see Figure 2 ).

Figure 2 WriteNode Method (Close Figure 2)
// new document stream
XmlWriter tw = new XmlTextWriter(Console.Out);
tw.WriteStartDocument();
tw.WriteStartElement("Container");
// write product.xml to new document stream
XmlTextReader reader = new XmlTextReader("product.xml");
tw.WriteNode(reader, true);
// write material.xml to new document stream
reader = new XmlTextReader("material.xml");
tw.WriteNode(reader, true);
tw.WriteEndElement();
tw.WriteEndDocument();
Figure 1 Merging XML Docs (Close Figure 1)
// the other documents will be merged into this one
// under the Container element
XmlDocument doc = new XmlDocument();
XmlNode cont = doc.CreateElement("Container");
doc.AppendChild(cont);

// first document to merge
XmlDocument stuff = new XmlDocument();
stuff.Load("product.xml");
XmlNode imported =
  doc.ImportNode(stuff.DocumentElement, true);
doc.DocumentElement.AppendChild(imported);

// second document to merge
stuff.Load("material.xml");
imported = doc.ImportNode(stuff.DocumentElement, true);
doc.DocumentElement.AppendChild(imported);

// print merged documents
Console.WriteLine(doc.InnerXml);

And finally, you could also use XSLT to accomplish this via the document function. This is probably the easiest solution of all:

<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <Container>
      <xsl:copy-of select="document('product.xml')"/>
      <xsl:copy-of select="document('material.xml')"/>
    </Container>
  </xsl:template>
</xsl:stylesheet>
See the code download at the link at the top of this article.

Q Is it possible to validate an XML document against an XML Schema definition embedded within a Web Services Description Language (WSDL) document?

A Yes. XmlValidatingReader is the class that provides XML Schema validation in the .NET Framework. It provides a Schemas property of type XmlSchemaCollection for holding a cache of schemas you want to validate against:

XmlTextReader r = new XmlTextReader("employee.xml");
XmlValidatingReader vr = new XmlValidatingReader(r);
// load schema into cache
vr.Schemas.Add("http://example.org/employee", "emp.xsd");
// read through XML stream - validates along the way
while (vr.Read()) ; // do nothing
This version of Add requires you to specify the namespace along with the file name. To get around having to specify the namespace, you can generate an XmlSchema object by calling XmlSchema.Read and use that instead:
XmlSchema schema = XmlSchema.Read("emp.xsd", null);
vr.Schemas.Add(schema);

The process for validating against an XML Schema definition embedded in a WSDL definition is very similar. Read the WSDL definition into a ServiceDescription object by calling ServiceDescription. You need to read and then iterate through the internal XmlSchema objects, loading them into the XmlSchemaCollection used by XmlValidatingReader:

ServiceDescription sd = ServiceDescription.Read("emp.wsdl");
foreach(XmlSchema embeddedXsd in sd.Types.Schemas)
   vr.Schemas.Add(embeddedXsd);

It doesn't really matter where the schema resides as long as it can be parsed into an XmlSchema object.

Q What are the best techniques for managing Web Service references in client applications?

A One of the ongoing challenges of Web development is link maintenance. Here's a typical scenario. Site A links to resources offered by site B. Sometime later, site B decides to reorganize its site, but site A never finds out about the changes, so its links remain broken for a (potentially long) period of time.

Figure 3 Client with Hardcoded Address
Figure 3 Client with Hardcoded Address

Web Services face the same issue since clients are usually tightly coupled to their endpoints through hardcoded URLs, as illustrated in Figure 3. For example, consider the following .asmx class that contains a simple WebMethod that echoes the input:

[WebService(Namespace="http://example.org/echo")]
public class EchoClass : WebService
{
    [WebMethod]
    public string Echo(string input)
    {
      return
        String.Format("Endpoint location: {0}\nInput: {1}",
          HttpContext.Current.Request.Url,
          input);
    }
}

Assume that this class is bound to an .asmx file called echo.asmx that resides at the URL http://localhost/echoservice/echo.asmx. Using the .NET Framework, you can build a proxy class for this endpoint with wsdl.exe, as shown in the following:

wsdl.exe http://localhost/echoservice/echo.asmx?wsdl

When you do, by default wsdl.exe generates a proxy class with the endpoint's URL hardcoded into the constructor, as shown here:

•••
public class EchoClass : SoapHttpClientProtocol {
  public EchoClass() {
    this.Url = "http://localhost/echoservice/echo.asmx";
  }
  •••
}
This enables you to write code against the proxy without specifying the endpoint location at run time. When you invoke methods on the class, it automatically generates the correct SOAP messages and sends them to the URL hardcoded in the constructor:
EchoClass e = new EchoClass();
// SOAP message for Echo automatically sent to
// http://localhost/echoservice/echo.asmx
Console.WriteLine(e.Echo());

However, if the Web Service administrator decides to move endpoint1.asmx to a different location after the client application ships, he has broken the Web Service link, which can only be fixed by recompiling all client apps hardcoded against the original path.

To help alleviate this problem, wsdl.exe makes it possible to read the URL from a user-defined key in the client application's configuration file. This is accomplished by using the /appsettingurlkey:<key> switch, as shown here:

wsdl.exe /appsettingurlkey:EchoServiceLocation
  http://localhost/echoservice/echo.asmx?wsdl

In this case, the generated proxy's constructor will contain extra code for reading the URL value from the application configuration file before using the default location:

public EchoClass() {
   string urlSetting = ConfigurationSettings.AppSettings[
       "EchoServiceLocation"];
   if ((urlSetting != null)) {
     this.Url = urlSetting;
   }
   else {
     this.Url = "http://localhost/echoservice/echo.asmx";
   }
}

Now, assuming the application assembly is called client.exe, you can create a configuration file called client.exe.config with the following appSettings key to configure the proxy class dynamically:

<configuration>
  <appSettings>
    <add key="EchoServiceLocation"
      value="http://localhost/echoservice/echo.asmx" />
  </appSettings>
</configuration>

With this in place, if the Web Service administrators decide to move things around, at least client applications don't have to be recompiled. They can simply update their local configuration files with the new location and they're ready to go. This still isn't ideal, however, since clients have to find out the correct location and make the change manually.

Universal Description, Discovery, and Integration (UDDI) can simplify things a step further through the UDDI invocation pattern. This pattern defines a sequence of steps for determining the current location of a Web Service at run time. In a nutshell it states that if you invoke a service and the endpoint is not found, you then query a well-known UDDI repository (whose address shouldn't change) and request the Web Service's current location. As long as the Web Service is registered with UDDI and has kept its record up to date, the client should then be able to update its local configuration and reattempt the invocation. Implementing the UDDI invocation pattern makes it possible for your proxy to determine the new location and update the local configuration file automatically.

To use the UDDI invocation pattern, first you need to publish your Web Service with a UDDI repository, like the one Microsoft offers at http://uddi.microsoft.com. You could also host your own enterprise-level UDDI repository and just use it locally. Windows® Server 2003 will ship with UDDI Services to facilitate this. It doesn't really matter where you decide to publish your Web Services since the UDDI API is the same regardless.

If you don't already have an account with the UDDI server you decide to use, you'll have to register yourself first. Then, simply walk through the steps to publish your Web Service. Once you've published your Web Service, the UDDI server assigns it a binding key that you'll use in the future to look it up (see Figure 4). With the UDDI SDK 2.0, Microsoft makes it easy to programmatically access the UDDI repository in languages targeted for the .NET Framework. The FindCurrentLocation method in Figure 5 shows how to implement part of the UDDI invocation pattern.

Figure 5 FindCurrentLocation (Close Figure 5)
using System;
using System.Configuration;
using Microsoft.Uddi;
•••

public static string FindCurrentLocation(
  WebException we, string bindingKeyName, string uddiKeyName)
{
    if (NotFound(we))
    {
        Inquire.Url =
            ConfigurationSettings.AppSettings[keyName];
        GetBindingDetail gbd = new GetBindingDetail();
        gbd.BindingKeys.Add(
          ConfigurationSettings.AppSettings[bindingKeyName]);
        BindingDetail bd = gbd.Send();
        if (bd != null && bd.BindingTemplates.Count > 0)
          return bd.BindingTemplates[0].AccessPoint.Text;
    }
    return "";
}
Figure 4 Registering a Web Service with UDDI
Figure 4 Registering a Web Service with UDDI

The method expects to find the UDDI server's URL as well as the Web Service binding key in the client application's configuration file, making it easy to reuse the code across projects and Web Services. It only contacts the UDDI server if it determines the WebException was related to an inability to find the host or endpoint through the call to NotFound (see Figure 6).

Figure 6 NotFound (Close Figure 6)
internal static bool NotFound(WebException we)
{
    if (we.Status == WebExceptionStatus.ConnectFailure)
        return true;
    else if (we.Response != null)
    {
        HttpWebResponse r =
            we.Response as HttpWebResponse;
        switch (r.StatusCode)
        {
            case HttpStatusCode.Gone:
            case HttpStatusCode.NotFound:
            case HttpStatusCode.Moved:
            case HttpStatusCode.Redirect:
                return true;
            default:
                return false;
        }
    }
    return false;
}

If you're successful in finding the new location of the Web Service through the call to FindCurrentLocation, you'll also want to update the client's configuration file so it doesn't have to perform the query every time the Web Service is invoked. This can be accomplished using the DOM, as shown in Figure 7. I put FindCurrentLocation and UpdateLocalConfiguration into a class called InvocationPattern and marked them as public/static. You can easily use these methods inside of your error handling code for a given Web Service invocation.

Figure 7 Update Config File (Close Figure 7)
public static void UpdateLocalConfiguration(string configFileName,
    string keyName, string keyValue)
{
    XmlDocument doc = new XmlDocument();
    doc.Load(configFileName);
    string query = string.Format(
     "/configuration/appSettings/add[@key='{0}']", keyName);
    XmlNode key = doc.SelectSingleNode(query);
    if (key != null)
    {
        XmlElement keyElement = key as XmlElement;
        keyElement.SetAttribute("value", keyValue);
        doc.Save(configFileName);
    }
}

Consider a client app that uses the following configuration file:

<configuration>
  <appSettings>
    <add key="EchoServiceLocation"
       value="http://staff.develop.com/aarons/dotnet/echo.asmx" />
    <add key="UddiServerLocation"
       value="http://test.uddi.microsoft.com/inquire" />
    <add key="EchoServiceUddiBindingKey"
       value="c4e334ff-5e16-471a-9886-5e4c8fd29025" />
  </appSettings>
</configuration>
The client application code in Figure 8 illustrates how to use these methods to implement the UDDI invocation pattern.

Figure 8 Implement UDDI Invocation Pattern (Close Figure 8)
using DevelopMentor.Uddi;
•••

EchoClass proxy = new EchoClass();
try
{
    // first attempt, upon failure we'll contact UDDI
    // below and try again...
    Console.WriteLine(proxy.Echo(args[0]));
}
catch(WebException e)
{
    string newLoc = InvocationPattern.FindCurrentLocation(
        e, "EchoServiceUddiBindingKey", "UddiServerLocation");
    if (newLoc != "")
    {
        // reattempt invocation w/new location
        proxy.Url = newLoc;
        Console.WriteLine(proxy.Echo(args[0]));
        // update local configuration file
        InvocationPattern.UpdateLocalConfiguration(
            "echoclient.exe.config", "EchoServiceLocation", newLoc);
        return;
    }
    Console.WriteLine(e.Message);
}

With this code in place the client application can now correct itself when the Web Service location changes over time. You can experiment with this by simply changing the EchoServiceLocation value in the client's configuration file to a bogus URL. It should then contact the UDDI server and update the configuration file with the correct URL. Also, try renaming your .asmx file to something else (echomoved.asmx), update the location in UDDI, and rerun the client. It should automatically invoke the new location and the client configuration file should then contain the new URL. This approach assumes that you're willing to keep the UDDI information up to date and that the UDDI server will always be available at the specified location.

Another solution that completely decouples the client from the physical network architecture is to route incoming Web Service requests to the correct endpoint location at run time. You can use a Web Service router that translates logical endpoints into physical locations (see Figure 9). In this instance the client is configured to call a logical endpoint, the router (whose address shouldn't change), which determines the correct endpoint to use at run time.

Figure 9 SOAP Router
Figure 9 SOAP Router

Web Services Enhancement 1.0 for Microsoft .NET (WSE) makes this possible through WS-Routing and WS-Referral. To use this approach, you need to install the WSE (see http://msdn.microsoft.com/webservices) and configure a virtual directory to serve as your router. Then you'll choose and configure a new file extension to use for routing purposes (.rp, for example). From here you can configure the virtual directory to use a referral cache file to determine routing instructions at run time. The following code shows a sample referral cache file that forwards all incoming requests targeted at http://localhost/referralrouter/echo.rp to http://localhost/echoservice/echo.asmx:

<r:referrals
  xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
  <r:ref>
    <r:for>
      <r:exact>http://localhost/referralrouter/echo.rp </r:exact>
    </r:for> <r:if />
    <r:go>
      <r:via>http://localhost/echoservice/echo.asmx </r:via>
    </r:go>
    <r:refId>uuid:fa469956-0057-4e77-962a-81c5e292f2ae</r:refId>
  </r:ref>
</r:referrals>

Now, if you decide to move the Web Service to a new location, you can simply update the referral cache file and clients don't have to do a thing—they're automatically forwarded on the next invocation. For more on using routing techniques with the WSE, see "Routing SOAP Messages with Web Services Enhancements 1.0".

As you can see, there are various techniques to managing references to Web Services in client applications. At minimum, don't hardcode the URLs into your proxy classes; use configuration files. Also invest in a long-term maintenance strategy that includes the UDDI invocation pattern or server-side routing techniques.

Feel free to download the sample code from the link at the top of this article and experiment on your own.

Q How can I invoke a Web Service directly from a browser?

A Since Web Services are designed for application consumption (not human consumption), today's Web browsers don't offer much built-in integration. Actually, it's more common for server-side ASP or ASP.NET pages to invoke Web Services, effectively merging information from multiple sources into the HTML stream rendered by the browser. It is possible, however, to invoke Web Services directly from client-side HTML pages, but it does require a bit of client-side script for it to be a useful part of a Web app.

The ASP.NET Web Service infrastructure facilitates browser integration by supporting simple HTTP invocation protocols that don't require SOAP messages on the wire. For example, you should consider the following WebMethod called Add:

[WebMethod]
public double Add(double x, double y)
{
    return x+y;
}
By default, ASP.NET makes it possible to invoke this method using three techniques: SOAP, HTTP GET, and HTTP POST. SOAP is the standard technique supported by today's Web Service toolkits and infrastructure. The HTTP GET and POST mechanisms make it much easier to invoke Web Services from dumb HTTP clients (like a Web browser) that know nothing about SOAP.

The following is the HTTP Get request:

GET /mathservice/math.asmx/add?x=string&y=string
HTTP/1.1
Host: localhost
In the case of HTTP GET, you simply tack the input parameters onto the query string, as shown here:
http://localhost/mathservice/math.asmx/Add?x=33&y=66
If you're using HTTP POST, the input parameters are encoded the same way, only they're sent as part of the message body, not as part of the query string. Since the input data is expected in the URL-encoded format, you can invoke the Web Service directly from an HTML form. For example, the following form generates the correct HTTP message to invoke Add using a GET request:
<form target="_blank" method="GET"
  action='http://localhost/mathservice/math.asmx/Add' >
  <input type="text" size="50" name="x">
  <input type="text" size="50" name="y">
</form>

The documentation generated by ASP.NET contains a form (like the one shown in the previous code snippet) for testing the Web Service (see Figure 10). When you press the Invoke button, however, it opens a new instance of Microsoft Internet Explorer and displays the raw XML result. Had the form not used target="_blank", it would have rendered the raw XML result in the same instance of Internet Explorer.

Figure 10 Testing the Web Service
Figure 10 Testing the Web Service

The HTML form technique does work across all Web browsers, but you wouldn't want the raw XML to be rendered and viewed by the user. Instead, you'd probably want to harvest the returned information and utilize it in your HTML display as you see fit. This is not difficult to do, but it does require writing a bit of client-side scripting to manually send the request, harvest the result, and update the page. And depending on which tools you choose for this, the solution may or may not work across different browser versions.

Figure 11 HTML Math Client
Figure 11 HTML Math Client

For example, consider the HTML page shown in Figure 11. When you press the Invoke button on this page, it issues an HTTP GET request programmatically using the MSXML2.XMLHTTP class and updates the result textbox with the value found in the returned XML as shown in the following:

function btnInvokeMath_onclick() {
    var req = new ActiveXObject("MSXML2.XMLHttp.4.0");
    var url = "http://localhost/"+
        "mathservice/math.asmx/" +
        selOperation.value +
        "?x=" + txtX.value +
        "&y=" + txtY.value;
    req.open("GET", url, false);
    req.send();
    txtResult.value = req.responseXML.text;
}

The code to invoke the Web Service using an HTTP POST is not much different. Just send the URL-encoded data as part of the HTTP body and set the Content-Type header to "application/x-www-form-urlencoded", as shown here:

function btnInvokeMath_onclick() {
  var req = new     ActiveXObject("MSXML2.XMLHttp");
  var url = "http://localhost/"+
    "mathservice/math.asmx/" +
    "selOperation.value;
  var body = "x=" + txtX.value + "&y=" +
    txtY.value;
    req.open("POST", url, false);
    req.setRequestHeader("Content-Type",
      "application/x-www-form-urlencoded");
    req.send(body);
    txtResult.value = req.responseXML.text;
}

Both of these examples send the requests synchronously, which probably isn't acceptable in most situations, since the browser appears to hang while waiting for the response. You can modify the code to send the request asynchronously by passing in a value of true as the last parameter of the call to open and by supplying a callback function for receiving the response once it arrives.

Overall, these techniques work well as long as you're working with simple interfaces defined completely in terms of simple types. As soon as you start using methods that accept complex types (classes or structs) as parameters to a WebMethod, the ASP.NET infrastructure only supports SOAP invocations. For example, consider the following WebMethod that calculates the distance between two Point instances:

public class Point
{
    public double x;
    public double y;
    •••
}

[WebMethod]
public double CalcDistance(Point orig, Point dest)
{
    return Math.Sqrt(
        Math.Pow(orig.x-dest.x, 2) +
        Math.Pow(orig.y-dest.y, 2));
}

In this case, when you browse to the .asmx endpoint, you won't see the test form or the descriptions of the GET/POST invocations because the operation takes complex types that don't naturally map to a URL encoding. Hence, as I just said, you can only invoke this operation using SOAP.

Invoking this operation directly from an HTML page is a bit more tedious because you have to generate the correct SOAP message. Figure 12 shows how to generate the SOAP message along with a Content-Type header of "text/xml" and the appropriate SOAPAction header for this operation. I could have generated the SOAP message programmatically using the DOM API, but it would have required quite a bit more code—it was easier in this case (and sufficiently safe) to just generate it as a string of XML 1.0.

Figure 12 Generating SOAP Messages (Close Figure 12)
function btnInvoke_onclick() {
    var req = new ActiveXObject("MSXML2.XMLHttp.4.0");
    var url = "http://localhost/mathservice/math.asmx";
    req.open("POST", url, false);
    req.setRequestHeader("Content-Type", "text/xml");
    req.setRequestHeader("SOAPAction",
        "http://example.org/math/CalcDistance");
    req.send(getSoapRequestMessage(txtOrigX.value,
         txtOrigY.value, txtDestX.value, txtDestY.value));
    txtResult.value = req.responseXML.text;
    alert(req.responseXML.xml);
}

function getSoapRequestMessage(origX, origY, destX, destY) {
  return
  "<soap:Envelope " +
  "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " +
  "xmlns:xsd='http://www.w3.org/2001/XMLSchema' " +
  "xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>" +
  "  <soap:Body>" +
  "    <CalcDistance xmlns='http://example.org/math'>" +
  "     <orig><x>"+origX +"</x>"+<y>"+origY+"</y>"+"</orig>"+
  "     <dest><x>"+destX +"</x>"+<y>"+destY+"</y>"+"</dest>"+
  "    </CalcDistance>" +
  "  </soap:Body>" +
  "</soap:Envelope>";
}

It's clearly more laborious to invoke via SOAP from HTML clients. To help alleviate this, Microsoft provides a DHTML behavior capable of generating the appropriate SOAP message for a given Web Service operation. You can read about the behavior and download the webservice.htc file from ASP.NET. (You should note that DHTML behaviors are only supported in Internet Explorer 5.0 and above.)

To use the Web Service behavior, put webservice.htc into your virtual directory along with your HTML pages and reference it within an HTML element, as shown here:

•••
<div id="proxy" style="behavior:url(webservice.htc)"></div>
•••
Then you'll have a variable reference to the Web Service behavior object named 'proxy'. Next, you need to initialize the proxy object with the WSDL file for the service (this drives the SOAP message generation process) as shown here:
function window_onload() {
    proxy.useService(
      "http://localhost/mathservice/"+
      "math.asmx?wsdl", "MathService");
}
And finally, use the generic callService function in order to invoke the operation by name, supplying the necessary input values:
function btnInvokeMath_onclick() {
    proxy.MathService.callService(resultHandler,
      selOperation.value, txtX.value,       txtY.value);
}

The Web Service behavior always invokes the operation asynchronously, so I defined a callback function to harvest the return value once it arrives:

function resultHandler(result) {
    txtResult.value = result.value;
}

If you need to pass in complex types, as is the case with CalcDistance, you can use associative arrays in JavaScript as demonstrated here (the return value is also processed by resultHandler):

function btnInvoke_onclick() {
    // orig Point instances
    var orig = new Array();
    orig.x = txtOrigX.value;
    orig.y = txtOrigY.value;
    // dest Point instance
    var dest = new Array();
    dest.x = txtDestX.value;
    dest.y = txtDestY.value;
    // invoke CalcDistance operation
    proxy.MathService.callService(resultHandler, "CalcDistance",
                                  orig, dest);
}

You can also process returned objects using the same technique. For example, consider the following WebMethod that returns an array of Point objects:

[WebMethod]
public Point[] GetPoints()
{
    return new Point[] {
        new Point(23, 44),
        new Point(11, 19),
        new Point(98, 82)
    };
}
You can invoke this operation and process the returned Point array as illustrated here (see Figure 13 for the results):
function btnInvoke_onclick() {
    proxy.MathService.callService(resultHandler,"GetPoints");
}

function resultHandler(result)
{
    var points="";
    // harvest GetPoints result
    for (var i=0; i<result.value.length; i++)
        points += "<h2>Point (x=" + result.value[i].x +
            ", y=" + result.value[i].y + ")</h2>";
    results.innerHTML = points;
}

Overall, the Web Service behavior can greatly simplify the process of invoking Web Services via SOAP directly from HTML pages. If a Web Service offers a simpler GET interface, however, you may find it easier to implement across different browser versions.

Figure 13 Invoking GetPoints
Figure 13 Invoking GetPoints

Around the time both Amazon and Google announced support for their SOAP-based services, many developers began questioning their decision to use SOAP over simpler GET invocations. The ensuing debate has already influenced SOAP 1.2 (see http://www.w3.org/TR/soap12-part2).

Send your questions and comments for Aaron to xmlfiles@microsoft.com.

Aaron Skonnardis an instructor/researcher at DevelopMentor, where he develops the XML and Web Service-related curriculum. Aaron coauthored Essential XML Quick Reference (Addison-Wesley, 2001) and Essential XML (Addison-Wesley, 2000). Reach him at http://staff.develop.com/aarons.


Cutting Edge: Customize Your Open File Dialog

Cutting Edge
Customize Your Open File Dialog
Dino Esposito

Code download available at: CuttingEdge0303.exe (96KB)
Contents
OpenFileDialog
System Settings for the Places Bar
RegOverridePredefKey
Overriding the Places Bar Key
A Custom Places Bar
Putting It All Together

Displaying an Open File dialog is certainly easy in the Microsoft® .NET Framework with Windows® Forms, but the resulting window is not as customizable as when you create it through the Win32® API. With Windows 2000, Microsoft added a nice feature—the places bar, which is the vertical toolbar that appears on the left side of the window to let you select a frequently visited folder. As you can see in Figure 1, the places bar contains buttons to take the user directly to five folders—History, Desktop, My Documents, My Computer, and My Network Places.

Figure 1 Selecting a Folder in the Places Bar
Figure 1 Selecting a Folder in the Places Bar

When coding against the Open File common dialog in the Win32 API, you can set a style to hide the places bar. But like other features of the Win32 common dialogs, this setting seems to have gotten lost in the migration to the .NET Framework. Creating a common dialog has never been easier than it is in the Framework, but this simplicity comes at the cost of some flexibility. In addition, in managed code there is no way to extend the layout of the dialog with additional controls.

In this column, I'll focus on the places bar of the Open File common dialog. I'll discuss how to customize the list of folders displayed and how to make it application specific and even call specific. In the process of doing so, I'll review some of the registry hives and nodes and APIs in the .NET Framework for registry key manipulation. Finally, I'll show you a class that extends the OpenFileDialog system class with a collection representing the places to show in the toolbar.

OpenFileDialog

The OpenFileDialog class represents the system-provided common dialog box that allows the user to select and open a file. The class inherits from CommonDialog, but no additional classes can inherit from it. To show a dialog and pick up a file, you use this surprisingly simple C# code:

openFileDialog.InitialDirectory = @"c:\";
openFileDialog.Filter = "Bitmap|*.bmp|All|*.*";
openFileDialog.ShowDialog();

Notice the special formatting required by the Filter property string. The Filter property identifies the entries in the file's type box. The contents of the property must be a string consisting of pipe-separated pairs of strings. In each pipe-separated pair, the first token represents a descriptive name of the type to select, whereas the second token stands for the mask for the files. For example, if you want to filter the folder view to display all bitmaps or all files, use the following string:

Bitmap|*.bmp|All|*.*

The use of the pipe as the separator is mandatory in the .NET Framework. In Win32 you would use nulls instead (in ASCII, use 0). However, a common programming practice in Win32 is to use pipes in the string and then programmatically replace them with nulls. The good news is that this service is now automatically provided by the .NET Framework.

The OpenFileDialog class exposes a set of properties to configure the dialog. For example, you can choose the initial directory, the initial filter index, the title of the window, whether multiple files can be selected, and whether the application's current directory should be restored before closing. The class also fires an event (called FileOk) whenever the user clicks on the Open button. As I mentioned earlier, OpenFileDialog is a sealed class, so you can't derive from it. However, if you want to customize the behavior of a file dialog, to the extent that it is possible, you should create a brand new class deriving from the abstract class FileDialog. In this case, you have access to a couple of powerful but protected methods such as HookProc and RunDialog. HookProc defines the dialog box hook procedure that adds specific functionality to the common dialog. RunDialog has the following signature:

protected abstract bool RunDialog(
   IntPtr hwndOwner
);

The method receives the HWND handle of the window that owns the dialog box. The typical implementation of this method simply consists of storing the hwndOwner argument in the CommonDialog's protected member hwndOwner. The RunDialog method is important because it allows you to set up a persistent dialog box and select multiple files from different folders. To transform an otherwise modal dialog box into a modeless one, you replace the owner window and make the dialog a child of the desktop window. The handle of the desktop window is returned by the Win32 API function GetDesktopWindow. Incidentally, while customizing the Open File dialog using a bunch of API functions is an absolute necessity.

System Settings for the Places Bar

The contents of the places bar are not completely configurable by applications in either Win32 or in the .NET Framework. In the past couple of years, though, some Knowledge Base articles have reported that you can modify the list of places by simply writing some entries in a particular registry key. In other words, the list of places normally displayed by the dialog is only the default list. The internal Win32 code attempts to read the user's list of places from the registry. If it fails—that is, if no list has been specified—the default list is used. So which registry key can you use? It is located under HKEY_CURRENT_USER and, as such, is specific to the logged user. Here's the path:

Software
  \Microsoft
    \Windows
      \CurrentVersion
        \Policies
          \ComDlg32
            \PlacesBar

The key doesn't exist by default and must be explicitly created. Try creating the key using either the Registry Editor or regedt32. Remember that you must be logged in with administrator rights in order to modify the registry. After creating the key, try launching any Win32 or managed application that makes use of the Windows Open File common dialog. For example, try it with Microsoft Paint; the result is shown in Figure 2. What's going on?

Figure 2 Empty Places Bar
Figure 2 Empty Places Bar

When the Win32 internal code detected the registry subtree you just created, it discarded the default list. Since you haven't listed any places, the places bar is empty. (Note that this change affects all applications running on the system as long as the user who changed the settings is still logged in.)

Figure 3 Customizing Favorite Places
Figure 3 Customizing Favorite Places

How can you specify your own favorite places? You should create entries in the aforementioned key. You can't create more than five entries because any more will be ignored. Each entry should be of type REG_SZ (a string value) and must be named "PlaceX", where X is a zero-based index. You can specify a place through a fully qualified path. Alternately, if you want to target special folders such as My Documents or My Computer, you use a folder ID. In this case, create a REG_DWORD entry and enter the folder number in hexadecimal. The two places entries in Figure 3 can be seen in action in Figure 4.

Figure 4 Two Places
Figure 4 Two Places

If fewer than five entries are specified, the rest are left empty. No more than five places will ever fit in the bar. It is important that you name the entries Place0, Place1, and so on. In order to revert to the default, just delete the two keys that you added—that is ComDlg32\PlacesBar. Be extremely careful when you delete registry keys. You should make sure that only those two keys are removed, otherwise you could corrupt your system!

The following C# code shows how to enumerate the registered places for the current user:

RegistryKey placesBarRoot;
placesBarRoot = Registry.CurrentUser.OpenSubKey(key);
string[] valuesOfKey = placesBarRoot.GetValueNames();
for(int i=0; i<valuesOfKey.Length; i++) {
   Console.WriteLine(placesBarRoot.GetValue(valuesOfKey[i]);
}
placesBarRoot.Close();
You begin by opening the places bar key on the current user hive. The GetValueNames method of the RegistryKey class fills an array of strings with the names of all the entries found. In the example that I give, the valuesOfKey array would contain strings like Place0, Place1, and so forth. The value of each key is read through the GetValue method.

In this way you can certainly customize the places that appear in the Open File common dialog, but don't forget that the changes are extended to all running applications. The registry settings work on a per-user basis and Microsoft doesn't provide an API to programmatically configure the places bar on a per-application or per-call basis. Is there a way to trick the system and customize the places bar each time you display the file dialog? The answer is yes, but the implementation is not trivial and it entails the use of a little-known Win32 API function—RegOverridePredefKey.

RegOverridePredefKey

The RegOverridePredefKey function requires Windows 2000 or later; it is not supported on systems running Windows 9x. Mostly intended for software installation programs, the function allows you to map one predefined registry key onto another. The ultimate goal of this function is to enable a setup program to examine the changes to the registry that an installable component is attempting to make. In practice, before invoking certain components the setup program will map a critical registry subtree elsewhere and lets the component proceed.

When the component is finished, the installation program looks over the changes and decides whether they are safe. If they are, the setup program mirrors the changes to the original locations intended by the DLL. Otherwise, the changes can either be rejected or adapted before writing to the target locations. The prototype of the function is shown here:

LONG RegOverridePredefKey(
  HKEY hKey,
  HKEY hNewHKey
);
The first argument is the registry key to remap, while the second argument is the location of the redirected key. The redirect key should either be a predefined key or should be currently open. Once RegOverridePredefKey returns, any call to hKey is resolved in the subtree rooted in the hNewHKey key. For example, consider the following call:
   HKEY hkMyCU;
   RegCreateKey(HKEY_CURRENT_USER, "Dino",
       &hkMyCU);
   RegOverridePredefKey(HKEY_CURRENT_USER,
       hkMyCU);

After the call takes place, a call to read from Software\Microsoft will actually read from Dino\Software\Microsoft. The hive must be the same for both keys. The automatic redirection applies only to the process that calls RegOverridePredefKey. If the hNewHKey argument is null, the function restores the default mapping of the key. Just the fact that the redirection is process specific gives you the tools to implement an application-specific places bar.

Overriding the Places Bar Key

Creating or updating registry entries is the only way to customize the list of places in the Open File dialog. However, to make the changes application specific you need to adapt the contents of the unique system key for each call. If you really read and write to the registry whenever an application needs to display the dialog, too much traffic is generated and, more importantly, concurrently running applications would override each other's settings. By using the RegOverridePredefKey key, you actually create a process-specific copy of the specified registry tree and can update it without corrupting the registry. Since the mapping lives only in the context of the process, no other running applications would be affected. The RegOverridePredefKey function is not directly supported by the .NET Framework, meaning that you need to explicitly import the function through the P/Invoke interoperability platform.

Not all Win32 registry functions have a matching managed class or static method in the .NET Framework. The data structure that is the core of the registry in Win32—the HKEY handle—is completely hidden in the .NET Framework and has been replaced by a class called RegistryKey. The RegistryKey class does make use of the HKEY handle internally, but there is no way for you to read that information from within an application built on the .NET Framework. The hkey data member, in fact, is marked as private. How does this affect you? (Who knows whether the Redmontonians will publicly expose the HKEY member in the next version of the .NET Framework?)

The RegOverridePredefKey function cannot be imported and adapted to use instances of the RegistryKey class to manage registry keys. You should import the function as shown here:

[DllImport("advapi32.dll")]
private static extern long RegOverridePredefKey(
    IntPtr hkey,
    IntPtr hnewKey
);
The issue is that you can't call the wrapper method I've just shown and pass it a registry key that has been opened using the .NET Framework classes. At this point, I see two possible approaches: either you open the registry key to map and its redirector using a Win32 function like RegOpenKeyEx and RegOpenKey, or you put all the initialization code in a new Win32 DLL and call its functions from within the application. In this column, I'll choose the second option. Figure 5 shows the Win32 code of a simple DLL that does the job. (I must confess that getting back to Win32 DLLs has been a little hard for me after more than two years spent coding only for the .NET Framework.)

Figure 5 Simple DLL (Close Figure 5)
#include "stdafx.h"

BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved)
{
    return TRUE;
}

HKEY APIENTRY InitializeRegistry()
{
    HKEY hkMyCU;
    RegCreateKey(HKEY_CURRENT_USER, "Dino", &hkMyCU);
    RegOverridePredefKey(HKEY_CURRENT_USER, hkMyCU);
    return hkMyCU;
}

void ResetRegistry(HKEY hkMyCU)
{
    RegOverridePredefKey(HKEY_CURRENT_USER, NULL);
    RegCloseKey(hkMyCU);
    return;
}

The library defines and exports two functions called InitializeRegistry and ResetRegistry. InitializeRegistry is parameterless but returns a Win32 HKEY object. ResetRegistry has no return value but takes the same HKEY opened with the previous method. The InitializeRegistry function opens the HKEY_CURRENT_USER hive and maps it to a newly created node called Dino. (Of course, you should feel free to rename it to something more meaningful to you.) The function creates the key if it doesn't already exist and then opens it. After you call InitializeRegistry, all the attempts to read and write under the HKCU result in readings and writings done under the remapped key. This occurs only for the current process. ResetRegistry restores the natural order of things, removes the mapping, and closes the redirector registry key. Of course, to avoid serious problems with other parts of your code, you should call InitializeRegistry/ResetRegistry within a very short time interval. You should never call InitializeRegistry upon the form's load or call ResetRegistry while unloading.

After compiling the Win32 DLL, place the file in the same folder as managed application executables. While compiling the DLL I repeatedly forgot to add an export file to the Visual Studio® 6.0 project with the immediateness of the .NET Framework programming in mind. I had assumed that declaring APIENTRY the functions would have been enough. As a result, the application built on the .NET Framework complained a few times that no such functions were found in the Win32 DLL. Using the public keyword in the .NET Framework is so easy and handy! This code snippet demonstrates how to import the two functions in a managed app.

[DllImport("myregutil.dll")]
private static extern IntPtr InitializeRegistry();
[DllImport("myregutil.dll")]
private static extern void ResetRegistry(IntPtr hKey);

A Custom Places Bar

Now let's see how to exploit this small Win32 library to create a custom places bar for each call made to the Open File common dialog. My goal here is to use an ad hoc class to set up the places bar and display the dialog. As mentioned earlier, though, you cannot create a new dialog class by inheriting from the OpenFileDialog class. When inheritance is not possible, aggregation is always an alternative to consider. Let's create an OpenDialogPlaces class that embeds an instance of the OpenFileDialog class. The following code snippet shows how this specific class would work:

   OpenDialogPlaces o = new OpenDialogPlaces();
   o.Places.Add(@"c:\\");
   o.Places.Add(@17);
   o.Init();
   o.OpenDialog.ShowDialog();
   o.Reset();

The class exposes an array called Places that you populate as needed. When finished, you invoke a class-specific method called Init and update the registry. Next, you display the dialog and call Reset to restore the original status of the registry. Note that this is not the only possible way to implement the feature; it just gives you an idea of how to achieve it.

The OpenDialogPlaces class descends from Object and creates an OpenFileDialog object upon instantiation:

   public OpenDialogPlaces()
      {
          m_places = new ArrayList();
          m_openFileDialog = new OpenFileDialog();
      }
Other private members include the handle to the overridden registry key, saved as an IntPtr object. Public members are the OpenDialog object representing the embedded common dialog instance and the Places collection.

The Init method sets up the registry for making the call. The mapping lasts until Reset is called, like this:

m_overriddenKey = InitializeRegistry();
RegistryKey reg;
reg = Registry.CurrentUser.CreateSubKey(Key_PlacesBar);
for(int i=0; i<Places.Count; i++)
{
   if(Places[i] != null)
      reg.SetValue("Place" + i.ToString(), Places[i]);
}
The call to InitializeRegistry lays the groundwork for creating a fake registry tree for the process to use. The code creates the tree under the redirector key and defines the place entries that the user added to the Places collection.

You use the CreateSubKey method on the Registry object to create a subtree. Note that the Win32 library remaps the CurrentUser key, so you have to create the subtree just below it. The SetValue method lets you create registry entries. This method is a managed wrapper for the RegSetValueEx Win32 API function. By default, it creates REG_SZ entries. The signature of the method is shown here:

public void SetValue(string name,
   object value)

The actual type of the value argument determines the type of registry key being created. In particular, if the argument is of type Int32, a REG_DWORD entry is created. Internally, the code performs the type check shown in the following code snippet:

if (value as Int32 != null)
{...}
You'll need a REG_SZ entry if the name of the folder is an absolute or relative path. You need to use the folder-specific number if you want to target a special folder (see Figure 6 for a list). In this case, a REG_DWORD entry is needed.

Figure 6 Folder IDs (Close Figure 6)

ID | Folder
0 | Desktop
2 | Programs folder on Start menu
3 | Control Panel
4 | Printers
5 | My Documents
6 | Favorites
7 | Startup folder on Start menu
8 | Recent Files
9 | Send To
10 | Recycle Bin
12 | Start menu
17 | My Computer
18 | My Network Places
20 | Fonts

Putting It All Together

If you fill the Places array with the values shown in the following code and then display the file dialog, you get a window like the one that is shown in Figure 7:

Figure 7 A Custom Places Bar
Figure 7 A Custom Places Bar
   o.Places.Add(@"C:\");
   o.Places.Add(17);
   o.Places.Add(5);
   o.Places.Add(@"C:\My Articles");
   o.Places.Add(6);
If you indicate folders with a custom icon or a comment, that will be reflected by the item in the places bar. As Figure 8 shows, two applications running at the same time can have different places bars.
Figure 8 Different Places Bars
Figure 8 Different Places Bars
The trick discussed here is not specific to the .NET Framework. It has to do with some characteristics of the Windows 2000 operating system and, as such, works well in Win32 also.

Send your questions and comments for Dino to cutting@microsoft.com.

Dino Espositois an instructor and consultant based in Rome, Italy. Author of Building Web Solutions with ASP.NET and ADO.NET and Applied XML Programming for .NET, both from Microsoft Press, he spends most of his time teaching classes on ASP.NET and speaking at conferences. Dino is currently writing Programming ASP.NET for Microsoft Press. Get in touch with Dino at dinoe@wintellect.com.


Design Patterns: Creating Dynamic Factories in .NET Using Reflection

Design Patterns
Creating Dynamic Factories in .NET Using Reflection
Romi Kovacs

Code download available at: DesignPatterns0303.exe (79KB)
Contents
The Concrete Factory Design Pattern
Common Implementations
A Dynamic Factory Using Reflection
Conclusion

As software development has grown over the years, patterns in the way developers write code began to emerge. Often there was a better way to approach many specific problems, and these approaches caught on. Many of them have been formalized into design patterns that can be used to address very specific coding challenges. This new column will present a variety of useful patterns applicable to a wide range of projects that will help you find easy solutions to your development problems.

Design patterns are a powerful tool for designing flexible soft-ware. They provide well-tested solutions to recurring software design problems. One such widely used pattern is the Concrete Factory. The Factory pattern decouples objects from knowledge about the creation of other objects or even the underlying type of those objects. Too often, however, the Factory pattern is not applied optimally, creating subtle coupling and low cohesion issues between various participants of the pattern. In this column, I'll use reflection in .NET to create factory classes for C#, removing dependencies common in some implementations of this pattern.

Two of the sacred tenets of sound software design are keeping elements loosely coupled, yet highly cohesive. Coupling determines how strongly or closely related software components are, while cohesion relates to how well focused a software unit is, whether it's a method, class, or class library.

The Concrete Factory Design Pattern

The Concrete Factory is one of the most widely used patterns. In order for an object A to send a message to object B, A must have a reference to B, which means that class B must be instantiated and a reference to object B must be available to A. If A instantiates B directly, A has a direct reference to B, but now they are tightly coupled, since A must know how to create B. In order to reduce tight coupling between these two objects, it is best to give the responsibility of creating B to a factory class, C, so that in addition to reducing the strength of coupling between A and B, other potential consumers of B can request an instance of B from C as well. This is what the Concrete Factory design pattern provides.

Note that coupling is not eliminated between objects A and B; rather, it is weakened because A no longer needs to know how to create B. A further weakening of this coupling would be achieved if factory class C returned an interface to object B (let's call it I), rather than the concrete object itself. This would ensure that no matter how many implementations of I exist, object A would only know of I. The reason an interface renders coupling even weaker is that object A is further abstracted from new implementations of I.

In the Factory pattern there is a client, a factory, and a product. The client is any object that needs an object from the factory. The product is the object returned to the client by the factory.

Common Implementations

There are quite a few variations of the Factory pattern. I'll look at the pros and cons of two of the most common approaches, then I'll introduce a new approach that uses reflection.

The first implementation I'll examine uses abstract and concrete factories. This implementation should not be confused with the Abstract Factory pattern, which handles the creation and return of families of objects. Suppose you have a computer parts store inventory application in which InventoryMgr is the Client class, PartsFactory, MonitorInvFactory, and KeyboardInvFactory make up the factory, and IPartsInventory is the product returned by the factory. The Unified Modeling Language (UML) diagram in Figure 1 illustrates this implementation. Here, MainClass is a class that sends a request to InventoryMgr.

Figure 1 Abstract and Concrete Factories
Figure 1 Abstract and Concrete Factories

In Figure 1, MainClass simply represents an object that passes on the user's request to InventoryMgr. If MainClass needed to replenish the inventory of monitors, for example, it would send a message to the InventoryMgr (see Figure 2).

Figure 2 MainClass, InventoryMgr, and IPartsInventory (Close Figure 2)
class MainClass {
    static void Main(string[] args) {

        PartsFactory myfactory = null;
        InventoryMgr myinvmgr = new InventoryMgr();

        foreach(string marg in args){
            switch(marg) {
                case "Monitors":
                    myfactory = new MonitorInvFactory();
                    break;
                case "Keyboards":
                    myfactory = new KeyboardInvFactory();
                    break;
                default:
                    break;
            }
            if(myfactory != null)
                myinvmgr.ReplenishInventory(myfactory);

            myfactory = null;
        }
    }
}
class InventoryMgr {
    public void ReplenishInventory(PartsFactory vfactory) {
        IPartsInventory PartInv = vfactory.ReturnPartInventory();
        PartInv.Restock();
    }
}

interface IPartsInventory {
    void Restock();
}

class MonitorInventory : IPartsInventory {
    public void Restock() {
        Console.WriteLine("The monitor inventory has been restocked");
    }
}

class KeyboardInventory : IPartsInventory {
    public void Restock() {
        Console.WriteLine("The keyboard inventory has been restocked");
    }
}

Take a look at the code in the abstract factory PartsFactory and the concrete factories MonitorInvFactory and KeyboardInvFactory in Figure 3. Although this is a reasonable approach to implementing the Factory pattern, it has some shortcomings. Consider how coupling manifests itself and to what degree it is present in this pattern. The InventoryMgr class looks good (coupling is low) since it's shielded from knowing about any of the concrete factories. The addition of new concrete factories in the future will not affect it. InventoryMgr is also decoupled from the different implementations of IPartsInventory by having a reference to the interface instead of a concrete object. So, what is the problem?

Figure 3 Abstract and Concrete Factory Code Fragments (Close Figure 3)
abstract class PartsFactory {
    public abstract IPartsInventory ReturnPartInventory();
}

class MonitorInvFactory : PartsFactory {
    public override IPartsInventory ReturnPartInventory() {
        return (IPartsInventory) new MonitorInventory();
    }
}
class KeyboardInvFactory : PartsFactory {
    public override IPartsInventory ReturnPartInventory() {
        return (IPartsInventory) new KeyboardInventory();
    }
}

One of the axioms in object-oriented design is "don't talk to strangers," meaning that objects should not have a reference to objects they do not absolutely need in order to function properly. If you look at the code fragment for MainClass in Figure 2, this rule is violated because MainClass creates concrete factories. MainClass does not truly need to know about concrete factories since it does not send a message to them. It simply creates them and passes them on to InventoryMgr. This results in an unnecessary coupling between MainClass, MonitorInvFactory, and KeyboardInvFactory.

As a general rule, objects should only create other objects if they plan to send a message or messages to those objects, unless their main responsibility is the creation and return of those objects. Factories, for instance, are such classes. An adverse effect of unnecessary coupling is lower cohesion. MainClass has lowered its cohesion as well since, given its role as a message forwarding agent, it should not concern itself with what concrete factories are needed to process the request. Its focus should simply be taking a request, possibly repackaging it, and sending it to InventoryMgr for further processing. As you'll see later on, reflection helps remove unnecessary coupling and improve cohesion in all classes that participate in the Factory pattern.

Let's examine another popular implementation of the Factory pattern. This approach does not make use of abstract factories. It only uses a concrete factory to create objects; therefore it is considerably less complex. Let's take a look at what the code looks like in MainClass, InventoryMgr, and PartsFactory. IPartsInventory has not changed (see Figure 2). MonitorInvFactory and KeyboardInvFactory (see Figure 3) are no longer needed, since a single concrete factory class in now being used. The most striking change is the addition of an enumerator, enmInvParts.

Figure 4 shows that the code in MainClass is significantly cleaner, less coupled, and more cohesive than the previous implementation in Figure 2. MainClass is no longer "talking to strangers." Instead of being coupled to factories, it is now coupled to the enumeration enmInvParts, which simply provides a repackaging mechanism of the command-line request. Repackaging the request comes naturally to MainClass since it fits well with its responsibility of simply passing on the request to InventoryMgr. Although InventoryMgr is coupled to PartsFactory, coupling has not truly changed, since InventoryMgr was previously coupled to the abstract version of PartsFactory by means of parameter passing (see Figure 2). At first glance, it looks like the coupling and cohesion issues have disappeared, so I can pop the champagne cork and declare victory. Well, not yet.

Figure 4 MainClass (Close Figure 4)
class MainClass {
    static void Main(string[] args) {

        InventoryMgr InvMgr = new InventoryMgr();

        foreach(string marg in args){
            switch(marg) {
                case "Monitors":
                    InvMgr.ReplenishInventory(enmInvParts.Monitors);
                    break;
                case "Keyboards":
                    InvMgr.ReplenishInventory(enmInvParts.Keyboards);
                    break;
                default:
                    break;
            }
        }
    }
}

public enum enmInvParts : int {Monitors = 1, Keyboards};

class InventoryMgr {
    public void ReplenishInventory(enmInvParts InventoryPart) {
        PartsFactory factory = new PartsFactory();
        IPartsInventory IP = factory.ReturnPartInventory(InventoryPart);
        IP.Restock();
    }
}

class PartsFactory {
    public IPartsInventory ReturnPartInventory(enmInvParts InvPart) {
        IPartsInventory InvType;

        switch(InvPart) {
            case enmInvParts.Monitors:
                InvType = new MonitorInventory();
                break;
            case enmInvParts.Keyboards:
                InvType = new KeyboardInventory();
                break;
            default:
                InvType = null;
                break;
        }
        return InvType;
    }
}

If you take a closer look, you see that the coupling has moved from MainClass to PartsFactory. Although PartsFactory is now coupled to IPartsInventory and its implementor objects, coupling does not affect it nearly as adversely as MainClass was affected in the implementation of the Factory pattern in Figure 2 because class cohesion has not deteriorated. In other words, PartsFactory remains focused. If you could remove this hardcoded coupling from the factory, you would achieve the lowest possible coupling and highest cohesion in all the classes that make up the implementation of the Factory pattern. Stay tuned; next I'll describe how reflection can get you pretty close to that lofty goal.

A Dynamic Factory Using Reflection

Reflection is simply a mechanism that allows components or classes to interrogate each other at run time and discover information that goes beyond the information gleaned from the publicly available interfaces the objects expose. In essence, reflection enables objects to provide information about themselves (metadata).

The .NET Framework provides objects the ability to describe themselves through the use of attributes. An attribute is declared as a class that inherits from System.Attribute. Once an attribute is defined, it can be attached to types such as interfaces, classes, or an assembly. The code in Figure 5 defines two attributes.

Figure 5 Two Attributes Defined (Close Figure 5)
[AttributeUsage(AttributeTargets.Class)]
public class InventoryPartAttribute : Attribute {
    private enmInvParts mInventoryPart;
    public InventoryPartAttribute (enmInvParts  vInvPart)    {
            mInventoryPart = vInvPart;
    }
    public enmInvParts InventoryPartSupported {
           get {return mInventoryPart;}
           set { mInventoryPart = value;}
    }
}

[AttributeUsage(AttributeTargets.Interface)]
public class ImplAttr : Attribute {
    private Type[] mImplementorList;
    public ImplAttr(Type[] Implementors){
           mImplementorList = Implementors;
    }
    public Type[] ImplementorList  {
           get {return mImplementorList;}
           set {mImplementorList = value;}
    }
}

The first attribute is InventoryPartAttribute, which will be attached to the classes that implement the IPartsInventory interface in order to specify which type of parts they handle. The following code illustrates how this is achieved:

[InventoryPartAttribute(enmInvParts.Monitors)]
class MonitorInventory : IPartsInventory {
    public void Restock() {
        Console.WriteLine("monitor inventory restocked");
    }
}

[InventoryPartAttribute(enmInvParts.Keyboards)]
class KeyboardInventory : IPartsInventory {
    public void Restock() {
        Console.WriteLine("keyboard inventory restocked");
    }
}

The second attribute defined in Figure 5 is attached to the IPartsInventory interface. This allows for the interface to be interrogated about which types implement it, like so:

[ImplAttr(new Type[]{typeof(MonitorInventory),typeof(KeyboardInventory)})]
interface IPartsInventory() {
  public void Restock();
}

So far, I have created two attributes and attached them to both the IPartsInventory interface and the classes that implement it (MonitorInventory and KeyboardInventory).

The class with the largest amount of code changes is PartsFactory. This should certainly be no surprise, since it is the class whose hardcoded switch statement I'm trying to replace with code that's more dynamic through the use of attributes. Let's examine each line of code of the newly modified PartsFactory class in Figure 6.

Figure 6 PartsFactory Class (Close Figure 6)
class PartsFactory {

    public IPartsInventory ReturnPartInventory(enmInvParts vInvPart) {

        IPartsInventory InvPart = null;
        object Obj;
        Type[] IntrfaceImpl;
        Attribute Attr;
        enmInvParts enmInventoryPart;
        InventoryPartAttribute InvPartAttr;
        int ImplementorCount;

        //Retrieve the attribute ImplAttr attached to the IPartsInventory
        //interface
        Attr = Attribute.GetCustomAttribute(typeof(IPartsInventory),
               typeof(ImplAttr));

        //Retrieve the Type array containing the types that implement
        //the IPartsInventory interface
        IntrfaceImpl = ((ImplAttr)Attr).ImplementorList;

        //Determine the number of classes that
        //implement IPartsInventory
        ImplementorCount = IntrfaceImpl.GetLength(0);

        for (int i = 0; i < ImplementorCount; i++) {
            Attr = Attribute.GetCustomAttribute(IntrfaceImpl[i],
                   typeof(InventoryPartAttribute));

            InvPartAttr = (InventoryPartAttribute)Attr;

            //Determine what inventory part this class supports
            enmInventoryPart = InvPartAttr.InventoryPartSupported;

            if((int) enmInventoryPart == (int)vInvPart) {
                Obj = Activator.CreateInstance(IntrfaceImpl[i]);
                InvPart = (IPartsInventory)Obj;
                break;
            }
        }
        return InvPart;
    }
}

The first line retrieves the ImplAttr attribute of the IPartsInventory as shown here:

Attr = Attribute.GetCustomAttribute(typeof(IPartsInventory),
       typeof(ImplAttr));
Next, I cast the Attr attribute to my custom ImplAttr attribute and the array of types that implement IPartsInventory is retrieved by reading the attribute's ImplementorList property:
IntrfaceImpl = ((ImplAttr)Attr).ImplementorList;
I determine the number of classes that implement the interface by obtaining the length of the IntrfaceImpl array:
ImplementorCount = IntrfaceImpl.GetLength(0);
Next, I loop through the IntrfaceImpl array. The first thing I do within the loop is retrieve the InventoryPartAttribute attribute of each interface implementor class:
Attr = Attribute.GetCustomAttribute(IntrfaceImpl[i],
  typeof(InventoryPartAttribute));
Then, I cast the Attr attribute to my custom InventoryPartAttribute attribute and extract its value into the enmInventoryPart variable:
InvPartAttr = (InventoryPartAttribute)Attr;
enmInventoryPart = InvPartAttr.InventoryPartSupported;

If the value of the extracted enumerator matches the client's enumerator, the class supports the right type of inventory part, so I instantiate it and break out of the loop:

if((int) enmInventoryPart == (int)vInvPart) {
    Obj = Activator.CreateInstance(IntrfaceImpl[i])
            InvPart = (IPartsInventory)Obj;
            break;
    }
Finally, the factory returns the IPartsInventory object:
return InvPart;

Let's look at what happens when the need arises to add another object that derives from the IPartsInventory interface. I'll name this object MousePadInventory. After updating the enmInvParts enumerator to accommodate the new inventory part, I define the new class and attach the InventoryPartAttribute attribute to it:

public enum enmInvParts : int {Monitors = 1, Keyboards, MousePads};

[InventoryPartAttribute(enmInvParts.MousePads)]
class MousePadInventory : IPartsInventory {
    public void Restock() {
        Console.WriteLine("The mouse pad inventory has been restocked");
    }
}
Next, the ImplAttr attribute of the IPartsInventory interface needs to reflect that a new class is implementing the interface:
[ImplAttr(new Type[]{typeof(MonitorInventory),typeof(KeyboardInventory),
          typeof(MousePadInventory)})]
interface IPartsInventory() {
    public void Restock();
}

Then, I update MainClass to handle the request to replenish the newly added mouse pad inventory. The only change is to add another case for "MousePads" to the MainClass class shown in Figure 4. Add the following code right after the "Keyboards" case:

case "MousePads":
     InvMgr.ReplenishInventory(enmInvParts.Keyboards);
     break;

Now I'm finished. There is no need to change PartsFactory or InventoryMgr. This shows that I have successfully removed all remaining coupling issues caused by the switch statement inside PartsFactory and that adding a new class requires minimal effort.

Conclusion

The Concrete Factory pattern is one of the simplest yet most powerful design patterns. Because of its simplicity, the subtle coupling and cohesion implications that accompany the implementation you choose when applying the pattern are sometimes overlooked. Indeed, it is not always possible or necessary to severely reduce coupling or completely maximize cohesion; however, you need to be mindful of their presence and their implications in whatever context you happen to apply this design pattern.

Send your questions and comments to mmpatt@microsoft.com.

Romi Kovacsa senior consultant with Praxis Solutions, a software consulting company based in Indianapolis, IN. He and his wife, two kids, and rambunctious miniature schnauzer live in Greenwood, IN. Romi can be reached at romi.kovacs@praxis-sol.com.


Advanced Basics: Handling Null Values with Controls

Advanced Basics
Handling Null Values with Controls
Ken Spencer

Code download available at: AdvancedBasics0303.exe (113KB)

Q In Visual Basic® .NET, the textbox and checkbox controls do not accept null values. Is there a way to modify these controls in order to be able to accept nulls?

A This is a good question. To answer it, I had to do a bit of research and testing. Luckily, you should find the solution applicable to any control you use. First I need to clarify what is meant by null. In the database itself a null value is simply represented by NULL. In Visual Basic .NET and ADO.NET, null is mapped into a special value, DBNull. This distinguishes DBNull from the .NET null value, Nothing. In this column, I'll only be dealing with DBNull.

In thinking about the problem, two approaches came to mind. One was to use inheritance and derive a new control from an existing control, then modify the new control to handle nulls. The other approach was to create what I would call a composite-type control that contains the desired functionality. To test each, I used one approach for the checkbox and one for the textbox.

Let's look at the textbox first as this control uses the composite approach, which is similar to control development in Visual Basic 6.0. In order to create this control, I built a new Windows® Control Library project. I renamed the default control TextBoxNoNull and made the file name for the class TextBoxNoNull.vb.

Next, I sized the user control to 96 × 20. In order to turn this control into a textbox, I added a textbox control to the user control. Then I set the size of the textbox so that it would be exactly the same size as the user control.

Now, the fun begins. The code I created for the textbox control is shown in Figure 1. The first step in generating the code was figuring out how to deal with the null values. If you try to place a null value (such as DBNull) in a string, an error is thrown. This makes for a bit of a challenging task when you try to handle nulls in a control because if the property you are setting happens to be a string or anything other than an object type, an error will be thrown when you try to set the property to DBNull.

Figure 1 Null Textbox (Close Figure 1)
Public Shadows Property text() As Object
    Get
        Return txtBoxStandard.Text
    End Get
    Set(ByVal Value As Object)
        Try

            If IsDBNull(Value) = True Then
                txtBoxStandard.Text = ""
            Else
                If Len(Value) = 0 Then
                    txtBoxStandard.Text = ""
                Else
                    txtBoxStandard.Text = Value
                End If
            End If
        Catch exc As Exception
            txtBoxStandard.Text = "Incorrect value type " & exc.Message

        End Try
    End Set
End Property

Private Sub TextBoxNoNull_Resize(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles MyBase.Resize
    Dim oControl As UserControl

    oControl = CType(sender, UserControl)

    txtBoxStandard.Width = oControl.Width
    txtBoxStandard.Height = oControl.Height
End Sub

Private Sub TextBoxNoNull_Layout(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.LayoutEventArgs) _
    Handles MyBase.Layout
    Try
        txtBoxStandard.Width = e.AffectedControl.Width
        txtBoxStandard.Height = e.AffectedControl.Height
    Catch exc As Exception
    End Try
End Sub

To handle this I created a new Text property of type object. Since the underlying control has a Text property, I had to create this new property with the Shadows keyword.

The code in the property procedure is pretty simple. The Get function simply returns the value of the child textbox. The Set procedure has the code to test for DBNull. The Try/Catch block is used to make sure any errors are caught and handled by throwing the error message. The If...Then block sets the text of the textbox to an empty string if the value is DBNull or empty; otherwise, the textbox is set to the new value.

Now, how do you keep the textbox sized to match the user control? Use the Resize event, right? Partially. This works for run-time changes to the control, but what about design-time changes? To change the textbox size in design mode, I used the Layout event to trap these changes. It contains almost the same code as the Resize event, except that it uses the AffectedControl class of the System.Windows.Forms.LayoutEventArgs passed to the event to extract the height and width of the control. This code would occasionally generate a runtime error, complaining that there is not a valid object. Using a dummy Try/Catch error handler to trap this error solved the problem.

Next, let's look at the checkbox and see how it can handle nulls. Instead of creating a simple composite control, I created the new checkbox by deriving from the standard checkbox (see Figure 2) by creating a new class and adding the following Inherits statement:

Inherits System.Windows.Forms.checkbox
This makes the new class behave exactly like the standard checkbox control. So far, so good.

Figure 2 Null Checkbox (Close Figure 2)
Public Class checkNoNull
    Inherits System.Windows.Forms.CheckBox
    Private mChecked As Boolean

Public Shadows Property Checked() As Object
    Get
        Return mChecked
    End Get
    Set(ByVal Value As Object)
        Try
            If IsDBNull(Value) = True Then
                mChecked = False
            Else
                If Len(Value) = 0 Then
                    mChecked = False
                ElseIf Value = True Then
                    mChecked = True
                    Else
                        mChecked = False
                    End If
                End If
            Catch exc As Exception
                mChecked = False
            End Try
                MyBase.Checked = mChecked
        End Set
   End Property

Private Sub checkNoNull_CheckedChanged( _
        ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles MyBase.CheckedChanged

    Checked = MyBase.Checked
End Sub
End Class

Next, I added the following line to declare a class-level variable to hold the checked state:

Private mChecked As Boolean
At this point I had to deal with the Checked property and figure out how to make it handle DBNull. Like the Text property in the textbox, I created a new Checked property of type Object. This property either returns or sets the mChecked variable. As with the textbox, this code checks to see if the new value is DBNull and handles it appropriately. Instead of returning empty strings or any type of error, this code simply returns True if the value is True; if the value is False, then it returns False.

Just after the end of the Try block, the following line was placed to set the Checked property of the base class to be equal to the current value of the local variable:

MyBase.Checked = mChecked

That takes care of handling values set in code, but what happens when the user enters a value by clicking the checkbox? To handle this action, I created an event handler for the CheckedChanged event. This event is provided by the underlying base class and occurs when a user clicks the checkbox. The only code in this event is the following, which sets the Checked property of the new checkbox class to the value the state caused by the user's click.

Checked = MyBase.Checked

Now, a word of caution. Patience is required when building controls. During the development of these controls, I ran into a stack overflow error. This caused all sorts of problems such as the host form refusing to load, the solution refusing to load, and so on. What caused this error? Instead of the line used at the end of the Try/Catch block, I had inadvertently used this line:

Me.Checked = mChecked
This actually just resets the Checked property of the new class in a recursive manner, causing the stack overflow. The moral? You should be careful with Me and MyBase since they can really affect the environment dramatically.

Let's discuss one more approach to handling nulls. The function in Figure 3 checks a variable to make sure it is valid and returns either a blank string or the value.

Figure 3 Check for Null (Close Figure 3)
Function CheckNull(ByVal Value As Object) As String
    Dim outVar As String
    Try
        If IsDBNull(Value) = True Then
            outVar = ""
        Else
            If Len(Value) = 0 Then
                outVar = ""
            Else
                outVar = CStr(Value)
            End If
        End If
    Catch exc As Exception
        outVar = ""
    End Try
    Return outVar
End Function

This function is easy to use, but where do you put it so you can reuse it? You can, of course, place it in a module for your project. But having to recreate the module each time is a pain. Instead, you can create a new macro and add this code:

Sub LoadGeneralModule()
        DTE.ItemOperations.AddExistingItem( _
            "C:\Components\modDBGeneral.vb")
End Sub
All this line does is take the file modDBGeneral.vb from the C:\Components folder and add it to the current project. To use this, I customize the toolbar and add an icon for this macro. Then it's one click to load the module whenever it's needed.

Handling null values is pretty simple in most cases. To do so, you can riddle your code with If statements or you can create routines or custom controls to handle the nulls. Nulls can be the result of many circumstances. The sample code for this column uses a function (GetCustomerRegion) that returns a single string using the Command object's ExecuteScalar method (see the link at the top of this article). If you set the return type to String, this function will generate an error if you try to return a value that is DBNull. So, you can put your error handling right there and you will not have any null values returned.

DataSets, on the other hand, can legally contain DBNull values. Not only does a DataSet need DBNull values, but the DataGrid also supports DBNull fields. If you try to set a textbox or checkbox to a value from either a DataSet or DataGrid and the value is DBNull, an error will occur. That's where these custom versions come in very handy, as they happily accept the DBNull value but then return either an error message or False. In production applications, I would change the checkbox to always return an empty string in cases where the value is blank or DBNull.

Remember, it's little things like null handling that make applications reliable and trusted.

Send your questions and comments for Ken to basics@microsoft.com.

Ken Spencerworks for 32X Tech (http://www.32X.com), where he provides training, software development, and consulting services on Microsoft technologies.


House of Web Services: Accessing Raw SOAP Messages in ASP.NET Web Services

House of Web Services
Accessing Raw SOAP Messages in ASP.NET Web Services
Tim Ewald

Code download available at: WebServices0303.exe (54KB)
Contents
Why Access Raw SOAP Messages?
Accessing Input and Output Streams
Exposing Input and Output Streams
A Prototypical Implementation
Piecing it All Together
What About Exceptions?
Why Bother with XML?

Web Services exchange XML messages. Most of today's Web Service toolkits do their best to hide this fact from developers, by exposing a Web Service's behavior as method invocations against objects instead. But what if you want access to the actual XML being sent on the wire? ASP.NET does not expose raw SOAP messages to a service, but with the built-in extensibility hooks and a little elbow grease, you can gain access to them.

But before I begin, let me make an observation about ASP.NET Web Services in general. When you develop Web Services in Visual Studio® .NET, the tool encourages you to use the ASP.NET plumbing a certain way. Specifically, it prompts you to implement a service as a class that exposes a set of methods marked with the [WebMethod] attribute, auto-generate a corresponding Web Services Description Language (WSDL) description and client proxy code, and then implement a client. However, there are other ways to use the Web Services infrastructure.

In his article "Place XML Message Design Ahead of Schema Planning to Improve Web Services Interoperability", Yasser Shohoud describes the importance of explicitly designing the messages a Web Service will send and receive. He argues that you should start the development of a Web Service by producing a contract in WSDL and then generating both service and client code from that, a view that I and many others share. The approach in which you write WSDL first takes advantage of the fact that the ASP.NET Web Services infrastructure is fairly modular and you only have to use the parts that you need. In this case, if you write your WSDL first, you don't need support for auto-generating it from your service code. I tend to think of the features of ASP.NET Web Services as falling into four large groups:

  • Extensible automatic WSDL generation
  • Message dispatching
  • Message filtering
  • Object serialization and deserialization

You can choose to embrace, ignore, or alter each piece as best suits your needs. Shohoud and many others choose to ignore the first one—automatic WSDL generation—as a basic design principle. The point is that the ASP.NET Web Services plumbing is flexible enough to let you make that choice. My goal in this and future columns is to explore these choices and to see how far you can push the Web Services plumbing of the Microsoft® .NET Framework. I'll start this column by showing you how to expose raw SOAP messages to a service, which is really a way of ignoring the object serialization and deserialization feature support for automatically mapping XML to objects.

Why Access Raw SOAP Messages?

The ASP.NET Web Services infrastructure assumes that, in general, developers prefer to deal with objects instead of XML. Its default behavior is to deserialize each SOAP message it receives from a client into objects and values that can be passed as input parameters to a method. After the method completes, it serializes the output parameters and return value into a SOAP message to send back to the client. The goal is to hide the use of XML.

But what if you want to deal with XML directly? For instance, maybe you want to query the messages you receive using XPath. Maybe your service is getting XML from SQL Server™ and you want to send it back to a client without having to turn it into objects, which the plumbing is just going to serialize back into XML anyway. Maybe you have a loosely coupled system that supports five different purchase order formats and you want to use XSLT to normalize them to your preferred internal format before continuing with the rest of your processing. Or maybe you are using objects that the ASP.NET Web Services plumbing can't serialize automatically, like a System.Collections.Hashtable or any implementation of IDictionary, and you want to serialize them by hand. In any of these cases, it would be better if you could manipulate SOAP messages using the System.Xml APIs of the .NET Framework.

The ASP.NET Web Services plumbing offers some limited support for accessing data as XML using pieces of the Document Object Model (DOM) API, notably System.Xml.XmlElement. While that's certainly a step in the right direction, it really doesn't go far enough. Optimally, any approach designed for exposing the SOAP messages that a Web Service produces and consumes as raw XML would work at the stream level. The System.Xml streaming APIs, called XmlReader and XmlWriter, are the basic plugs for XML I/O that all the higher-level APIs actually build on. If SOAP messages were exposed to streams, XmlReader and XmlWriter can be used to operate on them using the DOM, an XSLT transform, or any other XML technique.

Accessing Input and Output Streams

ASP.NET does not expose the streams containing inbound and outbound SOAP messages to a Web Service, but it will expose them to a SOAP extension. A SOAP extension is a filter that sits between the HTTP handler that processes requests sent to .asmx files and the class that actually implements a service. SOAP extensions can process an input message before a service's method is invoked and can process an output message after a service's method completes. In either case, the service is none the wiser.

Of key importance in the SOAP extension architecture is the ability to chain input and output streams. In the absence of any SOAP extensions, Web Services plumbing deals directly with the streams representing HTTP messages. A SOAP extension can replace the HTTP streams with streams of its own choosing, typically instances of System.IO.MemoryStream. The Web Service ends up working with the replacement streams and the plumbing leaves it to the SOAP extension to copy data between these streams and the "real" ones. "Real" is in quotes because any SOAP extension may in fact be dealing with replacement streams provided by another SOAP extension. This is the reason why extensions are said to "chain" streams.

Exposing Input and Output Streams

There is no reason that a SOAP extension cannot make the streams it works with available to a service. If it did, a service's methods would be able to read and write both input and output SOAP messages by hand. There is one challenge, however. If a method writes its own output SOAP message into the chained stream supplied by a SOAP extension and then the ASP.NET Web Service plumbing automatically generates an output SOAP message into the same stream, there will be a problem. The solution is to provide two output streams to the method, one for it to write into and one for the normal plumbing to use. The diagram in Figure 1 shows this basic architecture and flow.

Figure 1 Web Services Message Flow
Figure 1 Web Services Message Flow

Normally, the ASP.NET Web Service deals directly with the HTTP input and output streams. In this case, however, the XmlStreamSoapExtension SOAP extension class chains the HTTP output stream and exposes a memory stream to the serialization layer instead. It also creates an additional output stream for the method to write its output SOAP message to. Note that the extension does not chain the input stream. Instead, it simply exposes the underlying HTTP stream directly. The service method accesses the input and output streams via the static properties of the SoapStreams class.

A Prototypical Implementation

The code in Figure 2 shows the implementation of XmlStreamSoapExtension (I omitted a couple of no-op operations for simplicity). The ChainStream method gives the SOAP extension a chance to replace the streams holding input and output messages. Since this extension wants to replace the output stream but not the input stream, it uses the output flag to determine which stream it is being asked to replace. A given SOAP extension object is always asked to chain the input stream before the output stream. The XmlStreamSoapExtension implementation uses the output flag—initially set to false—to skip the request to chain the input stream. This is done for efficiency; it prevents having to make an extra copy of the input message.

Figure 2 XMLStreamSoapExtension Implementation (Close Figure 2)
// XmlStreamSoapExtension exposes raw SOAP messages to
// an ASP.NET Web Service
public class XmlStreamSoapExtension : SoapExtension
{
  bool output = false;        // flag indicating input or output
  Stream httpOutputStream;    // HTTP output stream to send real output to
  Stream chainedOutputStream; // output stream for ASP.NET
                              // plumbing to write to
  Stream appOutputStream;     // output stream for method to write to

  ... // no-op operations omitted for simplicity

  // ChainStream replaces original stream with extension's stream
  public override Stream ChainStream(Stream stream)
  {
    Stream result = stream;
    // only replace output stream with memory stream
    if (output)
    {
      httpOutputStream = stream;
      result = chainedOutputStream = new MemoryStream();
    }
    else
    {
      output = true;
    }
    return result;
  }

  // ProcessMessage is called to process SOAP messages
  // after inbound messages are deserialized to input
  // parameters and output parameters are serialized to
  // outbound messages
  public override void ProcessMessage(SoapMessage message)
  {
    switch (message.Stage)
    {
      case SoapMessageStage.AfterDeserialize :
      {
        // rewind HTTP input stream to start and store
        // reference in current HTTP context
        HttpContext.Current.Request.InputStream.Position = 0;
        HttpContext.Current.Items["SoapInputStream"] =
            HttpContext.Current.Request.InputStream;

        // create new memory stream for method to write
        // output message to and store reference in
        // current HTTP context
        appOutputStream = new MemoryStream();
        HttpContext.Current.Items["SoapOutputStream"] = appOutputStream;

        break;
      }
      case SoapMessageStage.AfterSerialize :
      {
        // flush memory stream method wrote its output message to, rewind
        // it and copy it to the HTTP output stream
        appOutputStream.Flush();
        appOutputStream.Position = 0;
        CopyStream(appOutputStream, httpOutputStream);
        appOutputStream.Close();
        break;
      }
    }
  }

  // CopyStream copies the contents of a source stream
  // to a destination stream
  private void CopyStream(Stream src, Stream dest)
  {
    StreamReader reader = new StreamReader(src);
    StreamWriter writer = new StreamWriter(dest);
    writer.Write(reader.ReadToEnd());
    writer.Flush();
  }
}

The ProcessMessage method is where the real work is done. ProcessMessage is invoked before and after an input message is deserialized to input parameters and before and after output parameters are serialized to an output message. After an input message is deserialized, the extension rewinds the HTTP input stream so a method can read it (the stream's cursor advances during deserialization) and creates a new memory stream for the method to write an output message to. This output stream, appOutputStream, is the second output stream required to make this scheme work. (The first output stream, chainedOutputStream, is created when ChainStream is called the second time.) References to both streams are stored in the current HTTP context's Items collection, with the keys "SoapInputStream" and "SoapOutputStream," respectively. After an output message is serialized, ProcessMessage copies the contents of the second output stream, appOutputStream, to the HTTP output stream—httpOutputStream. (Most SOAP extensions would copy the contents of their chained output stream to the HTTP output stream at this point.)

The CopyStream method is used simply to copy the data from one stream to another.

Two helper classes make it easier to use the XmlStreamSoapExtension class. The XmlStreamSoapExtensionAttribute class is used to mark a particular method as using this SOAP extension. The SoapStreams class exposes the input and output streams containing the raw SOAP messages to a method as a pair of static properties. The implementation of SoapStreams is shown in Figure 3.

Figure 3 SoapStreams Implementation (Close Figure 3)
public class SoapStreams
{
  public static Stream InputMessage
  {
    get
    {
      return (Stream) HttpContext.Current.Items["SoapInputStream"];
    }
  }
  public static Stream OutputMessage
  {
    get
    {
      return (Stream) HttpContext.Current.Items["SoapOutputStream"];
    }
  }
}

Piecing it All Together

I've created a sample Web Service that adds two numbers. It's a simple example that shows how the XmlStreamSoapExtension works. The service's message formats are shown in Figure 4, expressed in XML Schema. These messages are used to implement a single operation called Add, described by the WSDL code in Figure 5.

Figure 5 Add Operation in WSDL (Close Figure 5)
<wsdl:definitions
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:tns="urn:msdn-microsoft-com:hows"
 targetNamespace="urn:msdn-microsoft-com:hows" >

  <wsdl:import namespace="urn:msdn-microsoft-com:hows"
               location="server.xsd" />

  <wsdl:types/>

  <wsdl:message name="Add">
    <wsdl:part name="data" element="tns2:Add" />
  </wsdl:message>

  <wsdl:message name="AddResponse">
    <wsdl:part name="data" element="tns2:AddResponse" />
  </wsdl:message>

  <wsdl:portType name="Arithmetic">
    <wsdl:operation name="Add">
      <wsdl:input message="tns:Add" />
      <wsdl:output message="tns:AddResponse" />
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="Arithmetic" type="tns:Arithmetic">
    <soap:binding transport=http://schemas.xmlsoap.org/soap/http
                  style="document" />
    <wsdl:operation name="Add">
      <soap:operation soapAction="urn:msdn-microsoft-com:hows#Add"
                      style="document" />
      <wsdl:input message="tns:Add" >
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output message="tns:AddResponse" >
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

</wsdl:definitions>
Figure 4 Web Service Message Formats (Close Figure 4)
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="urn:msdn-microsoft-com:hows"
            elementFormDefault="qualified">

  <xsd:element name="Add">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="n1" type="xsd:int" />
        <xsd:element name="n2" type="xsd:int" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="AddResponse">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="sum" type="xsd:int" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

</xsd:schema>

Figure 6 shows a sample service generated from that WSDL using the wsdl.exe command-line tool's /server switch and then modified. Note the presence of the [XmlStreamSoapExtension] attribute, which tells the ASP.NET plumbing to use the XmlStreamSoapExtension class to process messages that map to the Add method. Also note that the parameters to the method have been commented out; since it deals with SOAP messages directly, there is no need to serialize or deserialize any parameters. One side effect of this change is that you cannot auto-generate an accurate WSDL definition for this class. If you prefer writing WSDL first (as I do), this is no big deal. Alternatively, you could implement a SOAP extension reflector that modified the generated WSDL to reflect the XML formats a method expected to produce and consume (see Scott Short's article "Take Advantage of Existing External XML Schemas with a Custom Import Framework in ASP.NET" in the December 2002 issue of MSDN Magazine for more information).

Figure 6 Web Service Generated by WSDL (Close Figure 6)
[WebServiceBinding(Name="Arithmetic",
                   Namespace="urn:msdn-microsoft-com:hows")]
public class Arithmetic : WebService
{
  [XmlStreamSoapExtension]
  [WebMethod]
  [SoapDocumentMethod("urn:msdn-microsoft-com:hows#Add",
                      Use=SoapBindingUse.Literal,
                      ParameterStyle=SoapParameterStyle.Bare)]
  [return: XmlElement("AddResponse",
                      Namespace="urn:msdn-microsoft-com:hows")]
  public /* AddResponse */ void Add(/*Add Add1*/)
  {
    // create validating reader with appropriate schemas
    XmlValidatingReader valid = new XmlValidatingReader(
              new XmlTextReader(SoapStreams.InputMessage));
    valid.Schemas.Add(XmlSchema.Read(new XmlTextReader(
      HttpContext.Current.Server.MapPath("server.xsd")), null));

    // load and validate input message
    XmlDocument doc = new XmlDocument();
    doc.Load(valid);

    // create transform and load XSLT
    XslTransform transform = new XslTransform();
    transform.Load(new XmlTextReader(
      HttpContext.Current.Server.MapPath("add.xslt")));

    // process input message and generate the output message
    transform.Transform(doc, null, new XmlTextWriter(
      SoapStreams.OutputMessage, Encoding.UTF8));
  }
}

The implementation of Add simply retrieves the input message stream using SoapStreams.InputMessage and parses it into a DOM, validating it against the service's schema along the way (something the ASP.NET Web Service plumbing does not do by default). Then it applies an XSLT to generate the output message, which it writes to SoapStreams.OutputMessage. Here is the transform the method uses, called add.xslt:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0">
  <soap:Body>
    <ns:AddResponse xmlns:ns="urn:msdn-microsoft-com:hows">
      <ns:sum><xsl:value-of select="sum(//ns:Add/*/text())"/></ns:sum>
    </ns:AddResponse>
  </soap:Body>
</soap:Envelope>

What About Exceptions?

There is one more thing to think about: what happens if an exception occurs? Normally, the ASP.NET Web Services infrastructure maps exceptions to SOAP Faults. But the implementation of XmlStreamSoapExtension.ProcessMessage ignores the stream containing the output SOAP message generated by that plumbing (chainedOutputStream) and uses the one created by the method instead (the one in appOutputStream). This is a problem.

There are two possible solutions. One is to insist that every method that uses the XmlStreamSoapExtension handle exceptions itself, producing an output SOAP message containing a SOAP Fault element if necessary. The other is to add some logic to the extension's ProcessMessage method that looks for a SOAP Fault element in the output message generated by the plumbing. If a Fault is present, an exception was thrown and the message containing the Fault should be returned. Figure 7 shows an updated version of XmlStreamSoapExtension.ProcessMessage to do that.

Figure 7 Looking for a SOAP Fault (Close Figure 7)
// ProcessMessage is called to process SOAP messages after inbound messages
// are deserialized to input parameters and output parameters are
// serialized to outbound messages
public override void ProcessMessage(SoapMessage message)
{
  switch (message.Stage)
  {
    case SoapMessageStage.AfterDeserialize :
    {
      // rewind HTTP input stream to start and store
      // reference in current HTTP context
      HttpContext.Current.Request.InputStream.Position = 0;
      HttpContext.Current.Items["SoapInputStream"] =
          HttpContext.Current.Request.InputStream;
      // create new memory stream for method to write output message to
      // and store reference in current HTTP context
      appOutputStream = new MemoryStream();
      HttpContext.Current.Items["SoapOutputStream"] = appOutputStream;

      break;
    }
    case SoapMessageStage.AfterSerialize :
    {
      // scan chained output stream looking for SOAP fault
      chainedOutputStream.Position = 0;
      XmlReader reader = new XmlTextReader(chainedOutputStream);
      reader.ReadStartElement("Envelope",
        "http://schemas.xmlsoap.org/soap/envelope/");
      reader.MoveToContent();
      if (reader.LocalName == "Header") reader.Skip();
      reader.ReadStartElement("Body",
        "http://schemas.xmlsoap.org/soap/envelope/");
      reader.MoveToContent();
      if (reader.LocalName == "Fault" && reader.NamespaceURI ==
          "http://schemas.xmlsoap.org/soap/envelope/")
      {
        // fault was found, so rewind chained output stream
        // and copy it to HTTP output stream
        chainedOutputStream.Position = 0;
        CopyStream(chainedOutputStream, httpOutputStream);
      }
      else
      {
        // No fault was found, so flush memory stream that method wrote its
        // output message to, rewind it and copy it to the HTTP output stream
        appOutputStream.Flush();
        appOutputStream.Position = 0;
        CopyStream(appOutputStream, httpOutputStream);
      }
      appOutputStream.Close();
      break;
    }
  }
}

Why Bother with XML?

It is a testament to the extensibility of the ASP.NET Web Services infrastructure that with a fairly simple SOAP extension, you can expose raw SOAP messages to the methods of a service class. Why bother? SOAP and Web Services are XML technologies. While it is often convenient to implement Web Services using objects, hiding the underlying XML means you have to give up some very powerful tools, like XPath, XSLT, and XML Query. Working at the XML level is probably unnecessary when you are adding two numbers together (although it was nice to get support for XML Schema validation), but that's really not the point. The point is that in many cases working with XML is actually easier than working with objects and it is nice to be able to deal directly with SOAP messages when your app requires it. You may wonder why I didn't just go all the way and implement my own Web Service endpoint using a low-level HTTP handler (an approach I've taken in the past). The main advantage of working inside (for the most part) of the ASP.NET Web Services infrastructure is that you can also take advantage of the object abstraction when it makes sense, a feature that a plain vanilla HTTP solution wouldn't provide.

Got a question? Send questions and comments to housews@microsoft.com.

Tim Ewaldis a Program Manager for XML Web Services at Microsoft. He is currently redesigning MSDN's architecture around Web services, as well as writing and speaking about the technology. He is the author of Transactional COM+: Designing Scalable Applications (Addison-Wesley, 2001). Reach Tim at tewald@microsoft.com.


Basic Instincts: Static Event Binding Using WithEvents

Basic Instincts
Static Event Binding Using WithEvents
Ted Pattison

Contents
Using the WithEvents Keyword
Static Event-binding Magic
Using WithEvents Fields in Inherited Classes
Summing it Up

This month's Basic Instincts column builds upon my last three columns in which I introduced and explained the fundamental concepts and syntax associated with delegates and events. Last month I showed you how to design and write a simple class that defines and raises events. You also saw how to dynamically bind an event handler to an event using the AddHandler keyword. This month I am going to discuss static event binding, an alternative technique for registering an event handler.

Using the WithEvents Keyword

Programmers with previous experience in Visual Basic® may find that static event binding is fairly easy because of its familiar syntax using the WithEvents keyword. Let me revisit the example of the BankAccount class that I used in last month's column. This class defines an event as a public member and raises the event from within a method definition, as shown here:

Delegate Sub LargeWithdrawHandler(ByVal Amount As Decimal)

Class BankAccount
  Public Event LargeWithdraw As LargeWithdrawHandler
  Sub Withdraw(ByVal Amount As Decimal)
    '*** send notifications if required
    If (Amount > 5000) Then
      RaiseEvent LargeWithdraw(Amount)
    End If
    '*** perform withdrawal
  End Sub
End Class

Objects created from the BankAccount class expose the LargeWithdraw event. You can see that a BankAccount object contains the logic to raise the LargeWithdraw event whenever a withdrawal is made for a value greater than $5,000.

Imagine that you want to create a new class named AccountAuditor1 to act as an event listener using static event binding. You can define a class as an event listener by adding one or more fields defined with the WithEvents keyword:

Class AccountAuditor1
  Private WithEvents account As BankAccount
  '*** other members omitted
End Class
You should note that a field defined using the WithEvents keyword must be based on a class that defines one or more instance events; otherwise it will cause a compile-time error. In this example, the field that is named account can be defined using the WithEvents keyword because the BankAccount class defines an instance event named LargeWithdraw.

The point of defining the account field with the WithEvents keyword is to allow methods defined within the AccountAuditor1 class to be registered as event handlers for events raised by a BankAccount object. Now that I've defined a WithEvents field, I'll create a method that will act as an event handler for the LargeWithdraw event.

When you define a method that's going to be an event handler, it must have the appropriate calling signature. For example, a method that's going to act as an event handler for the LargeWithdraw event must have a calling signature that matches LargeWithdrawHandler. Look at the following class definition:

Class AccountAuditor1
  Private WithEvents account As BankAccount
  Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
    '*** handler method implementation
  End Sub
End Class

In this example, I've added a new method named Handler1. As you can see, this handler method has a calling signature that matches the delegate type LargeWithdrawHandler. Also notice that the definition of the Handler1 method contains a Handles clause:

Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
You should see that a Handles clause is based on a WithEvents field and an event. The Handles clause is important because it provides a hint to the Visual Basic .NET compiler. More specifically, the presence of a Handles clause triggers the Visual Basic .NET compiler to generate extra code that will create and register an event handler. In this particular case, the compiler generates code to create an event handler of type LargeWithdrawHandler that's bound to the Handler1 method. The compiler will then generate code to register it with the BankAccount object that has been assigned to the account field.

Note that the Handles keyword is new in Visual Basic .NET. Earlier versions of Visual Basic required you to use a specific naming convention for event handler methods. For example, Visual Basic 6.0 would require the handler method in the previous example to be defined using the name account_LargeWithdraw. However, in Visual Basic .NET the name of the handler method doesn't matter; what does matter is that the handler method is defined with a Handles clause.

The real magic is performed by the Visual Basic .NET compiler when you assign an event source object to a WithEvents field. I'm going to defer the discussion of how the compiler performs this magic until later. For now, I'm going to make one more addition to AccountAuditor1 so the class can be used as an event listener.

A listener object needs an event source object. For example, it doesn't make sense to create an AccountAuditor1 object unless you have a BankAccount object that's going to act as an event source. Therefore, I'm going to add a constructor so that every AccountAuditor1 object is initialized with a BankAccount object as its event source, like this:

Class AccountAuditor1
  Private WithEvents account As BankAccount
  Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
    '*** handler method implementation
  End Sub
  Sub New(ByVal SourceAccount As BankAccount)
    Me.account = SourceAccount '*** triggers binding of event handler
  End Sub
End Class

Note that this constructor assigns the SourceAccount parameter to the WithEvents field named account. This is the line of code where the automatic binding of the event handler takes place. Now the AccountAuditor1 class can be used to create a listener object. For example, imagine you wrote the following application:

'*** create event source
Dim account1 As New BankAccount()

'*** create listener object and bind event handler
Dim listener1 As New AccountAuditor1(account1)

'*** do something that triggers event
account1.Withdraw(5001)

When the constructor of the AccountAuditor1 class executes, the Visual Basic .NET compiler has generated the code to create an event handler object that's bound to the Handler1 method. The compiler also generates code to register the event handler with the BankAccount object by calling the registration method add_LargeWithdraw. Therefore, the Handler1 method will execute whenever the Withdraw method raises the LargeWithdraw event.

You have just seen the fundamentals of how to create a listener object using static event binding. Figure 1 shows a complete application that uses static event binding to implement a callback design that is similar to the other techniques you have seen over the last three Basic Instincts columns. You should note that static and dynamic event binding are two different approaches that can often be used to achieve similar goals.

Figure 1 Event-based Design for Callback Notifications (Close Figure 1)
Delegate Sub LargeWithdrawHandler(ByVal Amount As Decimal)

Class BankAccount
  Public Event LargeWithdraw As LargeWithdrawHandler
  Sub Withdraw(ByVal Amount As Decimal)
    '*** send notifications if required
    If (Amount > 5000) Then
      RaiseEvent LargeWithdraw(Amount)
    End If
    '*** perform withdrawal
  End Sub
End Class

Class AccountAuditor1
  Private WithEvents account As BankAccount
  Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
    '*** handler method implementation
    MsgBox("Handler1")
  End Sub
  Sub New(ByVal SourceAccount As BankAccount)
    Me.account = SourceAccount ''*** triggers binding of event handler
  End Sub
End Class

Class AccountAuditor2
  Private WithEvents account As BankAccount
  Sub Handler2(ByVal amount As Decimal) Handles account.LargeWithdraw
    '*** handler method implementation
    MsgBox("Handler2")
  End Sub
  Sub New(ByVal SourceAccount As BankAccount)
    Me.account = SourceAccount '*** triggers binding of event handler
  End Sub
End Class

Module MyApp
  Sub Main()
    '*** create bank account object
    Dim account1 As New BankAccount()
    '*** register event handlers
    Dim listener1 As New AccountAuditor1(account1)
    Dim listener2 As New AccountAuditor2(account1)
    '*** do something that triggers callback
    account1.Withdraw(5001)
  End Sub
End Module

Now that you have seen both static and dynamic event binding, you might be wondering which one you should use. Ideally, you should learn how to use both. The Visual Studio® .NET IDE uses static event binding when you ask it to generate skeleton definitions for your event handler methods. Therefore, your understanding of static event binding will be important when you are working with an event-driven application framework such as Windows® Forms or ASP.NET Web Forms.

However, it's also important that you know how to use dynamic event binding, which I showed last month, because of its flexibility. For example, static event binding can only be used in cases where the event source is an object. It cannot be used when the event source is a class. In other words, static event binding can be used with instance events but cannot be used with shared events. Dynamic event binding, on the other hand, will allow you to bind to either shared events or instance events.

There are circumstances when the Visual Studio .NET IDE is not able to generate all the event handling code you need for an application and you'll have to write the code to create and register event handlers by hand. In cases like these, you will find that dynamic event binding is more straightforward and easier to use. After all, it only takes a single AddHandler statement to create an event handler from a method and bind it to an event. The only requirement is that the handler method have the calling signature that's required for the event in question.

One more interesting thing to note is that static event binding is a special programming feature that is unique to Visual Basic .NET. Other managed languages, such as C#, support dynamic event binding but do not support the equivalent of static event binding. If you are going to switch between managed languages or you need to port code from C# to Visual Basic .NET, you should consider relying on dynamic event binding.

Static Event-binding Magic

Now I'd like to discuss the low-level details of how the Visual Basic .NET compiler supports static event binding. You can use static event binding without understanding all the details I am about to explain, but I'll provide the details about what the compiler is doing to satisfy any curiosity you may have about how things work behind the scenes.

Let's start by looking at what happens when you compile a class definition with a WithEvents field. Assume that you have written the following class definition:

Class AccountAuditor
  Private WithEvents account As BankAccount
  '*** other members omitted
End Class
What happens when you compile this class? The Visual Basic .NET compiler generates the class definition shown in ILDasm (see Figure 2). As you can see, the class definition generated by the compiler is very different from the one you wrote. After it has been compiled, there is no longer a field named account. Instead, there is a private field named _account and a read/write property named account. The compiler has also generated special implementations for the account property's Set and Get methods. All the magic is in the Set method implementation.

Figure 2 The Compiler's Class Definition
Figure 2 The Compiler's Class Definition

So what really happens when you assign an event source object to a WithEvents field? For example, what happens when you assign a BankAccount object to the account field in the constructor of the AccountAuditor class?

Class AccountAuditor
  Private WithEvents account As BankAccount
  Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
    *** handler method implementation
  End Sub
  Sub New(ByVal source As BankAccount)
    Me.account = source '*** triggers call to add_LargeWithdraw
  End Sub
End Class

It's important to see that you are really not assigning the event source object to a field. Instead, you are assigning the event source object to a property which causes the Set method named set_account to execute. The implementation for set_account is generated to create and register an event handler for each method defined with the Handles clause. Figure 3 shows how the code you write gets translated by the compiler.

Figure 3 Static Event Binding (Close Figure 3)
'*******************************************
'**** the code you write looks like this ***
'*******************************************
Class AccountAuditor
  Private WithEvents account As BankAccount
  Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
    *** handler method implementation
  End Sub
  Sub New(ByVal SourceAccount As BankAccount)
    Me.account = SourceAccount
  End Sub
End Class

'***************************************************
'*** the code that gets compiled looks like this ***
'***************************************************
Class AccountAuditor
  Private _account As BankAccount
  Private Property account() As BankAccount
    Get
      Return _account
    End Get
    '*** magic code starts here ***************************************
    Set(ByVal Value As BankAccount)
      If (Not _account Is Nothing) Then
        _account.remove_LargeWithdraw(AddressOf Me.Handler1)
      End If
      If (Not Value Is Nothing) Then
        _account = Value
        _account.add_LargeWithdraw(AddressOf Me.Handler1)
      End If
    End Set
    '*** magic code ends here *****************************************
  End Property
  Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
    '*** handler implementation
  End Sub
  Sub New(ByVal source As BankAccount)
    Me.account = source '*** triggers call Set method
  End Sub
End Class

Examine the code inside the Set method of the AccountAuditor class shown in Figure 3. This code checks to see if there is an existing event source object being referenced by the _account field. If there is, the code removes it by calling the unregistration method remove_LargeWithdraw. Next, the Set method checks the Value parameter to see whether the assigned value is a valid reference to an event source object or a value of Nothing. If the Value parameter holds a valid reference to an event source object, the Set method creates an event handler bound to the Handler1 method and registers it by calling add_LargeWithdraw.

So, there's really no magic involved. When you assign a valid object reference to a WithEvents field, the compiler generates code to create delegate objects and bind them to each method that has been defined with a Handles clause. The compiler also generates the code to register these delegate objects by calling the event registration methods defined by the notification source.

Note that you are not required to bind a listener object to an event source during initialization. You can assign a value to a WithEvents field any time during the lifetime of a listener object. Consider the class definition in Figure 4. With this new design, an AccountAuditor object will not be bound to an event source after it has been initialized. However, you can call StartListening at any time to bind a listener object to an event source object. Note however that a call to StartListening will disconnect the listener object from an existing event source so that it can connect to the new one. A call to StopListening will disconnect the listener object from an existing event source and, in addition, leave it in an unbound state.

Figure 4 Binding Listener Object Later (Close Figure 4)
Class AccountAuditor
  Private WithEvents account As BankAccount
  Sub Handler1(ByVal amount As Decimal) Handles account.LargeWithdraw
    '*** handler method implementation
  End Sub
  Sub StartListening(ByVal source As BankAccount)
    Me.account = source '*** triggers call to add_LargeWithdraw
  End Sub
  Sub StopListening()
    Me.account = Nothing '*** triggers call to remove_LargeWithdraw
  End Sub
End Class

At this point it's fair to say that the Visual Basic .NET compiler is doing a good deal of work for you behind the scenes when you use static event binding. Furthermore, this example only involved a single handler method. In practice, you will often have many handler methods associated with a single WithEvents field.

Using WithEvents Fields in Inherited Classes

In the Microsoft® .NET Framework, it is common for a base class to raise events that are designed to be handled by derived classes. The idea is that a derived class author can customize behavior by adding event handlers to respond to events raised by a base class. This design technique provides an alternative to using overridable methods. It's also an important technique for you to understand because it is used extensively by application frameworks such as Windows Forms and ASP.NET.

Let's look at a simple example to see how this works. You have already seen that a Handles clause can be written in terms of a WithEvents field. You can also write a Handles clause using the MyBase keyword to handle an event defined within a base class, as shown in the following code:

Class CheckingAccount : Inherits BankAccount
  Sub Handler1(ByVal amount As Decimal) Handles MyBase.LargeWithdraw
    '*** handler method implementation
  End Sub
End Class

Once again, the Visual Basic .NET compiler generates the code that's needed to create an event handler and register it. However, the code for a base class event is generated in a slightly different fashion than the code for an event associated with a WithEvents field. In this example, the Visual Basic .NET compiler adds the code for binding to the LargeWithdraw method into the constructor of the CheckingAccount class.

There is one other thing you should keep in mind when working with a base class that exposes events. While a derived class can handle a base class event, it cannot raise a base class event. Take a look at the following example:

Class CheckingAccount : Inherits BankAccount
  Sub SomeOtherMethod()
    RaiseEvent LargeWithdraw(5001) '*** compile error
  End Sub
End Class
Since the implementation for an event involves a private field, the event can only be raised from within the class in which it is defined. Therefore, you will experience a compile-time error if you try to raise a base class event using a RaiseEvent statement or if you attempt to access the private field by name.

Summing it Up

I've shown you the two different techniques for registering event handlers for events: dynamic event binding and static event binding. To improve your knowledge of Visual Basic .NET, you must become comfortable with both techniques.

In the next installment of this column I will continue my discussion of events by exploring some of the most common delegate types and events in the Framework Class Libraries. In particular, I am going to focus on a delegate type named System.EventHandler and show how it provides a foundation for most of the events you will use in both Windows Forms and ASP.NET.

Send your questions and comments for Ted to instinct@microsoft.com.

Ted Pattisonis an instructor and researcher at DevelopMentor (http://www.develop.com), where he co-manages the Visual Basic curriculum. He is the author of Programming Distributed Applications with COM and Microsoft Visual Basic 6.0 (Microsoft Press, 2000).


C++ Q&amp;A: Find Icons, Launch an App from List Control, and More

C++ Q&A
Find Icons, Launch an App from List Control, and More
Paul DiLascia

Code download available at: CQA0303.exe (8,029KB)

Q When creating a MessageBox, I can easily display a question mark icon by using the flag MB_ICONQUESTION. But how can I put that same icon on my own dialog or form? Where or how can I find the icon?

Eric Lambrecht

A This question falls into the category of easily forgotten topics from Windows 101. You can grab any of the so-called system icons by calling ::LoadIcon with one of the predefined special IDI_XXX resource IDs. For example:

HICON hIconQuestion = ::LoadIcon(NULL, IDI_QUESTION);

I wrote a little program, SysIcons, that displays all the system icons. Figure 1 shows the relevant code from MainFrm.cpp; Figure 2 shows it in action. If you want to use one of these system icons in your own dialog or other window, create a static control the normal way and write the following code:

HICON hicon = ::LoadIcon(NULL, IDI_HAND);
m_wndStatic.SetIcon(hicon);
This assumes m_wndStatic is a CStatic control in your dialog or window. SysIcons has an About dialog that displays the question mark icon you asked about. For details, download the source from the link at the top of this article.

Figure 1 MainFrm.cpp (Close Figure 1)
////////////////////////////////////////////////////////////////
// MSDN Magazine — March 2003
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio .NET on Windows XP. Tab size=3.
//
#include "StdAfx.h"
#include "SysIcons.h"
#include "MainFrm.h"

•••

IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_CREATE()
   ON_WM_PAINT()
END_MESSAGE_MAP()

CMainFrame::CMainFrame()
{
}

CMainFrame::~CMainFrame()
{
}

const struct {
   LPCTSTR nResID;
   LPCTSTR name;
} SysIcons[] = {
   { IDI_APPLICATION, _T("IDI_APPLICATION") },
   { IDI_HAND, _T("IDI_HAND") },
   { IDI_QUESTION, _T("IDI_QUESTION") },
   { IDI_EXCLAMATION, _T("IDI_EXCLAMATION") },
   { IDI_ASTERISK, _T("IDI_ASTERISK") },
#if(WINVER >= 0x0400)
   { IDI_WINLOGO, _T("IDI_WINLOGO") },
   { IDI_WARNING, _T("IDI_WARNING") },
   { IDI_ERROR, _T("IDI_ERROR") },
   { IDI_INFORMATION, _T("IDI_INFORMATION") },
#endif
   { NULL, NULL }
};

void CMainFrame::OnPaint()
{
   CPaintDC dc(this);

   CRect rcClient;
   GetClientRect(&rcClient);

   int cyIcon = GetSystemMetrics(SM_CYICON);
   int cxIcon = GetSystemMetrics(SM_CXICON);

   CRect rcIcon(0,0,cxIcon,cyIcon);
   CRect rcText(cxIcon, 0, rcClient.Width()-cxIcon, cyIcon);

   for (UINT i=0; SysIcons[i].nResID; i++) {
      HICON hicon = ::LoadIcon(NULL, SysIcons[i].nResID);
      ASSERT(hicon);
      CString name = SysIcons[i].name;
      dc.DrawIcon(rcIcon.TopLeft(), hicon);
      dc.DrawText(name, rcText, DT_LEFT);
      rcIcon += CPoint(0, rcIcon.Height());
      rcText += CPoint(0, rcIcon.Height());
   }
}
Figure 2 System Icons
Figure 2 System Icons

While system icons would seem to merit no further discussion, Windows® makes even this simple subject more complex than expected. As Figure 2 shows, IDI_HAND doesn't resemble a hand at all, at least not on Windows XP. Likewise, contrary to its name, IDI_ASTERISK is a word balloon that contains the letter "i". The explanation for this lexical obfuscation lies in the historical record: older versions of Windows displayed the hand and asterisk; newer versions use the new icons. winuser.h reflects the changes, as shown here:

#if(WINVER >= 0x0400)
#define IDI_WARNING     IDI_EXCLAMATION
#define IDI_ERROR       IDI_HAND
#define IDI_INFORMATION IDI_ASTERISK
#endif /* WINVER >= 0x0400 */

If you want to keep up with the Redmondtonians, use the new symbols. Your code will be more readable too, since the symbols of warning, error, and information more accurately convey the purpose for using these icons.

Another perplexing tidbit is that while winuser.h has a new symbol IDI_WINLOGO, the icon that results from loading it in a Windows XP-based app is not the familiar flying flag we all know and love, but rather the same generic window you get with IDI_APPLICATION (see Figure 2). Careful reading of the documentation reveals that indeed this feature is by design. While other platforms presumably yield the flying window, on Windows XP IDI_WINLOGO yields the application icon. What corporate conspiracy, if any, lies behind this equivocation is beyond my humble ken. If you think you know, drop me a line.

What about if you're targeting Microsoft® .NET? How can you display system icons in your app built using the .NET Framework? Well, you can always call LoadIcon directly through the wonders of interop—but why bother when the .NET Framework already exposes the system icons through a special class, SystemIcons:

Icon icon = SystemIcons.Question;

Figure 3 shows the full list of SystemIcons and their Win32® IDI_XXX counterparts. Just for amusement, I translated SysIcons to C#. Figure 4 shows the result. SysIcons.cs uses reflection to probe all the static properties of SystemIcons. First, get all the public static properties, as shown here:

PropertyInfo[] props =
  typeof(SystemIcons).GetProperties(
    BindingFlags.Public|BindingFlags.Static);
Then display all the ones that are icons:
foreach (PropertyInfo p in props) {
  Object obj = p.GetValue(null, null);
  if (obj.GetType()==typeof(Icon)) {
    Icon icon = (Icon)obj;
•••// display it
  }
}

Figure 4 SysIcons (Close Figure 4)
////////////////////////////////////////////////////////////////
// MSDN Magazine — March 2003
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio .NET on Windows XP. Tab size=3.
//
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;

namespace WinApp
{
   public class Form1 : System.Windows.Forms.Form
   {
      public Form1()
      {
         BackColor = SystemColors.Window;
      }

      protected override void OnPaint(PaintEventArgs e)
      {
         // get property info for all SystemIcons static properties
         PropertyInfo[] props = typeof(SystemIcons).GetProperties(
            BindingFlags.Public|BindingFlags.Static);

         Graphics g = e.Graphics;
         Font font = new Font("Verdana", 12, FontStyle.Bold);
         SolidBrush brush = new SolidBrush(Color.Black);
         int y = 0;

         // Display each icon. Use reflection to get all the static
         // members of SysIcons—cool!
         //
         foreach (PropertyInfo p in props) {
            Object obj = p.GetValue(null, null);
            if (obj.GetType()==typeof(Icon)) {
               Icon icon = (Icon)obj;
               g.DrawIcon(icon, 0, y);
               g.DrawString(String.Format("SystemIcons.{0}",p.Name),
                  font, brush, icon.Width+2, y);
               y += icon.Height;
            }
         }
      }

      protected override Size DefaultSize
      {
         get { return new Size(300,350); }
      }

      [STAThread]
      static void Main()
      {
         Application.Run(new Form1());
      }
   }
}
Figure 3 SystemIcons (Close Figure 3)

Win32 Resource ID | .NET Framework SystemIcons
(LoadIcon) | Static Property
IDI_APPLICATION | SystemIcons.Application
IDI_ASTERISK | SystemIcons.Asterisk
IDI_ERROR | SystemIcons.Error
IDI_EXCLAMATION | SystemIcons.Exclamation
IDI_HAND | SystemIcons.Hand
IDI_INFORMATION | SystemIcons.Information
IDI_QUESTION | SystemIcons.Question
IDI_WARNING | SystemIcons.Warning
IDI_WINLOGO | SystemIcons.WinLogo

Currently, the only properties of SystemIcons are the actual Icons, but you never know what the Redmontonians might add, so it's safer to check the type for Icon. Using reflection is way cooler than hardcoding all possible symbols, the kind of thing that wins you guru points. Once you have an Icon, you can convert it to a Bitmap like so:

Icon icon = SystemIcons.Question;
Bitmap bm = icon.ToBitmap();

Since Bitmap derives from Image, you can use it anywhere you can use Image. For example, as the BackgroundImage in a PictureBox—though I confess I was not able to make any of the icons paint properly in a PictureBox. Even after calling Bitmap.MakeTransparent, the Framework still paints the icons with a black background.

Q I want to double-click on an item in a list control and then launch the registered program for that file. It sounds so simple, but I can't figure out how to do it. Can you help?

David Rogers

A I get this question so frequently I'll answer it again for the newbies who may be reading this (don't feel embarrassed, we all begin as newbies). To open any file in Windows, call

ShellExecute(NULL, "open", lpFileName, NULL, NULL, SW_SHOWNORMAL);
where lpFileName is the full path name of the file. You can pass a string like "C:\\MyFinances.xls", or "http://msdn.microsoft.com" to launch the browser. If all you want to do is get the name of the program associated with a file without actually running it, you can call ::FindExecutable.

Q I've long been a fan of your TraceWin program for MFC. I use it all the time for debugging. I recently started a C# project. Is there some way I can make TraceWin work with the .NET Framework? Also, since this is going to be a global application, how hard would it be to make TraceWin support Unicode? Can I just recompile it with #define _UNICODE?

Peter Kerensky

A First of all, thanks for using TraceWin! You may have missed my recent article ".NET GUI Bliss: Streamline Your Code and Simplify Localization Using an XML-based GUI Language Parser", where I briefly described a TraceWin listener I wrote that targets the .NET Framework. Since I only mentioned it without describing the details, and since MFC does tracing differently in version 7.0, now seems like a good time to revisit TraceWin.

Figure 5 TraceWin in Action
Figure 5 TraceWin in Action

For those of you who have no idea what I'm talking about, TraceWin is a little applet that displays TRACE diagnostics so you can see them without running your program in the debugger. Figure 5 is a picture worth a thousand words. I first described TraceWin way back in the October 1995 issue of MSJ, before some of you were even born. (What, you don't believe the magazine has any seven-year-old readers?) In the old days, TRACE was #defined to AfxTrace, an MFC function that formats its parameters before calling afxDump, MFC's global CDumpContext. All trace diagnostics eventually went through CDumpContext::OutputString, which in version 6.0 looked something like this:

void CDumpContext::OutputString(LPCTSTR lpsz){
   if (m_pFile != NULL) {
      m_pFile->Write(lpsz, lstrlen(lpsz)*sizeof(TCHAR));
   } else {
      // normal debug thing
      OutputDebugString(lpsz);
   }
}
The special CFile member m_pFile is normally NULL, but if you set it to a CFile-derived object, you can effectively redirect all MFC trace output wherever you want. The original TraceWin.h described in 1995 implements a CFile-derived class with a Write method that sends the text to TraceWin. Pretty clever, huh? TraceWin.h has a self-initializing static object so all you have to do is #include TraceWin.h and away you go.

But like I said, that was then. This is now. Ever since its marriage to the ActiveX® Template Library (ATL), MFC does tracing somewhat differently. In version 7.0, a.k.a. Visual Studio® .NET, TRACE is now defined in afx.h like so:

#define TRACE ATLTRACE

MFC uses ATL. In short, ATL uses the C runtime (CRT) library's built-in debugging routines. So all trace diagnostics for both MFC and ATL now go through _CrtDbgReport, a low-level C runtime function for reporting debug diagnostics. There's only one downside to this: since _CrtDbgReport is declared with char*, not TCHAR, debug messages have to be ANSI (the old MFC system used TCHAR)—but overall the new scheme is better. All tracing now rests on the same foundation. The CRT has a function _CrtSetReportHook that lets you install a function to intercept the diagnostic stream. MFC installs its own hook that calls afxDump:

// details omitted to protect you
int _AfxCrtReportHook(int nRptType, char *szMsg, int* pResult)
{
  // no hook on asserts or when m_pFile is NULL
  if (nRptType==_CRT_ASSERT || afxDump.m_pFile==NULL)
    return FALSE;
  // non-NULL m_pFile: go through afxDump
  *pResult = FALSE;
  afxDump << szMsg;
  return TRUE;
}

If afxDump has a file (m_pFile), MFC sends the message through afxDump; otherwise it lets the CRT do its thing (which ultimately displays the message in the debugger's output window). The upshot of this long digression is: even when using ATLTRACE and the CRT, the old TraceWin.h from 1995 still works by setting afxDump.m_pFile. Amazing.

You might be thinking, "if it works, don't fix it"—and generally you'd be right. But now that MFC has joined the ATL/C runtime bandwagon, I'm suffering from code envy. Why not upgrade TraceWin.h, too? If TraceWin.h intercepted trace diagnostics through the C runtime, then non-MFC programmers—even C programmers—could use TraceWin. Say no more. Figure 6 shows the code. No more CFile, no more MFC. The revised TraceWin.h defines a new class, CTraceWinListener, with a singleton instance that sets everything up. The constructor installs a debug hook that passes strings to TraceWin as before, using WM_COPYDATA. Everything is straightforward and simple; all you have to do is #include TraceWin.h in your application. For details, download the source code from the link at the top of this article.

Figure 6 TraceWin (Close Figure 6)
////////////////////////////////////////////////////////////////
// TraceWin 1995-2003 MSDN Magazine
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// ***********************************************************************
// TraceWin is a tool that displays diagnostic (TRACE, ATLTRACE) output
// in the TraceWin applet window.
//
// To use TraceWin, you must #include this file in your main program
// file, but only once—i.e. NOT in StdAfx.h—or you'll get multiply-defined
// symbol errors in the linker. This file contains an auto-initializing
// singleton instance, so all you have to do is #include the file.
//
// To see the output, you also need TraceWin.exe, which if you don't
// have already, you can download from http://www.dilascia.com/TraceWin.htm
//
// ***********************************************************************
//
#ifdef _DEBUG

// Window class name used by the main window of the TRACEWIN applet.
#define TRACEWND_CLASSNAME _T("MfxTraceWindow") // backwards compat

// ID sent as COPYDATASRUCT::dwData to identify the WM_COPYDATA message
// as coming from an app using TraceWin.
#define ID_COPYDATA_TRACEMSG MAKELONG(MAKEWORD('t','w'),MAKEWORD('i','n'))

//////////////////
// Self-initializing CRT-based trace "listener" hooks
// itself into C runtime debug system.
//
class CTraceWinListener {
protected:
   static CTraceWinListener singleton;  // one-and-only instance
   static _CRT_REPORT_HOOK pfnOldHook;  // ptr to old reporting hook

   // ctor installs hook
   CTraceWinListener()
   {
      // if this bombs, you probably #included TraceWin.h twice
      ASSERT(pfnOldHook == NULL);
      pfnOldHook = _CrtSetReportHook(MyCrtReportHook);
   }

   // dtor removes hook
   ~CTraceWinListener()
   {
      pfnOldHook = _CrtSetReportHook(pfnOldHook);
   }

   // hook function installed in CRT: passes text to TraceWin
   static int __cdecl MyCrtReportHook(int nRptType, char *szMsg, int* pRes)
   {
      // call the old report hook if there was one
      if (pfnOldHook && (*pfnOldHook)(nRptType, szMsg, pRes)) {
         return TRUE;
      }

      // don't hook asserts
      if (nRptType == _CRT_ASSERT)
         return FALSE;

      // Find trace window. Note that it's not really safe to store
      // this HWND if I want to allow closing/restarting TraceWin. The
      // window handle could change!
      HWND hTraceWnd = ::FindWindow(TRACEWND_CLASSNAME, NULL);
      if (hTraceWnd) {
         COPYDATASTRUCT cds;
         cds.dwData = ID_COPYDATA_TRACEMSG;
         cds.cbData = strlen(szMsg);
         cds.lpData = (void*)szMsg;
         WPARAM wParam = 0;
         ::SendMessage(hTraceWnd, WM_COPYDATA, wParam, (LPARAM)&cds);
         *pRes = FALSE;
      }
      return FALSE; // don't stop next hook
   }
};

// one-and-only singleton instance automatically installs debug hook
CTraceWinListener CTraceWinListener::singleton;
_CRT_REPORT_HOOK  CTraceWinListener::pfnOldHook=NULL;

#endif // _DEBUG

Now that MFC, C++, and C programmers can all use TraceWin, what about programmers using the .NET Framework? Never fear, the Framework has a way to include them, too. It has a diagnostic system with the notion of trace "listeners." A trace listener is just a class derived from—what else?—TraceListener, with overloaded Write and WriteLine functions that can do whatever you want. For example, you could feed your debug messages through a text-to-speech converter linked to a geostationary satellite to broadcast your Trace messages live on Monday Night Football. But it costs a lot to buy your own satellite and, besides, who wants his bugs seen by millions? Fortunately, writing a listener for TraceWin is much easier. All that's required is a Write function that sends WM_COPYDATA messages to the TraceWin applet. Figure 7 shows the class. This is the kind of code you can write in your sleep, provided you know a little interop voodoo.

Figure 7 TraceWinListener (Close Figure 7)
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;

//////////////////
// This module implements a TraceWin listener for .NET.
// Use it to see trace diagnostics in my TraceWin applet window.
// To install in your app, add the following lines:
//
//    using TraceWin;
//    Debug.Listeners.Add(new TraceWinListener());
//
// You must add a reference to TraceWinListener.dll in your project and
// don't forget to compile with /d:TRACE.
//
namespace TraceWin {

//////////////////
// Handy trace listener writes to TraceWin. Neat!
//
public class TraceWinListener : TraceListener {

   [StructLayout(LayoutKind.Sequential)]
   private struct COPYDATASTRUCT {
      public Int32 dwData;
      public Int32 cbData;
      public IntPtr lpData;
   }

   [DllImport("user32.dll")]
   private static extern long SendMessage(Int32 hwnd, Int32 msg,
      Int32 hwndFrom, ref COPYDATASTRUCT cd);

   [DllImport("user32.dll")]
   private static extern Int32 FindWindow(String classname, String text);

   [DllImport("kernel32.dll")]
   private static extern Int32 GlobalSize(IntPtr hmem);

   public override void Write(String s) {
      // Don't forget to use IndentLevel and IndentSize!
      if (Trace.IndentLevel>0) {
         s = s.Insert(0,new String(' ',
            Trace.IndentSize * Trace.IndentLevel));
      }

      // Send WM_COPYDATA message to trace window
      Int32 hTraceWnd = FindWindow("MfxTraceWindow",null);
      if (hTraceWnd!=0) {
         COPYDATASTRUCT cd = new COPYDATASTRUCT();
         Int32 WM_COPYDATA = 0x004A;    // Win32 API message id
         cd.dwData = 0x6e697775;        // magic message code TraceWin
         cd.lpData = Marshal.StringToHGlobalUni(s);
         cd.cbData = GlobalSize(cd.lpData);
         SendMessage(hTraceWnd, WM_COPYDATA, 0, ref cd);
         Marshal.FreeHGlobal(cd.lpData);
      }
   }

   public override void WriteLine(String s) {
      Write(s+"\n");
   }
}

} // namespace

First, you need the magic declarations for the Win32 functions SendMessage, FindWindow, and so on, as well as a struct for COPYDATASTRUCT. These appear at the top of Figure 7. After inserting Trace.IndentLevel number of spaces ahead of the trace message (don't forget this if you ever write your own listener!), TraceWinListener.Write calls ::FindWindow to find TraceWin, then sends it a WM_COPYDATA message with the magic TraceWin code 0x6e697775. You could use interop to marshal the String through COPYDATASTRUCT as LPWStr, but WM_COPYDATA needs to know the exact number of bytes in your memory block, so TraceWinListener allocates global memory and passes it as an IntPtr, as shown in the following code:

COPYDATASTRUCT cd = new COPYDATASTRUCT();
Int32 WM_COPYDATA = 0x004A;
cd.dwData = 0x6e697775; // magic TraceWin code
cd.lpData = Marshal.StringToHGlobalUni(s);
cd.cbData = GlobalSize(cd.lpData);
SendMessage(hTraceWnd, WM_COPYDATA, 0, ref cd);
Marshal.FreeHGlobal(cd.lpData);

Marshal.StringToHGlobalUni copies the string to a newly allocated block in global memory, converting to Unicode along the way. I couldn't find any common language runtime function to get the length of a global memory block, so I used interop to call ::GlobalSize directly:

[DllImport("kernel32.dll")]
private static extern Int32 GlobalSize(IntPtr hmem);
•••
IntPtr data = Marshal.AllocHGlobal(...);
int size = GlobalSize(data); // it works!

Windows needs to know the size (in bytes) of the WM_COPYDATA memory block in order to copy it across the process boundary. It's not generally safe to assume the length of a Unicode string is always twice String.Length, so let the Marshaler convert the string, then call GlobalSize to get its true size. There's probably a more clever interop way to handle this situation, but I didn't have the time or patience to figure it out. In magazine-land we live on very tight schedules.

And speaking of Unicode (we were speaking of Unicode, remember?), how do you make TraceWin understand Rundi? _CrtDbgReport doesn't do Unicode, but the .NET Framework is multinational, so why limit TraceWin? This is where you have to modify TraceWin itself. If you've been paying close attention, you'll have noticed that so far I've only described changes to client-side code (TraceWin.h and TraceWinListener), not the TraceWin applet itself.

To make TraceWin global, the first thing I did was change the project settings (in Visual Studio, select "Use Unicode Character Set" in the project properties under General properties) and recompile. To my great astonishment, there were no errors. I guess _T and all those LPCTSTR definitions really work. But recompiling with _UNICODE isn't enough: TraceWin still has to support ANSI. I don't want to break all those ANSI-compliant apps out there already using TraceWin—I might get a pile of flame mail. To support Unicode without dropping ANSI clients, TraceWin needs a new WM_COPYDATA subcode, just like Windows does with all its A and W versions of every WM_ message:

// same as before
#define ID_COPYDATA_TRACEMSGA 0x6e697774
// new
#define ID_COPYDATA_TRACEMSGW (ID_COPYDATA_TRACEMSGA+1)

TraceWin processes the new message in CMainFrame::OnTraceMsg, the message handler for WM_COPYDATA. Here's the pseudocode from MainFrm.cpp:

LRESULT
CMainFrame::OnTraceMsg(WPARAM wp, LPARAM lp)
{
  COPYDATASTRUCT* pcd = (COPYDATASTRUCT*)lp;
  if (pcd->dwData==ID_COPYDATA_TRACEMSGW) {
    // already Unicode
    // string len = data len/2
  } else if (pcd->dwData==ID_COPYDATA_TRACEMSGA) {
    // convert from ANSI to Unicode
    // (call MultiByteToWideChar)
  }
  •••
}

In short: whereas the old TraceWin was an ANSI app that accepted only ANSI strings, the new TraceWin is a Unicode app that accepts either ANSI or Unicode. If your app wants to send ANSI, it uses ID_COPYDATA_TRACEMSGA; for Unicode, use ID_COPYDATA_TRACEMSGW. Of course, you don't have to do anything personally, since TraceWin.h and TraceWinListener do the right thing automatically. All you have to do is use them. For C/C++ apps, just #include TraceWin.h. For the .NET Framework, add a reference to TraceWinListener.dll and insert the following lines somewhere:

using TraceWin;
Debug.Listeners.Add(new
    TraceWinListener());

Don't forget to compile with /d:TRACE! Visual Studio .NET does it automatically in Debug builds. As usual, you can download the entire TraceWin source code from the link at the top of this article. Happy programming!

Send your questions and comments for Paul to cppqa@microsoft.com.

Paul DiLasciais a freelance writer, consultant, and Web/UI designer-at-large. He is the author of Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992). Paul can be reached at askpd@pobox.com or http://www.dilascia.com.


Talking To...: Michael Howard Discusses the Secure Windows Initiative

Talking To...
Michael Howard Discusses the Secure Windows Initiative

The growth of interconnected computers in recent years has pushed security concerns to the forefront of development and application design. The Microsoft effort, dubbed the Secure Windows Initiative (SWI), focuses on securing new and legacy code. A key player on the Secure Windows Initiative team is Senior Security Program Manager Michael Howard. Michael has a long history working on security-related issues and has written two books along the way—Writing Secure Code and Designing Secure Web-based Applications for Windows 2000 (both from Microsoft Press).

Erica Wiechers, co-host of the .NET Show on MSDN, sat down with Michael recently for an update on the security effort. Here's what he had to say.

MSDN Microsoft is heavily focused on security issues these days. How has the thinking about security changed over the past few years at Microsoft?

Howard Simply put—threats have changed, and all software must adapt to reflect the changing, and frankly, more dangerous landscape. Security—and by security I don't mean security features, I mean secure features—is at the forefront of everyone's thoughts at Microsoft. What was previously the domain of a small bunch of specialists is now part of daily life in the various Microsoft product groups. It's part of getting the job done. And Bill's January 2002 e-mail on Trustworthy Computing has added a huge impetus and urgency to the process.

MSDN What is the main charter of the Secure Windows Initiative group at Microsoft?

Howard Our role is simple: help product groups build more secure products. Our ultimate goal is to put our group out of business by seeding product groups with expertise, helping them design, develop, test, and document their products correctly and securely. All product teams should get to a stage where their security effort is self-sufficient over time, but we are in the building phase right now, so our group performs a great deal of hand holding until the teams can run on their own.

MSDN Describe your role in that group.

Howard I have many roles including security education, research, consulting, and writing. The education aspect is critical—in general it's rare to find new developers who understand how to build secure software, so our group fills that gap. I probably spend an average of six hours a week educating people. I also spend time researching things such as new threat modeling methods, determining attack profiles, and new vulnerability types. Because of the SWI charter, I also spend a good chunk of my time working with other product groups to make sure they are on track, answer questions, go over designs, code, threats, test plans, and so on.

MSDN What are some projects you are currently working on?

Howard You name it! We just finished working with Windows XP SP1 and Visual Studio .NET 2003; now we're onto Windows Server 2003, SQL Server, Microsoft Office, the next big Visual Studio .NET release, and much, much more.

MSDN What do you see as the biggest challenge that developers face while trying to code secure applications?

Howard Legacy code is definitely the biggest challenge in that respect. We think we have the new code pretty much solved. People know the right things to do now that we have provided mandatory training, set security rules in place, improved the tools, and created a huge security awareness company-wide. However, attackers target legacy code as well as new code, and the role of the various security pushes is to fix issues in both old and new code. We can task people here at Microsoft to review and fix all code, old and new, and make it part of their job.

MSDN What security features would you like to see incorporated into future Microsoft products?

Howard I would like to see people not focus on security features. In fact, I truly believe that the biggest security benefit we can provide our customers is to install only critical features by default. If the user wants to enable other features, then they should be optional installs.

I say this because we can create products that defend against the threats we know about today. Of course, there will be new threats in the future that we do not know about today, and if a feature has such a vulnerability and it is installed by default, the user of that particular feature is automatically susceptible to attack and will need to deploy a security fix quickly. However, if the feature is rarely used and not running by default, then it cannot be attacked. Therefore, the path deployment urgency is vastly reduced. In short, if a feature is not used by 90 percent of the product's users, then the feature should be disabled by default.